extract vmcoreinfo from /proc/vmcore for Xen
authorKeir Fraser <keir.fraser@citrix.com>
Fri, 13 Jun 2008 08:54:03 +0000 (09:54 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Fri, 13 Jun 2008 08:54:03 +0000 (09:54 +0100)
- the machine address and the size of the vmcoreinfo area is returned
  via the kexec_op(get_range) hypercall
- fill the vmcoreinfo data when the kexec_op(crash load) hypercall
  is called

Signed-off-by: Itsuro Oda <oda@valinux.co.jp>
12 files changed:
xen/arch/ia64/xen/machine_kexec.c
xen/arch/ia64/xen/mm.c
xen/arch/x86/machine_kexec.c
xen/arch/x86/mm.c
xen/common/kexec.c
xen/common/page_alloc.c
xen/include/asm-ia64/config.h
xen/include/asm-ia64/mm.h
xen/include/asm-x86/config.h
xen/include/asm-x86/mm.h
xen/include/public/kexec.h
xen/include/xen/mm.h

index 221f59cf16c0dc21a769b1d090b8137a0fa6af19..9fcd189d66da7e353045d7e33de500399ab2d40d 100644 (file)
@@ -193,6 +193,15 @@ int machine_kexec_get(xen_kexec_range_t *range)
        return -EINVAL;
 }
 
+void arch_crash_save_vmcoreinfo(void)
+{
+       VMCOREINFO_SYMBOL(dom_xen);
+       VMCOREINFO_SYMBOL(dom_io);
+       VMCOREINFO_SYMBOL(xen_pstart);
+       VMCOREINFO_SYMBOL(frametable_pg_dir);
+       VMCOREINFO_SYMBOL_ALIAS(xen_heap_start, xen_pickle_offset);
+}
+
 /*
  * Local variables:
  * mode: C
index ceb4aa3cce502154926155d947ea5203c39e78d6..0a4994ba8bd00d77c6e1bb0ae2bd8c475bcd458e 100644 (file)
@@ -189,7 +189,7 @@ static void domain_page_flush_and_put(struct domain* d, unsigned long mpaddr,
 
 extern unsigned long ia64_iobase;
 
-static struct domain *dom_xen, *dom_io;
+struct domain *dom_xen, *dom_io;
 
 /*
  * This number is bigger than DOMID_SELF, DOMID_XEN and DOMID_IO.
index 4c2ccd8080b2575354b9f4aa9af49c594f4f7cef..d98eb77fa7c6d286bfbd6671bf79938ce12926f6 100644 (file)
@@ -145,6 +145,19 @@ int machine_kexec_get(xen_kexec_range_t *range)
        return machine_kexec_get_xen(range);
 }
 
+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
index 85530dad8d95a34670df87c66f46ee9fb83ca64a..af1033d1d7af45c7b241fa25ebfa3d6960a427a7 100644 (file)
@@ -151,7 +151,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;
index 02f633d660a32f7442004fe55a6db53b961e73da..2eb73e94b5399cd7d126a3d51f33a849d6d890b8 100644 (file)
@@ -43,6 +43,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)
@@ -208,6 +211,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_internal(xen_kexec_range_t *range)
 {
     int ret = -EINVAL;
@@ -220,6 +230,9 @@ static int kexec_get_range_internal(xen_kexec_range_t *range)
     case KEXEC_RANGE_MA_CPU:
         ret = kexec_get_cpu(range);
         break;
+    case KEXEC_RANGE_MA_VMCOREINFO:
+        ret = kexec_get_vmcoreinfo(range);
+        break;
     default:
         ret = machine_kexec_get(range);
         break;
@@ -288,6 +301,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
+}
+
 static int kexec_load_unload_internal(unsigned long op, xen_kexec_load_t *load)
 {
     xen_kexec_image_t *image;
@@ -316,6 +379,8 @@ static int kexec_load_unload_internal(unsigned long op, xen_kexec_load_t *load)
             /* Make new image the active one */
             change_bit(bit, &kexec_flags);
         }
+
+        crash_save_vmcoreinfo();
     }
 
     /* Unload the old image if present and load successful */
index d1773c679e76afa1debee87564c5bcecc55845ed..410622cdd2209a5ac485bef599248bf1f0c12d1c 100644 (file)
@@ -102,7 +102,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)                       \
index dc557bfca3320d44b366a226a59dbd44c97ea683..24d2495b349850196e1a342c377c64ccf6ebd094 100644 (file)
@@ -295,4 +295,6 @@ struct screen_info { };
 
 #define CONFIG_XENCOMM_MARK_DIRTY 1
 
+#define ARCH_CRASH_SAVE_VMCOREINFO
+
 #endif /* _IA64_CONFIG_H_ */
index 716e9bd7c5fdddf2b6905baf58e642e75ccd6ce2..a5871cc712b603bc967cc93511d9d721fdcb64a6 100644 (file)
@@ -503,4 +503,6 @@ int steal_page(
 
 unsigned long domain_get_maximum_gpfn(struct domain *d);
 
+extern struct domain *dom_xen, *dom_io;        /* for vmcoreinfo */
+
 #endif /* __ASM_IA64_MM_H__ */
index c2d8ad1d6a9dfe4a03ec64723dd6b5812873bafb..19bb4209f5cf397d88a8bec677d1cee6a77f35db 100644 (file)
@@ -371,4 +371,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__ */
index 73c24fb2c3a41aca5be671e83a83ab79ed5f898e..bd8af02ff24ce3a1070fcb490156f811102be116 100644 (file)
@@ -357,4 +357,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__ */
index fbad3606ac27a86f3bad2ecce0fd1c98db00513f..ac1743c93d7433f721d95bc55865497985d6017d 100644 (file)
@@ -138,6 +138,7 @@ typedef struct xen_kexec_load {
                                      * the ia64_boot_param */
 #define KEXEC_RANGE_MA_EFI_MEMMAP 5 /* machine address and size of
                                      * of the EFI Memory Map */
+#define KEXEC_RANGE_MA_VMCOREINFO 6 /* machine address and size of vmcoreinfo */
 
 /*
  * Find the address and size of certain memory areas
@@ -154,6 +155,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 */
 
 /*
index 1341bb0fa092f850d00974c40e576348b5c200a1..08bd72d8ce2b511b8bad39d8f0555f0b0228a583 100644 (file)
@@ -104,4 +104,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__ */