aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorHollis Blanchard <hollisb@us.ibm.com>2007-03-21 18:08:31 -0500
committerHollis Blanchard <hollisb@us.ibm.com>2007-03-21 18:08:31 -0500
commit001e8c5cd8f60e7cafbfed9869862db46b5ed473 (patch)
tree7ac30f8387c3f66c1860ea9421e0a681bb4b4b7f /tools
parenta7706a8de0119f07b6f7e014a78fd07947af3787 (diff)
parent5b3327347f83a473755b00a76ff1176dc6cda301 (diff)
downloadxen-001e8c5cd8f60e7cafbfed9869862db46b5ed473.tar.gz
xen-001e8c5cd8f60e7cafbfed9869862db46b5ed473.tar.bz2
xen-001e8c5cd8f60e7cafbfed9869862db46b5ed473.zip
Merge with xen-unstable.hg.
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/Rules.mk5
-rw-r--r--tools/blktap/drivers/block-qcow.c1
-rw-r--r--tools/firmware/Makefile6
-rw-r--r--tools/firmware/hvmloader/32bitbios_support.c175
-rw-r--r--tools/firmware/hvmloader/acpi/acpi2_0.h54
-rw-r--r--tools/firmware/hvmloader/acpi/build.c49
-rw-r--r--tools/firmware/hvmloader/hvmloader.c142
-rw-r--r--tools/firmware/hvmloader/smbios.c46
-rw-r--r--tools/firmware/hvmloader/util.c21
-rw-r--r--tools/firmware/hvmloader/util.h12
-rw-r--r--tools/firmware/rombios/32bit/tcgbios/tcgbios.c64
-rw-r--r--tools/firmware/rombios/32bitgateway.c27
-rw-r--r--tools/firmware/rombios/rombios.c237
-rw-r--r--tools/firmware/rombios/tcgbios.c4
-rw-r--r--tools/ioemu/hw/ide.c57
-rw-r--r--tools/ioemu/hw/usb-hid.c47
-rw-r--r--tools/ioemu/hw/usb-ohci.c2
-rw-r--r--tools/ioemu/hw/usb-uhci.c48
-rw-r--r--tools/ioemu/hw/usb.c40
-rw-r--r--tools/ioemu/hw/usb.h6
-rw-r--r--tools/ioemu/target-i386-dm/exec-dm.c16
-rw-r--r--tools/ioemu/target-i386-dm/helper2.c36
-rw-r--r--tools/ioemu/vl.c19
-rw-r--r--tools/ioemu/vl.h1
-rw-r--r--tools/ioemu/xenstore.c179
-rw-r--r--tools/libxc/Makefile2
-rw-r--r--tools/libxc/xc_core.c6
-rw-r--r--tools/libxc/xc_core_ia64.c24
-rw-r--r--tools/libxc/xc_core_x86.c24
-rw-r--r--tools/libxc/xc_dom_x86.c34
-rw-r--r--tools/libxc/xc_hvm_build.c15
-rw-r--r--tools/libxc/xc_hvm_restore.c82
-rw-r--r--tools/libxc/xc_hvm_save.c182
-rw-r--r--tools/libxc/xc_linux_restore.c5
-rw-r--r--tools/libxc/xc_misc.c19
-rw-r--r--tools/libxc/xc_private.c16
-rw-r--r--tools/libxc/xc_ptrace_core.c1
-rw-r--r--tools/libxc/xenctrl.h8
-rw-r--r--tools/libxc/xenguest.h9
-rw-r--r--tools/libxc/xg_private.c9
-rw-r--r--tools/libxen/include/xen_crashdump.h23
-rw-r--r--tools/libxen/include/xen_vbd.h17
-rw-r--r--tools/libxen/include/xen_vdi.h49
-rw-r--r--tools/libxen/include/xen_vif.h16
-rw-r--r--tools/libxen/include/xen_vm.h110
-rw-r--r--tools/libxen/src/xen_common.c21
-rw-r--r--tools/libxen/src/xen_crashdump.c37
-rw-r--r--tools/libxen/src/xen_vbd.c31
-rw-r--r--tools/libxen/src/xen_vdi.c104
-rw-r--r--tools/libxen/src/xen_vif.c28
-rw-r--r--tools/libxen/src/xen_vm.c173
-rw-r--r--tools/libxen/test/test_bindings.c6
-rw-r--r--tools/python/scripts/test_hvm_create.py3
-rw-r--r--tools/python/scripts/test_vm_create.py6
-rw-r--r--tools/python/scripts/xapi.py11
-rw-r--r--tools/python/scripts/xapi.vdicfg.py3
-rw-r--r--tools/python/xen/lowlevel/xc/xc.c94
-rw-r--r--tools/python/xen/util/blkif.py17
-rw-r--r--tools/python/xen/util/xmlrpclib2.py52
-rw-r--r--tools/python/xen/xend/XendAPI.py424
-rw-r--r--tools/python/xen/xend/XendCheckpoint.py26
-rw-r--r--tools/python/xen/xend/XendConfig.py376
-rw-r--r--tools/python/xen/xend/XendDomain.py4
-rw-r--r--tools/python/xen/xend/XendDomainInfo.py197
-rw-r--r--tools/python/xen/xend/XendError.py7
-rw-r--r--tools/python/xen/xend/XendLogging.py12
-rw-r--r--tools/python/xen/xend/XendNode.py65
-rw-r--r--tools/python/xen/xend/XendVDI.py27
-rw-r--r--tools/python/xen/xend/XendVMMetrics.py70
-rw-r--r--tools/python/xen/xend/image.py57
-rw-r--r--tools/python/xen/xend/server/SrvDaemon.py9
-rw-r--r--tools/python/xen/xend/server/XMLRPCServer.py2
-rw-r--r--tools/python/xen/xend/server/vfbif.py2
-rw-r--r--tools/python/xen/xm/XenAPI.py2
-rw-r--r--tools/python/xen/xm/addlabel.py2
-rw-r--r--tools/python/xen/xm/create.dtd118
-rw-r--r--tools/python/xen/xm/create.py83
-rw-r--r--tools/python/xen/xm/main.py541
-rw-r--r--tools/python/xen/xm/messages/en/xen-xm.po5
-rw-r--r--tools/python/xen/xm/new.py13
-rw-r--r--tools/python/xen/xm/shutdown.py37
-rw-r--r--tools/python/xen/xm/xenapi_create.py636
-rw-r--r--tools/xcutils/Makefile6
-rw-r--r--tools/xcutils/xc_save.c129
-rw-r--r--tools/xm-test/tests/block-create/07_block_attach_baddevice_neg.py4
-rw-r--r--tools/xm-test/tests/block-create/08_block_attach_bad_filedevice_neg.py4
-rw-r--r--tools/xm-test/tests/destroy/01_destroy_basic_pos.py2
-rw-r--r--tools/xm-test/tests/network-attach/network_utils.py19
-rw-r--r--tools/xm-test/tests/vtpm/09_vtpm-xapi.py11
-rw-r--r--tools/xm-test/tests/vtpm/vtpm_utils.py3
90 files changed, 3679 insertions, 1745 deletions
diff --git a/tools/Rules.mk b/tools/Rules.mk
index df3b231a1a..3e13eceb55 100644
--- a/tools/Rules.mk
+++ b/tools/Rules.mk
@@ -23,6 +23,11 @@ LDFLAGS += $(shell getconf LFS_LDFLAGS)
CFLAGS-$(CONFIG_X86_32) += $(call cc-option,$(CC),-mno-tls-direct-seg-refs)
CFLAGS += $(CFLAGS-y)
+# Require GCC v3.4+ (to avoid issues with alignment constraints in Xen headers)
+ifeq ($(CONFIG_X86)$(call cc-ver,$(CC),0x030400),yn)
+$(error Xen tools require at least gcc-3.4)
+endif
+
%.opic: %.c
$(CC) $(CPPFLAGS) -DPIC $(CFLAGS) -fPIC -c -o $@ $<
diff --git a/tools/blktap/drivers/block-qcow.c b/tools/blktap/drivers/block-qcow.c
index 36f77e6f05..b0822f729d 100644
--- a/tools/blktap/drivers/block-qcow.c
+++ b/tools/blktap/drivers/block-qcow.c
@@ -1057,6 +1057,7 @@ int tdqcow_queue_write(struct disk_driver *dd, uint64_t sector,
index_in_cluster+n);
if (!cluster_offset) {
DPRINTF("Ooops, no write cluster offset!\n");
+ aio_unlock(s, sector);
return cb(dd, -EIO, sector, nb_sectors, id, private);
}
diff --git a/tools/firmware/Makefile b/tools/firmware/Makefile
index 8091da46d3..38338471fd 100644
--- a/tools/firmware/Makefile
+++ b/tools/firmware/Makefile
@@ -14,10 +14,10 @@ SUBDIRS += hvmloader
.PHONY: all
all:
- @set -e; if ! `which bcc 1>/dev/null 2>/dev/null`; then \
+ @set -e; if [ $$((`( bcc -v 2>&1 | grep version || echo 0.0.0 ) | cut -d' ' -f 3 | awk -F. '{ printf "0x%02x%02x%02x", $$1, $$2, $$3}'`)) -lt $$((0x00100e)) ] ; then \
echo "***********************************************************"; \
- echo "WARNING: Install dev86 package to build firmware!"; \
- echo " (http://www.cix.co.uk/~mayday)"; \
+ echo "Require dev86 package version >= 0.16.14 to build firmware!"; \
+ echo "(visit http://www.cix.co.uk/~mayday for more information)"; \
echo "***********************************************************"; \
else \
for subdir in $(SUBDIRS); do \
diff --git a/tools/firmware/hvmloader/32bitbios_support.c b/tools/firmware/hvmloader/32bitbios_support.c
index f9274090cc..7cb32a299d 100644
--- a/tools/firmware/hvmloader/32bitbios_support.c
+++ b/tools/firmware/hvmloader/32bitbios_support.c
@@ -17,158 +17,129 @@
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*/
+
#include <inttypes.h>
#include <elf.h>
#ifdef __sun__
#include <sys/machelf.h>
#endif
-#include <xen/hvm/e820.h>
#include "util.h"
#include "config.h"
#include "../rombios/32bit/32bitbios_flat.h"
#include "../rombios/32bit/jumptable.h"
-
-/*
- * relocate ELF file of type ET_REL
- */
-static int relocate_elf(unsigned char *elfarray) {
+/* Relocate ELF file of type ET_REL */
+static void relocate_elf(char *elfarray)
+{
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfarray;
Elf32_Shdr *shdr = (Elf32_Shdr *)&elfarray[ehdr->e_shoff];
- int i;
+ Elf32_Sym *syms, *sym;
+ Elf32_Rel *rels;
+ char *code;
+ uint32_t *loc, fix;
+ int i, j;
- if (ehdr->e_type != ET_REL) {
- printf("Not a relocatable BIOS object file. Has type %d, need %d\n",
- ehdr->e_type, ET_REL);
- return -1;
- }
+ for ( i = 0; i < ehdr->e_shnum; i++ )
+ shdr[i].sh_addr = (Elf32_Addr)&elfarray[shdr[i].sh_offset];
+
+ for ( i = 0; i < ehdr->e_shnum; i++ )
+ {
+ if ( shdr[i].sh_type == SHT_RELA )
+ printf("Unsupported section type SHT_RELA\n");
- for (i = 0; i < ehdr->e_shnum; i++) {
- if (!(shdr[i]).sh_flags & SHF_ALLOC) {
- shdr[i].sh_addr = 0;
+ if ( shdr[i].sh_type != SHT_REL )
continue;
- }
- shdr[i].sh_addr = (Elf32_Addr)&elfarray[shdr[i].sh_offset];
- }
- for (i = 0; i < ehdr->e_shnum; i++) {
- if (shdr[i].sh_type == SHT_REL && shdr[i].sh_addr != 0) {
- Elf32_Shdr *targetsec = (Elf32_Shdr *)&(shdr[shdr[i].sh_info]);
- Elf32_Shdr *symtabsec = (Elf32_Shdr *)&(shdr[shdr[i].sh_link]);
- Elf32_Sym *syms = (Elf32_Sym *)symtabsec->sh_addr;
- Elf32_Rel *rels = (Elf32_Rel *)shdr[i].sh_addr;
- unsigned char *code = (unsigned char *)targetsec->sh_addr;
- int j;
-
- for (j = 0; j < shdr[i].sh_size / sizeof(Elf32_Rel); j++) {
- int idx = ELF32_R_SYM(rels[j].r_info);
- Elf32_Sym *symbol = &syms[idx];
- uint32_t *loc = (uint32_t *)&code[rels[j].r_offset];
- uint32_t fix = shdr[symbol->st_shndx].sh_addr +
- symbol->st_value;
-
- switch (ELF32_R_TYPE(rels[j].r_info)) {
- case R_386_PC32:
- *loc += (fix - (uint32_t)loc);
- break;
-
- case R_386_32:
- *loc += fix;
- break;
- }
+ syms = (Elf32_Sym *)shdr[shdr[i].sh_link].sh_addr;
+ rels = (Elf32_Rel *)shdr[i].sh_addr;
+ code = (char *)shdr[shdr[i].sh_info].sh_addr;
+
+ for ( j = 0; j < shdr[i].sh_size / sizeof(Elf32_Rel); j++ )
+ {
+ sym = &syms[ELF32_R_SYM(rels[j].r_info)];
+ loc = (uint32_t *)&code[rels[j].r_offset];
+ fix = shdr[sym->st_shndx].sh_addr + sym->st_value;
+
+ switch ( ELF32_R_TYPE(rels[j].r_info) )
+ {
+ case R_386_PC32:
+ *loc += fix - (uint32_t)loc;
+ break;
+
+ case R_386_32:
+ *loc += fix;
+ break;
}
- } else if (shdr[i].sh_type == SHT_RELA) {
- return -2;
}
}
- return 0;
}
-/* scan the rombios for the destination of the jumptable */
-static char* get_jump_table_start(void)
+/* Scan the rombios for the destination of the jump table. */
+static char *get_jump_table_start(void)
{
char *bios_mem;
for ( bios_mem = (char *)ROMBIOS_BEGIN;
bios_mem != (char *)ROMBIOS_END;
- bios_mem++ ) {
- if (strncmp(bios_mem, "___JMPT", 7) == 0)
+ bios_mem++ )
+ if ( !strncmp(bios_mem, "___JMPT", 7) )
return bios_mem;
- }
return NULL;
}
-/* copy relocated jumptable into the rombios */
-static int copy_jumptable(unsigned char *elfarray)
+/* Copy relocated jumptable into the rombios. */
+static void copy_jumptable(char *elfarray)
{
- int rc = 0;
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfarray;
Elf32_Shdr *shdr = (Elf32_Shdr *)&elfarray[ehdr->e_shoff];
- Elf32_Shdr *shdr_strings = (Elf32_Shdr *)&shdr[ehdr->e_shstrndx];
- char *secstrings = (char *)&elfarray[shdr_strings->sh_offset];
- uint32_t *rombiosjumptable = (uint32_t *)get_jump_table_start();
- uint32_t *biosjumptable = NULL;
+ char *secstrings = &elfarray[shdr[ehdr->e_shstrndx].sh_offset];
+ char *jump_table = get_jump_table_start();
int i;
- if (rombiosjumptable == NULL) {
- return -3;
- }
-
- /* find the section with the jump table and copy to lower BIOS memory */
- for (i = 0; i < ehdr->e_shnum; i++) {
- if (!strcmp(JUMPTABLE_SECTION_NAME, secstrings + shdr[i].sh_name)) {
- uint32_t biosjumptableentries;
- biosjumptable = (uint32_t *)shdr[i].sh_addr;
- biosjumptableentries = shdr[i].sh_size / 4;
- for (int j = 0; j < biosjumptableentries; j++) {
- rombiosjumptable[j] = biosjumptable[j];
- if (biosjumptable[j] == 0 &&
- j < (biosjumptableentries - 1)) {
- printf("WARNING: jumptable entry %d is NULL!\n",j);
- }
- }
+ /* Find the section with the jump table and copy to lower BIOS memory. */
+ for ( i = 0; i < ehdr->e_shnum; i++ )
+ if ( !strcmp(JUMPTABLE_SECTION_NAME, secstrings + shdr[i].sh_name) )
break;
- }
- }
- if (biosjumptable == NULL) {
+ if ( i == ehdr->e_shnum )
+ {
printf("Could not find " JUMPTABLE_SECTION_NAME " section in file.\n");
- rc = -4;
+ return;
}
- return 0;
+ if ( jump_table == NULL )
+ {
+ printf("Could not find jump table in file.\n");
+ return;
+ }
+
+ memcpy(jump_table, (char *)shdr[i].sh_addr, shdr[i].sh_size);
}
-static int relocate_32bitbios(unsigned char *elfarray, uint32_t elfarraysize)
+static void relocate_32bitbios(char *elfarray, uint32_t elfarraysize)
{
- int rc = 0;
uint32_t mask = (64 * 1024) - 1;
- uint32_t to_malloc = (elfarraysize + mask) & ~mask; /* round to 64kb */
- unsigned char *highbiosarea;
-
- highbiosarea = (unsigned char *)(long)
- e820_malloc((uint64_t)to_malloc,
- E820_RESERVED,
- (uint64_t)0xffffffff);
-
- if (highbiosarea != 0) {
- memcpy(highbiosarea, elfarray, elfarraysize);
- rc = relocate_elf(highbiosarea);
- if (rc == 0) {
- rc = copy_jumptable(highbiosarea);
- }
- } else {
- rc = -5;
+ char *highbiosarea;
+
+ highbiosarea = (char *)(long)
+ e820_malloc((elfarraysize + mask) & ~mask, /* round to 64kb */
+ E820_RESERVED,
+ (uint64_t)0xffffffff);
+ if ( highbiosarea == NULL )
+ {
+ printf("No available memory for BIOS high memory area\n");
+ return;
}
- return rc;
+ memcpy(highbiosarea, elfarray, elfarraysize);
+ relocate_elf(highbiosarea);
+ copy_jumptable(highbiosarea);
}
-int highbios_setup(void)
+void highbios_setup(void)
{
- return relocate_32bitbios((unsigned char *)highbios_array,
- sizeof(highbios_array));
+ relocate_32bitbios((char *)highbios_array, sizeof(highbios_array));
}
diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h b/tools/firmware/hvmloader/acpi/acpi2_0.h
index 04824f5642..3e8424e138 100644
--- a/tools/firmware/hvmloader/acpi/acpi2_0.h
+++ b/tools/firmware/hvmloader/acpi/acpi2_0.h
@@ -49,8 +49,8 @@ struct acpi_header {
uint32_t length;
uint8_t revision;
uint8_t checksum;
- uint8_t oem_id[6];
- uint8_t oem_table_id[8];
+ char oem_id[6];
+ char oem_table_id[8];
uint32_t oem_revision;
uint32_t creator_id;
uint32_t creator_revision;
@@ -90,7 +90,7 @@ struct acpi_20_generic_address {
struct acpi_10_rsdp {
uint64_t signature;
uint8_t checksum;
- uint8_t oem_id[6];
+ char oem_id[6];
uint8_t reserved;
uint32_t rsdt_address;
};
@@ -101,7 +101,7 @@ struct acpi_10_rsdp {
struct acpi_20_rsdp {
uint64_t signature;
uint8_t checksum;
- uint8_t oem_id[6];
+ char oem_id[6];
uint8_t revision;
uint32_t rsdt_address;
uint32_t length;
@@ -143,6 +143,51 @@ struct acpi_20_tcpa {
#define ACPI_2_0_TCPA_LAML_SIZE (64*1024)
/*
+ * Fixed ACPI Description Table Structure (FADT) in ACPI 1.0.
+ */
+struct acpi_10_fadt {
+ struct acpi_header header;
+ uint32_t firmware_ctrl;
+ uint32_t dsdt;
+ uint8_t reserved0;
+ uint8_t preferred_pm_profile;
+ uint16_t sci_int;
+ uint32_t smi_cmd;
+ uint8_t acpi_enable;
+ uint8_t acpi_disable;
+ uint8_t s4bios_req;
+ uint8_t pstate_cnt;
+ uint32_t pm1a_evt_blk;
+ uint32_t pm1b_evt_blk;
+ uint32_t pm1a_cnt_blk;
+ uint32_t pm1b_cnt_blk;
+ uint32_t pm2_cnt_blk;
+ uint32_t pm_tmr_blk;
+ uint32_t gpe0_blk;
+ uint32_t gpe1_blk;
+ uint8_t pm1_evt_len;
+ uint8_t pm1_cnt_len;
+ uint8_t pm2_cnt_len;
+ uint8_t pm_tmr_len;
+ uint8_t gpe0_blk_len;
+ uint8_t gpe1_blk_len;
+ uint8_t gpe1_base;
+ uint8_t cst_cnt;
+ uint16_t p_lvl2_lat;
+ uint16_t p_lvl3_lat;
+ uint16_t flush_size;
+ uint16_t flush_stride;
+ uint8_t duty_offset;
+ uint8_t duty_width;
+ uint8_t day_alrm;
+ uint8_t mon_alrm;
+ uint8_t century;
+ uint16_t iapc_boot_arch;
+ uint8_t reserved1;
+ uint32_t flags;
+};
+
+/*
* Fixed ACPI Description Table Structure (FADT).
*/
struct acpi_20_fadt {
@@ -345,6 +390,7 @@ struct acpi_20_madt_intsrcovr {
#define ACPI_2_0_XSDT_REVISION 0x01
#define ACPI_2_0_TCPA_REVISION 0x02
#define ACPI_2_0_HPET_REVISION 0x01
+#define ACPI_1_0_FADT_REVISION 0x01
#pragma pack ()
diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c
index ff99160612..7be1ea4a71 100644
--- a/tools/firmware/hvmloader/acpi/build.c
+++ b/tools/firmware/hvmloader/acpi/build.c
@@ -20,9 +20,9 @@
#include "ssdt_tpm.h"
#include "../config.h"
#include "../util.h"
-#include <xen/hvm/e820.h>
-#define align16(sz) (((sz) + 15) & ~15)
+#define align16(sz) (((sz) + 15) & ~15)
+#define fixed_strcpy(d, s) strncpy((d), (s), sizeof(d))
extern struct acpi_20_rsdp Rsdp;
extern struct acpi_20_rsdt Rsdt;
@@ -57,8 +57,8 @@ int construct_madt(struct acpi_20_madt *madt)
memset(madt, 0, sizeof(*madt));
madt->header.signature = ACPI_2_0_MADT_SIGNATURE;
madt->header.revision = ACPI_2_0_MADT_REVISION;
- strncpy(madt->header.oem_id, ACPI_OEM_ID, 6);
- strncpy(madt->header.oem_table_id, ACPI_OEM_TABLE_ID, 8);
+ fixed_strcpy(madt->header.oem_id, ACPI_OEM_ID);
+ fixed_strcpy(madt->header.oem_table_id, ACPI_OEM_TABLE_ID);
madt->header.oem_revision = ACPI_OEM_REVISION;
madt->header.creator_id = ACPI_CREATOR_ID;
madt->header.creator_revision = ACPI_CREATOR_REVISION;
@@ -131,8 +131,8 @@ int construct_hpet(struct acpi_20_hpet *hpet)
memset(hpet, 0, sizeof(*hpet));
hpet->header.signature = ACPI_2_0_HPET_SIGNATURE;
hpet->header.revision = ACPI_2_0_HPET_REVISION;
- strncpy(hpet->header.oem_id, ACPI_OEM_ID, 6);
- strncpy(hpet->header.oem_table_id, ACPI_OEM_TABLE_ID, 8);
+ fixed_strcpy(hpet->header.oem_id, ACPI_OEM_ID);
+ fixed_strcpy(hpet->header.oem_table_id, ACPI_OEM_TABLE_ID);
hpet->header.oem_revision = ACPI_OEM_REVISION;
hpet->header.creator_id = ACPI_CREATOR_ID;
hpet->header.creator_revision = ACPI_CREATOR_REVISION;
@@ -150,6 +150,7 @@ int construct_processor_objects(uint8_t *buf)
{
static const char pdat[13] = { 0x5b, 0x83, 0x0b, 0x50, 0x52 };
static const char hex[] = "0123456789ABCDEF";
+ static const char pr_scope[] = "\\_PR_";
unsigned int i, length, nr_cpus = get_vcpu_nr();
struct acpi_header *hdr;
uint8_t *p = buf;
@@ -161,8 +162,8 @@ int construct_processor_objects(uint8_t *buf)
hdr = (struct acpi_header *)p;
hdr->signature = ASCII32('S','S','D','T');
hdr->revision = 2;
- strncpy(hdr->oem_id, ACPI_OEM_ID, 6);
- strncpy(hdr->oem_table_id, ACPI_OEM_TABLE_ID, 8);
+ fixed_strcpy(hdr->oem_id, ACPI_OEM_ID);
+ fixed_strcpy(hdr->oem_table_id, ACPI_OEM_TABLE_ID);
hdr->oem_revision = ACPI_OEM_REVISION;
hdr->creator_id = ACPI_CREATOR_ID;
hdr->creator_revision = ACPI_CREATOR_REVISION;
@@ -176,7 +177,7 @@ int construct_processor_objects(uint8_t *buf)
*p++ = 0x10;
/* PkgLength (includes length bytes!). */
- length = 1 + 5 + (nr_cpus * sizeof(pdat));
+ length = 1 + strlen(pr_scope) + (nr_cpus * sizeof(pdat));
if ( length <= 0x3f )
{
*p++ = length;
@@ -195,8 +196,8 @@ int construct_processor_objects(uint8_t *buf)
}
/* NameString */
- strncpy(p, "\\_PR_", 5);
- p += 5;
+ strncpy(p, pr_scope, strlen(pr_scope));
+ p += strlen(pr_scope);
/*
* 3. Processor Objects.
@@ -263,8 +264,8 @@ int construct_secondary_tables(uint8_t *buf, unsigned long *table_ptrs)
tcpa->header.signature = ACPI_2_0_TCPA_SIGNATURE;
tcpa->header.length = sizeof(*tcpa);
tcpa->header.revision = ACPI_2_0_TCPA_REVISION;
- strncpy(tcpa->header.oem_id, ACPI_OEM_ID, 6);
- strncpy(tcpa->header.oem_table_id, ACPI_OEM_TABLE_ID, 8);
+ fixed_strcpy(tcpa->header.oem_id, ACPI_OEM_ID);
+ fixed_strcpy(tcpa->header.oem_table_id, ACPI_OEM_TABLE_ID);
tcpa->header.oem_revision = ACPI_OEM_REVISION;
tcpa->header.creator_id = ACPI_CREATOR_ID;
tcpa->header.creator_revision = ACPI_CREATOR_REVISION;
@@ -291,6 +292,7 @@ int acpi_build_tables(uint8_t *buf)
struct acpi_20_rsdt *rsdt;
struct acpi_20_xsdt *xsdt;
struct acpi_20_fadt *fadt;
+ struct acpi_10_fadt *fadt_10;
struct acpi_20_facs *facs;
unsigned char *dsdt;
unsigned long secondary_tables[16];
@@ -304,6 +306,25 @@ int acpi_build_tables(uint8_t *buf)
memcpy(dsdt, &AmlCode, DsdtLen);
offset += align16(DsdtLen);
+ /*
+ * N.B. ACPI 1.0 operating systems may not handle FADT with revision 2
+ * or above properly, notably Windows 2000, which tries to copy FADT
+ * into a 116 bytes buffer thus causing an overflow. The solution is to
+ * link the higher revision FADT with the XSDT only and introduce a
+ * compatible revision 1 FADT that is linked with the RSDT. Refer to:
+ * http://www.acpi.info/presentations/S01USMOBS169_OS%20new.ppt
+ */
+ fadt_10 = (struct acpi_10_fadt *)&buf[offset];
+ memcpy(fadt_10, &Fadt, sizeof(struct acpi_10_fadt));
+ offset += align16(sizeof(struct acpi_10_fadt));
+ fadt_10->header.length = sizeof(struct acpi_10_fadt);
+ fadt_10->header.revision = ACPI_1_0_FADT_REVISION;
+ fadt_10->dsdt = (unsigned long)dsdt;
+ fadt_10->firmware_ctrl = (unsigned long)facs;
+ set_checksum(fadt_10,
+ offsetof(struct acpi_header, checksum),
+ sizeof(struct acpi_10_fadt));
+
fadt = (struct acpi_20_fadt *)&buf[offset];
memcpy(fadt, &Fadt, sizeof(struct acpi_20_fadt));
offset += align16(sizeof(struct acpi_20_fadt));
@@ -330,7 +351,7 @@ int acpi_build_tables(uint8_t *buf)
rsdt = (struct acpi_20_rsdt *)&buf[offset];
memcpy(rsdt, &Rsdt, sizeof(struct acpi_header));
- rsdt->entry[0] = (unsigned long)fadt;
+ rsdt->entry[0] = (unsigned long)fadt_10;
for ( i = 0; secondary_tables[i]; i++ )
rsdt->entry[i+1] = secondary_tables[i];
rsdt->header.length = sizeof(struct acpi_header) + (i+1)*sizeof(uint32_t);
diff --git a/tools/firmware/hvmloader/hvmloader.c b/tools/firmware/hvmloader/hvmloader.c
index bed26597ca..beabd06248 100644
--- a/tools/firmware/hvmloader/hvmloader.c
+++ b/tools/firmware/hvmloader/hvmloader.c
@@ -29,7 +29,6 @@
#include "pci_regs.h"
#include <xen/version.h>
#include <xen/hvm/params.h>
-#include <xen/hvm/e820.h>
/* memory map */
#define HYPERCALL_PHYSICAL_ADDRESS 0x00080000
@@ -38,23 +37,53 @@
#define VMXASSIST_PHYSICAL_ADDRESS 0x000D0000
#define ROMBIOS_PHYSICAL_ADDRESS 0x000F0000
-/* invoke SVM's paged realmode support */
-#define SVM_VMMCALL_RESET_TO_REALMODE 0x80000001
-
-/*
- * C runtime start off
- */
asm(
" .text \n"
" .globl _start \n"
"_start: \n"
+ /* C runtime kickoff. */
" cld \n"
" cli \n"
- " lgdt gdt_desr \n"
- " movl $stack_top, %esp \n"
- " movl %esp, %ebp \n"
+ " movl $stack_top,%esp \n"
+ " movl %esp,%ebp \n"
" call main \n"
- " ud2 \n"
+ /* Relocate real-mode trampoline to 0x0. */
+ " mov $trampoline_start,%esi \n"
+ " xor %edi,%edi \n"
+ " mov $trampoline_end,%ecx \n"
+ " sub %esi,%ecx \n"
+ " rep movsb \n"
+ /* Load real-mode compatible segment state (base 0x0000, limit 0xffff). */
+ " lgdt gdt_desr \n"
+ " mov $0x0010,%ax \n"
+ " mov %ax,%ds \n"
+ " mov %ax,%es \n"
+ " mov %ax,%fs \n"
+ " mov %ax,%gs \n"
+ " mov %ax,%ss \n"
+ /* Initialise all 32-bit GPRs to zero. */
+ " xor %eax,%eax \n"
+ " xor %ebx,%ebx \n"
+ " xor %ecx,%ecx \n"
+ " xor %edx,%edx \n"
+ " xor %esp,%esp \n"
+ " xor %ebp,%ebp \n"
+ " xor %esi,%esi \n"
+ " xor %edi,%edi \n"
+ /* Enter real mode, reload all segment registers and IDT. */
+ " ljmp $0x8,$0x0 \n"
+ "trampoline_start: .code16 \n"
+ " mov %eax,%cr0 \n"
+ " ljmp $0,$1f-trampoline_start\n"
+ "1: mov %ax,%ds \n"
+ " mov %ax,%es \n"
+ " mov %ax,%fs \n"
+ " mov %ax,%gs \n"
+ " mov %ax,%ss \n"
+ " lidt 1f-trampoline_start \n"
+ " ljmp $0xf000,$0xfff0 \n"
+ "1: .word 0x3ff,0,0 \n"
+ "trampoline_end: .code32 \n"
" \n"
"gdt_desr: \n"
" .word gdt_end - gdt - 1 \n"
@@ -63,8 +92,8 @@ asm(
" .align 8 \n"
"gdt: \n"
" .quad 0x0000000000000000 \n"
- " .quad 0x00CF92000000FFFF \n"
- " .quad 0x00CF9A000000FFFF \n"
+ " .quad 0x00009a000000ffff \n" /* Ring 0 code, base 0 limit 0xffff */
+ " .quad 0x000092000000ffff \n" /* Ring 0 data, base 0 limit 0xffff */
"gdt_end: \n"
" \n"
" .bss \n"
@@ -84,19 +113,6 @@ cirrus_check(void)
}
static int
-vmmcall(int function, int edi, int esi, int edx, int ecx, int ebx)
-{
- int eax;
-
- __asm__ __volatile__ (
- ".byte 0x0F,0x01,0xD9"
- : "=a" (eax)
- : "a"(function),
- "b"(ebx), "c"(ecx), "d"(edx), "D"(edi), "S"(esi) );
- return eax;
-}
-
-static int
check_amd(void)
{
char id[12];
@@ -280,25 +296,57 @@ static void pci_setup(void)
}
}
-static
-int must_load_nic(void)
+/*
+ * If the network card is in the boot order, load the Etherboot option ROM.
+ * Read the boot order bytes from CMOS and check if any of them are 0x4.
+ */
+static int must_load_nic(void)
{
- /* If the network card is in the boot order, load the Etherboot
- * option ROM. Read the boot order bytes from CMOS and check
- * if any of them are 0x4. */
uint8_t boot_order;
- /* Read CMOS register 0x3d (boot choices 0 and 1) */
- outb(0x70, 0x3d);
- boot_order = inb(0x71);
- if ( (boot_order & 0xf) == 0x4 || (boot_order & 0xf0) == 0x40 )
- return 1;
- /* Read CMOS register 0x38 (boot choice 2 and FDD test flag) */
- outb(0x70, 0x38);
- boot_order = inb(0x71);
- if ( (boot_order & 0xf0) == 0x40 )
+ /* Read CMOS register 0x3d (boot choices 0 and 1). */
+ boot_order = cmos_inb(0x3d);
+ if ( ((boot_order & 0xf) == 0x4) || ((boot_order & 0xf0) == 0x40) )
return 1;
- return 0;
+
+ /* Read CMOS register 0x38 (boot choice 2 and FDD test flag). */
+ boot_order = cmos_inb(0x38);
+ return ((boot_order & 0xf0) == 0x40);
+}
+
+/* Replace possibly erroneous memory-size CMOS fields with correct values. */
+static void cmos_write_memory_size(void)
+{
+ struct e820entry *map = E820_MAP;
+ int i, nr = *E820_MAP_NR;
+ uint32_t base_mem = 640, ext_mem = 0, alt_mem = 0;
+
+ for ( i = 0; i < nr; i++ )
+ if ( (map[i].addr >= 0x100000) && (map[i].type == E820_RAM) )
+ break;
+
+ if ( i != nr )
+ {
+ alt_mem = ext_mem = map[i].addr + map[i].size;
+ ext_mem = (ext_mem > 0x0100000) ? (ext_mem - 0x0100000) >> 10 : 0;
+ if ( ext_mem > 0xffff )
+ ext_mem = 0xffff;
+ alt_mem = (alt_mem > 0x1000000) ? (alt_mem - 0x1000000) >> 16 : 0;
+ }
+
+ /* All BIOSes: conventional memory (640kB). */
+ cmos_outb(0x15, (uint8_t)(base_mem >> 0));
+ cmos_outb(0x16, (uint8_t)(base_mem >> 8));
+
+ /* All BIOSes: extended memory (1kB chunks above 1MB). */
+ cmos_outb(0x17, (uint8_t)( ext_mem >> 0));
+ cmos_outb(0x18, (uint8_t)( ext_mem >> 8));
+ cmos_outb(0x30, (uint8_t)( ext_mem >> 0));
+ cmos_outb(0x31, (uint8_t)( ext_mem >> 8));
+
+ /* Some BIOSes: alternative extended memory (64kB chunks above 16MB). */
+ cmos_outb(0x34, (uint8_t)( alt_mem >> 0));
+ cmos_outb(0x35, (uint8_t)( alt_mem >> 8));
}
int main(void)
@@ -349,13 +397,9 @@ int main(void)
ASSERT((ACPI_PHYSICAL_ADDRESS + acpi_sz) <= 0xF0000);
}
- if ( check_amd() )
- {
- /* AMD implies this is SVM */
- printf("SVM go ...\n");
- vmmcall(SVM_VMMCALL_RESET_TO_REALMODE, 0, 0, 0, 0, 0);
- }
- else
+ cmos_write_memory_size();
+
+ if ( !check_amd() )
{
printf("Loading VMXAssist ...\n");
memcpy((void *)VMXASSIST_PHYSICAL_ADDRESS,
@@ -368,7 +412,7 @@ int main(void)
);
}
- printf("Failed to invoke ROMBIOS\n");
+ printf("Invoking ROMBIOS ...\n");
return 0;
}
diff --git a/tools/firmware/hvmloader/smbios.c b/tools/firmware/hvmloader/smbios.c
index df25999c3a..c9a4992e4c 100644
--- a/tools/firmware/hvmloader/smbios.c
+++ b/tools/firmware/hvmloader/smbios.c
@@ -22,7 +22,6 @@
#include <stdint.h>
#include <xen/version.h>
-#include <xen/hvm/e820.h>
#include "smbios.h"
#include "smbios_types.h"
#include "util.h"
@@ -129,47 +128,32 @@ write_smbios_tables(void *start,
return (size_t)((char *)p - (char *)start);
}
-/* This tries to figure out how much pseudo-physical memory (in MB)
- is allocated to the current domU.
-
- It iterates through the e820 table, adding up the 'usable' and
- 'reserved' entries and rounding up to the nearest MB.
-
- The e820map is not at e820 in hvmloader, so this uses the
- E820_MAP_* constants from e820.h to pick it up where libxenguest
- left it.
- */
+/* Calculate how much pseudo-physical memory (in MB) is allocated to us. */
static uint64_t
get_memsize(void)
{
- struct e820entry *map = NULL;
- uint8_t num_entries = 0;
+ struct e820entry *map = E820_MAP;
+ uint8_t num_entries = *E820_MAP_NR;
uint64_t memsize = 0;
- uint8_t i;
-
- map = (struct e820entry *) (E820_MAP_PAGE + E820_MAP_OFFSET);
- num_entries = *((uint8_t *) (E820_MAP_PAGE + E820_MAP_NR_OFFSET));
-
- /* walk through e820map, ignoring any entries that aren't marked
- as usable or reserved. */
+ int i;
+ /*
+ * Walk through e820map, ignoring any entries that aren't marked
+ * as usable or reserved.
+ */
for ( i = 0; i < num_entries; i++ )
{
- if (map->type == E820_RAM || map->type == E820_RESERVED)
+ if ( (map->type == E820_RAM) || (map->type == E820_RESERVED) )
memsize += map->size;
map++;
}
- /* Round up to the nearest MB. The user specifies domU
- pseudo-physical memory in megabytes, so not doing this
- could easily lead to reporting one less MB than the user
- specified. */
- if ( memsize & ((1<<20)-1) )
- memsize = (memsize >> 20) + 1;
- else
- memsize = (memsize >> 20);
-
- return memsize;
+ /*
+ * Round up to the nearest MB. The user specifies domU pseudo-physical
+ * memory in megabytes, so not doing this could easily lead to reporting
+ * one less MB than the user specified.
+ */
+ return (memsize + (1 << 20) - 1) >> 20;
}
void
diff --git a/tools/firmware/hvmloader/util.c b/tools/firmware/hvmloader/util.c
index ce32a9001e..2f5f23d1e5 100644
--- a/tools/firmware/hvmloader/util.c
+++ b/tools/firmware/hvmloader/util.c
@@ -27,17 +27,17 @@
void outb(uint16_t addr, uint8_t val)
{
- __asm__ __volatile__ ( "outb %%al, %%dx" :: "d"(addr), "a"(val) );
+ __asm__ __volatile__ ( "outb %%al, %%dx" : : "d" (addr), "a" (val) );
}
void outw(uint16_t addr, uint16_t val)
{
- __asm__ __volatile__ ( "outw %%ax, %%dx" :: "d"(addr), "a"(val) );
+ __asm__ __volatile__ ( "outw %%ax, %%dx" : : "d" (addr), "a" (val) );
}
void outl(uint16_t addr, uint32_t val)
{
- __asm__ __volatile__ ( "outl %%eax, %%dx" :: "d"(addr), "a"(val) );
+ __asm__ __volatile__ ( "outl %%eax, %%dx" : : "d" (addr), "a" (val) );
}
uint8_t inb(uint16_t addr)
@@ -61,6 +61,18 @@ uint32_t inl(uint16_t addr)
return val;
}
+uint8_t cmos_inb(uint8_t idx)
+{
+ outb(0x70, idx);
+ return inb(0x71);
+}
+
+void cmos_outb(uint8_t idx, uint8_t val)
+{
+ outb(0x70, idx);
+ outb(0x71, val);
+}
+
char *itoa(char *a, unsigned int i)
{
unsigned int _i = i, x = 0;
@@ -280,9 +292,6 @@ uuid_to_string(char *dest, uint8_t *uuid)
*p = '\0';
}
-#include <xen/hvm/e820.h>
-#define E820_MAP_NR ((unsigned char *)E820_MAP_PAGE + E820_MAP_NR_OFFSET)
-#define E820_MAP ((struct e820entry *)(E820_MAP_PAGE + E820_MAP_OFFSET))
uint64_t e820_malloc(uint64_t size, uint32_t type, uint64_t mask)
{
uint64_t addr = 0;
diff --git a/tools/firmware/hvmloader/util.h b/tools/firmware/hvmloader/util.h
index 368f93ddda..cc1f42dba9 100644
--- a/tools/firmware/hvmloader/util.h
+++ b/tools/firmware/hvmloader/util.h
@@ -26,6 +26,10 @@ uint8_t inb(uint16_t addr);
uint16_t inw(uint16_t addr);
uint32_t inl(uint16_t addr);
+/* CMOS access */
+uint8_t cmos_inb(uint8_t idx);
+void cmos_outb(uint8_t idx, uint8_t val);
+
/* APIC access */
uint32_t ioapic_read(uint32_t reg);
void ioapic_write(uint32_t reg, uint32_t val);
@@ -78,9 +82,13 @@ int vprintf(const char *fmt, va_list ap);
/* Allocate region of specified type in the e820 table. */
uint64_t e820_malloc(uint64_t size, uint32_t type, uint64_t mask);
-/* Prepare the 32bit BIOS */
-int highbios_setup(void);
+/* General e820 access. */
+#include <xen/hvm/e820.h>
+#define E820_MAP_NR ((unsigned char *)E820_MAP_PAGE + E820_MAP_NR_OFFSET)
+#define E820_MAP ((struct e820entry *)(E820_MAP_PAGE + E820_MAP_OFFSET))
+/* Prepare the 32bit BIOS */
+void highbios_setup(void);
#define isdigit(c) ((c) >= '0' && (c) <= '9')
diff --git a/tools/firmware/rombios/32bit/tcgbios/tcgbios.c b/tools/firmware/rombios/32bit/tcgbios/tcgbios.c
index dc1a9e0d51..e4483982c4 100644
--- a/tools/firmware/rombios/32bit/tcgbios/tcgbios.c
+++ b/tools/firmware/rombios/32bit/tcgbios/tcgbios.c
@@ -95,13 +95,15 @@ struct ptti_cust *TCG_CommandList[] = {
};
/* local function prototypes */
-static void sha1(const unsigned char *data, uint32_t length, unsigned char *hash);
+static void sha1(const unsigned char *data, uint32_t length,
+ unsigned char *hash);
static uint32_t TCG_ShutdownPreBootInterface(uint32_t ebx);
static uint32_t HashAll32(struct hai *hai, unsigned char *hash,
uint32_t magic, uint32_t ecx, uint32_t edx);
static uint32_t HashLogExtendEvent32(struct hleei_short *hleei_s,
struct hleeo *hleeo,
- uint32_t magic, uint32_t ecx, uint32_t edx);
+ uint32_t magic, uint32_t ecx,
+ uint32_t edx);
static uint32_t HashLogEvent32(struct hlei *hlei, struct hleo *hleo,
uint32_t ebx, uint32_t ecx, uint32_t edx);
static uint32_t PassThroughToTPM32(struct pttti *pttti, struct pttto *pttto,
@@ -181,8 +183,7 @@ uint32_t MA_InitTPM(uint16_t startupcode)
}
static
-uint32_t MA_Transmit(unsigned char *cmdbuffer,
- unsigned char *respbuffer,
+uint32_t MA_Transmit(unsigned char *cmdbuffer, unsigned char *respbuffer,
uint32_t respbufferlen)
{
uint32_t rc = 0;
@@ -289,15 +290,14 @@ void tcpa_acpi_init(void)
uint32_t ctr = 0;
/* get RSDT from RSDP */
rsdt = (struct acpi_20_rsdt *)rsdp->rsdt_address;
- /* rsdt may be anywhere in 32bit space */
length = rsdt->header.length;
off = 36;
while ((off + 3) < length) {
/* try all pointers to structures */
tcpa = (struct acpi_20_tcpa *)rsdt->entry[ctr];
/* valid TCPA ACPI table ? */
- if (ACPI_2_0_TCPA_SIGNATURE == tcpa->header.signature &&
- acpi_validate_entry(&tcpa->header) == 0) {
+ if (ACPI_2_0_TCPA_SIGNATURE == tcpa->header.signature
+ && acpi_validate_entry(&tcpa->header) == 0) {
found = 1;
break;
}
@@ -311,7 +311,6 @@ void tcpa_acpi_init(void)
tcpa = 0;
}
- /* initialize the TCPA part of the EBDA with our data */
tcpa_acpi.tcpa_ptr = tcpa;
tcpa_acpi.lasa_last_ptr = 0;
tcpa_acpi.entry_count = 0;
@@ -748,9 +747,7 @@ void tcpa_measure_post(Bit32u from, Bit32u to)
}
static
-uint32_t SendCommand32(uint32_t idx,
- struct pttto *pttto,
- uint32_t size_ptto)
+uint32_t SendCommand32(uint32_t idx, struct pttto *pttto, uint32_t size_ptto)
{
uint32_t rc = 0;
struct pttti *pttti = (struct pttti *)TCG_CommandList[idx];
@@ -796,7 +793,8 @@ uint32_t tcpa_initialize_tpm(uint32_t physpres)
uint32_t pttto_size = sizeof(_pttto);
if (rc == 0) {
- rc = SendCommand32(IDX_CMD_TPM_Startup_0x01, pttto, pttto_size);
+ rc = SendCommand32(IDX_CMD_TPM_Startup_0x01, pttto,
+ pttto_size);
}
if (rc == 0 && physpres != 0) {
@@ -884,11 +882,8 @@ uint32_t _TCG_TPM_Extend(unsigned char *hash, uint32_t pcrindex)
static
-uint32_t HashLogExtendEvent32(struct hleei_short *hleei_s,
- struct hleeo *hleeo,
- uint32_t magic,
- uint32_t ecx,
- uint32_t edx)
+uint32_t HashLogExtendEvent32(struct hleei_short *hleei_s, struct hleeo *hleeo,
+ uint32_t magic, uint32_t ecx, uint32_t edx)
{
uint32_t rc = 0;
uint16_t size;
@@ -978,11 +973,8 @@ uint32_t HashLogExtendEvent32(struct hleei_short *hleei_s,
static
-uint32_t PassThroughToTPM32(struct pttti *pttti,
- struct pttto *pttto,
- uint32_t magic,
- uint32_t ecx,
- uint32_t edx)
+uint32_t PassThroughToTPM32(struct pttti *pttti, struct pttto *pttto,
+ uint32_t magic, uint32_t ecx, uint32_t edx)
{
uint32_t rc = 0;
uint8_t *cmd32;
@@ -1047,9 +1039,7 @@ uint32_t TCG_ShutdownPreBootInterface(uint32_t ebx)
static
uint32_t HashLogEvent32(struct hlei *hlei, struct hleo *hleo,
- uint32_t ebx,
- uint32_t ecx,
- uint32_t edx)
+ uint32_t ebx, uint32_t ecx, uint32_t edx)
{
uint32_t rc = 0;
uint16_t size;
@@ -1144,9 +1134,7 @@ uint32_t HashLogEvent32(struct hlei *hlei, struct hleo *hleo,
static
uint32_t HashAll32(struct hai *hai, unsigned char *hash,
- uint32_t magic,
- uint32_t ecx,
- uint32_t edx)
+ uint32_t magic, uint32_t ecx, uint32_t edx)
{
uint32_t rc = 0;
@@ -1187,9 +1175,7 @@ uint32_t HashAll32(struct hai *hai, unsigned char *hash,
static
uint32_t TSS32(struct ti *ti, struct to *to,
- uint32_t ebx,
- uint32_t ecx,
- uint32_t edx)
+ uint32_t ebx, uint32_t ecx, uint32_t edx)
{
uint32_t rc = 0;
if (TCG_IsShutdownPreBootInterface() == 0) {
@@ -1209,11 +1195,11 @@ uint32_t TSS32(struct ti *ti, struct to *to,
static
uint32_t CompactHashLogExtendEvent32(unsigned char *buffer,
- uint32_t info,
- uint32_t magic,
- uint32_t length,
- uint32_t pcrindex,
- uint32_t *edx_ptr)
+ uint32_t info,
+ uint32_t magic,
+ uint32_t length,
+ uint32_t pcrindex,
+ uint32_t *edx_ptr)
{
uint32_t rc = 0;
struct hleeo hleeo;
@@ -1356,9 +1342,7 @@ void sha1_do(sha1_ctx *ctx, const unsigned char *data32, uint32_t length)
/* treat data in 64-byte chunks */
for (offset = 0; length - offset >= 64; offset += 64) {
- /* copy into the 'w' array */
memcpy(w, data32 + offset, 64);
- /* hash the block in the 'w' array */
sha1_block((uint32_t *)w, ctx);
bits += (64 * 8);
}
@@ -1408,7 +1392,8 @@ void sha1(const unsigned char *data, uint32_t length, unsigned char *hash)
}
-uint32_t TCGInterruptHandler(pushad_regs_t *regs, uint32_t esds, uint32_t flags_ptr)
+uint32_t TCGInterruptHandler(pushad_regs_t *regs, uint32_t esds,
+ uint32_t flags_ptr)
{
uint16_t DS = esds >> 16;
uint16_t ES = esds & 0xffff;
@@ -1435,7 +1420,6 @@ uint32_t TCGInterruptHandler(pushad_regs_t *regs, uint32_t esds, uint32_t flags_
}
}
break;
-
case 0x01:
regs->u.r32.eax =
HashLogExtendEvent32((struct hleei_short*)
diff --git a/tools/firmware/rombios/32bitgateway.c b/tools/firmware/rombios/32bitgateway.c
index 98f61be6e4..4da5a39c45 100644
--- a/tools/firmware/rombios/32bitgateway.c
+++ b/tools/firmware/rombios/32bitgateway.c
@@ -153,26 +153,17 @@ realmode_gdtdesc: ;to be used in real mode
switch_to_realmode:
; Implementation of switching from protected mode to real mode
- ; restores all registers and prepares cs, es, ds, ss to be used
- ; in real mode
+ ; prepares cs, es, ds, ss to be used in real mode
+ ; spills eax
START_PM_CODE
; need to fix up the stack to return in 16 bit mode
; currently the 32 bit return address is on the stack
- push bp ;pop@A1
- mov bp, sp
- push eax ;pop@X
-
- mov eax, [bp] ; return address low 16bits
- ; and 'bp' are being moved
- mov 2[bp], eax
-
- pop eax ;@X
- add sp, #2 ; adjust stack for 'lost' bytes
+ pop eax
+ push ax
- push eax ;pop@1
- push bx ;pop@2
- push si ;pop@3
+ push bx ;pop@1
+ push si ;pop@2
call _ebda_ss_offset32 ; get the offset of the ss
mov bx, ax ; entry within the ebda.
@@ -229,10 +220,8 @@ switch_to_realmode_goon_2:
sti ; allow interrupts
- pop si ;@3
- pop bx ;@2
- pop eax ;@1
- pop bp ;@A1
+ pop si ;@2
+ pop bx ;@1
ret
diff --git a/tools/firmware/rombios/rombios.c b/tools/firmware/rombios/rombios.c
index 7b6ef8062d..eb288a80fa 100644
--- a/tools/firmware/rombios/rombios.c
+++ b/tools/firmware/rombios/rombios.c
@@ -4196,178 +4196,86 @@ ASM_END
case 0xe8:
switch(regs.u.r8.al)
{
- case 0x20: // coded by osmaker aka K.J.
- if(regs.u.r32.edx == 0x534D4150) /* SMAP */
- {
-#ifdef HVMASSIST
- if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
- Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
-
- if (regs.u.r16.bx + 0x14 <= e820_table_size) {
- memcpyb(ES, regs.u.r16.di,
- 0xe000, 0x10 + regs.u.r16.bx, 0x14);
- }
- regs.u.r32.ebx += 0x14;
- if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
- regs.u.r32.ebx = 0;
- regs.u.r32.eax = 0x534D4150;
- regs.u.r32.ecx = 0x14;
- CLEAR_CF();
- return;
- } else if (regs.u.r16.bx == 1) {
- extended_memory_size = inb_cmos(0x35);
- extended_memory_size <<= 8;
- extended_memory_size |= inb_cmos(0x34);
- extended_memory_size *= 64;
- if (extended_memory_size > 0x3bc000) // greater than EFF00000???
- {
- extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
- }
- extended_memory_size *= 1024;
- extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
-
- if (extended_memory_size <= 15728640)
- {
- extended_memory_size = inb_cmos(0x31);
- extended_memory_size <<= 8;
- extended_memory_size |= inb_cmos(0x30);
- extended_memory_size *= 1024;
- }
-
- write_word(ES, regs.u.r16.di, 0x0000);
- write_word(ES, regs.u.r16.di+2, 0x0010);
- write_word(ES, regs.u.r16.di+4, 0x0000);
- write_word(ES, regs.u.r16.di+6, 0x0000);
-
- write_word(ES, regs.u.r16.di+8, extended_memory_size);
- extended_memory_size >>= 16;
- write_word(ES, regs.u.r16.di+10, extended_memory_size);
- extended_memory_size >>= 16;
- write_word(ES, regs.u.r16.di+12, extended_memory_size);
- extended_memory_size >>= 16;
- write_word(ES, regs.u.r16.di+14, extended_memory_size);
-
- write_word(ES, regs.u.r16.di+16, 0x1);
- write_word(ES, regs.u.r16.di+18, 0x0);
-
- regs.u.r32.ebx = 0;
- regs.u.r32.eax = 0x534D4150;
- regs.u.r32.ecx = 0x14;
- CLEAR_CF();
- return;
- } else { /* AX=E820, DX=534D4150, BX unrecognized */
- goto int15_unimplemented;
- }
-#else
- switch(regs.u.r16.bx)
- {
- case 0:
- write_word(ES, regs.u.r16.di, 0x00);
- write_word(ES, regs.u.r16.di+2, 0x00);
- write_word(ES, regs.u.r16.di+4, 0x00);
- write_word(ES, regs.u.r16.di+6, 0x00);
-
- write_word(ES, regs.u.r16.di+8, 0xFC00);
- write_word(ES, regs.u.r16.di+10, 0x0009);
- write_word(ES, regs.u.r16.di+12, 0x0000);
- write_word(ES, regs.u.r16.di+14, 0x0000);
-
- write_word(ES, regs.u.r16.di+16, 0x1);
- write_word(ES, regs.u.r16.di+18, 0x0);
-
- regs.u.r32.ebx = 1;
-
- regs.u.r32.eax = 0x534D4150;
- regs.u.r32.ecx = 0x14;
- CLEAR_CF();
- return;
- break;
- case 1:
- extended_memory_size = inb_cmos(0x35);
- extended_memory_size <<= 8;
- extended_memory_size |= inb_cmos(0x34);
- extended_memory_size *= 64;
- if(extended_memory_size > 0x3bc000) // greater than EFF00000???
- {
- extended_memory_size = 0x3bc000; // everything after this is reserved memory until we get to 0x100000000
- }
- extended_memory_size *= 1024;
- extended_memory_size += 15728640; // make up for the 16mb of memory that is chopped off
-
- if(extended_memory_size <= 15728640)
- {
- extended_memory_size = inb_cmos(0x31);
- extended_memory_size <<= 8;
- extended_memory_size |= inb_cmos(0x30);
- extended_memory_size *= 1024;
- }
-
- write_word(ES, regs.u.r16.di, 0x0000);
- write_word(ES, regs.u.r16.di+2, 0x0010);
- write_word(ES, regs.u.r16.di+4, 0x0000);
- write_word(ES, regs.u.r16.di+6, 0x0000);
-
- write_word(ES, regs.u.r16.di+8, extended_memory_size);
- extended_memory_size >>= 16;
- write_word(ES, regs.u.r16.di+10, extended_memory_size);
- extended_memory_size >>= 16;
- write_word(ES, regs.u.r16.di+12, extended_memory_size);
- extended_memory_size >>= 16;
- write_word(ES, regs.u.r16.di+14, extended_memory_size);
-
- write_word(ES, regs.u.r16.di+16, 0x1);
- write_word(ES, regs.u.r16.di+18, 0x0);
-
- regs.u.r32.ebx = 0;
- regs.u.r32.eax = 0x534D4150;
- regs.u.r32.ecx = 0x14;
- CLEAR_CF();
- return;
- break;
- default: /* AX=E820, DX=534D4150, BX unrecognized */
- goto int15_unimplemented;
+ case 0x20: {
+ Bit16u e820_table_size = read_word(0xe000, 0x8) * 0x14;
+
+ if (regs.u.r32.edx != 0x534D4150) /* SMAP */
+ goto int15_unimplemented;
+
+ if ((regs.u.r16.bx / 0x14) * 0x14 == regs.u.r16.bx) {
+ if (regs.u.r16.bx + 0x14 <= e820_table_size)
+ memcpyb(ES, regs.u.r16.di,
+ 0xe000, 0x10 + regs.u.r16.bx, 0x14);
+ regs.u.r32.ebx += 0x14;
+ if ((regs.u.r32.ebx + 0x14 - 1) > e820_table_size)
+ regs.u.r32.ebx = 0;
+ } else if (regs.u.r16.bx == 1) {
+ Bit32u base, type;
+ Bit16u off;
+ for (off = 0; off < e820_table_size; off += 0x14) {
+ base = read_dword(0xe000, 0x10 + off);
+ type = read_dword(0xe000, 0x20 + off);
+ if ((base >= 0x100000) && (type == 1))
break;
}
-#endif
- } else {
- // if DX != 0x534D4150)
- goto int15_unimplemented;
- }
+ if (off == e820_table_size) {
+ SET_CF();
+ break;
+ }
+ memcpyb(ES, regs.u.r16.di, 0xe000, 0x10 + off, 0x14);
+ regs.u.r32.ebx = 0;
+ } else { /* AX=E820, DX=534D4150, BX unrecognized */
+ goto int15_unimplemented;
+ }
+
+ regs.u.r32.eax = 0x534D4150;
+ regs.u.r32.ecx = 0x14;
+ CLEAR_CF();
break;
+ }
- case 0x01:
- // do we have any reason to fail here ?
- CLEAR_CF();
+ case 0x01: {
+ Bit16u off, e820_table_size = read_word(0xe000, 0x8) * 0x14;
+ Bit32u base, type, size;
- // my real system sets ax and bx to 0
- // this is confirmed by Ralph Brown list
- // but syslinux v1.48 is known to behave
- // strangely if ax is set to 0
- // regs.u.r16.ax = 0;
- // regs.u.r16.bx = 0;
+ // do we have any reason to fail here ?
+ CLEAR_CF();
- // Get the amount of extended memory (above 1M)
- regs.u.r8.cl = inb_cmos(0x30);
- regs.u.r8.ch = inb_cmos(0x31);
+ // Get the amount of extended memory (above 1M)
+ regs.u.r8.cl = inb_cmos(0x30);
+ regs.u.r8.ch = inb_cmos(0x31);
- // limit to 15M
- if(regs.u.r16.cx > 0x3c00)
- {
- regs.u.r16.cx = 0x3c00;
- }
+ // limit to 15M
+ if (regs.u.r16.cx > (15*1024))
+ regs.u.r16.cx = 15*1024;
+
+ // Find first RAM E820 entry >= 1MB.
+ for (off = 0; off < e820_table_size; off += 0x14) {
+ base = read_dword(0xe000, 0x10 + off);
+ type = read_dword(0xe000, 0x20 + off);
+ if ((base >= 0x100000) && (type == 1))
+ break;
+ }
- // Get the amount of extended memory above 16M in 64k blocs
- regs.u.r8.dl = inb_cmos(0x34);
- regs.u.r8.dh = inb_cmos(0x35);
+ // If there is RAM above 16MB, return amount in 64kB chunks.
+ regs.u.r16.dx = 0;
+ if (off != e820_table_size) {
+ size = base + read_dword(0xe000, 0x18 + off);
+ if (size > 0x1000000) {
+ size -= 0x1000000;
+ regs.u.r16.dx = (Bit16u)(size >> 16);
+ }
+ }
- // Set configured memory equal to extended memory
- regs.u.r16.ax = regs.u.r16.cx;
- regs.u.r16.bx = regs.u.r16.dx;
- break;
+ // Set configured memory equal to extended memory
+ regs.u.r16.ax = regs.u.r16.cx;
+ regs.u.r16.bx = regs.u.r16.dx;
+ break;
+ }
default: /* AH=0xE8?? but not implemented */
- goto int15_unimplemented;
- }
- break;
+ goto int15_unimplemented;
+ }
+ break;
int15_unimplemented:
// fall into the default
default:
@@ -7792,10 +7700,11 @@ ASM_END
bootdrv = (Bit8u)(status>>8);
bootseg = read_word(ebda_seg,&EbdaData->cdemu.load_segment);
- /* Canonicalize bootseg:bootip */
#if BX_TCGBIOS
tcpa_add_bootdevice((Bit32u)1L, (Bit32u)0L);
#endif
+
+ /* Canonicalize bootseg:bootip */
bootip = (bootseg & 0x0fff) << 4;
bootseg &= 0xf000;
break;
@@ -7812,8 +7721,6 @@ ASM_END
#if BX_TCGBIOS
tcpa_ipl((Bit32u)bootseg); /* specs: 8.2.3 steps 4 and 5 */
#endif
- /* Debugging info */
- printf("Booting from %x:%x\n", bootseg, bootip);
/* Jump to the boot vector */
ASM_START
diff --git a/tools/firmware/rombios/tcgbios.c b/tools/firmware/rombios/tcgbios.c
index c8f5af2853..de2066fd1d 100644
--- a/tools/firmware/rombios/tcgbios.c
+++ b/tools/firmware/rombios/tcgbios.c
@@ -228,6 +228,8 @@ int1a_function32(regs, ES, DS, FLAGS)
{
Bit16u rc;
+ BX_DEBUG_INT1A("int1a_32: AX=%04x\n", regs.u.r16.ax);
+
switch (regs.u.r8.ah) {
case 0xbb:
/*
@@ -256,8 +258,10 @@ int1a_function32(regs, ES, DS, FLAGS)
default:
SET_CF();
}
+ break;
default:
SET_CF();
break;
}
+ BX_DEBUG_INT1A("int1a_32: FLAGS=%04x\n", FLAGS);
}
diff --git a/tools/ioemu/hw/ide.c b/tools/ioemu/hw/ide.c
index c4db9fe738..274dd8f850 100644
--- a/tools/ioemu/hw/ide.c
+++ b/tools/ioemu/hw/ide.c
@@ -396,17 +396,41 @@ typedef struct PCIIDEState {
#ifdef DMA_MULTI_THREAD
+static pthread_t ide_dma_thread;
static int file_pipes[2];
static void ide_dma_loop(BMDMAState *bm);
static void dma_thread_loop(BMDMAState *bm);
+extern int suspend_requested;
static void *dma_thread_func(void* opaque)
{
BMDMAState* req;
-
- while (read(file_pipes[0], &req, sizeof(req))) {
- dma_thread_loop(req);
+ fd_set fds;
+ int rv, nfds = file_pipes[0] + 1;
+ struct timeval tm;
+
+ while (1) {
+
+ /* Wait at most a second for the pipe to become readable */
+ FD_ZERO(&fds);
+ FD_SET(file_pipes[0], &fds);
+ tm.tv_sec = 1;
+ tm.tv_usec = 0;
+ rv = select(nfds, &fds, NULL, NULL, &tm);
+
+ if (rv != 0) {
+ if (read(file_pipes[0], &req, sizeof(req)) == 0)
+ return NULL;
+ dma_thread_loop(req);
+ } else {
+ if (suspend_requested) {
+ /* Need to tidy up the DMA thread so that we don't end up
+ * finishing operations after the domain's ioreqs are
+ * drained and its state saved */
+ return NULL;
+ }
+ }
}
return NULL;
@@ -414,24 +438,41 @@ static void *dma_thread_func(void* opaque)
static void dma_create_thread(void)
{
- pthread_t tid;
int rt;
+ pthread_attr_t a;
if (pipe(file_pipes) != 0) {
fprintf(stderr, "create pipe failed\n");
exit(1);
}
- if ((rt = pthread_create(&tid, NULL, dma_thread_func, NULL))) {
+ if ((rt = pthread_attr_init(&a))
+ || (rt = pthread_attr_setdetachstate(&a, PTHREAD_CREATE_JOINABLE))) {
+ fprintf(stderr, "Oops, dma thread attr setup failed, errno=%d\n", rt);
+ exit(1);
+ }
+
+ if ((rt = pthread_create(&ide_dma_thread, &a, dma_thread_func, NULL))) {
fprintf(stderr, "Oops, dma thread creation failed, errno=%d\n", rt);
exit(1);
}
+}
- if ((rt = pthread_detach(tid))) {
- fprintf(stderr, "Oops, dma thread detachment failed, errno=%d\n", rt);
- exit(1);
+void ide_stop_dma_thread(void)
+{
+ int rc;
+ /* Make sure the IDE DMA thread is stopped */
+ if ( (rc = pthread_join(ide_dma_thread, NULL)) != 0 )
+ {
+ fprintf(stderr, "Oops, error collecting IDE DMA thread (%s)\n",
+ strerror(rc));
}
}
+
+#else
+void ide_stop_dma_thread(void)
+{
+}
#endif /* DMA_MULTI_THREAD */
#if defined(__ia64__)
diff --git a/tools/ioemu/hw/usb-hid.c b/tools/ioemu/hw/usb-hid.c
index 60849a4ed0..c7af3d65ab 100644
--- a/tools/ioemu/hw/usb-hid.c
+++ b/tools/ioemu/hw/usb-hid.c
@@ -517,6 +517,49 @@ static void usb_mouse_handle_destroy(USBDevice *dev)
qemu_free(s);
}
+void usb_mouse_save(QEMUFile *f, void *opaque)
+{
+ USBMouseState *s = (USBMouseState*)opaque;
+
+ qemu_put_be32s(f, &s->dx);
+ qemu_put_be32s(f, &s->dy);
+ qemu_put_be32s(f, &s->dz);
+ qemu_put_be32s(f, &s->buttons_state);
+ qemu_put_be32s(f, &s->x);
+ qemu_put_be32s(f, &s->y);
+ qemu_put_be32s(f, &s->kind);
+ qemu_put_be32s(f, &s->mouse_grabbed);
+ qemu_put_be32s(f, &s->status_changed);
+
+}
+
+int usb_mouse_load(QEMUFile *f, void *opaque, int version_id)
+{
+ USBMouseState *s = (USBMouseState*)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_be32s(f, &s->dx);
+ qemu_get_be32s(f, &s->dy);
+ qemu_get_be32s(f, &s->dz);
+ qemu_get_be32s(f, &s->buttons_state);
+ qemu_get_be32s(f, &s->x);
+ qemu_get_be32s(f, &s->y);
+ qemu_get_be32s(f, &s->kind);
+ qemu_get_be32s(f, &s->mouse_grabbed);
+ qemu_get_be32s(f, &s->status_changed);
+
+ if ( s->kind == USB_TABLET) {
+ fprintf(logfile, "usb_mouse_load:add usb_tablet_event.\n");
+ qemu_add_mouse_event_handler(usb_tablet_event, s, 1);
+ } else if ( s->kind == USB_MOUSE) {
+ fprintf(logfile, "usb_mouse_load:add usb_mouse_event.\n");
+ qemu_add_mouse_event_handler(usb_mouse_event, s, 0);
+ }
+}
+
+
USBDevice *usb_tablet_init(void)
{
USBMouseState *s;
@@ -536,6 +579,8 @@ USBDevice *usb_tablet_init(void)
pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
+ register_savevm("USB tablet dev", 0, 1, usb_mouse_save, usb_mouse_load, s);
+
return (USBDevice *)s;
}
@@ -558,5 +603,7 @@ USBDevice *usb_mouse_init(void)
pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse");
+ register_savevm("USB mouse dev", 0, 1, usb_mouse_save, usb_mouse_load, s);
+
return (USBDevice *)s;
}
diff --git a/tools/ioemu/hw/usb-ohci.c b/tools/ioemu/hw/usb-ohci.c
index e87d9da70a..a563262676 100644
--- a/tools/ioemu/hw/usb-ohci.c
+++ b/tools/ioemu/hw/usb-ohci.c
@@ -1186,5 +1186,7 @@ void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn)
qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach);
}
+ register_savevm("OHCI USB", 0, 1, generic_pci_save, generic_pci_load, ohci);
+
ohci_reset(ohci);
}
diff --git a/tools/ioemu/hw/usb-uhci.c b/tools/ioemu/hw/usb-uhci.c
index 7212c5e82d..46cff274cf 100644
--- a/tools/ioemu/hw/usb-uhci.c
+++ b/tools/ioemu/hw/usb-uhci.c
@@ -658,6 +658,50 @@ static void uhci_map(PCIDevice *pci_dev, int region_num,
register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
}
+void uhci_usb_save(QEMUFile *f, void *opaque)
+{
+ int i;
+ UHCIState *s = (UHCIState*)opaque;
+
+ qemu_put_be16s(f, &s->cmd);
+ qemu_put_be16s(f, &s->status);
+ qemu_put_be16s(f, &s->intr);
+ qemu_put_be16s(f, &s->frnum);
+ qemu_put_be32s(f, &s->fl_base_addr);
+ qemu_put_8s(f, &s->sof_timing);
+ qemu_put_8s(f, &s->status2);
+
+ for(i = 0; i < NB_PORTS; i++) {
+ qemu_put_be16s(f, &s->ports[i].ctrl);
+ }
+
+ qemu_put_timer(f, s->frame_timer);
+}
+
+int uhci_usb_load(QEMUFile *f, void *opaque, int version_id)
+{
+ int i;
+ UHCIState *s = (UHCIState*)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_be16s(f, &s->cmd);
+ qemu_get_be16s(f, &s->status);
+ qemu_get_be16s(f, &s->intr);
+ qemu_get_be16s(f, &s->frnum);
+ qemu_get_be32s(f, &s->fl_base_addr);
+ qemu_get_8s(f, &s->sof_timing);
+ qemu_get_8s(f, &s->status2);
+
+ for(i = 0; i < NB_PORTS; i++) {
+ qemu_get_be16s(f, &s->ports[i].ctrl);
+ }
+
+ qemu_get_timer(f, s->frame_timer);
+
+}
+
void usb_uhci_init(PCIBus *bus, int devfn)
{
UHCIState *s;
@@ -693,4 +737,8 @@ void usb_uhci_init(PCIBus *bus, int devfn)
to rely on this. */
pci_register_io_region(&s->dev, 4, 0x20,
PCI_ADDRESS_SPACE_IO, uhci_map);
+
+ register_savevm("UHCI_usb_pci", 0, 1, generic_pci_save, generic_pci_load, s);
+
+ register_savevm("UHCI usb controller", 0, 1, uhci_usb_save, uhci_usb_load, s);
}
diff --git a/tools/ioemu/hw/usb.c b/tools/ioemu/hw/usb.c
index 34aac5fa9b..e4166518b0 100644
--- a/tools/ioemu/hw/usb.c
+++ b/tools/ioemu/hw/usb.c
@@ -191,3 +191,43 @@ int set_usb_string(uint8_t *buf, const char *str)
}
return q - buf;
}
+
+void generic_usb_save(QEMUFile* f, void *opaque)
+{
+ USBDevice *s = (USBDevice*)opaque;
+
+ qemu_put_be32s(f, &s->speed);
+ qemu_put_8s(f, &s->addr);
+ qemu_put_be32s(f, &s->state);
+
+ qemu_put_buffer(f, s->setup_buf, 8);
+ qemu_put_buffer(f, s->data_buf, 1024);
+
+ qemu_put_be32s(f, &s->remote_wakeup);
+ qemu_put_be32s(f, &s->setup_state);
+ qemu_put_be32s(f, &s->setup_len);
+ qemu_put_be32s(f, &s->setup_index);
+
+}
+
+int generic_usb_load(QEMUFile* f, void *opaque, int version_id)
+{
+ USBDevice *s = (USBDevice*)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_be32s(f, &s->speed);
+ qemu_get_8s(f, &s->addr);
+ qemu_get_be32s(f, &s->state);
+
+ qemu_get_buffer(f, s->setup_buf, 8);
+ qemu_get_buffer(f, s->data_buf, 1024);
+
+ qemu_get_be32s(f, &s->remote_wakeup);
+ qemu_get_be32s(f, &s->setup_state);
+ qemu_get_be32s(f, &s->setup_len);
+ qemu_get_be32s(f, &s->setup_index);
+
+ return 0;
+}
diff --git a/tools/ioemu/hw/usb.h b/tools/ioemu/hw/usb.h
index 98fde06569..9df69f8dc8 100644
--- a/tools/ioemu/hw/usb.h
+++ b/tools/ioemu/hw/usb.h
@@ -176,3 +176,9 @@ USBDevice *usb_tablet_init(void);
/* usb-msd.c */
USBDevice *usb_msd_init(const char *filename);
+
+/* usb.c */
+void generic_usb_save(QEMUFile* f, void *opaque);
+int generic_usb_load(QEMUFile* f, void *opaque, int version_id);
+
+
diff --git a/tools/ioemu/target-i386-dm/exec-dm.c b/tools/ioemu/target-i386-dm/exec-dm.c
index 35891ed064..225f8b6f3a 100644
--- a/tools/ioemu/target-i386-dm/exec-dm.c
+++ b/tools/ioemu/target-i386-dm/exec-dm.c
@@ -450,6 +450,9 @@ static inline int paddr_is_ram(target_phys_addr_t addr)
#define phys_ram_addr(x) (phys_ram_base + (x))
#endif
+extern unsigned long *logdirty_bitmap;
+extern unsigned long logdirty_bitmap_size;
+
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
int len, int is_write)
{
@@ -485,9 +488,20 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
l = 1;
}
} else if (paddr_is_ram(addr)) {
- /* Reading from RAM */
+ /* Writing to RAM */
ptr = phys_ram_addr(addr);
memcpy(ptr, buf, l);
+ if (logdirty_bitmap != NULL) {
+ /* Record that we have dirtied this frame */
+ unsigned long pfn = addr >> TARGET_PAGE_BITS;
+ if (pfn / 8 >= logdirty_bitmap_size) {
+ fprintf(logfile, "dirtying pfn %x >= bitmap size %x\n",
+ pfn, logdirty_bitmap_size * 8);
+ } else {
+ logdirty_bitmap[pfn / HOST_LONG_BITS]
+ |= 1UL << pfn % HOST_LONG_BITS;
+ }
+ }
#ifdef __ia64__
sync_icache(ptr, l);
#endif
diff --git a/tools/ioemu/target-i386-dm/helper2.c b/tools/ioemu/target-i386-dm/helper2.c
index dc3394d5b7..17261e632d 100644
--- a/tools/ioemu/target-i386-dm/helper2.c
+++ b/tools/ioemu/target-i386-dm/helper2.c
@@ -439,6 +439,18 @@ void cpu_ioreq_xor(CPUState *env, ioreq_t *req)
req->data = tmp1;
}
+void cpu_ioreq_xchg(CPUState *env, ioreq_t *req)
+{
+ unsigned long tmp1;
+
+ if (req->data_is_ptr != 0)
+ hw_error("expected scalar value");
+
+ read_physical(req->addr, req->size, &tmp1);
+ write_physical(req->addr, req->size, &req->data);
+ req->data = tmp1;
+}
+
void __handle_ioreq(CPUState *env, ioreq_t *req)
{
if (!req->data_is_ptr && req->dir == IOREQ_WRITE && req->size != 4)
@@ -463,6 +475,9 @@ void __handle_ioreq(CPUState *env, ioreq_t *req)
case IOREQ_TYPE_XOR:
cpu_ioreq_xor(env, req);
break;
+ case IOREQ_TYPE_XCHG:
+ cpu_ioreq_xchg(env, req);
+ break;
default:
hw_error("Invalid ioreq type 0x%x\n", req->type);
}
@@ -577,7 +592,28 @@ int main_loop(void)
destroy_hvm_domain();
else {
char qemu_file[20];
+ ioreq_t *req;
+ int rc;
+
sprintf(qemu_file, "/tmp/xen.qemu-dm.%d", domid);
+ xc_domain_pause(xc_handle, domid);
+
+ /* Pull all outstanding ioreqs through the system */
+ handle_buffered_io(env);
+ main_loop_wait(1); /* For the select() on events */
+
+ /* Stop the IDE thread */
+ ide_stop_dma_thread();
+
+ /* Make sure that all outstanding IO responses are handled too */
+ if ( xc_hvm_drain_io(xc_handle, domid) != 0 )
+ {
+ fprintf(stderr, "error clearing ioreq rings (%s)\n",
+ strerror(errno));
+ return -1;
+ }
+
+ /* Save the device state */
if (qemu_savevm(qemu_file) < 0)
fprintf(stderr, "qemu save fail.\n");
}
diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c
index 0b78fa8650..6f9219fa40 100644
--- a/tools/ioemu/vl.c
+++ b/tools/ioemu/vl.c
@@ -841,10 +841,22 @@ void qemu_get_timer(QEMUFile *f, QEMUTimer *ts)
#ifdef CONFIG_DM
static void timer_save(QEMUFile *f, void *opaque)
{
+ /* need timer for save/restoe qemu_timer in usb_uhci */
+ if (cpu_ticks_enabled) {
+ hw_error("cannot save state if virtual timers are running");
+ }
+ qemu_put_be64s(f, &cpu_clock_offset);
}
static int timer_load(QEMUFile *f, void *opaque, int version_id)
{
+ if (version_id != 1)
+ return -EINVAL;
+ if (cpu_ticks_enabled) {
+ return -EINVAL;
+ }
+
+ qemu_get_be64s(f, &cpu_clock_offset);
return 0;
}
#else /* !CONFIG_DM */
@@ -3900,6 +3912,7 @@ static int usb_device_add(const char *devname)
const char *p;
USBDevice *dev;
USBPort *port;
+ char usb_name[256] = "USB ";
if (!free_usb_ports)
return -1;
@@ -3936,6 +3949,12 @@ static int usb_device_add(const char *devname)
free_usb_ports = port->next;
port->next = used_usb_ports;
used_usb_ports = port;
+
+ pstrcpy(usb_name + strlen(usb_name),
+ sizeof(usb_name) - strlen(usb_name),
+ devname);
+ register_savevm(usb_name, 0, 1, generic_usb_save, generic_usb_load, dev);
+
usb_attach(port, dev);
return 0;
}
diff --git a/tools/ioemu/vl.h b/tools/ioemu/vl.h
index 8535ba689c..a6b53aa312 100644
--- a/tools/ioemu/vl.h
+++ b/tools/ioemu/vl.h
@@ -843,6 +843,7 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table,
void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn);
int pmac_ide_init (BlockDriverState **hd_table,
SetIRQFunc *set_irq, void *irq_opaque, int irq);
+void ide_stop_dma_thread(void);
/* cdrom.c */
int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
diff --git a/tools/ioemu/xenstore.c b/tools/ioemu/xenstore.c
index edaf741c3d..26063f5a93 100644
--- a/tools/ioemu/xenstore.c
+++ b/tools/ioemu/xenstore.c
@@ -11,9 +11,14 @@
#include "vl.h"
#include "block_int.h"
#include <unistd.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
static struct xs_handle *xsh = NULL;
-static char *hd_filename[MAX_DISKS];
+static char *media_filename[MAX_DISKS];
static QEMUTimer *insert_timer = NULL;
#define UWAIT_MAX (30*1000000) /* thirty seconds */
@@ -40,10 +45,10 @@ static void insert_media(void *opaque)
int i;
for (i = 0; i < MAX_DISKS; i++) {
- if (hd_filename[i]) {
- do_change(bs_table[i]->device_name, hd_filename[i]);
- free(hd_filename[i]);
- hd_filename[i] = NULL;
+ if (media_filename[i] && bs_table[i]) {
+ do_change(bs_table[i]->device_name, media_filename[i]);
+ free(media_filename[i]);
+ media_filename[i] = NULL;
}
}
}
@@ -82,7 +87,7 @@ void xenstore_parse_domain_config(int domid)
unsigned int len, num, hd_index;
for(i = 0; i < MAX_DISKS; i++)
- hd_filename[i] = NULL;
+ media_filename[i] = NULL;
xsh = xs_daemon_open();
if (xsh == NULL) {
@@ -128,19 +133,12 @@ void xenstore_parse_domain_config(int domid)
continue;
free(type);
type = xs_read(xsh, XBT_NULL, buf, &len);
- /* read params to get the patch of the image -- read it last
- * so that we have its path in buf when setting up the
- * watch */
if (pasprintf(&buf, "%s/params", bpath) == -1)
continue;
free(params);
params = xs_read(xsh, XBT_NULL, buf, &len);
if (params == NULL)
continue;
- if (params[0]) {
- hd_filename[hd_index] = params; /* strdup() */
- params = NULL; /* don't free params on re-use */
- }
/*
* check if device has a phantom vbd; the phantom is hooked
* to the frontend device (for ease of cleanup), so lookup
@@ -151,38 +149,42 @@ void xenstore_parse_domain_config(int domid)
continue;
free(fpath);
fpath = xs_read(xsh, XBT_NULL, buf, &len);
- if (fpath != NULL) {
+ if (fpath) {
if (pasprintf(&buf, "%s/dev", fpath) == -1)
continue;
+ free(params);
params = xs_read(xsh, XBT_NULL, buf , &len);
- if (params != NULL) {
- free(hd_filename[hd_index]);
- hd_filename[hd_index] = params;
- params = NULL; /* don't free params on re-use */
+ if (params) {
/*
* wait for device, on timeout silently fail because we will
* fail to open below
*/
- waitForDevice(hd_filename[hd_index]);
+ waitForDevice(params);
}
}
+
bs_table[hd_index] = bdrv_new(dev);
- /* re-establish buf */
- if (pasprintf(&buf, "%s/params", bpath) == -1)
- continue;
/* check if it is a cdrom */
if (type && !strcmp(type, "cdrom")) {
bdrv_set_type_hint(bs_table[hd_index], BDRV_TYPE_CDROM);
- xs_watch(xsh, buf, dev);
+ if (pasprintf(&buf, "%s/params", bpath) != -1)
+ xs_watch(xsh, buf, dev);
}
- if (hd_filename[hd_index]) {
- if (bdrv_open(bs_table[hd_index], hd_filename[hd_index],
- 0 /* snapshot */) < 0)
+ /* open device now if media present */
+ if (params[0]) {
+ if (bdrv_open(bs_table[hd_index], params, 0 /* snapshot */) < 0)
fprintf(stderr, "qemu: could not open hard disk image '%s'\n",
- hd_filename[hd_index]);
+ params);
}
}
+ /* Set a watch for log-dirty requests from the migration tools */
+ if (pasprintf(&buf, "%s/logdirty/next-active", path) != -1) {
+ xs_watch(xsh, buf, "logdirty");
+ fprintf(logfile, "Watching %s\n", buf);
+ }
+
+
out:
free(type);
free(params);
@@ -201,6 +203,116 @@ int xenstore_fd(void)
return -1;
}
+unsigned long *logdirty_bitmap = NULL;
+unsigned long logdirty_bitmap_size;
+extern int vga_ram_size, bios_size;
+
+void xenstore_process_logdirty_event(void)
+{
+ char *act;
+ static char *active_path = NULL;
+ static char *next_active_path = NULL;
+ static char *seg = NULL;
+ unsigned int len;
+ int i;
+
+ fprintf(logfile, "Triggered log-dirty buffer switch\n");
+
+ if (!seg) {
+ char *path, *p, *key_ascii, key_terminated[17] = {0,};
+ key_t key;
+ int shmid;
+
+ /* Find and map the shared memory segment for log-dirty bitmaps */
+ if (!(path = xs_get_domain_path(xsh, domid))) {
+ fprintf(logfile, "Log-dirty: can't get domain path in store\n");
+ exit(1);
+ }
+ if (!(path = realloc(path, strlen(path)
+ + strlen("/logdirty/next-active") + 1))) {
+ fprintf(logfile, "Log-dirty: out of memory\n");
+ exit(1);
+ }
+ strcat(path, "/logdirty/");
+ p = path + strlen(path);
+ strcpy(p, "key");
+
+ key_ascii = xs_read(xsh, XBT_NULL, path, &len);
+ if (!key_ascii) {
+ /* No key yet: wait for the next watch */
+ free(path);
+ return;
+ }
+ strncpy(key_terminated, key_ascii, 16);
+ free(key_ascii);
+ key = (key_t) strtoull(key_terminated, NULL, 16);
+
+ /* Figure out how bit the log-dirty bitmaps are */
+ logdirty_bitmap_size = ((phys_ram_size + 0x20
+ - (vga_ram_size + bios_size))
+ >> (TARGET_PAGE_BITS)); /* nr of bits in map*/
+ if (logdirty_bitmap_size > HVM_BELOW_4G_MMIO_START >> TARGET_PAGE_BITS)
+ logdirty_bitmap_size +=
+ HVM_BELOW_4G_MMIO_LENGTH >> TARGET_PAGE_BITS; /* still bits */
+ logdirty_bitmap_size = ((logdirty_bitmap_size + HOST_LONG_BITS - 1)
+ / HOST_LONG_BITS); /* longs */
+ logdirty_bitmap_size *= sizeof (unsigned long); /* bytes */
+
+ /* Map the shared-memory segment */
+ if ((shmid = shmget(key,
+ 2 * logdirty_bitmap_size,
+ S_IRUSR|S_IWUSR)) == -1
+ || (seg = shmat(shmid, NULL, 0)) == (void *)-1) {
+ fprintf(logfile, "Log-dirty: can't map segment %16.16llx (%s)\n",
+ (unsigned long long) key, strerror(errno));
+ exit(1);
+ }
+
+ fprintf(logfile, "Log-dirty: mapped segment at %p\n", seg);
+
+ /* Double-check that the bitmaps are the size we expect */
+ if (logdirty_bitmap_size != *(uint32_t *)seg) {
+ fprintf(logfile, "Log-dirty: got %lu, calc %lu\n",
+ *(uint32_t *)seg, logdirty_bitmap_size);
+ return;
+ }
+
+ /* Remember the paths for the next-active and active entries */
+ strcpy(p, "active");
+ if (!(active_path = strdup(path))) {
+ fprintf(logfile, "Log-dirty: out of memory\n");
+ exit(1);
+ }
+ strcpy(p, "next-active");
+ if (!(next_active_path = strdup(path))) {
+ fprintf(logfile, "Log-dirty: out of memory\n");
+ exit(1);
+ }
+ free(path);
+ }
+
+ /* Read the required active buffer from the store */
+ act = xs_read(xsh, XBT_NULL, next_active_path, &len);
+ if (!act) {
+ fprintf(logfile, "Log-dirty: can't read next-active\n");
+ exit(1);
+ }
+
+ /* Switch buffers */
+ i = act[0] - '0';
+ if (i != 0 && i != 1) {
+ fprintf(logfile, "Log-dirty: bad next-active entry: %s\n", act);
+ exit(1);
+ }
+ logdirty_bitmap = seg + i * logdirty_bitmap_size;
+
+ /* Ack that we've switched */
+ xs_write(xsh, XBT_NULL, active_path, act, len);
+ free(act);
+}
+
+
+
void xenstore_process_event(void *opaque)
{
char **vec, *image = NULL;
@@ -210,6 +322,11 @@ void xenstore_process_event(void *opaque)
if (!vec)
return;
+ if (!strcmp(vec[XS_WATCH_TOKEN], "logdirty")) {
+ xenstore_process_logdirty_event();
+ goto out;
+ }
+
if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) ||
strlen(vec[XS_WATCH_TOKEN]) != 3)
goto out;
@@ -220,13 +337,13 @@ void xenstore_process_event(void *opaque)
do_eject(0, vec[XS_WATCH_TOKEN]);
bs_table[hd_index]->filename[0] = 0;
- if (hd_filename[hd_index]) {
- free(hd_filename[hd_index]);
- hd_filename[hd_index] = NULL;
+ if (media_filename[hd_index]) {
+ free(media_filename[hd_index]);
+ media_filename[hd_index] = NULL;
}
if (image[0]) {
- hd_filename[hd_index] = strdup(image);
+ media_filename[hd_index] = strdup(image);
xenstore_check_new_media_present(5000);
}
diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile
index ff034ea260..c924ea509a 100644
--- a/tools/libxc/Makefile
+++ b/tools/libxc/Makefile
@@ -58,7 +58,7 @@ GUEST_SRCS-$(CONFIG_POWERPC) += xc_dom_powerpc.c
CFLAGS += -Werror -Wmissing-prototypes
CFLAGS += -fno-strict-aliasing
-CFLAGS += $(INCLUDES) -I.
+CFLAGS += $(INCLUDES) -I. -I../xenstore
# Needed for posix_fadvise64() in xc_linux.c
CFLAGS-$(CONFIG_Linux) += -D_GNU_SOURCE
diff --git a/tools/libxc/xc_core.c b/tools/libxc/xc_core.c
index 3dcf51e131..3c1ff185a6 100644
--- a/tools/libxc/xc_core.c
+++ b/tools/libxc/xc_core.c
@@ -349,11 +349,7 @@ xc_domain_dumpcore_via_callback(int xc_handle,
/* Map the shared info frame */
live_shinfo = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
PROT_READ, info.shared_info_frame);
- if ( !live_shinfo
-#ifdef __ia64__
- && !info.hvm
-#endif
- )
+ if ( !live_shinfo && !info.hvm )
{
PERROR("Couldn't map live_shinfo");
goto out;
diff --git a/tools/libxc/xc_core_ia64.c b/tools/libxc/xc_core_ia64.c
index 455d532ee2..dff561b3d4 100644
--- a/tools/libxc/xc_core_ia64.c
+++ b/tools/libxc/xc_core_ia64.c
@@ -22,6 +22,28 @@
#include "xc_core.h"
#include "xc_efi.h"
#include "xc_dom.h"
+#include <inttypes.h>
+
+static int
+xc_memory_map_cmp(const void *lhs__, const void *rhs__)
+{
+ const struct xc_core_memory_map *lhs =
+ (const struct xc_core_memory_map *)lhs__;
+ const struct xc_core_memory_map *rhs =
+ (const struct xc_core_memory_map *)rhs__;
+
+ if (lhs->addr < rhs->addr)
+ return -1;
+ if (lhs->addr > rhs->addr)
+ return 1;
+
+ /* memory map overlap isn't allowed. complain */
+ DPRINTF("duplicated addresses are detected "
+ "(0x%" PRIx64 ", 0x%" PRIx64 "), "
+ "(0x%" PRIx64 ", 0x%" PRIx64 ")\n",
+ lhs->addr, lhs->size, rhs->addr, rhs->size);
+ return 0;
+}
int
xc_core_arch_auto_translated_physmap(const xc_dominfo_t *info)
@@ -111,6 +133,7 @@ memory_map_get_old_hvm(int xc_handle, xc_dominfo_t *info,
}
*mapp = map;
*nr_entries = i;
+ qsort(map, *nr_entries, sizeof(map[0]), &xc_memory_map_cmp);
return 0;
out:
@@ -196,6 +219,7 @@ xc_core_arch_memory_map_get(int xc_handle, xc_dominfo_t *info,
ret = 0;
out:
munmap(memmap_info, PAGE_SIZE);
+ qsort(map, *nr_entries, sizeof(map[0]), &xc_memory_map_cmp);
return ret;
old:
diff --git a/tools/libxc/xc_core_x86.c b/tools/libxc/xc_core_x86.c
index 6ea775aef6..bd82110713 100644
--- a/tools/libxc/xc_core_x86.c
+++ b/tools/libxc/xc_core_x86.c
@@ -21,12 +21,15 @@
#include "xg_private.h"
#include "xc_core.h"
+static int max_gpfn(int xc_handle, domid_t domid)
+{
+ return xc_memory_op(xc_handle, XENMEM_maximum_gpfn, &domid);
+}
+
int
xc_core_arch_auto_translated_physmap(const xc_dominfo_t *info)
{
- if ( info->hvm )
- return 1;
- return 0;
+ return info->hvm;
}
int
@@ -35,14 +38,14 @@ xc_core_arch_memory_map_get(int xc_handle, xc_dominfo_t *info,
xc_core_memory_map_t **mapp,
unsigned int *nr_entries)
{
- unsigned long max_pfn = live_shinfo->arch.max_pfn;
- xc_core_memory_map_t *map = NULL;
+ unsigned long max_pfn = max_gpfn(xc_handle, info->domid);
+ xc_core_memory_map_t *map;
map = malloc(sizeof(*map));
- if ( !map )
+ if ( map == NULL )
{
PERROR("Could not allocate memory");
- goto out;
+ return -1;
}
map->addr = 0;
@@ -51,11 +54,6 @@ xc_core_arch_memory_map_get(int xc_handle, xc_dominfo_t *info,
*mapp = map;
*nr_entries = 1;
return 0;
-
-out:
- if ( map )
- free(map);
- return -1;
}
int
@@ -67,7 +65,7 @@ xc_core_arch_map_p2m(int xc_handle, xc_dominfo_t *info,
xen_pfn_t *live_p2m_frame_list_list = NULL;
xen_pfn_t *live_p2m_frame_list = NULL;
uint32_t dom = info->domid;
- unsigned long max_pfn = live_shinfo->arch.max_pfn;
+ unsigned long max_pfn = max_gpfn(xc_handle, info->domid);
int ret = -1;
int err;
diff --git a/tools/libxc/xc_dom_x86.c b/tools/libxc/xc_dom_x86.c
index 0641078f9c..6a71cec811 100644
--- a/tools/libxc/xc_dom_x86.c
+++ b/tools/libxc/xc_dom_x86.c
@@ -434,24 +434,12 @@ static int vcpu_x86_32(struct xc_dom_image *dom, void *ptr)
{
vcpu_guest_context_x86_32_t *ctxt = ptr;
xen_pfn_t cr3_pfn;
- int i;
xc_dom_printf("%s: called\n", __FUNCTION__);
/* clear everything */
memset(ctxt, 0, sizeof(*ctxt));
- /* Virtual IDT is empty at start-of-day. */
- for ( i = 0; i < 256; i++ )
- {
- ctxt->trap_ctxt[i].vector = i;
- ctxt->trap_ctxt[i].cs = FLAT_KERNEL_CS_X86_32;
- }
-
- /* No callback handlers. */
- ctxt->event_callback_cs = FLAT_KERNEL_CS_X86_32;
- ctxt->failsafe_callback_cs = FLAT_KERNEL_CS_X86_32;
-
ctxt->user_regs.ds = FLAT_KERNEL_DS_X86_32;
ctxt->user_regs.es = FLAT_KERNEL_DS_X86_32;
ctxt->user_regs.fs = FLAT_KERNEL_DS_X86_32;
@@ -465,11 +453,10 @@ static int vcpu_x86_32(struct xc_dom_image *dom, void *ptr)
dom->parms.virt_base + (dom->start_info_pfn) * PAGE_SIZE_X86;
ctxt->user_regs.eflags = 1 << 9; /* Interrupt Enable */
- ctxt->kernel_ss = FLAT_KERNEL_SS_X86_32;
- ctxt->kernel_sp =
- dom->parms.virt_base + (dom->bootstack_pfn + 1) * PAGE_SIZE_X86;
+ ctxt->kernel_ss = ctxt->user_regs.ss;
+ ctxt->kernel_sp = ctxt->user_regs.esp;
- ctxt->flags = VGCF_in_kernel_X86_32;
+ ctxt->flags = VGCF_in_kernel_X86_32 | VGCF_online_X86_32;
if ( dom->parms.pae == 2 /* extended_cr3 */ ||
dom->parms.pae == 3 /* bimodal */ )
ctxt->vm_assist |= (1UL << VMASST_TYPE_pae_extended_cr3);
@@ -486,20 +473,12 @@ static int vcpu_x86_64(struct xc_dom_image *dom, void *ptr)
{
vcpu_guest_context_x86_64_t *ctxt = ptr;
xen_pfn_t cr3_pfn;
- int i;
xc_dom_printf("%s: called\n", __FUNCTION__);
/* clear everything */
memset(ctxt, 0, sizeof(*ctxt));
- /* Virtual IDT is empty at start-of-day. */
- for ( i = 0; i < 256; i++ )
- {
- ctxt->trap_ctxt[i].vector = i;
- ctxt->trap_ctxt[i].cs = FLAT_KERNEL_CS_X86_64;
- }
-
ctxt->user_regs.ds = FLAT_KERNEL_DS_X86_64;
ctxt->user_regs.es = FLAT_KERNEL_DS_X86_64;
ctxt->user_regs.fs = FLAT_KERNEL_DS_X86_64;
@@ -513,11 +492,10 @@ static int vcpu_x86_64(struct xc_dom_image *dom, void *ptr)
dom->parms.virt_base + (dom->start_info_pfn) * PAGE_SIZE_X86;
ctxt->user_regs.rflags = 1 << 9; /* Interrupt Enable */
- ctxt->kernel_ss = FLAT_KERNEL_SS_X86_64;
- ctxt->kernel_sp =
- dom->parms.virt_base + (dom->bootstack_pfn + 1) * PAGE_SIZE_X86;
+ ctxt->kernel_ss = ctxt->user_regs.ss;
+ ctxt->kernel_sp = ctxt->user_regs.esp;
- ctxt->flags = VGCF_in_kernel_X86_64;
+ ctxt->flags = VGCF_in_kernel_X86_64 | VGCF_online_X86_64;
cr3_pfn = xc_dom_p2m_guest(dom, dom->pgtables_seg.pfn);
ctxt->ctrlreg[3] = xen_pfn_to_cr3_x86_64(cr3_pfn);
xc_dom_printf("%s: cr3: pfn 0x%" PRIpfn " mfn 0x%" PRIpfn "\n",
diff --git a/tools/libxc/xc_hvm_build.c b/tools/libxc/xc_hvm_build.c
index 2238d315bc..751aa9cf7a 100644
--- a/tools/libxc/xc_hvm_build.c
+++ b/tools/libxc/xc_hvm_build.c
@@ -137,6 +137,12 @@ static void build_e820map(void *e820_page, unsigned long long mem_size)
e820entry[nr_map].type = E820_RAM;
nr_map++;
+ /* Explicitly reserve space for special pages (ioreq and xenstore). */
+ e820entry[nr_map].addr = mem_size - PAGE_SIZE * 3;
+ e820entry[nr_map].size = PAGE_SIZE * 3;
+ e820entry[nr_map].type = E820_RESERVED;
+ nr_map++;
+
if ( extra_mem_size )
{
e820entry[nr_map].addr = (1ULL << 32);
@@ -280,7 +286,6 @@ static int setup_guest(int xc_handle,
/* NB. evtchn_upcall_mask is unused: leave as zero. */
memset(&shared_info->evtchn_mask[0], 0xff,
sizeof(shared_info->evtchn_mask));
- shared_info->arch.max_pfn = page_array[nr_pages - 1];
munmap(shared_info, PAGE_SIZE);
if ( v_end > HVM_BELOW_4G_RAM_END )
@@ -302,9 +307,15 @@ static int setup_guest(int xc_handle,
/* Set [er]ip in the way that's right for Xen */
if ( strstr(caps, "x86_64") )
+ {
ctxt->c64.user_regs.rip = elf_uval(&elf, elf.ehdr, e_entry);
+ ctxt->c64.flags = VGCF_online;
+ }
else
+ {
ctxt->c32.user_regs.eip = elf_uval(&elf, elf.ehdr, e_entry);
+ ctxt->c32.flags = VGCF_online;
+ }
return 0;
@@ -344,7 +355,7 @@ static int xc_hvm_build_internal(int xc_handle,
memset(&launch_domctl, 0, sizeof(launch_domctl));
launch_domctl.domain = (domid_t)domid;
- launch_domctl.u.vcpucontext.vcpu = 0;
+ launch_domctl.u.vcpucontext.vcpu = 0;
set_xen_guest_handle(launch_domctl.u.vcpucontext.ctxt, &ctxt.c);
launch_domctl.cmd = XEN_DOMCTL_setvcpucontext;
rc = xc_domctl(xc_handle, &launch_domctl);
diff --git a/tools/libxc/xc_hvm_restore.c b/tools/libxc/xc_hvm_restore.c
index 001fe2a6e4..4b54b0aaf5 100644
--- a/tools/libxc/xc_hvm_restore.c
+++ b/tools/libxc/xc_hvm_restore.c
@@ -70,9 +70,6 @@ int xc_hvm_restore(int xc_handle, int io_fd,
{
DECLARE_DOMCTL;
- /* The new domain's shared-info frame number. */
- unsigned long shared_info_frame;
-
/* A copy of the CPU context of the guest. */
vcpu_guest_context_t ctxt;
@@ -86,8 +83,6 @@ int xc_hvm_restore(int xc_handle, int io_fd,
uint8_t *hvm_buf = NULL;
unsigned long long v_end, memsize;
unsigned long shared_page_nr;
- shared_info_t *shared_info = NULL;
- xen_pfn_t arch_max_pfn;
unsigned long pfn;
unsigned int prev_pc, this_pc;
@@ -96,11 +91,12 @@ int xc_hvm_restore(int xc_handle, int io_fd,
/* Types of the pfns in the current region */
unsigned long region_pfn_type[MAX_BATCH_SIZE];
- struct xen_add_to_physmap xatp;
-
/* Number of pages of memory the guest has. *Not* the same as max_pfn. */
unsigned long nr_pages;
+ /* The size of an array big enough to contain all guest pfns */
+ unsigned long pfn_array_size = max_pfn + 1;
+
/* hvm guest mem size (Mb) */
memsize = (unsigned long long)*store_mfn;
v_end = memsize << 20;
@@ -127,7 +123,7 @@ int xc_hvm_restore(int xc_handle, int io_fd,
}
- pfns = malloc(max_pfn * sizeof(xen_pfn_t));
+ pfns = malloc(pfn_array_size * sizeof(xen_pfn_t));
if (pfns == NULL) {
ERROR("memory alloc failed");
errno = ENOMEM;
@@ -139,11 +135,10 @@ int xc_hvm_restore(int xc_handle, int io_fd,
goto out;
}
- for ( i = 0; i < max_pfn; i++ )
+ for ( i = 0; i < pfn_array_size; i++ )
pfns[i] = i;
- for ( i = HVM_BELOW_4G_RAM_END >> PAGE_SHIFT; i < max_pfn; i++ )
+ for ( i = HVM_BELOW_4G_RAM_END >> PAGE_SHIFT; i < pfn_array_size; i++ )
pfns[i] += HVM_BELOW_4G_MMIO_LENGTH >> PAGE_SHIFT;
- arch_max_pfn = pfns[max_pfn - 1];/* used later */
/* Allocate memory for HVM guest, skipping VGA hole 0xA0000-0xC0000. */
rc = xc_domain_memory_populate_physmap(
@@ -281,6 +276,14 @@ int xc_hvm_restore(int xc_handle, int io_fd,
else
shared_page_nr = (v_end >> PAGE_SHIFT) - 1;
+ /* Paranoia: clean pages. */
+ if ( xc_clear_domain_page(xc_handle, dom, shared_page_nr) ||
+ xc_clear_domain_page(xc_handle, dom, shared_page_nr-1) ||
+ xc_clear_domain_page(xc_handle, dom, shared_page_nr-2) ) {
+ ERROR("error clearing comms frames!\n");
+ goto out;
+ }
+
xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_PFN, shared_page_nr-1);
xc_set_hvm_param(xc_handle, dom, HVM_PARAM_BUFIOREQ_PFN, shared_page_nr-2);
xc_set_hvm_param(xc_handle, dom, HVM_PARAM_IOREQ_PFN, shared_page_nr);
@@ -289,29 +292,6 @@ int xc_hvm_restore(int xc_handle, int io_fd,
*store_mfn = (v_end >> PAGE_SHIFT) - 2;
DPRINTF("hvm restore:calculate new store_mfn=0x%lx,v_end=0x%llx..\n", *store_mfn, v_end);
- /* restore hvm context including pic/pit/shpage */
- if (!read_exact(io_fd, &rec_len, sizeof(uint32_t))) {
- ERROR("error read hvm context size!\n");
- goto out;
- }
-
- hvm_buf = malloc(rec_len);
- if (hvm_buf == NULL) {
- ERROR("memory alloc for hvm context buffer failed");
- errno = ENOMEM;
- goto out;
- }
-
- if (!read_exact(io_fd, hvm_buf, rec_len)) {
- ERROR("error read hvm buffer!\n");
- goto out;
- }
-
- if (( rc = xc_domain_hvm_setcontext(xc_handle, dom, hvm_buf, rec_len))) {
- ERROR("error set hvm buffer!\n");
- goto out;
- }
-
if (!read_exact(io_fd, &nr_vcpus, sizeof(uint32_t))) {
ERROR("error read nr vcpu !\n");
goto out;
@@ -339,28 +319,28 @@ int xc_hvm_restore(int xc_handle, int io_fd,
}
}
- /* Shared-info pfn */
- if (!read_exact(io_fd, &(shared_info_frame), sizeof(uint32_t)) ) {
- ERROR("reading the shared-info pfn failed!\n");
+ /* restore hvm context including pic/pit/shpage */
+ if (!read_exact(io_fd, &rec_len, sizeof(uint32_t))) {
+ ERROR("error read hvm context size!\n");
goto out;
}
- /* Map the shared-info frame where it was before */
- xatp.domid = dom;
- xatp.space = XENMAPSPACE_shared_info;
- xatp.idx = 0;
- xatp.gpfn = shared_info_frame;
- if ( (rc = xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp)) != 0 ) {
- ERROR("setting the shared-info pfn failed!\n");
+
+ hvm_buf = malloc(rec_len);
+ if (hvm_buf == NULL) {
+ ERROR("memory alloc for hvm context buffer failed");
+ errno = ENOMEM;
goto out;
}
- if ( (xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp) != 0) ||
- ((shared_info = xc_map_foreign_range(
- xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE,
- shared_info_frame)) == NULL) )
+
+ if (!read_exact(io_fd, hvm_buf, rec_len)) {
+ ERROR("error read hvm buffer!\n");
goto out;
- /* shared_info.arch.max_pfn is used by dump-core */
- shared_info->arch.max_pfn = arch_max_pfn;
- munmap(shared_info, PAGE_SIZE);
+ }
+
+ if (( rc = xc_domain_hvm_setcontext(xc_handle, dom, hvm_buf, rec_len))) {
+ ERROR("error set hvm buffer!\n");
+ goto out;
+ }
rc = 0;
goto out;
diff --git a/tools/libxc/xc_hvm_save.c b/tools/libxc/xc_hvm_save.c
index d1b44bd1c6..75a017cf7c 100644
--- a/tools/libxc/xc_hvm_save.c
+++ b/tools/libxc/xc_hvm_save.c
@@ -27,12 +27,14 @@
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
-#include <xen/hvm/e820.h>
#include "xc_private.h"
#include "xg_private.h"
#include "xg_save_restore.h"
+#include <xen/hvm/e820.h>
+#include <xen/hvm/params.h>
+
/*
** Default values for important tuning parameters. Can override by passing
** non-zero replacement values to xc_hvm_save().
@@ -49,11 +51,30 @@ static unsigned long max_mfn;
/* virtual starting address of the hypervisor */
static unsigned long hvirt_start;
-/* #levels of page tables used by the currrent guest */
+/* #levels of page tables used by the current guest */
static unsigned int pt_levels;
-/* total number of pages used by the current guest */
-static unsigned long max_pfn;
+/* Shared-memory bitmaps for getting log-dirty bits from qemu */
+static unsigned long *qemu_bitmaps[2];
+static int qemu_active;
+static int qemu_non_active;
+
+int xc_hvm_drain_io(int handle, domid_t dom)
+{
+ DECLARE_HYPERCALL;
+ xen_hvm_drain_io_t arg;
+ int rc;
+
+ hypercall.op = __HYPERVISOR_hvm_op;
+ hypercall.arg[0] = HVMOP_drain_io;
+ hypercall.arg[1] = (unsigned long)&arg;
+ arg.domid = dom;
+ if ( lock_pages(&arg, sizeof(arg)) != 0 )
+ return -1;
+ rc = do_xen_hypercall(handle, &hypercall);
+ unlock_pages(&arg, sizeof(arg));
+ return rc;
+}
/*
** During (live) save/migrate, we maintain a number of bitmaps to track
@@ -61,7 +82,8 @@ static unsigned long max_pfn;
*/
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
-#define BITMAP_SIZE ((max_pfn + BITS_PER_LONG - 1) / 8)
+#define BITS_TO_LONGS(bits) (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
+#define BITMAP_SIZE (BITS_TO_LONGS(pfn_array_size) * sizeof(unsigned long))
#define BITMAP_ENTRY(_nr,_bmap) \
((unsigned long *)(_bmap))[(_nr)/BITS_PER_LONG]
@@ -108,6 +130,7 @@ static inline int permute( int i, int nr, int order_nr )
return i;
}
+
static uint64_t tv_to_us(struct timeval *new)
{
return (new->tv_sec * 1000000) + new->tv_usec;
@@ -183,7 +206,7 @@ static int print_stats(int xc_handle, uint32_t domid, int pages_sent,
return 0;
}
-static int analysis_phase(int xc_handle, uint32_t domid, int max_pfn,
+static int analysis_phase(int xc_handle, uint32_t domid, int pfn_array_size,
unsigned long *arr, int runs)
{
long long start, now;
@@ -196,7 +219,7 @@ static int analysis_phase(int xc_handle, uint32_t domid, int max_pfn,
int i;
xc_shadow_control(xc_handle, domid, XEN_DOMCTL_SHADOW_OP_CLEAN,
- arr, max_pfn, NULL, 0, NULL);
+ arr, pfn_array_size, NULL, 0, NULL);
DPRINTF("#Flush\n");
for ( i = 0; i < 40; i++ ) {
usleep(50000);
@@ -236,7 +259,7 @@ static int suspend_and_state(int (*suspend)(int), int xc_handle, int io_fd,
if (info->shutdown && info->shutdown_reason == SHUTDOWN_suspend)
- return 0; // success
+ return 0; // success
if (info->paused) {
// try unpausing domain, wait, and retest
@@ -261,17 +284,26 @@ static int suspend_and_state(int (*suspend)(int), int xc_handle, int io_fd,
}
int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
- uint32_t max_factor, uint32_t flags, int (*suspend)(int))
+ uint32_t max_factor, uint32_t flags, int (*suspend)(int),
+ void *(*init_qemu_maps)(int, unsigned),
+ void (*qemu_flip_buffer)(int, int))
{
xc_dominfo_t info;
int rc = 1, i, j, last_iter, iter = 0;
int live = (flags & XCFLAGS_LIVE);
int debug = (flags & XCFLAGS_DEBUG);
+ int stdvga = (flags & XCFLAGS_STDVGA);
int sent_last_iter, skip_this_iter;
- /* The new domain's shared-info frame number. */
- unsigned long shared_info_frame;
+ /* The highest guest-physical frame number used by the current guest */
+ unsigned long max_pfn;
+
+ /* The size of an array big enough to contain all guest pfns */
+ unsigned long pfn_array_size;
+
+ /* Other magic frames: ioreqs and xenstore comms */
+ unsigned long ioreq_pfn, bufioreq_pfn, store_pfn;
/* A copy of the CPU context of the guest. */
vcpu_guest_context_t ctxt;
@@ -283,15 +315,12 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
uint32_t hvm_buf_size;
uint8_t *hvm_buf = NULL;
- /* Live mapping of shared info structure */
- shared_info_t *live_shinfo = NULL;
-
/* base of the region in which domain memory is mapped */
unsigned char *region_base = NULL;
uint32_t rec_size, nr_vcpus;
- /* power of 2 order of max_pfn */
+ /* power of 2 order of pfn_array_size */
int order_nr;
/* bitmap of pages:
@@ -337,7 +366,6 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
ERROR("HVM:Could not get vcpu context");
goto out;
}
- shared_info_frame = info.shared_info_frame;
/* cheesy sanity check */
if ((info.max_memkb >> (PAGE_SHIFT - 10)) > max_mfn) {
@@ -346,10 +374,12 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
goto out;
}
- /* Map the shared info frame */
- if(!(live_shinfo = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
- PROT_READ, shared_info_frame))) {
- ERROR("HVM:Couldn't map live_shinfo");
+ if ( xc_get_hvm_param(xc_handle, dom, HVM_PARAM_STORE_PFN, &store_pfn)
+ || xc_get_hvm_param(xc_handle, dom, HVM_PARAM_IOREQ_PFN, &ioreq_pfn)
+ || xc_get_hvm_param(xc_handle, dom,
+ HVM_PARAM_BUFIOREQ_PFN, &bufioreq_pfn) )
+ {
+ ERROR("HVM: Could not read magic PFN parameters");
goto out;
}
@@ -357,8 +387,6 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
"nr_pages=0x%lx\n", info.max_memkb, max_mfn, info.nr_pages);
if (live) {
- ERROR("hvm domain doesn't support live migration now.\n");
- goto out;
if (xc_shadow_control(xc_handle, dom,
XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY,
@@ -368,6 +396,7 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
}
last_iter = 0;
+
DPRINTF("hvm domain live migration debug start: logdirty enable.\n");
} else {
/* This is a non-live suspend. Issue the call back to get the
@@ -388,20 +417,28 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
/* Calculate the highest PFN of "normal" memory:
* HVM memory is sequential except for the VGA and MMIO holes. */
- max_pfn = info.nr_pages;
+ max_pfn = info.nr_pages - 1;
+ /* If the domain has a Cirrus framebuffer and we haven't already
+ * suspended qemu-dm, it will have 8MB of framebuffer memory
+ * still allocated, which we don't want to copy: qemu will save it
+ * for us later */
+ if ( live && !stdvga )
+ max_pfn -= 0x800;
/* Skip the VGA hole from 0xa0000 to 0xc0000 */
- max_pfn += 0x20;
+ max_pfn += 0x20;
/* Skip the MMIO hole: 256MB just below 4GB */
if ( max_pfn >= (HVM_BELOW_4G_MMIO_START >> PAGE_SHIFT) )
max_pfn += (HVM_BELOW_4G_MMIO_LENGTH >> PAGE_SHIFT);
- skip_this_iter = 0;/*XXX*/
+ /* Size of any array that covers 0 ... max_pfn */
+ pfn_array_size = max_pfn + 1;
+
/* pretend we sent all the pages last iteration */
- sent_last_iter = max_pfn;
+ sent_last_iter = pfn_array_size;
- /* calculate the power of 2 order of max_pfn, e.g.
+ /* calculate the power of 2 order of pfn_array_size, e.g.
15->4 16->4 17->5 */
- for (i = max_pfn-1, order_nr = 0; i ; i >>= 1, order_nr++)
+ for (i = pfn_array_size-1, order_nr = 0; i ; i >>= 1, order_nr++)
continue;
/* Setup to_send / to_fix and to_skip bitmaps */
@@ -409,6 +446,15 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
to_skip = malloc(BITMAP_SIZE);
+ if (live) {
+ /* Get qemu-dm logging dirty pages too */
+ void *seg = init_qemu_maps(dom, BITMAP_SIZE);
+ qemu_bitmaps[0] = seg;
+ qemu_bitmaps[1] = seg + BITMAP_SIZE;
+ qemu_active = 0;
+ qemu_non_active = 1;
+ }
+
hvm_buf_size = xc_domain_hvm_getcontext(xc_handle, dom, 0, 0);
if ( hvm_buf_size == -1 )
{
@@ -435,7 +481,7 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
return 1;
}
- analysis_phase(xc_handle, dom, max_pfn, to_skip, 0);
+ analysis_phase(xc_handle, dom, pfn_array_size, to_skip, 0);
/* We want zeroed memory so use calloc rather than malloc. */
@@ -465,9 +511,10 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
DPRINTF("Saving HVM domain memory pages: iter %d 0%%", iter);
- while( N < max_pfn ){
+ while( N < pfn_array_size ){
- unsigned int this_pc = (N * 100) / max_pfn;
+ unsigned int this_pc = (N * 100) / pfn_array_size;
+ int rc;
if ((this_pc - prev_pc) >= 5) {
DPRINTF("\b\b\b\b%3d%%", this_pc);
@@ -476,9 +523,9 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
/* slightly wasteful to peek the whole array evey time,
but this is fast enough for the moment. */
- if (!last_iter && xc_shadow_control(
- xc_handle, dom, XEN_DOMCTL_SHADOW_OP_PEEK,
- to_skip, max_pfn, NULL, 0, NULL) != max_pfn) {
+ if (!last_iter && (rc = xc_shadow_control(
+ xc_handle, dom, XEN_DOMCTL_SHADOW_OP_PEEK, to_skip,
+ pfn_array_size, NULL, 0, NULL)) != pfn_array_size) {
ERROR("Error peeking HVM shadow bitmap");
goto out;
}
@@ -486,11 +533,11 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
/* load pfn_batch[] with the mfn of all the pages we're doing in
this batch. */
- for (batch = 0; batch < MAX_BATCH_SIZE && N < max_pfn ; N++) {
+ for (batch = 0; batch < MAX_BATCH_SIZE && N < pfn_array_size; N++){
- int n = permute(N, max_pfn, order_nr);
+ int n = permute(N, pfn_array_size, order_nr);
- if (debug) {
+ if (0&&debug) {
DPRINTF("%d pfn= %08lx %d \n",
iter, (unsigned long)n, test_bit(n, to_send));
}
@@ -505,7 +552,10 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
/* Skip PFNs that aren't really there */
if ((n >= 0xa0 && n < 0xc0) /* VGA hole */
|| (n >= (HVM_BELOW_4G_MMIO_START >> PAGE_SHIFT)
- && n < (1ULL << 32) >> PAGE_SHIFT)) /* 4G MMIO hole */
+ && n < (1ULL << 32) >> PAGE_SHIFT) /* 4G MMIO hole */
+ || n == store_pfn
+ || n == ioreq_pfn
+ || n == bufioreq_pfn)
continue;
/*
@@ -570,7 +620,7 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
print_stats( xc_handle, dom, sent_this_iter, &stats, 1);
DPRINTF("Total pages sent= %ld (%.2fx)\n",
- total_sent, ((float)total_sent)/max_pfn );
+ total_sent, ((float)total_sent)/pfn_array_size );
}
if (last_iter && debug){
@@ -597,7 +647,7 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
((sent_this_iter > sent_last_iter) && RATE_IS_MAX()) ||
(iter >= max_iters) ||
(sent_this_iter+skip_this_iter < 50) ||
- (total_sent > max_pfn*max_factor) ) {
+ (total_sent > pfn_array_size*max_factor) ) {
DPRINTF("Start last iteration for HVM domain\n");
last_iter = 1;
@@ -608,23 +658,36 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
goto out;
}
- DPRINTF("SUSPEND shinfo %08lx eip %08lx edx %08lx\n",
- info.shared_info_frame,
+ DPRINTF("SUSPEND eip %08lx edx %08lx\n",
(unsigned long)ctxt.user_regs.eip,
(unsigned long)ctxt.user_regs.edx);
}
if (xc_shadow_control(xc_handle, dom,
XEN_DOMCTL_SHADOW_OP_CLEAN, to_send,
- max_pfn, NULL, 0, &stats) != max_pfn) {
+ pfn_array_size, NULL,
+ 0, &stats) != pfn_array_size) {
ERROR("Error flushing shadow PT");
goto out;
}
+ /* Pull in the dirty bits from qemu too */
+ if (!last_iter) {
+ qemu_active = qemu_non_active;
+ qemu_non_active = qemu_active ? 0 : 1;
+ qemu_flip_buffer(dom, qemu_active);
+ for (j = 0; j < BITMAP_SIZE / sizeof(unsigned long); j++) {
+ to_send[j] |= qemu_bitmaps[qemu_non_active][j];
+ qemu_bitmaps[qemu_non_active][j] = 0;
+ }
+ } else {
+ for (j = 0; j < BITMAP_SIZE / sizeof(unsigned long); j++)
+ to_send[j] |= qemu_bitmaps[qemu_active][j];
+ }
+
sent_last_iter = sent_this_iter;
print_stats(xc_handle, dom, sent_this_iter, &stats, 1);
-
}
@@ -640,20 +703,6 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
goto out;
}
- if ( (rec_size = xc_domain_hvm_getcontext(xc_handle, dom, hvm_buf,
- hvm_buf_size)) == -1) {
- ERROR("HVM:Could not get hvm buffer");
- goto out;
- }
-
- if (!write_exact(io_fd, &rec_size, sizeof(uint32_t))) {
- ERROR("error write hvm buffer size");
- goto out;
- }
-
- if ( !write_exact(io_fd, hvm_buf, rec_size) ) {
- ERROR("write HVM info failed!\n");
- }
/* save vcpu/vmcs context */
if (!write_exact(io_fd, &nr_vcpus, sizeof(uint32_t))) {
@@ -682,12 +731,21 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
}
}
- /* Shared-info pfn */
- if (!write_exact(io_fd, &(shared_info_frame), sizeof(uint32_t)) ) {
- ERROR("write shared-info pfn failed!\n");
+ if ( (rec_size = xc_domain_hvm_getcontext(xc_handle, dom, hvm_buf,
+ hvm_buf_size)) == -1) {
+ ERROR("HVM:Could not get hvm buffer");
+ goto out;
+ }
+
+ if (!write_exact(io_fd, &rec_size, sizeof(uint32_t))) {
+ ERROR("error write hvm buffer size");
goto out;
}
-
+
+ if ( !write_exact(io_fd, hvm_buf, rec_size) ) {
+ ERROR("write HVM info failed!\n");
+ }
+
/* Success! */
rc = 0;
diff --git a/tools/libxc/xc_linux_restore.c b/tools/libxc/xc_linux_restore.c
index 6fa0388d3f..d3a87262a0 100644
--- a/tools/libxc/xc_linux_restore.c
+++ b/tools/libxc/xc_linux_restore.c
@@ -189,6 +189,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
uint64_t vcpumap = 1ULL;
unsigned int max_vcpu_id = 0;
+ int new_ctxt_format = 0;
max_pfn = nr_pfns;
@@ -372,6 +373,7 @@ int xc_linux_restore(int xc_handle, int io_fd,
}
if (j == -2) {
+ new_ctxt_format = 1;
if (!read_exact(io_fd, &max_vcpu_id, sizeof(int)) ||
(max_vcpu_id >= 64) ||
!read_exact(io_fd, &vcpumap, sizeof(uint64_t))) {
@@ -797,6 +799,9 @@ int xc_linux_restore(int xc_handle, int io_fd,
goto out;
}
+ if ( !new_ctxt_format )
+ ctxt.flags |= VGCF_online;
+
if (i == 0) {
/*
* Uncanonicalise the suspend-record frame number and poke
diff --git a/tools/libxc/xc_misc.c b/tools/libxc/xc_misc.c
index b2a648528a..987eb0eb13 100644
--- a/tools/libxc/xc_misc.c
+++ b/tools/libxc/xc_misc.c
@@ -33,6 +33,25 @@ int xc_readconsolering(int xc_handle,
return ret;
}
+int xc_send_debug_keys(int xc_handle, char *keys)
+{
+ int ret, len = strlen(keys);
+ DECLARE_SYSCTL;
+
+ sysctl.cmd = XEN_SYSCTL_debug_keys;
+ set_xen_guest_handle(sysctl.u.debug_keys.keys, keys);
+ sysctl.u.debug_keys.nr_keys = len;
+
+ if ( (ret = lock_pages(keys, len)) != 0 )
+ return ret;
+
+ ret = do_sysctl(xc_handle, &sysctl);
+
+ unlock_pages(keys, len);
+
+ return ret;
+}
+
int xc_physinfo(int xc_handle,
xc_physinfo_t *put_info)
{
diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c
index 77321c458b..3e2557e581 100644
--- a/tools/libxc/xc_private.c
+++ b/tools/libxc/xc_private.c
@@ -23,7 +23,7 @@ void xc_default_error_handler(const xc_error const *err)
fprintf(stderr, "ERROR %s: %s\n", desc, err->message);
}
-const xc_error const *xc_get_last_error(void)
+const xc_error *xc_get_last_error(void)
{
return &last_error;
}
@@ -263,6 +263,15 @@ int xc_memory_op(int xc_handle,
goto out1;
}
break;
+ case XENMEM_current_reservation:
+ case XENMEM_maximum_reservation:
+ case XENMEM_maximum_gpfn:
+ if ( lock_pages(arg, sizeof(domid_t)) )
+ {
+ PERROR("Could not lock");
+ goto out1;
+ }
+ break;
}
ret = do_xen_hypercall(xc_handle, &hypercall);
@@ -287,6 +296,11 @@ int xc_memory_op(int xc_handle,
case XENMEM_add_to_physmap:
unlock_pages(arg, sizeof(struct xen_add_to_physmap));
break;
+ case XENMEM_current_reservation:
+ case XENMEM_maximum_reservation:
+ case XENMEM_maximum_gpfn:
+ unlock_pages(arg, sizeof(domid_t));
+ break;
}
out1:
diff --git a/tools/libxc/xc_ptrace_core.c b/tools/libxc/xc_ptrace_core.c
index 82d06bb2d8..42d49cfcb7 100644
--- a/tools/libxc/xc_ptrace_core.c
+++ b/tools/libxc/xc_ptrace_core.c
@@ -390,7 +390,6 @@ map_gmfn_to_offset_elf(unsigned long gmfn)
{
/*
* linear search
- * There is no gurantee that those tables are sorted.
*/
unsigned long i;
if (current_is_auto_translated_physmap) {
diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
index 199750de73..4b346a74f0 100644
--- a/tools/libxc/xenctrl.h
+++ b/tools/libxc/xenctrl.h
@@ -467,6 +467,8 @@ int xc_readconsolering(int xc_handle,
unsigned int *pnr_chars,
int clear);
+int xc_send_debug_keys(int xc_handle, char *keys);
+
typedef xen_sysctl_physinfo_t xc_physinfo_t;
int xc_physinfo(int xc_handle,
xc_physinfo_t *info);
@@ -770,19 +772,19 @@ typedef struct {
* data pointed to are only valid until the next call to
* libxc.
*/
-const xc_error const *xc_get_last_error(void);
+const xc_error *xc_get_last_error(void);
/*
* Clear the last error
*/
void xc_clear_last_error(void);
-typedef void (*xc_error_handler)(const xc_error const* err);
+typedef void (*xc_error_handler)(const xc_error * const err);
/*
* The default error handler which prints to stderr
*/
-void xc_default_error_handler(const xc_error const* err);
+void xc_default_error_handler(const xc_error * const err);
/*
* Convert an error code into a text description
diff --git a/tools/libxc/xenguest.h b/tools/libxc/xenguest.h
index cb3c6a4d1c..76b7413f15 100644
--- a/tools/libxc/xenguest.h
+++ b/tools/libxc/xenguest.h
@@ -12,6 +12,7 @@
#define XCFLAGS_LIVE 1
#define XCFLAGS_DEBUG 2
#define XCFLAGS_HVM 4
+#define XCFLAGS_STDVGA 8
/**
@@ -31,8 +32,10 @@ int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
* @return 0 on success, -1 on failure
*/
int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
- uint32_t max_factor, uint32_t flags /* XCFLAGS_xxx */,
- int (*suspend)(int domid));
+ uint32_t max_factor, uint32_t flags /* XCFLAGS_xxx */,
+ int (*suspend)(int domid),
+ void *(*init_qemu_maps)(int, unsigned),
+ void (*qemu_flip_buffer)(int, int));
/**
* This function will restore a saved domain running Linux.
@@ -155,6 +158,8 @@ int xc_set_hvm_param(
int xc_get_hvm_param(
int handle, domid_t dom, int param, unsigned long *value);
+int xc_hvm_drain_io(int handle, domid_t dom);
+
/* PowerPC specific. */
int xc_prose_build(int xc_handle,
uint32_t domid,
diff --git a/tools/libxc/xg_private.c b/tools/libxc/xg_private.c
index 63ffea4aad..1014131004 100644
--- a/tools/libxc/xg_private.c
+++ b/tools/libxc/xg_private.c
@@ -201,7 +201,9 @@ __attribute__((weak))
__attribute__((weak))
int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
uint32_t max_factor, uint32_t flags,
- int (*suspend)(int domid))
+ int (*suspend)(int domid),
+ void *(*init_qemu_maps)(int, unsigned),
+ void (*qemu_flip_buffer)(int, int))
{
errno = ENOSYS;
return -1;
@@ -229,6 +231,11 @@ __attribute__((weak)) int xc_set_hvm_param(
return -ENOSYS;
}
+__attribute__((weak)) int xc_hvm_drain_io(int handle, domid_t dom)
+{
+ return -ENOSYS;
+}
+
/*
* Local variables:
* mode: C
diff --git a/tools/libxen/include/xen_crashdump.h b/tools/libxen/include/xen_crashdump.h
index fff0a1a144..00869dbb4c 100644
--- a/tools/libxen/include/xen_crashdump.h
+++ b/tools/libxen/include/xen_crashdump.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, XenSource Inc.
+ * Copyright (c) 2006-2007, XenSource Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -162,20 +162,6 @@ xen_crashdump_get_by_uuid(xen_session *session, xen_crashdump *result, char *uui
/**
- * Create a new crashdump instance, and return its handle.
- */
-extern bool
-xen_crashdump_create(xen_session *session, xen_crashdump *result, xen_crashdump_record *record);
-
-
-/**
- * Destroy the specified crashdump instance.
- */
-extern bool
-xen_crashdump_destroy(xen_session *session, xen_crashdump crashdump);
-
-
-/**
* Get the uuid field of the given crashdump.
*/
extern bool
@@ -197,6 +183,13 @@ xen_crashdump_get_vdi(xen_session *session, xen_vdi *result, xen_crashdump crash
/**
+ * Destroy the specified crashdump
+ */
+extern bool
+xen_crashdump_destroy(xen_session *session, xen_crashdump self);
+
+
+/**
* Return a list of all the crashdumps known to the system.
*/
extern bool
diff --git a/tools/libxen/include/xen_vbd.h b/tools/libxen/include/xen_vbd.h
index 86ad38f207..14a6685a95 100644
--- a/tools/libxen/include/xen_vbd.h
+++ b/tools/libxen/include/xen_vbd.h
@@ -72,7 +72,6 @@ typedef struct xen_vbd_record
struct xen_vm_record_opt *vm;
struct xen_vdi_record_opt *vdi;
char *device;
- char *image;
bool bootable;
enum xen_vbd_mode mode;
enum xen_vbd_type type;
@@ -358,6 +357,22 @@ xen_vbd_media_change(xen_session *session, xen_vbd vbd, xen_vdi vdi);
/**
+ * Hotplug the specified VBD, dynamically attaching it to the running
+ * VM
+ */
+extern bool
+xen_vbd_plug(xen_session *session, xen_vbd self);
+
+
+/**
+ * Hot-unplug the specified VBD, dynamically unattaching it from the
+ * running VM
+ */
+extern bool
+xen_vbd_unplug(xen_session *session, xen_vbd self);
+
+
+/**
* Return a list of all the VBDs known to the system.
*/
extern bool
diff --git a/tools/libxen/include/xen_vdi.h b/tools/libxen/include/xen_vdi.h
index 90120370d5..9ebb8fd9ee 100644
--- a/tools/libxen/include/xen_vdi.h
+++ b/tools/libxen/include/xen_vdi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, XenSource Inc.
+ * Copyright (c) 2006-2007, XenSource Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,6 +22,7 @@
#include "xen_common.h"
#include "xen_crashdump_decl.h"
#include "xen_sr_decl.h"
+#include "xen_string_string_map.h"
#include "xen_vbd_decl.h"
#include "xen_vdi_decl.h"
#include "xen_vdi_type.h"
@@ -73,11 +74,10 @@ typedef struct xen_vdi_record
struct xen_crashdump_record_opt_set *crash_dumps;
int64_t virtual_size;
int64_t physical_utilisation;
- int64_t sector_size;
- char *location;
enum xen_vdi_type type;
bool sharable;
bool read_only;
+ xen_string_string_map *other_config;
} xen_vdi_record;
/**
@@ -251,13 +251,6 @@ xen_vdi_get_physical_utilisation(xen_session *session, int64_t *result, xen_vdi
/**
- * Get the sector_size field of the given VDI.
- */
-extern bool
-xen_vdi_get_sector_size(xen_session *session, int64_t *result, xen_vdi vdi);
-
-
-/**
* Get the type field of the given VDI.
*/
extern bool
@@ -279,24 +272,24 @@ xen_vdi_get_read_only(xen_session *session, bool *result, xen_vdi vdi);
/**
- * Set the name/label field of the given VDI.
+ * Get the other_config field of the given VDI.
*/
extern bool
-xen_vdi_set_name_label(xen_session *session, xen_vdi vdi, char *label);
+xen_vdi_get_other_config(xen_session *session, xen_string_string_map **result, xen_vdi vdi);
/**
- * Set the name/description field of the given VDI.
+ * Set the name/label field of the given VDI.
*/
extern bool
-xen_vdi_set_name_description(xen_session *session, xen_vdi vdi, char *description);
+xen_vdi_set_name_label(xen_session *session, xen_vdi vdi, char *label);
/**
- * Set the SR field of the given VDI.
+ * Set the name/description field of the given VDI.
*/
extern bool
-xen_vdi_set_sr(xen_session *session, xen_vdi vdi, xen_sr sr);
+xen_vdi_set_name_description(xen_session *session, xen_vdi vdi, char *description);
/**
@@ -321,6 +314,30 @@ xen_vdi_set_read_only(xen_session *session, xen_vdi vdi, bool read_only);
/**
+ * Set the other_config field of the given VDI.
+ */
+extern bool
+xen_vdi_set_other_config(xen_session *session, xen_vdi vdi, xen_string_string_map *other_config);
+
+
+/**
+ * Add the given key-value pair to the other_config field of the given
+ * VDI.
+ */
+extern bool
+xen_vdi_add_to_other_config(xen_session *session, xen_vdi vdi, char *key, char *value);
+
+
+/**
+ * Remove the given key and its corresponding value from the
+ * other_config field of the given VDI. If the key is not in that Map, then
+ * do nothing.
+ */
+extern bool
+xen_vdi_remove_from_other_config(xen_session *session, xen_vdi vdi, char *key);
+
+
+/**
* Take an exact copy of the VDI; the snapshot lives in the same
* Storage Repository as its parent.
*/
diff --git a/tools/libxen/include/xen_vif.h b/tools/libxen/include/xen_vif.h
index 05a070aff4..8a1cffb7bd 100644
--- a/tools/libxen/include/xen_vif.h
+++ b/tools/libxen/include/xen_vif.h
@@ -332,6 +332,22 @@ xen_vif_remove_from_qos_algorithm_params(xen_session *session, xen_vif vif, char
/**
+ * Hotplug the specified VIF, dynamically attaching it to the running
+ * VM
+ */
+extern bool
+xen_vif_plug(xen_session *session, xen_vif self);
+
+
+/**
+ * Hot-unplug the specified VIF, dynamically unattaching it from the
+ * running VM
+ */
+extern bool
+xen_vif_unplug(xen_session *session, xen_vif self);
+
+
+/**
* Return a list of all the VIFs known to the system.
*/
extern bool
diff --git a/tools/libxen/include/xen_vm.h b/tools/libxen/include/xen_vm.h
index 71a3f62ca4..ddce6a8d1d 100644
--- a/tools/libxen/include/xen_vm.h
+++ b/tools/libxen/include/xen_vm.h
@@ -40,39 +40,6 @@
* The VM class.
*
* A virtual machine (or 'guest').
- *
- * VM booting is controlled by setting one of the two mutually exclusive
- * groups: "PV", and "HVM". If HVM.boot_policy is the empty string, then
- * paravirtual domain building and booting will be used; otherwise the VM will
- * be loaded as an HVM domain, and booted using an emulated BIOS.
- *
- * When paravirtual booting is in use, the PV/bootloader field indicates the
- * bootloader to use. It may be "pygrub", in which case the platform's
- * default installation of pygrub will be used, or a full path within the
- * control domain to some other bootloader. The other fields, PV/kernel,
- * PV/ramdisk, PV/args and PV/bootloader_args will be passed to the bootloader
- * unmodified, and interpretation of those fields is then specific to the
- * bootloader itself, including the possibility that the bootloader will
- * ignore some or all of those given values. Finally the paths of all bootable
- * disks are added to the bootloader commandline (a disk is bootable if its
- * VBD has the bootable flag set). There may be zero, one or many bootable
- * disks; the bootloader decides which disk (if any) to boot from.
- *
- * If the bootloader is pygrub, then the menu.lst is parsed if present in the
- * guest's filesystem, otherwise the specified kernel and ramdisk are used, or
- * an autodetected kernel is used if nothing is specified and autodetection is
- * possible. PV/args is appended to the kernel command line, no matter which
- * mechanism is used for finding the kernel.
- *
- * If PV/bootloader is empty but PV/kernel is specified, then the kernel and
- * ramdisk values will be treated as paths within the control domain. If both
- * PV/bootloader and PV/kernel are empty, then the behaviour is as if
- * PV/bootloader was specified as "pygrub".
- *
- * When using HVM booting, HVM/boot_policy and HVM/boot_params specify the
- * boot handling. Only one policy is currently defined: "BIOS order". In
- * this case, HVM/boot_params should contain one key-value pair "order" = "N"
- * where N is the string that will be passed to QEMU..
*/
@@ -120,7 +87,6 @@ typedef struct xen_vm_record
int64_t memory_dynamic_max;
int64_t memory_dynamic_min;
int64_t memory_static_min;
- char *vcpus_policy;
xen_string_string_map *vcpus_params;
int64_t vcpus_max;
int64_t vcpus_at_startup;
@@ -139,11 +105,7 @@ typedef struct xen_vm_record
char *pv_bootloader_args;
char *hvm_boot_policy;
xen_string_string_map *hvm_boot_params;
- bool platform_std_vga;
- char *platform_serial;
- bool platform_localtime;
- bool platform_clock_offset;
- bool platform_enable_audio;
+ xen_string_string_map *platform;
char *pci_bus;
xen_string_string_map *other_config;
int64_t domid;
@@ -360,13 +322,6 @@ xen_vm_get_memory_static_min(xen_session *session, int64_t *result, xen_vm vm);
/**
- * Get the VCPUs/policy field of the given VM.
- */
-extern bool
-xen_vm_get_vcpus_policy(xen_session *session, char **result, xen_vm vm);
-
-
-/**
* Get the VCPUs/params field of the given VM.
*/
extern bool
@@ -493,38 +448,10 @@ xen_vm_get_hvm_boot_params(xen_session *session, xen_string_string_map **result,
/**
- * Get the platform/std_VGA field of the given VM.
- */
-extern bool
-xen_vm_get_platform_std_vga(xen_session *session, bool *result, xen_vm vm);
-
-
-/**
- * Get the platform/serial field of the given VM.
- */
-extern bool
-xen_vm_get_platform_serial(xen_session *session, char **result, xen_vm vm);
-
-
-/**
- * Get the platform/localtime field of the given VM.
+ * Get the platform field of the given VM.
*/
extern bool
-xen_vm_get_platform_localtime(xen_session *session, bool *result, xen_vm vm);
-
-
-/**
- * Get the platform/clock_offset field of the given VM.
- */
-extern bool
-xen_vm_get_platform_clock_offset(xen_session *session, bool *result, xen_vm vm);
-
-
-/**
- * Get the platform/enable_audio field of the given VM.
- */
-extern bool
-xen_vm_get_platform_enable_audio(xen_session *session, bool *result, xen_vm vm);
+xen_vm_get_platform(xen_session *session, xen_string_string_map **result, xen_vm vm);
/**
@@ -633,13 +560,6 @@ xen_vm_set_memory_static_min(xen_session *session, xen_vm vm, int64_t static_min
/**
- * Set the VCPUs/policy field of the given VM.
- */
-extern bool
-xen_vm_set_vcpus_policy(xen_session *session, xen_vm vm, char *policy);
-
-
-/**
* Set the VCPUs/params field of the given VM.
*/
extern bool
@@ -765,38 +685,32 @@ xen_vm_remove_from_hvm_boot_params(xen_session *session, xen_vm vm, char *key);
/**
- * Set the platform/std_VGA field of the given VM.
- */
-extern bool
-xen_vm_set_platform_std_vga(xen_session *session, xen_vm vm, bool std_vga);
-
-
-/**
- * Set the platform/serial field of the given VM.
+ * Set the platform field of the given VM.
*/
extern bool
-xen_vm_set_platform_serial(xen_session *session, xen_vm vm, char *serial);
+xen_vm_set_platform(xen_session *session, xen_vm vm, xen_string_string_map *platform);
/**
- * Set the platform/localtime field of the given VM.
+ * Add the given key-value pair to the platform field of the given VM.
*/
extern bool
-xen_vm_set_platform_localtime(xen_session *session, xen_vm vm, bool localtime);
+xen_vm_add_to_platform(xen_session *session, xen_vm vm, char *key, char *value);
/**
- * Set the platform/clock_offset field of the given VM.
+ * Remove the given key and its corresponding value from the platform
+ * field of the given VM. If the key is not in that Map, then do nothing.
*/
extern bool
-xen_vm_set_platform_clock_offset(xen_session *session, xen_vm vm, bool clock_offset);
+xen_vm_remove_from_platform(xen_session *session, xen_vm vm, char *key);
/**
- * Set the platform/enable_audio field of the given VM.
+ * Set the PCI_bus field of the given VM.
*/
extern bool
-xen_vm_set_platform_enable_audio(xen_session *session, xen_vm vm, bool enable_audio);
+xen_vm_set_pci_bus(xen_session *session, xen_vm vm, char *pci_bus);
/**
diff --git a/tools/libxen/src/xen_common.c b/tools/libxen/src/xen_common.c
index c6e2181850..f2c9644521 100644
--- a/tools/libxen/src/xen_common.c
+++ b/tools/libxen/src/xen_common.c
@@ -110,7 +110,7 @@ parse_structmap_value(xen_session *, xmlNode *, const abstract_type *,
static size_t size_of_member(const abstract_type *);
static const char *
-get_val_as_string(const struct abstract_type *, void *, char *);
+get_val_as_string(const struct abstract_type *, void *, char *, size_t);
void
@@ -666,8 +666,7 @@ static void parse_into(xen_session *s, xmlNode *value_node,
{
if (!is_container_node(value_node, "value") ||
value_node->children->type != XML_ELEMENT_NODE ||
- 0 != strcmp((char *)value_node->children->name, "struct") ||
- value_node->children->children == NULL)
+ 0 != strcmp((char *)value_node->children->name, "struct"))
{
server_error(s,
"Expected Map from the server, but didn't get it");
@@ -890,6 +889,9 @@ static size_t size_of_member(const abstract_type *type)
case REF:
return sizeof(arbitrary_record_opt *);
+ case STRUCT:
+ return type->struct_size;
+
default:
assert(false);
}
@@ -1183,7 +1185,8 @@ add_struct_value(const struct abstract_type *type, void *value,
case INT:
case ENUM:
{
- const char *val_as_string = get_val_as_string(type, value, buf);
+ const char *val_as_string =
+ get_val_as_string(type, value, buf, sizeof(buf));
adder(node, key, "string", val_as_string);
}
break;
@@ -1215,7 +1218,8 @@ add_struct_value(const struct abstract_type *type, void *value,
for (size_t i = 0; i < set_val->size; i++)
{
- void *member_value = set_val->contents + (i * member_size);
+ void *member_value = (char *)set_val->contents +
+ (i * member_size);
add_struct_value(member_type, member_value,
add_unnamed_value, NULL, data_node);
}
@@ -1254,7 +1258,7 @@ add_struct_value(const struct abstract_type *type, void *value,
void *r_value = contents + (i * member_size) + r_offset;
const char *l_value_as_string =
- get_val_as_string(l_type, l_value, buf);
+ get_val_as_string(l_type, l_value, buf, sizeof(buf));
add_struct_value(r_type, r_value, add_struct_member,
l_value_as_string, struct_node);
@@ -1270,7 +1274,8 @@ add_struct_value(const struct abstract_type *type, void *value,
static const char *
-get_val_as_string(const struct abstract_type *type, void *value, char *buf)
+get_val_as_string(const struct abstract_type *type, void *value, char *buf,
+ size_t bufsize)
{
switch (type->typename)
{
@@ -1304,7 +1309,7 @@ get_val_as_string(const struct abstract_type *type, void *value, char *buf)
case INT:
{
int64_t val = *(int64_t *)value;
- snprintf(buf, sizeof(buf), "%"PRId64, val);
+ snprintf(buf, bufsize, "%"PRId64, val);
return buf;
}
break;
diff --git a/tools/libxen/src/xen_crashdump.c b/tools/libxen/src/xen_crashdump.c
index 53504ba249..2d3840896e 100644
--- a/tools/libxen/src/xen_crashdump.c
+++ b/tools/libxen/src/xen_crashdump.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, XenSource Inc.
+ * Copyright (c) 2006-2007, XenSource Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -115,38 +115,24 @@ xen_crashdump_get_by_uuid(xen_session *session, xen_crashdump *result, char *uui
bool
-xen_crashdump_create(xen_session *session, xen_crashdump *result, xen_crashdump_record *record)
+xen_crashdump_get_vm(xen_session *session, xen_vm *result, xen_crashdump crashdump)
{
abstract_value param_values[] =
{
- { .type = &xen_crashdump_record_abstract_type_,
- .u.struct_val = record }
+ { .type = &abstract_type_string,
+ .u.string_val = crashdump }
};
abstract_type result_type = abstract_type_string;
*result = NULL;
- XEN_CALL_("crashdump.create");
- return session->ok;
-}
-
-
-bool
-xen_crashdump_destroy(xen_session *session, xen_crashdump crashdump)
-{
- abstract_value param_values[] =
- {
- { .type = &abstract_type_string,
- .u.string_val = crashdump }
- };
-
- xen_call_(session, "crashdump.destroy", param_values, 1, NULL, NULL);
+ XEN_CALL_("crashdump.get_VM");
return session->ok;
}
bool
-xen_crashdump_get_vm(xen_session *session, xen_vm *result, xen_crashdump crashdump)
+xen_crashdump_get_vdi(xen_session *session, xen_vdi *result, xen_crashdump crashdump)
{
abstract_value param_values[] =
{
@@ -157,24 +143,21 @@ xen_crashdump_get_vm(xen_session *session, xen_vm *result, xen_crashdump crashdu
abstract_type result_type = abstract_type_string;
*result = NULL;
- XEN_CALL_("crashdump.get_VM");
+ XEN_CALL_("crashdump.get_VDI");
return session->ok;
}
bool
-xen_crashdump_get_vdi(xen_session *session, xen_vdi *result, xen_crashdump crashdump)
+xen_crashdump_destroy(xen_session *session, xen_crashdump self)
{
abstract_value param_values[] =
{
{ .type = &abstract_type_string,
- .u.string_val = crashdump }
+ .u.string_val = self }
};
- abstract_type result_type = abstract_type_string;
-
- *result = NULL;
- XEN_CALL_("crashdump.get_VDI");
+ xen_call_(session, "crashdump.destroy", param_values, 1, NULL, NULL);
return session->ok;
}
diff --git a/tools/libxen/src/xen_vbd.c b/tools/libxen/src/xen_vbd.c
index def7403ef9..893bf70958 100644
--- a/tools/libxen/src/xen_vbd.c
+++ b/tools/libxen/src/xen_vbd.c
@@ -54,9 +54,6 @@ static const struct_member xen_vbd_record_struct_members[] =
{ .key = "device",
.type = &abstract_type_string,
.offset = offsetof(xen_vbd_record, device) },
- { .key = "image",
- .type = &abstract_type_string,
- .offset = offsetof(xen_vbd_record, image) },
{ .key = "bootable",
.type = &abstract_type_bool,
.offset = offsetof(xen_vbd_record, bootable) },
@@ -552,6 +549,34 @@ xen_vbd_media_change(xen_session *session, xen_vbd vbd, xen_vdi vdi)
bool
+xen_vbd_plug(xen_session *session, xen_vbd self)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = self }
+ };
+
+ xen_call_(session, "VBD.plug", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vbd_unplug(xen_session *session, xen_vbd self)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = self }
+ };
+
+ xen_call_(session, "VBD.unplug", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
xen_vbd_get_all(xen_session *session, struct xen_vbd_set **result)
{
diff --git a/tools/libxen/src/xen_vdi.c b/tools/libxen/src/xen_vdi.c
index 150d341b1b..10f3fc4066 100644
--- a/tools/libxen/src/xen_vdi.c
+++ b/tools/libxen/src/xen_vdi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, XenSource Inc.
+ * Copyright (c) 2006-2007, XenSource Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -24,6 +24,7 @@
#include "xen_crashdump.h"
#include "xen_internal.h"
#include "xen_sr.h"
+#include "xen_string_string_map.h"
#include "xen_vbd.h"
#include "xen_vdi.h"
#include "xen_vdi_type_internal.h"
@@ -64,12 +65,6 @@ static const struct_member xen_vdi_record_struct_members[] =
{ .key = "physical_utilisation",
.type = &abstract_type_int,
.offset = offsetof(xen_vdi_record, physical_utilisation) },
- { .key = "sector_size",
- .type = &abstract_type_int,
- .offset = offsetof(xen_vdi_record, sector_size) },
- { .key = "location",
- .type = &abstract_type_string,
- .offset = offsetof(xen_vdi_record, location) },
{ .key = "type",
.type = &xen_vdi_type_abstract_type_,
.offset = offsetof(xen_vdi_record, type) },
@@ -78,7 +73,10 @@ static const struct_member xen_vdi_record_struct_members[] =
.offset = offsetof(xen_vdi_record, sharable) },
{ .key = "read_only",
.type = &abstract_type_bool,
- .offset = offsetof(xen_vdi_record, read_only) }
+ .offset = offsetof(xen_vdi_record, read_only) },
+ { .key = "other_config",
+ .type = &abstract_type_string_string_map,
+ .offset = offsetof(xen_vdi_record, other_config) }
};
const abstract_type xen_vdi_record_abstract_type_ =
@@ -105,6 +103,7 @@ xen_vdi_record_free(xen_vdi_record *record)
xen_sr_record_opt_free(record->sr);
xen_vbd_record_opt_set_free(record->vbds);
xen_crashdump_record_opt_set_free(record->crash_dumps);
+ xen_string_string_map_free(record->other_config);
free(record);
}
@@ -315,22 +314,6 @@ xen_vdi_get_physical_utilisation(xen_session *session, int64_t *result, xen_vdi
bool
-xen_vdi_get_sector_size(xen_session *session, int64_t *result, xen_vdi vdi)
-{
- abstract_value param_values[] =
- {
- { .type = &abstract_type_string,
- .u.string_val = vdi }
- };
-
- abstract_type result_type = abstract_type_int;
-
- XEN_CALL_("VDI.get_sector_size");
- return session->ok;
-}
-
-
-bool
xen_vdi_get_type(xen_session *session, enum xen_vdi_type *result, xen_vdi vdi)
{
abstract_value param_values[] =
@@ -378,49 +361,50 @@ xen_vdi_get_read_only(xen_session *session, bool *result, xen_vdi vdi)
bool
-xen_vdi_set_name_label(xen_session *session, xen_vdi vdi, char *label)
+xen_vdi_get_other_config(xen_session *session, xen_string_string_map **result, xen_vdi vdi)
{
abstract_value param_values[] =
{
{ .type = &abstract_type_string,
- .u.string_val = vdi },
- { .type = &abstract_type_string,
- .u.string_val = label }
+ .u.string_val = vdi }
};
- xen_call_(session, "VDI.set_name_label", param_values, 2, NULL, NULL);
+ abstract_type result_type = abstract_type_string_string_map;
+
+ *result = NULL;
+ XEN_CALL_("VDI.get_other_config");
return session->ok;
}
bool
-xen_vdi_set_name_description(xen_session *session, xen_vdi vdi, char *description)
+xen_vdi_set_name_label(xen_session *session, xen_vdi vdi, char *label)
{
abstract_value param_values[] =
{
{ .type = &abstract_type_string,
.u.string_val = vdi },
{ .type = &abstract_type_string,
- .u.string_val = description }
+ .u.string_val = label }
};
- xen_call_(session, "VDI.set_name_description", param_values, 2, NULL, NULL);
+ xen_call_(session, "VDI.set_name_label", param_values, 2, NULL, NULL);
return session->ok;
}
bool
-xen_vdi_set_sr(xen_session *session, xen_vdi vdi, xen_sr sr)
+xen_vdi_set_name_description(xen_session *session, xen_vdi vdi, char *description)
{
abstract_value param_values[] =
{
{ .type = &abstract_type_string,
.u.string_val = vdi },
{ .type = &abstract_type_string,
- .u.string_val = sr }
+ .u.string_val = description }
};
- xen_call_(session, "VDI.set_SR", param_values, 2, NULL, NULL);
+ xen_call_(session, "VDI.set_name_description", param_values, 2, NULL, NULL);
return session->ok;
}
@@ -474,6 +458,56 @@ xen_vdi_set_read_only(xen_session *session, xen_vdi vdi, bool read_only)
bool
+xen_vdi_set_other_config(xen_session *session, xen_vdi vdi, xen_string_string_map *other_config)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi },
+ { .type = &abstract_type_string_string_map,
+ .u.set_val = (arbitrary_set *)other_config }
+ };
+
+ xen_call_(session, "VDI.set_other_config", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vdi_add_to_other_config(xen_session *session, xen_vdi vdi, char *key, char *value)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi },
+ { .type = &abstract_type_string,
+ .u.string_val = key },
+ { .type = &abstract_type_string,
+ .u.string_val = value }
+ };
+
+ xen_call_(session, "VDI.add_to_other_config", param_values, 3, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vdi_remove_from_other_config(xen_session *session, xen_vdi vdi, char *key)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = vdi },
+ { .type = &abstract_type_string,
+ .u.string_val = key }
+ };
+
+ xen_call_(session, "VDI.remove_from_other_config", param_values, 2, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
xen_vdi_snapshot(xen_session *session, xen_vdi *result, xen_vdi vdi)
{
abstract_value param_values[] =
diff --git a/tools/libxen/src/xen_vif.c b/tools/libxen/src/xen_vif.c
index 11cba1dcbd..a139a83bc3 100644
--- a/tools/libxen/src/xen_vif.c
+++ b/tools/libxen/src/xen_vif.c
@@ -500,6 +500,34 @@ xen_vif_remove_from_qos_algorithm_params(xen_session *session, xen_vif vif, char
bool
+xen_vif_plug(xen_session *session, xen_vif self)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = self }
+ };
+
+ xen_call_(session, "VIF.plug", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
+xen_vif_unplug(xen_session *session, xen_vif self)
+{
+ abstract_value param_values[] =
+ {
+ { .type = &abstract_type_string,
+ .u.string_val = self }
+ };
+
+ xen_call_(session, "VIF.unplug", param_values, 1, NULL, NULL);
+ return session->ok;
+}
+
+
+bool
xen_vif_get_all(xen_session *session, struct xen_vif_set **result)
{
diff --git a/tools/libxen/src/xen_vm.c b/tools/libxen/src/xen_vm.c
index 910c9f8b31..f80916188e 100644
--- a/tools/libxen/src/xen_vm.c
+++ b/tools/libxen/src/xen_vm.c
@@ -88,9 +88,6 @@ static const struct_member xen_vm_record_struct_members[] =
{ .key = "memory_static_min",
.type = &abstract_type_int,
.offset = offsetof(xen_vm_record, memory_static_min) },
- { .key = "VCPUs_policy",
- .type = &abstract_type_string,
- .offset = offsetof(xen_vm_record, vcpus_policy) },
{ .key = "VCPUs_params",
.type = &abstract_type_string_string_map,
.offset = offsetof(xen_vm_record, vcpus_params) },
@@ -145,21 +142,9 @@ static const struct_member xen_vm_record_struct_members[] =
{ .key = "HVM_boot_params",
.type = &abstract_type_string_string_map,
.offset = offsetof(xen_vm_record, hvm_boot_params) },
- { .key = "platform_std_VGA",
- .type = &abstract_type_bool,
- .offset = offsetof(xen_vm_record, platform_std_vga) },
- { .key = "platform_serial",
- .type = &abstract_type_string,
- .offset = offsetof(xen_vm_record, platform_serial) },
- { .key = "platform_localtime",
- .type = &abstract_type_bool,
- .offset = offsetof(xen_vm_record, platform_localtime) },
- { .key = "platform_clock_offset",
- .type = &abstract_type_bool,
- .offset = offsetof(xen_vm_record, platform_clock_offset) },
- { .key = "platform_enable_audio",
- .type = &abstract_type_bool,
- .offset = offsetof(xen_vm_record, platform_enable_audio) },
+ { .key = "platform",
+ .type = &abstract_type_string_string_map,
+ .offset = offsetof(xen_vm_record, platform) },
{ .key = "PCI_bus",
.type = &abstract_type_string,
.offset = offsetof(xen_vm_record, pci_bus) },
@@ -203,7 +188,6 @@ xen_vm_record_free(xen_vm_record *record)
free(record->name_description);
xen_vdi_record_opt_free(record->suspend_vdi);
xen_host_record_opt_free(record->resident_on);
- free(record->vcpus_policy);
xen_string_string_map_free(record->vcpus_params);
xen_console_record_opt_set_free(record->consoles);
xen_vif_record_opt_set_free(record->vifs);
@@ -217,7 +201,7 @@ xen_vm_record_free(xen_vm_record *record)
free(record->pv_bootloader_args);
free(record->hvm_boot_policy);
xen_string_string_map_free(record->hvm_boot_params);
- free(record->platform_serial);
+ xen_string_string_map_free(record->platform);
free(record->pci_bus);
xen_string_string_map_free(record->other_config);
xen_vm_metrics_record_opt_free(record->metrics);
@@ -510,23 +494,6 @@ xen_vm_get_memory_static_min(xen_session *session, int64_t *result, xen_vm vm)
bool
-xen_vm_get_vcpus_policy(xen_session *session, char **result, xen_vm vm)
-{
- abstract_value param_values[] =
- {
- { .type = &abstract_type_string,
- .u.string_val = vm }
- };
-
- abstract_type result_type = abstract_type_string;
-
- *result = NULL;
- XEN_CALL_("VM.get_VCPUs_policy");
- return session->ok;
-}
-
-
-bool
xen_vm_get_vcpus_params(xen_session *session, xen_string_string_map **result, xen_vm vm)
{
abstract_value param_values[] =
@@ -825,7 +792,7 @@ xen_vm_get_hvm_boot_params(xen_session *session, xen_string_string_map **result,
bool
-xen_vm_get_platform_std_vga(xen_session *session, bool *result, xen_vm vm)
+xen_vm_get_platform(xen_session *session, xen_string_string_map **result, xen_vm vm)
{
abstract_value param_values[] =
{
@@ -833,74 +800,10 @@ xen_vm_get_platform_std_vga(xen_session *session, bool *result, xen_vm vm)
.u.string_val = vm }
};
- abstract_type result_type = abstract_type_bool;
-
- XEN_CALL_("VM.get_platform_std_VGA");
- return session->ok;
-}
-
-
-bool
-xen_vm_get_platform_serial(xen_session *session, char **result, xen_vm vm)
-{
- abstract_value param_values[] =
- {
- { .type = &abstract_type_string,
- .u.string_val = vm }
- };
-
- abstract_type result_type = abstract_type_string;
+ abstract_type result_type = abstract_type_string_string_map;
*result = NULL;
- XEN_CALL_("VM.get_platform_serial");
- return session->ok;
-}
-
-
-bool
-xen_vm_get_platform_localtime(xen_session *session, bool *result, xen_vm vm)
-{
- abstract_value param_values[] =
- {
- { .type = &abstract_type_string,
- .u.string_val = vm }
- };
-
- abstract_type result_type = abstract_type_bool;
-
- XEN_CALL_("VM.get_platform_localtime");
- return session->ok;
-}
-
-
-bool
-xen_vm_get_platform_clock_offset(xen_session *session, bool *result, xen_vm vm)
-{
- abstract_value param_values[] =
- {
- { .type = &abstract_type_string,
- .u.string_val = vm }
- };
-
- abstract_type result_type = abstract_type_bool;
-
- XEN_CALL_("VM.get_platform_clock_offset");
- return session->ok;
-}
-
-
-bool
-xen_vm_get_platform_enable_audio(xen_session *session, bool *result, xen_vm vm)
-{
- abstract_value param_values[] =
- {
- { .type = &abstract_type_string,
- .u.string_val = vm }
- };
-
- abstract_type result_type = abstract_type_bool;
-
- XEN_CALL_("VM.get_platform_enable_audio");
+ XEN_CALL_("VM.get_platform");
return session->ok;
}
@@ -1150,22 +1053,6 @@ xen_vm_set_memory_static_min(xen_session *session, xen_vm vm, int64_t static_min
bool
-xen_vm_set_vcpus_policy(xen_session *session, xen_vm vm, char *policy)
-{
- abstract_value param_values[] =
- {
- { .type = &abstract_type_string,
- .u.string_val = vm },
- { .type = &abstract_type_string,
- .u.string_val = policy }
- };
-
- xen_call_(session, "VM.set_VCPUs_policy", param_values, 2, NULL, NULL);
- return session->ok;
-}
-
-
-bool
xen_vm_set_vcpus_params(xen_session *session, xen_vm vm, xen_string_string_map *params)
{
abstract_value param_values[] =
@@ -1442,81 +1329,67 @@ xen_vm_remove_from_hvm_boot_params(xen_session *session, xen_vm vm, char *key)
bool
-xen_vm_set_platform_std_vga(xen_session *session, xen_vm vm, bool std_vga)
+xen_vm_set_platform(xen_session *session, xen_vm vm, xen_string_string_map *platform)
{
abstract_value param_values[] =
{
{ .type = &abstract_type_string,
.u.string_val = vm },
- { .type = &abstract_type_bool,
- .u.bool_val = std_vga }
+ { .type = &abstract_type_string_string_map,
+ .u.set_val = (arbitrary_set *)platform }
};
- xen_call_(session, "VM.set_platform_std_VGA", param_values, 2, NULL, NULL);
+ xen_call_(session, "VM.set_platform", param_values, 2, NULL, NULL);
return session->ok;
}
bool
-xen_vm_set_platform_serial(xen_session *session, xen_vm vm, char *serial)
+xen_vm_add_to_platform(xen_session *session, xen_vm vm, char *key, char *value)
{
abstract_value param_values[] =
{
{ .type = &abstract_type_string,
.u.string_val = vm },
{ .type = &abstract_type_string,
- .u.string_val = serial }
- };
-
- xen_call_(session, "VM.set_platform_serial", param_values, 2, NULL, NULL);
- return session->ok;
-}
-
-
-bool
-xen_vm_set_platform_localtime(xen_session *session, xen_vm vm, bool localtime)
-{
- abstract_value param_values[] =
- {
+ .u.string_val = key },
{ .type = &abstract_type_string,
- .u.string_val = vm },
- { .type = &abstract_type_bool,
- .u.bool_val = localtime }
+ .u.string_val = value }
};
- xen_call_(session, "VM.set_platform_localtime", param_values, 2, NULL, NULL);
+ xen_call_(session, "VM.add_to_platform", param_values, 3, NULL, NULL);
return session->ok;
}
bool
-xen_vm_set_platform_clock_offset(xen_session *session, xen_vm vm, bool clock_offset)
+xen_vm_remove_from_platform(xen_session *session, xen_vm vm, char *key)
{
abstract_value param_values[] =
{
{ .type = &abstract_type_string,
.u.string_val = vm },
- { .type = &abstract_type_bool,
- .u.bool_val = clock_offset }
+ { .type = &abstract_type_string,
+ .u.string_val = key }
};
- xen_call_(session, "VM.set_platform_clock_offset", param_values, 2, NULL, NULL);
+ xen_call_(session, "VM.remove_from_platform", param_values, 2, NULL, NULL);
return session->ok;
}
bool
-xen_vm_set_platform_enable_audio(xen_session *session, xen_vm vm, bool enable_audio)
+xen_vm_set_pci_bus(xen_session *session, xen_vm vm, char *pci_bus)
{
abstract_value param_values[] =
{
{ .type = &abstract_type_string,
.u.string_val = vm },
- { .type = &abstract_type_bool,
- .u.bool_val = enable_audio }
+ { .type = &abstract_type_string,
+ .u.string_val = pci_bus }
};
- xen_call_(session, "VM.set_platform_enable_audio", param_values, 2, NULL, NULL);
+ xen_call_(session, "VM.set_PCI_bus", param_values, 2, NULL, NULL);
return session->ok;
}
diff --git a/tools/libxen/test/test_bindings.c b/tools/libxen/test/test_bindings.c
index 6a51cd3a05..92f2d9b6ca 100644
--- a/tools/libxen/test/test_bindings.c
+++ b/tools/libxen/test/test_bindings.c
@@ -373,8 +373,9 @@ static xen_vm create_new_vm(xen_session *session, bool hvm)
.memory_dynamic_max = 256,
.memory_dynamic_min = 128,
.memory_static_min = 128,
- .vcpus_policy = "credit",
.vcpus_params = vcpus_params,
+ .vcpus_max = 4,
+ .vcpus_at_startup = 2,
.actions_after_shutdown = XEN_ON_NORMAL_EXIT_DESTROY,
.actions_after_reboot = XEN_ON_NORMAL_EXIT_RESTART,
.actions_after_crash = XEN_ON_CRASH_BEHAVIOUR_PRESERVE,
@@ -420,8 +421,7 @@ static xen_vm create_new_vm(xen_session *session, bool hvm)
.name_label = "MyRootFS",
.name_description = "MyRootFS description",
.sr = &sr_record,
- .virtual_size = (1 << 21), // 1GiB / 512 bytes/sector
- .sector_size = 512,
+ .virtual_size = (INT64_C(1) << 30), // 1GiB
.type = XEN_VDI_TYPE_SYSTEM,
.sharable = false,
.read_only = false
diff --git a/tools/python/scripts/test_hvm_create.py b/tools/python/scripts/test_hvm_create.py
index 7cae70539a..35abfe0396 100644
--- a/tools/python/scripts/test_hvm_create.py
+++ b/tools/python/scripts/test_hvm_create.py
@@ -39,14 +39,13 @@ vm_cfg = {
local_vdi_cfg = {
'name_label': 'gentoo.hvm',
'name_description': '',
- 'location': 'file:/root/gentoo.amd64.hvm.img',
'virtual_size': 0,
- 'sector_size': 0,
'type': 'system',
'parent': '',
'SR_name': 'Local',
'sharable': False,
'read_only': False,
+ 'other_config': {'location': 'file:/root/gentoo.amd64.hvm.img'},
}
local_vbd_cfg = {
diff --git a/tools/python/scripts/test_vm_create.py b/tools/python/scripts/test_vm_create.py
index e4d8f3023a..6575f153ea 100644
--- a/tools/python/scripts/test_vm_create.py
+++ b/tools/python/scripts/test_vm_create.py
@@ -39,8 +39,7 @@ vm_cfg = {
vdi_cfg = {
'name_label': 'API_VDI',
'name_description': '',
- 'virtual_size': 100 * 1024 * 1024,
- 'sector_size': 1024,
+ 'virtual_size': 100 * 1024 * 1024 * 1024,
'type': 'system',
'parent': '',
'SR_name': 'QCoW',
@@ -60,14 +59,13 @@ vbd_cfg = {
local_vdi_cfg = {
'name_label': 'gentoo.amd64.img',
'name_description': '',
- 'location': 'file:/root/gentoo.amd64.img',
'virtual_size': 0,
- 'sector_size': 0,
'type': 'system',
'parent': '',
'SR_name': 'Local',
'sharable': False,
'read_only': False,
+ 'other_config': {'location': 'file:/root/gentoo.amd64.img'},
}
local_vbd_cfg = {
diff --git a/tools/python/scripts/xapi.py b/tools/python/scripts/xapi.py
index 1e49f86d4c..1a07795212 100644
--- a/tools/python/scripts/xapi.py
+++ b/tools/python/scripts/xapi.py
@@ -40,8 +40,7 @@ VM_LIST_FORMAT = '%(name_label)-18s %(memory_actual)-5s %(VCPUs_number)-5s'\
' %(power_state)-10s %(uuid)-36s'
SR_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(physical_size)-10s' \
'%(type)-10s'
-VDI_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(virtual_size)-8s '\
- '%(sector_size)-8s'
+VDI_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(virtual_size)-8s'
VBD_LIST_FORMAT = '%(device)-6s %(uuid)-36s %(VDI)-8s'
TASK_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(status)-8s %(progress)-4s'
VIF_LIST_FORMAT = '%(name)-8s %(device)-7s %(uuid)-36s %(MAC)-10s'
@@ -96,12 +95,9 @@ OPTIONS = {
'vdi-create': [(('--name-label',), {'help': 'Name for VDI'}),
(('--name-description',), {'help': 'Description for VDI'}),
- (('--sector-size',), {'type': 'int',
- 'help': 'Sector size',
- 'default': 0}),
(('--virtual-size',), {'type': 'int',
'default': 0,
- 'help': 'Size of VDI in sectors'}),
+ 'help': 'Size of VDI in bytes'}),
(('--type',), {'choices': ['system', 'user', 'ephemeral'],
'default': 'system',
'help': 'VDI type'}),
@@ -569,8 +565,7 @@ def xapi_vdi_list(args, async = False):
if not is_long:
print VDI_LIST_FORMAT % {'name_label': 'VDI Label',
'uuid' : 'UUID',
- 'virtual_size': 'Bytes',
- 'sector_size': 'Sector Size'}
+ 'virtual_size': 'Bytes'}
for vdi in vdis:
vdi_struct = execute(server, 'VDI.get_record', (session, vdi))
diff --git a/tools/python/scripts/xapi.vdicfg.py b/tools/python/scripts/xapi.vdicfg.py
index 86129bfae9..cb63653550 100644
--- a/tools/python/scripts/xapi.vdicfg.py
+++ b/tools/python/scripts/xapi.vdicfg.py
@@ -1,7 +1,6 @@
name_label = 'VDI 1'
name_description = ''
-virtual_size = 10 * 1024 * 1024
-sector_size = 1024
+virtual_size = 10 * 1024 * 1024 * 1024
type = 'system'
sharable = False
read_only = False
diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c
index 1e40d515cb..975b7d3a38 100644
--- a/tools/python/xen/lowlevel/xc/xc.c
+++ b/tools/python/xen/lowlevel/xc/xc.c
@@ -47,20 +47,24 @@ static PyObject *dom_op(XcObject *self, PyObject *args,
static PyObject *pyxc_error_to_exception(void)
{
PyObject *pyerr;
- const xc_error const *err = xc_get_last_error();
+ const xc_error *err = xc_get_last_error();
const char *desc = xc_error_code_to_desc(err->code);
- if (err->code == XC_ERROR_NONE)
+ if ( err->code == XC_ERROR_NONE )
return PyErr_SetFromErrno(xc_error_obj);
- if (err->message[0] != '\0')
+ if ( err->message[0] != '\0' )
pyerr = Py_BuildValue("(iss)", err->code, desc, err->message);
else
pyerr = Py_BuildValue("(is)", err->code, desc);
xc_clear_last_error();
- PyErr_SetObject(xc_error_obj, pyerr);
+ if ( pyerr != NULL )
+ {
+ PyErr_SetObject(xc_error_obj, pyerr);
+ Py_DECREF(pyerr);
+ }
return NULL;
}
@@ -70,13 +74,13 @@ static PyObject *pyxc_domain_dumpcore(XcObject *self, PyObject *args)
uint32_t dom;
char *corefile;
- if (!PyArg_ParseTuple(args, "is", &dom, &corefile))
+ if ( !PyArg_ParseTuple(args, "is", &dom, &corefile) )
return NULL;
if ( (corefile == NULL) || (corefile[0] == '\0') )
return NULL;
- if (xc_domain_dumpcore(self->xc_handle, dom, corefile) != 0)
+ if ( xc_domain_dumpcore(self->xc_handle, dom, corefile) != 0 )
return pyxc_error_to_exception();
Py_INCREF(zero);
@@ -168,10 +172,10 @@ static PyObject *pyxc_domain_shutdown(XcObject *self, PyObject *args)
{
uint32_t dom, reason;
- if (!PyArg_ParseTuple(args, "ii", &dom, &reason))
+ if ( !PyArg_ParseTuple(args, "ii", &dom, &reason) )
return NULL;
- if (xc_domain_shutdown(self->xc_handle, dom, reason) != 0)
+ if ( xc_domain_shutdown(self->xc_handle, dom, reason) != 0 )
return pyxc_error_to_exception();
Py_INCREF(zero);
@@ -183,10 +187,10 @@ static PyObject *pyxc_domain_resume(XcObject *self, PyObject *args)
uint32_t dom;
int fast;
- if (!PyArg_ParseTuple(args, "ii", &dom, &fast))
+ if ( !PyArg_ParseTuple(args, "ii", &dom, &fast) )
return NULL;
- if (xc_domain_resume(self->xc_handle, dom, fast) != 0)
+ if ( xc_domain_resume(self->xc_handle, dom, fast) != 0 )
return pyxc_error_to_exception();
Py_INCREF(zero);
@@ -282,7 +286,7 @@ static PyObject *pyxc_domain_getinfo(XcObject *self,
PyObject *args,
PyObject *kwds)
{
- PyObject *list, *info_dict;
+ PyObject *list, *info_dict, *pyhandle;
uint32_t first_dom = 0;
int max_doms = 1024, nr_doms, i, j;
@@ -308,26 +312,34 @@ static PyObject *pyxc_domain_getinfo(XcObject *self,
list = PyList_New(nr_doms);
for ( i = 0 ; i < nr_doms; i++ )
{
- PyObject *pyhandle = PyList_New(sizeof(xen_domain_handle_t));
+ info_dict = Py_BuildValue(
+ "{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i"
+ ",s:L,s:L,s:L,s:i,s:i}",
+ "domid", (int)info[i].domid,
+ "online_vcpus", info[i].nr_online_vcpus,
+ "max_vcpu_id", info[i].max_vcpu_id,
+ "hvm", info[i].hvm,
+ "dying", info[i].dying,
+ "crashed", info[i].crashed,
+ "shutdown", info[i].shutdown,
+ "paused", info[i].paused,
+ "blocked", info[i].blocked,
+ "running", info[i].running,
+ "mem_kb", (long long)info[i].nr_pages*(XC_PAGE_SIZE/1024),
+ "cpu_time", (long long)info[i].cpu_time,
+ "maxmem_kb", (long long)info[i].max_memkb,
+ "ssidref", (int)info[i].ssidref,
+ "shutdown_reason", info[i].shutdown_reason);
+ pyhandle = PyList_New(sizeof(xen_domain_handle_t));
+ if ( (pyhandle == NULL) || (info_dict == NULL) )
+ {
+ Py_DECREF(list);
+ if ( pyhandle != NULL ) { Py_DECREF(pyhandle); }
+ if ( info_dict != NULL ) { Py_DECREF(info_dict); }
+ return NULL;
+ }
for ( j = 0; j < sizeof(xen_domain_handle_t); j++ )
PyList_SetItem(pyhandle, j, PyInt_FromLong(info[i].handle[j]));
- info_dict = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i"
- ",s:l,s:L,s:l,s:i,s:i}",
- "domid", info[i].domid,
- "online_vcpus", info[i].nr_online_vcpus,
- "max_vcpu_id", info[i].max_vcpu_id,
- "hvm", info[i].hvm,
- "dying", info[i].dying,
- "crashed", info[i].crashed,
- "shutdown", info[i].shutdown,
- "paused", info[i].paused,
- "blocked", info[i].blocked,
- "running", info[i].running,
- "mem_kb", info[i].nr_pages*(XC_PAGE_SIZE/1024),
- "cpu_time", info[i].cpu_time,
- "maxmem_kb", info[i].max_memkb,
- "ssidref", info[i].ssidref,
- "shutdown_reason", info[i].shutdown_reason);
PyDict_SetItemString(info_dict, "handle", pyhandle);
Py_DECREF(pyhandle);
PyList_SetItem(list, i, info_dict);
@@ -1007,6 +1019,24 @@ static PyObject *pyxc_domain_send_trigger(XcObject *self,
return zero;
}
+static PyObject *pyxc_send_debug_keys(XcObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ char *keys;
+
+ static char *kwd_list[] = { "keys", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "s", kwd_list, &keys) )
+ return NULL;
+
+ if ( xc_send_debug_keys(self->xc_handle, keys) != 0 )
+ return pyxc_error_to_exception();
+
+ Py_INCREF(zero);
+ return zero;
+}
+
static PyObject *dom_op(XcObject *self, PyObject *args,
int (*fn)(int, uint32_t))
{
@@ -1380,6 +1410,12 @@ static PyMethodDef pyxc_methods[] = {
" vcpu [int]: VCPU to be sent trigger.\n"
"Returns: [int] 0 on success; -1 on error.\n" },
+ { "send_debug_keys",
+ (PyCFunction)pyxc_send_debug_keys,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Inject debug keys into Xen.\n"
+ " keys [str]: String of keys to inject.\n" },
+
#ifdef __powerpc__
{ "arch_alloc_real_mode_area",
(PyCFunction)pyxc_alloc_real_mode_area,
diff --git a/tools/python/xen/util/blkif.py b/tools/python/xen/util/blkif.py
index 363bd41dd2..15d20dde8c 100644
--- a/tools/python/xen/util/blkif.py
+++ b/tools/python/xen/util/blkif.py
@@ -66,16 +66,23 @@ def blkdev_segment(name):
'type' : 'Disk' }
return val
-def blkdev_uname_to_file(uname):
- """Take a blkdev uname and return the corresponding filename."""
- fn = None
+def _parse_uname(uname):
+ fn = taptype = None
if uname.find(":") != -1:
(typ, fn) = uname.split(":", 1)
if typ == "phy" and not fn.startswith("/"):
fn = "/dev/%s" %(fn,)
if typ == "tap":
- (typ, fn) = fn.split(":", 1)
- return fn
+ (taptype, fn) = fn.split(":", 1)
+ return (fn, taptype)
+
+def blkdev_uname_to_file(uname):
+ """Take a blkdev uname and return the corresponding filename."""
+ return _parse_uname(uname)[0]
+
+def blkdev_uname_to_taptype(uname):
+ """Take a blkdev uname and return the blktap type."""
+ return _parse_uname(uname)[1]
def mount_mode(name):
mode = None
diff --git a/tools/python/xen/util/xmlrpclib2.py b/tools/python/xen/util/xmlrpclib2.py
index a77b61b5ee..3bdd717de2 100644
--- a/tools/python/xen/util/xmlrpclib2.py
+++ b/tools/python/xen/util/xmlrpclib2.py
@@ -200,6 +200,18 @@ class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
else:
response = self._dispatch(method, params)
+ if self.xenapi and \
+ (response is None or
+ not isinstance(response, dict) or
+ 'Status' not in response):
+ log.exception('Internal error handling %s: Invalid result %s',
+ method, response)
+ response = { "Status": "Failure",
+ "ErrorDescription":
+ ['INTERNAL_ERROR',
+ 'Invalid result %s handling %s' %
+ (response, method)]}
+
# With either Unicode or normal strings, we can only transmit
# \t, \n, \r, \u0020-\ud7ff, \ue000-\ufffd, and \u10000-\u10ffff
# in an XML document. xmlrpclib does not escape these values
@@ -215,24 +227,30 @@ class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer):
response = xmlrpclib.dumps(response,
methodresponse=1,
allow_none=1)
- except xmlrpclib.Fault, fault:
- response = xmlrpclib.dumps(fault)
except Exception, exn:
- if self.xenapi:
- if _is_not_supported(exn):
- errdesc = ['MESSAGE_METHOD_UNKNOWN', method]
+ try:
+ if self.xenapi:
+ if _is_not_supported(exn):
+ errdesc = ['MESSAGE_METHOD_UNKNOWN', method]
+ else:
+ log.exception('Internal error handling %s', method)
+ errdesc = ['INTERNAL_ERROR', str(exn)]
+
+ response = xmlrpclib.dumps(
+ ({ "Status": "Failure",
+ "ErrorDescription": errdesc },),
+ methodresponse = 1)
else:
- log.exception('Internal error handling %s', method)
- errdesc = ['INTERNAL_ERROR', str(exn)]
- response = xmlrpclib.dumps(
- ({ "Status": "Failure",
- "ErrorDescription": errdesc },),
- methodresponse = 1)
- else:
- log.exception('Internal error handling %s', method)
- import xen.xend.XendClient
- response = xmlrpclib.dumps(
- xmlrpclib.Fault(xen.xend.XendClient.ERROR_INTERNAL, str(exn)))
+ import xen.xend.XendClient
+ if isinstance(exn, xmlrpclib.Fault):
+ response = xmlrpclib.dumps(exn)
+ else:
+ log.exception('Internal error handling %s', method)
+ response = xmlrpclib.dumps(
+ xmlrpclib.Fault(xen.xend.XendClient.ERROR_INTERNAL, str(exn)))
+ except:
+ log.exception('Internal error handling error')
+
return response
@@ -241,7 +259,7 @@ def _is_not_supported(exn):
try:
m = notSupportedRE.search(exn[0])
return m is not None
- except TypeError, e:
+ except:
return False
diff --git a/tools/python/xen/xend/XendAPI.py b/tools/python/xen/xend/XendAPI.py
index 4ab6916b53..a0f7c351b4 100644
--- a/tools/python/xen/xend/XendAPI.py
+++ b/tools/python/xen/xend/XendAPI.py
@@ -31,10 +31,14 @@ from xen.xend.XendError import *
from xen.xend.XendClient import ERROR_INVALID_DOMAIN
from xen.xend.XendLogging import log
from xen.xend.XendTask import XendTask
+from xen.xend.XendVMMetrics import XendVMMetrics
from xen.xend.XendAPIConstants import *
from xen.util.xmlrpclib2 import stringify
+from xen.util.blkif import blkdev_name_to_number
+
+
AUTH_NONE = 'none'
AUTH_PAM = 'pam'
@@ -192,6 +196,16 @@ def valid_vm(func):
_check_ref(XendDomain.instance().is_valid_vm,
'VM', func, *args, **kwargs)
+def valid_vm_metrics(func):
+ """Decorator to verify if vm_metrics_ref is valid before calling method.
+
+ @param func: function with params: (self, session, vm_metrics_ref, ...)
+ @rtype: callable object
+ """
+ return lambda *args, **kwargs: \
+ _check_ref(XendVMMetrics.is_valid_vm_metrics,
+ 'VM_metrics', func, *args, **kwargs)
+
def valid_network(func):
"""Decorator to verify if network_ref is valid before calling method.
@@ -400,6 +414,7 @@ class XendAPI(object):
'host_metrics' : valid_host_metrics,
'network' : valid_network,
'VM' : valid_vm,
+ 'VM_metrics' : valid_vm_metrics,
'VBD' : valid_vbd,
'VBD_metrics' : valid_vbd_metrics,
'VIF' : valid_vif,
@@ -629,6 +644,7 @@ class XendAPI(object):
host_attr_ro = ['software_version',
'resident_VMs',
'host_CPUs',
+ 'cpu_configuration',
'metrics',
'capabilities',
'supported_bootloaders',
@@ -638,6 +654,7 @@ class XendAPI(object):
'API_version_vendor_implementation']
host_attr_rw = ['name_label',
+ 'sched_policy',
'name_description',
'other_config']
@@ -647,7 +664,9 @@ class XendAPI(object):
('shutdown', None),
('add_to_other_config', None),
('remove_from_other_config', None),
- ('dmesg', 'String')]
+ ('dmesg', 'String'),
+ ('get_log', 'String'),
+ ('send_debug_keys', None)]
host_funcs = [('get_by_name_label', 'Set(host)')]
@@ -676,8 +695,9 @@ class XendAPI(object):
return xen_api_success_void()
def host_remove_from_other_config(self, session, host_ref, key):
node = XendNode.instance()
- del node.other_config[key]
- node.save()
+ if key in node.other_config:
+ del node.other_config[key]
+ node.save()
return xen_api_success_void()
def host_get_API_version_major(self, _, ref):
return xen_api_success(XEN_API_VERSION_MAJOR)
@@ -699,7 +719,13 @@ class XendAPI(object):
return xen_api_success(XendNode.instance().get_capabilities())
def host_get_supported_bootloaders(self, session, host_ref):
return xen_api_success(['pygrub'])
-
+ def host_get_sched_policy(self, _, host_ref):
+ return xen_api_success(XendNode.instance().get_vcpus_policy())
+ def host_set_sched_policy(self, _, host_ref, policy):
+ return xen_api_todo()
+ def host_get_cpu_configuration(self, _, host_ref):
+ return xen_api_success(XendNode.instance().get_cpu_configuration())
+
# object methods
def host_disable(self, session, host_ref):
XendDomain.instance().set_allow_new_domains(False)
@@ -716,8 +742,21 @@ class XendAPI(object):
return xen_api_error(XEND_ERROR_HOST_RUNNING)
return xen_api_error(XEND_ERROR_UNSUPPORTED)
- def host_dmesg(self, session, host_ref):
- return xen_api_success(XendDmesg.instance().info())
+ def host_dmesg(self, session, host_ref, clear):
+ if clear:
+ return xen_api_success(XendDmesg.instance().clear())
+ else:
+ return xen_api_success(XendDmesg.instance().info())
+
+ def host_get_log(self, session, host_ref):
+ log_file = open(XendLogging.getLogFilename())
+ log_buffer = log_file.read()
+ return xen_api_success(log_buffer)
+
+ def host_send_debug_keys(self, _, host_ref, keys):
+ node = XendNode.instance()
+ node.send_debug_keys(keys)
+ return xen_api_success_void()
def host_get_record(self, session, host_ref):
node = XendNode.instance()
@@ -734,9 +773,11 @@ class XendAPI(object):
'other_config': node.other_config,
'resident_VMs': dom.get_domain_refs(),
'host_CPUs': node.get_host_cpu_refs(),
+ 'cpu_configuration': node.get_cpu_configuration(),
'metrics': node.host_metrics_uuid,
'capabilities': node.get_capabilities(),
- 'supported_bootloaders': 'pygrub'}
+ 'supported_bootloaders': 'pygrub',
+ 'sched_policy': node.get_vcpus_policy()}
return xen_api_success(record)
# class methods
@@ -758,7 +799,8 @@ class XendAPI(object):
'modelname',
'stepping',
'flags',
- 'utilisation']
+ 'utilisation',
+ 'features']
# attributes
def _host_cpu_get(self, ref, field):
@@ -767,6 +809,8 @@ class XendAPI(object):
def host_cpu_get_host(self, _, ref):
return xen_api_success(XendNode.instance().uuid)
+ def host_cpu_get_features(self, _, ref):
+ return self._host_cpu_get(ref, 'features')
def host_cpu_get_number(self, _, ref):
return self._host_cpu_get(ref, 'number')
def host_cpu_get_vendor(self, _, ref):
@@ -989,19 +1033,17 @@ class XendAPI(object):
VM_attr_ro = ['power_state',
'resident_on',
- 'memory_actual',
'memory_static_max',
'memory_static_min',
'VCPUs_number',
- 'VCPUs_utilisation',
'consoles',
'VIFs',
'VBDs',
'VTPMs',
- 'PCI_bus',
'tools_version',
'domid',
'is_control_domain',
+ 'metrics'
]
VM_attr_rw = ['name_label',
@@ -1011,7 +1053,6 @@ class XendAPI(object):
'auto_power_on',
'memory_dynamic_max',
'memory_dynamic_min',
- 'VCPUs_policy',
'VCPUs_params',
'actions_after_shutdown',
'actions_after_reboot',
@@ -1024,12 +1065,8 @@ class XendAPI(object):
'PV_bootloader_args',
'HVM_boot_policy',
'HVM_boot_params',
- 'platform_std_VGA',
- 'platform_serial',
- 'platform_localtime',
- 'platform_clock_offset',
- 'platform_enable_audio',
- 'platform_keymap',
+ 'platform',
+ 'PCI_bus',
'other_config']
VM_methods = [('clone', 'VM'),
@@ -1042,8 +1079,16 @@ class XendAPI(object):
('hard_reboot', None),
('suspend', None),
('resume', None),
+ ('send_sysrq', None),
+ ('add_to_HVM_boot_params', None),
+ ('remove_from_HVM_boot_params', None),
+ ('add_to_VCPUs_params', None),
+ ('remove_from_VCPUs_params', None),
+ ('add_to_platform', None),
+ ('remove_from_platform', None),
('add_to_other_config', None),
- ('remove_from_other_config', None)]
+ ('remove_from_other_config', None),
+ ('send_trigger', None)]
VM_funcs = [('create', 'VM'),
('get_by_name_label', 'Set(VM)')]
@@ -1058,7 +1103,6 @@ class XendAPI(object):
'memory_dynamic_max',
'memory_dynamic_min',
'memory_static_min',
- 'VCPUs_policy',
'VCPUs_params',
'actions_after_shutdown',
'actions_after_reboot',
@@ -1071,13 +1115,7 @@ class XendAPI(object):
'PV_bootloader_args',
'HVM_boot_policy',
'HVM_boot_params',
- 'platform_std_VGA',
- 'platform_serial',
- 'platform_localtime',
- 'platform_clock_offset',
- 'platform_enable_audio',
- 'platform_keymap',
- 'grub_cmdline',
+ 'platform',
'PCI_bus',
'other_config']
@@ -1089,7 +1127,10 @@ class XendAPI(object):
xd = XendDomain.instance()
dominfo = xd.get_vm_by_uuid(vm_ref)
dominfo.info[name] = value
- xd.managed_config_save(dominfo)
+ return self._VM_save(dominfo)
+
+ def _VM_save(self, dominfo):
+ XendDomain.instance().managed_config_save(dominfo)
return xen_api_success_void()
# attributes (ro)
@@ -1099,11 +1140,7 @@ class XendAPI(object):
def VM_get_resident_on(self, session, vm_ref):
return xen_api_success(XendNode.instance().uuid)
-
- def VM_get_memory_actual(self, session, vm_ref):
- dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- return xen_api_todo() # unsupported by xc
-
+
def VM_get_memory_static_max(self, session, vm_ref):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
return xen_api_success(dom.get_memory_static_max())
@@ -1116,10 +1153,6 @@ class XendAPI(object):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
return xen_api_success(dom.getVCpuCount())
- def VM_get_VCPUs_utilisation(self, session, vm_ref):
- dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- return xen_api_success(dom.get_vcpus_util())
-
def VM_get_VIFs(self, session, vm_ref):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
return xen_api_success(dom.get_vifs())
@@ -1136,14 +1169,14 @@ class XendAPI(object):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
return xen_api_success(dom.get_consoles())
- def VM_get_PCI_bus(self, session, vm_ref):
- dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- return dom.get_pci_bus()
-
def VM_get_tools_version(self, session, vm_ref):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
return dom.get_tools_version()
+ def VM_get_metrics(self, _, vm_ref):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ return xen_api_success(dom.get_metrics())
+
# attributes (rw)
def VM_get_name_label(self, session, vm_ref):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
@@ -1167,11 +1200,7 @@ class XendAPI(object):
def VM_get_memory_dynamic_min(self, session, vm_ref):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- return xen_api_success(dom.get_memory_dynamic_min())
-
- def VM_get_VCPUs_policy(self, session, vm_ref):
- dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- return xen_api_success(dom.get_vcpus_policy())
+ return xen_api_success(dom.get_memory_dynamic_min())
def VM_get_VCPUs_params(self, session, vm_ref):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
@@ -1214,29 +1243,16 @@ class XendAPI(object):
def VM_get_HVM_boot_params(self, session, vm_ref):
return self.VM_get('HVM_boot_params', session, vm_ref)
- def VM_get_platform_std_VGA(self, session, vm_ref):
+ def VM_get_platform(self, session, vm_ref):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- return xen_api_success(dom.get_platform_std_vga())
+ return xen_api_success(dom.get_platform())
- def VM_get_platform_serial(self, session, vm_ref):
- dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- return xen_api_success(dom.get_platform_serial())
-
- def VM_get_platform_localtime(self, session, vm_ref):
- dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- return xen_api_success(dom.get_platform_localtime())
-
- def VM_get_platform_clock_offset(self, session, vm_ref):
- dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- return xen_api_success(dom.get_platform_clock_offset())
-
- def VM_get_platform_enable_audio(self, session, vm_ref):
+ def VM_get_PCI_bus(self, session, vm_ref):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- return xen_api_success(dom.get_platform_enable_audio())
+ return dom.get_pci_bus()
- def VM_get_platform_keymap(self, session, vm_ref):
- dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- return xen_api_success(dom.get_platform_keymap())
+ def VM_set_PCI_bus(self, session, vm_ref, val):
+ return self.VM_set('PCI_bus', session, vm_ref, val)
def VM_get_other_config(self, session, vm_ref):
return self.VM_get('other_config', session, vm_ref)
@@ -1253,7 +1269,7 @@ class XendAPI(object):
def VM_set_name_label(self, session, vm_ref, label):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
dom.setName(label)
- return xen_api_success_void()
+ return self._VM_save(dom)
def VM_set_name_description(self, session, vm_ref, desc):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
@@ -1275,21 +1291,32 @@ class XendAPI(object):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
return xen_api_todo()
- def VM_set_VCPUs_policy(self, session, vm_ref, policy):
+ def VM_set_VCPUs_params(self, session, vm_ref, value):
+ return self.VM_set('vcpus_params', session, vm_ref, value)
+
+ def VM_add_to_VCPUs_params(self, session, vm_ref, key, value):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- return xen_api_todo()
-
- def VM_set_VCPUs_params(self, session, vm_ref, params):
+ if 'vcpus_params' not in dom.info:
+ dom.info['vcpus_params'] = {}
+ dom.info['vcpus_params'][key] = value
+ return self._VM_save(dom)
+
+ def VM_remove_from_VCPUs_params(self, session, vm_ref, key):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- return xen_api_todo()
+ if 'vcpus_params' in dom.info \
+ and key in dom.info['vcpus_params']:
+ del dom.info['vcpus_params'][key]
+ return self._VM_save(dom)
+ else:
+ return xen_api_success_void()
def VM_set_actions_after_shutdown(self, session, vm_ref, action):
- if action not in XEN_API_ON_NORMAL_EXIST:
+ if action not in XEN_API_ON_NORMAL_EXIT:
return xen_api_error(['VM_ON_NORMAL_EXIT_INVALID', vm_ref])
return self.VM_set('actions_after_shutdown', session, vm_ref, action)
def VM_set_actions_after_reboot(self, session, vm_ref, action):
- if action not in XEN_API_ON_NORMAL_EXIST:
+ if action not in XEN_API_ON_NORMAL_EXIT:
return xen_api_error(['VM_ON_NORMAL_EXIT_INVALID', vm_ref])
return self.VM_set('actions_after_reboot', session, vm_ref, action)
@@ -1319,14 +1346,16 @@ class XendAPI(object):
if 'HVM_boot_params' not in dom.info:
dom.info['HVM_boot_params'] = {}
dom.info['HVM_boot_params'][key] = value
- return xen_api_success_void()
+ return self._VM_save(dom)
def VM_remove_from_HVM_boot_params(self, session, vm_ref, key):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
if 'HVM_boot_params' in dom.info \
and key in dom.info['HVM_boot_params']:
del dom.info['HVM_boot_params'][key]
- return xen_api_success_void()
+ return self._VM_save(dom)
+ else:
+ return xen_api_success_void()
def VM_set_PV_bootloader(self, session, vm_ref, value):
return self.VM_set('PV_bootloader', session, vm_ref, value)
@@ -1343,40 +1372,42 @@ class XendAPI(object):
def VM_set_PV_bootloader_args(self, session, vm_ref, value):
return self.VM_set('PV_bootloader_args', session, vm_ref, value)
- def VM_set_platform_std_VGA(self, session, vm_ref, value):
- return self.VM_set('platform_std_vga', session, vm_ref, value)
+ def VM_set_platform(self, session, vm_ref, value):
+ return self.VM_set('platform', session, vm_ref, value)
- def VM_set_platform_serial(self, session, vm_ref, value):
- return self.VM_set('platform_serial', session, vm_ref, value)
+ def VM_add_to_platform(self, session, vm_ref, key, value):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ plat = dom.get_platform()
+ plat[key] = value
+ return self.VM_set_platform(session, vm_ref, plat)
+
+ def VM_remove_from_platform(self, session, vm_ref, key):
+ dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ plat = dom.get_platform()
+ if key in plat:
+ del plat[key]
+ return self.VM_set_platform(session, vm_ref, plat)
+ else:
+ return xen_api_success_void()
- def VM_set_platform_keymap(self, session, vm_ref, value):
- return self.VM_set('platform_keymap', session, vm_ref, value)
-
- def VM_set_platform_localtime(self, session, vm_ref, value):
- return self.VM_set('platform_localtime', session, vm_ref, value)
-
- def VM_set_platform_clock_offset(self, session, vm_ref, value):
- return self.VM_set('platform_clock_offset', session, vm_ref, value)
-
- def VM_set_platform_enable_audio(self, session, vm_ref, value):
- return self.VM_set('platform_enable_audio', session, vm_ref, value)
-
def VM_set_other_config(self, session, vm_ref, value):
- return self.VM_set('otherconfig', session, vm_ref, value)
+ return self.VM_set('other_config', session, vm_ref, value)
def VM_add_to_other_config(self, session, vm_ref, key, value):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- if dom and 'otherconfig' in dom.info:
- dom.info['otherconfig'][key] = value
- return xen_api_success_void()
+ if dom and 'other_config' in dom.info:
+ dom.info['other_config'][key] = value
+ return self._VM_save(dom)
def VM_remove_from_other_config(self, session, vm_ref, key):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- if dom and 'otherconfig' in dom.info \
- and key in dom.info['otherconfig']:
- del dom.info['otherconfig'][key]
- return xen_api_success_void()
-
+ if dom and 'other_config' in dom.info \
+ and key in dom.info['other_config']:
+ del dom.info['other_config'][key]
+ return self._VM_save(dom)
+ else:
+ return xen_api_success_void()
+
# class methods
def VM_get_all(self, session):
refs = [d.get_uuid() for d in XendDomain.instance().list('all')]
@@ -1417,11 +1448,8 @@ class XendAPI(object):
'memory_static_max': xeninfo.get_memory_static_max(),
'memory_dynamic_min': xeninfo.get_memory_dynamic_min(),
'memory_dynamic_max': xeninfo.get_memory_dynamic_max(),
- 'memory_actual': xeninfo.get_memory_static_min(),
- 'VCPUs_policy': xeninfo.get_vcpus_policy(),
'VCPUs_params': xeninfo.get_vcpus_params(),
'VCPUs_number': xeninfo.getVCpuCount(),
- 'VCPUs_utilisation': xeninfo.get_vcpus_util(),
'actions_after_shutdown': xeninfo.get_on_shutdown(),
'actions_after_reboot': xeninfo.get_on_reboot(),
'actions_after_suspend': xeninfo.get_on_suspend(),
@@ -1437,12 +1465,7 @@ class XendAPI(object):
'PV_bootloader_args': xeninfo.info.get('PV_bootloader_args'),
'HVM_boot_policy': xeninfo.info.get('HVM_boot_policy'),
'HVM_boot_params': xeninfo.info.get('HVM_boot_params'),
- 'platform_std_VGA': xeninfo.get_platform_std_vga(),
- 'platform_serial': xeninfo.get_platform_serial(),
- 'platform_localtime': xeninfo.get_platform_localtime(),
- 'platform_clock_offset': xeninfo.get_platform_clock_offset(),
- 'platform_enable_audio': xeninfo.get_platform_enable_audio(),
- 'platform_keymap': xeninfo.get_platform_keymap(),
+ 'platform': xeninfo.get_platform(),
'PCI_bus': xeninfo.get_pci_bus(),
'tools_version': xeninfo.get_tools_version(),
'other_config': xeninfo.info.get('other_config', {}),
@@ -1486,10 +1509,13 @@ class XendAPI(object):
start_paused = start_paused)
def VM_start(self, session, vm_ref, start_paused):
- return XendTask.log_progress(0, 100, do_vm_func,
- "domain_start", vm_ref,
- start_paused = start_paused)
-
+ try:
+ return XendTask.log_progress(0, 100, do_vm_func,
+ "domain_start", vm_ref,
+ start_paused = start_paused)
+ except HVMRequired, exn:
+ return xen_api_error(['VM_HVM_REQUIRED', vm_ref])
+
def VM_suspend(self, session, vm_ref):
return XendTask.log_progress(0, 100, do_vm_func,
"domain_suspend", vm_ref)
@@ -1498,10 +1524,56 @@ class XendAPI(object):
return XendTask.log_progress(0, 100, do_vm_func,
"domain_unpause", vm_ref)
+ def VM_send_sysrq(self, _, vm_ref, req):
+ xeninfo = XendDomain.instance().get_vm_by_uuid(vm_ref)
+ if xeninfo.state != XEN_API_VM_POWER_STATE_RUNNING:
+ return xen_api_error(
+ ['VM_BAD_POWER_STATE', vm_ref,
+ XendDomain.POWER_STATE_NAMES[XEN_API_VM_POWER_STATE_RUNNING],
+ XendDomain.POWER_STATE_NAMES[xeninfo.state]])
+ xeninfo.send_sysrq(req)
+ return xen_api_success_void()
+
+
+ def VM_send_trigger(self, _, vm_ref, trigger, vcpu):
+ xendom = XendDomain.instance()
+ xeninfo = xendom.get_vm_by_uuid(vm_ref)
+ xendom.domain_send_trigger(xeninfo.getDomid(), trigger, vcpu)
+ return xen_api_success_void()
+
+
+ # Xen API: Class VM_metrics
+ # ----------------------------------------------------------------
+
+ VM_metrics_attr_ro = ['memory_actual',
+ 'vcpus_number',
+ 'vcpus_utilisation']
+ VM_metrics_attr_rw = []
+ VM_metrics_methods = []
+
+ def _VM_metrics_get(self, ref):
+ return XendVMMetrics.get_by_uuid(ref)
+
+ def VM_metrics_get_all(self, _):
+ return xen_api_success(XendVMMetrics.get_all())
+
+ def VM_metrics_get_record(self, _, ref):
+ return xen_api_success(self._VM_metrics_get(ref).get_record())
+
+ def VM_metrics_get_memory_actual(self, _, ref):
+ return xen_api_success(self._VM_metrics_get(ref).get_memory_actual())
+
+ def VM_metrics_get_vcpus_number(self, _, ref):
+ return xen_api_success(self._VM_metrics_get(ref).get_vcpus_number())
+
+ def VM_metrics_get_vcpus_utilisation(self, _, ref):
+ return xen_api_success(self._VM_metrics_get(ref).get_vcpus_utilisation())
+
# Xen API: Class VBD
# ----------------------------------------------------------------
- VBD_attr_ro = ['metrics']
+ VBD_attr_ro = ['metrics',
+ 'runtime_properties']
VBD_attr_rw = ['VM',
'VDI',
'device',
@@ -1542,23 +1614,28 @@ class XendAPI(object):
# class methods
def VBD_create(self, session, vbd_struct):
xendom = XendDomain.instance()
+ xennode = XendNode.instance()
+
if not xendom.is_valid_vm(vbd_struct['VM']):
return xen_api_error(['HANDLE_INVALID', 'VM', vbd_struct['VM']])
dom = xendom.get_vm_by_uuid(vbd_struct['VM'])
- vbd_ref = ''
+ vdi = xennode.get_vdi_by_uuid(vbd_struct['VDI'])
+ if not vdi:
+ return xen_api_error(['HANDLE_INVALID', 'VDI', vdi_ref])
+
+ # new VBD via VDI/SR
+ vdi_image = vdi.get_location()
+
try:
- # new VBD via VDI/SR
- vdi_ref = vbd_struct.get('VDI')
- vdi = XendNode.instance().get_vdi_by_uuid(vdi_ref)
- if not vdi:
- return xen_api_error(['HANDLE_INVALID', 'VDI', vdi_ref])
- vdi_image = vdi.get_location()
vbd_ref = XendTask.log_progress(0, 100,
dom.create_vbd,
vbd_struct, vdi_image)
- except XendError:
- return xen_api_todo()
+ except XendError, e:
+ log.exception("Error in VBD_create")
+ return xen_api_error(['INTERNAL_ERROR', str(e)])
+
+ vdi.addVBD(vbd_ref)
xendom.managed_config_save(dom)
return xen_api_success(vbd_ref)
@@ -1570,7 +1647,14 @@ class XendAPI(object):
if not vm:
return xen_api_error(['HANDLE_INVALID', 'VBD', vbd_ref])
+ vdi_ref = XendDomain.instance()\
+ .get_dev_property_by_uuid('vbd', vbd_ref, "VDI")
+ vdi = XendNode.instance().get_vdi_by_uuid(vdi_ref)
+
XendTask.log_progress(0, 100, vm.destroy_vbd, vbd_ref)
+
+ vdi.removeVBD(vbd_ref)
+
return xen_api_success_void()
def _VBD_get(self, vbd_ref, prop):
@@ -1582,6 +1666,24 @@ class XendAPI(object):
def VBD_get_metrics(self, _, vbd_ref):
return xen_api_success(vbd_ref)
+ def VBD_get_runtime_properties(self, _, vbd_ref):
+ xendom = XendDomain.instance()
+ dominfo = xendom.get_vm_with_dev_uuid('vbd', vbd_ref)
+ device = dominfo.get_dev_config_by_uuid('vbd', vbd_ref)
+
+ try:
+ devid = int(device['id'])
+ device_sxps = dominfo.getDeviceSxprs('vbd')
+ device_dicts = [dict(device_sxp[1][1:]) for device_sxp in device_sxps]
+ device_dict = [device_dict
+ for device_dict in device_dicts
+ if int(device_dict['virtual-device']) == devid][0]
+
+ return xen_api_success(device_dict)
+ except Exception, exn:
+ log.exception(exn)
+ return xen_api_success({})
+
# attributes (rw)
def VBD_get_VM(self, session, vbd_ref):
return self._VBD_get(vbd_ref, 'VM')
@@ -1642,7 +1744,8 @@ class XendAPI(object):
# Xen API: Class VIF
# ----------------------------------------------------------------
- VIF_attr_ro = ['metrics']
+ VIF_attr_ro = ['metrics',
+ 'runtime_properties']
VIF_attr_rw = ['device',
'network',
'VM',
@@ -1679,18 +1782,17 @@ class XendAPI(object):
# class methods
def VIF_create(self, session, vif_struct):
xendom = XendDomain.instance()
- if xendom.is_valid_vm(vif_struct['VM']):
- dom = xendom.get_vm_by_uuid(vif_struct['VM'])
- try:
- vif_ref = dom.create_vif(vif_struct)
- xendom.managed_config_save(dom)
- return xen_api_success(vif_ref)
- except XendError:
- return xen_api_error(XEND_ERROR_TODO)
- else:
+ if not xendom.is_valid_vm(vif_struct['VM']):
return xen_api_error(['HANDLE_INVALID', 'VM', vif_struct['VM']])
-
+ dom = xendom.get_vm_by_uuid(vif_struct['VM'])
+ try:
+ vif_ref = dom.create_vif(vif_struct)
+ xendom.managed_config_save(dom)
+ return xen_api_success(vif_ref)
+ except XendError:
+ return xen_api_error(XEND_ERROR_TODO)
+
def VIF_destroy(self, session, vif_ref):
xendom = XendDomain.instance()
vm = xendom.get_vm_with_dev_uuid('vif', vif_ref)
@@ -1728,6 +1830,27 @@ class XendAPI(object):
vifs = reduce(lambda x, y: x + y, vifs)
return xen_api_success(vifs)
+ def VIF_get_runtime_properties(self, _, vif_ref):
+ xendom = XendDomain.instance()
+ dominfo = xendom.get_vm_with_dev_uuid('vif', vif_ref)
+ device = dominfo.get_dev_config_by_uuid('vif', vif_ref)
+
+ try:
+ devid = int(device['id'])
+
+ device_sxps = dominfo.getDeviceSxprs('vif')
+ device_dicts = [dict(device_sxp[1][1:])
+ for device_sxp in device_sxps]
+
+ device_dict = [device_dict
+ for device_dict in device_dicts
+ if int(device_dict['handle']) == devid][0]
+
+ return xen_api_success(device_dict)
+
+ except Exception, exn:
+ log.exception(exn)
+ return xen_api_success({})
# Xen API: Class VIF_metrics
# ----------------------------------------------------------------
@@ -1754,16 +1877,16 @@ class XendAPI(object):
# Xen API: Class VDI
# ----------------------------------------------------------------
- VDI_attr_ro = ['VBDs',
+ VDI_attr_ro = ['SR',
+ 'VBDs',
'physical_utilisation',
- 'sector_size',
'type']
VDI_attr_rw = ['name_label',
'name_description',
- 'SR',
'virtual_size',
'sharable',
- 'read_only']
+ 'read_only',
+ 'other_config']
VDI_attr_inst = VDI_attr_ro + VDI_attr_rw
VDI_methods = [('snapshot', 'VDI')]
@@ -1774,14 +1897,12 @@ class XendAPI(object):
return XendNode.instance().get_vdi_by_uuid(ref)
def VDI_get_VBDs(self, session, vdi_ref):
- return xen_api_todo()
+ vdi = XendNode.instance().get_vdi_by_uuid(vdi_ref)
+ return xen_api_success(vdi.getVBDs())
def VDI_get_physical_utilisation(self, session, vdi_ref):
return xen_api_success(self._get_VDI(vdi_ref).
- get_physical_utilisation())
-
- def VDI_get_sector_size(self, session, vdi_ref):
- return xen_api_success(self._get_VDI(vdi_ref).sector_size)
+ get_physical_utilisation())
def VDI_get_type(self, session, vdi_ref):
return xen_api_success(self._get_VDI(vdi_ref).type)
@@ -1812,9 +1933,6 @@ class XendAPI(object):
self._get_VDI(vdi_ref).name_description = value
return xen_api_success_void()
- def VDI_set_SR(self, session, vdi_ref, value):
- return xen_api_error(XEND_ERROR_UNSUPPORTED)
-
def VDI_set_virtual_size(self, session, vdi_ref, value):
return xen_api_error(XEND_ERROR_UNSUPPORTED)
@@ -1826,6 +1944,14 @@ class XendAPI(object):
self._get_VDI(vdi_ref).read_only = bool(value)
return xen_api_success_void()
+ def VDI_get_other_config(self, session, vdi_ref):
+ return xen_api_success(
+ self._get_VDI(vdi_ref).other_config)
+
+ def VDI_set_other_config(self, session, vdi_ref, other_config):
+ self._get_VDI(vdi_ref).other_config = other_config
+ return xen_api_success_void()
+
# Object Methods
def VDI_snapshot(self, session, vdi_ref):
return xen_api_todo()
@@ -1842,13 +1968,13 @@ class XendAPI(object):
'name_label': image.name_label,
'name_description': image.name_description,
'SR': image.sr_uuid,
- 'VBDs': [], # TODO
+ 'VBDs': image.getVBDs(),
'virtual_size': image.virtual_size,
'physical_utilisation': image.physical_utilisation,
- 'sector_size': image.sector_size,
'type': image.type,
'sharable': image.sharable,
'read_only': image.read_only,
+ 'other_config': image.other_config
})
# Class Functions
@@ -1929,7 +2055,7 @@ class XendAPI(object):
XendDomain.POWER_STATE_NAMES[dom.state]])
from xen.xend.server import tpmif
tpmif.destroy_vtpmstate(dom.getName())
- return xen_api_success(True)
+ return xen_api_success_void()
else:
return xen_api_error(['HANDLE_INVALID', 'VM', vtpm_struct['VM']])
diff --git a/tools/python/xen/xend/XendCheckpoint.py b/tools/python/xen/xend/XendCheckpoint.py
index e94d9fbde7..3982188016 100644
--- a/tools/python/xen/xend/XendCheckpoint.py
+++ b/tools/python/xen/xend/XendCheckpoint.py
@@ -9,6 +9,7 @@ import os
import re
import string
import threading
+import fcntl
from struct import pack, unpack, calcsize
from xen.util.xpopen import xPopen3
@@ -73,10 +74,15 @@ def save(fd, dominfo, network, live, dst, checkpoint=False):
write_exact(fd, config, "could not write guest state file: config")
image_cfg = dominfo.info.get('image', {})
- hvm = image_cfg.has_key('hvm')
+ hvm = dominfo.info.is_hvm()
+ stdvga = 0
if hvm:
log.info("save hvm domain")
+ if dominfo.info['platform'].has_key('stdvga'):
+ if dominfo.info['platform']['stdvga'] == 1:
+ stdvga = 1
+
# xc_save takes three customization parameters: maxit, max_f, and
# flags the last controls whether or not save is 'live', while the
# first two further customize behaviour when 'live' save is
@@ -84,7 +90,8 @@ def save(fd, dominfo, network, live, dst, checkpoint=False):
# libxenguest; see the comments and/or code in xc_linux_save() for
# more information.
cmd = [xen.util.auxbin.pathTo(XC_SAVE), str(fd),
- str(dominfo.getDomid()), "0", "0", str(int(live) | (int(hvm) << 2)) ]
+ str(dominfo.getDomid()), "0", "0",
+ str(int(live) | (int(hvm) << 2) | (int(stdvga) << 3)) ]
log.debug("[xc_save]: %s", string.join(cmd))
def saveInputHandler(line, tochild):
@@ -183,11 +190,11 @@ def restore(xd, fd, dominfo = None, paused = False):
# if hvm, pass mem size to calculate the store_mfn
image_cfg = dominfo.info.get('image', {})
- is_hvm = image_cfg.has_key('hvm')
+ is_hvm = dominfo.info.is_hvm()
if is_hvm:
hvm = dominfo.info['memory_static_min']
- apic = dominfo.info['image']['hvm'].get('apic', 0)
- pae = dominfo.info['image']['hvm'].get('pae', 0)
+ apic = int(dominfo.info['platform'].get('apic', 0))
+ pae = int(dominfo.info['platform'].get('pae', 0))
log.info("restore hvm domain %d, mem=%d, apic=%d, pae=%d",
dominfo.domid, hvm, apic, pae)
else:
@@ -224,6 +231,15 @@ def restore(xd, fd, dominfo = None, paused = False):
forkHelper(cmd, fd, handler.handler, True)
+ # We don't want to pass this fd to any other children -- we
+ # might need to recover ths disk space that backs it.
+ try:
+ flags = fcntl.fcntl(fd, fcntl.F_GETFD)
+ flags |= fcntl.FD_CLOEXEC
+ fcntl.fcntl(fd, fcntl.F_SETFD, flags)
+ except:
+ pass
+
if handler.store_mfn is None:
raise XendError('Could not read store MFN')
diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py
index ec8a66fb7e..d8f5c3fe66 100644
--- a/tools/python/xen/xend/XendConfig.py
+++ b/tools/python/xen/xend/XendConfig.py
@@ -12,7 +12,7 @@
# 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) 2006 XenSource Ltd
+# Copyright (C) 2006-2007 XenSource Ltd
#============================================================================
import logging
@@ -28,7 +28,7 @@ from xen.xend.PrettyPrint import prettyprintstring
from xen.xend.XendConstants import DOM_STATE_HALTED
log = logging.getLogger("xend.XendConfig")
-log.setLevel(logging.DEBUG)
+log.setLevel(logging.WARN)
"""
@@ -105,28 +105,23 @@ XENAPI_CFG_TO_LEGACY_CFG = {
'uuid': 'uuid',
'vcpus_number': 'vcpus',
'cpus': 'cpus',
- 'memory_static_min': 'memory',
- 'memory_static_max': 'maxmem',
'name_label': 'name',
'actions_after_shutdown': 'on_poweroff',
'actions_after_reboot': 'on_reboot',
'actions_after_crash': 'on_crash',
- 'platform_localtime': 'localtime',
'PV_bootloader': 'bootloader',
'PV_bootloader_args': 'bootloader_args',
}
LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG)
-# Mapping from XendConfig configuration keys to the old
-# legacy configuration keys that are found in the 'image'
-# SXP object.
-XENAPI_HVM_CFG = {
- 'platform_std_vga': 'stdvga',
- 'platform_serial' : 'serial',
- 'platform_localtime': 'localtime',
- 'platform_keymap' : 'keymap'
-}
+# Platform configuration keys.
+XENAPI_PLATFORM_CFG = [ 'acpi', 'apic', 'boot', 'device_model', 'display',
+ 'fda', 'fdb', 'keymap', 'isa', 'localtime',
+ 'nographic', 'pae', 'serial', 'sdl',
+ 'soundhw','stdvga', 'usb', 'usbdevice', 'vnc',
+ 'vncconsole', 'vncdisplay', 'vnclisten',
+ 'vncpasswd', 'vncunused', 'xauthority']
# List of XendConfig configuration keys that have no direct equivalent
# in the old world.
@@ -139,11 +134,10 @@ XENAPI_CFG_TYPES = {
'user_version': str,
'is_a_template': bool0,
'resident_on': str,
- 'memory_static_min': int,
+ 'memory_static_min': int, # note these are stored in bytes, not KB!
'memory_static_max': int,
'memory_dynamic_min': int,
'memory_dynamic_max': int,
- 'memory_actual': int,
'cpus': list,
'vcpus_policy': str,
'vcpus_params': dict,
@@ -151,7 +145,6 @@ XENAPI_CFG_TYPES = {
'actions_after_shutdown': str,
'actions_after_reboot': str,
'actions_after_crash': str,
- 'tpm_backend': int,
'PV_bootloader': str,
'PV_kernel': str,
'PV_ramdisk': str,
@@ -159,15 +152,10 @@ XENAPI_CFG_TYPES = {
'PV_bootloader_args': str,
'HVM_boot_policy': str,
'HVM_boot_params': dict,
- 'platform_std_vga': bool0,
- 'platform_serial': str,
- 'platform_localtime': bool0,
- 'platform_clock_offset': bool0,
- 'platform_enable_audio': bool0,
- 'platform_keymap': str,
- 'pci_bus': str,
+ 'PCI_bus': str,
+ 'platform': dict,
'tools_version': dict,
- 'otherconfig': dict,
+ 'other_config': dict,
}
# List of legacy configuration keys that have no equivalent in the
@@ -237,44 +225,7 @@ LEGACY_XENSTORE_VM_PARAMS = [
'on_xend_stop',
]
-LEGACY_IMAGE_CFG = [
- ('root', str),
- ('ip', str),
- ('nographic', int),
- ('vnc', int),
- ('sdl', int),
- ('vncdisplay', int),
- ('vncunused', int),
- ('vncpasswd', str),
- ('vnclisten', str),
-]
-
-LEGACY_IMAGE_HVM_CFG = [
- ('device_model', str),
- ('display', str),
- ('xauthority', str),
- ('vncconsole', int),
- ('pae', int),
- ('apic', int),
-]
-
-LEGACY_IMAGE_HVM_DEVICES_CFG = [
- ('acpi', int),
- ('boot', str),
- ('fda', str),
- ('fdb', str),
- ('isa', int),
- ('keymap', str),
- ('localtime', int),
- ('serial', str),
- ('stdvga', int),
- ('soundhw', str),
- ('usb', int),
- ('usbdevice', str),
- ('vcpus', int),
-]
-
-LEGACY_DM = '/usr/lib/xen/bin/qemu-dm'
+DEFAULT_DM = '/usr/lib/xen/bin/qemu-dm'
##
## Config Choices
@@ -316,7 +267,6 @@ class XendConfig(dict):
self._sxp_to_xapi_unsupported(sxp_obj)
elif xapi:
self.update_with_xenapi_config(xapi)
- self._add_xapi_unsupported(xapi)
elif dominfo:
# output from xc.domain_getinfo
self._dominfo_to_xapi(dominfo)
@@ -361,9 +311,7 @@ class XendConfig(dict):
'shadow_memory': 0,
'memory_static_max': 0,
'memory_dynamic_max': 0,
- 'memory_actual': 0,
'devices': {},
- 'image': {},
'security': None,
'on_xend_start': 'ignore',
'on_xend_stop': 'ignore',
@@ -377,24 +325,44 @@ class XendConfig(dict):
'vbd_refs': [],
'vtpm_refs': [],
'other_config': {},
+ 'platform': {}
}
return defaults
+ #
+ # Here we assume these values exist in the dict.
+ # If they don't we have a bigger problem, lets not
+ # try and 'fix it up' but acutually fix the cause ;-)
+ #
def _memory_sanity_check(self):
- if self['memory_static_min'] == 0:
- self['memory_static_min'] = self['memory_dynamic_min']
-
- # If the static max is not set, let's set it to dynamic max.
- # If the static max is smaller than static min, then fix it!
- self['memory_static_max'] = max(self['memory_static_max'],
- self['memory_dynamic_max'],
- self['memory_static_min'])
-
- for mem_type in ('memory_static_min', 'memory_static_max'):
- if self[mem_type] <= 0:
- raise XendConfigError('Memory value too low for %s: %d' %
- (mem_type, self[mem_type]))
+ log.debug("_memory_sanity_check memory_static_min: %s, "
+ "memory_static_max: %i, "
+ "memory_dynamic_min: %i, "
+ "memory_dynamic_max: %i",
+ self["memory_static_min"],
+ self["memory_static_max"],
+ self["memory_dynamic_min"],
+ self["memory_dynamic_max"])
+
+ if not self["memory_static_min"] <= self["memory_static_max"]:
+ raise XendConfigError("memory_static_min must be less " \
+ "than or equal to memory_static_max")
+ if not self["memory_dynamic_min"] <= self["memory_dynamic_max"]:
+ raise XendConfigError("memory_dynamic_min must be less " \
+ "than or equal to memory_dynamic_max")
+ if not self["memory_static_min"] <= self["memory_dynamic_min"]:
+ raise XendConfigError("memory_static_min must be less " \
+ "than or equal to memory_dynamic_min")
+ if not self["memory_dynamic_max"] <= self["memory_static_max"]:
+ raise XendConfigError("memory_dynamic_max must be less " \
+ "than or equal to memory_static_max")
+ if not self["memory_dynamic_max"] > 0:
+ raise XendConfigError("memory_dynamic_max must be greater " \
+ "than zero")
+ if not self["memory_static_max"] > 0:
+ raise XendConfigError("memory_static_max must be greater " \
+ "than zero")
def _actions_sanity_check(self):
for event in ['shutdown', 'reboot', 'crash']:
@@ -417,19 +385,34 @@ class XendConfig(dict):
if 'name_label' not in self:
self['name_label'] = 'Domain-' + self['uuid']
+ def _platform_sanity_check(self):
+ if self.is_hvm():
+ if 'device_model' not in self['platform']:
+ self['platform']['device_model'] = DEFAULT_DM
+
+ # Compatibility hack, can go away soon.
+ if 'soundhw' not in self['platform'] and \
+ self['platform'].get('enable_audio'):
+ self['platform']['soundhw'] = 'sb16'
+
def validate(self):
self._uuid_sanity_check()
self._name_sanity_check()
self._memory_sanity_check()
self._actions_sanity_check()
self._vcpus_sanity_check()
+ self._platform_sanity_check()
def _dominfo_to_xapi(self, dominfo):
self['domid'] = dominfo['domid']
self['online_vcpus'] = dominfo['online_vcpus']
self['vcpus_number'] = dominfo['max_vcpu_id'] + 1
- self['memory_dynamic_min'] = (dominfo['mem_kb'] + 1023)/1024
- self['memory_dynamic_max'] = (dominfo['maxmem_kb'] + 1023)/1024
+
+ self['memory_dynamic_min'] = dominfo['mem_kb'] * 1024
+ self['memory_dynamic_max'] = dominfo['mem_kb'] * 1024
+ self['memory_static_min'] = 0
+ self['memory_static_max'] = dominfo['maxmem_kb'] * 1024
+
self['cpu_time'] = dominfo['cpu_time']/1e9
# TODO: i don't know what the security stuff expects here
if dominfo.get('ssidref'):
@@ -483,6 +466,13 @@ class XendConfig(dict):
log.warn('Ignoring unrecognised value for deprecated option:'
'restart = \'%s\'', restart)
+ # Handle memory, passed in as MiB
+
+ if sxp.child_value(sxp_cfg, "memory") != None:
+ cfg["memory"] = int(sxp.child_value(sxp_cfg, "memory"))
+ if sxp.child_value(sxp_cfg, "maxmem") != None:
+ cfg["maxmem"] = int(sxp.child_value(sxp_cfg, "maxmem"))
+
# Only extract options we know about.
extract_keys = LEGACY_UNSUPPORTED_BY_XENAPI_CFG
extract_keys += XENAPI_CFG_TO_LEGACY_CFG.values()
@@ -498,6 +488,18 @@ class XendConfig(dict):
log.warn("Unable to parse key %s: %s: %s" %
(key, str(val), e))
+ if 'platform' not in cfg:
+ cfg['platform'] = {}
+ localtime = sxp.child_value(sxp_cfg, 'localtime')
+ if localtime is not None:
+ cfg['platform']['localtime'] = localtime
+
+ # Compatibility hack -- can go soon.
+ for key in XENAPI_PLATFORM_CFG:
+ val = sxp.child_value(sxp_cfg, "platform_" + key, None)
+ if val is not None:
+ self['platform'][key] = val
+
# Compatibility hack -- can go soon.
boot_order = sxp.child_value(sxp_cfg, 'HVM_boot')
if boot_order:
@@ -640,6 +642,21 @@ class XendConfig(dict):
except KeyError:
pass
+ # Lets try and handle memory correctly
+
+ MiB = 1024 * 1024
+
+ if "memory" in cfg:
+ self["memory_static_min"] = 0
+ self["memory_static_max"] = int(cfg["memory"]) * MiB
+ self["memory_dynamic_min"] = int(cfg["memory"]) * MiB
+ self["memory_dynamic_max"] = int(cfg["memory"]) * MiB
+
+ if "maxmem" in cfg:
+ self["memory_static_max"] = int(cfg["maxmem"]) * MiB
+
+ self._memory_sanity_check()
+
def update_with(n, o):
if not self.get(n):
self[n] = cfg.get(o, '')
@@ -652,17 +669,9 @@ class XendConfig(dict):
self.update_with_image_sxp(image_sxp)
# Convert Legacy HVM parameters to Xen API configuration
- self['platform_std_vga'] = bool0(cfg.get('stdvga', 0))
- self['platform_serial'] = str(cfg.get('serial', ''))
- self['platform_localtime'] = bool0(cfg.get('localtime', 0))
- self['platform_enable_audio'] = bool0(cfg.get('soundhw', 0))
-
- # make sure a sane maximum is set
- if self['memory_static_max'] <= 0:
- self['memory_static_max'] = self['memory_static_min']
-
- self['memory_dynamic_max'] = self['memory_static_max']
- self['memory_dynamic_min'] = self['memory_static_min']
+ for key in XENAPI_PLATFORM_CFG:
+ if key in cfg:
+ self['platform'][key] = cfg[key]
# set device references in the configuration
self['devices'] = cfg.get('devices', {})
@@ -672,7 +681,7 @@ class XendConfig(dict):
self['vtpm_refs'] = cfg.get('vtpm_refs', [])
# coalesce hvm vnc frame buffer with vfb config
- if self['image']['type'] == 'hvm' and self['image'].get('vnc', 0):
+ if self.is_hvm() and self['platform'].get('vnc', 0):
# add vfb device if it isn't there already
has_rfb = False
for console_uuid in self['console_refs']:
@@ -685,11 +694,11 @@ class XendConfig(dict):
if not has_rfb:
dev_config = ['vfb']
- # copy VNC related params from image config to vfb dev conf
+ # copy VNC related params from platform config to vfb dev conf
for key in ['vncpasswd', 'vncunused', 'vncdisplay',
'vnclisten']:
- if key in self['image']:
- dev_config.append([key, self['image'][key]])
+ if key in self['platform']:
+ dev_config.append([key, self['platform'][key]])
self.device_add('vfb', cfg_sxp = dev_config)
@@ -706,39 +715,19 @@ class XendConfig(dict):
# the image (as well as HVM images)
image_sxp = sxp.child_value(sxp_cfg, 'image', [])
if image_sxp:
- image = {}
- image['type'] = sxp.name(image_sxp)
- for arg, conv in LEGACY_IMAGE_CFG:
- val = sxp.child_value(image_sxp, arg, None)
- if val != None:
- image[arg] = conv(val)
-
- image_hvm = {}
- for arg, conv in LEGACY_IMAGE_HVM_CFG:
- val = sxp.child_value(image_sxp, arg, None)
- if val != None:
- image_hvm[arg] = conv(val)
-
- image_hvm_devices = {}
- for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG:
- val = sxp.child_value(image_sxp, arg, None)
- if val != None:
- image_hvm_devices[arg] = conv(val)
-
- if image_hvm or image_hvm_devices:
- image['hvm'] = image_hvm
- image['hvm']['devices'] = image_hvm_devices
-
+ image_type = sxp.name(image_sxp)
+ if image_type != 'hvm' and image_type != 'linux':
+ self['platform']['image_type'] = image_type
+
+ for key in XENAPI_PLATFORM_CFG:
+ val = sxp.child_value(image_sxp, key, None)
+ if val is not None:
+ self['platform'][key] = val
+
notes = sxp.children(image_sxp, 'notes')
if notes:
- image['notes'] = self.notes_from_sxp(notes[0])
-
- self['image'] = image
+ self['notes'] = self.notes_from_sxp(notes[0])
- for apikey, imgkey in XENAPI_HVM_CFG.items():
- val = sxp.child_value(image_sxp, imgkey, None)
- if val != None:
- self[apikey] = val
self._hvm_boot_params_from_sxp(image_sxp)
# extract backend value
@@ -774,33 +763,6 @@ class XendConfig(dict):
_set_cfg_if_exists('up_time')
_set_cfg_if_exists('status') # TODO, deprecated
- def _add_xapi_unsupported(self, xapi_dict):
- """Updates the configuration object with entries that are not
- officially supported by the Xen API but is required for
- the rest of Xend to function.
- """
-
- # populate image
- if 'image' in xapi_dict:
- self['image'].update(xapi_dict['image'])
- else:
- hvm = self['HVM_boot_policy'] != ''
- self['image']['type'] = hvm and 'hvm' or 'linux'
- if hvm:
- self['image']['hvm'] = {'devices': {}}
- for xapi, cfgapi in XENAPI_HVM_CFG.items():
- if xapi in self:
- self['image']['hvm']['devices'][cfgapi] = self[xapi]
-
- # currently unsupported options
- self['image']['hvm']['device_model'] = LEGACY_DM
- self['image']['vnc'] = 0
- self['image']['hvm']['pae'] = 1
-
- if self['platform_enable_audio']:
- self['image']['hvm']['devices']['soundhw'] = 'sb16'
-
-
def _get_old_state_string(self):
"""Returns the old xm state string.
@rtype: string
@@ -884,18 +846,29 @@ class XendConfig(dict):
else:
sxpr.append([legacy, self[xenapi]])
+ MiB = 1024*1024
+
+ sxpr.append(["maxmem", int(self["memory_static_max"])/MiB])
+ sxpr.append(["memory", int(self["memory_dynamic_max"])/MiB])
+
+ if not legacy_only:
+ sxpr.append(['memory_dynamic_min',
+ int(self.get('memory_dynamic_min'))])
+ sxpr.append(['memory_dynamic_max',
+ int(self.get('memory_dynamic_max'))])
+ sxpr.append(['memory_static_max',
+ int(self.get('memory_static_max'))])
+ sxpr.append(['memory_static_min',
+ int(self.get('memory_static_min'))])
+
for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG:
if legacy in ('domid', 'uuid'): # skip these
continue
if self.has_key(legacy) and self[legacy] not in (None, []):
sxpr.append([legacy, self[legacy]])
- if 'image' in self and self['image']:
- sxpr.append(['image', self.image_sxpr()])
-
+ sxpr.append(['image', self.image_sxpr()])
sxpr.append(['status', domain.state])
- sxpr.append(['memory_dynamic_min', self.get('memory_dynamic_min')])
- sxpr.append(['memory_dynamic_max', self.get('memory_dynamic_max')])
if domain.getDomid() is not None:
sxpr.append(['state', self._get_old_state_string()])
@@ -1339,7 +1312,7 @@ class XendConfig(dict):
def image_sxpr(self):
"""Returns a backwards compatible image SXP expression that is
used in xenstore's /vm/<uuid>/image value and xm list."""
- image = [self['image'].get('type', 'linux')]
+ image = [self.image_type()]
if self.has_key('PV_kernel'):
image.append(['kernel', self['PV_kernel']])
if self.has_key('PV_ramdisk') and self['PV_ramdisk']:
@@ -1347,28 +1320,12 @@ class XendConfig(dict):
if self.has_key('PV_args') and self['PV_args']:
image.append(['args', self['PV_args']])
- for arg, conv in LEGACY_IMAGE_CFG:
- if self['image'].has_key(arg):
- image.append([arg, self['image'][arg]])
+ for key in XENAPI_PLATFORM_CFG:
+ if key in self['platform']:
+ image.append([key, self['platform'][key]])
- if 'hvm' in self['image']:
- for arg, conv in LEGACY_IMAGE_HVM_CFG:
- if self['image']['hvm'].get(arg):
- image.append([arg, conv(self['image']['hvm'][arg])])
-
- if 'hvm' in self['image'] and 'devices' in self['image']['hvm']:
- for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG:
- val = self['image']['hvm']['devices'].get(arg)
- if val != None:
- try:
- if conv: val = conv(val)
- except (ValueError, TypeError):
- if type(val) == bool: val = int(val)
-
- image.append([arg, val])
-
- if 'notes' in self['image']:
- image.append(self.notes_sxp(self['image']['notes']))
+ if 'notes' in self:
+ image.append(self.notes_sxp(self['notes']))
return image
@@ -1399,57 +1356,24 @@ class XendConfig(dict):
self['PV_ramdisk'] = sxp.child_value(image_sxp, 'ramdisk','')
self['PV_args'] = kernel_args
- # Store image SXP in python dictionary format
- image = {}
- image['type'] = sxp.name(image_sxp)
- for arg, conv in LEGACY_IMAGE_CFG:
- val = sxp.child_value(image_sxp, arg, None)
- if val != None:
- image[arg] = conv(val)
-
- image_hvm = {}
- for arg, conv in LEGACY_IMAGE_HVM_CFG:
- val = sxp.child_value(image_sxp, arg, None)
- if val != None:
- image_hvm[arg] = conv(val)
-
- image_hvm_devices = {}
- for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG:
- val = sxp.child_value(image_sxp, arg, None)
- if val != None:
- try:
- image_hvm_devices[arg] = conv(val)
- except (ValueError, TypeError):
- image_hvm_devices[arg] = val
-
-
- if image_hvm or image_hvm_devices:
- image['hvm'] = image_hvm
- image['hvm']['devices'] = image_hvm_devices
+ for key in XENAPI_PLATFORM_CFG:
+ val = sxp.child_value(image_sxp, key, None)
+ if val is not None:
+ self['platform'][key] = val
notes = sxp.children(image_sxp, 'notes')
if notes:
- image['notes'] = self.notes_from_sxp(notes[0])
+ self['notes'] = self.notes_from_sxp(notes[0])
- self['image'] = image
-
- for apikey, imgkey in XENAPI_HVM_CFG.items():
- val = sxp.child_value(image_sxp, imgkey, None)
- if val != None:
- type_conv = XENAPI_CFG_TYPES[apikey]
- if callable(type_conv):
- self[apikey] = type_conv(val)
- else:
- self[apikey] = val
self._hvm_boot_params_from_sxp(image_sxp)
def set_notes(self, notes):
'Add parsed elfnotes to image'
- self['image']['notes'] = notes
+ self['notes'] = notes
def get_notes(self):
try:
- return self['image']['notes'] or {}
+ return self['notes'] or {}
except KeyError:
return {}
@@ -1471,11 +1395,9 @@ class XendConfig(dict):
self['HVM_boot_policy'] = 'BIOS order'
self['HVM_boot_params'] = { 'order' : boot }
+ def is_hvm(self):
+ return self['HVM_boot_policy'] != ''
-#
-# debugging
-#
-
-if __name__ == "__main__":
- pass
-
+ def image_type(self):
+ stored_type = self['platform'].get('image_type')
+ return stored_type or (self.is_hvm() and 'hvm' or 'linux')
diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py
index 7e5f618870..18aad354b4 100644
--- a/tools/python/xen/xend/XendDomain.py
+++ b/tools/python/xen/xend/XendDomain.py
@@ -495,7 +495,7 @@ class XendDomain:
self._refresh(refresh_shutdown = False)
dom = self.domain_lookup_nr(domid)
if not dom:
- raise XendInvalidDomain("No domain named '%s'." % str(domid))
+ raise XendInvalidDomain(str(domid))
return dom
finally:
self.domains_lock.release()
@@ -674,7 +674,7 @@ class XendDomain:
else:
return domid
- raise XendInvalidDomain("Domain does not exist")
+ raise XendInvalidDomain(vm_uuid)
finally:
self.domains_lock.release()
diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py
index c784c95f80..bd4c595797 100644
--- a/tools/python/xen/xend/XendDomainInfo.py
+++ b/tools/python/xen/xend/XendDomainInfo.py
@@ -13,7 +13,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
-# Copyright (C) 2005, 2006 XenSource Ltd
+# Copyright (C) 2005-2007 XenSource Ltd
#============================================================================
"""Representation of a single domain.
@@ -34,7 +34,7 @@ from types import StringTypes
import xen.lowlevel.xc
from xen.util import asserts
-from xen.util.blkif import blkdev_uname_to_file
+from xen.util.blkif import blkdev_uname_to_file, blkdev_uname_to_taptype
from xen.util import security
from xen.xend import balloon, sxp, uuid, image, arch, osdep
@@ -51,6 +51,8 @@ from xen.xend.xenstore.xswatch import xswatch
from xen.xend.XendConstants import *
from xen.xend.XendAPIConstants import *
+from xen.xend.XendVMMetrics import XendVMMetrics
+
MIGRATE_TIMEOUT = 30.0
BOOTLOADER_LOOPBACK_DEVICE = '/dev/xvdp'
@@ -176,14 +178,8 @@ def recreate(info, priv):
vm._storeVmDetails()
vm._storeDomDetails()
- if vm.info['image']: # Only dom0 should be without an image entry when
- # recreating, but we cope with missing ones
- # elsewhere just in case.
- vm.image = image.create(vm,
- vm.info,
- vm.info['image'],
- vm.info['devices'])
- vm.image.recreate()
+ vm.image = image.create(vm, vm.info)
+ vm.image.recreate()
vm._registerWatches()
vm.refreshShutdown(xeninfo)
@@ -375,6 +371,8 @@ class XendDomainInfo:
self._augmentInfo(priv)
self._checkName(self.info['name_label'])
+
+ self.metrics = XendVMMetrics(uuid.createString(), self)
#
@@ -448,9 +446,7 @@ class XendDomainInfo:
self.storeDom("control/shutdown", reason)
## shutdown hypercall for hvm domain desides xenstore write
- image_cfg = self.info.get('image', {})
- hvm = image_cfg.has_key('hvm')
- if hvm:
+ if self.info.is_hvm():
for code in DOMAIN_SHUTDOWN_REASONS.keys():
if DOMAIN_SHUTDOWN_REASONS[code] == reason:
break
@@ -580,12 +576,14 @@ class XendDomainInfo:
if target <= 0:
raise XendError('Invalid memory size')
- self.info['memory_static_min'] = target
+ MiB = 1024 * 1024
+ self.info['memory_dynamic_min'] = target * MiB
+ self.info['memory_dynamic_max'] = target * MiB
+
if self.domid >= 0:
self.storeVm("memory", target)
self.storeDom("memory/target", target << 10)
else:
- self.info['memory_dynamic_min'] = target
xen.xend.XendDomain.instance().managed_config_save(self)
def setMemoryMaximum(self, limit):
@@ -635,6 +633,10 @@ class XendDomainInfo:
except RuntimeError, exn:
raise XendError(str(exn))
+
+ def getDomInfo(self):
+ return dom_get(self.domid)
+
#
# internal functions ... TODO: re-categorised
#
@@ -664,6 +666,10 @@ class XendDomainInfo:
if arg in XendConfig.LEGACY_CFG_TO_XENAPI_CFG:
xapiarg = XendConfig.LEGACY_CFG_TO_XENAPI_CFG[arg]
self.info[xapiarg] = val
+ elif arg == "memory":
+ self.info["static_memory_min"] = val
+ elif arg == "maxmem":
+ self.info["static_memory_max"] = val
else:
self.info[arg] = val
@@ -780,7 +786,7 @@ class XendDomainInfo:
'vm': self.vmpath,
'name': self.info['name_label'],
'console/limit': str(xoptions.get_console_limit() * 1024),
- 'memory/target': str(self.info['memory_static_min'] * 1024),
+ 'memory/target': str(self.info['memory_dynamic_max'] / 1024),
}
def f(n, v):
@@ -864,7 +870,15 @@ class XendDomainInfo:
xapiarg = XendConfig.LEGACY_CFG_TO_XENAPI_CFG[arg]
if val != None and val != self.info[xapiarg]:
self.info[xapiarg] = val
- changed= True
+ changed = True
+ elif arg == "memory":
+ if val != None and val != self.info["static_memory_min"]:
+ self.info["static_memory_min"] = val
+ changed = True
+ elif arg == "maxmem":
+ if val != None and val != self.info["static_memory_max"]:
+ self.info["static_memory_max"] = val
+ changed = True
# Check whether image definition has been updated
image_sxp = self._readVm('image')
@@ -969,11 +983,12 @@ class XendDomainInfo:
def getMemoryTarget(self):
"""Get this domain's target memory size, in KB."""
- return self.info['memory_static_min'] * 1024
+ return self.info['memory_dynamic_max'] / 1024
def getMemoryMaximum(self):
"""Get this domain's maximum memory size, in KB."""
- return self.info['memory_static_max'] * 1024
+ # remember, info now stores memory in bytes
+ return self.info['memory_static_max'] / 1024
def getResume(self):
return str(self._resume)
@@ -1389,9 +1404,7 @@ class XendDomainInfo:
self.shutdownStartTime = None
- image_cfg = self.info.get('image', {})
- hvm = image_cfg.has_key('hvm')
-
+ hvm = self.info.is_hvm()
if hvm:
info = xc.xeninfo()
if 'hvm' not in info['xen_caps']:
@@ -1438,14 +1451,8 @@ class XendDomainInfo:
self._configureBootloader()
- if not self._infoIsSet('image'):
- raise VmError('Missing image in configuration')
-
try:
- self.image = image.create(self,
- self.info,
- self.info['image'],
- self.info['devices'])
+ self.image = image.create(self, self.info)
localtime = self.info.get('platform_localtime', False)
if localtime:
@@ -1463,13 +1470,14 @@ class XendDomainInfo:
# Use architecture- and image-specific calculations to determine
# the various headrooms necessary, given the raw configured
# values. maxmem, memory, and shadow are all in KiB.
+ # but memory_static_max etc are all stored in bytes now.
memory = self.image.getRequiredAvailableMemory(
- self.info['memory_static_min'] * 1024)
+ self.info['memory_dynamic_max'] / 1024)
maxmem = self.image.getRequiredAvailableMemory(
- self.info['memory_static_max'] * 1024)
+ self.info['memory_static_max'] / 1024)
shadow = self.image.getRequiredShadowMemory(
- self.info['shadow_memory'] * 1024,
- self.info['memory_static_max'] * 1024)
+ self.info['shadow_memory'] / 1024,
+ self.info['memory_static_max'] / 1024)
log.debug("_initDomain:shadow_memory=0x%x, memory_static_max=0x%x, memory_static_min=0x%x.", self.info['shadow_memory'], self.info['memory_static_max'], self.info['memory_static_min'],)
# Round shadow up to a multiple of a MiB, as shadow_mem_control
@@ -1505,9 +1513,15 @@ class XendDomainInfo:
self.info['start_time'] = time.time()
self._stateSet(DOM_STATE_RUNNING)
- except (RuntimeError, VmError), exn:
+ except VmError, exn:
log.exception("XendDomainInfo.initDomain: exception occurred")
- self.image.cleanupBootloading()
+ if self.image:
+ self.image.cleanupBootloading()
+ raise exn
+ except RuntimeError, exn:
+ log.exception("XendDomainInfo.initDomain: exception occurred")
+ if self.image:
+ self.image.cleanupBootloading()
raise VmError(str(exn))
@@ -1574,13 +1588,8 @@ class XendDomainInfo:
self.console_mfn = console_mfn
self._introduceDomain()
- image_cfg = self.info.get('image', {})
- hvm = image_cfg.has_key('hvm')
- if hvm:
- self.image = image.create(self,
- self.info,
- self.info['image'],
- self.info['devices'])
+ if self.info.is_hvm():
+ self.image = image.create(self, self.info)
if self.image:
self.image.createDeviceModel(True)
self.image.register_shutdown_watch()
@@ -1657,7 +1666,18 @@ class XendDomainInfo:
log.exception("XendDomainInfo.destroy: xc.domain_destroy failed.")
from xen.xend import XendDomain
- XendDomain.instance().remove_domain(self)
+
+ if "transient" in self.info["other_config"]\
+ and bool(self.info["other_config"]["transient"]):
+ xendDomainInstance = XendDomain.instance()
+
+ xendDomainInstance.domains_lock.acquire()
+ xendDomainInstance._refresh(refresh_shutdown = False)
+ xendDomainInstance.domains_lock.release()
+
+ xendDomainInstance.domain_delete(self.info["name_label"])
+ else:
+ XendDomain.instance().remove_domain(self)
self.cleanupDomain()
self._cleanup_phantom_devs(paths)
@@ -1742,11 +1762,7 @@ class XendDomainInfo:
if boot:
# HVM booting.
- self.info['image']['type'] = 'hvm'
- if not 'devices' in self.info['image']:
- self.info['image']['devices'] = {}
- self.info['image']['devices']['boot'] = \
- self.info['HVM_boot_params'].get('order', 'dc')
+ pass
elif not blexec and kernel:
# Boot from dom0. Nothing left to do -- the kernel and ramdisk
# will be picked up by image.py.
@@ -1770,7 +1786,8 @@ class XendDomainInfo:
disk = devinfo[1]['uname']
fn = blkdev_uname_to_file(disk)
- mounted = devtype == 'tap' and not os.stat(fn).st_rdev
+ taptype = blkdev_uname_to_taptype(disk)
+ mounted = devtype == 'tap' and taptype != 'aio' and taptype != 'sync' and not os.stat(fn).st_rdev
if mounted:
# This is a file, not a device. pygrub can cope with a
# file if it's raw, but if it's QCOW or other such formats
@@ -1786,7 +1803,7 @@ class XendDomainInfo:
from xen.xend import XendDomain
dom0 = XendDomain.instance().privilegedDomain()
- dom0._waitForDeviceUUID(dom0.create_vbd(vbd, fn))
+ dom0._waitForDeviceUUID(dom0.create_vbd(vbd, disk))
fn = BOOTLOADER_LOOPBACK_DEVICE
try:
@@ -1844,7 +1861,7 @@ class XendDomainInfo:
# 1MB per vcpu plus 4Kib/Mib of RAM. This is higher than
# the minimum that Xen would allocate if no value were given.
overhead_kb = self.info['vcpus_number'] * 1024 + \
- self.info['memory_static_max'] * 4
+ (self.info['memory_static_max'] / 1024 / 1024) * 4
overhead_kb = ((overhead_kb + 1023) / 1024) * 1024
# The domain might already have some shadow memory
overhead_kb -= xc.shadow_mem_control(self.domid) * 1024
@@ -1910,10 +1927,14 @@ class XendDomainInfo:
if self._infoIsSet(info_key):
to_store[key] = str(self.info[info_key])
- if self.info.get('image'):
- image_sxpr = self.info.image_sxpr()
- if image_sxpr:
- to_store['image'] = sxp.to_string(image_sxpr)
+ if self._infoIsSet("static_memory_min"):
+ to_store["memory"] = str(self.info["static_memory_min"])
+ if self._infoIsSet("static_memory_max"):
+ to_store["maxmem"] = str(self.info["static_memory_max"])
+
+ image_sxpr = self.info.image_sxpr()
+ if image_sxpr:
+ to_store['image'] = sxp.to_string(image_sxpr)
if self._infoIsSet('security'):
secinfo = self.info['security']
@@ -2000,7 +2021,11 @@ class XendDomainInfo:
info = dom_get(self.domid)
if not info:
return
-
+
+ if info["maxmem_kb"] < 0:
+ info["maxmem_kb"] = XendNode.instance() \
+ .physinfo_dict()['total_memory'] * 1024
+
#manually update ssidref / security fields
if security.on() and info.has_key('ssidref'):
if (info['ssidref'] != 0) and self.info.has_key('security'):
@@ -2057,15 +2082,6 @@ class XendDomainInfo:
return self.info.get('memory_dynamic_max', 0)
def get_memory_dynamic_min(self):
return self.info.get('memory_dynamic_min', 0)
-
- def get_vcpus_policy(self):
- sched_id = xc.sched_id_get()
- if sched_id == xen.lowlevel.xc.XEN_SCHEDULER_SEDF:
- return 'sedf'
- elif sched_id == xen.lowlevel.xc.XEN_SCHEDULER_CREDIT:
- return 'credit'
- else:
- return 'unknown'
def get_vcpus_params(self):
if self.getDomid() is None:
return self.info['vcpus_params']
@@ -2074,22 +2090,14 @@ class XendDomainInfo:
return retval
def get_power_state(self):
return XEN_API_VM_POWER_STATE[self.state]
- def get_platform_std_vga(self):
- return self.info.get('platform_std_vga', False)
- def get_platform_serial(self):
- return self.info.get('platform_serial', '')
- def get_platform_localtime(self):
- return self.info.get('platform_localtime', False)
- def get_platform_clock_offset(self):
- return self.info.get('platform_clock_offset', False)
- def get_platform_enable_audio(self):
- return self.info.get('platform_enable_audio', False)
- def get_platform_keymap(self):
- return self.info.get('platform_keymap', '')
+ def get_platform(self):
+ return self.info.get('platform', {})
def get_pci_bus(self):
return self.info.get('pci_bus', '')
def get_tools_version(self):
return self.info.get('tools_version', {})
+ def get_metrics(self):
+ return self.metrics.get_uuid();
def get_on_shutdown(self):
after_shutdown = self.info.get('actions_after_shutdown')
@@ -2278,8 +2286,6 @@ class XendDomainInfo:
@return: uuid of the device
"""
xenapi_vbd['image'] = vdi_image_path
- log.debug('create_vbd: %s' % xenapi_vbd)
- dev_uuid = ''
if vdi_image_path.startswith('tap'):
dev_uuid = self.info.device_add('tap', cfg_xenapi = xenapi_vbd)
else:
@@ -2289,16 +2295,25 @@ class XendDomainInfo:
raise XendError('Failed to create device')
if self.state == XEN_API_VM_POWER_STATE_RUNNING:
+
_, config = self.info['devices'][dev_uuid]
- dev_control = None
if vdi_image_path.startswith('tap'):
- dev_control = self.getDeviceController('tap')
+ dev_control = self.getDeviceController('tap')
else:
dev_control = self.getDeviceController('vbd')
-
- config['devid'] = dev_control.createDevice(config)
+ try:
+ devid = dev_control.createDevice(config)
+ dev_control.waitForDevice(devid)
+ self.info.device_update(dev_uuid,
+ cfg_xenapi = {'devid': devid})
+ except Exception, exn:
+ log.exception(exn)
+ del self.info['devices'][dev_uuid]
+ self.info['vbd_refs'].remove(dev_uuid)
+ raise
+
return dev_uuid
def create_phantom_vbd_with_vdi(self, xenapi_vbd, vdi_image_path):
@@ -2332,9 +2347,21 @@ class XendDomainInfo:
raise XendError('Failed to create device')
if self.state == XEN_API_VM_POWER_STATE_RUNNING:
+
_, config = self.info['devices'][dev_uuid]
- config['devid'] = self.getDeviceController('vif').createDevice(config)
+ dev_control = self.getDeviceController('vif')
+ try:
+ devid = dev_control.createDevice(config)
+ dev_control.waitForDevice(devid)
+ self.info.device_update(dev_uuid,
+ cfg_xenapi = {'devid': devid})
+ except Exception, exn:
+ log.exception(exn)
+ del self.info['devices'][dev_uuid]
+ self.info['vif_refs'].remove(dev_uuid)
+ raise
+
return dev_uuid
def create_vtpm(self, xenapi_vtpm):
@@ -2401,7 +2428,7 @@ class XendDomainInfo:
def __str__(self):
return '<domain id=%s name=%s memory=%s state=%s>' % \
(str(self.domid), self.info['name_label'],
- str(self.info['memory_static_min']), DOM_STATES[self.state])
+ str(self.info['memory_dynamic_max']), DOM_STATES[self.state])
__repr__ = __str__
diff --git a/tools/python/xen/xend/XendError.py b/tools/python/xen/xend/XendError.py
index f1507c43dc..bbd5f4f6dd 100644
--- a/tools/python/xen/xend/XendError.py
+++ b/tools/python/xen/xend/XendError.py
@@ -13,6 +13,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
+# Copyright (c) 2006, 2007 XenSource Inc.
#============================================================================
from xmlrpclib import Fault
@@ -55,6 +56,12 @@ class VmError(XendError):
"""Vm construction error."""
pass
+class HVMRequired(VmError):
+ def __init__(self):
+ XendError.__init__(self,
+ 'HVM guest support is unavailable: is VT/AMD-V '
+ 'supported by your CPU and enabled in your BIOS?')
+
XEND_ERROR_AUTHENTICATION_FAILED = ('ELUSER', 'Authentication Failed')
XEND_ERROR_SESSION_INVALID = ('EPERMDENIED', 'Session Invalid')
diff --git a/tools/python/xen/xend/XendLogging.py b/tools/python/xen/xend/XendLogging.py
index 6d6140188d..3d6b678f1d 100644
--- a/tools/python/xen/xend/XendLogging.py
+++ b/tools/python/xen/xend/XendLogging.py
@@ -59,6 +59,18 @@ if 'TRACE' not in logging.__dict__:
return filename, frame[2]
logging.Logger.findCaller = findCaller
+ # Work around a bug in Python's inspect module: findsource is supposed to
+ # raise IOError if it fails, with other functions in that module coping
+ # with that, but some people are seeing IndexError raised from there.
+ if hasattr(inspect, 'findsource'):
+ real_findsource = getattr(inspect, 'findsource')
+ def findsource(*args, **kwargs):
+ try:
+ return real_findsource(*args, **kwargs)
+ except IndexError, exn:
+ raise IOError(exn)
+ inspect.findsource = findsource
+
log = logging.getLogger("xend")
diff --git a/tools/python/xen/xend/XendNode.py b/tools/python/xen/xend/XendNode.py
index 9d2a70dd9e..3917c8080c 100644
--- a/tools/python/xen/xend/XendNode.py
+++ b/tools/python/xen/xend/XendNode.py
@@ -75,6 +75,11 @@ class XendNode:
self.other_config = {}
self.cpus = {}
self.host_metrics_uuid = uuid.createString()
+
+ # put some arbitrary params in other_config as this
+ # is directly exposed via XenAPI
+ self.other_config["xen_pagesize"] = self.xeninfo_dict()["xen_pagesize"]
+ self.other_config["platform_params"] = self.xeninfo_dict()["platform_params"]
# load CPU UUIDs
saved_cpus = self.state_store.load_state('cpu')
@@ -95,15 +100,12 @@ class XendNode:
self.cpus[u] = {'uuid': u, 'number': i }
for u in self.cpus.keys():
- log.error(self.cpus[u])
number = self.cpus[u]['number']
# We can run off the end of the cpuinfo list if domain0 does not
# have #vcpus == #pcpus. In that case we just replicate one that's
# in the hash table.
if not cpuinfo.has_key(number):
number = cpuinfo.keys()[0]
- log.error(number)
- log.error(cpuinfo)
if arch.type == "x86":
self.cpus[u].update(
{ 'host' : self.uuid,
@@ -356,14 +358,37 @@ class XendNode:
def xen_version(self):
info = self.xc.xeninfo()
+
try:
from xen import VERSION
- return {'Xen': '%(xen_major)d.%(xen_minor)d' % info,
+ info = {'Xen': '%(xen_major)d.%(xen_minor)d' % info,
'Xend': VERSION}
except (ImportError, AttributeError):
- return {'Xen': '%(xen_major)d.%(xen_minor)d' % info,
+ info = {'Xen': '%(xen_major)d.%(xen_minor)d' % info,
'Xend': '3.0.3'}
+ # Add xend_config_format
+ info.update(self.xendinfo_dict())
+
+ # Add version info about machine
+ info.update(self.nodeinfo_dict())
+
+ # Add specific xen version info
+ xeninfo_dict = self.xeninfo_dict()
+
+ info.update({
+ "xen_major": xeninfo_dict["xen_major"],
+ "xen_minor": xeninfo_dict["xen_minor"],
+ "xen_extra": xeninfo_dict["xen_extra"],
+ "cc_compiler": xeninfo_dict["cc_compiler"],
+ "cc_compile_by": xeninfo_dict["cc_compile_by"],
+ "cc_compile_domain": xeninfo_dict["cc_compile_domain"],
+ "cc_compile_date": xeninfo_dict["cc_compile_date"],
+ "xen_changeset": xeninfo_dict["xen_changeset"]
+ })
+
+ return info
+
def get_name(self):
return self.name
@@ -418,6 +443,27 @@ class XendNode:
return 0.0
+ def get_vcpus_policy(self):
+ sched_id = self.xc.sched_id_get()
+ if sched_id == xen.lowlevel.xc.XEN_SCHEDULER_SEDF:
+ return 'sedf'
+ elif sched_id == xen.lowlevel.xc.XEN_SCHEDULER_CREDIT:
+ return 'credit'
+ else:
+ return 'unknown'
+
+ def get_cpu_configuration(self):
+ phys_info = self.physinfo_dict()
+
+ cpu_info = {
+ "nr_nodes": phys_info["nr_nodes"],
+ "sockets_per_node": phys_info["sockets_per_node"],
+ "cores_per_socket": phys_info["cores_per_socket"],
+ "threads_per_core": phys_info["threads_per_core"]
+ }
+
+ return cpu_info
+
#
# Network Functions
#
@@ -453,6 +499,12 @@ class XendNode:
return pif.network
raise Exception('Bridge %s is not connected to a network' % bridge)
+ #
+ # Debug keys.
+ #
+
+ def send_debug_keys(self, keys):
+ return self.xc.send_debug_keys(keys)
#
# Getting host information.
@@ -478,7 +530,8 @@ class XendNode:
info['cores_per_socket'] *
info['threads_per_core'])
info['cpu_mhz'] = info['cpu_khz'] / 1000
- # physinfo is in KiB
+
+ # physinfo is in KiB, need it in MiB
info['total_memory'] = info['total_memory'] / 1024
info['free_memory'] = info['free_memory'] / 1024
diff --git a/tools/python/xen/xend/XendVDI.py b/tools/python/xen/xend/XendVDI.py
index f0dda203a8..140ca01226 100644
--- a/tools/python/xen/xend/XendVDI.py
+++ b/tools/python/xen/xend/XendVDI.py
@@ -54,7 +54,6 @@ class XendVDI(AutoSaveObject):
SAVED_CFG = ['name_label',
'name_description',
- 'sector_size',
'virtual_size',
'physical_utilisation',
'sharable',
@@ -67,13 +66,22 @@ class XendVDI(AutoSaveObject):
self.sr_uuid = sr_uuid
self.name_label = ""
self.name_description = ""
- self.sector_size = 1024
self.virtual_size = 0
self.physical_utilisation = 0
self.sharable = False
self.read_only = False
self.type = "system"
- self.location = ''
+ self.other_config = {}
+ self.vbds = []
+
+ def addVBD(self, vbd_ref):
+ self.vbds.append(vbd_ref)
+
+ def removeVBD(self, vbd_ref):
+ self.vbds.remove(vbd_ref)
+
+ def getVBDs(self):
+ return self.vbds
def load_config_dict(self, cfg):
"""Loads configuration into the object from a dict.
@@ -144,11 +152,10 @@ class XendVDI(AutoSaveObject):
'name_description': self.name_description,
'virtual_size': self.virtual_size,
'physical_utilisation': self.physical_utilisation,
- 'sector_size': self.sector_size,
'sharable': False,
'readonly': False,
'SR': self.sr_uuid,
- 'location': self.get_location(),
+ 'other_config': self.other_config,
'VBDs': []}
def get_location(self):
@@ -163,12 +170,11 @@ class XendQCoWVDI(XendVDI):
self.cfg_path = cfg_path
self.physical_utilisation = psize
self.virtual_size = vsize
- self.sector_size = 512
self.auto_save = True
- self.location = 'tap:qcow:%s' % self.qcow_path
+ self.other_config['location'] = 'tap:qcow:%s' % self.qcow_path
def get_location(self):
- return self.location
+ return self.other_config['location']
class XendLocalVDI(XendVDI):
def __init__(self, vdi_struct):
@@ -182,11 +188,10 @@ class XendLocalVDI(XendVDI):
self.name_description = vdi_struct.get('name_description', '')
self.physical_utilisation = 0
self.virtual_size = 0
- self.sector_size = 0
self.type = vdi_struct.get('type', '')
self.sharable = vdi_struct.get('sharable', False)
self.read_only = vdi_struct.get('read_only', False)
- self.location = vdi_struct.get('location', 'file:/dev/null')
+ self.other_config = vdi_struct.get('other_config', {})
def get_location(self):
- return self.location
+ return self.other_config['location']
diff --git a/tools/python/xen/xend/XendVMMetrics.py b/tools/python/xen/xend/XendVMMetrics.py
new file mode 100644
index 0000000000..d531411b30
--- /dev/null
+++ b/tools/python/xen/xend/XendVMMetrics.py
@@ -0,0 +1,70 @@
+#============================================================================
+# 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) 2006-2007 Xensource Inc.
+#============================================================================
+
+from xen.xend.XendLogging import log
+
+instances = {}
+
+class XendVMMetrics:
+ """VM Metrics."""
+
+ def get_by_uuid(_, uuid):
+ return instances[uuid]
+
+ get_by_uuid = classmethod(get_by_uuid)
+
+ def is_valid_vm_metrics(_, uuid):
+ return uuid in instances
+
+ is_valid_vm_metrics = classmethod(is_valid_vm_metrics)
+
+ def get_all(_):
+ return instances.keys()
+
+ get_all = classmethod(get_all)
+
+ def __init__(self, uuid, xend_domain_instance):
+ self.uuid = uuid
+ self.xend_domain_instance = xend_domain_instance
+ instances[uuid] = self
+
+ def get_uuid(self):
+ return self.uuid
+
+ def get_memory_actual(self):
+ return self.get_record()["memory_actual"]
+
+ def get_vcpus_number(self):
+ return self.get_record()["vcpus_number"]
+
+ def get_vcpus_utilisation(self):
+ return self.xend_domain_instance.get_vcpus_util()
+
+ def get_record(self):
+ domInfo = self.xend_domain_instance.getDomInfo()
+ if domInfo:
+ return { 'uuid' : self.uuid,
+ 'memory_actual' : domInfo["mem_kb"] * 1024,
+ 'vcpus_number' : domInfo["online_vcpus"],
+ 'vcpus_utilisation' : self.get_vcpus_utilisation()
+ }
+ else:
+ return { 'uuid' : self.uuid,
+ 'memory_actual' : 0,
+ 'vcpus_number' : 0,
+ 'vcpus_utilisation' : {}
+ }
diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py
index 4f929cd92d..d9e850ccc9 100644
--- a/tools/python/xen/xend/image.py
+++ b/tools/python/xen/xend/image.py
@@ -13,7 +13,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
-# Copyright (C) 2005 XenSource Ltd
+# Copyright (C) 2005-2007 XenSource Ltd
#============================================================================
@@ -24,7 +24,7 @@ import signal
import xen.lowlevel.xc
from xen.xend.XendConstants import REVERSE_DOMAIN_SHUTDOWN_REASONS
-from xen.xend.XendError import VmError, XendError
+from xen.xend.XendError import VmError, XendError, HVMRequired
from xen.xend.XendLogging import log
from xen.xend.XendOptions import instance as xenopts
from xen.xend.server.netif import randomMAC
@@ -36,13 +36,12 @@ xc = xen.lowlevel.xc.xc()
MAX_GUEST_CMDLINE = 1024
-def create(vm, vmConfig, imageConfig, deviceConfig):
+def create(vm, vmConfig):
"""Create an image handler for a vm.
@return ImageHandler instance
"""
- return findImageHandlerClass(imageConfig)(vm, vmConfig, imageConfig,
- deviceConfig)
+ return findImageHandlerClass(vmConfig)(vm, vmConfig)
class ImageHandler:
@@ -65,7 +64,7 @@ class ImageHandler:
ostype = None
- def __init__(self, vm, vmConfig, imageConfig, deviceConfig):
+ def __init__(self, vm, vmConfig):
self.vm = vm
self.bootloader = False
@@ -73,9 +72,9 @@ class ImageHandler:
self.ramdisk = None
self.cmdline = None
- self.configure(vmConfig, imageConfig, deviceConfig)
+ self.configure(vmConfig)
- def configure(self, vmConfig, imageConfig, _):
+ def configure(self, vmConfig):
"""Config actions common to all unix-like domains."""
if '_temp_using_bootloader' in vmConfig:
self.bootloader = True
@@ -233,30 +232,29 @@ class HVMImageHandler(ImageHandler):
ostype = "hvm"
- def __init__(self, vm, vmConfig, imageConfig, deviceConfig):
- ImageHandler.__init__(self, vm, vmConfig, imageConfig, deviceConfig)
+ def __init__(self, vm, vmConfig):
+ ImageHandler.__init__(self, vm, vmConfig)
self.shutdownWatch = None
self.rebootFeatureWatch = None
- def configure(self, vmConfig, imageConfig, deviceConfig):
- ImageHandler.configure(self, vmConfig, imageConfig, deviceConfig)
+ def configure(self, vmConfig):
+ ImageHandler.configure(self, vmConfig)
if not self.kernel:
self.kernel = '/usr/lib/xen/boot/hvmloader'
info = xc.xeninfo()
if 'hvm' not in info['xen_caps']:
- raise VmError("HVM guest support is unavailable: is VT/AMD-V "
- "supported by your CPU and enabled in your BIOS?")
+ raise HVMRequired()
self.dmargs = self.parseDeviceModelArgs(vmConfig)
- self.device_model = imageConfig['hvm'].get('device_model')
+ self.device_model = vmConfig['platform'].get('device_model')
if not self.device_model:
raise VmError("hvm: missing device model")
- self.display = imageConfig['hvm'].get('display')
- self.xauthority = imageConfig['hvm'].get('xauthority')
- self.vncconsole = imageConfig['hvm'].get('vncconsole')
+ self.display = vmConfig['platform'].get('display')
+ self.xauthority = vmConfig['platform'].get('xauthority')
+ self.vncconsole = vmConfig['platform'].get('vncconsole')
self.vm.storeVm(("image/dmargs", " ".join(self.dmargs)),
("image/device-model", self.device_model),
@@ -264,9 +262,9 @@ class HVMImageHandler(ImageHandler):
self.pid = None
- self.pae = imageConfig['hvm'].get('pae', 0)
- self.apic = imageConfig['hvm'].get('apic', 0)
- self.acpi = imageConfig['hvm']['devices'].get('acpi', 0)
+ self.pae = int(vmConfig['platform'].get('pae', 0))
+ self.apic = int(vmConfig['platform'].get('apic', 0))
+ self.acpi = int(vmConfig['platform'].get('acpi', 0))
def buildDomain(self):
@@ -302,11 +300,10 @@ class HVMImageHandler(ImageHandler):
'localtime', 'serial', 'stdvga', 'isa',
'acpi', 'usb', 'usbdevice', 'keymap' ]
- hvmDeviceConfig = vmConfig['image']['hvm']['devices']
ret = ['-vcpus', str(self.vm.getVCpuCount())]
for a in dmargs:
- v = hvmDeviceConfig.get(a)
+ v = vmConfig['platform'].get(a)
# python doesn't allow '-' in variable names
if a == 'stdvga': a = 'std-vga'
@@ -366,14 +363,14 @@ class HVMImageHandler(ImageHandler):
# Find RFB console device, and if it exists, make QEMU enable
# the VNC console.
#
- if vmConfig['image'].get('nographic'):
+ if int(vmConfig['platform'].get('nographic', 0)) != 0:
# skip vnc init if nographic is set
ret.append('-nographic')
return ret
vnc_config = {}
- has_vnc = int(vmConfig['image'].get('vnc', 0)) != 0
- has_sdl = int(vmConfig['image'].get('sdl', 0)) != 0
+ has_vnc = int(vmConfig['platform'].get('vnc', 0)) != 0
+ has_sdl = int(vmConfig['platform'].get('sdl', 0)) != 0
for dev_uuid in vmConfig['console_refs']:
dev_type, dev_info = vmConfig['devices'][dev_uuid]
if dev_type == 'vfb':
@@ -385,8 +382,8 @@ class HVMImageHandler(ImageHandler):
if not vnc_config:
for key in ('vncunused', 'vnclisten', 'vncdisplay',
'vncpasswd'):
- if key in vmConfig['image']:
- vnc_config[key] = vmConfig['image'][key]
+ if key in vmConfig['platform']:
+ vnc_config[key] = vmConfig['platform'][key]
if not vnc_config.get('vncunused', 0) and \
vnc_config.get('vncdisplay', 0):
@@ -604,9 +601,7 @@ def findImageHandlerClass(image):
@param image config
@return ImageHandler subclass or None
"""
- image_type = image['type']
- if image_type is None:
- raise VmError('missing image type')
+ image_type = image.image_type()
try:
return _handlers[arch.type][image_type]
except KeyError:
diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py
index 04f7a789a6..adb83b679c 100644
--- a/tools/python/xen/xend/server/SrvDaemon.py
+++ b/tools/python/xen/xend/server/SrvDaemon.py
@@ -276,9 +276,12 @@ class Daemon:
if not m:
return None
modulename = m.group(1)
- if re.search('sxp.py', modulename):
- return None
- if re.search('SrvServer.py', modulename):
+ if modulename.endswith('.pyc'):
+ modulename = modulename[:-1]
+ if modulename == 'sxp.py' or \
+ modulename == 'XendLogging.py' or \
+ modulename == 'XendMonitor.py' or \
+ modulename == 'server/SrvServer.py':
return None
self.traceindent += 1
self.print_trace("> %s:%s\n"
diff --git a/tools/python/xen/xend/server/XMLRPCServer.py b/tools/python/xen/xend/server/XMLRPCServer.py
index 7c3a2a1a9d..ed07811ff6 100644
--- a/tools/python/xen/xend/server/XMLRPCServer.py
+++ b/tools/python/xen/xend/server/XMLRPCServer.py
@@ -157,7 +157,7 @@ class XMLRPCServer:
self.server.register_function(fn, "xend.domain.%s" % name[7:])
# Functions in XendNode and XendDmesg
- for type, lst, n in [(XendNode, ['info'], 'node'),
+ for type, lst, n in [(XendNode, ['info', 'send_debug_keys'], 'node'),
(XendDmesg, ['info', 'clear'], 'node.dmesg')]:
inst = type.instance()
for name in lst:
diff --git a/tools/python/xen/xend/server/vfbif.py b/tools/python/xen/xend/server/vfbif.py
index fb510de25f..cbef190248 100644
--- a/tools/python/xen/xend/server/vfbif.py
+++ b/tools/python/xen/xend/server/vfbif.py
@@ -46,7 +46,7 @@ class VfbifController(DevController):
def createDevice(self, config):
DevController.createDevice(self, config)
- if self.vm.info.get('HVM_boot_policy'):
+ if self.vm.info.is_hvm():
# is HVM, so qemu-dm will handle the vfb.
return
diff --git a/tools/python/xen/xm/XenAPI.py b/tools/python/xen/xm/XenAPI.py
index 8d58c3f7f6..ae2448eb71 100644
--- a/tools/python/xen/xm/XenAPI.py
+++ b/tools/python/xen/xm/XenAPI.py
@@ -155,7 +155,7 @@ class Session(xen.util.xmlrpclib2.ServerProxy):
def _parse_result(result):
if type(result) != dict or 'Status' not in result:
- raise xmlrpclib.Fault(500, 'Missing Status in response from server')
+ raise xmlrpclib.Fault(500, 'Missing Status in response from server: ' + str(result))
if result['Status'] == 'Success':
if 'Value' in result:
return result['Value']
diff --git a/tools/python/xen/xm/addlabel.py b/tools/python/xen/xm/addlabel.py
index af176da433..2d42d6702d 100644
--- a/tools/python/xen/xm/addlabel.py
+++ b/tools/python/xen/xm/addlabel.py
@@ -17,7 +17,7 @@
# Author: Bryan D. Payne <bdpayne@us.ibm.com>
#============================================================================
-"""Labeling a domain configuration file or a resoruce.
+"""Labeling a domain configuration file or a resource.
"""
import os
import sys
diff --git a/tools/python/xen/xm/create.dtd b/tools/python/xen/xm/create.dtd
new file mode 100644
index 0000000000..b544edc5bd
--- /dev/null
+++ b/tools/python/xen/xm/create.dtd
@@ -0,0 +1,118 @@
+<!ENTITY % HTMLlat1 PUBLIC
+ "-//W3C//ENTITIES Latin 1 for XHTML//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent">
+%HTMLlat1;
+<!ENTITY % HTMLsymbol PUBLIC
+ "-//W3C//ENTITIES Symbols for XHTML//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent">
+%HTMLsymbol;
+<!ENTITY % HTMLspecial PUBLIC
+ "-//W3C//ENTITIES Special for XHTML//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent">
+%HTMLspecial;
+<!-- a Uniform Resource Identifier, see [RFC2396] -->
+<!ENTITY % URI "CDATA">
+<!ENTITY % NAMEID "name ID #REQUIRED">
+<!ENTITY % CRASH_BEHAVIOUR "( destroy
+ | coredump_and_destroy
+ | restart
+ | coredump_and_restart
+ | preserve
+ | rename_restart )">
+<!ENTITY % NORMAL_EXIT "( destroy | restart )">
+<!ENTITY % VDI_TYPE "( system
+ | user
+ | ephemeral
+ | suspend
+ | crashdump )">
+
+<!ELEMENT xm (vm*,
+ vdi*)>
+
+<!ELEMENT version (#PCDATA)>
+
+<!ELEMENT vm (name,
+ version,
+ (pv|hvm),
+ memory,
+ vbd*,
+ vif*,
+ vcpu_param*,
+ other_config*)>
+<!ATTLIST vm is_a_template CDATA #REQUIRED
+ auto_power_on CDATA #REQUIRED
+ vcpus_max CDATA #REQUIRED
+ vcpus_at_startup CDATA #REQUIRED
+ actions_after_shutdown %NORMAL_EXIT; #REQUIRED
+ actions_after_reboot %NORMAL_EXIT; #REQUIRED
+ actions_after_crash %CRASH_BEHAVIOUR; #REQUIRED
+ platform_std_VGA CDATA #REQUIRED
+ platform_serial CDATA #REQUIRED
+ platform_localtime CDATA #REQUIRED
+ platform_clock_offet CDATA #REQUIRED
+ platform_enable_audio CDATA #REQUIRED
+ PCI_bus CDATA #REQUIRED>
+
+<!ELEMENT memory EMPTY>
+<!ATTLIST memory static_min CDATA #REQUIRED
+ static_max CDATA #REQUIRED
+ dynamic_min CDATA #REQUIRED
+ dynamic_max CDATA #REQUIRED>
+
+<!ELEMENT vbd (qos_algorithm_param*)>
+<!ATTLIST vbd %NAMEID;
+ mode (RO | RW) #REQUIRED
+ vdi IDREF #REQUIRED
+ device CDATA #REQUIRED
+ bootable CDATA #REQUIRED
+ type (CD | disk) #REQUIRED
+ qos_algorithm_type CDATA #REQUIRED>
+
+<!ELEMENT vif (qos_algorithm_param*)>
+<!ATTLIST vif %NAMEID;
+ mac CDATA #REQUIRED
+ mtu CDATA #REQUIRED
+ device CDATA #REQUIRED
+ qos_algorithm_type CDATA #REQUIRED
+ bridge CDATA #IMPLIED
+ network CDATA #IMPLIED>
+
+<!ELEMENT pv EMPTY>
+<!ATTLIST pv kernel CDATA #REQUIRED
+ bootloader CDATA #REQUIRED
+ ramdisk CDATA #REQUIRED
+ args CDATA #REQUIRED
+ bootloader_args CDATA #REQUIRED>
+
+<!ELEMENT hvm (boot_param*)>
+<!ATTLIST hvm boot_policy CDATA #REQUIRED>
+
+<!ELEMENT boot_param EMPTY>
+<!ATTLIST boot_param key CDATA #REQUIRED
+ value CDATA #REQUIRED>
+
+<!ELEMENT vdi (name)>
+<!ATTLIST vdi %NAMEID;
+ src %URI; #REQUIRED
+ type %VDI_TYPE; #REQUIRED
+ size CDATA #REQUIRED
+ shareable CDATA #REQUIRED
+ read_only CDATA #REQUIRED>
+
+<!ELEMENT name (label,
+ description)>
+
+<!ELEMENT label (#PCDATA)>
+<!ELEMENT description (#PCDATA)>
+
+<!ELEMENT vcpu_param EMPTY>
+<!ATTLIST vcpu_param key CDATA #REQUIRED
+ value CDATA #REQUIRED>
+
+<!ELEMENT other_config EMPTY>
+<!ATTLIST other_config key CDATA #REQUIRED
+ value CDATA #REQUIRED>
+
+<!ELEMENT qos_algorithm_param EMPTY>
+<!ATTLIST qos_algorithm_param key CDATA #REQUIRED
+ value CDATA #REQUIRED>
diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py
index 450e3283d1..abdfa22031 100644
--- a/tools/python/xen/xm/create.py
+++ b/tools/python/xen/xm/create.py
@@ -28,12 +28,13 @@ import time
import xmlrpclib
from xen.xend import sxp
-from xen.xend import PrettyPrint
+from xen.xend import PrettyPrint as SXPPrettyPrint
from xen.xend import osdep
import xen.xend.XendClient
from xen.xend.XendBootloader import bootloader
from xen.util import blkif
from xen.util import security
+from xen.xm.main import serverType, SERVER_XEN_API, get_single_vm
from xen.xm.opts import *
@@ -98,6 +99,11 @@ gopts.opt('dryrun', short='n',
use="Dry run - prints the resulting configuration in SXP but "
"does not create the domain.")
+gopts.opt('xmldryrun', short='x',
+ fn=set_true, default=0,
+ use="XML dry run - prints the resulting configuration in XML but "
+ "does not create the domain.")
+
gopts.opt('paused', short='p',
fn=set_true, default=0,
use='Leave the domain paused after it is created.')
@@ -1241,34 +1247,59 @@ def main(argv):
except IOError, exn:
raise OptionError("Cannot read file %s: %s" % (config, exn[1]))
+ if serverType == SERVER_XEN_API:
+ from xen.xm.xenapi_create import sxp2xml
+ sxp2xml_inst = sxp2xml()
+ doc = sxp2xml_inst.convert_sxp_to_xml(config, transient=True)
+
if opts.vals.dryrun:
- PrettyPrint.prettyprint(config)
+ SXPPrettyPrint.prettyprint(config)
+
+ if opts.vals.xmldryrun and serverType == SERVER_XEN_API:
+ from xml.dom.ext import PrettyPrint as XMLPrettyPrint
+ XMLPrettyPrint(doc)
+
+ if opts.vals.dryrun or opts.vals.xmldryrun:
+ return
+
+ if opts.vals.console_autoconnect:
+ do_console(sxp.child_value(config, 'name', -1))
+
+ if serverType == SERVER_XEN_API:
+ from xen.xm.xenapi_create import xenapi_create
+ xenapi_create_inst = xenapi_create()
+ vm_refs = xenapi_create_inst.create(document = doc)
+
+ map(lambda vm_ref: server.xenapi.VM.start(vm_ref, 0), vm_refs)
else:
if not create_security_check(config):
- raise security.ACMError('Security Configuration prevents domain from starting')
- else:
- if opts.vals.console_autoconnect:
- cpid = os.fork()
- if cpid != 0:
- for i in range(10):
- # Catch failure of the create process
- time.sleep(1)
- (p, rv) = os.waitpid(cpid, os.WNOHANG)
- if os.WIFEXITED(rv):
- if os.WEXITSTATUS(rv) != 0:
- sys.exit(os.WEXITSTATUS(rv))
- try:
- # Acquire the console of the created dom
- name = sxp.child_value(config, 'name', -1)
- dom = server.xend.domain(name)
- domid = int(sxp.child_value(dom, 'domid', '-1'))
- console.execConsole(domid)
- except:
- pass
- print("Could not start console\n");
- sys.exit(0)
- dom = make_domain(opts, config)
-
+ raise security.ACMError(
+ 'Security Configuration prevents domain from starting')
+ dom = make_domain(opts, config)
+
+def do_console(domain_name):
+ cpid = os.fork()
+ if cpid != 0:
+ for i in range(10):
+ # Catch failure of the create process
+ time.sleep(1)
+ (p, rv) = os.waitpid(cpid, os.WNOHANG)
+ if os.WIFEXITED(rv):
+ if os.WEXITSTATUS(rv) != 0:
+ sys.exit(os.WEXITSTATUS(rv))
+ try:
+ # Acquire the console of the created dom
+ if serverType == SERVER_XEN_API:
+ domid = server.xenapi.VM.get_domid(
+ get_single_vm(domain_name))
+ else:
+ dom = server.xend.domain(domain_name)
+ domid = int(sxp.child_value(dom, 'domid', '-1'))
+ console.execConsole(domid)
+ except:
+ pass
+ print("Could not start console\n");
+ sys.exit(0)
if __name__ == '__main__':
main(sys.argv)
diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py
index 7075e95444..66a5951f7f 100644
--- a/tools/python/xen/xm/main.py
+++ b/tools/python/xen/xm/main.py
@@ -25,6 +25,7 @@ import atexit
import cmd
import os
import pprint
+import readline
import shlex
import sys
import re
@@ -32,11 +33,11 @@ import getopt
import socket
import traceback
import xmlrpclib
-import traceback
import time
import datetime
from select import select
import xml.dom.minidom
+from xen.util.blkif import blkdev_name_to_number
import warnings
warnings.filterwarnings('ignore', category=FutureWarning)
@@ -48,18 +49,19 @@ from xen.xend.XendConstants import *
from xen.xm.opts import OptionError, Opts, wrap, set_true
from xen.xm import console
-from xen.util import security
from xen.util.xmlrpclib2 import ServerProxy
import XenAPI
+
# getopt.gnu_getopt is better, but only exists in Python 2.3+. Use
# getopt.getopt if gnu_getopt is not available. This will mean that options
# may only be specified before positional arguments.
if not hasattr(getopt, 'gnu_getopt'):
getopt.gnu_getopt = getopt.getopt
-XM_CONFIG_FILE = '/etc/xen/xm-config.xml'
+XM_CONFIG_FILE_ENVVAR = 'XM_CONFIG_FILE'
+XM_CONFIG_FILE_DEFAULT = '/etc/xen/xm-config.xml'
# Supported types of server
SERVER_LEGACY_XMLRPC = 'LegacyXMLRPC'
@@ -133,11 +135,12 @@ SUBCOMMAND_HELP = {
'sched-credit': ('[-d <Domain> [-w[=WEIGHT]|-c[=CAP]]]',
'Get/set credit scheduler parameters.'),
'sysrq' : ('<Domain> <letter>', 'Send a sysrq to a domain.'),
+ 'debug-keys' : ('<Keys>', 'Send debug keys to Xen.'),
'trigger' : ('<Domain> <nmi|reset|init> [<VCPU>]',
'Send a trigger to a domain.'),
'vcpu-list' : ('[<Domain>]',
'List the VCPUs for a domain or all domains.'),
- 'vcpu-pin' : ('<Domain> <VCPU> <CPUs>',
+ 'vcpu-pin' : ('<Domain> <VCPU> <CPUs|all>',
'Set which CPUs a VCPU can use.'),
'vcpu-set' : ('<Domain> <vCPUs>',
'Set the number of active VCPUs for allowed for the'
@@ -260,7 +263,6 @@ common_commands = [
"shutdown",
"start",
"suspend",
- "trigger",
"top",
"unpause",
"uptime",
@@ -300,6 +302,7 @@ domain_commands = [
]
host_commands = [
+ "debug-keys",
"dmesg",
"info",
"log",
@@ -349,13 +352,14 @@ all_commands = (domain_commands + host_commands + scheduler_commands +
# Configuration File Parsing
##
+xmConfigFile = os.getenv(XM_CONFIG_FILE_ENVVAR, XM_CONFIG_FILE_DEFAULT)
config = None
-if os.path.isfile(XM_CONFIG_FILE):
+if os.path.isfile(xmConfigFile):
try:
- config = xml.dom.minidom.parse(XM_CONFIG_FILE)
+ config = xml.dom.minidom.parse(xmConfigFile)
except:
print >>sys.stderr, ('Ignoring invalid configuration file %s.' %
- XM_CONFIG_FILE)
+ xmConfigFile)
def parseServer():
if config:
@@ -489,6 +493,18 @@ def usage(cmd = None):
#
####################################################################
+def get_default_SR():
+ return [sr_ref
+ for sr_ref in server.xenapi.SR.get_all()
+ if server.xenapi.SR.get_type(sr_ref) == "local"][0]
+
+def get_default_Network():
+ return [network_ref
+ for network_ref in server.xenapi.network.get_all()][0]
+
+def map2sxp(m):
+ return [[k, m[k]] for k in m.keys()]
+
def arg_check(args, name, lo, hi = -1):
n = len([i for i in args if i != '--'])
@@ -555,7 +571,11 @@ class Shell(cmd.Cmd):
if serverType == SERVER_XEN_API:
res = server.xenapi._UNSUPPORTED_list_all_methods()
for f in res:
- setattr(Shell, 'do_' + f, self.default)
+ setattr(Shell, 'do_' + f + ' ', self.default)
+
+ def preloop(self):
+ cmd.Cmd.preloop(self)
+ readline.set_completer_delims(' ')
def default(self, line):
words = shlex.split(line)
@@ -576,9 +596,9 @@ class Shell(cmd.Cmd):
return False
def completedefault(self, text, line, begidx, endidx):
- cmd = line.split(' ')[0]
- clas, func = cmd.split('.')
- if begidx != len(cmd) + 1 or \
+ words = shlex.split(line[:begidx])
+ clas, func = words[0].split('.')
+ if len(words) > 1 or \
func.startswith('get_by_') or \
func == 'get_all':
return []
@@ -667,10 +687,41 @@ def xm_restore(args):
def getDomains(domain_names, state, full = 0):
- if domain_names:
- return [server.xend.domain(dom, full) for dom in domain_names]
+ if serverType == SERVER_XEN_API:
+ doms_sxp = []
+ doms_dict = []
+ dom_refs = server.xenapi.VM.get_all()
+ for dom_ref in dom_refs:
+ dom_rec = server.xenapi.VM.get_record(dom_ref)
+ dom_metrics_ref = server.xenapi.VM.get_metrics(dom_ref)
+ dom_metrics = server.xenapi.VM_metrics.get_record(dom_metrics_ref)
+ dom_rec.update({'name': dom_rec['name_label'],
+ 'memory_actual': int(dom_metrics['memory_actual'])/1024,
+ 'vcpus': dom_metrics['vcpus_number'],
+ 'state': '-----',
+ 'cpu_time': dom_metrics['vcpus_utilisation']})
+
+ doms_sxp.append(['domain'] + map2sxp(dom_rec))
+ doms_dict.append(dom_rec)
+
+ if domain_names:
+ doms = [['domain'] + map2sxp(dom) for dom in doms_dict
+ if dom["name"] in domain_names]
+
+ if len(doms) > 0:
+ return doms
+ else:
+ print "Error: no domain%s named %s" % \
+ (len(domain_names) > 1 and 's' or '',
+ ', '.join(domain_names))
+ sys.exit(-1)
+ else:
+ return doms_sxp
else:
- return server.xend.domains_with_state(True, state, full)
+ if domain_names:
+ return [server.xend.domain(dom, full) for dom in domain_names]
+ else:
+ return server.xend.domains_with_state(True, state, full)
def xm_list(args):
@@ -729,26 +780,48 @@ def parse_doms_info(info):
else:
up_time = time.time() - start_time
- return {
+ parsed_info = {
'domid' : get_info('domid', str, ''),
'name' : get_info('name', str, '??'),
- 'mem' : get_info('memory_dynamic_min', int, 0),
'state' : get_info('state', str, ''),
- 'cpu_time' : get_info('cpu_time', float, 0.0),
+
# VCPUs is the number online when the VM is up, or the number
# configured otherwise.
'vcpus' : get_info('online_vcpus', int,
get_info('vcpus', int, 0)),
- 'up_time' : up_time,
- 'seclabel' : security.get_security_printlabel(info),
+ 'up_time' : up_time
}
+ # We're not supporting security stuff just yet via XenAPI
+
+ if serverType != SERVER_XEN_API:
+ from xen.util import security
+ parsed_info['seclabel'] = security.get_security_printlabel(info)
+ else:
+ parsed_info['seclabel'] = ""
+
+ if serverType == SERVER_XEN_API:
+ parsed_info['mem'] = get_info('memory_actual', int, 0) / 1024
+ cpu_times = get_info('cpu_time', lambda x : (x), 0.0)
+ if sum(cpu_times.values()) > 0:
+ parsed_info['cpu_time'] = sum(cpu_times.values()) / float(len(cpu_times.values()))
+ else:
+ parsed_info['cpu_time'] = 0
+ else:
+ parsed_info['mem'] = get_info('memory', int,0)
+ parsed_info['cpu_time'] = get_info('cpu_time', float, 0.0)
+
+ return parsed_info
+
def check_sched_type(sched):
- current = 'unknown'
- for x in server.xend.node.info()[1:]:
- if len(x) > 1 and x[0] == 'xen_scheduler':
- current = x[1]
- break
+ if serverType == SERVER_XEN_API:
+ current = server.xenapi.host.get_sched_policy(server.xenapi.session.get_this_host())
+ else:
+ current = 'unknown'
+ for x in server.xend.node.info()[1:]:
+ if len(x) > 1 and x[0] == 'xen_scheduler':
+ current = x[1]
+ break
if sched != current:
err("Xen is running with the %s scheduler" % current)
sys.exit(1)
@@ -788,17 +861,22 @@ def xm_label_list(doms):
output = []
format = '%(name)-32s %(domid)3s %(mem)5d %(vcpus)5d %(state)10s ' \
'%(cpu_time)8.1f %(seclabel)9s'
-
- for dom in doms:
- d = parse_doms_info(dom)
- if security.active_policy not in ['INACTIVE', 'NULL', 'DEFAULT']:
- if not d['seclabel']:
- d['seclabel'] = 'ERROR'
- elif security.active_policy in ['DEFAULT']:
- d['seclabel'] = 'DEFAULT'
- else:
- d['seclabel'] = 'INACTIVE'
- output.append((format % d, d['seclabel']))
+
+ if serverType != SERVER_XEN_API:
+ from xen.util import security
+
+ for dom in doms:
+ d = parse_doms_info(dom)
+
+ if security.active_policy not in ['INACTIVE', 'NULL', 'DEFAULT']:
+ if not d['seclabel']:
+ d['seclabel'] = 'ERROR'
+ elif security.active_policy in ['DEFAULT']:
+ d['seclabel'] = 'DEFAULT'
+ else:
+ d['seclabel'] = 'INACTIVE'
+
+ output.append((format % d, d['seclabel']))
#sort by labels
output.sort(lambda x,y: cmp( x[1].lower(), y[1].lower()))
@@ -807,7 +885,6 @@ def xm_label_list(doms):
def xm_vcpu_list(args):
-
if args:
dominfo = map(server.xend.domain.getVCPUInfo, args)
else:
@@ -1078,7 +1155,10 @@ def xm_vcpu_pin(args):
dom = args[0]
vcpu = args[1]
- cpumap = cpu_make_map(args[2])
+ if args[2] == 'all':
+ cpumap = cpu_make_map('0-63')
+ else:
+ cpumap = cpu_make_map(args[2])
server.xend.domain.pincpu(dom, vcpu, cpumap)
@@ -1086,49 +1166,69 @@ def xm_mem_max(args):
arg_check(args, "mem-max", 2)
dom = args[0]
- mem = int_unit(args[1], 'm')
- server.xend.domain.maxmem_set(dom, mem)
+ if serverType == SERVER_XEN_API:
+ mem = int_unit(args[1], 'k') * 1024
+ server.xenapi.VM.set_memory_static_max(get_single_vm(dom), mem)
+ else:
+ mem = int_unit(args[1], 'm')
+ server.xend.domain.maxmem_set(dom, mem)
def xm_mem_set(args):
arg_check(args, "mem-set", 2)
dom = args[0]
- mem_target = int_unit(args[1], 'm')
- server.xend.domain.setMemoryTarget(dom, mem_target)
+ if serverType == SERVER_XEN_API:
+ mem_target = int_unit(args[1], 'm') * 1024 * 1024
+ server.xenapi.VM.set_memory_dynamic_max(get_single_vm(dom), mem_target)
+ server.xenapi.VM.set_memory_dynamic_min(get_single_vm(dom), mem_target)
+ else:
+ mem_target = int_unit(args[1], 'm')
+ server.xend.domain.setMemoryTarget(dom, mem_target)
def xm_vcpu_set(args):
arg_check(args, "vcpu-set", 2)
-
- server.xend.domain.setVCpuCount(args[0], int(args[1]))
+ dom = args[0]
+ vcpus = int(args[1])
+
+ if serverType == SERVER_XEN_API:
+ server.xenapi.VM.set_vcpus_live(get_single_vm(dom), vcpus)
+ else:
+ server.xend.domain.setVCpuCount(dom, vcpus)
def xm_destroy(args):
arg_check(args, "destroy", 1)
dom = args[0]
+
if serverType == SERVER_XEN_API:
server.xenapi.VM.hard_shutdown(get_single_vm(dom))
else:
server.xend.domain.destroy(dom)
-
def xm_domid(args):
arg_check(args, "domid", 1)
name = args[0]
- dom = server.xend.domain(name)
- print sxp.child_value(dom, 'domid')
+ if serverType == SERVER_XEN_API:
+ print server.xenapi.VM.get_domid(get_single_vm(name))
+ else:
+ dom = server.xend.domain(name)
+ print sxp.child_value(dom, 'domid')
def xm_domname(args):
arg_check(args, "domname", 1)
name = args[0]
-
- dom = server.xend.domain(name)
- print sxp.child_value(dom, 'name')
+
+ if serverType == SERVER_XEN_API:
+ print server.xenapi.VM.get_name_label(get_single_vm(name))
+ else:
+ dom = server.xend.domain(name)
+ print sxp.child_value(dom, 'name')
def xm_sched_sedf(args):
def ns_to_ms(val):
@@ -1276,13 +1376,59 @@ def xm_sched_credit(args):
def xm_info(args):
arg_check(args, "info", 0)
- info = server.xend.node.info()
-
- for x in info[1:]:
- if len(x) < 2:
- print "%-23s: (none)" % x[0]
- else:
- print "%-23s:" % x[0], x[1]
+ if serverType == SERVER_XEN_API:
+
+ # Need to fake out old style xm info as people rely on parsing it
+
+ host_record = server.xenapi.host.get_record(
+ server.xenapi.session.get_this_host())
+
+ host_cpu_records = map(server.xenapi.host_cpu.get_record, host_record["host_CPUs"])
+
+ host_metrics_record = server.xenapi.host_metrics.get_record(host_record["metrics"])
+
+ info = {
+ "host": host_record["name_label"],
+ "release": host_record["software_version"]["release"],
+ "version": host_record["software_version"]["version"],
+ "machine": host_record["software_version"]["machine"],
+ "nr_cpus": len(host_record["host_CPUs"]),
+ "nr_nodes": host_record["cpu_configuration"]["nr_nodes"],
+ "sockets_per_node": host_record["cpu_configuration"]["sockets_per_node"],
+ "cores_per_socket": host_record["cpu_configuration"]["cores_per_socket"],
+ "threads_per_core": host_record["cpu_configuration"]["threads_per_core"],
+ "cpu_mhz": sum([int(host_cpu_record["speed"]) for host_cpu_record in host_cpu_records])
+ / len(host_cpu_records),
+ "hw_caps": host_cpu_records[0]["features"],
+ "total_memory": int(host_metrics_record["memory_total"])/1024/1024,
+ "free_memory": int(host_metrics_record["memory_free"])/1024/1024,
+ "xen_major": host_record["software_version"]["xen_major"],
+ "xen_minor": host_record["software_version"]["xen_minor"],
+ "xen_extra": host_record["software_version"]["xen_extra"],
+ "xen_caps": " ".join(host_record["capabilities"]),
+ "xen_scheduler": host_record["sched_policy"],
+ "xen_pagesize": host_record["other_config"]["xen_pagesize"],
+ "platform_params": host_record["other_config"]["platform_params"],
+ "xen_changeset": host_record["software_version"]["xen_changeset"],
+ "cc_compiler": host_record["software_version"]["cc_compiler"],
+ "cc_compile_by": host_record["software_version"]["cc_compile_by"],
+ "cc_compile_domain": host_record["software_version"]["cc_compile_domain"],
+ "cc_compile_date": host_record["software_version"]["cc_compile_date"],
+ "xend_config_format":host_record["software_version"]["xend_config_format"]
+ }
+
+ sorted = info.items()
+ sorted.sort(lambda (x1,y1), (x2,y2): -cmp(x1,x2))
+
+ for (k, v) in sorted:
+ print "%-23s:" % k, v
+ else:
+ info = server.xend.node.info()
+ for x in info[1:]:
+ if len(x) < 2:
+ print "%-23s: (none)" % x[0]
+ else:
+ print "%-23s:" % x[0], x[1]
def xm_console(args):
arg_check(args, "console", 1, 2)
@@ -1308,13 +1454,17 @@ def xm_console(args):
dom = params[0]
try:
- info = server.xend.domain(dom)
+ if serverType == SERVER_XEN_API:
+ domid = int(server.xenapi.VM.get_domid(get_single_vm(dom)))
+ else:
+ info = server.xend.domain(dom)
+ domid = int(sxp.child_value(info, 'domid', '-1'))
except:
if quiet:
sys.exit(1)
else:
raise
- domid = int(sxp.child_value(info, 'domid', '-1'))
+
if domid == -1:
if quiet:
sys.exit(1)
@@ -1382,7 +1532,10 @@ def xm_sysrq(args):
arg_check(args, "sysrq", 2)
dom = args[0]
req = args[1]
- server.xend.domain.send_sysrq(dom, req)
+ if serverType == SERVER_XEN_API:
+ server.xenapi.VM.send_sysrq(get_single_vm(dom), req)
+ else:
+ server.xend.domain.send_sysrq(dom, req)
def xm_trigger(args):
vcpu = 0
@@ -1392,8 +1545,23 @@ def xm_trigger(args):
trigger = args[1]
if len(args) == 3:
vcpu = int(args[2])
+
+ if serverType == SERVER_XEN_API:
+ server.xenapi.VM.send_trigger(get_single_vm(dom), trigger, vcpu)
+ else:
+ server.xend.domain.send_trigger(dom, trigger, vcpu)
+
+def xm_debug_keys(args):
+ arg_check(args, "debug-keys", 1)
+
+ keys = str(args[0])
- server.xend.domain.send_trigger(dom, trigger, vcpu)
+ if serverType == SERVER_XEN_API:
+ server.xenapi.host.send_debug_keys(
+ server.xenapi.session.get_this_host(),
+ keys)
+ else:
+ server.xend.node.send_debug_keys(keys)
def xm_top(args):
arg_check(args, "top", 0)
@@ -1418,17 +1586,33 @@ def xm_dmesg(args):
err("No parameter required")
usage('dmesg')
- if not use_clear:
- print server.xend.node.dmesg.info()
+ if serverType == SERVER_XEN_API:
+ if not use_clear:
+ print server.xenapi.host.dmesg(
+ server.xenapi.session.get_this_host(),0)
+ else:
+ server.xenapi.host.dmesg(
+ server.xenapi.session.get_this_host(),1)
else:
- server.xend.node.dmesg.clear()
+ if not use_clear:
+ print server.xend.node.dmesg.info()
+ else:
+ server.xend.node.dmesg.clear()
def xm_log(args):
arg_check(args, "log", 0)
-
- print server.xend.node.log()
+
+ if serverType == SERVER_XEN_API:
+ print server.xenapi.host.get_log(
+ server.xenapi.session.get_this_host())
+ else:
+ print server.xend.node.log()
def xm_serve(args):
+ if serverType == SERVER_XEN_API:
+ print "Not supported with XenAPI"
+ sys.exit(-1)
+
arg_check(args, "serve", 0)
from fcntl import fcntl, F_SETFL
@@ -1503,12 +1687,21 @@ def xm_network_list(args):
(use_long, params) = arg_check_for_resource_list(args, "network-list")
dom = params[0]
- if use_long:
+
+ if serverType == SERVER_XEN_API:
+ vif_refs = server.xenapi.VM.get_VIFs(get_single_vm(dom))
+ vif_properties = \
+ map(server.xenapi.VIF.get_runtime_properties, vif_refs)
+ devs = map(lambda (handle, properties): [handle, map2sxp(properties)],
+ zip(range(len(vif_properties)), vif_properties))
+ else:
devs = server.xend.domain.getDeviceSxprs(dom, 'vif')
+
+ if use_long:
map(PrettyPrint.prettyprint, devs)
else:
hdr = 0
- for x in server.xend.domain.getDeviceSxprs(dom, 'vif'):
+ for x in devs:
if hdr == 0:
print 'Idx BE MAC Addr. handle state evt-ch tx-/rx-ring-ref BE-path'
hdr = 1
@@ -1528,12 +1721,25 @@ def xm_block_list(args):
(use_long, params) = arg_check_for_resource_list(args, "block-list")
dom = params[0]
- if use_long:
+
+ if serverType == SERVER_XEN_API:
+ vbd_refs = server.xenapi.VM.get_VBDs(get_single_vm(dom))
+ vbd_properties = \
+ map(server.xenapi.VBD.get_runtime_properties, vbd_refs)
+ vbd_devs = \
+ map(server.xenapi.VBD.get_device, vbd_refs)
+ vbd_devids = \
+ map(blkdev_name_to_number, vbd_devs)
+ devs = map(lambda (devid, prop): [devid, map2sxp(prop)],
+ zip(vbd_devids, vbd_properties))
+ else:
devs = server.xend.domain.getDeviceSxprs(dom, 'vbd')
+
+ if use_long:
map(PrettyPrint.prettyprint, devs)
else:
hdr = 0
- for x in server.xend.domain.getDeviceSxprs(dom, 'vbd'):
+ for x in devs:
if hdr == 0:
print 'Vdev BE handle state evt-ch ring-ref BE-path'
hdr = 1
@@ -1588,13 +1794,17 @@ def parse_block_configuration(args):
if len(args) == 5:
vbd.append(['backend', args[4]])
- # verify that policy permits attaching this resource
- if security.on():
- dominfo = server.xend.domain(dom)
- label = security.get_security_printlabel(dominfo)
- else:
- label = None
- security.res_security_check(args[1], label)
+ if serverType != SERVER_XEN_API:
+ # verify that policy permits attaching this resource
+ from xen.util import security
+
+ if security.on():
+ dominfo = server.xend.domain(dom)
+ label = security.get_security_printlabel(dominfo)
+ else:
+ label = None
+
+ security.res_security_check(args[1], label)
return (dom, vbd)
@@ -1602,8 +1812,45 @@ def parse_block_configuration(args):
def xm_block_attach(args):
arg_check(args, 'block-attach', 4, 5)
- (dom, vbd) = parse_block_configuration(args)
- server.xend.domain.device_create(dom, vbd)
+ if serverType == SERVER_XEN_API:
+ dom = args[0]
+ uname = args[1]
+ dev = args[2]
+ mode = args[3]
+
+ # First create new VDI
+ vdi_record = {
+ "name_label": "vdi" + str(uname.__hash__()),
+ "name_description": "",
+ "SR": get_default_SR(),
+ "virtual_size": 0,
+ "sector_size": 512,
+ "type": "system",
+ "sharable": False,
+ "read_only": mode!="w",
+ "other_config": {"location": uname}
+ }
+
+ vdi_ref = server.xenapi.VDI.create(vdi_record)
+
+ # Now create new VBD
+
+ vbd_record = {
+ "VM": get_single_vm(dom),
+ "VDI": vdi_ref,
+ "device": dev,
+ "bootable": True,
+ "mode": mode=="w" and "RW" or "RO",
+ "type": "Disk",
+ "qos_algorithm_type": "",
+ "qos_algorithm_params": {}
+ }
+
+ server.xenapi.VBD.create(vbd_record)
+
+ else:
+ (dom, vbd) = parse_block_configuration(args)
+ server.xend.domain.device_create(dom, vbd)
def xm_block_configure(args):
@@ -1621,15 +1868,65 @@ def xm_network_attach(args):
vif_params = ['type', 'mac', 'bridge', 'ip', 'script', \
'backend', 'vifname', 'rate', 'model']
- for a in args[1:]:
- vif_param = a.split("=")
- if len(vif_param) != 2 or vif_param[1] == '' or \
- vif_param[0] not in vif_params:
- err("Invalid argument: %s" % a)
- usage('network-attach')
- vif.append(vif_param)
+ if serverType == SERVER_XEN_API:
+ vif_record = {
+ "device": "eth0",
+ "network": get_default_Network(),
+ "VM": get_single_vm(dom),
+ "MAC": "",
+ "MTU": "",
+ "qos_algorithm_type": "",
+ "qos_algorithm_params": {},
+ "other_config": {}
+ }
+
+ def set(keys, val):
+ record = vif_record
+ for key in keys[:-1]:
+ record = record[key]
+ record[keys[-1]] = val
+
+ vif_conv = {
+ 'type':
+ lambda x: None,
+ 'mac':
+ lambda x: set(['MAC'], x),
+ 'bridge':
+ lambda x: set(['network'], get_net_from_bridge(x)),
+ 'ip':
+ lambda x: set(['other_config', 'ip'], x),
+ 'script':
+ lambda x: set(['other_config', 'script'], x),
+ 'backend':
+ lambda x: set(['other_config', 'backend'], x),
+ 'vifname':
+ lambda x: set(['device'], x),
+ 'rate':
+ lambda x: set(['qos_algorithm_params', 'rate'], x),
+ 'model':
+ lambda x: None
+ }
+
+ for a in args[1:]:
+ vif_param = a.split("=")
+ if len(vif_param) != 2 or vif_param[1] == '' or \
+ vif_param[0] not in vif_params:
+ err("Invalid argument: %s" % a)
+ usage('network-attach')
+ else:
+ vif_conv[vif_param[0]](vif_param[1])
- server.xend.domain.device_create(dom, vif)
+ print str(vif_record)
+ server.xenapi.VIF.create(vif_record)
+ else:
+ for a in args[1:]:
+ vif_param = a.split("=")
+ if len(vif_param) != 2 or vif_param[1] == '' or \
+ vif_param[0] not in vif_params:
+ err("Invalid argument: %s" % a)
+ usage('network-attach')
+ vif.append(vif_param)
+ server.xend.domain.device_create(dom, vif)
def detach(args, command, deviceClass):
@@ -1649,16 +1946,49 @@ def detach(args, command, deviceClass):
def xm_block_detach(args):
- try:
- detach(args, 'block-detach', 'vbd')
- return
- except:
- pass
- detach(args, 'block-detach', 'tap')
-
+ if serverType == SERVER_XEN_API:
+ arg_check(args, "xm_block_detach", 2, 3)
+ dom = args[0]
+ dev = args[1]
+ vbd_refs = server.xenapi.VM.get_VBDs(get_single_vm(dom))
+ vbd_refs = [vbd_ref for vbd_ref in vbd_refs
+ if server.xenapi.VBD.get_device(vbd_ref) == dev]
+ if len(vbd_refs) > 0:
+ vbd_ref = vbd_refs[0]
+ vdi_ref = server.xenapi.VBD.get_VDI(vbd_ref)
+
+ server.xenapi.VBD.destroy(vbd_ref)
+
+ if len(server.xenapi.VDI.get_VBDs(vdi_ref)) <= 0:
+ server.xenapi.VDI.destroy(vdi_ref)
+ else:
+ raise OptionError("Cannot find device '%s' in domain '%s'"
+ % (dev,dom))
+ else:
+ try:
+ detach(args, 'block-detach', 'vbd')
+ return
+ except:
+ pass
+ detach(args, 'block-detach', 'tap')
def xm_network_detach(args):
- detach(args, 'network-detach', 'vif')
+ if serverType == SERVER_XEN_API:
+ arg_check(args, "xm_block_detach", 2, 3)
+ dom = args[0]
+ devid = args[1]
+ vif_refs = server.xenapi.VM.get_VIFs(get_single_vm(dom))
+ vif_refs = [vif_ref for vif_ref in vif_refs
+ if server.xenapi.VIF.\
+ get_runtime_properties(vif_ref)["handle"] == devid]
+ if len(vif_refs) > 0:
+ vif_ref = vif_refs[0]
+
+ server.xenapi.VIF.destroy(vif_ref)
+ else:
+ print "Cannot find device '%s' in domain '%s'" % (devid,dom)
+ else:
+ detach(args, 'network-detach', 'vif')
def xm_vnet_list(args):
@@ -1738,6 +2068,7 @@ commands = {
"pause": xm_pause,
"unpause": xm_unpause,
# host commands
+ "debug-keys": xm_debug_keys,
"dmesg": xm_dmesg,
"info": xm_info,
"log": xm_log,
@@ -1881,7 +2212,7 @@ def _run_cmd(cmd, cmd_name, args):
err("Domain '%s' does not exist." % ex.faultString)
else:
err(ex.faultString)
- _usage(cmd_name)
+ _usage(cmd_name)
except xmlrpclib.ProtocolError, ex:
if ex.errcode == -1:
print >>sys.stderr, (
@@ -1898,13 +2229,17 @@ def _run_cmd(cmd, cmd_name, args):
err(str(e))
_usage(cmd_name)
print e.usage
- except security.ACMError, e:
- err(str(e))
- except:
- print "Unexpected error:", sys.exc_info()[0]
- print
- print "Please report to xen-devel@lists.xensource.com"
- raise
+ except Exception, e:
+ if serverType != SERVER_XEN_API:
+ from xen.util import security
+ if isinstance(e, security.ACMError):
+ err(str(e))
+ return False, 1
+ else:
+ print "Unexpected error:", sys.exc_info()[0]
+ print
+ print "Please report to xen-devel@lists.xensource.com"
+ raise
return False, 1
diff --git a/tools/python/xen/xm/messages/en/xen-xm.po b/tools/python/xen/xm/messages/en/xen-xm.po
index 3ea171b2fa..6e289b4aa3 100644
--- a/tools/python/xen/xm/messages/en/xen-xm.po
+++ b/tools/python/xen/xm/messages/en/xen-xm.po
@@ -19,7 +19,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Xen-xm 3.0\n"
-"PO-Revision-Date: 2007-02-20 15:22+0000\n"
+"PO-Revision-Date: 2007-03-10 23:17+0000\n"
"Last-Translator: Ewan Mellor <ewan@xensource.com>\n"
"Language-Team: xen-devel <xen-devel@lists.xensource.com>\n"
"MIME-Version: 1.0\n"
@@ -61,3 +61,6 @@ msgstr "The VLAN tag you gave (%(1)s) is invalid -- it must be between 0 and 409
msgid "VM_BAD_POWER_STATE"
msgstr "The VM must be %(2)s to perform the requested operation (it is currently %(3)s)."
+
+msgid "VM_HVM_REQUIRED"
+msgstr "HVM guest support is unavailable: is VT/AMD-V supported by your CPU and enabled in your BIOS?"
diff --git a/tools/python/xen/xm/new.py b/tools/python/xen/xm/new.py
index 2c6cae84b6..742c7ff8fd 100644
--- a/tools/python/xen/xm/new.py
+++ b/tools/python/xen/xm/new.py
@@ -22,6 +22,9 @@ from xen.xend import PrettyPrint
from xen.xend import sxp
from xen.xend import XendClient
+from xen.xm.main import serverType, SERVER_XEN_API
+from xen.xm.xenapi_create import *
+
from opts import *
from create import *
@@ -65,7 +68,15 @@ def main(argv):
if opts.vals.dryrun:
PrettyPrint.prettyprint(config)
- else:
+ return
+
+ if serverType == SERVER_XEN_API:
+ sxp2xml_inst = sxp2xml()
+ doc = sxp2xml_inst.convert_sxp_to_xml(config)
+
+ xenapi_create_inst = xenapi_create()
+ vm_refs = xenapi_create_inst.create(document = doc)
+ else:
make_unstarted_domain(opts, config)
if __name__ == '__main__':
diff --git a/tools/python/xen/xm/shutdown.py b/tools/python/xen/xm/shutdown.py
index 88d36dfba1..8284a73bca 100644
--- a/tools/python/xen/xm/shutdown.py
+++ b/tools/python/xen/xm/shutdown.py
@@ -21,7 +21,8 @@ import time
from xen.xend import sxp
from opts import *
-from main import server
+from main import server, serverType, SERVER_XEN_API, get_single_vm
+from xen.xend.XendAPIConstants import *
gopts = Opts(use="""[options] [DOM]
@@ -49,6 +50,9 @@ gopts.opt('reboot', short='R',
use='Shutdown and reboot.')
def wait_reboot(opts, doms, rcs):
+ if serverType == SERVER_XEN_API:
+ opts.err("Cannot wait for reboot w/ XenAPI (yet)")
+
while doms:
alive = server.xend.domains(0)
reboot = []
@@ -68,7 +72,12 @@ def wait_reboot(opts, doms, rcs):
def wait_shutdown(opts, doms):
while doms:
- alive = server.xend.domains(0)
+ if serverType == SERVER_XEN_API:
+ alive = [dom for dom in server.xenapi.VM.get_all()
+ if server.xenapi.VM.get_power_state(dom) ==
+ XEN_API_VM_POWER_STATE[XEN_API_VM_POWER_STATE_RUNNING]]
+ else:
+ alive = server.xend.domains(0)
dead = []
for d in doms:
if d in alive: continue
@@ -82,8 +91,16 @@ def wait_shutdown(opts, doms):
def shutdown(opts, doms, mode, wait):
rcs = {}
for d in doms:
- rcs[d] = server.xend.domain.getRestartCount(d)
- server.xend.domain.shutdown(d, mode)
+ if serverType == SERVER_XEN_API:
+ if mode == 'halt':
+ server.xenapi.VM.clean_shutdown(d)
+ if mode == 'reboot':
+ server.xenapi.VM.clean_reboot(d)
+ if mode == 'poweroff':
+ server.xenapi.VM.clean_shutdown(d)
+ else:
+ rcs[d] = server.xend.domain.getRestartCount(d)
+ server.xend.domain.shutdown(d, mode)
if wait:
if mode == 'reboot':
@@ -103,9 +120,13 @@ def shutdown_mode(opts):
return 'poweroff'
def main_all(opts, args):
- doms = server.xend.domains(0)
- dom0_name = sxp.child_value(server.xend.domain(0), 'name')
- doms.remove(dom0_name)
+ if serverType == SERVER_XEN_API:
+ doms = [dom for dom in server.xenapi.VM.get_all()
+ if not server.xenapi.VM.get_is_control_domain(dom)]
+ else:
+ doms = server.xend.domains(0)
+ dom0_name = sxp.child_value(server.xend.domain(0), 'name')
+ doms.remove(dom0_name)
mode = shutdown_mode(opts)
shutdown(opts, doms, mode, opts.vals.wait)
@@ -113,6 +134,8 @@ def main_dom(opts, args):
if len(args) == 0: opts.err('No domain parameter given')
if len(args) > 1: opts.err('No multiple domain parameters allowed')
dom = args[0]
+ if serverType == SERVER_XEN_API:
+ dom = get_single_vm(dom)
mode = shutdown_mode(opts)
shutdown(opts, [ dom ], mode, opts.vals.wait)
diff --git a/tools/python/xen/xm/xenapi_create.py b/tools/python/xen/xm/xenapi_create.py
new file mode 100644
index 0000000000..52d91e101b
--- /dev/null
+++ b/tools/python/xen/xm/xenapi_create.py
@@ -0,0 +1,636 @@
+#!/usr/bin/python
+#============================================================================
+# 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) 2007 Tom Wilkie <tom.wilkie@gmail.com>
+#============================================================================
+"""Domain creation using new XenAPI
+"""
+
+from xen.xm.main import server, get_default_SR
+from xml.dom.minidom import parse, getDOMImplementation
+from xml.dom.ext import PrettyPrint
+from xml.parsers.xmlproc import xmlproc, xmlval, xmldtd
+from xen.xend import sxp
+from xen.xend.XendAPIConstants import XEN_API_ON_NORMAL_EXIT, \
+ XEN_API_ON_CRASH_BEHAVIOUR
+
+
+import sys
+import os
+import traceback
+
+def log(_, msg):
+ #print "> " + msg
+ pass
+
+DEBUG = 0
+
+def get_name_label(node):
+ name_node = node.getElementsByTagName("name")[0]
+ label_node = name_node.getElementsByTagName("label")[0]
+ return " ".join([child.nodeValue for child in label_node.childNodes])
+
+def get_name_description(node):
+ name_node = node.getElementsByTagName("name")[0]
+ description_node = name_node.getElementsByTagName("description")[0]
+ return " ".join([child.nodeValue for child in description_node.childNodes])
+
+def get_text_in_child_node(node, child):
+ tag_node = node.getElementsByTagName(child)[0]
+ return tag_node.nodeValue
+
+def get_child_node_attribute(node, child, attribute):
+ tag_node = node.getElementsByTagName(child)[0]
+ return tag_node.attributes[attribute].value
+
+def get_child_nodes_as_dict(node, child_name,
+ key_attribute_name,
+ value_attribute_name):
+ return dict([(child.attributes[key_attribute_name].value,
+ child.attributes[value_attribute_name].value)
+ for child in node.getElementsByTagName(child_name)])
+
+def try_quietly(fn, *args):
+ try:
+ return fn(*args)
+ except:
+ return None
+
+class xenapi_create:
+
+ def __init__(self):
+ self.DEFAULT_STORAGE_REPOSITORY = get_default_SR()
+
+ self.dtd = "/usr/lib/python/xen/xm/create.dtd"
+
+ def create(self, filename=None, document=None):
+ """
+ Create a domain from an XML file or DOM tree
+ """
+ if filename is not None:
+ self.check_dtd(file)
+ document = parse(file)
+ elif document is not None:
+ self.check_dom_against_dtd(document)
+
+ self.check_doc(document)
+
+ vdis = document.getElementsByTagName("vdi")
+ vdi_refs_dict = self.create_vdis(vdis)
+
+ try:
+ vms = document.getElementsByTagName("vm")
+ return self.create_vms(vms, vdi_refs_dict)
+ except Exception, exn:
+ try_quietly(self.cleanup_vdis(vdi_refs_dict))
+ raise exn
+
+ # Methods to check xml file
+ # try to use dtd to check where possible
+ def check_dtd(self, file):
+ """
+ Check file against DTD.
+ Use this if possible as it gives nice
+ error messages
+ """
+ dtd = xmldtd.load_dtd(self.dtd)
+ parser = xmlproc.XMLProcessor()
+ parser.set_application(xmlval.ValidatingApp(dtd, parser))
+ parser.dtd = dtd
+ parser.ent = dtd
+ parser.parse_resource(file)
+
+ def check_dom_against_dtd(self, dom):
+ """
+ Check DOM again DTD.
+ Doesn't give as nice error messages.
+ (no location info)
+ """
+ dtd = xmldtd.load_dtd(self.dtd)
+ app = xmlval.ValidatingApp(dtd, self)
+ app.set_locator(self)
+ self.dom2sax(dom, app)
+
+ # Get errors back from ValidatingApp
+ def report_error(self, number, args=None):
+ self.errors = xmlproc.errors.english
+ try:
+ msg = self.errors[number]
+ if args != None:
+ msg = msg % args
+ except KeyError:
+ msg = self.errors[4002] % number # Unknown err msg :-)
+ print msg
+ sys.exit(-1)
+
+ # Here for compatibility with ValidatingApp
+ def get_line(self):
+ return -1
+
+ def get_column(self):
+ return -1
+
+ def dom2sax(self, dom, app):
+ """
+ Take a dom tree and tarverse it,
+ issuing SAX calls to app.
+ """
+ for child in dom.childNodes:
+ if child.nodeType == child.TEXT_NODE:
+ data = child.nodeValue
+ app.handle_data(data, 0, len(data))
+ else:
+ app.handle_start_tag(
+ child.nodeName,
+ self.attrs_to_dict(child.attributes))
+ self.dom2sax(child, app)
+ app.handle_end_tag(child.nodeName)
+
+ def attrs_to_dict(self, attrs):
+ return dict(attrs.items())
+
+ #
+ # Checks which cannot be done with dtd
+ #
+ def check_doc(self, doc):
+ vms = doc.getElementsByTagName("vm")
+ self.check_vms(vms)
+
+ def check_vms(self, vms):
+ map(self.check_vm, vms)
+
+ def check_vm(self, vm):
+ vifs = vm.getElementsByTagName("vif")
+ self.check_vifs(vifs)
+
+ def check_vifs(self, vifs):
+ map(self.check_vif, vifs)
+
+ def check_vif(self, vif):
+ """
+ Check that the vif has
+ either a bridge or network
+ name but not both
+ """
+ if "bridge" in vif.attributes.keys() \
+ and "network" in vif.attributes.keys():
+ raise "You cannot specify both a bridge and\
+ a network name."
+
+ # Cleanup methods here
+ def cleanup_vdis(self, vdi_refs_dict):
+ map(self.cleanup_vdi, vdi_refs_dict.values())
+
+ def cleanup_vdi(self, vdi_ref):
+ server.xenapi.VDI.destroy(vdi_ref)
+
+ def cleanup_vms(self, vm_refs):
+ map(self.cleanup_vm, vm_refs)
+
+ def cleanup_vm(self, vm_ref):
+ server.xenapi.VM.destroy(vm_ref)
+
+ # Create methods here
+ def create_vdis(self, vdis):
+ log(DEBUG, "create_vdis")
+ return dict(map(self.create_vdi, vdis))
+
+ def create_vdi(self, vdi):
+ log(DEBUG, "create_vdi")
+
+ vdi_record = {
+ "name_label": get_name_label(vdi),
+ "name_description": get_name_description(vdi),
+ "SR": self.DEFAULT_STORAGE_REPOSITORY,
+ "virtual_size": vdi.attributes["size"].value,
+ "type": vdi.attributes["type"].value,
+ "shareable": vdi.attributes["shareable"].value,
+ "read_only": vdi.attributes["read_only"].value,
+ "other_config": {"location":
+ vdi.attributes["src"].value}
+ }
+
+ key = vdi.attributes["name"].value
+ value = server.xenapi.VDI.create(vdi_record)
+
+ return (key, value)
+
+ def create_vms(self, vms, vdis):
+ log(DEBUG, "create_vms")
+ return map(lambda vm: self.create_vm(vm, vdis), vms)
+
+ def create_vm(self, vm, vdis):
+ log(DEBUG, "create_vm")
+
+ vm_record = {
+ "name_label":
+ get_name_label(vm),
+ "name_description":
+ get_name_description(vm),
+ "user_version":
+ get_text_in_child_node(vm, "version"),
+ "is_a_template":
+ vm.attributes["is_a_template"].value,
+ "auto_power_on":
+ vm.attributes["auto_power_on"].value,
+ "memory_static_max":
+ get_child_node_attribute(vm, "memory", "static_max"),
+ "memory_static_min":
+ get_child_node_attribute(vm, "memory", "static_min"),
+ "memory_dynamic_max":
+ get_child_node_attribute(vm, "memory", "dynamic_max"),
+ "memory_dynamic_min":
+ get_child_node_attribute(vm, "memory", "dynamic_min"),
+ "vcpus_params":
+ get_child_nodes_as_dict(vm, "vcpu_param", "key", "value"),
+ "vcpus_max":
+ vm.attributes["vcpus_max"].value,
+ "vcpus_at_startup":
+ vm.attributes["vcpus_at_startup"].value,
+ "actions_after_shutdown":
+ vm.attributes["actions_after_shutdown"].value,
+ "actions_after_reboot":
+ vm.attributes["actions_after_reboot"].value,
+ "actions_after_crash":
+ vm.attributes["actions_after_crash"].value,
+ "platform_std_VGA":
+ vm.attributes["platform_std_VGA"].value,
+ "platform_serial":
+ vm.attributes["platform_serial"].value,
+ "platform_localtime":
+ vm.attributes["platform_localtime"].value,
+ "platform_clock_offet":
+ vm.attributes["platform_clock_offet"].value,
+ "platform_enable_audio":
+ vm.attributes["platform_enable_audio"].value,
+ "PCI_bus":
+ vm.attributes["platform_enable_audio"].value,
+ "other_config":
+ get_child_nodes_as_dict(vm, "other_config", "key", "value")
+ }
+
+ if len(vm.getElementsByTagName("pv")) > 0:
+ vm_record.update({
+ "PV_bootloader":
+ get_child_node_attribute(vm, "pv", "bootloader"),
+ "PV_kernel":
+ get_child_node_attribute(vm, "pv", "kernel"),
+ "PV_ramdisk":
+ get_child_node_attribute(vm, "pv", "ramdisk"),
+ "PV_args":
+ get_child_node_attribute(vm, "pv", "args"),
+ "PV_bootloader_args":
+ get_child_node_attribute(vm, "pv", "bootloader_args")
+ })
+ else:
+ hvm = vm.getElementsByTagName("hvm")[0]
+ vm_record.update({
+ "HVM_boot_policy":
+ get_child_node_attribute(vm, "hvm", "boot_policy"),
+ "HVM_boot_params":
+ get_child_nodes_as_dict(hvm, "boot_params", "key", "value")
+ })
+ try:
+ vm_ref = server.xenapi.VM.create(vm_record)
+ except:
+ traceback.print_exc()
+ sys.exit(-1)
+
+ # Now create vbds
+
+ vbds = vm.getElementsByTagName("vbd")
+
+ self.create_vbds(vm_ref, vbds, vdis)
+
+ # Now create vifs
+
+ vifs = vm.getElementsByTagName("vif")
+
+ self.create_vifs(vm_ref, vifs)
+
+ return vm_ref
+
+ def create_vbds(self, vm_ref, vbds, vdis):
+ log(DEBUG, "create_vbds")
+ return map(lambda vbd: self.create_vbd(vm_ref, vbd, vdis), vbds)
+
+ def create_vbd(self, vm_ref, vbd, vdis):
+ log(DEBUG, "create_vbd")
+
+ vbd_record = {
+ "VM":
+ vm_ref,
+ "VDI":
+ vdis[vbd.attributes["vdi"].value],
+ "device":
+ vbd.attributes["device"].value,
+ "bootable":
+ vbd.attributes["bootable"].value,
+ "mode":
+ vbd.attributes["mode"].value,
+ "type":
+ vbd.attributes["type"].value,
+ "qos_algorithm_type":
+ vbd.attributes["qos_algorithm_type"].value,
+ "qos_algorithm_params":
+ get_child_nodes_as_dict(vbd,
+ "qos_algorithm_param", "key", "value")
+ }
+
+ return server.xenapi.VBD.create(vbd_record)
+
+ def create_vifs(self, vm_ref, vifs):
+ log(DEBUG, "create_vifs")
+ return map(lambda vif: self.create_vif(vm_ref, vif), vifs)
+
+ def create_vif(self, vm_ref, vif):
+ log(DEBUG, "create_vif")
+
+ if "bridge" in vif.attributes.keys():
+ raise "Not allowed to add by bridge just yet"
+ elif "network" in vif.attributes.keys():
+ network = [network_ref
+ for network_ref in server.xenapi.network.get_all()
+ if server.xenapi.network.get_name_label(network_ref)
+ == vif.attributes["network"].value][0]
+ else:
+ network = self._get_network_ref()
+
+ vif_record = {
+ "device":
+ vif.attributes["device"].value,
+ "network":
+ network,
+ "VM":
+ vm_ref,
+ "MAC":
+ vif.attributes["mac"].value,
+ "MTU":
+ vif.attributes["mtu"].value,
+ "qos_algorithm_type":
+ vif.attributes["qos_algorithm_type"].value,
+ "qos_algorithm_params":
+ get_child_nodes_as_dict(vif,
+ "qos_algorithm_param", "key", "value")
+ }
+
+ return server.xenapi.VIF.create(vif_record)
+
+ _network_refs = []
+
+ def _get_network_ref(self):
+ try:
+ return self._network_refs.pop(0)
+ except IndexError:
+ self._network_refs = server.xenapi.network.get_all()
+ return self._network_refs.pop(0)
+
+def get_child_by_name(exp, childname, default = None):
+ try:
+ return [child for child in sxp.children(exp)
+ if child[0] == childname][0][1]
+ except:
+ return default
+
+# Convert old sxp into new xml
+
+class sxp2xml:
+
+ def convert_sxp_to_xml(self, config, transient=False):
+
+ devices = [child for child in sxp.children(config)
+ if len(child) > 0 and child[0] == "device"]
+
+ vbds_sxp = map(lambda x: x[1], [device for device in devices
+ if device[1][0] == "vbd"])
+
+ vifs_sxp = map(lambda x: x[1], [device for device in devices
+ if device[1][0] == "vif"])
+ # Create XML Document
+
+ impl = getDOMImplementation()
+
+ document = impl.createDocument(None, "xm", None)
+
+ # Lets make the VM tag..
+
+ vm = document.createElement("vm")
+
+ # Some string compatibility
+
+ actions_after_shutdown \
+ = get_child_by_name(config, "on_poweroff", "destroy")
+ actions_after_reboot \
+ = get_child_by_name(config, "on_reboot", "restart")
+ actions_after_crash \
+ = get_child_by_name(config, "on_crash", "restart")
+
+ def conv_chk(val, vals):
+ val.replace("-", "_")
+ if val not in vals:
+ raise "Invalid value: " + val
+ else:
+ return val
+
+ actions_after_shutdown = conv_chk(actions_after_shutdown,\
+ XEN_API_ON_NORMAL_EXIT)
+ actions_after_reboot = conv_chk(actions_after_reboot, \
+ XEN_API_ON_NORMAL_EXIT)
+ actions_after_crash = conv_chk(actions_after_crash, \
+ XEN_API_ON_CRASH_BEHAVIOUR)
+ # Flesh out tag attributes
+
+ vm.attributes["is_a_template"] = "false"
+ vm.attributes["auto_power_on"] = "false"
+ vm.attributes["actions_after_shutdown"] \
+ = actions_after_shutdown
+ vm.attributes["actions_after_reboot"] \
+ = actions_after_reboot
+ vm.attributes["actions_after_crash"] \
+ = actions_after_crash
+ vm.attributes["platform_std_VGA"] = "false"
+ vm.attributes["platform_serial"] = ""
+ vm.attributes["platform_localtime"] = ""
+ vm.attributes["platform_clock_offet"] = ""
+ vm.attributes["platform_enable_audio"] = ""
+ vm.attributes["PCI_bus"] = ""
+
+ vm.attributes["vcpus_max"] \
+ = str(get_child_by_name(config, "vcpus", 1))
+ vm.attributes["vcpus_at_startup"] \
+ = str(get_child_by_name(config, "vcpus", 1))
+
+ # Make the name tag
+
+ vm.appendChild(self.make_name_tag(
+ get_child_by_name(config, "name"), document))
+
+ # Make version tag
+
+ version = document.createElement("version")
+ version.appendChild(document.createTextNode("1.0"))
+ vm.appendChild(version)
+
+ # Make pv or hvm tag
+
+ image = get_child_by_name(config, "image")
+
+ if image[0] == "linux":
+ pv = document.createElement("pv")
+ pv.attributes["kernel"] \
+ = get_child_by_name(image, "kernel", "")
+ pv.attributes["bootloader"] = ""
+ pv.attributes["ramdisk"] \
+ = get_child_by_name(image, "ramdisk", "")
+ pv.attributes["args"] \
+ = "root=" + get_child_by_name(image, "root", "") \
+ + " " + get_child_by_name(image, "args", "")
+ pv.attributes["bootloader_args"] = ""
+
+ vm.appendChild(pv)
+ elif image[0] == "hvm":
+ hvm = document.createElement("hvm")
+ hvm.attributes["boot_policy"] = ""
+
+ vm.appendChild(hvm)
+
+ # Make memory tag
+
+ memory = document.createElement("memory")
+
+ memory_str = str(int(
+ get_child_by_name(config, "memory"))*1024*1024)
+
+ memory.attributes["static_min"] = str(0)
+ memory.attributes["static_max"] = memory_str
+ memory.attributes["dynamic_min"] = memory_str
+ memory.attributes["dynamic_max"] = memory_str
+
+ if get_child_by_name(config, "maxmem"):
+ memory.attributes["static_max"] = \
+ str(int(get_child_by_name(config, "maxmem")*1024*1024))
+
+ vm.appendChild(memory)
+
+ # And now the vbds
+
+ vbds = map(lambda vbd: self.extract_vbd(vbd, document), vbds_sxp)
+
+ map(vm.appendChild, vbds)
+
+ # And now the vifs
+
+ vifs = map(lambda vif: self.extract_vif(vif, document), vifs_sxp)
+
+ map(vm.appendChild, vifs)
+
+ # transient?
+
+ if transient:
+ other_config = document.createElement("other_config")
+ other_config.attributes["key"] = "transient"
+ other_config.attributes["value"] = "True"
+ vm.appendChild(other_config)
+
+ # Add it to doc_root
+
+ document.documentElement.appendChild(vm)
+
+ # We want to pull out vdis
+
+ vdis = map(lambda vdb: self.extract_vdi(vdb, document), vbds_sxp)
+
+ map(document.documentElement.appendChild, vdis)
+
+ return document
+
+ def make_name_tag(self, label_text, document):
+ name = document.createElement("name")
+
+ label = document.createElement("label")
+ label.appendChild(document.createTextNode(str(label_text)))
+ name.appendChild(label)
+
+ description = document.createElement("description")
+ description.appendChild(document.createTextNode(" "))
+ name.appendChild(description)
+
+ return name
+
+ def extract_vbd(self, vbd_sxp, document):
+ src = get_child_by_name(vbd_sxp, "uname")
+ name = str(src.__hash__())
+
+ vbd = document.createElement("vbd")
+
+ vbd.attributes["name"] = "vdb" + name
+ vbd.attributes["vdi"] = "vdi" + name
+ vbd.attributes["mode"] \
+ = get_child_by_name(vbd_sxp, "mode") != "w" \
+ and "RO" or "RW"
+ vbd.attributes["device"] \
+ = get_child_by_name(vbd_sxp, "dev")
+ vbd.attributes["bootable"] = "1"
+ vbd.attributes["type"] = "disk"
+ vbd.attributes["qos_algorithm_type"] = ""
+
+ return vbd
+
+ def extract_vdi(self, vbd_sxp, document):
+ src = get_child_by_name(vbd_sxp, "uname")
+ name = "vdi" + str(src.__hash__())
+ path = src[src.find(":")+1:]
+
+ vdi = document.createElement("vdi")
+
+ vdi.attributes["src"] = src
+ vdi.attributes["read_only"] \
+ = (get_child_by_name(vbd_sxp, "mode") != "w") \
+ and "true" or "false"
+ vdi.attributes["size"] \
+ = str(os.path.getsize(path))
+ vdi.attributes["type"] = "system"
+ vdi.attributes["shareable"] = "false"
+ vdi.attributes["name"] = name
+
+ vdi.appendChild(self.make_name_tag(name, document))
+
+ return vdi
+
+ def extract_vif(self, vif_sxp, document):
+
+ vif = document.createElement("vif")
+
+ dev = get_child_by_name(vif_sxp, "vifname", "eth0")
+
+ vif.attributes["name"] \
+ = "vif" + str(dev.__hash__())
+ vif.attributes["mac"] \
+ = get_child_by_name(vif_sxp, "mac", "")
+ vif.attributes["mtu"] \
+ = get_child_by_name(vif_sxp, "mtu", "")
+ vif.attributes["device"] = dev
+ vif.attributes["qos_algorithm_type"] = ""
+
+ if get_child_by_name(vif_sxp, "bridge") is not None:
+ vif.attributes["bridge"] \
+ = get_child_by_name(vif_sxp, "bridge")
+
+ return vif
+
+
+
+
+
diff --git a/tools/xcutils/Makefile b/tools/xcutils/Makefile
index 6022505577..f8ac92f7d9 100644
--- a/tools/xcutils/Makefile
+++ b/tools/xcutils/Makefile
@@ -13,7 +13,7 @@ include $(XEN_ROOT)/tools/Rules.mk
PROGRAMS_INSTALL_DIR = /usr/$(LIBDIR)/xen/bin
-INCLUDES += -I $(XEN_LIBXC)
+INCLUDES += -I $(XEN_LIBXC) -I $(XEN_XENSTORE)
CFLAGS += -Werror -fno-strict-aliasing
CFLAGS += $(INCLUDES)
@@ -22,9 +22,9 @@ CFLAGS += $(INCLUDES)
CFLAGS += -Wp,-MD,.$(@F).d
PROG_DEP = .*.d
-PROGRAMS = xc_restore xc_save readnotes
+PROGRAMS = xc_restore xc_save readnotes
-LDLIBS = -L$(XEN_LIBXC) -lxenguest -lxenctrl
+LDLIBS = -L$(XEN_LIBXC) -L$(XEN_XENSTORE) -lxenguest -lxenctrl -lxenstore
.PHONY: all
all: build
diff --git a/tools/xcutils/xc_save.c b/tools/xcutils/xc_save.c
index 0c9530da4d..2285af4b97 100644
--- a/tools/xcutils/xc_save.c
+++ b/tools/xcutils/xc_save.c
@@ -12,7 +12,13 @@
#include <stdint.h>
#include <string.h>
#include <stdio.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <xs.h>
#include <xenctrl.h>
#include <xenguest.h>
@@ -31,6 +37,123 @@ static int suspend(int domid)
!strncmp(ans, "done\n", 5));
}
+/* For HVM guests, there are two sources of dirty pages: the Xen shadow
+ * log-dirty bitmap, which we get with a hypercall, and qemu's version.
+ * The protocol for getting page-dirtying data from qemu uses a
+ * double-buffered shared memory interface directly between xc_save and
+ * qemu-dm.
+ *
+ * xc_save calculates the size of the bitmaps and notifies qemu-dm
+ * through the store that it wants to share the bitmaps. qemu-dm then
+ * starts filling in the 'active' buffer.
+ *
+ * To change the buffers over, xc_save writes the other buffer number to
+ * the store and waits for qemu to acknowledge that it is now writing to
+ * the new active buffer. xc_save can then process and clear the old
+ * active buffer. */
+
+static char *qemu_active_path;
+static char *qemu_next_active_path;
+static struct xs_handle *xs;
+
+/* Get qemu to change buffers. */
+static void qemu_flip_buffer(int domid, int next_active)
+{
+ char digit = '0' + next_active;
+ unsigned int len;
+ char *active_str, **watch;
+ struct timeval tv;
+ fd_set fdset;
+
+ /* Tell qemu that we want it to start writing log-dirty bits to the
+ * other buffer */
+ if (!xs_write(xs, XBT_NULL, qemu_next_active_path, &digit, 1)) {
+ errx(1, "can't write next-active to store path (%s)\n",
+ qemu_next_active_path);
+ exit(1);
+ }
+
+ /* Wait a while for qemu to signal that it has switched to the new
+ * active buffer */
+ read_again:
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ FD_ZERO(&fdset);
+ FD_SET(xs_fileno(xs), &fdset);
+ if ((select(xs_fileno(xs) + 1, &fdset, NULL, NULL, &tv)) != 1) {
+ errx(1, "timed out waiting for qemu to switch buffers\n");
+ exit(1);
+ }
+ watch = xs_read_watch(xs, &len);
+ free(watch);
+
+ active_str = xs_read(xs, XBT_NULL, qemu_active_path, &len);
+ if (active_str == NULL || active_str[0] - '0' != next_active)
+ /* Watch fired but value is not yet right */
+ goto read_again;
+}
+
+static void * init_qemu_maps(int domid, unsigned int bitmap_size)
+{
+ key_t key;
+ char key_ascii[17] = {0,};
+ int shmid = -1;
+ void *seg;
+ char *path, *p;
+
+ /* Make a shared-memory segment */
+ while (shmid == -1)
+ {
+ key = rand(); /* No security, just a sequence of numbers */
+ shmid = shmget(key, 2 * bitmap_size,
+ IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR);
+ if (shmid == -1 && errno != EEXIST)
+ errx(1, "can't get shmem to talk to qemu-dm");
+ }
+
+ /* Map it into our address space */
+ seg = shmat(shmid, NULL, 0);
+ if (seg == (void *) -1)
+ errx(1, "can't map shmem to talk to qemu-dm");
+ memset(seg, 0, 2 * bitmap_size);
+
+ /* Write the size of it into the first 32 bits */
+ *(uint32_t *)seg = bitmap_size;
+
+ /* Tell qemu about it */
+ if ((xs = xs_daemon_open()) == NULL)
+ errx(1, "Couldn't contact xenstore");
+ if (!(path = xs_get_domain_path(xs, domid)))
+ errx(1, "can't get domain path in store");
+ if (!(path = realloc(path, strlen(path)
+ + strlen("/logdirty/next-active") + 1)))
+ errx(1, "no memory for constructing xenstore path");
+ strcat(path, "/logdirty/");
+ p = path + strlen(path);
+
+ strcpy(p, "key");
+ snprintf(key_ascii, 17, "%16.16llx", (unsigned long long) key);
+ if (!xs_write(xs, XBT_NULL, path, key_ascii, 16))
+ errx(1, "can't write key (%s) to store path (%s)\n", key_ascii, path);
+
+ /* Watch for qemu's indication of the active buffer, and request it
+ * to start writing to buffer 0 */
+ strcpy(p, "active");
+ if (!xs_watch(xs, path, "qemu-active-buffer"))
+ errx(1, "can't set watch in store (%s)\n", path);
+ if (!(qemu_active_path = strdup(path)))
+ errx(1, "no memory for copying xenstore path");
+
+ strcpy(p, "next-active");
+ if (!(qemu_next_active_path = strdup(path)))
+ errx(1, "no memory for copying xenstore path");
+
+ qemu_flip_buffer(domid, 0);
+
+ free(path);
+ return seg;
+}
+
int
main(int argc, char **argv)
@@ -52,9 +175,11 @@ main(int argc, char **argv)
flags = atoi(argv[5]);
if (flags & XCFLAGS_HVM)
- ret = xc_hvm_save(xc_fd, io_fd, domid, maxit, max_f, flags, &suspend);
+ ret = xc_hvm_save(xc_fd, io_fd, domid, maxit, max_f, flags,
+ &suspend, &init_qemu_maps, &qemu_flip_buffer);
else
- ret = xc_linux_save(xc_fd, io_fd, domid, maxit, max_f, flags, &suspend);
+ ret = xc_linux_save(xc_fd, io_fd, domid, maxit, max_f, flags,
+ &suspend);
xc_interface_close(xc_fd);
diff --git a/tools/xm-test/tests/block-create/07_block_attach_baddevice_neg.py b/tools/xm-test/tests/block-create/07_block_attach_baddevice_neg.py
index 3e9f0f2514..5d435e27c6 100644
--- a/tools/xm-test/tests/block-create/07_block_attach_baddevice_neg.py
+++ b/tools/xm-test/tests/block-create/07_block_attach_baddevice_neg.py
@@ -32,10 +32,10 @@ except ConsoleError, e:
status, output = traceCommand("xm block-attach %s phy:NOT-EXIST xvda1 w" % domain.getName())
eyecatcher = "Error"
-where = output.find(eyecatcher)
+where = re.compile(eyecatcher, re.IGNORECASE).search(output)
if status == 0:
FAIL("xm block-attach returned bad status, expected non 0, status is: %i" % status )
-elif where == -1:
+elif where is None:
FAIL("xm block-attach returned bad output, expected Error, output is: %s" % output )
try:
diff --git a/tools/xm-test/tests/block-create/08_block_attach_bad_filedevice_neg.py b/tools/xm-test/tests/block-create/08_block_attach_bad_filedevice_neg.py
index 802e101147..2fa482414a 100644
--- a/tools/xm-test/tests/block-create/08_block_attach_bad_filedevice_neg.py
+++ b/tools/xm-test/tests/block-create/08_block_attach_bad_filedevice_neg.py
@@ -31,10 +31,10 @@ except ConsoleError, e:
status, output = traceCommand("xm block-attach %s file:/dev/NOT-EXIST xvda1 w" % domain.getName())
eyecatcher = "Error"
-where = output.find(eyecatcher)
+where = re.compile(eyecatcher, re.IGNORECASE).search(output)
if status == 0:
FAIL("xm block-attach returned bad status, expected non 0, status is: %i" % status )
-elif where == -1:
+elif where is None:
FAIL("xm block-attach returned bad output, expected Error, output is: %s" % output )
try:
diff --git a/tools/xm-test/tests/destroy/01_destroy_basic_pos.py b/tools/xm-test/tests/destroy/01_destroy_basic_pos.py
index 3d007b12a4..02e31d6aa8 100644
--- a/tools/xm-test/tests/destroy/01_destroy_basic_pos.py
+++ b/tools/xm-test/tests/destroy/01_destroy_basic_pos.py
@@ -37,4 +37,4 @@ if not re.search("proc", run["output"]):
# destroy domain - positive test
status, output = traceCommand("xm destroy %s" % domain.getName())
if status != 0:
- FAIL("xm destroy returned invalud %i != 0" % status)
+ FAIL("xm destroy returned invalid %i != 0" % status)
diff --git a/tools/xm-test/tests/network-attach/network_utils.py b/tools/xm-test/tests/network-attach/network_utils.py
index 084b5ebd90..93fe72a811 100644
--- a/tools/xm-test/tests/network-attach/network_utils.py
+++ b/tools/xm-test/tests/network-attach/network_utils.py
@@ -12,6 +12,18 @@ def count_eth(console):
FAIL(str(e))
return len(run['output'].splitlines())
+def get_state(domain_name, number):
+ s, o = traceCommand("xm network-list %s | awk '/^%d/ {print $5}'" %
+ (domain_name, number))
+ print o
+
+ if s != 0:
+ FAIL("network-list failed")
+ if o == "":
+ return 0
+ else:
+ return int(o)
+
def network_attach(domain_name, console):
eths_before = count_eth(console)
status, output = traceCommand("xm network-attach %s" % domain_name)
@@ -30,6 +42,13 @@ def network_detach(domain_name, console, num=0):
if status != 0:
return -1, "xm network-detach returned invalid %i != 0" % status
+ for i in range(10):
+ if get_state(domain_name, num) == 0:
+ break
+ time.sleep(1)
+ else:
+ FAIL("network-detach failed: device did not disappear")
+
eths_after = count_eth(console)
if eths_after != (eths_before-1):
return -2, "Network device was not actually disconnected from domU"
diff --git a/tools/xm-test/tests/vtpm/09_vtpm-xapi.py b/tools/xm-test/tests/vtpm/09_vtpm-xapi.py
index 6a17c51045..15775801f6 100644
--- a/tools/xm-test/tests/vtpm/09_vtpm-xapi.py
+++ b/tools/xm-test/tests/vtpm/09_vtpm-xapi.py
@@ -91,7 +91,7 @@ if vtpm_uuid not in vm_vtpms:
try:
console = domain.start()
except DomainError, e:
- FAIL("Unable to create domain (%s)" % domName)
+ FAIL("Unable to create domain (%s)")
try:
console.sendInput("input")
@@ -113,7 +113,7 @@ if not re.search("PCR-00:",run["output"]):
FAIL("1. Virtual TPM is not working correctly on /dev/vtpm on backend side: \n%s" % run["output"])
try:
- rc = session.xenapi.VTPM.destroy(vtpm_uuid)
+ session.xenapi.VTPM.destroy(vtpm_uuid)
#Should never get here
FAIL("Could destroy vTPM while VM is running")
except:
@@ -124,7 +124,7 @@ if rc:
FAIL("Could not suspend VM")
try:
- rc = session.xenapi.VTPM.destroy(vtpm_uuid)
+ session.xenapi.VTPM.destroy(vtpm_uuid)
#May not throw an exception in 'suspend' state
except:
pass
@@ -150,8 +150,9 @@ if not re.search("PCR-00:",run["output"]):
domain.stop()
-rc = session.xenapi.VTPM.destroy(vtpm_uuid)
-if not rc:
+try:
+ session.xenapi.VTPM.destroy(vtpm_uuid)
+except:
FAIL("Could NOT destroy vTPM while domain is halted.")
domain.destroy()
diff --git a/tools/xm-test/tests/vtpm/vtpm_utils.py b/tools/xm-test/tests/vtpm/vtpm_utils.py
index 0af46574c9..da65aab5fb 100644
--- a/tools/xm-test/tests/vtpm/vtpm_utils.py
+++ b/tools/xm-test/tests/vtpm/vtpm_utils.py
@@ -8,7 +8,8 @@ from XmTestLib import *
if ENABLE_HVM_SUPPORT:
SKIP("vtpm tests not supported for HVM domains")
-status, output = traceCommand("ps aux | grep vtpm_manager | grep -v grep")
+status, output = traceCommand("COLUMNS=200 ; "
+ "ps aux | grep vtpm_manager | grep -v grep")
if output == "":
SKIP("virtual TPM manager must be started to run this test; might "
"need /dev/tpm0")