[PATCH 1/2] kexec-tools: detect page_offset dynamically

Wang Nan wangnan0 at huawei.com
Thu May 29 02:20:02 PDT 2014


ARM kernel can be compiled with CONFIG_VMSPLIT_1G, CONFIG_VMSPLIT_2G or
CONFIG_VMSPLIT_3G. This patch dynamically detects PAGE_OFFSET according
to _stext symbol from /proc/kallsyms.

Signed-off-by: Wang Nan <wangnan0 at huawei.com>
---
 kexec/arch/arm/crashdump-arm.c | 49 +++++++++++++++++++++++++++++++++++++++++-
 kexec/arch/arm/crashdump-arm.h |  4 +++-
 2 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/kexec/arch/arm/crashdump-arm.c b/kexec/arch/arm/crashdump-arm.c
index 0cd6935..e6ff3e0 100644
--- a/kexec/arch/arm/crashdump-arm.c
+++ b/kexec/arch/arm/crashdump-arm.c
@@ -56,11 +56,55 @@ static struct crash_elf_info elf_info = {
 	.class		= ELFCLASS32,
 	.data		= ELFDATANATIVE,
 	.machine	= EM_ARM,
-	.page_offset	= PAGE_OFFSET,
+	.page_offset	= DEFAULT_PAGE_OFFSET,
 };
 
 unsigned long phys_offset;
 
+/* Retrieve kernel _stext symbol virtual address from /proc/kallsyms */
+static unsigned long long get_kernel_stext_sym(void)
+{
+	const char *kallsyms = "/proc/kallsyms";
+	const char *stext = "_stext";
+	char sym[128];
+	char line[128];
+	FILE *fp;
+	unsigned long long vaddr;
+	char type;
+
+	fp = fopen(kallsyms, "r");	if (!fp) {
+		fprintf(stderr, "Cannot open %s\n", kallsyms);
+		return 0;
+	}
+
+	while(fgets(line, sizeof(line), fp) != NULL) {
+		if (sscanf(line, "%Lx %c %s", &vaddr, &type, sym) != 3)
+			continue;
+		if (strcmp(sym, stext) == 0) {
+			dbgprintf("kernel symbol %s vaddr = %16llx\n", stext, vaddr);
+			return vaddr;
+		}
+	}
+
+	fprintf(stderr, "Cannot get kernel %s symbol address\n", stext);
+	return 0;
+}
+
+static int get_kernel_page_offset(struct kexec_info *info,
+		struct crash_elf_info *elf_info)
+{
+	unsigned long long stext_sym_addr = get_kernel_stext_sym();
+	if (stext_sym_addr == 0) {
+		elf_info->page_offset = (unsigned long long)DEFAULT_PAGE_OFFSET;
+		dbgprintf("Unable to get _stext symbol from /proc/kallsyms, use default: %llx\n",
+				elf_info->page_offset);
+		return 0;
+	}
+	elf_info->page_offset = stext_sym_addr & (~KVBASE_MASK);
+	dbgprintf("page_offset is set to %llx\n", elf_info->page_offset);
+	return 0;
+}
+
 /**
  * crash_range_callback() - callback called for each iomem region
  * @data: not used
@@ -292,6 +336,9 @@ int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline)
 	phys_offset = usablemem_rgns.ranges->start;
 	dbgprintf("phys_offset: %#lx\n", phys_offset);
 
+	if (get_kernel_page_offset(info, &elf_info))
+		return -1;
+
 	err = crash_create_elf32_headers(info, &elf_info,
 					 usablemem_rgns.ranges,
 					 usablemem_rgns.size, &buf, &bufsz,
diff --git a/kexec/arch/arm/crashdump-arm.h b/kexec/arch/arm/crashdump-arm.h
index a342922..2dbde04 100644
--- a/kexec/arch/arm/crashdump-arm.h
+++ b/kexec/arch/arm/crashdump-arm.h
@@ -6,9 +6,11 @@ extern "C" {
 #endif
 
 #define COMMAND_LINE_SIZE	1024
-#define PAGE_OFFSET		0xc0000000
+#define DEFAULT_PAGE_OFFSET		(0xc0000000)
+#define KVBASE_MASK	(0x1ffffff)
 #define CRASH_MAX_MEMORY_RANGES	32
 
+
 extern struct memory_ranges usablemem_rgns;
 
 struct kexec_info;
-- 
1.8.4




More information about the kexec mailing list