From: Neil Horman <nhorman@redhat.com> Date: Mon, 18 Aug 2008 10:59:30 -0400 Subject: [xen] HV: ability to use makedumpfile with vmcoreinfo Message-id: 20080818145930.GD7052@hmsendeavour.rdu.redhat.com O-Subject: [RHEL 5.3 PATCH] 1/2: xen: add ability for dom0 kernels to use makedumpfile with vmcoreinfo (bz 454498) Bugzilla: 454498 RH-Acked-by: Bill Burns <bburns@redhat.com> RH-Acked-by: Bill Burns <bburns@redhat.com> Hey- This is the hypervisor portion of this patch diff --git a/arch/ia64/xen/machine_kexec.c b/arch/ia64/xen/machine_kexec.c index df7ad0c..cef8cab 100644 --- a/arch/ia64/xen/machine_kexec.c +++ b/arch/ia64/xen/machine_kexec.c @@ -1,6 +1,9 @@ #include <xen/lib.h> /* for printk() used in stubs */ #include <xen/types.h> #include <public/kexec.h> +#include <xen/mm.h> + +extern unsigned long frametable_pg_dir[]; int machine_kexec_load(int type, int slot, xen_kexec_image_t *image) { @@ -23,6 +26,14 @@ void machine_reboot_kexec(xen_kexec_image_t *image) printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); } +void arch_crash_save_vmcoreinfo(void) +{ + VMCOREINFO_SYMBOL(dom_xen); + VMCOREINFO_SYMBOL(dom_io); + VMCOREINFO_SYMBOL(xen_pstart); + VMCOREINFO_SYMBOL(frametable_pg_dir); +} + /* * Local variables: * mode: C diff --git a/arch/ia64/xen/mm.c b/arch/ia64/xen/mm.c index 26601f1..de7e72e 100644 --- a/arch/ia64/xen/mm.c +++ b/arch/ia64/xen/mm.c @@ -187,7 +187,7 @@ static int efi_ucwb(unsigned long physaddr, unsigned long size); extern unsigned long ia64_iobase; -static struct domain *dom_xen, *dom_io; +struct domain *dom_xen, *dom_io; // followings are stolen from arch_init_memory() @ xen/arch/x86/mm.c void diff --git a/arch/x86/machine_kexec.c b/arch/x86/machine_kexec.c index e5033da..d9d9ee2 100644 --- a/arch/x86/machine_kexec.c +++ b/arch/x86/machine_kexec.c @@ -140,6 +140,20 @@ void machine_kexec(xen_kexec_image_t *image) } } +void arch_crash_save_vmcoreinfo(void) +{ + VMCOREINFO_SYMBOL(dom_xen); + VMCOREINFO_SYMBOL(dom_io); + +#ifdef CONFIG_X86_PAE + VMCOREINFO_SYMBOL_ALIAS(pgd_l3, idle_pg_table); +#endif +#ifdef CONFIG_X86_64 + VMCOREINFO_SYMBOL_ALIAS(pgd_l4, idle_pg_table); +#endif +} + + /* * Local variables: * mode: C diff --git a/arch/x86/mm.c b/arch/x86/mm.c index f7f9e04..fe71d1f 100644 --- a/arch/x86/mm.c +++ b/arch/x86/mm.c @@ -140,7 +140,7 @@ static DEFINE_PER_CPU(struct percpu_mm_info, percpu_mm_info); #define FOREIGNDOM (this_cpu(percpu_mm_info).foreign ?: current->domain) /* Private domain structs for DOMID_XEN and DOMID_IO. */ -static struct domain *dom_xen, *dom_io; +struct domain *dom_xen, *dom_io; /* Frame table and its size in pages. */ struct page_info *frame_table; diff --git a/common/kexec.c b/common/kexec.c index 2437799..99ffdb9 100644 --- a/common/kexec.c +++ b/common/kexec.c @@ -42,6 +42,9 @@ static unsigned long kexec_flags = 0; /* the lowest bits are for KEXEC_IMAGE... static spinlock_t kexec_lock = SPIN_LOCK_UNLOCKED; +static unsigned char vmcoreinfo_data[VMCOREINFO_BYTES]; +static size_t vmcoreinfo_size = 0; + xen_kexec_reserve_t kexec_crash_area; static void __init parse_crashkernel(const char *str) @@ -222,6 +225,13 @@ static int kexec_get(cpu)(xen_kexec_range_t *range) return 0; } +static int kexec_get(vmcoreinfo)(xen_kexec_range_t *range) +{ + range->start = __pa((unsigned long)vmcoreinfo_data); + range->size = VMCOREINFO_BYTES; + return 0; +} + static int kexec_get(range)(XEN_GUEST_HANDLE(void) uarg) { xen_kexec_range_t range; @@ -241,6 +251,9 @@ static int kexec_get(range)(XEN_GUEST_HANDLE(void) uarg) case KEXEC_RANGE_MA_CPU: ret = kexec_get(cpu)(&range); break; + case KEXEC_RANGE_MA_VMCOREINFO: + ret = kexec_get(vmcoreinfo)(&range); + break; } if ( ret == 0 && unlikely(copy_to_guest(uarg, &range, 1)) ) @@ -269,6 +282,56 @@ static int kexec_load_get_bits(int type, int *base, int *bit) return 0; } +void vmcoreinfo_append_str(const char *fmt, ...) +{ + va_list args; + char buf[0x50]; + int r; + size_t note_size = sizeof(Elf_Note) + ELFNOTE_ALIGN(strlen(VMCOREINFO_NOTE_NAME) + 1); + + if (vmcoreinfo_size + note_size + sizeof(buf) > VMCOREINFO_BYTES) + return; + + va_start(args, fmt); + r = vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + memcpy(&vmcoreinfo_data[note_size + vmcoreinfo_size], buf, r); + + vmcoreinfo_size += r; +} + +static void crash_save_vmcoreinfo(void) +{ + size_t data_size; + + if (vmcoreinfo_size > 0) /* already saved */ + return; + + data_size = VMCOREINFO_BYTES - (sizeof(Elf_Note) + ELFNOTE_ALIGN(strlen(VMCOREINFO_NOTE_NAME) + 1)); + setup_note((Elf_Note *)vmcoreinfo_data, VMCOREINFO_NOTE_NAME, 0, data_size); + + VMCOREINFO_PAGESIZE(PAGE_SIZE); + + VMCOREINFO_SYMBOL(domain_list); + VMCOREINFO_SYMBOL(frame_table); + VMCOREINFO_SYMBOL(alloc_bitmap); + VMCOREINFO_SYMBOL(max_page); + VMCOREINFO_SYMBOL(xenheap_phys_end); + + VMCOREINFO_STRUCT_SIZE(page_info); + VMCOREINFO_STRUCT_SIZE(domain); + + VMCOREINFO_OFFSET(page_info, count_info); + VMCOREINFO_OFFSET_ALIAS(page_info, u, _domain); + VMCOREINFO_OFFSET(domain, domain_id); + VMCOREINFO_OFFSET(domain, next_in_list); + +#ifdef ARCH_CRASH_SAVE_VMCOREINFO + arch_crash_save_vmcoreinfo(); +#endif +} + #endif static int kexec_load_unload(unsigned long op, XEN_GUEST_HANDLE(void) uarg) @@ -307,6 +370,9 @@ static int kexec_load_unload(unsigned long op, XEN_GUEST_HANDLE(void) uarg) /* Make new image the active one */ change_bit(bit, &kexec_flags); } +#ifndef COMPAT + crash_save_vmcoreinfo(); +#endif } /* Unload the old image if present and load successful */ diff --git a/common/page_alloc.c b/common/page_alloc.c index 834e09e..6c010fa 100644 --- a/common/page_alloc.c +++ b/common/page_alloc.c @@ -93,7 +93,7 @@ static unsigned long scrub_pages; * One bit per page of memory. Bit set => page is allocated. */ -static unsigned long *alloc_bitmap; +unsigned long *alloc_bitmap; #define PAGES_PER_MAPWORD (sizeof(unsigned long) * 8) #define allocated_in_map(_pn) \ diff --git a/include/asm-ia64/config.h b/include/asm-ia64/config.h index ee14018..12c9bf9 100644 --- a/include/asm-ia64/config.h +++ b/include/asm-ia64/config.h @@ -282,4 +282,6 @@ struct screen_info { }; /* Define CONFIG_PRIVIFY to support privified OS (deprecated). */ #undef CONFIG_PRIVIFY +#define ARCH_CRASH_SAVE_VMCOREINFO + #endif /* _IA64_CONFIG_H_ */ diff --git a/include/asm-ia64/mm.h b/include/asm-ia64/mm.h index d5d4148..6e88fa9 100644 --- a/include/asm-ia64/mm.h +++ b/include/asm-ia64/mm.h @@ -508,4 +508,6 @@ int steal_page( #define domain_get_maximum_gpfn(d) (-ENOSYS) +extern struct domain *dom_xen, *dom_io; /* for vmcoreinfo */ + #endif /* __ASM_IA64_MM_H__ */ diff --git a/include/asm-x86/config.h b/include/asm-x86/config.h index 83e118b..cbdccf7 100644 --- a/include/asm-x86/config.h +++ b/include/asm-x86/config.h @@ -390,4 +390,6 @@ extern unsigned long xen_phys_start, xenheap_phys_start, xenheap_phys_end; #define ELFSIZE 32 #endif +#define ARCH_CRASH_SAVE_VMCOREINFO + #endif /* __X86_CONFIG_H__ */ diff --git a/include/asm-x86/mm.h b/include/asm-x86/mm.h index 43d03ec..8c02a76 100644 --- a/include/asm-x86/mm.h +++ b/include/asm-x86/mm.h @@ -402,4 +402,6 @@ unsigned int domain_clamp_alloc_bitsize(struct domain *d, unsigned int bits); unsigned long domain_get_maximum_gpfn(struct domain *d); +extern struct domain *dom_xen, *dom_io; /* for vmcoreinfo */ + #endif /* __ASM_X86_MM_H__ */ diff --git a/include/public/kexec.h b/include/public/kexec.h index ca6e85b..7af1d47 100644 --- a/include/public/kexec.h +++ b/include/public/kexec.h @@ -109,6 +109,7 @@ typedef struct xen_kexec_load { #define KEXEC_RANGE_MA_XEN 1 /* machine address and size of Xen itself */ #define KEXEC_RANGE_MA_CPU 2 /* machine address and size of a CPU note */ +#define KEXEC_RANGE_MA_VMCOREINFO 6 /* machine address and size of vmcoreinfo */ /* * Find the address and size of certain memory areas * range == KEXEC_RANGE_... [in] @@ -124,6 +125,27 @@ typedef struct xen_kexec_range { unsigned long start; } xen_kexec_range_t; +/* vmcoreinfo stuff */ +#define VMCOREINFO_BYTES (4096) +#define VMCOREINFO_NOTE_NAME "VMCOREINFO_XEN" +void arch_crash_save_vmcoreinfo(void); +void vmcoreinfo_append_str(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); +#define VMCOREINFO_PAGESIZE(value) \ + vmcoreinfo_append_str("PAGESIZE=%ld\n", value) +#define VMCOREINFO_SYMBOL(name) \ + vmcoreinfo_append_str("SYMBOL(%s)=%lx\n", #name, (unsigned long)&name) +#define VMCOREINFO_SYMBOL_ALIAS(alias, name) \ + vmcoreinfo_append_str("SYMBOL(%s)=%lx\n", #alias, (unsigned long)&name) +#define VMCOREINFO_STRUCT_SIZE(name) \ + vmcoreinfo_append_str("SIZE(%s)=%zu\n", #name, sizeof(struct name)) +#define VMCOREINFO_OFFSET(name, field) \ + vmcoreinfo_append_str("OFFSET(%s.%s)=%zu\n", #name, #field, \ + offsetof(struct name, field)) +#define VMCOREINFO_OFFSET_ALIAS(name, field, alias) \ + vmcoreinfo_append_str("OFFSET(%s.%s)=%zu\n", #name, #alias, \ + offsetof(struct name, field)) + #endif /* _XEN_PUBLIC_KEXEC_H */ /* diff --git a/include/xen/mm.h b/include/xen/mm.h index a5183fd..8a67fc7 100644 --- a/include/xen/mm.h +++ b/include/xen/mm.h @@ -108,4 +108,6 @@ int guest_remove_page(struct domain *d, unsigned long gmfn); /* Returns TRUE if the memory at address @p is ordinary RAM. */ int memory_is_conventional_ram(paddr_t p); +extern unsigned long *alloc_bitmap; /* for vmcoreinfo */ + #endif /* __XEN_MM_H__ */