* [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-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
* 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 threadend 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