blob: fe535b60705cf33d02eb49abfe85f64e7eeb270b [file] [log] [blame]
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001From 769da25627cebb2a53caee5d5be78a32d376adc1 Mon Sep 17 00:00:00 2001
2From: AKASHI Takahiro <takahiro.akashi@linaro.org>
3Date: Wed, 5 Aug 2015 13:45:15 +0900
4Subject: [PATCH 5/9] arm64: kdump: add elf core header segment
5
6Elf core header contains the information necessary for the coredump of
7the 1st kernel, including its physcal memory layout as well as cpu register
8states at the panic.
9The segment is allocated inside the reserved memory of crash dump kernel.
10
11Upstream-Status: Backport [https://git.linaro.org/people/takahiro.akashi/kexec-tools.git]
12
13Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
14Signed-off-by: He Zhe <zhe.he@windriver.com>
15---
16 kexec/arch/arm64/crashdump-arm64.c | 96 ++++++++++++++++++++++++++++++++++++++
17 kexec/arch/arm64/crashdump-arm64.h | 3 ++
18 kexec/arch/arm64/iomem.h | 2 +
19 kexec/arch/arm64/kexec-elf-arm64.c | 10 ++++
20 4 files changed, 111 insertions(+)
21
22diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c
23index dcaca43..8346131 100644
24--- a/kexec/arch/arm64/crashdump-arm64.c
25+++ b/kexec/arch/arm64/crashdump-arm64.c
26@@ -39,6 +39,39 @@ struct memory_ranges usablemem_rgns = {
27 .ranges = &crash_reserved_mem,
28 };
29
30+struct memory_range elfcorehdr_mem;
31+
32+static struct crash_elf_info elf_info = {
33+ .class = ELFCLASS64,
34+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
35+ .data = ELFDATA2LSB,
36+#else
37+ .data = ELFDATA2MSB,
38+#endif
39+ .machine = EM_AARCH64,
40+};
41+
42+/*
43+ * Note: The returned value is correct only if !CONFIG_RANDOMIZE_BASE.
44+ */
45+static uint64_t get_kernel_page_offset(void)
46+{
47+ int i;
48+
49+ if (elf_info.kern_vaddr_start == UINT64_MAX)
50+ return UINT64_MAX;
51+
52+ /* Current max virtual memory range is 48-bits. */
53+ for (i = 48; i > 0; i--)
54+ if (!(elf_info.kern_vaddr_start & (1UL << i)))
55+ break;
56+
57+ if (i <= 0)
58+ return UINT64_MAX;
59+ else
60+ return UINT64_MAX << i;
61+}
62+
63 /*
64 * iomem_range_callback() - callback called for each iomem region
65 * @data: not used
66@@ -62,6 +95,10 @@ static int iomem_range_callback(void *UNUSED(data), int UNUSED(nr),
67 else if (strncmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM)) == 0)
68 return mem_regions_add(&crash_memory_rgns,
69 base, length, RANGE_RAM);
70+ else if (strncmp(str, KERNEL_CODE, strlen(KERNEL_CODE)) == 0)
71+ elf_info.kern_paddr_start = base;
72+ else if (strncmp(str, KERNEL_DATA, strlen(KERNEL_DATA)) == 0)
73+ elf_info.kern_size = base + length - elf_info.kern_paddr_start;
74
75 return 0;
76 }
77@@ -115,5 +152,64 @@ static int crash_get_memory_ranges(void)
78 dbgprint_mem_range("Coredump memory ranges",
79 crash_memory_rgns.ranges, crash_memory_rgns.size);
80
81+ /*
82+ * For additional kernel code/data segment.
83+ * kern_paddr_start/kern_size are determined in iomem_range_callback
84+ */
85+ elf_info.kern_vaddr_start = get_kernel_sym("_text");
86+ if (!elf_info.kern_vaddr_start)
87+ elf_info.kern_vaddr_start = UINT64_MAX;
88+
89+ return 0;
90+}
91+
92+/*
93+ * load_crashdump_segments() - load the elf core header
94+ * @info: kexec info structure
95+ *
96+ * This function creates and loads an additional segment of elf core header
97+ : which is used to construct /proc/vmcore on crash dump kernel.
98+ *
99+ * Return 0 in case of success and -1 in case of error.
100+ */
101+
102+int load_crashdump_segments(struct kexec_info *info)
103+{
104+ unsigned long elfcorehdr;
105+ unsigned long bufsz;
106+ void *buf;
107+ int err;
108+
109+ /*
110+ * First fetch all the memory (RAM) ranges that we are going to
111+ * pass to the crash dump kernel during panic.
112+ */
113+
114+ err = crash_get_memory_ranges();
115+
116+ if (err)
117+ return err;
118+
119+ elf_info.page_offset = get_kernel_page_offset();
120+ dbgprintf("%s: page_offset: %016llx\n", __func__,
121+ elf_info.page_offset);
122+
123+ err = crash_create_elf64_headers(info, &elf_info,
124+ crash_memory_rgns.ranges, crash_memory_rgns.size,
125+ &buf, &bufsz, ELF_CORE_HEADER_ALIGN);
126+
127+ if (err)
128+ return err;
129+
130+ elfcorehdr = add_buffer_phys_virt(info, buf, bufsz, bufsz, 0,
131+ crash_reserved_mem.start, crash_reserved_mem.end,
132+ -1, 0);
133+
134+ elfcorehdr_mem.start = elfcorehdr;
135+ elfcorehdr_mem.end = elfcorehdr + bufsz - 1;
136+
137+ dbgprintf("%s: elfcorehdr 0x%llx-0x%llx\n", __func__,
138+ elfcorehdr_mem.start, elfcorehdr_mem.end);
139+
140 return 0;
141 }
142diff --git a/kexec/arch/arm64/crashdump-arm64.h b/kexec/arch/arm64/crashdump-arm64.h
143index 07a0ed0..da75a2d 100644
144--- a/kexec/arch/arm64/crashdump-arm64.h
145+++ b/kexec/arch/arm64/crashdump-arm64.h
146@@ -18,5 +18,8 @@
147
148 extern struct memory_ranges usablemem_rgns;
149 extern struct memory_range crash_reserved_mem;
150+extern struct memory_range elfcorehdr_mem;
151+
152+extern int load_crashdump_segments(struct kexec_info *info);
153
154 #endif /* CRASHDUMP_ARM64_H */
155diff --git a/kexec/arch/arm64/iomem.h b/kexec/arch/arm64/iomem.h
156index 20cda87..d4864bb 100644
157--- a/kexec/arch/arm64/iomem.h
158+++ b/kexec/arch/arm64/iomem.h
159@@ -2,6 +2,8 @@
160 #define IOMEM_H
161
162 #define SYSTEM_RAM "System RAM\n"
163+#define KERNEL_CODE "Kernel code\n"
164+#define KERNEL_DATA "Kernel data\n"
165 #define CRASH_KERNEL "Crash kernel\n"
166 #define IOMEM_RESERVED "reserved\n"
167
168diff --git a/kexec/arch/arm64/kexec-elf-arm64.c b/kexec/arch/arm64/kexec-elf-arm64.c
169index daf8bf0..c70a37a 100644
170--- a/kexec/arch/arm64/kexec-elf-arm64.c
171+++ b/kexec/arch/arm64/kexec-elf-arm64.c
172@@ -119,6 +119,16 @@ int elf_arm64_load(int argc, char **argv, const char *kernel_buf,
173 dbgprintf("%s: PE format: %s\n", __func__,
174 (arm64_header_check_pe_sig(header) ? "yes" : "no"));
175
176+ if (info->kexec_flags & KEXEC_ON_CRASH) {
177+ /* create and initialize elf core header segment */
178+ result = load_crashdump_segments(info);
179+ if (result) {
180+ dbgprintf("%s: Creating eflcorehdr failed.\n",
181+ __func__);
182+ goto exit;
183+ }
184+ }
185+
186 /* load the kernel */
187 result = elf_exec_load(&ehdr, info);
188
189--
1901.9.1
191