* [PATCH] [makedumpfile] Implement memory regions on IA64
@ 2007-04-26 19:37 Bernhard Walle
2007-05-11 6:59 ` Ken'ichi Ohmichi
0 siblings, 1 reply; 10+ messages in thread
From: Bernhard Walle @ 2007-04-26 19:37 UTC (permalink / raw)
To: Kexec Mailing List; +Cc: Ken'ichi Ohmichi
This patch fixes an error in vaddr_to_offset_ia64() which happened on
a SGI machine here while retrieving the utsname from the kernel dump
image. It implements memory region support for IA64.
The code is mainly from crash (http://people.redhat.com/~anderson/).
Signed-off-by: Bernhard Walle <bwalle@suse.de>
---
ia64.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
makedumpfile.c | 4 ++++
makedumpfile.h | 9 ++++++++-
3 files changed, 69 insertions(+), 1 deletion(-)
--- a/ia64.c
+++ b/ia64.c
@@ -23,6 +23,8 @@ get_phys_base_ia64(struct DumpInfo *info
int i;
struct pt_load_segment *pls;
+ info->phys_base = 0;
+
/*
* Default to 64MB.
*/
@@ -48,5 +50,60 @@ get_machdep_info_ia64(struct DumpInfo *i
return TRUE;
}
+/*
+ * Convert Virtual Address to File Offest.
+ */
+off_t
+vaddr_to_offset_ia64(struct DumpInfo *info, unsigned long long vaddr)
+{
+ int i;
+ off_t offset;
+ struct pt_load_segment *pls;
+ unsigned long paddr;
+
+
+ switch (VADDR_REGION(vaddr)) {
+ case KERNEL_CACHED_REGION:
+ paddr = vaddr - (ulong)(KERNEL_CACHED_BASE);
+ break;
+
+ case KERNEL_UNCACHED_REGION:
+ paddr = vaddr - (ulong)(KERNEL_UNCACHED_BASE);
+ break;
+
+ case KERNEL_VMALLOC_REGION:
+ paddr = vaddr - info->kernel_start +
+ (info->phys_base & KERNEL_TR_PAGE_MASK);
+ break;
+
+ default:
+ ERRMSG("Unknown region (%d)\n", VADDR_REGION(vaddr));
+ return 0;
+ }
+
+ for (i = offset = 0; i < info->num_load_memory; i++) {
+ pls = &info->pt_load_segments[i];
+ if ((paddr >= pls->phys_start)
+ && (paddr < pls->phys_end)) {
+ offset = (off_t)(paddr - pls->phys_start) +
+ pls->file_offset;
+ break;
+ }
+ }
+
+ return offset;
+}
+
+int
+get_machdep_kernel_start_ia64(struct DumpInfo *info)
+{
+ if (SYMBOL(_stext) != NOT_FOUND_SYMBOL)
+ info->kernel_start = SYMBOL(_stext);
+
+ /* TODO: fallback */
+
+ return TRUE;
+}
+
#endif /* ia64 */
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -2206,6 +2206,10 @@ initial(struct DumpInfo *info)
if (!get_structure_info(info))
return FALSE;
}
+
+ if (!get_machdep_kernel_start(info))
+ return FALSE;
+
if (!check_release(info))
return FALSE;
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -377,6 +377,7 @@ int get_machdep_info_x86();
#define get_phys_base(X) TRUE
#define get_machdep_info(X) get_machdep_info_x86(X)
#define vaddr_to_offset(X, Y) vaddr_to_offset_general(X,Y)
+#define get_machdep_kernel_start(X) TRUE
#endif /* x86 */
#ifdef __x86_64__
@@ -386,6 +387,7 @@ off_t vaddr_to_offset_x86_64();
#define get_phys_base(X) get_phys_base_x86_64(X)
#define get_machdep_info(X) get_machdep_info_x86_64(X)
#define vaddr_to_offset(X, Y) vaddr_to_offset_x86_64(X, Y)
+#define get_machdep_kernel_start(X) TRUE
#endif /* x86_64 */
#ifdef __powerpc__ /* powerpc */
@@ -393,14 +395,18 @@ int get_machdep_info_ppc64();
#define get_machdep_info(X) get_machdep_info_ppc64(X)
#define get_phys_base(X) TRUE
#define vaddr_to_offset(X, Y) vaddr_to_offset_general(X, Y)
+#define get_machdep_kernel_start(X) TRUE
#endif /* powerpc */
#ifdef __ia64__ /* ia64 */
int get_phys_base_ia64();
int get_machdep_info_ia64();
+int get_machdep_kernel_start_ia64();
+off_t vaddr_to_offset_ia64();
#define get_machdep_info(X) get_machdep_info_ia64(X)
#define get_phys_base(X) get_phys_base_ia64(X)
-#define vaddr_to_offset(X, Y) vaddr_to_offset_general(X, Y)
+#define get_machdep_kernel_start(X) get_machdep_kernel_start_ia64(X)
+#define vaddr_to_offset(X, Y) vaddr_to_offset_ia64(X, Y)
#define VADDR_REGION(X) ((X) >> REGION_SHIFT)
#endif /* ia64 */
@@ -491,6 +497,7 @@ struct DumpInfo {
unsigned long max_physmem_bits;
unsigned long sections_per_root;
unsigned long phys_base;
+ unsigned long kernel_start;
/*
* diskdimp info:
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] [makedumpfile] Implement memory regions on IA64
@ 2007-04-27 10:31 tachibana
0 siblings, 0 replies; 10+ messages in thread
From: tachibana @ 2007-04-27 10:31 UTC (permalink / raw)
To: kexec
Hi Bernhard-san,
Sorry, the subject was wrong.
I send my reply again.
2007/04/26 14:21:53 +0200, Bernhard Walle <bwalle@suse.de> wrote:
>
>Hello,
>
>I found in your announcment of makedumpfile 1.1.1:
>
> Todo:
> - ia64 DISCONTIGMEM support
>
>Did you already do something in this area? If you have something to
>test, I'd be happy. :)
Thank you for your vaddr_to_offset_ia64() patch.
We are currently investigating ia64 discontigmem, and
your patch will be our help.
I think your patch has problems when translating virtual address into
physical address for ia64 discontigmem if layer 3 (or layer 4)
paging is necessary.
In Japan, we have a vacation on April 28th - May 6th.
Sorry, we will reply again after the vacation.
Thanks
tachibana
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] [makedumpfile] Implement memory regions on IA64
2007-04-26 19:37 [PATCH] [makedumpfile] Implement memory regions on IA64 Bernhard Walle
@ 2007-05-11 6:59 ` Ken'ichi Ohmichi
2007-05-14 18:15 ` Bernhard Walle
0 siblings, 1 reply; 10+ messages in thread
From: Ken'ichi Ohmichi @ 2007-05-11 6:59 UTC (permalink / raw)
To: Bernhard Walle; +Cc: Jay Lan, Kexec Mailing List
[-- Attachment #1: Type: text/plain, Size: 1165 bytes --]
Hi Bernhard,
2007/04/26 21:37:25 +0200, Bernhard Walle <bwalle@suse.de> wrote:
>This patch fixes an error in vaddr_to_offset_ia64() which happened on
>a SGI machine here while retrieving the utsname from the kernel dump
>image. It implements memory region support for IA64.
Thank you for the patch.
For ia64 DISCONTIGMEM support, I added the translation (virtual address
to physical address) by using layer 3 paging into your patch.
I created 2 attached patches for ia64 DISCONTIGMEM support.
I confirmed makedumpfile with these patches can run on linux-2.6.18 kernel
(made of RHEL5 kernel by changing configs from SPARSEMEM to DISCONTIGMEM).
Could you please test them on SLES10 ?
BTW, the patches don't run on stock linux-2.6.20 w/DISCONTIGMEM
(it works with stock linux-2.6.20 w/SPARSEMEM)
I am trying to resolve the problem and if you have any idea about
kernel changes between 2.6.18-20, please let me know.
The attached patches (for makedumpfile version 1.1.3):
- 01-vaddr_to_offset_ia64.patch
The translation by using layer 3 paging is added to Bernhard's patch.
- 02-ia64-discontigmem.patch
ia64 DISCONTIGMEM support.
Thanks
Ken'ichi Ohmichi
[-- Attachment #2: 02-ia64-discontigmem.patch --]
[-- Type: application/octet-stream, Size: 3504 bytes --]
diff -puN makedumpfile.org/makedumpfile.c makedumpfile/makedumpfile.c
--- makedumpfile.org/makedumpfile.c 2007-05-11 23:06:33.000000000 +0900
+++ makedumpfile/makedumpfile.c 2007-05-11 23:55:33.000000000 +0900
@@ -1455,6 +1455,8 @@ get_structure_info(struct DumpInfo *info
OFFSET_INIT(pglist_data.node_start_pfn, "pglist_data","node_start_pfn");
OFFSET_INIT(pglist_data.node_spanned_pages, "pglist_data",
"node_spanned_pages");
+ OFFSET_INIT(pglist_data.pgdat_next, "pglist_data",
+ "pgdat_next");
/*
* Get offsets of the zone's members.
@@ -1502,7 +1504,12 @@ get_mem_type(struct DumpInfo *info)
|| (OFFSET(page._count) == NOT_FOUND_STRUCTURE)
|| (OFFSET(page.mapping) == NOT_FOUND_STRUCTURE)) {
ret = NOT_FOUND_MEMTYPE;
- } else if ((SYMBOL(node_data) != NOT_FOUND_SYMBOL)
+ } else if ((((SYMBOL(node_data) != NOT_FOUND_SYMBOL)
+ && (ARRAY_LENGTH(node_data) != NOT_FOUND_STRUCTURE))
+ || ((SYMBOL(pgdat_list) != NOT_FOUND_SYMBOL)
+ && (OFFSET(pglist_data.pgdat_next) != NOT_FOUND_STRUCTURE))
+ || ((SYMBOL(pgdat_list) != NOT_FOUND_SYMBOL)
+ && (ARRAY_LENGTH(pgdat_list) != NOT_FOUND_STRUCTURE)))
&& (SIZE(pglist_data) != NOT_FOUND_STRUCTURE)
&& (OFFSET(pglist_data.node_mem_map) != NOT_FOUND_STRUCTURE)
&& (OFFSET(pglist_data.node_start_pfn) != NOT_FOUND_STRUCTURE)
@@ -1613,6 +1620,8 @@ generate_config(struct DumpInfo *info)
pglist_data.node_start_pfn);
WRITE_MEMBER_OFFSET("pglist_data.node_spanned_pages",
pglist_data.node_spanned_pages);
+ WRITE_MEMBER_OFFSET("pglist_data.pgdat_next",
+ pglist_data.pgdat_next);
WRITE_MEMBER_OFFSET("zone.free_pages", zone.free_pages);
WRITE_MEMBER_OFFSET("zone.free_area", zone.free_area);
WRITE_MEMBER_OFFSET("zone.vm_stat", zone.vm_stat);
@@ -1782,6 +1791,8 @@ read_config(struct DumpInfo *info)
pglist_data.node_start_pfn);
READ_MEMBER_OFFSET("pglist_data.node_spanned_pages",
pglist_data.node_spanned_pages);
+ READ_MEMBER_OFFSET("pglist_data.pgdat_next",
+ pglist_data.pgdat_next);
READ_MEMBER_OFFSET("zone.free_pages", zone.free_pages);
READ_MEMBER_OFFSET("zone.free_area", zone.free_area);
READ_MEMBER_OFFSET("zone.vm_stat", zone.vm_stat);
@@ -1880,6 +1891,7 @@ next_online_node(int first)
unsigned long
next_online_pgdat(struct DumpInfo *info, int node)
{
+ int i;
unsigned long pgdat;
/*
@@ -1926,6 +1938,33 @@ pgdat2:
pgdat3:
/*
+ * linux-2.6.16 or before
+ */
+ if ((SYMBOL(pgdat_list) == NOT_FOUND_SYMBOL)
+ || (OFFSET(pglist_data.pgdat_next) == NOT_FOUND_STRUCTURE))
+ goto pgdat4;
+
+ if (!readmem(info, SYMBOL(pgdat_list), &pgdat, sizeof pgdat))
+ goto pgdat4;
+
+ if (!is_kvaddr(pgdat))
+ goto pgdat4;
+
+ if (node == 0)
+ return pgdat;
+
+ for (i = 1; i < node; i++) {
+ if (!readmem(info, pgdat + OFFSET(pglist_data.pgdat_next),
+ &pgdat, sizeof pgdat))
+ goto pgdat4;
+
+ if (!is_kvaddr(pgdat))
+ goto pgdat4;
+ }
+ return pgdat;
+
+pgdat4:
+ /*
* Get the pglist_data structure from symbol "contig_page_data".
*/
if (SYMBOL(contig_page_data) == NOT_FOUND_SYMBOL)
diff -puN makedumpfile.org/makedumpfile.h makedumpfile/makedumpfile.h
--- makedumpfile.org/makedumpfile.h 2007-05-11 23:06:33.000000000 +0900
+++ makedumpfile/makedumpfile.h 2007-05-11 23:20:00.000000000 +0900
@@ -612,6 +612,7 @@ struct offset_table {
long node_mem_map;
long node_start_pfn;
long node_spanned_pages;
+ long pgdat_next;
} pglist_data;
struct free_area {
long free_list;
[-- Attachment #3: 01-vaddr_to_offset_ia64.patch --]
[-- Type: application/octet-stream, Size: 8580 bytes --]
Signed-off-by: Bernhard Walle <bwalle@suse.de>
Signed-off-by: Ken'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp>
---
diff -puN backup/v1.1.3/ia64.c makedumpfile/ia64.c
--- backup/v1.1.3/ia64.c 2007-04-13 15:44:45.000000000 +0900
+++ makedumpfile/ia64.c 2007-05-11 23:02:25.000000000 +0900
@@ -23,6 +23,8 @@ get_phys_base_ia64(struct DumpInfo *info
int i;
struct pt_load_segment *pls;
+ info->phys_base = 0;
+
/*
* Default to 64MB.
*/
@@ -48,5 +50,125 @@ get_machdep_info_ia64(struct DumpInfo *i
return TRUE;
}
+unsigned long
+ia64_vtop(struct DumpInfo *info, unsigned long long vaddr)
+{
+ unsigned long paddr = 0, temp, page_dir, pgd_pte, page_middle, pmd_pte;
+ unsigned long page_table, pte;
+
+ if (VADDR_REGION(vaddr) != KERNEL_VMALLOC_REGION) {
+ ERRMSG("vaddr(%llx) is not KERNEL_VMALLOC_REGION.\n", vaddr);
+ return paddr;
+ }
+ paddr = vaddr_to_paddr(info, vaddr);
+ if (paddr)
+ return paddr;
+
+ /*
+ * Translate a virtual address to a physical address
+ * by using Layer 3 paging.
+ */
+ if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) {
+ ERRMSG("Can't get the symbol of swapper_pg_dir.\n");
+ return paddr;
+ }
+
+ /*
+ * Get PGD
+ */
+ temp = vaddr & MASK_PGD;
+ temp = temp >> (PGDIR_SHIFT - 3);
+ page_dir = SYMBOL(swapper_pg_dir) + temp;
+ if (!readmem(info, page_dir, &pgd_pte, sizeof pgd_pte)) {
+ ERRMSG("Can't get pgd_pte (page_dir:%lx).\n", page_dir);
+ return paddr;
+ }
+
+ /*
+ * Get PMD
+ */
+ temp = vaddr & MASK_PMD;
+ temp = temp >> (PMD_SHIFT - 3);
+ page_middle = pgd_pte + temp;
+ /*
+ * Convert physical address to virtual address
+ */
+ page_middle = paddr_to_vaddr(info, page_middle);
+ if (!readmem(info, page_middle, &pmd_pte, sizeof pmd_pte)) {
+ ERRMSG("Can't get pmd_pte (page_middle:%lx).\n", page_middle);
+ return paddr;
+ }
+
+ /*
+ * Get PTE
+ */
+ temp = vaddr & MASK_PTE;
+ temp = temp >> (PAGE_SHIFT - 3);
+ page_table = pmd_pte + temp;
+ /*
+ * Convert physical address to virtual address
+ */
+ page_table = paddr_to_vaddr(info, page_table);
+ if (!readmem(info, page_table, &pte, sizeof pte)) {
+ ERRMSG("Can't get pte (page_table:%lx).\n", page_table);
+ return paddr;
+ }
+
+ /*
+ * Get physical address
+ */
+ temp = vaddr & MASK_POFFSET;
+ paddr = (pte & _PAGE_PPN_MASK) + temp;
+ if (info->flag_debug) {
+ MSG("vaddr:%llx -> paddr:%lx\n", vaddr, paddr);
+ }
+
+ return paddr;
+}
+
+
+/*
+ * Convert Virtual Address to File Offest.
+ */
+off_t
+vaddr_to_offset_ia64(struct DumpInfo *info, unsigned long long vaddr)
+{
+ int i;
+ off_t offset;
+ struct pt_load_segment *pls;
+ unsigned long paddr;
+
+
+ switch (VADDR_REGION(vaddr)) {
+ case KERNEL_CACHED_REGION:
+ paddr = vaddr - (ulong)(KERNEL_CACHED_BASE);
+ break;
+
+ case KERNEL_UNCACHED_REGION:
+ paddr = vaddr - (ulong)(KERNEL_UNCACHED_BASE);
+ break;
+
+ case KERNEL_VMALLOC_REGION:
+ paddr = ia64_vtop(info, vaddr);
+ break;
+
+ default:
+ ERRMSG("Unknown region (%ld)\n", VADDR_REGION(vaddr));
+ return 0;
+ }
+
+ for (i = offset = 0; i < info->num_load_memory; i++) {
+ pls = &info->pt_load_segments[i];
+ if ((paddr >= pls->phys_start)
+ && (paddr < pls->phys_end)) {
+ offset = (off_t)(paddr - pls->phys_start) +
+ pls->file_offset;
+ break;
+ }
+ }
+
+ return offset;
+}
+
#endif /* ia64 */
diff -puN backup/v1.1.3/makedumpfile.c makedumpfile/makedumpfile.c
--- backup/v1.1.3/makedumpfile.c 2007-04-13 15:44:55.000000000 +0900
+++ makedumpfile/makedumpfile.c 2007-05-11 23:02:25.000000000 +0900
@@ -64,6 +64,44 @@ paddr_to_offset(struct DumpInfo *info, u
return offset;
}
+unsigned long long
+vaddr_to_paddr(struct DumpInfo *info, unsigned long long vaddr)
+{
+ int i;
+ unsigned long long paddr;
+ struct pt_load_segment *pls;
+
+ for (i = paddr = 0; i < info->num_load_memory; i++) {
+ pls = &info->pt_load_segments[i];
+ if ((vaddr >= pls->virt_start)
+ && (vaddr < pls->virt_end)) {
+ paddr = (off_t)(vaddr - pls->virt_start) +
+ pls->phys_start;
+ break;
+ }
+ }
+ return paddr;
+}
+
+unsigned long long
+paddr_to_vaddr(struct DumpInfo *info, unsigned long long paddr)
+{
+ int i;
+ unsigned long long vaddr;
+ struct pt_load_segment *pls;
+
+ for (i = vaddr = 0; i < info->num_load_memory; i++) {
+ pls = &info->pt_load_segments[i];
+ if ((paddr >= pls->phys_start)
+ && (paddr < pls->phys_end)) {
+ vaddr = (off_t)(paddr - pls->phys_start) +
+ pls->virt_start;
+ break;
+ }
+ }
+ return vaddr;
+}
+
/*
* Convert Virtual Address to File Offest.
* If this function returns 0x0, File Offset isn't found.
@@ -735,6 +773,7 @@ get_elf_info(struct DumpInfo *info)
* capture(2nd)-kernel, the problem will happen.
*/
info->page_size = sysconf(_SC_PAGE_SIZE);
+ info->page_shift = ffs(info->page_size) - 1;
info->max_mapnr = get_max_mapnr(info);
@@ -1364,6 +1403,7 @@ get_symbol_info(struct DumpInfo *info)
SYMBOL_INIT(system_utsname, "system_utsname");
SYMBOL_INIT(init_uts_ns, "init_uts_ns");
SYMBOL_INIT(_stext, "_stext");
+ SYMBOL_INIT(swapper_pg_dir, "swapper_pg_dir");
SYMBOL_INIT(phys_base, "phys_base");
SYMBOL_INIT(node_online_map, "node_online_map");
SYMBOL_INIT(node_data, "node_data");
@@ -1539,6 +1579,7 @@ generate_config(struct DumpInfo *info)
WRITE_SYMBOL("system_utsname", system_utsname);
WRITE_SYMBOL("init_uts_ns", init_uts_ns);
WRITE_SYMBOL("_stext", _stext);
+ WRITE_SYMBOL("swapper_pg_dir", swapper_pg_dir);
WRITE_SYMBOL("phys_base", phys_base);
WRITE_SYMBOL("node_online_map", node_online_map);
WRITE_SYMBOL("node_data", node_data);
@@ -1631,6 +1672,7 @@ read_config_basic_info(struct DumpInfo *
break;
}
info->page_size = page_size;
+ info->page_shift = ffs(info->page_size) - 1;
if (!get_release || !info->page_size) {
ERRMSG("Invalid format in %s", info->name_configfile);
@@ -1713,6 +1755,7 @@ read_config(struct DumpInfo *info)
READ_SYMBOL("system_utsname", system_utsname);
READ_SYMBOL("init_uts_ns", init_uts_ns);
READ_SYMBOL("_stext", _stext);
+ READ_SYMBOL("swapper_pg_dir", swapper_pg_dir);
READ_SYMBOL("phys_base", phys_base);
READ_SYMBOL("node_online_map", node_online_map);
READ_SYMBOL("node_data", node_data);
@@ -2206,6 +2249,7 @@ initial(struct DumpInfo *info)
if (!get_structure_info(info))
return FALSE;
}
+
if (!check_release(info))
return FALSE;
diff -puN backup/v1.1.3/makedumpfile.h makedumpfile/makedumpfile.h
--- backup/v1.1.3/makedumpfile.h 2007-04-13 15:44:55.000000000 +0900
+++ makedumpfile/makedumpfile.h 2007-05-11 23:02:25.000000000 +0900
@@ -367,6 +367,22 @@ do { \
#define _SECTION_SIZE_BITS (30)
#define _MAX_PHYSMEM_BITS (50)
#define SIZEOF_NODE_ONLINE_MAP (32)
+
+/*
+ * Layer 3 paging
+ */
+#define _PAGE_PPN_MASK (((1UL << _MAX_PHYSMEM_BITS) - 1) & ~0xfffUL)
+#define PAGE_SHIFT (info->page_shift)
+#define PTRS_PER_PTD_SHIFT (PAGE_SHIFT - 3)
+
+#define PMD_SHIFT (PAGE_SHIFT + PTRS_PER_PTD_SHIFT)
+#define PGDIR_SHIFT (PMD_SHIFT + PTRS_PER_PTD_SHIFT)
+
+#define MASK_POFFSET ((1UL << PAGE_SHIFT) - 1)
+#define MASK_PTE ((1UL << PMD_SHIFT) - 1) &~((1UL << PAGE_SHIFT) - 1)
+#define MASK_PMD ((1UL << PGDIR_SHIFT) - 1) &~((1UL << PMD_SHIFT) - 1)
+#define MASK_PGD ((1UL << REGION_SHIFT) - 1) & (~((1UL << PGDIR_SHIFT) - 1))
+
#endif /* ia64 */
/*
@@ -398,10 +414,11 @@ int get_machdep_info_ppc64();
#ifdef __ia64__ /* ia64 */
int get_phys_base_ia64();
int get_machdep_info_ia64();
+off_t vaddr_to_offset_ia64();
#define get_machdep_info(X) get_machdep_info_ia64(X)
#define get_phys_base(X) get_phys_base_ia64(X)
-#define vaddr_to_offset(X, Y) vaddr_to_offset_general(X, Y)
-#define VADDR_REGION(X) ((X) >> REGION_SHIFT)
+#define vaddr_to_offset(X, Y) vaddr_to_offset_ia64(X, Y)
+#define VADDR_REGION(X) (((unsigned long)(X)) >> REGION_SHIFT)
#endif /* ia64 */
#define MSG(x...) fprintf(stderr, x)
@@ -486,6 +503,7 @@ struct DumpInfo {
int flag_rearrange; /* flag of creating dumpfile from
flattened format */
long page_size; /* size of page */
+ long page_shift;
unsigned long long max_mapnr; /* number of page descriptor */
unsigned long section_size_bits;
unsigned long max_physmem_bits;
@@ -555,6 +573,7 @@ struct symbol_table {
unsigned long system_utsname;
unsigned long init_uts_ns;
unsigned long _stext;
+ unsigned long swapper_pg_dir;
unsigned long phys_base;
unsigned long node_online_map;
unsigned long node_data;
@@ -651,3 +670,7 @@ struct dwarf_info {
extern struct dwarf_info dwarf_info;
+int readmem();
+unsigned long long vaddr_to_paddr();
+unsigned long long paddr_to_vaddr();
+
[-- Attachment #4: Type: text/plain, Size: 143 bytes --]
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] [makedumpfile] Implement memory regions on IA64
2007-05-11 6:59 ` Ken'ichi Ohmichi
@ 2007-05-14 18:15 ` Bernhard Walle
2007-05-14 21:49 ` Bernhard Walle
0 siblings, 1 reply; 10+ messages in thread
From: Bernhard Walle @ 2007-05-14 18:15 UTC (permalink / raw)
To: Ken'ichi Ohmichi; +Cc: Jay Lan, Kexec Mailing List
[-- Attachment #1.1: Type: text/plain, Size: 1304 bytes --]
Hi,
sorry for the late reply, but I was out of office last week.
* Ken'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp> [2007-05-11 08:59]:
> 2007/04/26 21:37:25 +0200, Bernhard Walle <bwalle@suse.de> wrote:
> >This patch fixes an error in vaddr_to_offset_ia64() which happened on
> >a SGI machine here while retrieving the utsname from the kernel dump
> >image. It implements memory region support for IA64.
>
> For ia64 DISCONTIGMEM support, I added the translation (virtual address
> to physical address) by using layer 3 paging into your patch.
> I created 2 attached patches for ia64 DISCONTIGMEM support.
>
> I confirmed makedumpfile with these patches can run on linux-2.6.18 kernel
> (made of RHEL5 kernel by changing configs from SPARSEMEM to DISCONTIGMEM).
> Could you please test them on SLES10 ?
it doesn't work here. The config file is generated, but at runtime I
get a SEGV which is caused by a endless recusion of ia64_vtop() while
resolving the utsname.
I'm looking into this ...
> BTW, the patches don't run on stock linux-2.6.20 w/DISCONTIGMEM
> (it works with stock linux-2.6.20 w/SPARSEMEM)
> I am trying to resolve the problem and if you have any idea about
> kernel changes between 2.6.18-20, please let me know.
Sorry, no.
Thanks,
Bernhard
[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]
[-- Attachment #2: Type: text/plain, Size: 143 bytes --]
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] [makedumpfile] Implement memory regions on IA64
2007-05-14 18:15 ` Bernhard Walle
@ 2007-05-14 21:49 ` Bernhard Walle
2007-05-15 22:08 ` Bernhard Walle
0 siblings, 1 reply; 10+ messages in thread
From: Bernhard Walle @ 2007-05-14 21:49 UTC (permalink / raw)
To: Ken'ichi Ohmichi, Kexec Mailing List, Jay Lan
[-- Attachment #1.1: Type: text/plain, Size: 1530 bytes --]
* Bernhard Walle <bwalle@suse.de> [2007-05-14 20:15]:
> * Ken'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp> [2007-05-11 08:59]:
> > 2007/04/26 21:37:25 +0200, Bernhard Walle <bwalle@suse.de> wrote:
> > >This patch fixes an error in vaddr_to_offset_ia64() which happened on
> > >a SGI machine here while retrieving the utsname from the kernel dump
> > >image. It implements memory region support for IA64.
> >
> > For ia64 DISCONTIGMEM support, I added the translation (virtual address
> > to physical address) by using layer 3 paging into your patch.
> > I created 2 attached patches for ia64 DISCONTIGMEM support.
> >
> > I confirmed makedumpfile with these patches can run on linux-2.6.18 kernel
> > (made of RHEL5 kernel by changing configs from SPARSEMEM to DISCONTIGMEM).
> > Could you please test them on SLES10 ?
>
> it doesn't work here. The config file is generated, but at runtime I
> get a SEGV which is caused by a endless recusion of ia64_vtop() while
> resolving the utsname.
Because of CONFIG_PGTABLE_4=y in SUSE kernels. Your implementation
assumes a 3-level-pagetable.
> > BTW, the patches don't run on stock linux-2.6.20 w/DISCONTIGMEM
> > (it works with stock linux-2.6.20 w/SPARSEMEM)
> > I am trying to resolve the problem and if you have any idea about
> > kernel changes between 2.6.18-20, please let me know.
>
> Sorry, no.
And I guess because of the same reason (maybe the default changed?).
I'm working on support for the 4 layer pagetable.
Thanks,
Bernhard
[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]
[-- Attachment #2: Type: text/plain, Size: 143 bytes --]
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] [makedumpfile] Implement memory regions on IA64
2007-05-14 21:49 ` Bernhard Walle
@ 2007-05-15 22:08 ` Bernhard Walle
2007-05-16 11:20 ` Ken'ichi Ohmichi
0 siblings, 1 reply; 10+ messages in thread
From: Bernhard Walle @ 2007-05-15 22:08 UTC (permalink / raw)
To: Ken'ichi Ohmichi; +Cc: Jay Lan, Kexec Mailing List
Hello,
* Bernhard Walle <bwalle@suse.de> [2007-05-14 23:49]:
>
> I'm working on support for the 4 layer pagetable.
Here's my first attempt. It works with SLES 10, SP1 on a Tiger4
machine with 16 GiB of memory. (I had still problems with a big
SGI machine when creating the bitmap. I'm investigating this, too.)
The problem is not to implement the 4 layer page table, but to
*detect* it. crash uses the built-in configuration data in the kernel
image, and that's what I used in my patch. If you have a better and
still reliable method, I'm open to suggestions. :-)
Also, I only use the page table translation when the memory is
vmalloc'd. That's the same way crash does it and that should be
well-tested.
The patch requires your two patches. Please give me your feedback!
And I hope I didn't accidentally break the 3 layer page table.
Thanks,
Bernhard
---
ia64.c | 148 +++++++++++++++++++++++++++++++++++++++++++++---
makedumpfile.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
makedumpfile.h | 43 +++++++++++++-
3 files changed, 354 insertions(+), 11 deletions(-)
--- a/ia64.c
+++ b/ia64.c
@@ -3,6 +3,9 @@
*
* Copyright (C) 2006 NEC Corporation
*
+ * Some parts are taken and adapted from the crash-utility,
+ * (c) by RedHat Inc.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -17,6 +20,18 @@
#include "makedumpfile.h"
+
+/*
+ * vmalloc() starting address is either the traditional 0xa000000000000000 or
+ * bumped up in 2.6 to 0xa000000200000000.
+ */
+int
+is_vmalloc_addr_ia64(struct DumpInfo *info, unsigned long vaddr)
+{
+ return ((vaddr >= info->vmalloc_start) &&
+ (vaddr < (ulong)KERNEL_UNCACHED_BASE));
+}
+
int
get_phys_base_ia64(struct DumpInfo *info)
{
@@ -51,18 +66,80 @@ get_machdep_info_ia64(struct DumpInfo *i
}
unsigned long
-ia64_vtop(struct DumpInfo *info, unsigned long long vaddr)
+ia64_vtop3(struct DumpInfo *info, unsigned long long vaddr)
{
unsigned long paddr = 0, temp, page_dir, pgd_pte, page_middle, pmd_pte;
unsigned long page_table, pte;
- if (VADDR_REGION(vaddr) != KERNEL_VMALLOC_REGION) {
- ERRMSG("vaddr(%llx) is not KERNEL_VMALLOC_REGION.\n", vaddr);
+
+ /*
+ * Translate a virtual address to a physical address
+ * by using Layer 3 paging.
+ */
+ if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) {
+ ERRMSG("Can't get the symbol of swapper_pg_dir.\n");
return paddr;
}
- paddr = vaddr_to_paddr(info, vaddr);
- if (paddr)
+
+ /*
+ * Get PGD
+ */
+ temp = vaddr & MASK_PGD_3L;
+ temp = temp >> (PGDIR_SHIFT_3L - 3);
+ page_dir = SYMBOL(swapper_pg_dir) + temp;
+ if (!readmem(info, page_dir, &pgd_pte, sizeof pgd_pte)) {
+ ERRMSG("Can't get pgd_pte (page_dir:%lx).\n", page_dir);
return paddr;
+ }
+
+ /*
+ * Get PMD
+ */
+ temp = vaddr & MASK_PMD;
+ temp = temp >> (PMD_SHIFT - 3);
+ page_middle = pgd_pte + temp;
+ /*
+ * Convert physical address to virtual address
+ */
+ page_middle = paddr_to_vaddr(info, page_middle);
+ if (!readmem(info, page_middle, &pmd_pte, sizeof pmd_pte)) {
+ ERRMSG("Can't get pmd_pte (page_middle:%lx).\n", page_middle);
+ return paddr;
+ }
+
+ /*
+ * Get PTE
+ */
+ temp = vaddr & MASK_PTE;
+ temp = temp >> (PAGE_SHIFT - 3);
+ page_table = pmd_pte + temp;
+ /*
+ * Convert physical address to virtual address
+ */
+ page_table = paddr_to_vaddr(info, page_table);
+ if (!readmem(info, page_table, &pte, sizeof pte)) {
+ ERRMSG("Can't get pte (page_table:%lx).\n", page_table);
+ return paddr;
+ }
+
+ /*
+ * Get physical address
+ */
+ temp = vaddr & MASK_POFFSET;
+ paddr = (pte & _PAGE_PPN_MASK) + temp;
+ if (info->flag_debug) {
+ MSG("vaddr:%llx -> paddr:%lx\n", vaddr, paddr);
+ }
+
+ return paddr;
+}
+
+unsigned long
+ia64_vtop4(struct DumpInfo *info, unsigned long long vaddr)
+{
+ unsigned long paddr = 0, temp, page_dir, pgd_pte, page_upper,
+ pud_pte, page_middle, pmd_pte;
+ unsigned long page_table, pte;
/*
* Translate a virtual address to a physical address
@@ -76,8 +153,8 @@ ia64_vtop(struct DumpInfo *info, unsigne
/*
* Get PGD
*/
- temp = vaddr & MASK_PGD;
- temp = temp >> (PGDIR_SHIFT - 3);
+ temp = vaddr & MASK_PGD_4L;
+ temp = temp >> (PGDIR_SHIFT_4L - 3);
page_dir = SYMBOL(swapper_pg_dir) + temp;
if (!readmem(info, page_dir, &pgd_pte, sizeof pgd_pte)) {
ERRMSG("Can't get pgd_pte (page_dir:%lx).\n", page_dir);
@@ -85,11 +162,26 @@ ia64_vtop(struct DumpInfo *info, unsigne
}
/*
+ * Get PUD
+ */
+ temp = vaddr & MASK_PUD;
+ temp = temp >> (PUD_SHIFT - 3);
+ page_upper = pgd_pte + temp;
+ /*
+ * Convert physical address to virtual address
+ */
+ page_upper = paddr_to_vaddr(info, page_upper);
+ if (!readmem(info, page_upper, &pud_pte, sizeof pud_pte)) {
+ ERRMSG("Can't get pud_pte (page_upper:%lx).\n", page_upper);
+ return paddr;
+ }
+
+ /*
* Get PMD
*/
temp = vaddr & MASK_PMD;
temp = temp >> (PMD_SHIFT - 3);
- page_middle = pgd_pte + temp;
+ page_middle = pud_pte + temp;
/*
* Convert physical address to virtual address
*/
@@ -126,6 +218,30 @@ ia64_vtop(struct DumpInfo *info, unsigne
return paddr;
}
+unsigned long
+ia64_vtop(struct DumpInfo *info, unsigned long long vaddr)
+{
+ unsigned long paddr = 0;
+
+ if (VADDR_REGION(vaddr) != KERNEL_VMALLOC_REGION) {
+ ERRMSG("vaddr(%llx) is not KERNEL_VMALLOC_REGION.\n", vaddr);
+ return paddr;
+ }
+ paddr = vaddr_to_paddr(info, vaddr);
+ if (paddr)
+ return paddr;
+
+ if (!is_vmalloc_addr_ia64(info, vaddr)) {
+ paddr = vaddr - info->kernel_start +
+ (info->phys_base & KERNEL_TR_PAGE_MASK);
+ return paddr;
+ }
+
+ if (info->mem_flags & MEMORY_4LAYER_PAGETABLE)
+ return ia64_vtop4(info, vaddr);
+ else
+ return ia64_vtop3(info, vaddr);
+}
/*
* Convert Virtual Address to File Offest.
@@ -170,5 +286,21 @@ vaddr_to_offset_ia64(struct DumpInfo *in
return offset;
}
+int
+get_machdep_kernel_start_ia64(struct DumpInfo *info)
+{
+ if (SYMBOL(_stext) == NOT_FOUND_SYMBOL)
+ return FALSE;
+
+ info->kernel_start = SYMBOL(_stext);
+
+ if (VADDR_REGION(info->kernel_start) == KERNEL_VMALLOC_REGION)
+ info->vmalloc_start = info->kernel_start + 4*1024UL*1024UL*1024UL;
+ else
+ info->vmalloc_start = KERNEL_VMALLOC_BASE;
+
+ return TRUE;
+}
+
#endif /* ia64 */
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -1420,6 +1420,174 @@ get_symbol_info(struct DumpInfo *info)
return TRUE;
}
+
+int
+read_kernel_config(struct DumpInfo *info)
+{
+ int ii, ret, end, found=0;
+ unsigned long size, bufsz;
+ char *pos, *ln, *buf, *head, *tail, *val, *uncomp;
+ char line[512];
+ z_stream stream;
+ unsigned long kernel_config_data;
+
+ kernel_config_data = get_symbol_addr(info, "kernel_config_data");
+ if (kernel_config_data <= 0) {
+ ERRMSG("Can't read kernel cofiguration from kernel binary");
+ return FALSE;
+ }
+
+ /* We don't know how large IKCONFIG is, so we start with
+ * 32k, if we can't find MAGIC_END assume we didn't read
+ * enough, double it and try again.
+ */
+ ii = 32;
+
+again:
+ size = ii * 1024;
+
+ if ((buf = (char *)malloc(size)) == NULL) {
+ MSG("cannot malloc IKCONFIG input buffer\n");
+ return FALSE;
+ }
+
+ if (!readmem(info, kernel_config_data, buf, size)) {
+ MSG("cannot read kernel_config_data\n");
+ goto out2;
+ }
+
+ /* Find the start */
+ if (strstr(buf, MAGIC_START))
+ head = buf + MAGIC_SIZE + 10; /* skip past MAGIC_START and gzip header */
+ else {
+ MSG("could not find MAGIC_START!\n");
+ goto out2;
+ }
+
+ tail = head;
+
+ end = strlen(MAGIC_END);
+
+ /* Find the end*/
+ while (tail < (buf + (size - 1))) {
+
+ if (strncmp(tail, MAGIC_END, end)==0) {
+ found = 1;
+ break;
+ }
+ tail++;
+ }
+
+ if (found) {
+ bufsz = tail - head;
+ size = 10 * bufsz;
+ if ((uncomp = (char *)malloc(size)) == NULL) {
+ MSG("cannot malloc IKCONFIG output buffer\n");
+ goto out2;
+ }
+ } else {
+ if (ii > 512) {
+ MSG("could not find MAGIC_END!\n");
+ goto out2;
+ } else {
+ free(buf);
+ ii *= 2;
+ goto again;
+ }
+ }
+
+
+ /* initialize zlib */
+ stream.next_in = (Bytef *)head;
+ stream.avail_in = (uInt)bufsz;
+
+ stream.next_out = (Bytef *)uncomp;
+ stream.avail_out = (uInt)size;
+
+ stream.zalloc = NULL;
+ stream.zfree = NULL;
+ stream.opaque = NULL;
+
+ ret = inflateInit2(&stream, -MAX_WBITS);
+ if (ret != Z_OK) {
+ ERRMSG("error while reading kernel config, inflateInit2 "
+ "returned %d\n", ret);
+ goto out1;
+ }
+
+ ret = inflate(&stream, Z_FINISH);
+
+ if (ret != Z_STREAM_END) {
+ inflateEnd(&stream);
+ if (ret == Z_NEED_DICT ||
+ (ret == Z_BUF_ERROR && stream.avail_in == 0)) {
+ ERRMSG("error while reading kernel config, stream.avail_in = 0,"
+ "inflate returned %d\n", ret);
+ goto out1;
+ }
+ ERRMSG("error while reading kernel config, inflate returned"
+ "with %d\n", ret);
+ goto out1;
+ }
+ size = stream.total_out;
+
+ ret = inflateEnd(&stream);
+
+ pos = uncomp;
+
+ do {
+ ret = sscanf(pos, "%511[^\n]\n%n", line, &ii);
+ if (ret > 0) {
+ pos += ii;
+
+ ln = line;
+
+ /* skip leading whitespace */
+ while (is_blank(*ln))
+ ln++;
+
+ /* skip comments */
+ if (*ln == '#')
+ continue;
+
+ /* Find '=' */
+ if ((head = strchr(ln, '=')) != NULL) {
+ *head = '\0';
+ val = head + 1;
+
+ head--;
+
+ /* skip trailing whitespace */
+ while (is_blank(*head)) {
+ *head = '\0';
+ head--;
+ }
+
+ /* skip whitespace */
+ while (is_blank(*val))
+ val++;
+
+ } else /* Bad line, skip it */
+ continue;
+
+ if (strcmp(ln, "CONFIG_PGTABLE_4") == 0)
+ info->mem_flags |= MEMORY_4LAYER_PAGETABLE;
+ }
+ } while (ret > 0);
+
+
+ free(uncomp);
+ free(buf);
+ return TRUE;
+
+out1:
+ free(uncomp);
+out2:
+ free(buf);
+
+ return FALSE;
+}
+
int
get_structure_info(struct DumpInfo *info)
{
@@ -2289,9 +2457,15 @@ initial(struct DumpInfo *info)
return FALSE;
}
+ if (!get_machdep_kernel_start(info))
+ return FALSE;
+
if (!check_release(info))
return FALSE;
+ if (!read_kernel_config(info))
+ return FALSE;
+
if (!get_machdep_info(info))
return FALSE;
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -29,6 +29,7 @@
#include <libelf.h>
#include <dwarf.h>
#include <byteswap.h>
+#include <ctype.h>
#include "diskdump_mod.h"
/*
@@ -64,6 +65,19 @@ enum {
#define LSEEKED_PDESC (2)
#define LSEEKED_PDATA (3)
+/*
+ * Flags
+ */
+#define MEMORY_4LAYER_PAGETABLE (1 << 0)
+
+/*
+ * For kernel configuration
+ */
+#define MAGIC_START "IKCFG_ST"
+#define MAGIC_END "IKCFG_ED"
+#define MAGIC_SIZE (sizeof(MAGIC_START) - 1)
+
+
static inline int
test_bit(int nr, unsigned long addr)
{
@@ -73,6 +87,12 @@ test_bit(int nr, unsigned long addr)
return ((mask & addr) != 0);
}
+static inline int
+is_blank(int c)
+{
+ return c == ' ' || c == '\t';
+}
+
#define isLRU(flags) test_bit(PG_lru, flags)
#define isPrivate(flags) test_bit(PG_private, flags)
#define isSwapCache(flags) test_bit(PG_swapcache, flags)
@@ -376,12 +396,21 @@ do { \
#define PTRS_PER_PTD_SHIFT (PAGE_SHIFT - 3)
#define PMD_SHIFT (PAGE_SHIFT + PTRS_PER_PTD_SHIFT)
-#define PGDIR_SHIFT (PMD_SHIFT + PTRS_PER_PTD_SHIFT)
+#define PGDIR_SHIFT_3L (PMD_SHIFT + PTRS_PER_PTD_SHIFT)
#define MASK_POFFSET ((1UL << PAGE_SHIFT) - 1)
#define MASK_PTE ((1UL << PMD_SHIFT) - 1) &~((1UL << PAGE_SHIFT) - 1)
-#define MASK_PMD ((1UL << PGDIR_SHIFT) - 1) &~((1UL << PMD_SHIFT) - 1)
-#define MASK_PGD ((1UL << REGION_SHIFT) - 1) & (~((1UL << PGDIR_SHIFT) - 1))
+#define MASK_PMD ((1UL << PGDIR_SHIFT_3L) - 1) &~((1UL << PMD_SHIFT) - 1)
+#define MASK_PGD_3L ((1UL << REGION_SHIFT) - 1) & (~((1UL << PGDIR_SHIFT_3L) - 1))
+
+/*
+ * Layer 4 paging
+ */
+#define PUD_SHIFT (PMD_SHIFT + PTRS_PER_PTD_SHIFT)
+#define PGDIR_SHIFT_4L (PUD_SHIFT + PTRS_PER_PTD_SHIFT)
+
+#define MASK_PUD ((1UL << REGION_SHIFT) - 1) & (~((1UL << PUD_SHIFT) - 1))
+#define MASK_PGD_4L ((1UL << REGION_SHIFT) - 1) & (~((1UL << PGDIR_SHIFT_4L) - 1))
#endif /* ia64 */
@@ -393,6 +422,7 @@ int get_machdep_info_x86();
#define get_phys_base(X) TRUE
#define get_machdep_info(X) get_machdep_info_x86(X)
#define vaddr_to_offset(X, Y) vaddr_to_offset_general(X,Y)
+#define get_machdep_kernel_start(X) TRUE
#endif /* x86 */
#ifdef __x86_64__
@@ -402,6 +432,7 @@ off_t vaddr_to_offset_x86_64();
#define get_phys_base(X) get_phys_base_x86_64(X)
#define get_machdep_info(X) get_machdep_info_x86_64(X)
#define vaddr_to_offset(X, Y) vaddr_to_offset_x86_64(X, Y)
+#define get_machdep_kernel_start(X) TRUE
#endif /* x86_64 */
#ifdef __powerpc__ /* powerpc */
@@ -409,16 +440,19 @@ int get_machdep_info_ppc64();
#define get_machdep_info(X) get_machdep_info_ppc64(X)
#define get_phys_base(X) TRUE
#define vaddr_to_offset(X, Y) vaddr_to_offset_general(X, Y)
+#define get_machdep_kernel_start(X) TRUE
#endif /* powerpc */
#ifdef __ia64__ /* ia64 */
int get_phys_base_ia64();
int get_machdep_info_ia64();
+int get_machdep_kernel_start_ia64();
off_t vaddr_to_offset_ia64();
#define get_machdep_info(X) get_machdep_info_ia64(X)
#define get_phys_base(X) get_phys_base_ia64(X)
#define vaddr_to_offset(X, Y) vaddr_to_offset_ia64(X, Y)
#define VADDR_REGION(X) (((unsigned long)(X)) >> REGION_SHIFT)
+#define get_machdep_kernel_start(X) get_machdep_kernel_start_ia64(X)
#endif /* ia64 */
#define MSG(x...) fprintf(stderr, x)
@@ -509,6 +543,8 @@ struct DumpInfo {
unsigned long max_physmem_bits;
unsigned long sections_per_root;
unsigned long phys_base;
+ unsigned long kernel_start;
+ unsigned long vmalloc_start;
/*
* diskdimp info:
@@ -532,6 +568,7 @@ struct DumpInfo {
*/
unsigned int num_mem_map;
struct mem_map_data *mem_map_data;
+ unsigned int mem_flags;
/*
* Dump memory image info:
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] [makedumpfile] Implement memory regions on IA64
2007-05-15 22:08 ` Bernhard Walle
@ 2007-05-16 11:20 ` Ken'ichi Ohmichi
2007-05-16 11:26 ` Bernhard Walle
2007-05-21 9:32 ` Ken'ichi Ohmichi
0 siblings, 2 replies; 10+ messages in thread
From: Ken'ichi Ohmichi @ 2007-05-16 11:20 UTC (permalink / raw)
To: Bernhard Walle; +Cc: Jay Lan, Kexec Mailing List
Hi Bernhard,
2007/05/16 00:08:45 +0200, Bernhard Walle <bwalle@suse.de> wrote:
>Hello,
>
>* Bernhard Walle <bwalle@suse.de> [2007-05-14 23:49]:
>>
>> I'm working on support for the 4 layer pagetable.
>
>Here's my first attempt. It works with SLES 10, SP1 on a Tiger4
>machine with 16 GiB of memory. (I had still problems with a big
>SGI machine when creating the bitmap. I'm investigating this, too.)
>
>The problem is not to implement the 4 layer page table, but to
>*detect* it. crash uses the built-in configuration data in the kernel
>image, and that's what I used in my patch. If you have a better and
>still reliable method, I'm open to suggestions. :-)
Thank you for the patch.
I tested makedumpfile with your patch on linux-2.6.18 ia64,
and it output the following message and failed.
Error message:
$ makedumpfile -cd 31 -x vmlinux vmcore dumpfile
Can't read kernel cofiguration from kernel binary
makedumpfile Failed.
$
The reason was that kernel binary file didn't have "kernel_config_data"
because CONFIG_IKCONFIG was not set in my .config.
It is uncertain that "kernel_config_data" exists in a kernel binary.
I propose that makedumpfile distinguishes the page table (3L or 4L)
by checking the defined file name of pud_t.
I'm trying for the above implementation.
I will send you the patch when it is complete.
All the pud_t(s) of linux-2.6.16 - 2.6.21 are defined in the following files:
CONFIG_PGTABLE_4
include/asm-ia64/page.h
!CONFIG_PGTABLE_4
include/asm-generic/pgtable-nopud.h
Thanks
Ken'ichi Ohmichi
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] [makedumpfile] Implement memory regions on IA64
2007-05-16 11:20 ` Ken'ichi Ohmichi
@ 2007-05-16 11:26 ` Bernhard Walle
2007-05-21 9:32 ` Ken'ichi Ohmichi
1 sibling, 0 replies; 10+ messages in thread
From: Bernhard Walle @ 2007-05-16 11:26 UTC (permalink / raw)
To: Ken'ichi Ohmichi; +Cc: Jay Lan, Kexec Mailing List
* Ken'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp> [2007-05-16 13:20]:
>
> I propose that makedumpfile distinguishes the page table (3L or 4L)
> by checking the defined file name of pud_t.
> I'm trying for the above implementation.
> I will send you the patch when it is complete.
If that works it's clearly the better approach.
Thanks,
Bernhard
--
SUSE LINUX Products GmbH Tel. +49 (911) 74053-0
Maxfeldstr. 5 GF: Markus Rex
90409 Nürnberg, Germany HRB 16746 (AG Nürnberg)
OpenPGP DDAF6454: F61F 34CC 09CA FB82 C9F6 BA4B 8865 3696 DDAF 6454
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] [makedumpfile] Implement memory regions on IA64
2007-05-16 11:20 ` Ken'ichi Ohmichi
2007-05-16 11:26 ` Bernhard Walle
@ 2007-05-21 9:32 ` Ken'ichi Ohmichi
2007-05-21 9:54 ` Bernhard Walle
1 sibling, 1 reply; 10+ messages in thread
From: Ken'ichi Ohmichi @ 2007-05-21 9:32 UTC (permalink / raw)
To: Bernhard Walle; +Cc: Jay Lan, Kexec Mailing List
Hi Bernhard,
2007/05/16 20:20:00 +0900, "Ken'ichi Ohmichi" <oomichi@mxs.nes.nec.co.jp> wrote:
>I propose that makedumpfile distinguishes the page table (3L or 4L)
>by checking the defined file name of pud_t.
>I'm trying for the above implementation.
>I will send you the patch when it is complete.
The attached patch is for the above implementation.
It works fine with linux-2.6.18.
Could you test it with your environment ?
Please apply the attached patch with the following makedumpfile:
makedumpfile-1.1.3
+ 2007/05/11 by Ken'ichi, 01-vaddr_to_offset_ia64.patch
+ 2007/05/11 by Ken'ichi, 02-ia64-discontigmem.patch
+ 2007/05/16 by Bernhard, [Re: Implement memory regions on IA64] patch
+ 2007/05/21 by Ken'ichi, [Re: Fix missing last node] patch
Thanks
Ken'ichi Ohmichi
--
diff -puN makedumpfile.org/ia64.c makedumpfile/ia64.c
--- makedumpfile.org/ia64.c 2007-05-21 19:20:06.000000000 +0900
+++ makedumpfile/ia64.c 2007-05-21 19:34:06.000000000 +0900
@@ -62,6 +62,15 @@ get_machdep_info_ia64(struct DumpInfo *i
info->section_size_bits = _SECTION_SIZE_BITS;
info->max_physmem_bits = _MAX_PHYSMEM_BITS;
+ if (!strncmp(SRCFILE(pud_t), STR_PUD_T_4L, strlen(STR_PUD_T_4L)))
+ info->mem_flags |= MEMORY_4LAYER_PAGETABLE;
+
+ else if (!strncmp(SRCFILE(pud_t), STR_PUD_T_3L, strlen(STR_PUD_T_3L)))
+ info->mem_flags |= MEMORY_3LAYER_PAGETABLE;
+
+ else
+ MSG("Can't distinguish the pgtable.\n");
+
return TRUE;
}
diff -puN makedumpfile.org/makedumpfile.c makedumpfile/makedumpfile.c
--- makedumpfile.org/makedumpfile.c 2007-05-21 19:20:06.000000000 +0900
+++ makedumpfile/makedumpfile.c 2007-05-21 19:28:54.000000000 +0900
@@ -26,6 +26,7 @@ struct symbol_table symbol_table;
struct size_table size_table;
struct offset_table offset_table;
struct array_table array_table;
+struct srcfile_table srcfile_table;
struct dwarf_info dwarf_info;
struct vm_table *vt = 0;
@@ -1141,6 +1142,15 @@ is_search_symbol(int cmd)
return FALSE;
}
+int
+is_search_srcfile(int cmd)
+{
+ if (cmd == DWARF_INFO_GET_TYPEDEF_SRCNAME)
+ return TRUE;
+ else
+ return FALSE;
+}
+
static void
search_structure(Dwarf *dwarfd, Dwarf_Die *die, int *found)
{
@@ -1190,6 +1200,49 @@ search_structure(Dwarf *dwarfd, Dwarf_Di
}
static void
+search_srcfile(Dwarf *dwarfd, Dwarf_Die *die, int *found)
+{
+ int tag = 0, rtag = 0;
+ char *src_name = NULL;
+ const char *name;
+
+ switch (dwarf_info.cmd) {
+ case DWARF_INFO_GET_TYPEDEF_SRCNAME:
+ rtag = DW_TAG_typedef;
+ break;
+ }
+
+ /*
+ * If we get to here then we don't have any more
+ * children, check to see if this is a relevant tag
+ */
+ do {
+ tag = dwarf_tag(die);
+ name = dwarf_diename(die);
+
+ if ((tag != rtag) || (!name)
+ || strcmp(name, dwarf_info.decl_name))
+ continue;
+
+ src_name = (char *)dwarf_decl_file(die);
+
+ if (!src_name)
+ break;
+
+ } while (!dwarf_siblingof(die, die));
+
+ if (!src_name)
+ return;
+
+ /*
+ * Found the demanded one.
+ */
+ strncpy(dwarf_info.src_name, src_name, LEN_SRCFILE);
+
+ *found = TRUE;
+}
+
+static void
search_symbol(Dwarf *dwarfd, Dwarf_Die *die, int *found)
{
int tag;
@@ -1250,6 +1303,9 @@ search_die_tree(Dwarf *dwarfd, Dwarf_Die
else if (is_search_symbol(dwarf_info.cmd))
search_symbol(dwarfd, die, found);
+
+ else if (is_search_srcfile(dwarf_info.cmd))
+ search_srcfile(dwarfd, die, found);
}
int
@@ -1390,6 +1446,23 @@ get_array_length(char *name01, char *nam
return dwarf_info.array_length;
}
+/*
+ * Get the source filename.
+ */
+int
+get_source_filename(char *decl_name, char *src_name, int cmd)
+{
+ dwarf_info.cmd = cmd;
+ dwarf_info.decl_name = decl_name;
+
+ if (!get_debug_info())
+ return FALSE;
+
+ strncpy(src_name, dwarf_info.src_name, LEN_SRCFILE);
+
+ return TRUE;
+}
+
int
get_symbol_info(struct DumpInfo *info)
{
@@ -1420,174 +1493,6 @@ get_symbol_info(struct DumpInfo *info)
return TRUE;
}
-
-int
-read_kernel_config(struct DumpInfo *info)
-{
- int ii, ret, end, found=0;
- unsigned long size, bufsz;
- char *pos, *ln, *buf, *head, *tail, *val, *uncomp;
- char line[512];
- z_stream stream;
- unsigned long kernel_config_data;
-
- kernel_config_data = get_symbol_addr(info, "kernel_config_data");
- if (kernel_config_data <= 0) {
- ERRMSG("Can't read kernel cofiguration from kernel binary");
- return FALSE;
- }
-
- /* We don't know how large IKCONFIG is, so we start with
- * 32k, if we can't find MAGIC_END assume we didn't read
- * enough, double it and try again.
- */
- ii = 32;
-
-again:
- size = ii * 1024;
-
- if ((buf = (char *)malloc(size)) == NULL) {
- MSG("cannot malloc IKCONFIG input buffer\n");
- return FALSE;
- }
-
- if (!readmem(info, kernel_config_data, buf, size)) {
- MSG("cannot read kernel_config_data\n");
- goto out2;
- }
-
- /* Find the start */
- if (strstr(buf, MAGIC_START))
- head = buf + MAGIC_SIZE + 10; /* skip past MAGIC_START and gzip header */
- else {
- MSG("could not find MAGIC_START!\n");
- goto out2;
- }
-
- tail = head;
-
- end = strlen(MAGIC_END);
-
- /* Find the end*/
- while (tail < (buf + (size - 1))) {
-
- if (strncmp(tail, MAGIC_END, end)==0) {
- found = 1;
- break;
- }
- tail++;
- }
-
- if (found) {
- bufsz = tail - head;
- size = 10 * bufsz;
- if ((uncomp = (char *)malloc(size)) == NULL) {
- MSG("cannot malloc IKCONFIG output buffer\n");
- goto out2;
- }
- } else {
- if (ii > 512) {
- MSG("could not find MAGIC_END!\n");
- goto out2;
- } else {
- free(buf);
- ii *= 2;
- goto again;
- }
- }
-
-
- /* initialize zlib */
- stream.next_in = (Bytef *)head;
- stream.avail_in = (uInt)bufsz;
-
- stream.next_out = (Bytef *)uncomp;
- stream.avail_out = (uInt)size;
-
- stream.zalloc = NULL;
- stream.zfree = NULL;
- stream.opaque = NULL;
-
- ret = inflateInit2(&stream, -MAX_WBITS);
- if (ret != Z_OK) {
- ERRMSG("error while reading kernel config, inflateInit2 "
- "returned %d\n", ret);
- goto out1;
- }
-
- ret = inflate(&stream, Z_FINISH);
-
- if (ret != Z_STREAM_END) {
- inflateEnd(&stream);
- if (ret == Z_NEED_DICT ||
- (ret == Z_BUF_ERROR && stream.avail_in == 0)) {
- ERRMSG("error while reading kernel config, stream.avail_in = 0,"
- "inflate returned %d\n", ret);
- goto out1;
- }
- ERRMSG("error while reading kernel config, inflate returned"
- "with %d\n", ret);
- goto out1;
- }
- size = stream.total_out;
-
- ret = inflateEnd(&stream);
-
- pos = uncomp;
-
- do {
- ret = sscanf(pos, "%511[^\n]\n%n", line, &ii);
- if (ret > 0) {
- pos += ii;
-
- ln = line;
-
- /* skip leading whitespace */
- while (is_blank(*ln))
- ln++;
-
- /* skip comments */
- if (*ln == '#')
- continue;
-
- /* Find '=' */
- if ((head = strchr(ln, '=')) != NULL) {
- *head = '\0';
- val = head + 1;
-
- head--;
-
- /* skip trailing whitespace */
- while (is_blank(*head)) {
- *head = '\0';
- head--;
- }
-
- /* skip whitespace */
- while (is_blank(*val))
- val++;
-
- } else /* Bad line, skip it */
- continue;
-
- if (strcmp(ln, "CONFIG_PGTABLE_4") == 0)
- info->mem_flags |= MEMORY_4LAYER_PAGETABLE;
- }
- } while (ret > 0);
-
-
- free(uncomp);
- free(buf);
- return TRUE;
-
-out1:
- free(uncomp);
-out2:
- free(buf);
-
- return FALSE;
-}
-
int
get_structure_info(struct DumpInfo *info)
{
@@ -1653,6 +1558,14 @@ get_structure_info(struct DumpInfo *info
}
int
+get_srcfile_info(struct DumpInfo *info)
+{
+ TYPEDEF_SRCFILE_INIT(pud_t, "pud_t");
+
+ return TRUE;
+}
+
+int
is_sparsemem_extreme(struct DumpInfo *info)
{
if (ARRAY_LENGTH(mem_section)
@@ -1722,6 +1635,9 @@ generate_config(struct DumpInfo *info)
if (!get_structure_info(info))
return FALSE;
+ if (!get_srcfile_info(info))
+ return FALSE;
+
if ((SYMBOL(system_utsname) == NOT_FOUND_SYMBOL)
&& (SYMBOL(init_uts_ns) == NOT_FOUND_SYMBOL)) {
ERRMSG("Can't get the symbol of system_utsname.\n");
@@ -1807,6 +1723,11 @@ generate_config(struct DumpInfo *info)
WRITE_ARRAY_LENGTH("zone.free_area", zone.free_area);
+ /*
+ * write the source file of 1st kernel
+ */
+ WRITE_SRCFILE("pud_t", pud_t);
+
return TRUE;
}
@@ -1920,6 +1841,30 @@ read_config_structure(struct DumpInfo *i
}
int
+read_config_string(struct DumpInfo *info, char *str_in, char *str_out)
+{
+ char buf[BUFSIZE_FGETS];
+ unsigned int i;
+
+ if (fseek(info->file_configfile, 0, SEEK_SET) < 0) {
+ ERRMSG("Can't seek the config file(%s). %s\n",
+ info->name_configfile, strerror(errno));
+ return FALSE;
+ }
+
+ while (fgets(buf, BUFSIZE_FGETS, info->file_configfile)) {
+ i = strlen(buf);
+ if (buf[i - 1] == '\n')
+ buf[i - 1] = '\0';
+ if (strncmp(buf, str_in, strlen(str_in)) == 0) {
+ strncpy(str_out, buf + strlen(str_in), BUFSIZE_FGETS - strlen(str_in));
+ break;
+ }
+ }
+ return TRUE;
+}
+
+int
read_config(struct DumpInfo *info)
{
if (!read_config_basic_info(info))
@@ -1974,6 +1919,8 @@ read_config(struct DumpInfo *info)
READ_ARRAY_LENGTH("mem_section", mem_section);
READ_ARRAY_LENGTH("zone.free_area", zone.free_area);
+ READ_SRCFILE("pud_t", pud_t);
+
return TRUE;
}
@@ -2455,6 +2402,9 @@ initial(struct DumpInfo *info)
}
if (!get_structure_info(info))
return FALSE;
+
+ if (!get_srcfile_info(info))
+ return FALSE;
}
if (!get_machdep_kernel_start(info))
@@ -2463,9 +2413,6 @@ initial(struct DumpInfo *info)
if (!check_release(info))
return FALSE;
- if (!read_kernel_config(info))
- return FALSE;
-
if (!get_machdep_info(info))
return FALSE;
diff -puN makedumpfile.org/makedumpfile.h makedumpfile/makedumpfile.h
--- makedumpfile.org/makedumpfile.h 2007-05-21 19:20:06.000000000 +0900
+++ makedumpfile/makedumpfile.h 2007-05-21 19:36:43.000000000 +0900
@@ -69,14 +69,7 @@ enum {
* Flags
*/
#define MEMORY_4LAYER_PAGETABLE (1 << 0)
-
-/*
- * For kernel configuration
- */
-#define MAGIC_START "IKCFG_ST"
-#define MAGIC_END "IKCFG_ED"
-#define MAGIC_SIZE (sizeof(MAGIC_START) - 1)
-
+#define MEMORY_3LAYER_PAGETABLE (1 << 1)
static inline int
test_bit(int nr, unsigned long addr)
@@ -87,12 +80,6 @@ test_bit(int nr, unsigned long addr)
return ((mask & addr) != 0);
}
-static inline int
-is_blank(int c)
-{
- return c == ' ' || c == '\t';
-}
-
#define isLRU(flags) test_bit(PG_lru, flags)
#define isPrivate(flags) test_bit(PG_private, flags)
#define isSwapCache(flags) test_bit(PG_swapcache, flags)
@@ -288,6 +275,29 @@ do { \
} while (0)
/*
+ * for source file name
+ */
+#define SRCFILE(X) (srcfile_table.X)
+#define TYPEDEF_SRCFILE_INIT(decl_name, str_decl_name) \
+do { \
+ get_source_filename(str_decl_name, SRCFILE(decl_name), DWARF_INFO_GET_TYPEDEF_SRCNAME); \
+} while (0)
+
+#define WRITE_SRCFILE(str_decl_name, decl_name) \
+do { \
+ if (strlen(SRCFILE(decl_name))) { \
+ fprintf(info->file_configfile, "%s%s\n", \
+ STR_SRCFILE(str_decl_name), SRCFILE(decl_name)); \
+ } \
+} while (0)
+
+#define READ_SRCFILE(str_decl_name, decl_name) \
+do { \
+ if (!read_config_string(info, STR_SRCFILE(str_decl_name), SRCFILE(decl_name))) \
+ return FALSE; \
+} while (0)
+
+/*
* kernel version
*/
#define VERSION_2_6_15 (15)
@@ -309,6 +319,7 @@ do { \
#define STR_SIZE(X) "SIZE("X")="
#define STR_OFFSET(X) "OFFSET("X")="
#define STR_LENGTH(X) "LENGTH("X")="
+#define STR_SRCFILE(X) "SRCFILE("X")="
/*
* common value
@@ -412,6 +423,12 @@ do { \
#define MASK_PUD ((1UL << REGION_SHIFT) - 1) & (~((1UL << PUD_SHIFT) - 1))
#define MASK_PGD_4L ((1UL << REGION_SHIFT) - 1) & (~((1UL << PGDIR_SHIFT_4L) - 1))
+/*
+ * Key for distinguishing PGTABLE_3L or PGTABLE_4L.
+ */
+#define STR_PUD_T_3L "include/asm-generic/pgtable-nopud.h"
+#define STR_PUD_T_4L "include/asm/page.h"
+
#endif /* ia64 */
/*
@@ -679,10 +696,19 @@ struct array_table {
} zone;
};
+#define LEN_SRCFILE (50)
+struct srcfile_table {
+ /*
+ * typedef
+ */
+ char pud_t[LEN_SRCFILE];
+};
+
extern struct symbol_table symbol_table;
extern struct size_table size_table;
extern struct offset_table offset_table;
extern struct array_table array_table;
+extern struct srcfile_table srcfile_table;
/*
* Debugging information
@@ -693,6 +719,7 @@ extern struct array_table array_table;
#define DWARF_INFO_GET_MEMBER_ARRAY_LENGTH (4)
#define DWARF_INFO_GET_SYMBOL_ARRAY_LENGTH (5)
#define DWARF_INFO_CHECK_SYMBOL_ARRAY_TYPE (6)
+#define DWARF_INFO_GET_TYPEDEF_SRCNAME (7)
struct dwarf_info {
unsigned int cmd; /* IN */
@@ -701,14 +728,17 @@ struct dwarf_info {
char *struct_name; /* IN */
char *symbol_name; /* IN */
char *member_name; /* IN */
+ char *decl_name; /* IN */
long struct_size; /* OUT */
long member_offset; /* OUT */
long array_length; /* OUT */
+ char src_name[LEN_SRCFILE]; /* OUT */
};
extern struct dwarf_info dwarf_info;
int readmem();
+off_t paddr_to_offset();
unsigned long long vaddr_to_paddr();
unsigned long long paddr_to_vaddr();
_
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] [makedumpfile] Implement memory regions on IA64
2007-05-21 9:32 ` Ken'ichi Ohmichi
@ 2007-05-21 9:54 ` Bernhard Walle
0 siblings, 0 replies; 10+ messages in thread
From: Bernhard Walle @ 2007-05-21 9:54 UTC (permalink / raw)
To: Ken'ichi Ohmichi; +Cc: Jay Lan, Kexec Mailing List
* Ken'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp> [2007-05-21 11:32]:
> 2007/05/16 20:20:00 +0900, "Ken'ichi Ohmichi" <oomichi@mxs.nes.nec.co.jp> wrote:
> >I propose that makedumpfile distinguishes the page table (3L or 4L)
> >by checking the defined file name of pud_t.
> >I'm trying for the above implementation.
> >I will send you the patch when it is complete.
>
> The attached patch is for the above implementation.
> It works fine with linux-2.6.18.
> Could you test it with your environment ?
works, thanks.
Bernhard
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2007-05-21 9:54 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-04-26 19:37 [PATCH] [makedumpfile] Implement memory regions on IA64 Bernhard Walle
2007-05-11 6:59 ` Ken'ichi Ohmichi
2007-05-14 18:15 ` Bernhard Walle
2007-05-14 21:49 ` Bernhard Walle
2007-05-15 22:08 ` Bernhard Walle
2007-05-16 11:20 ` Ken'ichi Ohmichi
2007-05-16 11:26 ` Bernhard Walle
2007-05-21 9:32 ` Ken'ichi Ohmichi
2007-05-21 9:54 ` Bernhard Walle
-- strict thread matches above, loose matches on Subject: below --
2007-04-27 10:31 tachibana
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox