From 1f698f3f9f667540ee8256dc05dc41641b8859e7 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 20 Jun 2007 16:18:03 +0100 Subject: [PATCH 01/45] x86: introduce specialized clear_page() More than doubles performance of page clearing on not too old processors (SSE2 supported). Signed-off-by: Jan Beulich Signed-off-by: Keir Fraser --- xen/arch/x86/Makefile | 1 + xen/arch/x86/clear_page.S | 26 ++++++++++++++++++++++++++ xen/arch/x86/domain.c | 9 ++++++--- xen/arch/x86/x86_64/Makefile | 2 +- xen/arch/x86/x86_64/mm.c | 9 ++++++--- xen/include/asm-x86/page.h | 11 ++++++++--- 6 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 xen/arch/x86/clear_page.S diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index c7ccbda0d5..3899874714 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -10,6 +10,7 @@ subdir-$(x86_64) += x86_64 obj-y += apic.o obj-y += bitops.o +obj-y += clear_page.o obj-y += compat.o obj-y += delay.o obj-y += dmi_scan.o diff --git a/xen/arch/x86/clear_page.S b/xen/arch/x86/clear_page.S new file mode 100644 index 0000000000..d3e8bba915 --- /dev/null +++ b/xen/arch/x86/clear_page.S @@ -0,0 +1,26 @@ +#include +#include + +#ifdef __i386__ +#define ptr_reg %edx +#else +#define ptr_reg %rdi +#endif + +ENTRY(clear_page_sse2) +#ifdef __i386__ + mov 4(%esp), ptr_reg +#endif + mov $PAGE_SIZE/16, %ecx + xor %eax,%eax + +0: dec %ecx + movnti %eax, (ptr_reg) + movnti %eax, 4(ptr_reg) + movnti %eax, 8(ptr_reg) + movnti %eax, 12(ptr_reg) + lea 16(ptr_reg), ptr_reg + jnz 0b + + sfence + ret diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 79dc4baa37..bf83032a29 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -151,7 +151,8 @@ int setup_arg_xlat_area(struct vcpu *v, l4_pgentry_t *l4tab) pg = alloc_domheap_page(NULL); if ( !pg ) return -ENOMEM; - d->arch.mm_arg_xlat_l3 = clear_page(page_to_virt(pg)); + d->arch.mm_arg_xlat_l3 = page_to_virt(pg); + clear_page(d->arch.mm_arg_xlat_l3); } l4tab[l4_table_offset(COMPAT_ARG_XLAT_VIRT_BASE)] = @@ -444,7 +445,8 @@ int arch_domain_create(struct domain *d) if ( (pg = alloc_domheap_page(NULL)) == NULL ) goto fail; - d->arch.mm_perdomain_l2 = clear_page(page_to_virt(pg)); + d->arch.mm_perdomain_l2 = page_to_virt(pg); + clear_page(d->arch.mm_perdomain_l2); for ( i = 0; i < (1 << pdpt_order); i++ ) d->arch.mm_perdomain_l2[l2_table_offset(PERDOMAIN_VIRT_START)+i] = l2e_from_page(virt_to_page(d->arch.mm_perdomain_pt)+i, @@ -452,7 +454,8 @@ int arch_domain_create(struct domain *d) if ( (pg = alloc_domheap_page(NULL)) == NULL ) goto fail; - d->arch.mm_perdomain_l3 = clear_page(page_to_virt(pg)); + d->arch.mm_perdomain_l3 = page_to_virt(pg); + clear_page(d->arch.mm_perdomain_l3); d->arch.mm_perdomain_l3[l3_table_offset(PERDOMAIN_VIRT_START)] = l3e_from_page(virt_to_page(d->arch.mm_perdomain_l2), __PAGE_HYPERVISOR); diff --git a/xen/arch/x86/x86_64/Makefile b/xen/arch/x86/x86_64/Makefile index 98f20a43c6..f712ca66f3 100644 --- a/xen/arch/x86/x86_64/Makefile +++ b/xen/arch/x86/x86_64/Makefile @@ -1,12 +1,12 @@ subdir-y += compat obj-y += entry.o -obj-y += compat_kexec.o obj-y += gpr_switch.o obj-y += mm.o obj-y += traps.o obj-$(CONFIG_COMPAT) += compat.o +obj-$(CONFIG_COMPAT) += compat_kexec.o obj-$(CONFIG_COMPAT) += domain.o obj-$(CONFIG_COMPAT) += physdev.o obj-$(CONFIG_COMPAT) += platform_hypercall.o diff --git a/xen/arch/x86/x86_64/mm.c b/xen/arch/x86/x86_64/mm.c index 444432f136..f7f7a7b802 100644 --- a/xen/arch/x86/x86_64/mm.c +++ b/xen/arch/x86/x86_64/mm.c @@ -106,7 +106,8 @@ void __init paging_init(void) /* Create user-accessible L2 directory to map the MPT for guests. */ if ( (l2_pg = alloc_domheap_page(NULL)) == NULL ) goto nomem; - l3_ro_mpt = clear_page(page_to_virt(l2_pg)); + l3_ro_mpt = page_to_virt(l2_pg); + clear_page(l3_ro_mpt); l4e_write(&idle_pg_table[l4_table_offset(RO_MPT_VIRT_START)], l4e_from_page(l2_pg, __PAGE_HYPERVISOR | _PAGE_USER)); @@ -132,7 +133,8 @@ void __init paging_init(void) if ( (l2_pg = alloc_domheap_page(NULL)) == NULL ) goto nomem; va = RO_MPT_VIRT_START + (i << L2_PAGETABLE_SHIFT); - l2_ro_mpt = clear_page(page_to_virt(l2_pg)); + l2_ro_mpt = page_to_virt(l2_pg); + clear_page(l2_ro_mpt); l3e_write(&l3_ro_mpt[l3_table_offset(va)], l3e_from_page(l2_pg, __PAGE_HYPERVISOR | _PAGE_USER)); l2_ro_mpt += l2_table_offset(va); @@ -152,7 +154,8 @@ void __init paging_init(void) l3_ro_mpt = l4e_to_l3e(idle_pg_table[l4_table_offset(HIRO_COMPAT_MPT_VIRT_START)]); if ( (l2_pg = alloc_domheap_page(NULL)) == NULL ) goto nomem; - compat_idle_pg_table_l2 = l2_ro_mpt = clear_page(page_to_virt(l2_pg)); + compat_idle_pg_table_l2 = l2_ro_mpt = page_to_virt(l2_pg); + clear_page(l2_ro_mpt); l3e_write(&l3_ro_mpt[l3_table_offset(HIRO_COMPAT_MPT_VIRT_START)], l3e_from_page(l2_pg, __PAGE_HYPERVISOR)); l2_ro_mpt += l2_table_offset(HIRO_COMPAT_MPT_VIRT_START); diff --git a/xen/include/asm-x86/page.h b/xen/include/asm-x86/page.h index 681da219a3..4b4133214b 100644 --- a/xen/include/asm-x86/page.h +++ b/xen/include/asm-x86/page.h @@ -192,8 +192,9 @@ static inline l4_pgentry_t l4e_from_paddr(paddr_t pa, unsigned int flags) #define pgentry_ptr_to_slot(_p) \ (((unsigned long)(_p) & ~PAGE_MASK) / sizeof(*(_p))) -/* Page-table type. */ #ifndef __ASSEMBLY__ + +/* Page-table type. */ #if CONFIG_PAGING_LEVELS == 2 /* x86_32 default */ typedef struct { u32 pfn; } pagetable_t; @@ -214,9 +215,11 @@ typedef struct { u64 pfn; } pagetable_t; #define pagetable_from_page(pg) pagetable_from_pfn(page_to_mfn(pg)) #define pagetable_from_paddr(p) pagetable_from_pfn((p)>>PAGE_SHIFT) #define pagetable_null() pagetable_from_pfn(0) -#endif -#define clear_page(_p) memset((void *)(_p), 0, PAGE_SIZE) +void clear_page_sse2(void *); +#define clear_page(_p) (cpu_has_xmm2 ? \ + clear_page_sse2((void *)(_p)) : \ + (void)memset((void *)(_p), 0, PAGE_SIZE)) #define copy_page(_t,_f) memcpy((void *)(_t), (void *)(_f), PAGE_SIZE) #define mfn_valid(mfn) ((mfn) < max_page) @@ -245,6 +248,8 @@ typedef struct { u64 pfn; } pagetable_t; #define pfn_to_paddr(pfn) ((paddr_t)(pfn) << PAGE_SHIFT) #define paddr_to_pfn(pa) ((unsigned long)((pa) >> PAGE_SHIFT)) +#endif /* !defined(__ASSEMBLY__) */ + /* High table entries are reserved by the hypervisor. */ #if defined(CONFIG_X86_32) && !defined(CONFIG_X86_PAE) #define DOMAIN_ENTRIES_PER_L2_PAGETABLE \ From 084df3b9f77bdc13b470e9feafc463c96dc9fb85 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 20 Jun 2007 16:52:01 +0100 Subject: [PATCH 02/45] kernel command line extension In order to allow appending to the dom0 command line even with boot loaders that only allow editing the kernel (i.e. Xen in our case) command line, support a '--' separator option. Signed-off-by: Jan Beulich Signed-off-by: Keir Fraser --- xen/arch/x86/setup.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 23e216ac44..c630cb242f 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -405,7 +405,7 @@ void init_done(void) void __init __start_xen(unsigned long mbi_p) { char *memmap_type = NULL; - char __cmdline[] = "", *cmdline = __cmdline; + char __cmdline[] = "", *cmdline = __cmdline, *kextra; unsigned long _initrd_start = 0, _initrd_len = 0; unsigned int initrdidx = 1; char *_policy_start = NULL; @@ -426,6 +426,17 @@ void __init __start_xen(unsigned long mbi_p) /* Parse the command-line options. */ if ( (mbi->flags & MBI_CMDLINE) && (mbi->cmdline != 0) ) cmdline = __va(mbi->cmdline); + if ( (kextra = strstr(cmdline, " -- ")) != NULL ) + { + /* + * Options after ' -- ' separator belong to dom0. + * 1. Orphan dom0's options from Xen's command line. + * 2. Skip all but final leading space from dom0's options. + */ + *kextra = '\0'; + kextra += 3; + while ( kextra[1] == ' ' ) kextra++; + } cmdline_parse(cmdline); parse_video_info(); @@ -1009,18 +1020,27 @@ void __init __start_xen(unsigned long mbi_p) /* Grab the DOM0 command line. */ cmdline = (char *)(mod[0].string ? __va(mod[0].string) : NULL); - if ( cmdline != NULL ) + if ( (cmdline != NULL) || (kextra != NULL) ) { static char dom0_cmdline[MAX_GUEST_CMDLINE]; - /* Skip past the image name and copy to a local buffer. */ - while ( *cmdline == ' ' ) cmdline++; - if ( (cmdline = strchr(cmdline, ' ')) != NULL ) + dom0_cmdline[0] = '\0'; + + if ( cmdline != NULL ) { + /* Skip past the image name and copy to a local buffer. */ while ( *cmdline == ' ' ) cmdline++; - safe_strcpy(dom0_cmdline, cmdline); + if ( (cmdline = strchr(cmdline, ' ')) != NULL ) + { + while ( *cmdline == ' ' ) cmdline++; + safe_strcpy(dom0_cmdline, cmdline); + } } + if ( kextra != NULL ) + /* kextra always includes exactly one leading space. */ + safe_strcat(dom0_cmdline, kextra); + /* Append any extra parameters. */ if ( skip_ioapic_setup && !strstr(dom0_cmdline, "noapic") ) safe_strcat(dom0_cmdline, " noapic"); From 7000b6bdac03497819db86818058b43c47bad4dc Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 20 Jun 2007 16:58:21 +0100 Subject: [PATCH 03/45] tools: Create directory /var/lib/xen at install target. Signed-off-by: Keir Fraser --- tools/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/Makefile b/tools/Makefile index 7cf1bed341..9d55900d2c 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -43,6 +43,7 @@ install: check $(MAKE) ioemuinstall $(INSTALL_DIR) $(DESTDIR)/var/xen/dump $(INSTALL_DIR) $(DESTDIR)/var/log/xen + $(INSTALL_DIR) $(DESTDIR)/var/lib/xen .PHONY: clean clean: check_clean From a1f868f2a3bef3d349b679061da57b937ea24b1a Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 20 Jun 2007 17:05:48 +0100 Subject: [PATCH 04/45] x86: early exception enhancement In order to at least have some minimal debuging capabilities when Xen crashes really early, dump out registers and stack contents in a raw form. Signed-off-by: Jan Beulich Signed-off-by: Keir Fraser --- xen/arch/x86/boot/x86_32.S | 16 +++++++++++++++- xen/arch/x86/boot/x86_64.S | 15 +++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/xen/arch/x86/boot/x86_32.S b/xen/arch/x86/boot/x86_32.S index 1220f940a5..4119d6ee1f 100644 --- a/xen/arch/x86/boot/x86_32.S +++ b/xen/arch/x86/boot/x86_32.S @@ -36,15 +36,29 @@ /* This is the default interrupt handler. */ int_msg: - .asciz "Unknown interrupt\n" + .asciz "Unknown interrupt (cr2=%08x)\n" +hex_msg: + .asciz " %08x" ALIGN ignore_int: + pusha cld mov $(__HYPERVISOR_DS),%eax mov %eax,%ds mov %eax,%es + mov %cr2,%eax + push %eax pushl $int_msg call printk + add $8,%esp + mov %esp,%ebp +0: pushl (%ebp) + add $4,%ebp + pushl $hex_msg + call printk + add $8,%esp + test $0xffc,%ebp + jnz 0b 1: jmp 1b ENTRY(stack_start) diff --git a/xen/arch/x86/boot/x86_64.S b/xen/arch/x86/boot/x86_64.S index d3c11b8788..46c34c1702 100644 --- a/xen/arch/x86/boot/x86_64.S +++ b/xen/arch/x86/boot/x86_64.S @@ -56,12 +56,23 @@ /* This is the default interrupt handler. */ int_msg: - .asciz "Unknown interrupt\n" + .asciz "Unknown interrupt (cr2=%016lx)\n" +hex_msg: + .asciz " %016lx" ignore_int: - cld + SAVE_ALL + movq %cr2,%rsi leaq int_msg(%rip),%rdi xorl %eax,%eax call printk + movq %rsp,%rbp +0: movq (%rbp),%rsi + addq $8,%rbp + leaq hex_msg(%rip),%rdi + xorl %eax,%eax + call printk + testq $0xff8,%rbp + jnz 0b 1: jmp 1b From d40dbdf39f8dbfb89f2812c7a11db49d0e73c44f Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 20 Jun 2007 17:07:15 +0100 Subject: [PATCH 05/45] tools: Adjust tools' path calculation. I'm suggesting this change to make another tiny step towards the ability to run the tools e.g. out of the build tree (so that multiple different Xen versions can co-exist without the requirement to re-install the respective version with each boot). Signed-off-by: Jan Beulich --- tools/misc/xen-python-path | 9 +++++++-- tools/python/xen/util/auxbin.py | 9 +++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/tools/misc/xen-python-path b/tools/misc/xen-python-path index da3d2dd2ba..57774a332b 100644 --- a/tools/misc/xen-python-path +++ b/tools/misc/xen-python-path @@ -28,8 +28,13 @@ import os import os.path import sys -for p in ['python%s' % sys.version[:3], 'python']: - for l in ['/usr/lib64', '/usr/lib']: +usr = os.path.dirname(os.path.dirname(sys.argv[0])) +list = [ os.path.join(usr,'lib64') ] +list += [ os.path.join(usr,'lib') ] +list += ['/usr/lib64', '/usr/lib'] + +for l in list: + for p in ['python%s' % sys.version[:3], 'python']: for k in ['', 'site-packages/']: d = os.path.join(l, p, k) if os.path.exists(os.path.join(d, AUXBIN)): diff --git a/tools/python/xen/util/auxbin.py b/tools/python/xen/util/auxbin.py index 5d2066157c..75e38a838e 100644 --- a/tools/python/xen/util/auxbin.py +++ b/tools/python/xen/util/auxbin.py @@ -27,6 +27,7 @@ LIB_64_ARCHS = [ 'x86_64', 's390x', 'sparc64'] import os import os.path +import sys def execute(exe, args = None): @@ -47,6 +48,14 @@ def path(): def libpath(): machine = os.uname()[4] + if sys.argv[0] != '-c': + prefix = os.path.dirname(os.path.dirname(sys.argv[0])) + path = os.path.join(prefix, os.path.basename(LIB_64)) + if machine in LIB_64_ARCHS and os.path.exists(path): + return path + path = os.path.join(prefix, os.path.basename(LIB_32)) + if os.path.exists(path): + return path if machine in LIB_64_ARCHS and os.path.exists(LIB_64): return LIB_64 else: From a45afa4a5da04b31cb2f067bcecbb14cba1965a5 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 20 Jun 2007 18:43:04 +0100 Subject: [PATCH 06/45] x86: Add hypercall function for retrieving EDD info. Signed-off-by: Jan Beulich Signed-off-by: Keir Fraser --- xen/arch/x86/boot/edd.S | 24 +++++------ xen/arch/x86/platform_hypercall.c | 72 +++++++++++++++++++++++++++++++ xen/arch/x86/setup.c | 2 +- xen/include/asm-x86/edd.h | 18 ++++++-- xen/include/public/platform.h | 32 ++++++++++++++ 5 files changed, 131 insertions(+), 17 deletions(-) diff --git a/xen/arch/x86/boot/edd.S b/xen/arch/x86/boot/edd.S index fcc8132e5e..51d20d0500 100644 --- a/xen/arch/x86/boot/edd.S +++ b/xen/arch/x86/boot/edd.S @@ -24,7 +24,7 @@ /* Maximum number of EDD information structures at boot_edd_info. */ #define EDD_INFO_MAX 6 -/* Maximum number of MBR signatures at boot_edd_signature. */ +/* Maximum number of MBR signatures at boot_mbr_signature. */ #define EDD_MBR_SIG_MAX 16 /* Size of components of EDD information structure. */ @@ -40,10 +40,8 @@ get_edd: # Read the first sector of each BIOS disk device and store the 4-byte signature edd_mbr_sig_start: movb $0x80, %dl # from device 80 - movw $bootsym(boot_edd_signature),%bx # store buffer ptr in bx + movw $bootsym(boot_mbr_signature),%bx # store buffer ptr in bx edd_mbr_sig_read: - movl $0xFFFFFFFF, %eax - movl %eax, (%bx) # assume failure pushw %bx movb $0x02, %ah # 0x02 Read Sectors movb $1, %al # read 1 sector @@ -64,11 +62,12 @@ edd_mbr_sig_read: cmpb $0, %ah # some BIOSes do not set CF jne edd_mbr_sig_done # on failure, we're done. movl bootsym(boot_edd_info)+EDD_MBR_SIG_OFFSET,%eax - movl %eax, (%bx) # store signature from MBR - incb bootsym(boot_edd_signature_nr) # note that we stored something + movb %dl, (%bx) # store BIOS drive number + movl %eax, 4(%bx) # store signature from MBR + incb bootsym(boot_mbr_signature_nr) # note that we stored something incb %dl # increment to next device - addw $4, %bx # increment sig buffer ptr - cmpb $EDD_MBR_SIG_MAX,bootsym(boot_edd_signature_nr) + addw $8, %bx # increment sig buffer ptr + cmpb $EDD_MBR_SIG_MAX,bootsym(boot_mbr_signature_nr) jb edd_mbr_sig_read edd_mbr_sig_done: @@ -150,12 +149,13 @@ edd_done: opt_edd: .byte 0 # edd=on/off/skipmbr -.globl boot_edd_info_nr, boot_edd_signature_nr +.globl boot_edd_info, boot_edd_info_nr +.globl boot_mbr_signature, boot_mbr_signature_nr boot_edd_info_nr: .byte 0 -boot_edd_signature_nr: +boot_mbr_signature_nr: .byte 0 -boot_edd_signature: - .fill EDD_MBR_SIG_MAX*4,1,0 +boot_mbr_signature: + .fill EDD_MBR_SIG_MAX*8,1,0 boot_edd_info: .fill 512,1,0 # big enough for a disc sector diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c index 766a357e65..5478bc34be 100644 --- a/xen/arch/x86/platform_hypercall.c +++ b/xen/arch/x86/platform_hypercall.c @@ -20,12 +20,17 @@ #include #include #include +#include #include #include "cpu/mtrr/mtrr.h" #ifndef COMPAT typedef long ret_t; DEFINE_SPINLOCK(xenpf_lock); +# undef copy_from_compat +# define copy_from_compat copy_from_guest +# undef copy_to_compat +# define copy_to_compat copy_to_guest #else extern spinlock_t xenpf_lock; #endif @@ -151,6 +156,73 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op) } break; + case XENPF_firmware_info: + switch ( op->u.firmware_info.type ) + { + case XEN_FW_DISK_INFO: { + const struct edd_info *info; + u16 length; + + ret = -ESRCH; + if ( op->u.firmware_info.index >= bootsym(boot_edd_info_nr) ) + break; + + info = bootsym(boot_edd_info) + op->u.firmware_info.index; + + /* Transfer the EDD info block. */ + ret = -EFAULT; + if ( copy_from_compat(&length, op->u.firmware_info.u. + disk_info.edd_params, 1) ) + break; + if ( length > info->edd_device_params.length ) + length = info->edd_device_params.length; + if ( copy_to_compat(op->u.firmware_info.u.disk_info.edd_params, + (u8 *)&info->edd_device_params, + length) ) + break; + if ( copy_to_compat(op->u.firmware_info.u.disk_info.edd_params, + &length, 1) ) + break; + + /* Transfer miscellaneous other information values. */ +#define C(x) op->u.firmware_info.u.disk_info.x = info->x; + C(device); + C(version); + C(interface_support); + C(legacy_max_cylinder); + C(legacy_max_head); + C(legacy_sectors_per_track); +#undef C + + ret = (copy_field_to_guest(u_xenpf_op, op, + u.firmware_info.u.disk_info) + ? -EFAULT : 0); + break; + } + case XEN_FW_DISK_MBR_SIGNATURE: { + const struct mbr_signature *sig; + + ret = -ESRCH; + if ( op->u.firmware_info.index >= bootsym(boot_mbr_signature_nr) ) + break; + + sig = bootsym(boot_mbr_signature) + op->u.firmware_info.index; + + op->u.firmware_info.u.disk_mbr_signature.device = sig->device; + op->u.firmware_info.u.disk_mbr_signature.mbr_signature = + sig->signature; + + ret = (copy_field_to_guest(u_xenpf_op, op, + u.firmware_info.u.disk_mbr_signature) + ? -EFAULT : 0); + break; + } + default: + ret = -EINVAL; + break; + } + break; + default: ret = -ENOSYS; break; diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index c630cb242f..12dad990b0 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -505,7 +505,7 @@ void __init __start_xen(unsigned long mbi_p) printk("Disc information:\n"); printk(" Found %d MBR signatures\n", - bootsym(boot_edd_signature_nr)); + bootsym(boot_mbr_signature_nr)); printk(" Found %d EDD information structures\n", bootsym(boot_edd_info_nr)); diff --git a/xen/include/asm-x86/edd.h b/xen/include/asm-x86/edd.h index 4079dafe09..bfab9d3930 100644 --- a/xen/include/asm-x86/edd.h +++ b/xen/include/asm-x86/edd.h @@ -32,12 +32,22 @@ struct edd_info { u16 legacy_max_cylinder; /* %cl[7:6]:%ch: maximum cylinder number */ u8 legacy_max_head; /* %dh: maximum head number */ u8 legacy_sectors_per_track; /* %cl[5:0]: maximum sector number */ - /* Int13, Fn41: Get Device Parameters */ - u8 edd_device_params[74]; /* as filled into %ds:%si */ + /* Int13, Fn41: Get Device Parameters (as filled into %ds:%esi). */ + struct { + u16 length; + u8 data[72]; + } edd_device_params; } __attribute__ ((packed)); -extern u32 boot_edd_signature[]; -extern u8 boot_edd_signature_nr; +struct mbr_signature { + u8 device; + u8 pad[3]; + u32 signature; +} __attribute__ ((packed)); + +/* These all reside in the boot trampoline. Access via bootsym(). */ +extern struct mbr_signature boot_mbr_signature[]; +extern u8 boot_mbr_signature_nr; extern struct edd_info boot_edd_info[]; extern u8 boot_edd_info_nr; diff --git a/xen/include/public/platform.h b/xen/include/public/platform.h index 2937b4d31d..50e3b5149c 100644 --- a/xen/include/public/platform.h +++ b/xen/include/public/platform.h @@ -114,6 +114,37 @@ struct xenpf_platform_quirk { typedef struct xenpf_platform_quirk xenpf_platform_quirk_t; DEFINE_XEN_GUEST_HANDLE(xenpf_platform_quirk_t); +#define XENPF_firmware_info 50 +#define XEN_FW_DISK_INFO 1 +#define XEN_FW_DISK_MBR_SIGNATURE 2 +struct xenpf_firmware_info { + /* IN variables. */ + uint32_t type; + uint32_t index; + /* OUT variables. */ + union { + struct { + /* Int13, Fn48: Check Extensions Present. */ + uint8_t device; /* %dl: bios device number */ + uint8_t version; /* %ah: major version */ + uint16_t interface_support; /* %cx: support bitmap */ + /* Int13, Fn08: Legacy Get Device Parameters. */ + uint16_t legacy_max_cylinder; /* %cl[7:6]:%ch: max cyl # */ + uint8_t legacy_max_head; /* %dh: max head # */ + uint8_t legacy_sectors_per_track; /* %cl[5:0]: max sector # */ + /* Int13, Fn41: Get Device Parameters (as filled into %ds:%esi). */ + /* NB. First uint16_t of buffer must be set to buffer size. */ + XEN_GUEST_HANDLE(void) edd_params; + } disk_info; /* XEN_FW_DISK_INFO */ + struct { + uint8_t device; /* bios device number */ + uint32_t mbr_signature; /* offset 0x1b8 in mbr */ + } disk_mbr_signature; /* XEN_FW_DISK_MBR_SIGNATURE */ + } u; +}; +typedef struct xenpf_firmware_info xenpf_firmware_info_t; +DEFINE_XEN_GUEST_HANDLE(xenpf_firmware_info_t); + struct xen_platform_op { uint32_t cmd; uint32_t interface_version; /* XENPF_INTERFACE_VERSION */ @@ -124,6 +155,7 @@ struct xen_platform_op { struct xenpf_read_memtype read_memtype; struct xenpf_microcode_update microcode; struct xenpf_platform_quirk platform_quirk; + struct xenpf_firmware_info firmware_info; uint8_t pad[128]; } u; }; From 50e71c0768ca4a8e40e094efde886ccba722fea6 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 20 Jun 2007 19:08:45 +0100 Subject: [PATCH 07/45] Remove stray semi-colon in macro. Signed-off-by: Keir Fraser --- xen/arch/x86/platform_hypercall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c index 5478bc34be..79376bb2a4 100644 --- a/xen/arch/x86/platform_hypercall.c +++ b/xen/arch/x86/platform_hypercall.c @@ -185,7 +185,7 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op) break; /* Transfer miscellaneous other information values. */ -#define C(x) op->u.firmware_info.u.disk_info.x = info->x; +#define C(x) op->u.firmware_info.u.disk_info.x = info->x C(device); C(version); C(interface_support); From cc324a58e1599668be563a5e41998ab759d3755a Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 20 Jun 2007 19:24:08 +0100 Subject: [PATCH 08/45] Add hypercall function for retrieving EDID info Signed-off-by: Jan Beulich Signed-off-by: Keir Fraser --- xen/arch/x86/platform_hypercall.c | 24 ++++++++++++++++++++++++ xen/include/public/platform.h | 12 ++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c index 79376bb2a4..33dd905d07 100644 --- a/xen/arch/x86/platform_hypercall.c +++ b/xen/arch/x86/platform_hypercall.c @@ -24,6 +24,9 @@ #include #include "cpu/mtrr/mtrr.h" +extern uint16_t boot_edid_caps; +extern uint8_t boot_edid_info[]; + #ifndef COMPAT typedef long ret_t; DEFINE_SPINLOCK(xenpf_lock); @@ -217,6 +220,27 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op) ? -EFAULT : 0); break; } + case XEN_FW_VBEDDC_INFO: + ret = -ESRCH; + if ( op->u.firmware_info.index != 0 ) + break; + if ( *(u32 *)bootsym(boot_edid_info) == 0x13131313 ) + break; + + op->u.firmware_info.u.ddc_info.capabilities = + bootsym(boot_edid_caps); + op->u.firmware_info.u.ddc_info.edid_transfer_time = + bootsym(boot_edid_caps) >> 8; + + ret = 0; + if ( copy_field_to_guest(u_xenpf_op, op, u.firmware_info. + u.ddc_info.capabilities) || + copy_field_to_guest(u_xenpf_op, op, u.firmware_info. + u.ddc_info.edid_transfer_time) || + copy_to_compat(op->u.firmware_info.u.ddc_info.edid, + bootsym(boot_edid_info), 128) ) + ret = -EFAULT; + break; default: ret = -EINVAL; break; diff --git a/xen/include/public/platform.h b/xen/include/public/platform.h index 50e3b5149c..2b2a595c77 100644 --- a/xen/include/public/platform.h +++ b/xen/include/public/platform.h @@ -115,8 +115,9 @@ typedef struct xenpf_platform_quirk xenpf_platform_quirk_t; DEFINE_XEN_GUEST_HANDLE(xenpf_platform_quirk_t); #define XENPF_firmware_info 50 -#define XEN_FW_DISK_INFO 1 -#define XEN_FW_DISK_MBR_SIGNATURE 2 +#define XEN_FW_DISK_INFO 1 /* from int 13 AH=08/41/48 */ +#define XEN_FW_DISK_MBR_SIGNATURE 2 /* from MBR offset 0x1b8 */ +#define XEN_FW_VBEDDC_INFO 3 /* from int 10 AX=4f15 */ struct xenpf_firmware_info { /* IN variables. */ uint32_t type; @@ -140,6 +141,13 @@ struct xenpf_firmware_info { uint8_t device; /* bios device number */ uint32_t mbr_signature; /* offset 0x1b8 in mbr */ } disk_mbr_signature; /* XEN_FW_DISK_MBR_SIGNATURE */ + struct { + /* Int10, AX=4F15: Get EDID info. */ + uint8_t capabilities; + uint8_t edid_transfer_time; + /* must refer to 128-byte buffer */ + XEN_GUEST_HANDLE(uint8_t) edid; + } ddc_info; /* XEN_FW_VBEDDC_INFO */ } u; }; typedef struct xenpf_firmware_info xenpf_firmware_info_t; From f09e6f80624aeaac7e5070358ccf6580391c1cb2 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 20 Jun 2007 19:31:37 +0100 Subject: [PATCH 09/45] Rename ddc_info -> vbeddc_info in interface header. Signed-off-by: Keir Fraser --- xen/arch/x86/platform_hypercall.c | 10 +++++----- xen/include/public/platform.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c index 33dd905d07..2e087c4103 100644 --- a/xen/arch/x86/platform_hypercall.c +++ b/xen/arch/x86/platform_hypercall.c @@ -227,17 +227,17 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op) if ( *(u32 *)bootsym(boot_edid_info) == 0x13131313 ) break; - op->u.firmware_info.u.ddc_info.capabilities = + op->u.firmware_info.u.vbeddc_info.capabilities = bootsym(boot_edid_caps); - op->u.firmware_info.u.ddc_info.edid_transfer_time = + op->u.firmware_info.u.vbeddc_info.edid_transfer_time = bootsym(boot_edid_caps) >> 8; ret = 0; if ( copy_field_to_guest(u_xenpf_op, op, u.firmware_info. - u.ddc_info.capabilities) || + u.vbeddc_info.capabilities) || copy_field_to_guest(u_xenpf_op, op, u.firmware_info. - u.ddc_info.edid_transfer_time) || - copy_to_compat(op->u.firmware_info.u.ddc_info.edid, + u.vbeddc_info.edid_transfer_time) || + copy_to_compat(op->u.firmware_info.u.vbeddc_info.edid, bootsym(boot_edid_info), 128) ) ret = -EFAULT; break; diff --git a/xen/include/public/platform.h b/xen/include/public/platform.h index 2b2a595c77..3347666dbf 100644 --- a/xen/include/public/platform.h +++ b/xen/include/public/platform.h @@ -147,7 +147,7 @@ struct xenpf_firmware_info { uint8_t edid_transfer_time; /* must refer to 128-byte buffer */ XEN_GUEST_HANDLE(uint8_t) edid; - } ddc_info; /* XEN_FW_VBEDDC_INFO */ + } vbeddc_info; /* XEN_FW_VBEDDC_INFO */ } u; }; typedef struct xenpf_firmware_info xenpf_firmware_info_t; From 284d8c488102b6d59adb2a89930e9e3827f1ba19 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 21 Jun 2007 09:47:39 +0100 Subject: [PATCH 10/45] libxenguest: Add missing range-check on count field read from a domain save/restore file. Signed-off-by: Keir Fraser --- tools/libxc/xc_domain_restore.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/libxc/xc_domain_restore.c b/tools/libxc/xc_domain_restore.c index aaabed6d42..3193ce191c 100644 --- a/tools/libxc/xc_domain_restore.c +++ b/tools/libxc/xc_domain_restore.c @@ -903,13 +903,14 @@ int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom, /* Get the list of PFNs that are not in the psuedo-phys map */ { - unsigned int count; + unsigned int count = 0; unsigned long *pfntab; int nr_frees, rc; - if ( !read_exact(io_fd, &count, sizeof(count)) ) + if ( !read_exact(io_fd, &count, sizeof(count)) || + (count > (1U << 28)) ) /* up to 1TB of address space */ { - ERROR("Error when reading pfn count"); + ERROR("Error when reading pfn count (= %u)", count); goto out; } From 5a07d757fb2f8b993f02ba1258413e628dd8d85c Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 21 Jun 2007 12:10:01 +0100 Subject: [PATCH 11/45] libxenguest: Add another range check to dom restore. Signed-off-by: Keir Fraser --- tools/libxc/xc_domain_restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/libxc/xc_domain_restore.c b/tools/libxc/xc_domain_restore.c index 3193ce191c..e7ff90dcfd 100644 --- a/tools/libxc/xc_domain_restore.c +++ b/tools/libxc/xc_domain_restore.c @@ -465,7 +465,7 @@ int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom, if ( j == 0 ) break; /* our work here is done */ - if ( j > MAX_BATCH_SIZE ) + if ( (j > MAX_BATCH_SIZE) || (j < 0) ) { ERROR("Max batch size exceeded. Giving up."); goto out; From 0b3c29f7fdda202ef847673a4212f0fdf5c26e5e Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 21 Jun 2007 12:13:06 +0100 Subject: [PATCH 12/45] i386: remove NMI deferral by instead making sure selector registers are always stored/restored correctly despite the potential for an NMI (and also MCE, with a subsequent patch) to kick in. The idea is to always check values read from %ds and %es against __HYPERVISOR_DS, and only store into the current frame (all normal handlers) or the outer-most one (NMI and MCE) if the value read is different. That way, any NMI or MCE occurring during frame setup will store selectors not saved so far on behalf of the interrupted handler, with that interrupted handler either having managed to read the guest selector (in which case it can store it regardless of whether NMI/MCE kicked in between the read and the store) or finding __HYPERVISOR_DS already in the register, in which case it'll know not to store (as the nested handler would have done the store). For the restore portion this makes use of the fact that there's exactly one such code sequence, and by moving the selector restore part past all other restores (including all stack pointer adjustments) the NMI/MCE handlers can safely detect whether any selector would have been restored already (by range checking EIP) and move EIP back to the beginning of the selector restore sequence without having to play with the stack pointer itself or any other gpr. Signed-off-by: Jan Beulich Signed-off-by: Keir Fraser --- xen/arch/x86/x86_32/entry.S | 141 ++++++++++--------- xen/arch/x86/x86_32/supervisor_mode_kernel.S | 29 ++-- xen/arch/x86/x86_32/traps.c | 11 -- xen/include/asm-x86/processor.h | 1 - xen/include/asm-x86/x86_32/asm_defns.h | 71 ++++++---- 5 files changed, 132 insertions(+), 121 deletions(-) diff --git a/xen/arch/x86/x86_32/entry.S b/xen/arch/x86/x86_32/entry.S index 15be0e6e16..26769fa67e 100644 --- a/xen/arch/x86/x86_32/entry.S +++ b/xen/arch/x86/x86_32/entry.S @@ -72,35 +72,34 @@ andl $~3,reg; \ movl (reg),reg; - ALIGN restore_all_guest: ASSERT_INTERRUPTS_DISABLED testl $X86_EFLAGS_VM,UREGS_eflags(%esp) - jnz restore_all_vm86 + popl %ebx + popl %ecx + popl %edx + popl %esi + popl %edi + popl %ebp + popl %eax + leal 4(%esp),%esp + jnz .Lrestore_iret_guest #ifdef CONFIG_X86_SUPERVISOR_MODE_KERNEL - testl $2,UREGS_cs(%esp) - jnz 1f + testb $2,UREGS_cs-UREGS_eip(%esp) + jnz .Lrestore_sregs_guest call restore_ring0_guest - jmp restore_all_vm86 -1: + jmp .Lrestore_iret_guest #endif -.Lft1: mov UREGS_ds(%esp),%ds -.Lft2: mov UREGS_es(%esp),%es -.Lft3: mov UREGS_fs(%esp),%fs -.Lft4: mov UREGS_gs(%esp),%gs -restore_all_vm86: - popl %ebx - popl %ecx - popl %edx - popl %esi - popl %edi - popl %ebp - popl %eax - addl $4,%esp +.Lrestore_sregs_guest: +.Lft1: mov UREGS_ds-UREGS_eip(%esp),%ds +.Lft2: mov UREGS_es-UREGS_eip(%esp),%es +.Lft3: mov UREGS_fs-UREGS_eip(%esp),%fs +.Lft4: mov UREGS_gs-UREGS_eip(%esp),%gs +.Lrestore_iret_guest: .Lft5: iret .section .fixup,"ax" -.Lfx5: subl $28,%esp +.Lfx1: subl $28,%esp pushl 28(%esp) # error_code/entry_vector movl %eax,UREGS_eax+4(%esp) movl %ebp,UREGS_ebp+4(%esp) @@ -109,9 +108,6 @@ restore_all_vm86: movl %edx,UREGS_edx+4(%esp) movl %ecx,UREGS_ecx+4(%esp) movl %ebx,UREGS_ebx+4(%esp) -.Lfx1: SET_XEN_SEGMENTS(a) - movl %eax,%fs - movl %eax,%gs sti popl %esi pushfl # EFLAGS @@ -147,7 +143,7 @@ failsafe_callback: .long .Lft2,.Lfx1 .long .Lft3,.Lfx1 .long .Lft4,.Lfx1 - .long .Lft5,.Lfx5 + .long .Lft5,.Lfx1 .previous .section __ex_table,"a" .long .Ldf1,failsafe_callback @@ -169,8 +165,8 @@ restore_all_xen: ENTRY(hypercall) subl $4,%esp FIXUP_RING0_GUEST_STACK - SAVE_ALL(b) - sti + SAVE_ALL(1f,1f) +1: sti GET_CURRENT(%ebx) cmpl $NR_hypercalls,%eax jae bad_hypercall @@ -420,9 +416,14 @@ ENTRY(divide_error) ALIGN handle_exception: FIXUP_RING0_GUEST_STACK - SAVE_ALL_NOSEGREGS(a) - SET_XEN_SEGMENTS(a) - testb $X86_EFLAGS_IF>>8,UREGS_eflags+1(%esp) + SAVE_ALL(1f,2f) + .text 1 + /* Exception within Xen: make sure we have valid %ds,%es. */ +1: mov %ecx,%ds + mov %ecx,%es + jmp 2f + .previous +2: testb $X86_EFLAGS_IF>>8,UREGS_eflags+1(%esp) jz exception_with_ints_disabled sti # re-enable interrupts 1: xorl %eax,%eax @@ -542,9 +543,9 @@ ENTRY(spurious_interrupt_bug) jmp handle_exception ENTRY(early_page_fault) - SAVE_ALL_NOSEGREGS(a) - movl %esp,%edx - pushl %edx + SAVE_ALL(1f,1f) +1: movl %esp,%eax + pushl %eax call do_early_page_fault addl $4,%esp jmp restore_all_xen @@ -555,49 +556,53 @@ ENTRY(nmi) iret #else # Save state but do not trash the segment registers! - # We may otherwise be unable to reload them or copy them to ring 1. + pushl $TRAP_nmi<<16 + SAVE_ALL(.Lnmi_xen,.Lnmi_common) +.Lnmi_common: + movl %esp,%eax pushl %eax - SAVE_ALL_NOSEGREGS(a) - - # We can only process the NMI if: - # A. We are the outermost Xen activation (in which case we have - # the selectors safely saved on our stack) - # B. DS and ES contain sane Xen values. - # In all other cases we bail without touching DS-GS, as we have - # interrupted an enclosing Xen activation in tricky prologue or - # epilogue code. - movl UREGS_eflags(%esp),%eax - movb UREGS_cs(%esp),%al - testl $(3|X86_EFLAGS_VM),%eax - jnz continue_nmi - movl %ds,%eax - cmpw $(__HYPERVISOR_DS),%ax - jne defer_nmi - movl %es,%eax - cmpw $(__HYPERVISOR_DS),%ax - jne defer_nmi - -continue_nmi: - SET_XEN_SEGMENTS(d) - movl %esp,%edx - pushl %edx call do_nmi addl $4,%esp + /* + * NB. We may return to Xen context with polluted %ds/%es. But in such + * cases we have put guest DS/ES on the guest stack frame, which will + * be detected by SAVE_ALL(), or we have rolled back restore_guest. + */ jmp ret_from_intr - -defer_nmi: - movl $FIXMAP_apic_base,%eax - # apic_wait_icr_idle() -1: movl %ss:APIC_ICR(%eax),%ebx - testl $APIC_ICR_BUSY,%ebx - jnz 1b - # __send_IPI_shortcut(APIC_DEST_SELF, TRAP_deferred_nmi) - movl $(APIC_DM_FIXED | APIC_DEST_SELF | APIC_DEST_PHYSICAL | \ - TRAP_deferred_nmi),%ss:APIC_ICR(%eax) - jmp restore_all_xen +.Lnmi_xen: + /* Check the outer (guest) context for %ds/%es state validity. */ + GET_GUEST_REGS(%ebx) + testl $X86_EFLAGS_VM,%ss:UREGS_eflags(%ebx) + mov %ds,%eax + mov %es,%edx + jnz .Lnmi_vm86 + /* We may have interrupted Xen while messing with %ds/%es... */ + cmpw %ax,%cx + mov %ecx,%ds /* Ensure %ds is valid */ + cmove UREGS_ds(%ebx),%eax /* Grab guest DS if it wasn't in %ds */ + cmpw %dx,%cx + movl %eax,UREGS_ds(%ebx) /* Ensure guest frame contains guest DS */ + cmove UREGS_es(%ebx),%edx /* Grab guest ES if it wasn't in %es */ + mov %ecx,%es /* Ensure %es is valid */ + movl $.Lrestore_sregs_guest,%ecx + movl %edx,UREGS_es(%ebx) /* Ensure guest frame contains guest ES */ + cmpl %ecx,UREGS_eip(%esp) + jbe .Lnmi_common + cmpl $.Lrestore_iret_guest,UREGS_eip(%esp) + ja .Lnmi_common + /* Roll outer context restore_guest back to restoring %ds/%es. */ + movl %ecx,UREGS_eip(%esp) + jmp .Lnmi_common +.Lnmi_vm86: + /* vm86 is easy: the CPU saved %ds/%es so we can safely stomp them. */ + mov %ecx,%ds + mov %ecx,%es + jmp .Lnmi_common #endif /* !CONFIG_X86_SUPERVISOR_MODE_KERNEL */ ENTRY(setup_vm86_frame) + mov %ecx,%ds + mov %ecx,%es # Copies the entire stack frame forwards by 16 bytes. .macro copy_vm86_words count=18 .if \count diff --git a/xen/arch/x86/x86_32/supervisor_mode_kernel.S b/xen/arch/x86/x86_32/supervisor_mode_kernel.S index ea2276993d..c7957049cf 100644 --- a/xen/arch/x86/x86_32/supervisor_mode_kernel.S +++ b/xen/arch/x86/x86_32/supervisor_mode_kernel.S @@ -20,40 +20,45 @@ #include #include +#define guestreg(field) ((field)-UREGS_eip+36) + # Upon entry the stack should be the Xen stack and contain: - # %ss, %esp, EFLAGS, %cs|1, %eip, ERROR, SAVE_ALL, RETURN + # %ss, %esp, EFLAGS, %cs|1, %eip, RETURN # On exit the stack should be %ss:%esp (i.e. the guest stack) # and contain: - # EFLAGS, %cs, %eip, ERROR, SAVE_ALL, RETURN + # EFLAGS, %cs, %eip, RETURN ALIGN ENTRY(restore_ring0_guest) - # Point %gs:%esi to guest stack. -RRG0: movw UREGS_ss+4(%esp),%gs - movl UREGS_esp+4(%esp),%esi + pusha - # Copy EFLAGS...EBX, RETURN from Xen stack to guest stack. - movl $(UREGS_kernel_sizeof>>2)+1,%ecx + # Point %gs:%esi to guest stack. +RRG0: movw guestreg(UREGS_ss)(%esp),%gs + movl guestreg(UREGS_esp)(%esp),%esi + + # Copy EFLAGS, %cs, %eip, RETURN, PUSHA from Xen stack to guest stack. + movl $12,%ecx /* 12 32-bit values */ 1: subl $4,%esi movl -4(%esp,%ecx,4),%eax RRG1: movl %eax,%gs:(%esi) loop 1b -RRG2: andl $~3,%gs:UREGS_cs+4(%esi) +RRG2: andl $~3,%gs:guestreg(UREGS_cs)(%esi) movl %gs,%eax # We need to do this because these registers are not present # on the guest stack so they cannot be restored by the code in # restore_all_guest. -RRG3: mov UREGS_ds+4(%esp),%ds -RRG4: mov UREGS_es+4(%esp),%es -RRG5: mov UREGS_fs+4(%esp),%fs -RRG6: mov UREGS_gs+4(%esp),%gs +RRG3: mov guestreg(UREGS_ds)(%esp),%ds +RRG4: mov guestreg(UREGS_es)(%esp),%es +RRG5: mov guestreg(UREGS_fs)(%esp),%fs +RRG6: mov guestreg(UREGS_gs)(%esp),%gs RRG7: movl %eax,%ss movl %esi,%esp + popa ret .section __ex_table,"a" .long RRG0,domain_crash_synchronous diff --git a/xen/arch/x86/x86_32/traps.c b/xen/arch/x86/x86_32/traps.c index c3fc0fdd2a..4519348b85 100644 --- a/xen/arch/x86/x86_32/traps.c +++ b/xen/arch/x86/x86_32/traps.c @@ -232,15 +232,6 @@ unsigned long do_iret(void) return 0; } -#include -BUILD_SMP_INTERRUPT(deferred_nmi, TRAP_deferred_nmi) -fastcall void smp_deferred_nmi(struct cpu_user_regs *regs) -{ - asmlinkage void do_nmi(struct cpu_user_regs *); - ack_APIC_irq(); - do_nmi(regs); -} - void __init percpu_traps_init(void) { struct tss_struct *tss = &doublefault_tss; @@ -252,8 +243,6 @@ void __init percpu_traps_init(void) /* The hypercall entry vector is only accessible from ring 1. */ _set_gate(idt_table+HYPERCALL_VECTOR, 14, 1, &hypercall); - set_intr_gate(TRAP_deferred_nmi, &deferred_nmi); - /* * Make a separate task for double faults. This will get us debug output if * we blow the kernel stack. diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index 9157a29811..419c35db62 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -104,7 +104,6 @@ #define TRAP_alignment_check 17 #define TRAP_machine_check 18 #define TRAP_simd_error 19 -#define TRAP_deferred_nmi 31 /* Set for entry via SYSCALL. Informs return code to use SYSRETQ not IRETQ. */ /* NB. Same as VGCF_in_syscall. No bits in common with any other TRAP_ defn. */ diff --git a/xen/include/asm-x86/x86_32/asm_defns.h b/xen/include/asm-x86/x86_32/asm_defns.h index 6aac4cbf16..c12039e910 100644 --- a/xen/include/asm-x86/x86_32/asm_defns.h +++ b/xen/include/asm-x86/x86_32/asm_defns.h @@ -26,7 +26,16 @@ #define ASSERT_INTERRUPTS_ENABLED ASSERT_INTERRUPT_STATUS(nz) #define ASSERT_INTERRUPTS_DISABLED ASSERT_INTERRUPT_STATUS(z) -#define __SAVE_ALL_PRE \ +/* + * Saves all register state into an exception/interrupt stack frame. + * Returns to the caller at if the interrupted context is within + * Xen; at if the interrupted context is vm86; or falls through + * if the interrupted context is an ordinary guest protected-mode context. + * In all cases %ecx contains __HYPERVISOR_DS. %ds/%es are guaranteed to + * contain __HYPERVISOR_DS unless control passes to , in which case + * the caller is reponsible for validity of %ds/%es. + */ +#define SAVE_ALL(xen_lbl, vm86_lbl) \ cld; \ pushl %eax; \ pushl %ebp; \ @@ -37,30 +46,34 @@ pushl %ecx; \ pushl %ebx; \ testl $(X86_EFLAGS_VM),UREGS_eflags(%esp); \ - jz 2f; \ - call setup_vm86_frame; \ - jmp 3f; \ - 2:testb $3,UREGS_cs(%esp); \ - jz 1f; \ - mov %ds,UREGS_ds(%esp); \ - mov %es,UREGS_es(%esp); \ - mov %fs,UREGS_fs(%esp); \ - mov %gs,UREGS_gs(%esp); \ - 3: - -#define SAVE_ALL_NOSEGREGS(_reg) \ - __SAVE_ALL_PRE \ - 1: - -#define SET_XEN_SEGMENTS(_reg) \ - movl $(__HYPERVISOR_DS),%e ## _reg ## x; \ - mov %e ## _reg ## x,%ds; \ - mov %e ## _reg ## x,%es; - -#define SAVE_ALL(_reg) \ - __SAVE_ALL_PRE \ - SET_XEN_SEGMENTS(_reg) \ - 1: + mov %ds,%edi; \ + mov %es,%esi; \ + mov $(__HYPERVISOR_DS),%ecx; \ + jnz 86f; \ + .text 1; \ + 86: call setup_vm86_frame; \ + jmp vm86_lbl; \ + .previous; \ + testb $3,UREGS_cs(%esp); \ + jz xen_lbl; \ + /* \ + * We are the outermost Xen context, but our \ + * life is complicated by NMIs and MCEs. These \ + * could occur in our critical section and \ + * pollute %ds and %es. We have to detect that \ + * this has occurred and avoid saving Xen DS/ES \ + * values to the guest stack frame. \ + */ \ + cmpw %cx,%di; \ + mov %ecx,%ds; \ + mov %fs,UREGS_fs(%esp); \ + cmove UREGS_ds(%esp),%edi; \ + cmpw %cx,%si; \ + mov %edi,UREGS_ds(%esp); \ + cmove UREGS_es(%esp),%esi; \ + mov %ecx,%es; \ + mov %gs,UREGS_gs(%esp); \ + mov %esi,UREGS_es(%esp) #ifdef PERF_COUNTERS #define PERFC_INCR(_name,_idx,_cur) \ @@ -97,8 +110,8 @@ __asm__( \ STR(x) ":\n\t" \ "pushl $"#v"<<16\n\t" \ STR(FIXUP_RING0_GUEST_STACK) \ - STR(SAVE_ALL(a)) \ - "movl %esp,%eax\n\t" \ + STR(SAVE_ALL(1f,1f)) "\n\t" \ + "1:movl %esp,%eax\n\t" \ "pushl %eax\n\t" \ "call "STR(smp_##x)"\n\t" \ "addl $4,%esp\n\t" \ @@ -109,8 +122,8 @@ __asm__( \ "\n" __ALIGN_STR"\n" \ "common_interrupt:\n\t" \ STR(FIXUP_RING0_GUEST_STACK) \ - STR(SAVE_ALL(a)) \ - "movl %esp,%eax\n\t" \ + STR(SAVE_ALL(1f,1f)) "\n\t" \ + "1:movl %esp,%eax\n\t" \ "pushl %eax\n\t" \ "call " STR(do_IRQ) "\n\t" \ "addl $4,%esp\n\t" \ From d8b6ccfe2d40d2964feb992bf2026957c54e982a Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 21 Jun 2007 14:03:57 +0100 Subject: [PATCH 13/45] x86: clear guest's EFLAGS.RF after emulating instructions Signed-off-by: Jan Beulich --- xen/arch/x86/hvm/io.c | 1 + xen/arch/x86/hvm/platform.c | 3 +++ xen/arch/x86/hvm/vmx/vmx.c | 21 ++++++++++++--------- xen/arch/x86/traps.c | 2 ++ xen/arch/x86/x86_emulate.c | 1 + xen/include/asm-x86/hvm/svm/emulate.h | 1 + 6 files changed, 20 insertions(+), 9 deletions(-) diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c index 0a99dd27d6..97e1215a58 100644 --- a/xen/arch/x86/hvm/io.c +++ b/xen/arch/x86/hvm/io.c @@ -858,6 +858,7 @@ void hvm_io_assist(void) } /* Copy register changes back into current guest state. */ + regs->eflags &= ~X86_EFLAGS_RF; hvm_load_cpu_guest_regs(v, regs); memcpy(guest_cpu_user_regs(), regs, HVM_CONTEXT_STACK_BYTES); diff --git a/xen/arch/x86/hvm/platform.c b/xen/arch/x86/hvm/platform.c index 2b173c18de..5de0770322 100644 --- a/xen/arch/x86/hvm/platform.c +++ b/xen/arch/x86/hvm/platform.c @@ -1065,6 +1065,7 @@ void handle_mmio(unsigned long gpa) } regs->eip += inst_len; /* advance %eip */ + regs->eflags &= ~X86_EFLAGS_RF; switch ( mmio_op->instr ) { case INSTR_MOV: @@ -1122,6 +1123,7 @@ void handle_mmio(unsigned long gpa) /* IO read --> memory write */ if ( dir == IOREQ_READ ) errcode |= PFEC_write_access; regs->eip -= inst_len; /* do not advance %eip */ + regs->eflags |= X86_EFLAGS_RF; /* RF was set by original #PF */ hvm_inject_exception(TRAP_page_fault, errcode, addr); return; } @@ -1150,6 +1152,7 @@ void handle_mmio(unsigned long gpa) /* Failed on the page-spanning copy. Inject PF into * the guest for the address where we failed */ regs->eip -= inst_len; /* do not advance %eip */ + regs->eflags |= X86_EFLAGS_RF; /* RF was set by #PF */ /* Must set CR2 at the failing address */ addr += size - rv; gdprintk(XENLOG_DEBUG, "Pagefault on non-io side of a " diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index f36b58f261..bb5a48aa87 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -1315,16 +1315,20 @@ static int __get_instruction_length(void) static void inline __update_guest_eip(unsigned long inst_len) { - unsigned long current_eip, intr_shadow; + unsigned long x; - current_eip = __vmread(GUEST_RIP); - __vmwrite(GUEST_RIP, current_eip + inst_len); + x = __vmread(GUEST_RIP); + __vmwrite(GUEST_RIP, x + inst_len); - intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO); - if ( intr_shadow & (VMX_INTR_SHADOW_STI | VMX_INTR_SHADOW_MOV_SS) ) + x = __vmread(GUEST_RFLAGS); + if ( x & X86_EFLAGS_RF ) + __vmwrite(GUEST_RFLAGS, x & ~X86_EFLAGS_RF); + + x = __vmread(GUEST_INTERRUPTIBILITY_INFO); + if ( x & (VMX_INTR_SHADOW_STI | VMX_INTR_SHADOW_MOV_SS) ) { - intr_shadow &= ~(VMX_INTR_SHADOW_STI | VMX_INTR_SHADOW_MOV_SS); - __vmwrite(GUEST_INTERRUPTIBILITY_INFO, intr_shadow); + x &= ~(VMX_INTR_SHADOW_STI | VMX_INTR_SHADOW_MOV_SS); + __vmwrite(GUEST_INTERRUPTIBILITY_INFO, x); } } @@ -1896,7 +1900,7 @@ static void vmx_world_save(struct vcpu *v, struct vmx_assist_context *c) c->eip += __get_instruction_length(); /* Safe: MOV Cn, LMSW, CLTS */ c->esp = __vmread(GUEST_RSP); - c->eflags = __vmread(GUEST_RFLAGS); + c->eflags = __vmread(GUEST_RFLAGS) & ~X86_EFLAGS_RF; c->cr0 = v->arch.hvm_vmx.cpu_shadow_cr0; c->cr3 = v->arch.hvm_vmx.cpu_cr3; @@ -2272,7 +2276,6 @@ static int vmx_set_cr0(unsigned long value) "Enabling CR0.PE at %%eip 0x%lx", eip); if ( vmx_assist(v, VMX_ASSIST_RESTORE) ) { - eip = __vmread(GUEST_RIP); HVM_DBG_LOG(DBG_LEVEL_1, "Restoring to %%eip 0x%lx", eip); return 0; /* do not update eip! */ diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index c14847a668..c26fde22f9 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -631,6 +631,7 @@ static int emulate_forced_invalid_op(struct cpu_user_regs *regs) regs->ecx = c; regs->edx = d; regs->eip = eip; + regs->eflags &= ~X86_EFLAGS_RF; return EXCRET_fault_fixed; } @@ -1787,6 +1788,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) done: regs->eip = eip; + regs->eflags &= ~X86_EFLAGS_RF; return EXCRET_fault_fixed; fail: diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c index 70262d6131..213da19f5d 100644 --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -1630,6 +1630,7 @@ x86_emulate( } /* Commit shadow register state. */ + _regs.eflags &= ~EF_RF; *ctxt->regs = _regs; done: diff --git a/xen/include/asm-x86/hvm/svm/emulate.h b/xen/include/asm-x86/hvm/svm/emulate.h index 8a4e139d22..8c183b89de 100644 --- a/xen/include/asm-x86/hvm/svm/emulate.h +++ b/xen/include/asm-x86/hvm/svm/emulate.h @@ -138,6 +138,7 @@ static void inline __update_guest_eip( { ASSERT(inst_len > 0); vmcb->rip += inst_len; + vmcb->rflags &= ~X86_EFLAGS_RF; } #endif /* __ASM_X86_HVM_SVM_EMULATE_H__ */ From 814685710454a2061ac4e5941d3eb6acda5ea6b1 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 21 Jun 2007 15:10:04 +0100 Subject: [PATCH 14/45] x86: machine check exception handling Properly handle MCE (connecting the exisiting, but so far unused vendor specific handlers). HVM guests don't own CR4.MCE (and hence can't suppress the exception) anymore, preventing silent machine shutdown. Signed-off-by: Jan Beulich Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/svm/svm.c | 44 +++++++++++++++++++++------- xen/arch/x86/hvm/svm/vmcb.c | 8 ++++-- xen/arch/x86/hvm/vmx/vmcs.c | 2 +- xen/arch/x86/hvm/vmx/vmx.c | 32 +++++++++++++++++---- xen/arch/x86/traps.c | 9 +++--- xen/arch/x86/x86_32/entry.S | 46 +++++++++++++++++------------- xen/arch/x86/x86_64/entry.S | 40 ++++++++++++++------------ xen/arch/x86/x86_64/traps.c | 10 +++++-- xen/include/asm-x86/hvm/hvm.h | 7 +++++ xen/include/asm-x86/hvm/svm/vmcb.h | 8 ------ xen/include/asm-x86/hvm/trace.h | 1 + xen/include/asm-x86/hvm/vmx/vmx.h | 7 ----- xen/include/asm-x86/processor.h | 3 +- xen/include/public/trace.h | 1 + 14 files changed, 135 insertions(+), 83 deletions(-) diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 9275a01052..ca259286d2 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -391,7 +391,7 @@ int svm_vmcb_restore(struct vcpu *v, struct hvm_hw_cpu *c) } skip_cr3: - vmcb->cr4 = c->cr4 | SVM_CR4_HOST_MASK; + vmcb->cr4 = c->cr4 | HVM_CR4_HOST_MASK; v->arch.hvm_svm.cpu_shadow_cr4 = c->cr4; vmcb->idtr.limit = c->idtr_limit; @@ -448,7 +448,8 @@ int svm_vmcb_restore(struct vcpu *v, struct hvm_hw_cpu *c) /* update VMCB for nested paging restore */ if ( paging_mode_hap(v->domain) ) { vmcb->cr0 = v->arch.hvm_svm.cpu_shadow_cr0; - vmcb->cr4 = v->arch.hvm_svm.cpu_shadow_cr4; + vmcb->cr4 = v->arch.hvm_svm.cpu_shadow_cr4 | + (HVM_CR4_HOST_MASK & ~X86_CR4_PAE); vmcb->cr3 = c->cr3; vmcb->np_enable = 1; vmcb->g_pat = 0x0007040600070406ULL; /* guest PAT */ @@ -805,8 +806,10 @@ static void svm_ctxt_switch_from(struct vcpu *v) : : "a" (__pa(root_vmcb[cpu])) ); #ifdef __x86_64__ - /* Resume use of IST2 for NMIs now that the host TR is reinstated. */ - idt_tables[cpu][TRAP_nmi].a |= 2UL << 32; + /* Resume use of ISTs now that the host TR is reinstated. */ + idt_tables[cpu][TRAP_double_fault].a |= 1UL << 32; /* IST1 */ + idt_tables[cpu][TRAP_nmi].a |= 2UL << 32; /* IST2 */ + idt_tables[cpu][TRAP_machine_check].a |= 3UL << 32; /* IST3 */ #endif } @@ -826,10 +829,12 @@ static void svm_ctxt_switch_to(struct vcpu *v) set_segment_register(ss, 0); /* - * Cannot use IST2 for NMIs while we are running with the guest TR. But - * this doesn't matter: the IST is only needed to handle SYSCALL/SYSRET. + * Cannot use ISTs for NMI/#MC/#DF while we are running with the guest TR. + * But this doesn't matter: the IST is only req'd to handle SYSCALL/SYSRET. */ - idt_tables[cpu][TRAP_nmi].a &= ~(2UL << 32); + idt_tables[cpu][TRAP_double_fault].a &= ~(3UL << 32); + idt_tables[cpu][TRAP_nmi].a &= ~(3UL << 32); + idt_tables[cpu][TRAP_machine_check].a &= ~(3UL << 32); #endif svm_restore_dr(v); @@ -1823,9 +1828,19 @@ static int mov_to_cr(int gpreg, int cr, struct cpu_user_regs *regs) break; case 4: /* CR4 */ + if ( value & ~mmu_cr4_features ) + { + HVM_DBG_LOG(DBG_LEVEL_1, "Guest attempts to enable unsupported " + "CR4 features %lx (host %lx)", + value, mmu_cr4_features); + svm_inject_exception(v, TRAP_gp_fault, 1, 0); + break; + } + if ( paging_mode_hap(v->domain) ) { - vmcb->cr4 = v->arch.hvm_svm.cpu_shadow_cr4 = value; + v->arch.hvm_svm.cpu_shadow_cr4 = value; + vmcb->cr4 = value | (HVM_CR4_HOST_MASK & ~X86_CR4_PAE); paging_update_paging_modes(v); /* signal paging update to ASID handler */ svm_asid_g_update_paging (v); @@ -1875,7 +1890,7 @@ static int mov_to_cr(int gpreg, int cr, struct cpu_user_regs *regs) } v->arch.hvm_svm.cpu_shadow_cr4 = value; - vmcb->cr4 = value | SVM_CR4_HOST_MASK; + vmcb->cr4 = value | HVM_CR4_HOST_MASK; /* * Writing to CR4 to modify the PSE, PGE, or PAE flag invalidates @@ -2265,12 +2280,13 @@ static int svm_reset_to_realmode(struct vcpu *v, vmcb->cr2 = 0; vmcb->efer = EFER_SVME; - vmcb->cr4 = SVM_CR4_HOST_MASK; + vmcb->cr4 = HVM_CR4_HOST_MASK; v->arch.hvm_svm.cpu_shadow_cr4 = 0; if ( paging_mode_hap(v->domain) ) { vmcb->cr0 = v->arch.hvm_svm.cpu_shadow_cr0; - vmcb->cr4 = v->arch.hvm_svm.cpu_shadow_cr4; + vmcb->cr4 = v->arch.hvm_svm.cpu_shadow_cr4 | + (HVM_CR4_HOST_MASK & ~X86_CR4_PAE); } /* This will jump to ROMBIOS */ @@ -2411,6 +2427,12 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs *regs) break; } + case VMEXIT_EXCEPTION_MC: + HVMTRACE_0D(MCE, v); + svm_store_cpu_guest_regs(v, regs, NULL); + do_machine_check(regs); + break; + case VMEXIT_VINTR: vmcb->vintr.fields.irq = 0; vmcb->general1_intercepts &= ~GENERAL1_INTERCEPT_VINTR; diff --git a/xen/arch/x86/hvm/svm/vmcb.c b/xen/arch/x86/hvm/svm/vmcb.c index c6b1ccddea..3141f7377b 100644 --- a/xen/arch/x86/hvm/svm/vmcb.c +++ b/xen/arch/x86/hvm/svm/vmcb.c @@ -224,7 +224,7 @@ static int construct_vmcb(struct vcpu *v) /* Guest CR4. */ arch_svm->cpu_shadow_cr4 = read_cr4() & ~(X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE); - vmcb->cr4 = arch_svm->cpu_shadow_cr4 | SVM_CR4_HOST_MASK; + vmcb->cr4 = arch_svm->cpu_shadow_cr4 | HVM_CR4_HOST_MASK; paging_update_paging_modes(v); vmcb->cr3 = v->arch.hvm_vcpu.hw_cr3; @@ -235,7 +235,9 @@ static int construct_vmcb(struct vcpu *v) vmcb->np_enable = 1; /* enable nested paging */ vmcb->g_pat = 0x0007040600070406ULL; /* guest PAT */ vmcb->h_cr3 = pagetable_get_paddr(v->domain->arch.phys_table); - vmcb->cr4 = arch_svm->cpu_shadow_cr4 = 0; + vmcb->cr4 = arch_svm->cpu_shadow_cr4 = + (HVM_CR4_HOST_MASK & ~X86_CR4_PAE); + vmcb->exception_intercepts = HVM_TRAP_MASK; /* No point in intercepting CR0/3/4 reads, because the hardware * will return the guest versions anyway. */ @@ -249,7 +251,7 @@ static int construct_vmcb(struct vcpu *v) } else { - vmcb->exception_intercepts = 1U << TRAP_page_fault; + vmcb->exception_intercepts = HVM_TRAP_MASK | (1U << TRAP_page_fault); } return 0; diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index 1740277c8e..4c03b31ffc 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -421,7 +421,7 @@ static void construct_vmcs(struct vcpu *v) __vmwrite(VMCS_LINK_POINTER_HIGH, ~0UL); #endif - __vmwrite(EXCEPTION_BITMAP, 1U << TRAP_page_fault); + __vmwrite(EXCEPTION_BITMAP, HVM_TRAP_MASK | (1U << TRAP_page_fault)); /* Guest CR0. */ cr0 = read_cr0(); diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index bb5a48aa87..e958bc292f 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -615,7 +615,7 @@ int vmx_vmcs_restore(struct vcpu *v, struct hvm_hw_cpu *c) } #endif - __vmwrite(GUEST_CR4, (c->cr4 | VMX_CR4_HOST_MASK)); + __vmwrite(GUEST_CR4, (c->cr4 | HVM_CR4_HOST_MASK)); v->arch.hvm_vmx.cpu_shadow_cr4 = c->cr4; __vmwrite(CR4_READ_SHADOW, v->arch.hvm_vmx.cpu_shadow_cr4); @@ -2001,7 +2001,7 @@ static int vmx_world_restore(struct vcpu *v, struct vmx_assist_context *c) else HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %x", c->cr3); - __vmwrite(GUEST_CR4, (c->cr4 | VMX_CR4_HOST_MASK)); + __vmwrite(GUEST_CR4, (c->cr4 | HVM_CR4_HOST_MASK)); v->arch.hvm_vmx.cpu_shadow_cr4 = c->cr4; __vmwrite(CR4_READ_SHADOW, v->arch.hvm_vmx.cpu_shadow_cr4); @@ -2400,6 +2400,14 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs) case 4: /* CR4 */ old_cr = v->arch.hvm_vmx.cpu_shadow_cr4; + if ( value & ~mmu_cr4_features ) + { + HVM_DBG_LOG(DBG_LEVEL_1, "Guest attempts to enable unsupported " + "CR4 features %lx (host %lx)", + value, mmu_cr4_features); + vmx_inject_hw_exception(v, TRAP_gp_fault, 0); + break; + } if ( (value & X86_CR4_PAE) && !(old_cr & X86_CR4_PAE) ) { if ( vmx_pgbit_test(v) ) @@ -2440,7 +2448,7 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs) } } - __vmwrite(GUEST_CR4, value| VMX_CR4_HOST_MASK); + __vmwrite(GUEST_CR4, value | HVM_CR4_HOST_MASK); v->arch.hvm_vmx.cpu_shadow_cr4 = value; __vmwrite(CR4_READ_SHADOW, v->arch.hvm_vmx.cpu_shadow_cr4); @@ -2826,7 +2834,8 @@ static void vmx_reflect_exception(struct vcpu *v) } } -static void vmx_failed_vmentry(unsigned int exit_reason) +static void vmx_failed_vmentry(unsigned int exit_reason, + struct cpu_user_regs *regs) { unsigned int failed_vmentry_reason = (uint16_t)exit_reason; unsigned long exit_qualification; @@ -2843,6 +2852,9 @@ static void vmx_failed_vmentry(unsigned int exit_reason) break; case EXIT_REASON_MACHINE_CHECK: printk("caused by machine check.\n"); + HVMTRACE_0D(MCE, current); + vmx_store_cpu_guest_regs(current, regs, NULL); + do_machine_check(regs); break; default: printk("reason not known yet!"); @@ -2872,7 +2884,7 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs *regs) local_irq_enable(); if ( unlikely(exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY) ) - return vmx_failed_vmentry(exit_reason); + return vmx_failed_vmentry(exit_reason, regs); switch ( exit_reason ) { @@ -2923,12 +2935,20 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs *regs) vmx_inject_hw_exception(v, TRAP_page_fault, regs->error_code); break; case TRAP_nmi: - HVMTRACE_0D(NMI, v); if ( (intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI ) + { + HVMTRACE_0D(NMI, v); + vmx_store_cpu_guest_regs(v, regs, NULL); do_nmi(regs); /* Real NMI, vector 2: normal processing. */ + } else vmx_reflect_exception(v); break; + case TRAP_machine_check: + HVMTRACE_0D(MCE, v); + vmx_store_cpu_guest_regs(v, regs, NULL); + do_machine_check(regs); + break; default: goto exit_and_crash; } diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index c26fde22f9..7ba2abc40d 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -86,6 +86,7 @@ asmlinkage void _name(void); \ asmlinkage int do_ ## _name(struct cpu_user_regs *regs) asmlinkage void nmi(void); +asmlinkage void machine_check(void); DECLARE_TRAP_HANDLER(divide_error); DECLARE_TRAP_HANDLER(debug); DECLARE_TRAP_HANDLER(int3); @@ -103,7 +104,6 @@ DECLARE_TRAP_HANDLER(coprocessor_error); DECLARE_TRAP_HANDLER(simd_coprocessor_error); DECLARE_TRAP_HANDLER(alignment_check); DECLARE_TRAP_HANDLER(spurious_interrupt_bug); -DECLARE_TRAP_HANDLER(machine_check); long do_set_debugreg(int reg, unsigned long value); unsigned long do_get_debugreg(int reg); @@ -731,10 +731,11 @@ asmlinkage int do_int3(struct cpu_user_regs *regs) return do_guest_trap(TRAP_int3, regs, 0); } -asmlinkage int do_machine_check(struct cpu_user_regs *regs) +asmlinkage void do_machine_check(struct cpu_user_regs *regs) { - fatal_trap(TRAP_machine_check, regs); - return 0; + extern fastcall void (*machine_check_vector)( + struct cpu_user_regs *, long error_code); + machine_check_vector(regs, regs->error_code); } void propagate_page_fault(unsigned long addr, u16 error_code) diff --git a/xen/arch/x86/x86_32/entry.S b/xen/arch/x86/x86_32/entry.S index 26769fa67e..06eda7bff1 100644 --- a/xen/arch/x86/x86_32/entry.S +++ b/xen/arch/x86/x86_32/entry.S @@ -534,10 +534,6 @@ ENTRY(page_fault) movw $TRAP_page_fault,2(%esp) jmp handle_exception -ENTRY(machine_check) - pushl $TRAP_machine_check<<16 - jmp handle_exception - ENTRY(spurious_interrupt_bug) pushl $TRAP_spurious_int<<16 jmp handle_exception @@ -550,18 +546,20 @@ ENTRY(early_page_fault) addl $4,%esp jmp restore_all_xen -ENTRY(nmi) +handle_nmi_mce: #ifdef CONFIG_X86_SUPERVISOR_MODE_KERNEL - # NMI entry protocol is incompatible with guest kernel in ring 0. + # NMI/MCE entry protocol is incompatible with guest kernel in ring 0. + addl $4,%esp iret #else # Save state but do not trash the segment registers! - pushl $TRAP_nmi<<16 - SAVE_ALL(.Lnmi_xen,.Lnmi_common) -.Lnmi_common: - movl %esp,%eax - pushl %eax - call do_nmi + SAVE_ALL(.Lnmi_mce_xen,.Lnmi_mce_common) +.Lnmi_mce_common: + xorl %eax,%eax + movw UREGS_entry_vector(%esp),%ax + movl %esp,%edx + pushl %edx + call *exception_table(,%eax,4) addl $4,%esp /* * NB. We may return to Xen context with polluted %ds/%es. But in such @@ -569,13 +567,13 @@ ENTRY(nmi) * be detected by SAVE_ALL(), or we have rolled back restore_guest. */ jmp ret_from_intr -.Lnmi_xen: +.Lnmi_mce_xen: /* Check the outer (guest) context for %ds/%es state validity. */ GET_GUEST_REGS(%ebx) testl $X86_EFLAGS_VM,%ss:UREGS_eflags(%ebx) mov %ds,%eax mov %es,%edx - jnz .Lnmi_vm86 + jnz .Lnmi_mce_vm86 /* We may have interrupted Xen while messing with %ds/%es... */ cmpw %ax,%cx mov %ecx,%ds /* Ensure %ds is valid */ @@ -587,19 +585,27 @@ ENTRY(nmi) movl $.Lrestore_sregs_guest,%ecx movl %edx,UREGS_es(%ebx) /* Ensure guest frame contains guest ES */ cmpl %ecx,UREGS_eip(%esp) - jbe .Lnmi_common + jbe .Lnmi_mce_common cmpl $.Lrestore_iret_guest,UREGS_eip(%esp) - ja .Lnmi_common + ja .Lnmi_mce_common /* Roll outer context restore_guest back to restoring %ds/%es. */ movl %ecx,UREGS_eip(%esp) - jmp .Lnmi_common -.Lnmi_vm86: + jmp .Lnmi_mce_common +.Lnmi_mce_vm86: /* vm86 is easy: the CPU saved %ds/%es so we can safely stomp them. */ mov %ecx,%ds mov %ecx,%es - jmp .Lnmi_common + jmp .Lnmi_mce_common #endif /* !CONFIG_X86_SUPERVISOR_MODE_KERNEL */ +ENTRY(nmi) + pushl $TRAP_nmi<<16 + jmp handle_nmi_mce + +ENTRY(machine_check) + pushl $TRAP_machine_check<<16 + jmp handle_nmi_mce + ENTRY(setup_vm86_frame) mov %ecx,%ds mov %ecx,%es @@ -620,7 +626,7 @@ ENTRY(setup_vm86_frame) ENTRY(exception_table) .long do_divide_error .long do_debug - .long 0 # nmi + .long do_nmi .long do_int3 .long do_overflow .long do_bounds diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S index 2d47c3a305..3c586ae52d 100644 --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -505,11 +505,6 @@ ENTRY(page_fault) movl $TRAP_page_fault,4(%rsp) jmp handle_exception -ENTRY(machine_check) - pushq $0 - movl $TRAP_machine_check,4(%rsp) - jmp handle_exception - ENTRY(spurious_interrupt_bug) pushq $0 movl $TRAP_spurious_int,4(%rsp) @@ -527,31 +522,38 @@ ENTRY(early_page_fault) call do_early_page_fault jmp restore_all_xen -ENTRY(nmi) - pushq $0 +handle_ist_exception: SAVE_ALL testb $3,UREGS_cs(%rsp) - jz nmi_in_hypervisor_mode + jz 1f /* Interrupted guest context. Copy the context to stack bottom. */ - GET_GUEST_REGS(%rbx) + GET_GUEST_REGS(%rdi) + movq %rsp,%rsi movl $UREGS_kernel_sizeof/8,%ecx -1: popq %rax - movq %rax,(%rbx) - addq $8,%rbx - loop 1b - subq $UREGS_kernel_sizeof,%rbx - movq %rbx,%rsp -nmi_in_hypervisor_mode: - movq %rsp,%rdi - call do_nmi + movq %rdi,%rsp + rep movsq +1: movq %rsp,%rdi + movl UREGS_entry_vector(%rsp),%eax + leaq exception_table(%rip),%rdx + callq *(%rdx,%rax,8) jmp ret_from_intr +ENTRY(nmi) + pushq $0 + movl $TRAP_nmi,4(%rsp) + jmp handle_ist_exception + +ENTRY(machine_check) + pushq $0 + movl $TRAP_machine_check,4(%rsp) + jmp handle_ist_exception + .data ENTRY(exception_table) .quad do_divide_error .quad do_debug - .quad 0 # nmi + .quad do_nmi .quad do_int3 .quad do_overflow .quad do_bounds diff --git a/xen/arch/x86/x86_64/traps.c b/xen/arch/x86/x86_64/traps.c index 6b14040a14..cd45d756cf 100644 --- a/xen/arch/x86/x86_64/traps.c +++ b/xen/arch/x86/x86_64/traps.c @@ -294,8 +294,9 @@ void __init percpu_traps_init(void) { /* Specify dedicated interrupt stacks for NMIs and double faults. */ set_intr_gate(TRAP_double_fault, &double_fault); - idt_table[TRAP_double_fault].a |= 1UL << 32; /* IST1 */ - idt_table[TRAP_nmi].a |= 2UL << 32; /* IST2 */ + idt_table[TRAP_double_fault].a |= 1UL << 32; /* IST1 */ + idt_table[TRAP_nmi].a |= 2UL << 32; /* IST2 */ + idt_table[TRAP_machine_check].a |= 3UL << 32; /* IST3 */ /* * The 32-on-64 hypercall entry vector is only accessible from ring 1. @@ -310,7 +311,10 @@ void __init percpu_traps_init(void) stack_bottom = (char *)get_stack_bottom(); stack = (char *)((unsigned long)stack_bottom & ~(STACK_SIZE - 1)); - /* Double-fault handler has its own per-CPU 2kB stack. */ + /* Machine Check handler has its own per-CPU 1kB stack. */ + init_tss[cpu].ist[2] = (unsigned long)&stack[1024]; + + /* Double-fault handler has its own per-CPU 1kB stack. */ init_tss[cpu].ist[0] = (unsigned long)&stack[2048]; /* NMI handler has its own per-CPU 1kB stack. */ diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index 203427593e..5fc6a338a7 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -302,4 +302,11 @@ static inline int hvm_event_injection_faulted(struct vcpu *v) return hvm_funcs.event_injection_faulted(v); } +/* These bits in the CR4 are owned by the host */ +#define HVM_CR4_HOST_MASK (mmu_cr4_features & \ + (X86_CR4_VMXE | X86_CR4_PAE | X86_CR4_MCE)) + +/* These exceptions must always be intercepted. */ +#define HVM_TRAP_MASK (1U << TRAP_machine_check) + #endif /* __ASM_X86_HVM_HVM_H__ */ diff --git a/xen/include/asm-x86/hvm/svm/vmcb.h b/xen/include/asm-x86/hvm/svm/vmcb.h index 95a7756738..afea99d7b9 100644 --- a/xen/include/asm-x86/hvm/svm/vmcb.h +++ b/xen/include/asm-x86/hvm/svm/vmcb.h @@ -464,14 +464,6 @@ void svm_destroy_vmcb(struct vcpu *v); void setup_vmcb_dump(void); -/* These bits in the CR4 are owned by the host */ -#if CONFIG_PAGING_LEVELS >= 3 -#define SVM_CR4_HOST_MASK (X86_CR4_PAE) -#else -#define SVM_CR4_HOST_MASK 0 -#endif - - #endif /* ASM_X86_HVM_SVM_VMCS_H__ */ /* diff --git a/xen/include/asm-x86/hvm/trace.h b/xen/include/asm-x86/hvm/trace.h index a48605b359..740d1d1108 100644 --- a/xen/include/asm-x86/hvm/trace.h +++ b/xen/include/asm-x86/hvm/trace.h @@ -21,6 +21,7 @@ #define DO_TRC_HVM_CPUID 1 #define DO_TRC_HVM_INTR 1 #define DO_TRC_HVM_NMI 1 +#define DO_TRC_HVM_MCE 1 #define DO_TRC_HVM_SMI 1 #define DO_TRC_HVM_VMMCALL 1 #define DO_TRC_HVM_HLT 1 diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h index f42d6f34a4..157f7ba31a 100644 --- a/xen/include/asm-x86/hvm/vmx/vmx.h +++ b/xen/include/asm-x86/hvm/vmx/vmx.h @@ -143,13 +143,6 @@ void vmx_vlapic_msr_changed(struct vcpu *v); #define X86_SEG_AR_GRANULARITY (1u << 15) /* 15, granularity */ #define X86_SEG_AR_SEG_UNUSABLE (1u << 16) /* 16, segment unusable */ -/* These bits in the CR4 are owned by the host */ -#if CONFIG_PAGING_LEVELS >= 3 -#define VMX_CR4_HOST_MASK (X86_CR4_VMXE | X86_CR4_PAE) -#else -#define VMX_CR4_HOST_MASK (X86_CR4_VMXE) -#endif - #define VMCALL_OPCODE ".byte 0x0f,0x01,0xc1\n" #define VMCLEAR_OPCODE ".byte 0x66,0x0f,0xc7\n" /* reg/opcode: /6 */ #define VMLAUNCH_OPCODE ".byte 0x0f,0x01,0xc2\n" diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index 419c35db62..6a44e505d0 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -566,7 +566,8 @@ void compat_show_guest_stack(struct cpu_user_regs *, int lines); extern void mtrr_ap_init(void); extern void mtrr_bp_init(void); -extern void mcheck_init(struct cpuinfo_x86 *c); +void mcheck_init(struct cpuinfo_x86 *c); +asmlinkage void do_machine_check(struct cpu_user_regs *regs); int cpuid_hypervisor_leaves( uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); diff --git a/xen/include/public/trace.h b/xen/include/public/trace.h index bc34abe3ce..33654e458e 100644 --- a/xen/include/public/trace.h +++ b/xen/include/public/trace.h @@ -88,6 +88,7 @@ #define TRC_HVM_VMMCALL (TRC_HVM_HANDLER + 0x12) #define TRC_HVM_HLT (TRC_HVM_HANDLER + 0x13) #define TRC_HVM_INVLPG (TRC_HVM_HANDLER + 0x14) +#define TRC_HVM_MCE (TRC_HVM_HANDLER + 0x15) /* This structure represents a single trace buffer record. */ struct t_rec { From 5408361cc6d15d7dabdc263c749b8053e8f9b03d Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 21 Jun 2007 15:17:31 +0100 Subject: [PATCH 15/45] hvm svm: No guest access to SVM MSRs. Signed-off-by: Mats Petersson --- xen/arch/x86/hvm/svm/svm.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index ca259286d2..82e1bad024 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -2086,9 +2086,11 @@ static inline void svm_do_msr_access( case MSR_IA32_TIME_STAMP_COUNTER: msr_content = hvm_get_guest_time(v); break; + case MSR_IA32_APICBASE: msr_content = vcpu_vlapic(v)->hw.apic_base_msr; break; + case MSR_EFER: msr_content = v->arch.hvm_svm.cpu_shadow_efer; break; @@ -2110,6 +2112,10 @@ static inline void svm_do_msr_access( msr_content = 0; break; + case MSR_K8_VM_HSAVE_PA: + svm_inject_exception(v, TRAP_gp_fault, 1, 0); + break; + default: if ( rdmsr_hypervisor_regs(ecx, &eax, &edx) || rdmsr_safe(ecx, eax, edx) == 0 ) @@ -2143,9 +2149,15 @@ static inline void svm_do_msr_access( hvm_set_guest_time(v, msr_content); pt_reset(v); break; + case MSR_IA32_APICBASE: vlapic_msr_set(vcpu_vlapic(v), msr_content); break; + + case MSR_K8_VM_HSAVE_PA: + svm_inject_exception(v, TRAP_gp_fault, 1, 0); + break; + default: if ( !long_mode_do_msr_write(regs) ) wrmsr_hypervisor_regs(ecx, regs->eax, regs->edx); From d127010888b19e06ecdf3fe33d7876eb09072121 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 21 Jun 2007 18:02:50 +0100 Subject: [PATCH 16/45] Fix x86/64 failsafe callback handling. Signed-off-by: Keir Fraser --- xen/arch/x86/x86_64/compat/entry.S | 10 +++++----- xen/arch/x86/x86_64/entry.S | 22 +++++++++++----------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S index 44c037bd33..fed4f66e98 100644 --- a/xen/arch/x86/x86_64/compat/entry.S +++ b/xen/arch/x86/x86_64/compat/entry.S @@ -143,12 +143,12 @@ compat_restore_all_guest: .Lft0: iretq .section .fixup,"ax" -.Lfx0: popq -15*8-8(%rsp) # error_code/entry_vector - SAVE_ALL # 15*8 bytes pushed - movq -8(%rsp),%rsi # error_code/entry_vector - sti # after stack abuse (-1024(%rsp)) +.Lfx0: sti + SAVE_ALL + movq UREGS_error_code(%rsp),%rsi + movq %rsp,%rax + andq $~0xf,%rsp pushq $__HYPERVISOR_DS # SS - leaq 8(%rsp),%rax pushq %rax # RSP pushfq # RFLAGS pushq $__HYPERVISOR_CS # CS diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S index 3c586ae52d..b51c5d494b 100644 --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -57,23 +57,23 @@ restore_all_guest: /* No special register assumptions. */ iret_exit_to_guest: addq $8,%rsp -.Lft1: iretq +.Lft0: iretq .section .fixup,"ax" -.Lfx1: popq -15*8-8(%rsp) # error_code/entry_vector - SAVE_ALL # 15*8 bytes pushed - movq -8(%rsp),%rsi # error_code/entry_vector - sti # after stack abuse (-1024(%rsp)) +.Lfx0: sti + SAVE_ALL + movq UREGS_error_code(%rsp),%rsi + movq %rsp,%rax + andq $~0xf,%rsp pushq $__HYPERVISOR_DS # SS - leaq 8(%rsp),%rax pushq %rax # RSP - pushf # RFLAGS + pushfq # RFLAGS pushq $__HYPERVISOR_CS # CS - leaq .Ldf1(%rip),%rax + leaq .Ldf0(%rip),%rax pushq %rax # RIP pushq %rsi # error_code/entry_vector jmp handle_exception -.Ldf1: GET_CURRENT(%rbx) +.Ldf0: GET_CURRENT(%rbx) jmp test_all_events failsafe_callback: GET_CURRENT(%rbx) @@ -88,10 +88,10 @@ failsafe_callback: jmp test_all_events .previous .section __pre_ex_table,"a" - .quad .Lft1,.Lfx1 + .quad .Lft0,.Lfx0 .previous .section __ex_table,"a" - .quad .Ldf1,failsafe_callback + .quad .Ldf0,failsafe_callback .previous ALIGN From e5417ae6f97aeb2b6c35b2e8de2b7b9f237ded62 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 21 Jun 2007 21:36:26 +0100 Subject: [PATCH 17/45] i386: Simplify failsafe callback handling. Signed-off-by: Keir Fraser --- xen/arch/x86/x86_32/entry.S | 14 +++----------- xen/include/asm-x86/x86_32/asm_defns.h | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/xen/arch/x86/x86_32/entry.S b/xen/arch/x86/x86_32/entry.S index 06eda7bff1..8ca596e15f 100644 --- a/xen/arch/x86/x86_32/entry.S +++ b/xen/arch/x86/x86_32/entry.S @@ -99,17 +99,9 @@ restore_all_guest: .Lrestore_iret_guest: .Lft5: iret .section .fixup,"ax" -.Lfx1: subl $28,%esp - pushl 28(%esp) # error_code/entry_vector - movl %eax,UREGS_eax+4(%esp) - movl %ebp,UREGS_ebp+4(%esp) - movl %edi,UREGS_edi+4(%esp) - movl %esi,UREGS_esi+4(%esp) - movl %edx,UREGS_edx+4(%esp) - movl %ecx,UREGS_ecx+4(%esp) - movl %ebx,UREGS_ebx+4(%esp) - sti - popl %esi +.Lfx1: sti + SAVE_ALL_GPRS + mov UREGS_error_code(%esp),%esi pushfl # EFLAGS movl $__HYPERVISOR_CS,%eax pushl %eax # CS diff --git a/xen/include/asm-x86/x86_32/asm_defns.h b/xen/include/asm-x86/x86_32/asm_defns.h index c12039e910..6bf7e2c619 100644 --- a/xen/include/asm-x86/x86_32/asm_defns.h +++ b/xen/include/asm-x86/x86_32/asm_defns.h @@ -26,6 +26,17 @@ #define ASSERT_INTERRUPTS_ENABLED ASSERT_INTERRUPT_STATUS(nz) #define ASSERT_INTERRUPTS_DISABLED ASSERT_INTERRUPT_STATUS(z) +#define SAVE_ALL_GPRS \ + cld; \ + pushl %eax; \ + pushl %ebp; \ + SETUP_EXCEPTION_FRAME_POINTER; \ + pushl %edi; \ + pushl %esi; \ + pushl %edx; \ + pushl %ecx; \ + pushl %ebx + /* * Saves all register state into an exception/interrupt stack frame. * Returns to the caller at if the interrupted context is within @@ -36,15 +47,7 @@ * the caller is reponsible for validity of %ds/%es. */ #define SAVE_ALL(xen_lbl, vm86_lbl) \ - cld; \ - pushl %eax; \ - pushl %ebp; \ - SETUP_EXCEPTION_FRAME_POINTER; \ - pushl %edi; \ - pushl %esi; \ - pushl %edx; \ - pushl %ecx; \ - pushl %ebx; \ + SAVE_ALL_GPRS; \ testl $(X86_EFLAGS_VM),UREGS_eflags(%esp); \ mov %ds,%edi; \ mov %es,%esi; \ From 837eceb66757cfb3ae1bb961e1310a9a03dd2eaa Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 25 Jun 2007 16:52:39 +0100 Subject: [PATCH 18/45] ioemu: Fix ifdef __x86_64__ Signed-off-by: Keir Fraser --- tools/ioemu/target-i386-dm/exec-dm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ioemu/target-i386-dm/exec-dm.c b/tools/ioemu/target-i386-dm/exec-dm.c index 50df679873..dc4c227355 100644 --- a/tools/ioemu/target-i386-dm/exec-dm.c +++ b/tools/ioemu/target-i386-dm/exec-dm.c @@ -448,7 +448,7 @@ static void memcpy_words(void *dst, void *src, size_t n) { asm ( " movl %%edx,%%ecx \n" -#ifdef __x86_64 +#ifdef __x86_64__ " shrl $3,%%ecx \n" " andl $7,%%edx \n" " rep movsq \n" From b1b322eb8b57b4a0f797fab3a533bddc60d782b4 Mon Sep 17 00:00:00 2001 From: Steven Hand Date: Tue, 26 Jun 2007 12:40:37 +0100 Subject: [PATCH 19/45] Deinitialize timers before destroying the local apic; this protects us against a late firing timer callback function (e.g. hpet_timer_fn) which tries to access local APIC state. Signed-off-by: Steven Hand --- xen/arch/x86/hvm/hvm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 570181e523..2d730f6682 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -423,12 +423,6 @@ void hvm_vcpu_destroy(struct vcpu *v) { struct domain *d = v->domain; - vlapic_destroy(v); - hvm_funcs.vcpu_destroy(v); - - /* Event channel is already freed by evtchn_destroy(). */ - /*free_xen_event_channel(v, v->arch.hvm_vcpu.xen_port);*/ - if ( v->vcpu_id == 0 ) { /* NB. All these really belong in hvm_domain_destroy(). */ @@ -437,6 +431,12 @@ void hvm_vcpu_destroy(struct vcpu *v) pmtimer_deinit(d); hpet_deinit(d); } + + vlapic_destroy(v); + hvm_funcs.vcpu_destroy(v); + + /* Event channel is already freed by evtchn_destroy(). */ + /*free_xen_event_channel(v, v->arch.hvm_vcpu.xen_port);*/ } From 774dab5320b405b32391705a2b54f710209f6ef6 Mon Sep 17 00:00:00 2001 From: Tim Deegan Date: Tue, 26 Jun 2007 17:54:10 +0100 Subject: [PATCH 20/45] [VMX] Set up GUEST_CR0 as well as CR0_READ_SHADOW when restoring saved vcpus. Also simplify the CR3 reload path. Signed-off-by: Tim Deegan --- xen/arch/x86/hvm/vmx/vmx.c | 39 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index e958bc292f..dccf27515f 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -560,6 +560,9 @@ int vmx_vmcs_restore(struct vcpu *v, struct hvm_hw_cpu *c) __vmwrite(GUEST_RSP, c->rsp); __vmwrite(GUEST_RFLAGS, c->rflags); + v->arch.hvm_vmx.cpu_cr0 = (c->cr0 | X86_CR0_PE | X86_CR0_PG + | X86_CR0_NE | X86_CR0_WP | X86_CR0_ET); + __vmwrite(GUEST_CR0, v->arch.hvm_vmx.cpu_cr0); v->arch.hvm_vmx.cpu_shadow_cr0 = c->cr0; __vmwrite(CR0_READ_SHADOW, v->arch.hvm_vmx.cpu_shadow_cr0); @@ -577,33 +580,17 @@ int vmx_vmcs_restore(struct vcpu *v, struct hvm_hw_cpu *c) goto skip_cr3; } - if (c->cr3 == v->arch.hvm_vmx.cpu_cr3) { - /* - * This is simple TLB flush, implying the guest has - * removed some translation or changed page attributes. - * We simply invalidate the shadow. - */ - mfn = gmfn_to_mfn(v->domain, c->cr3 >> PAGE_SHIFT); - if (mfn != pagetable_get_pfn(v->arch.guest_table)) { - goto bad_cr3; - } - } else { - /* - * If different, make a shadow. Check if the PDBR is valid - * first. - */ - HVM_DBG_LOG(DBG_LEVEL_VMMU, "CR3 c->cr3 = %"PRIx64, c->cr3); - /* current!=vcpu as not called by arch_vmx_do_launch */ - mfn = gmfn_to_mfn(v->domain, c->cr3 >> PAGE_SHIFT); - if( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), v->domain)) { - goto bad_cr3; - } - old_base_mfn = pagetable_get_pfn(v->arch.guest_table); - v->arch.guest_table = pagetable_from_pfn(mfn); - if (old_base_mfn) - put_page(mfn_to_page(old_base_mfn)); - v->arch.hvm_vmx.cpu_cr3 = c->cr3; + HVM_DBG_LOG(DBG_LEVEL_VMMU, "CR3 c->cr3 = %"PRIx64, c->cr3); + /* current!=vcpu as not called by arch_vmx_do_launch */ + mfn = gmfn_to_mfn(v->domain, c->cr3 >> PAGE_SHIFT); + if( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), v->domain)) { + goto bad_cr3; } + old_base_mfn = pagetable_get_pfn(v->arch.guest_table); + v->arch.guest_table = pagetable_from_pfn(mfn); + if (old_base_mfn) + put_page(mfn_to_page(old_base_mfn)); + v->arch.hvm_vmx.cpu_cr3 = c->cr3; skip_cr3: #if defined(__x86_64__) From 76d84e88e052c90cd5ea5508ff9ccfdd894993b9 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 27 Jun 2007 19:59:21 +0100 Subject: [PATCH 21/45] Remove incorrect __init prefixes Following functions can be __init in Linux, however shouldn't in Xen. __print_IO_APIC is called by keyhandler, while setup_ioapic_dest is invoked in one platform hypercall. Signed-off-by Kevin Tian --- xen/arch/x86/io_apic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c index 5aff60f52b..5f4665238b 100644 --- a/xen/arch/x86/io_apic.c +++ b/xen/arch/x86/io_apic.c @@ -371,7 +371,7 @@ static int pin_2_irq(int idx, int apic, int pin); * so mask in all cases should simply be TARGET_CPUS */ #ifdef CONFIG_SMP -void __init setup_ioapic_dest(void) +void /*__init*/ setup_ioapic_dest(void) { int pin, ioapic, irq, irq_entry; @@ -849,7 +849,7 @@ static inline void UNEXPECTED_IO_APIC(void) { } -void __init __print_IO_APIC(void) +void /*__init*/ __print_IO_APIC(void) { int apic, i; union IO_APIC_reg_00 reg_00; From 5ba704e7172b26b3dedb431f8180af3d7dcbed70 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 27 Jun 2007 20:00:50 +0100 Subject: [PATCH 22/45] x86: remove unused nopaging_gdt_descr Signed-off-by: Kevin Tian --- xen/arch/x86/boot/x86_32.S | 5 ----- 1 file changed, 5 deletions(-) diff --git a/xen/arch/x86/boot/x86_32.S b/xen/arch/x86/boot/x86_32.S index 4119d6ee1f..b876a7fd09 100644 --- a/xen/arch/x86/boot/x86_32.S +++ b/xen/arch/x86/boot/x86_32.S @@ -80,11 +80,6 @@ gdt_descr: .word LAST_RESERVED_GDT_BYTE .long gdt_table - FIRST_RESERVED_GDT_BYTE - .word 0 -nopaging_gdt_descr: - .word LAST_RESERVED_GDT_BYTE - .long sym_phys(gdt_table) - FIRST_RESERVED_GDT_BYTE - .align PAGE_SIZE, 0 /* NB. Rings != 0 get access up to MACH2PHYS_VIRT_END. This allows access to */ /* the machine->physical mapping table. Ring 0 can access all memory. */ From 78e2e202db32ff0a47772c30a3430f01d4312844 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 27 Jun 2007 20:08:21 +0100 Subject: [PATCH 23/45] Fix VMX guest can't boot after MCE enabled. Signed-off-by: Xin Li --- xen/arch/x86/hvm/vmx/vmx.c | 9 +++++---- xen/include/asm-x86/processor.h | 6 ++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index dccf27515f..2c5d4eb35b 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -2387,14 +2387,15 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs) case 4: /* CR4 */ old_cr = v->arch.hvm_vmx.cpu_shadow_cr4; - if ( value & ~mmu_cr4_features ) + if ( value & X86_CR4_RESERVED_BITS ) { - HVM_DBG_LOG(DBG_LEVEL_1, "Guest attempts to enable unsupported " - "CR4 features %lx (host %lx)", - value, mmu_cr4_features); + HVM_DBG_LOG(DBG_LEVEL_1, + "Guest attempts to set reserved bit in CR4: %lx", + value); vmx_inject_hw_exception(v, TRAP_gp_fault, 0); break; } + if ( (value & X86_CR4_PAE) && !(old_cr & X86_CR4_PAE) ) { if ( vmx_pgbit_test(v) ) diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index 6a44e505d0..2d79337f8a 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -81,6 +81,12 @@ #define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */ #define X86_CR4_VMXE 0x2000 /* enable VMX */ +#define X86_CR4_RESERVED_BITS \ + ~(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | \ + X86_CR4_DE | X86_CR4_PSE | X86_CR4_PAE | \ + X86_CR4_MCE | X86_CR4_PGE | X86_CR4_PCE | \ + X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE) + /* * Trap/fault mnemonics. */ From 748338bb07903ba8c89457866418e4ab37c22c90 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 27 Jun 2007 20:17:54 +0100 Subject: [PATCH 24/45] hvm: Sync SVM CR4 handling with VMX. Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/svm/svm.c | 8 ++++---- xen/arch/x86/hvm/vmx/vmx.c | 2 +- xen/include/asm-x86/hvm/hvm.h | 9 ++++++++- xen/include/asm-x86/processor.h | 6 ------ 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 82e1bad024..e3ac5233b6 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -1828,11 +1828,11 @@ static int mov_to_cr(int gpreg, int cr, struct cpu_user_regs *regs) break; case 4: /* CR4 */ - if ( value & ~mmu_cr4_features ) + if ( value & HVM_CR4_GUEST_RESERVED_BITS ) { - HVM_DBG_LOG(DBG_LEVEL_1, "Guest attempts to enable unsupported " - "CR4 features %lx (host %lx)", - value, mmu_cr4_features); + HVM_DBG_LOG(DBG_LEVEL_1, + "Guest attempts to set reserved bit in CR4: %lx", + value); svm_inject_exception(v, TRAP_gp_fault, 1, 0); break; } diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 2c5d4eb35b..0f361b5877 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -2387,7 +2387,7 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs) case 4: /* CR4 */ old_cr = v->arch.hvm_vmx.cpu_shadow_cr4; - if ( value & X86_CR4_RESERVED_BITS ) + if ( value & HVM_CR4_GUEST_RESERVED_BITS ) { HVM_DBG_LOG(DBG_LEVEL_1, "Guest attempts to set reserved bit in CR4: %lx", diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index 5fc6a338a7..12cfcefdb0 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -302,10 +302,17 @@ static inline int hvm_event_injection_faulted(struct vcpu *v) return hvm_funcs.event_injection_faulted(v); } -/* These bits in the CR4 are owned by the host */ +/* These bits in CR4 are owned by the host. */ #define HVM_CR4_HOST_MASK (mmu_cr4_features & \ (X86_CR4_VMXE | X86_CR4_PAE | X86_CR4_MCE)) +/* These bits in CR4 cannot be set by the guest. */ +#define HVM_CR4_GUEST_RESERVED_BITS \ + ~(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | \ + X86_CR4_DE | X86_CR4_PSE | X86_CR4_PAE | \ + X86_CR4_MCE | X86_CR4_PGE | X86_CR4_PCE | \ + X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT) + /* These exceptions must always be intercepted. */ #define HVM_TRAP_MASK (1U << TRAP_machine_check) diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index 2d79337f8a..6a44e505d0 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -81,12 +81,6 @@ #define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */ #define X86_CR4_VMXE 0x2000 /* enable VMX */ -#define X86_CR4_RESERVED_BITS \ - ~(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | \ - X86_CR4_DE | X86_CR4_PSE | X86_CR4_PAE | \ - X86_CR4_MCE | X86_CR4_PGE | X86_CR4_PCE | \ - X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE) - /* * Trap/fault mnemonics. */ From 8d2566713dc369c562f04ac4bc987065b770145e Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 27 Jun 2007 20:53:57 +0100 Subject: [PATCH 25/45] vmx: Make use of VMX_INSTRUCTION_INFO field to obtain the segment register of OUTS Signed-off-by: Weidong Han Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/vmx/vmcs.c | 3 ++ xen/arch/x86/hvm/vmx/vmx.c | 49 +++++++++++++++++++++--------- xen/include/asm-x86/hvm/vmx/vmcs.h | 2 ++ 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index 4c03b31ffc..ea2afdb72e 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -43,6 +43,7 @@ u32 vmx_cpu_based_exec_control __read_mostly; u32 vmx_secondary_exec_control __read_mostly; u32 vmx_vmexit_control __read_mostly; u32 vmx_vmentry_control __read_mostly; +bool_t cpu_has_vmx_ins_outs_instr_info __read_mostly; static u32 vmcs_revision_id __read_mostly; @@ -133,6 +134,7 @@ void vmx_init_vmcs_config(void) vmx_secondary_exec_control = _vmx_secondary_exec_control; vmx_vmexit_control = _vmx_vmexit_control; vmx_vmentry_control = _vmx_vmentry_control; + cpu_has_vmx_ins_outs_instr_info = !!(vmx_msr_high & (1U<<22)); } else { @@ -142,6 +144,7 @@ void vmx_init_vmcs_config(void) BUG_ON(vmx_secondary_exec_control != _vmx_secondary_exec_control); BUG_ON(vmx_vmexit_control != _vmx_vmexit_control); BUG_ON(vmx_vmentry_control != _vmx_vmentry_control); + BUG_ON(cpu_has_vmx_ins_outs_instr_info != !!(vmx_msr_high & (1U<<22))); } /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */ diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 0f361b5877..4d11313b08 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -1466,16 +1466,34 @@ static void vmx_do_invlpg(unsigned long va) paging_invlpg(v, va); } -/* - * get segment for string pio according to guest instruction - */ -static void vmx_str_pio_get_segment(int long_mode, unsigned long eip, - int inst_len, enum x86_segment *seg) +/* Get segment for OUTS according to guest instruction. */ +static enum x86_segment vmx_outs_get_segment( + int long_mode, unsigned long eip, int inst_len) { unsigned char inst[MAX_INST_LEN]; + enum x86_segment seg = x86_seg_ds; int i; extern int inst_copy_from_guest(unsigned char *, unsigned long, int); + if ( likely(cpu_has_vmx_ins_outs_instr_info) ) + { + unsigned int instr_info = __vmread(VMX_INSTRUCTION_INFO); + + /* Get segment register according to bits 17:15. */ + switch ( (instr_info >> 15) & 7 ) + { + case 0: seg = x86_seg_es; break; + case 1: seg = x86_seg_cs; break; + case 2: seg = x86_seg_ss; break; + case 3: seg = x86_seg_ds; break; + case 4: seg = x86_seg_fs; break; + case 5: seg = x86_seg_gs; break; + default: BUG(); + } + + goto out; + } + if ( !long_mode ) eip += __vmread(GUEST_CS_BASE); @@ -1484,7 +1502,7 @@ static void vmx_str_pio_get_segment(int long_mode, unsigned long eip, { gdprintk(XENLOG_ERR, "Get guest instruction failed\n"); domain_crash(current->domain); - return; + goto out; } for ( i = 0; i < inst_len; i++ ) @@ -1501,25 +1519,28 @@ static void vmx_str_pio_get_segment(int long_mode, unsigned long eip, #endif continue; case 0x2e: /* CS */ - *seg = x86_seg_cs; + seg = x86_seg_cs; continue; case 0x36: /* SS */ - *seg = x86_seg_ss; + seg = x86_seg_ss; continue; case 0x26: /* ES */ - *seg = x86_seg_es; + seg = x86_seg_es; continue; case 0x64: /* FS */ - *seg = x86_seg_fs; + seg = x86_seg_fs; continue; case 0x65: /* GS */ - *seg = x86_seg_gs; + seg = x86_seg_gs; continue; case 0x3e: /* DS */ - *seg = x86_seg_ds; + seg = x86_seg_ds; continue; } } + + out: + return seg; } static int vmx_str_pio_check_descriptor(int long_mode, unsigned long eip, @@ -1532,7 +1553,7 @@ static int vmx_str_pio_check_descriptor(int long_mode, unsigned long eip, *base = 0; *limit = 0; if ( seg != x86_seg_es ) - vmx_str_pio_get_segment(long_mode, eip, inst_len, &seg); + seg = vmx_outs_get_segment(long_mode, eip, inst_len); switch ( seg ) { @@ -1578,7 +1599,7 @@ static int vmx_str_pio_check_descriptor(int long_mode, unsigned long eip, } *ar_bytes = __vmread(ar_field); - return !(*ar_bytes & 0x10000); + return !(*ar_bytes & X86_SEG_AR_SEG_UNUSABLE); } diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h b/xen/include/asm-x86/hvm/vmx/vmcs.h index 2513eac43a..25662f1749 100644 --- a/xen/include/asm-x86/hvm/vmx/vmcs.h +++ b/xen/include/asm-x86/hvm/vmx/vmcs.h @@ -131,6 +131,8 @@ extern u32 vmx_vmentry_control; #define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001 extern u32 vmx_secondary_exec_control; +extern bool_t cpu_has_vmx_ins_outs_instr_info; + #define cpu_has_vmx_virtualize_apic_accesses \ (vmx_secondary_exec_control & SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES) #define cpu_has_vmx_tpr_shadow \ From cee3908623186dd5e0bd79f302f65671deea799c Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 27 Jun 2007 20:56:25 +0100 Subject: [PATCH 26/45] vmx: Exclude VMX_PROCBASED_CTL2 from set of MSRs a VMX guest is allowd to access. Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/vmx/vmx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 4d11313b08..b2a01e89ac 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -2601,7 +2601,7 @@ static inline int vmx_do_msr_read(struct cpu_user_regs *regs) case MSR_IA32_APICBASE: msr_content = vcpu_vlapic(v)->hw.apic_base_msr; break; - case MSR_IA32_VMX_BASIC...MSR_IA32_VMX_CR4_FIXED1: + case MSR_IA32_VMX_BASIC...MSR_IA32_VMX_PROCBASED_CTLS2: goto gp_fault; default: if ( long_mode_do_msr_read(regs) ) @@ -2727,7 +2727,7 @@ static inline int vmx_do_msr_write(struct cpu_user_regs *regs) case MSR_IA32_APICBASE: vlapic_msr_set(vcpu_vlapic(v), msr_content); break; - case MSR_IA32_VMX_BASIC...MSR_IA32_VMX_CR4_FIXED1: + case MSR_IA32_VMX_BASIC...MSR_IA32_VMX_PROCBASED_CTLS2: goto gp_fault; default: if ( !long_mode_do_msr_write(regs) ) From 3bc33badf2f2afcb61dca3ee5446e4c13f0c26b4 Mon Sep 17 00:00:00 2001 From: Steven Hand Date: Wed, 27 Jun 2007 21:01:08 +0100 Subject: [PATCH 27/45] Add new sysctl to return runtime information about physical CPU utilization. Signed-off-by: Steven Hadn --- tools/libxc/xc_misc.c | 19 +++++++++++++++++++ tools/libxc/xenctrl.h | 2 ++ xen/common/schedule.c | 8 ++++++-- xen/common/sysctl.c | 32 ++++++++++++++++++++++++++++++++ xen/include/public/sysctl.h | 13 +++++++++++++ 5 files changed, 72 insertions(+), 2 deletions(-) diff --git a/tools/libxc/xc_misc.c b/tools/libxc/xc_misc.c index 987eb0eb13..e17bf7f721 100644 --- a/tools/libxc/xc_misc.c +++ b/tools/libxc/xc_misc.c @@ -109,6 +109,25 @@ int xc_perfc_control(int xc_handle, return rc; } +int xc_cpuinfo(int xc_handle, int max_cpus, uint64_t *info, int *nr_cpus) +{ + int ret; + DECLARE_SYSCTL; + + sysctl.cmd = XEN_SYSCTL_cpuinfo; + sysctl.u.cpuinfo.max_cpus = max_cpus; + set_xen_guest_handle(sysctl.u.cpuinfo.buffer, info); + + if ( (ret = do_sysctl(xc_handle, &sysctl)) != 0 ) + return ret; + + if(nr_cpus) + *nr_cpus = sysctl.u.cpuinfo.nr_cpus; + + return 0; +} + + int xc_hvm_set_pci_intx_level( int xc_handle, domid_t dom, uint8_t domain, uint8_t bus, uint8_t device, uint8_t intx, diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index df71417c7e..26325f0c46 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -479,6 +479,8 @@ int xc_physinfo(int xc_handle, int xc_sched_id(int xc_handle, int *sched_id); +int xc_cpuinfo(int xc_handle, int max_cpus, uint64_t *info, int *nr_cpus); + int xc_domain_setmaxmem(int xc_handle, uint32_t domid, unsigned int max_memkb); diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 7911f5f99c..17443a44f4 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -72,8 +72,12 @@ static inline void vcpu_runstate_change( ASSERT(v->runstate.state != new_state); ASSERT(spin_is_locked(&per_cpu(schedule_data,v->processor).schedule_lock)); - v->runstate.time[v->runstate.state] += - new_entry_time - v->runstate.state_entry_time; + if(unlikely((v->runstate.state_entry_time - new_entry_time) > TIME_SLOP)) + /* Local time on this CPU has been warped */ + v->runstate.time[v->runstate.state] = new_entry_time; + else + v->runstate.time[v->runstate.state] += + new_entry_time - v->runstate.state_entry_time; v->runstate.state_entry_time = new_entry_time; v->runstate.state = new_state; } diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c index 0cba2c1164..28cbf9b71f 100644 --- a/xen/common/sysctl.c +++ b/xen/common/sysctl.c @@ -136,6 +136,38 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl) } break; + case XEN_SYSCTL_cpuinfo: + { + uint32_t i, nr_cpus; + uint64_t idletime; + + nr_cpus = (op->u.cpuinfo.max_cpus > NR_CPUS) ? NR_CPUS : + op->u.cpuinfo.max_cpus; + + for ( i = 0; i < nr_cpus; i++ ) + { + if(!idle_vcpu[i]) + /* XXX: assumes no further CPUs after first missing one */ + break; + + /* somewhat imprecise but should suffice */ + idletime = idle_vcpu[i]->runstate.time[RUNSTATE_running] + + (NOW() - idle_vcpu[i]->runstate.state_entry_time); + if ( copy_to_guest_offset(op->u.cpuinfo.buffer, i, &idletime, 1) ) + { + ret = -EFAULT; + break; + } + } + + op->u.cpuinfo.nr_cpus = i; + ret = 0; + + if( copy_to_guest (u_sysctl, op, 1) ) + ret = -EFAULT; + } + break; + default: ret = arch_do_sysctl(op, u_sysctl); break; diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index e18d7243f6..be20efc4c1 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -152,6 +152,18 @@ struct xen_sysctl_debug_keys { typedef struct xen_sysctl_debug_keys xen_sysctl_debug_keys_t; DEFINE_XEN_GUEST_HANDLE(xen_sysctl_debug_keys_t); +/* Get physical CPU information */ +#define XEN_SYSCTL_cpuinfo 8 +struct xen_sysctl_cpuinfo { + /* IN variables. */ + uint32_t max_cpus; + XEN_GUEST_HANDLE_64(uint64_t) buffer; + /* IN/OUT variables. */ + uint32_t nr_cpus; +}; +typedef struct xen_sysctl_cpuinfo xen_sysctl_cpuinfo_t; +DEFINE_XEN_GUEST_HANDLE(xen_sysctl_cpuinfo_t); + struct xen_sysctl { uint32_t cmd; uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */ @@ -163,6 +175,7 @@ struct xen_sysctl { struct xen_sysctl_perfc_op perfc_op; struct xen_sysctl_getdomaininfolist getdomaininfolist; struct xen_sysctl_debug_keys debug_keys; + struct xen_sysctl_cpuinfo cpuinfo; uint8_t pad[128]; } u; }; From 3f96f21796c6ab5ffec50b70e0457d973eb5d9c2 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 27 Jun 2007 21:05:54 +0100 Subject: [PATCH 28/45] xenconsoled: improve robustness of logfile handling Check the 'log_reload' on every iteration of the select() loop, not just when select() returns EINTR. This is because the log reload signal may have iterrupted a syscall other than select & thus without this change we might miss the reload signal. The second change makes us process the hypervisor logs on every iteration of the loop, not just upon timeouts. This is because if a guest VM were consistently sending some log message and < 1 second period, the select() would never hit the 1 second timeout and thus never process the HV logs. Thanks to Markus Armbruster for pointing out both these edge cases Signed-off-by: Daniel P. Berrange --- tools/console/daemon/io.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c index d67f4c3abd..42015ebc29 100644 --- a/tools/console/daemon/io.c +++ b/tools/console/daemon/io.c @@ -764,27 +764,31 @@ void handle_io(void) /* XXX I wish we didn't have to busy wait for hypervisor logs * but there's no obvious way to get event channel notifications * for new HV log data as we can with guest */ - ret = select(max_fd + 1, &readfds, &writefds, 0, log_hv_fd != -1 ? &timeout : NULL); + ret = select(max_fd + 1, &readfds, &writefds, 0, + log_hv_fd != -1 ? &timeout : NULL); + if (log_reload) { + handle_log_reload(); + log_reload = 0; + } + + /* Abort if select failed, except for EINTR cases + which indicate a possible log reload */ if (ret == -1) { - if (errno == EINTR) { - if (log_reload) { - handle_log_reload(); - log_reload = 0; - } + if (errno == EINTR) continue; - } dolog(LOG_ERR, "Failure in select: %d (%s)", errno, strerror(errno)); break; } - /* Check for timeout */ - if (ret == 0) { - if (log_hv_fd != -1) - handle_hv_logs(); + /* Always process HV logs even if not a timeout */ + if (log_hv_fd != -1) + handle_hv_logs(); + + /* Must not check returned FDSET if it was a timeout */ + if (ret == 0) continue; - } if (FD_ISSET(xs_fileno(xs), &readfds)) handle_xs(); @@ -806,10 +810,14 @@ void handle_io(void) } } - if (log_hv_fd != -1) + if (log_hv_fd != -1) { close(log_hv_fd); - if (xc_handle != -1) + log_hv_fd = -1; + } + if (xc_handle != -1) { xc_interface_close(xc_handle); + xc_handle = -1; + } } /* From 4706b975b068905baf16fbd42d12da825143b25d Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 27 Jun 2007 21:27:51 +0100 Subject: [PATCH 29/45] Small sysctl cleanups. Signed-off-by: Keir Fraser --- xen/common/schedule.c | 8 ++------ xen/common/sysctl.c | 17 +++++++++-------- xen/include/public/sysctl.h | 2 +- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 17443a44f4..7911f5f99c 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -72,12 +72,8 @@ static inline void vcpu_runstate_change( ASSERT(v->runstate.state != new_state); ASSERT(spin_is_locked(&per_cpu(schedule_data,v->processor).schedule_lock)); - if(unlikely((v->runstate.state_entry_time - new_entry_time) > TIME_SLOP)) - /* Local time on this CPU has been warped */ - v->runstate.time[v->runstate.state] = new_entry_time; - else - v->runstate.time[v->runstate.state] += - new_entry_time - v->runstate.state_entry_time; + v->runstate.time[v->runstate.state] += + new_entry_time - v->runstate.state_entry_time; v->runstate.state_entry_time = new_entry_time; v->runstate.state = new_state; } diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c index 28cbf9b71f..16a6b5fb31 100644 --- a/xen/common/sysctl.c +++ b/xen/common/sysctl.c @@ -140,19 +140,20 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl) { uint32_t i, nr_cpus; uint64_t idletime; + struct vcpu *v; - nr_cpus = (op->u.cpuinfo.max_cpus > NR_CPUS) ? NR_CPUS : - op->u.cpuinfo.max_cpus; + nr_cpus = min_t(uint32_t, op->u.cpuinfo.max_cpus, NR_CPUS); for ( i = 0; i < nr_cpus; i++ ) { - if(!idle_vcpu[i]) - /* XXX: assumes no further CPUs after first missing one */ + /* Assume no holes in idle-vcpu map. */ + if ( (v = idle_vcpu[i]) == NULL ) break; - /* somewhat imprecise but should suffice */ - idletime = idle_vcpu[i]->runstate.time[RUNSTATE_running] + - (NOW() - idle_vcpu[i]->runstate.state_entry_time); + idletime = v->runstate.time[RUNSTATE_running]; + if ( v->is_running ) + idletime += NOW() - v->runstate.state_entry_time; + if ( copy_to_guest_offset(op->u.cpuinfo.buffer, i, &idletime, 1) ) { ret = -EFAULT; @@ -163,7 +164,7 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl) op->u.cpuinfo.nr_cpus = i; ret = 0; - if( copy_to_guest (u_sysctl, op, 1) ) + if ( copy_to_guest(u_sysctl, op, 1) ) ret = -EFAULT; } break; diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index be20efc4c1..ef467d1304 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -158,7 +158,7 @@ struct xen_sysctl_cpuinfo { /* IN variables. */ uint32_t max_cpus; XEN_GUEST_HANDLE_64(uint64_t) buffer; - /* IN/OUT variables. */ + /* OUT variables. */ uint32_t nr_cpus; }; typedef struct xen_sysctl_cpuinfo xen_sysctl_cpuinfo_t; From 9ba645fd7db85d46ea47e8020752ad971f233f61 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 27 Jun 2007 21:28:19 +0100 Subject: [PATCH 30/45] By default allow differences between Xen and XenLinux public headers. Signed-off-by: Keir Fraser --- buildconfigs/mk.linux-2.6-xen | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/buildconfigs/mk.linux-2.6-xen b/buildconfigs/mk.linux-2.6-xen index bf5550062b..a0c6916349 100644 --- a/buildconfigs/mk.linux-2.6-xen +++ b/buildconfigs/mk.linux-2.6-xen @@ -28,6 +28,11 @@ _build: build include buildconfigs/src.$(XEN_LINUX_SOURCE) +# Default to allowing interface mismatch +ifndef XEN_LINUX_ALLOW_INTERFACE_MISMATCH +XEN_LINUX_ALLOW_INTERFACE_MISMATCH := y +endif + # The real action starts here! .PHONY: build build: $(LINUX_DIR)/include/linux/autoconf.h From 41b3adc9252a1d70ea1e7a4f67696227adbed2ca Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 27 Jun 2007 21:43:43 +0100 Subject: [PATCH 31/45] More getcpuinfo sysctl cleanup. Signed-off-by: Keir Fraser --- tools/libxc/xc_misc.c | 29 +++++++++++++++++------------ tools/libxc/xenctrl.h | 4 +++- xen/common/sysctl.c | 14 +++++++------- xen/include/public/sysctl.h | 27 +++++++++++++++------------ 4 files changed, 42 insertions(+), 32 deletions(-) diff --git a/tools/libxc/xc_misc.c b/tools/libxc/xc_misc.c index e17bf7f721..85f7921e77 100644 --- a/tools/libxc/xc_misc.c +++ b/tools/libxc/xc_misc.c @@ -101,30 +101,35 @@ int xc_perfc_control(int xc_handle, rc = do_sysctl(xc_handle, &sysctl); - if (nbr_desc) + if ( nbr_desc ) *nbr_desc = sysctl.u.perfc_op.nr_counters; - if (nbr_val) + if ( nbr_val ) *nbr_val = sysctl.u.perfc_op.nr_vals; return rc; } -int xc_cpuinfo(int xc_handle, int max_cpus, uint64_t *info, int *nr_cpus) +int xc_getcpuinfo(int xc_handle, int max_cpus, + xc_cpuinfo_t *info, int *nr_cpus) { - int ret; + int rc; DECLARE_SYSCTL; - sysctl.cmd = XEN_SYSCTL_cpuinfo; - sysctl.u.cpuinfo.max_cpus = max_cpus; - set_xen_guest_handle(sysctl.u.cpuinfo.buffer, info); + sysctl.cmd = XEN_SYSCTL_getcpuinfo; + sysctl.u.getcpuinfo.max_cpus = max_cpus; + set_xen_guest_handle(sysctl.u.getcpuinfo.info, info); - if ( (ret = do_sysctl(xc_handle, &sysctl)) != 0 ) - return ret; + if ( (rc = lock_pages(info, max_cpus*sizeof(*info))) != 0 ) + return rc; - if(nr_cpus) - *nr_cpus = sysctl.u.cpuinfo.nr_cpus; + rc = do_sysctl(xc_handle, &sysctl); - return 0; + unlock_pages(info, max_cpus*sizeof(*info)); + + if ( nr_cpus ) + *nr_cpus = sysctl.u.getcpuinfo.nr_cpus; + + return rc; } diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index 26325f0c46..25def6b9fc 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -479,7 +479,9 @@ int xc_physinfo(int xc_handle, int xc_sched_id(int xc_handle, int *sched_id); -int xc_cpuinfo(int xc_handle, int max_cpus, uint64_t *info, int *nr_cpus); +typedef xen_sysctl_cpuinfo_t xc_cpuinfo_t; +int xc_getcpuinfo(int xc_handle, int max_cpus, + xc_cpuinfo_t *info, int *nr_cpus); int xc_domain_setmaxmem(int xc_handle, uint32_t domid, diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c index 16a6b5fb31..efc7c2fd1a 100644 --- a/xen/common/sysctl.c +++ b/xen/common/sysctl.c @@ -136,13 +136,13 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl) } break; - case XEN_SYSCTL_cpuinfo: + case XEN_SYSCTL_getcpuinfo: { uint32_t i, nr_cpus; - uint64_t idletime; + struct xen_sysctl_cpuinfo cpuinfo; struct vcpu *v; - nr_cpus = min_t(uint32_t, op->u.cpuinfo.max_cpus, NR_CPUS); + nr_cpus = min_t(uint32_t, op->u.getcpuinfo.max_cpus, NR_CPUS); for ( i = 0; i < nr_cpus; i++ ) { @@ -150,18 +150,18 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl) if ( (v = idle_vcpu[i]) == NULL ) break; - idletime = v->runstate.time[RUNSTATE_running]; + cpuinfo.idletime = v->runstate.time[RUNSTATE_running]; if ( v->is_running ) - idletime += NOW() - v->runstate.state_entry_time; + cpuinfo.idletime += NOW() - v->runstate.state_entry_time; - if ( copy_to_guest_offset(op->u.cpuinfo.buffer, i, &idletime, 1) ) + if ( copy_to_guest_offset(op->u.getcpuinfo.info, i, &cpuinfo, 1) ) { ret = -EFAULT; break; } } - op->u.cpuinfo.nr_cpus = i; + op->u.getcpuinfo.nr_cpus = i; ret = 0; if ( copy_to_guest(u_sysctl, op, 1) ) diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index ef467d1304..d51052aefe 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -140,9 +140,7 @@ struct xen_sysctl_getdomaininfolist { typedef struct xen_sysctl_getdomaininfolist xen_sysctl_getdomaininfolist_t; DEFINE_XEN_GUEST_HANDLE(xen_sysctl_getdomaininfolist_t); -/* - * Inject debug keys into Xen. - */ +/* Inject debug keys into Xen. */ #define XEN_SYSCTL_debug_keys 7 struct xen_sysctl_debug_keys { /* IN variables. */ @@ -152,17 +150,22 @@ struct xen_sysctl_debug_keys { typedef struct xen_sysctl_debug_keys xen_sysctl_debug_keys_t; DEFINE_XEN_GUEST_HANDLE(xen_sysctl_debug_keys_t); -/* Get physical CPU information */ -#define XEN_SYSCTL_cpuinfo 8 +/* Get physical CPU information. */ +#define XEN_SYSCTL_getcpuinfo 8 struct xen_sysctl_cpuinfo { - /* IN variables. */ - uint32_t max_cpus; - XEN_GUEST_HANDLE_64(uint64_t) buffer; - /* OUT variables. */ - uint32_t nr_cpus; -}; + uint64_t idletime; +}; typedef struct xen_sysctl_cpuinfo xen_sysctl_cpuinfo_t; DEFINE_XEN_GUEST_HANDLE(xen_sysctl_cpuinfo_t); +struct xen_sysctl_getcpuinfo { + /* IN variables. */ + uint32_t max_cpus; + XEN_GUEST_HANDLE_64(xen_sysctl_cpuinfo_t) info; + /* OUT variables. */ + uint32_t nr_cpus; +}; +typedef struct xen_sysctl_getcpuinfo xen_sysctl_getcpuinfo_t; +DEFINE_XEN_GUEST_HANDLE(xen_sysctl_getcpuinfo_t); struct xen_sysctl { uint32_t cmd; @@ -175,7 +178,7 @@ struct xen_sysctl { struct xen_sysctl_perfc_op perfc_op; struct xen_sysctl_getdomaininfolist getdomaininfolist; struct xen_sysctl_debug_keys debug_keys; - struct xen_sysctl_cpuinfo cpuinfo; + struct xen_sysctl_getcpuinfo getcpuinfo; uint8_t pad[128]; } u; }; From 45b712c3d32f5b0b3d344e9915a78a7d97b27d62 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 27 Jun 2007 22:20:17 +0100 Subject: [PATCH 32/45] hvm: Destroy timers early during domain death. Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/hvm.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 2d730f6682..71ca313f8a 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -242,6 +242,11 @@ void hvm_domain_relinquish_resources(struct domain *d) { hvm_destroy_ioreq_page(d, &d->arch.hvm_domain.ioreq); hvm_destroy_ioreq_page(d, &d->arch.hvm_domain.buf_ioreq); + + pit_deinit(d); + rtc_deinit(d); + pmtimer_deinit(d); + hpet_deinit(d); } void hvm_domain_destroy(struct domain *d) @@ -421,17 +426,6 @@ int hvm_vcpu_initialise(struct vcpu *v) void hvm_vcpu_destroy(struct vcpu *v) { - struct domain *d = v->domain; - - if ( v->vcpu_id == 0 ) - { - /* NB. All these really belong in hvm_domain_destroy(). */ - pit_deinit(d); - rtc_deinit(d); - pmtimer_deinit(d); - hpet_deinit(d); - } - vlapic_destroy(v); hvm_funcs.vcpu_destroy(v); From 4730f5017499c1829f0f457afb84ab1d52d1f409 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 28 Jun 2007 18:40:20 +0100 Subject: [PATCH 33/45] Fix fixup of invalid PTE writes, broken by 13392:0fd65225e4c6. By the time we test if addr is the upper word it has already been aligned to the 8 byte pte size. Signed-off-by: Ian Campbell --- xen/arch/x86/mm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index c86a895819..29bfd5f878 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -3240,6 +3240,7 @@ static int ptwr_emulated_update( struct ptwr_emulate_ctxt *ptwr_ctxt) { unsigned long mfn; + unsigned long unaligned_addr = addr; struct page_info *page; l1_pgentry_t pte, ol1e, nl1e, *pl1e; struct vcpu *v = current; @@ -3294,7 +3295,7 @@ static int ptwr_emulated_update( if ( unlikely(!get_page_from_l1e(nl1e, d)) ) { if ( (CONFIG_PAGING_LEVELS >= 3) && is_pv_32bit_domain(d) && - (bytes == 4) && (addr & 4) && !do_cmpxchg && + (bytes == 4) && (unaligned_addr & 4) && !do_cmpxchg && (l1e_get_flags(nl1e) & _PAGE_PRESENT) ) { /* From 9659b6cb45a1b6f2f4e441f9fe8ac01a5792f1d9 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 28 Jun 2007 20:35:50 +0100 Subject: [PATCH 34/45] xend: Fix irq-permissions setting during domain creation. Signed-off-by: Keir Fraser --- tools/python/xen/xend/server/irqif.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/python/xen/xend/server/irqif.py b/tools/python/xen/xend/server/irqif.py index 346ad7cf4d..7e96726834 100644 --- a/tools/python/xen/xend/server/irqif.py +++ b/tools/python/xen/xend/server/irqif.py @@ -61,7 +61,7 @@ class IRQController(DevController): pirq = get_param('irq') - rc = xc.domain_irq_permission(dom = self.getDomid(), + rc = xc.domain_irq_permission(domid = self.getDomid(), pirq = pirq, allow_access = True) From 1dd1b5a9f6ad61d3a6df79ba66785644115656ad Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Fri, 29 Jun 2007 14:38:18 +0100 Subject: [PATCH 35/45] Add a duplication definition check for devices. This patch adds a duplication definition check for devices. It checks the following definitions. - vbd : uname and device name - vif : mac Signed-off-by: Masaki Kanno --- tools/python/xen/xend/XendConfig.py | 94 ++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 15 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 4bb6dd7857..16ebea6f09 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -28,6 +28,7 @@ from xen.xend.XendDevices import XendDevices from xen.xend.PrettyPrint import prettyprintstring from xen.xend.XendConstants import DOM_STATE_HALTED from xen.xend.server.netif import randomMAC +from xen.util.blkif import blkdev_name_to_number log = logging.getLogger("xend.XendConfig") log.setLevel(logging.WARN) @@ -934,6 +935,55 @@ class XendConfig(dict): return sxpr + def _blkdev_name_to_number(self, dev): + try: + devid = int(dev) + except ValueError: + # devid is not a number but a string containing either device + # name (e.g. xvda) or device_type/device_id (e.g. vbd/51728) + dev2 = type(dev) is str and dev.split('/')[-1] or None + if dev2 == None: + log.debug("Could not check the device %s", dev) + return None + try: + devid = int(dev2) + except ValueError: + devid = blkdev_name_to_number(dev2) + if devid == None: + log.debug("The device %s is not device name", dev2) + return None + return devid + + def device_duplicate_check(self, dev_type, dev_info, defined_config): + defined_devices_sxpr = self.all_devices_sxpr(target = defined_config) + + if dev_type == 'vbd': + dev_uname = dev_info.get('uname') + blkdev_name = dev_info.get('dev') + devid = self._blkdev_name_to_number(blkdev_name) + if devid == None: + return + + for o_dev_type, o_dev_info in defined_devices_sxpr: + if dev_type == o_dev_type: + if dev_uname == sxp.child_value(o_dev_info, 'uname'): + raise XendConfigError('The uname "%s" is already defined' % + dev_uname) + o_blkdev_name = sxp.child_value(o_dev_info, 'dev') + o_devid = self._blkdev_name_to_number(o_blkdev_name) + if o_devid != None and devid == o_devid: + raise XendConfigError('The device "%s" is already defined' % + blkdev_name) + + elif dev_type == 'vif': + dev_mac = dev_info.get('mac') + + for o_dev_type, o_dev_info in defined_devices_sxpr: + if dev_type == o_dev_type: + if dev_mac == sxp.child_value(o_dev_info, 'mac'): + raise XendConfigError('The mac "%s" is already defined' % + dev_mac) + def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None, target = None): """Add a device configuration in SXP format or XenAPI struct format. @@ -998,6 +1048,8 @@ class XendConfig(dict): if not dev_info.get('mac'): dev_info['mac'] = randomMAC() + self.device_duplicate_check(dev_type, dev_info, target) + # create uuid if it doesn't exist dev_uuid = dev_info.get('uuid', None) if not dev_uuid: @@ -1275,15 +1327,19 @@ class XendConfig(dict): return False - def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None): + def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None, target = None): """Get Device SXPR by either giving the device UUID or (type, config). @rtype: list of lists @return: device config sxpr """ sxpr = [] - if dev_uuid != None and dev_uuid in self['devices']: - dev_type, dev_info = self['devices'][dev_uuid] + + if target == None: + target = self + + if dev_uuid != None and dev_uuid in target['devices']: + dev_type, dev_info = target['devices'][dev_uuid] if dev_type == None or dev_info == None: raise XendConfigError("Required either UUID or device type and " @@ -1300,8 +1356,12 @@ class XendConfig(dict): return sxpr - def ordered_device_refs(self): + def ordered_device_refs(self, target = None): result = [] + + if target == None: + target = self + # vkbd devices *must* be before vfb devices, otherwise # there is a race condition when setting up devices # where the daemon spawned for the vfb may write stuff @@ -1309,27 +1369,30 @@ class XendConfig(dict): # setup permissions on the vkbd backend path. This race # results in domain creation failing with 'device already # connected' messages - result.extend([u for u in self['devices'].keys() if self['devices'][u][0] == 'vkbd']) + result.extend([u for u in target['devices'].keys() if target['devices'][u][0] == 'vkbd']) - result.extend(self['console_refs'] + - self['vbd_refs'] + - self['vif_refs'] + - self['vtpm_refs']) + result.extend(target.get('console_refs', []) + + target.get('vbd_refs', []) + + target.get('vif_refs', []) + + target.get('vtpm_refs', [])) - result.extend([u for u in self['devices'].keys() if u not in result]) + result.extend([u for u in target['devices'].keys() if u not in result]) return result - def all_devices_sxpr(self): + def all_devices_sxpr(self, target = None): """Returns the SXPR for all devices in the current configuration.""" sxprs = [] pci_devs = [] - if 'devices' not in self: + if target == None: + target = self + + if 'devices' not in target: return sxprs - ordered_refs = self.ordered_device_refs() + ordered_refs = self.ordered_device_refs(target = target) for dev_uuid in ordered_refs: - dev_type, dev_info = self['devices'][dev_uuid] + dev_type, dev_info = target['devices'][dev_uuid] if dev_type == 'pci': # special case for pci devices sxpr = [['uuid', dev_info['uuid']]] for pci_dev_info in dev_info['devs']: @@ -1340,7 +1403,8 @@ class XendConfig(dict): sxprs.append((dev_type, sxpr)) else: sxpr = self.device_sxpr(dev_type = dev_type, - dev_info = dev_info) + dev_info = dev_info, + target = target) sxprs.append((dev_type, sxpr)) return sxprs From 450f5b5b9e64c3afccc49fdec6af5b768cedaded Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Sun, 1 Jul 2007 22:10:13 +0100 Subject: [PATCH 36/45] xend: Don't allow migrate with assigned PCI devs. This can potentially cause a whole machine crash, which I think has been seen in the wild. The case in the wild was caused by xendomains auto-resuming domains on reboot, so it wasn't even operator error. There's no sane way to migrate or suspend domains with PCI devs, so I disallow it completely. Signed-off-by: Mark Williamson --- tools/python/xen/xend/server/pciif.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/python/xen/xend/server/pciif.py b/tools/python/xen/xend/server/pciif.py index 68af9d78cc..90b2420230 100644 --- a/tools/python/xen/xend/server/pciif.py +++ b/tools/python/xen/xend/server/pciif.py @@ -185,3 +185,6 @@ class PciController(DevController): def waitForBackend(self,devid): return (0, "ok - no hotplug") + + def migrate(self, config, network, dst, step, domName): + raise XendError('Migration not permitted with assigned PCI device.') From c32cff27bab6b78df0ea846bc7ddae3090f3d88a Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Sun, 1 Jul 2007 22:10:38 +0100 Subject: [PATCH 37/45] xend: Pass information to user when failing migrate due to PCI dev. When failing a migration / save due to the domain owning a PCI device make sure that we tell the user what went wrong! Signed-off-by: Mark Williamson --- tools/python/xen/xend/XendCheckpoint.py | 2 ++ tools/python/xen/xend/XendDomain.py | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/python/xen/xend/XendCheckpoint.py b/tools/python/xen/xend/XendCheckpoint.py index 2cfc06a2db..1aa7d7f69d 100644 --- a/tools/python/xen/xend/XendCheckpoint.py +++ b/tools/python/xen/xend/XendCheckpoint.py @@ -148,6 +148,8 @@ def save(fd, dominfo, network, live, dst, checkpoint=False): except: log.exception("Failed to reset the migrating domain's name") + raise exn + def restore(xd, fd, dominfo = None, paused = False): signature = read_exact(fd, len(SIGNATURE), diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 4d082a5ac9..bca5830185 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -1262,8 +1262,10 @@ class XendDomain: try: XendCheckpoint.save(fd, dominfo, False, False, dst, checkpoint=checkpoint) - finally: + except Exception, e: os.close(fd) + raise e + os.close(fd) except OSError, ex: raise XendError("can't write guest state file %s: %s" % (dst, ex[1])) From caa6c26fb32d2d040098eb87c51cb3d9e6efebf4 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Sun, 1 Jul 2007 22:16:41 +0100 Subject: [PATCH 38/45] xendomains: Ignore 'lost+found' when finding saved dom images. Signed-off-by: Gawain Lynch --- tools/examples/init.d/xendomains | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/examples/init.d/xendomains b/tools/examples/init.d/xendomains index 6ad7a9b9e9..0fffd42c80 100644 --- a/tools/examples/init.d/xendomains +++ b/tools/examples/init.d/xendomains @@ -221,11 +221,12 @@ start() if [ "$XENDOMAINS_RESTORE" = "true" ] && contains_something "$XENDOMAINS_SAVE" then - mkdir -p $(dirname "$LOCKFILE") + XENDOMAINS_SAVED=`/bin/ls $XENDOMAINS_SAVE/* | grep -v 'lost+found'` + mkdir -p $(dirname "$LOCKFILE") touch $LOCKFILE echo -n "Restoring Xen domains:" saved_domains=`ls $XENDOMAINS_SAVE` - for dom in $XENDOMAINS_SAVE/*; do + for dom in $XENDOMAINS_SAVED; do echo -n " ${dom##*/}" xm restore $dom if [ $? -ne 0 ]; then @@ -259,6 +260,7 @@ start() if [ $? -eq 0 ] || is_running $dom; then echo -n "(skip)" else + echo "(booting)" xm create --quiet --defconfig $dom if [ $? -ne 0 ]; then rc_failed $? From 883a5de1d274d5cdfd2bd2ee4a62189e6f25a19f Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Sun, 1 Jul 2007 22:18:04 +0100 Subject: [PATCH 39/45] Remove unused VMXAssist test code. Signed-off-by: Xin Li --- tools/firmware/vmxassist/head.S | 76 ------------------------------ tools/firmware/vmxassist/machine.h | 15 ------ tools/firmware/vmxassist/setup.c | 55 --------------------- tools/firmware/vmxassist/vm86.c | 14 +----- 4 files changed, 1 insertion(+), 159 deletions(-) diff --git a/tools/firmware/vmxassist/head.S b/tools/firmware/vmxassist/head.S index 7cb4ec1069..3af285eada 100644 --- a/tools/firmware/vmxassist/head.S +++ b/tools/firmware/vmxassist/head.S @@ -25,81 +25,13 @@ * switch happens to the environment below. The magic indicates * that this is a valid context. */ -#ifdef TEST - .byte 0x55, 0xaa - .byte 0x80 - .code16 - jmp _start16 -#else jmp _start -#endif .align 8 .long VMXASSIST_MAGIC .long newctx /* new context */ .long oldctx /* old context */ -#ifdef TEST -/* - * We are running in 16-bit. Get into the protected mode as soon as - * possible. We use our own (minimal) GDT to get started. - * - * ROM is a misnomer as this code isn't really rommable (although it - * only requires a few changes) but it does live in a BIOS ROM segment. - * This code allows me to debug vmxassists under (a modified version of) - * Bochs and load it as a "optromimage1". - */ - .code16 - .globl _start16 -_start16: - cli - - /* load our own global descriptor table */ - data32 addr32 lgdt %cs:(rom_gdtr - TEXTADDR) - - /* go to protected mode */ - movl %cr0, %eax - orl $(CR0_PE), %eax - movl %eax, %cr0 - data32 ljmp $0x08, $1f - - .align 32 - .globl rom_gdt -rom_gdt: - .word 0, 0 /* 0x00: reserved */ - .byte 0, 0, 0, 0 - - .word 0xFFFF, 0 /* 0x08: CS 32-bit */ - .byte 0, 0x9A, 0xCF, 0 - - .word 0xFFFF, 0 /* 0x10: CS 32-bit */ - .byte 0, 0x92, 0xCF, 0 -rom_gdt_end: - - .align 4 - .globl rom_gdtr -rom_gdtr: - .word rom_gdt_end - rom_gdt - 1 - .long rom_gdt - - .code32 -1: - /* welcome to the 32-bit world */ - movw $0x10, %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %ss - movw %ax, %fs - movw %ax, %gs - - /* enable Bochs debug facilities */ - movw $0x8A00, %dx - movw $0x8A00, %ax - outw %ax, (%dx) - - jmp _start -#endif /* TEST */ - /* * This is the real start. Control was transfered to this point * with CR0_PE set and executing in some 32-bit segment. We call @@ -111,9 +43,6 @@ _start: cli /* save register parameters to C land */ -#ifdef TEST - xorl %edx, %edx -#endif /* clear bss */ cld @@ -145,11 +74,6 @@ _start: halt: push $halt_msg call printf -#ifdef TEST - movw $0x8A00, %dx - movw $0x8AE0, %ax - outw %ax, (%dx) -#endif cli jmp . diff --git a/tools/firmware/vmxassist/machine.h b/tools/firmware/vmxassist/machine.h index cff1fd0c20..788d6748f8 100644 --- a/tools/firmware/vmxassist/machine.h +++ b/tools/firmware/vmxassist/machine.h @@ -56,13 +56,6 @@ #define LPGSIZE (1 << LOG_PDSIZE) /* large page size */ #define LPGMASK (~(LPGSIZE - 1)) /* large page mask */ -#ifdef TEST -#define PTE_P (1 << 0) /* Present */ -#define PTE_RW (1 << 1) /* Read/Write */ -#define PTE_US (1 << 2) /* User/Supervisor */ -#define PTE_PS (1 << 7) /* Page Size */ -#endif - /* Programmable Interrupt Contoller (PIC) defines */ #define PIC_MASTER 0x20 #define PIC_SLAVE 0xA0 @@ -195,14 +188,6 @@ set_cr4(unsigned value) __asm__ __volatile__("movl %0, %%cr4" : /* no outputs */ : "r"(value)); } -#ifdef TEST -static inline void -breakpoint(void) -{ - outw(0x8A00, 0x8AE0); -} -#endif /* TEST */ - #endif /* __ASSEMBLY__ */ #endif /* __MACHINE_H__ */ diff --git a/tools/firmware/vmxassist/setup.c b/tools/firmware/vmxassist/setup.c index bc7c573348..fd03e3c6cb 100644 --- a/tools/firmware/vmxassist/setup.c +++ b/tools/firmware/vmxassist/setup.c @@ -47,19 +47,6 @@ unsigned long long idt[NR_TRAPS] __attribute__ ((aligned(32))); struct dtr idtr = { sizeof(idt)-1, (unsigned long) &idt }; -#ifdef TEST -unsigned pgd[NR_PGD] __attribute__ ((aligned(PGSIZE))) = { 0 }; - -struct e820entry e820map[] = { - { 0x0000000000000000ULL, 0x000000000009F800ULL, E820_RAM }, - { 0x000000000009F800ULL, 0x0000000000000800ULL, E820_RESERVED }, - { 0x00000000000C0000ULL, 0x0000000000040000ULL, E820_RESERVED }, - { 0x0000000000100000ULL, 0x0000000000000000ULL, E820_RAM }, - { 0x0000000000000000ULL, 0x0000000000003000ULL, E820_NVS }, - { 0x0000000000003000ULL, 0x000000000000A000ULL, E820_ACPI }, -}; -#endif /* TEST */ - struct vmx_assist_context oldctx; struct vmx_assist_context newctx; @@ -84,39 +71,12 @@ banner(void) (((get_cmos(0x31) << 8) | get_cmos(0x30)) + 0x400) << 10; memory_size += 0x400 << 10; /* + 1MB */ -#ifdef TEST - /* Create an SMAP for our debug environment */ - e820map[4].size = memory_size - e820map[4].addr - PGSIZE; - e820map[5].addr = memory_size - PGSIZE; - e820map[6].addr = memory_size; - e820map[7].addr += memory_size; - - *HVM_E820_NR = sizeof(e820map)/sizeof(e820map[0]); - memcpy(HVM_E820, e820map, sizeof(e820map)); -#endif - printf("Memory size %ld MB\n", memory_size >> 20); printf("E820 map:\n"); print_e820_map(HVM_E820, *HVM_E820_NR); printf("\n"); } -#ifdef TEST -void -setup_paging(void) -{ - unsigned long i; - - if (((unsigned)pgd & ~PGMASK) != 0) - panic("PGD not page aligned"); - set_cr4(get_cr4() | CR4_PSE); - for (i = 0; i < NR_PGD; i++) - pgd[i] = (i * LPGSIZE)| PTE_PS | PTE_US | PTE_RW | PTE_P; - set_cr3((unsigned) pgd); - set_cr0(get_cr0() | (CR0_PE|CR0_PG)); -} -#endif /* TEST */ - void setup_gdt(void) { @@ -211,11 +171,7 @@ enter_real_mode(struct regs *regs) regs->ves = regs->vds = regs->vfs = regs->vgs = 0xF000; if (booting_cpu == 0) { regs->cs = 0xF000; /* ROM BIOS POST entry point */ -#ifdef TEST - regs->eip = 0xFFE0; -#else regs->eip = 0xFFF0; -#endif } else { regs->cs = booting_vector << 8; /* AP entry point */ regs->eip = 0; @@ -269,13 +225,8 @@ setup_ctx(void) * more natural to enable CR0.PE to cause a world switch to * protected mode rather than disabling it. */ -#ifdef TEST - c->cr0 = (get_cr0() | CR0_NE | CR0_PG) & ~CR0_PE; - c->cr3 = (unsigned long) pgd; -#else c->cr0 = (get_cr0() | CR0_NE) & ~CR0_PE; c->cr3 = 0; -#endif c->cr4 = get_cr4(); c->idtr_limit = sizeof(idt)-1; @@ -369,16 +320,10 @@ main(void) if (booting_cpu == 0) banner(); -#ifdef TEST - setup_paging(); -#endif - setup_gdt(); setup_idt(); -#ifndef TEST set_cr4(get_cr4() | CR4_VME); -#endif setup_ctx(); diff --git a/tools/firmware/vmxassist/vm86.c b/tools/firmware/vmxassist/vm86.c index d702c031cc..357a73e353 100644 --- a/tools/firmware/vmxassist/vm86.c +++ b/tools/firmware/vmxassist/vm86.c @@ -561,11 +561,7 @@ lmsw(struct regs *regs, unsigned prefix, unsigned modrm) unsigned cr0 = (oldctx.cr0 & 0xFFFFFFF0) | ax; TRACE((regs, regs->eip - eip, "lmsw 0x%x", ax)); -#ifndef TEST oldctx.cr0 = cr0 | CR0_PE | CR0_NE; -#else - oldctx.cr0 = cr0 | CR0_PE | CR0_NE | CR0_PG; -#endif if (cr0 & CR0_PE) set_mode(regs, VM86_REAL_TO_PROTECTED); @@ -656,13 +652,8 @@ movcr(struct regs *regs, unsigned prefix, unsigned opc) TRACE((regs, regs->eip - eip, "movl %%cr%d, %%eax", cr)); switch (cr) { case 0: -#ifndef TEST setreg32(regs, modrm, oldctx.cr0 & ~(CR0_PE | CR0_NE)); -#else - setreg32(regs, modrm, - oldctx.cr0 & ~(CR0_PE | CR0_NE | CR0_PG)); -#endif break; case 2: setreg32(regs, modrm, get_cr2()); @@ -680,9 +671,6 @@ movcr(struct regs *regs, unsigned prefix, unsigned opc) switch (cr) { case 0: oldctx.cr0 = getreg32(regs, modrm) | (CR0_PE | CR0_NE); -#ifdef TEST - oldctx.cr0 |= CR0_PG; -#endif if (getreg32(regs, modrm) & CR0_PE) set_mode(regs, VM86_REAL_TO_PROTECTED); else @@ -1086,7 +1074,7 @@ jmpl(struct regs *regs, int prefix) if (mode == VM86_REAL_TO_PROTECTED) /* jump to protected mode */ set_mode(regs, VM86_PROTECTED); - else if (mode == VM86_PROTECTED_TO_REAL)/* jump to real mode */ + else if (mode == VM86_PROTECTED_TO_REAL) /* jump to real mode */ set_mode(regs, VM86_REAL); else panic("jmpl"); From 1b3a517175f58da8dab8c4aff5f244e622957212 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Sun, 1 Jul 2007 22:20:46 +0100 Subject: [PATCH 40/45] Make network-bridge fail on NFS or iscsi root. Since setting up bridging involves bringing down the network interface, bridging clearly isn't compatible with the likes of NFS or iSCSI root. Signed-off-by: Mark McLoughlin --- tools/examples/network-bridge | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tools/examples/network-bridge b/tools/examples/network-bridge index a7ee9067be..6b528d8a48 100755 --- a/tools/examples/network-bridge +++ b/tools/examples/network-bridge @@ -172,11 +172,23 @@ show_status () { echo '============================================================' } +is_network_root () { + local rootfs=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $3; }}' /etc/mtab) + local rootopts=$(awk '{ if ($1 !~ /^[ \t]*#/ && $2 == "/") { print $4; }}' /etc/mtab) + + [[ "$rootfs" =~ "^nfs" ]] || [[ "$rootopts" =~ "_netdev" ]] && return 0 || return 1 +} + op_start () { if [ "${bridge}" = "null" ] ; then return fi + if is_network_root ; then + [ -x /usr/bin/logger ] && /usr/bin/logger "network-bridge: bridging not supported on network root; not starting" + return + fi + if link_exists "$pdev"; then # The device is already up. return From ea66464712cdb7200087bd4354ba4329200ddc96 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Sun, 1 Jul 2007 22:21:58 +0100 Subject: [PATCH 41/45] ACM: Fix a problem with the boot option parser. Signed-off-by: Stefan Berger --- xen/acm/acm_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/acm/acm_core.c b/xen/acm/acm_core.c index 5cbff94bad..7203954909 100644 --- a/xen/acm/acm_core.c +++ b/xen/acm/acm_core.c @@ -89,7 +89,7 @@ static void __init set_dom0_ssidref(const char *val) if (hi < ACM_MAX_NUM_TYPES && hi >= 1) dom0_ste_ssidref = hi; for (i = 0; i < sizeof(polname); i++) { - polname[i] = c[7+i]; + polname[i] = c[5+i]; if (polname[i] == '\0' || polname[i] == '\t' || polname[i] == '\n' || polname[i] == ' ' || polname[i] == ':') { From e0ccefb2fb2329d2f18f8a51c5b1b195564c6761 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Sun, 1 Jul 2007 22:23:16 +0100 Subject: [PATCH 42/45] xm: Fix a typo for xm network-detach. Signed-off-by: Masaki Kanno --- tools/python/xen/xm/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index d19a131972..17da145843 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -2213,7 +2213,7 @@ def xm_block_detach(args): def xm_network_detach(args): if serverType == SERVER_XEN_API: - arg_check(args, "xm_block_detach", 2, 3) + arg_check(args, "xm_network_detach", 2, 3) dom = args[0] devid = args[1] vif_refs = server.xenapi.VM.get_VIFs(get_single_vm(dom)) From 0cf4932910783de7126b89a4c9c6e0712ff37291 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Sun, 1 Jul 2007 22:25:27 +0100 Subject: [PATCH 43/45] xm: Fix xm block-detach error message duplication. Signed-off-by: Masaki Kanno --- tools/python/xen/xm/main.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 17da145843..8bc0efe90a 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -2168,9 +2168,7 @@ def xm_network_attach(args): server.xend.domain.device_create(dom, vif) -def detach(args, command, deviceClass): - arg_check(args, command, 2, 3) - +def detach(args, deviceClass): dom = args[0] dev = args[1] try: @@ -2204,12 +2202,13 @@ def xm_block_detach(args): raise OptionError("Cannot find device '%s' in domain '%s'" % (dev,dom)) else: + arg_check(args, 'block-detach', 2, 3) try: - detach(args, 'block-detach', 'vbd') + detach(args, 'vbd') return except: pass - detach(args, 'block-detach', 'tap') + detach(args, 'tap') def xm_network_detach(args): if serverType == SERVER_XEN_API: @@ -2227,7 +2226,8 @@ def xm_network_detach(args): else: print "Cannot find device '%s' in domain '%s'" % (devid,dom) else: - detach(args, 'network-detach', 'vif') + arg_check(args, 'network-detach', 2, 3) + detach(args, 'vif') def xm_vnet_list(args): From d0e4f15cfdad64de400ab32ab544f5434b38c9f7 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Mon, 2 Jul 2007 00:24:59 +0100 Subject: [PATCH 44/45] Use 32bit operand and address during VMXAssist protected to real. Signed-off-by: Xin Li --- tools/firmware/vmxassist/setup.c | 3 +- tools/firmware/vmxassist/vm86.c | 61 ++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/tools/firmware/vmxassist/setup.c b/tools/firmware/vmxassist/setup.c index fd03e3c6cb..1e2e86c27b 100644 --- a/tools/firmware/vmxassist/setup.c +++ b/tools/firmware/vmxassist/setup.c @@ -198,9 +198,10 @@ enter_real_mode(struct regs *regs) } /* go from protected to real mode */ - regs->eflags |= EFLAGS_VM; set_mode(regs, VM86_PROTECTED_TO_REAL); emulate(regs); + if (mode != VM86_REAL) + panic("failed to emulate between clear PE and long jump.\n"); } /* diff --git a/tools/firmware/vmxassist/vm86.c b/tools/firmware/vmxassist/vm86.c index 357a73e353..847b625e07 100644 --- a/tools/firmware/vmxassist/vm86.c +++ b/tools/firmware/vmxassist/vm86.c @@ -580,8 +580,13 @@ movr(struct regs *regs, unsigned prefix, unsigned opc) unsigned addr = operand(prefix, regs, modrm); unsigned val, r = (modrm >> 3) & 7; - if ((modrm & 0xC0) == 0xC0) /* no registers */ - return 0; + if ((modrm & 0xC0) == 0xC0) { + /* + * Emulate all guest instructions in protected to real mode. + */ + if (mode != VM86_PROTECTED_TO_REAL) + return 0; + } switch (opc) { case 0x88: /* addr32 mov r8, r/m8 */ @@ -806,8 +811,13 @@ mov_to_seg(struct regs *regs, unsigned prefix, unsigned opc) { unsigned modrm = fetch8(regs); - /* Only need to emulate segment loads in real->protected mode. */ - if (mode != VM86_REAL_TO_PROTECTED) + /* + * Emulate segment loads in: + * 1) real->protected mode. + * 2) protected->real mode. + */ + if ((mode != VM86_REAL_TO_PROTECTED) && + (mode != VM86_PROTECTED_TO_REAL)) return 0; /* Register source only. */ @@ -817,6 +827,8 @@ mov_to_seg(struct regs *regs, unsigned prefix, unsigned opc) switch ((modrm & 0x38) >> 3) { case 0: /* es */ regs->ves = getreg16(regs, modrm); + if (mode == VM86_PROTECTED_TO_REAL) + return 1; saved_rm_regs.ves = 0; oldctx.es_sel = regs->ves; return 1; @@ -825,21 +837,29 @@ mov_to_seg(struct regs *regs, unsigned prefix, unsigned opc) case 2: /* ss */ regs->uss = getreg16(regs, modrm); + if (mode == VM86_PROTECTED_TO_REAL) + return 1; saved_rm_regs.uss = 0; oldctx.ss_sel = regs->uss; return 1; case 3: /* ds */ regs->vds = getreg16(regs, modrm); + if (mode == VM86_PROTECTED_TO_REAL) + return 1; saved_rm_regs.vds = 0; oldctx.ds_sel = regs->vds; return 1; case 4: /* fs */ regs->vfs = getreg16(regs, modrm); + if (mode == VM86_PROTECTED_TO_REAL) + return 1; saved_rm_regs.vfs = 0; oldctx.fs_sel = regs->vfs; return 1; case 5: /* gs */ regs->vgs = getreg16(regs, modrm); + if (mode == VM86_PROTECTED_TO_REAL) + return 1; saved_rm_regs.vgs = 0; oldctx.gs_sel = regs->vgs; return 1; @@ -1055,7 +1075,8 @@ set_mode(struct regs *regs, enum vm86_mode newmode) } mode = newmode; - TRACE((regs, 0, states[mode])); + if (mode != VM86_PROTECTED) + TRACE((regs, 0, states[mode])); } static void @@ -1269,6 +1290,12 @@ opcode(struct regs *regs) unsigned opc, modrm, disp; unsigned prefix = 0; + if (mode == VM86_PROTECTED_TO_REAL && + oldctx.cs_arbytes.fields.default_ops_size) { + prefix |= DATA32; + prefix |= ADDR32; + } + for (;;) { switch ((opc = fetch8(regs))) { case 0x07: /* pop %es */ @@ -1379,17 +1406,29 @@ opcode(struct regs *regs) continue; case 0x66: - TRACE((regs, regs->eip - eip, "data32")); - prefix |= DATA32; + if (mode == VM86_PROTECTED_TO_REAL && + oldctx.cs_arbytes.fields.default_ops_size) { + TRACE((regs, regs->eip - eip, "data16")); + prefix &= ~DATA32; + } else { + TRACE((regs, regs->eip - eip, "data32")); + prefix |= DATA32; + } continue; case 0x67: - TRACE((regs, regs->eip - eip, "addr32")); - prefix |= ADDR32; + if (mode == VM86_PROTECTED_TO_REAL && + oldctx.cs_arbytes.fields.default_ops_size) { + TRACE((regs, regs->eip - eip, "addr16")); + prefix &= ~ADDR32; + } else { + TRACE((regs, regs->eip - eip, "addr32")); + prefix |= ADDR32; + } continue; - case 0x88: /* addr32 mov r8, r/m8 */ - case 0x8A: /* addr32 mov r/m8, r8 */ + case 0x88: /* mov r8, r/m8 */ + case 0x8A: /* mov r/m8, r8 */ if (mode != VM86_REAL && mode != VM86_REAL_TO_PROTECTED) goto invalid; if ((prefix & ADDR32) == 0) From 4cb346f848a1e0748b03582e91c29c7e757ecb0a Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 2 Jul 2007 08:42:13 +0100 Subject: [PATCH 45/45] Fix 15435:ab95b9764b20. The changeset did not consider about ":cdrom" and "ioemu:" of a disk definition. Signed-off-by: Masaki Kanno --- tools/python/xen/xend/XendConfig.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 16ebea6f09..17628f337a 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -936,6 +936,13 @@ class XendConfig(dict): return sxpr def _blkdev_name_to_number(self, dev): + if 'ioemu:' in dev: + _, dev = dev.split(':', 1) + try: + dev, _ = dev.split(':', 1) + except ValueError: + pass + try: devid = int(dev) except ValueError: