diff options
author | Hollis Blanchard <hollisb@us.ibm.com> | 2007-03-21 18:08:31 -0500 |
---|---|---|
committer | Hollis Blanchard <hollisb@us.ibm.com> | 2007-03-21 18:08:31 -0500 |
commit | 001e8c5cd8f60e7cafbfed9869862db46b5ed473 (patch) | |
tree | 7ac30f8387c3f66c1860ea9421e0a681bb4b4b7f /tools | |
parent | a7706a8de0119f07b6f7e014a78fd07947af3787 (diff) | |
parent | 5b3327347f83a473755b00a76ff1176dc6cda301 (diff) | |
download | xen-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')
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") |