blob: 1420affa28e7b62f554e3f6ff4aa59f612052e9f [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2018 MediaTek Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24#include <kernel/vm.h>
25#include <malloc.h>
26#include <printf.h>
27#include <stdlib.h>
28#include <string.h>
29#include "kdump.h"
30#include "mrdump_elf64.h"
31
32struct memelfnote {
33 const char *name;
34 int type;
35 unsigned int datasz;
36 void *data;
37};
38
39static int notesize(struct memelfnote *en)
40{
41 int sz;
42
43 sz = sizeof(struct elf64_note);
44 sz += ROUNDUP((strlen(en->name) + 1), 4);
45 sz += ROUNDUP(en->datasz, 4);
46
47 return sz;
48}
49
50static uint8_t *storenote(struct memelfnote *men, uint8_t *bufp)
51{
52 struct elf64_note en;
53 en.n_namesz = strlen(men->name) + 1;
54 en.n_descsz = men->datasz;
55 en.n_type = men->type;
56
57 memcpy(bufp, &en, sizeof(en));
58 bufp += sizeof(en);
59
60 memcpy(bufp, men->name, en.n_namesz);
61 bufp += en.n_namesz;
62 bufp = (uint8_t *) ROUNDUP((uint64_t)bufp, 4);
63 memcpy(bufp, men->data, men->datasz);
64 bufp += men->datasz;
65
66 bufp = (uint8_t *) ROUNDUP((uint64_t)bufp, 4);
67 return bufp;
68}
69
70static uint8_t *kdump_core_write_cpu_note(const struct mrdump_control_block *mrdump_cb, int cpu, struct elf64_phdr *nhdr, uint8_t *bufp)
71{
72 struct memelfnote notes;
73 struct elf_arm64_prstatus64 prstatus;
74 char cpustr[16];
75
76 memset(&prstatus, 0, sizeof(struct elf_arm64_prstatus64));
77
78 snprintf(cpustr, sizeof(cpustr), "CPU%d", cpu);
79 /* set up the process status */
80 notes.name = cpustr;
81 notes.type = NT_PRSTATUS;
82 notes.datasz = sizeof(struct elf_arm64_prstatus64);
83 notes.data = &prstatus;
84
85 prstatus.pr_pid = cpu + 1;
86 memcpy(&prstatus.pr_reg, &mrdump_cb->crash_record.cpu_regs[cpu].arm64_regs, sizeof(elf_arm64_gregset_t));
87
88 nhdr->p_filesz += notesize(&notes);
89 return storenote(&notes, bufp);
90}
91
92static uint8_t *kdump_core_write_machdesc(const struct mrdump_control_block *mrdump_cb, struct elf64_phdr *nhdr, uint8_t *bufp)
93{
94 struct memelfnote notes;
95 struct elf_mrdump_machdesc machdesc;
96 const struct mrdump_machdesc *kparams = &mrdump_cb->machdesc;
97
98 memset(&machdesc, 0, sizeof(struct elf_mrdump_machdesc));
99
100 notes.name = "MRDUMP01";
101 notes.type = NT_MRDUMP_MACHDESC;
102 notes.datasz = sizeof(struct elf_mrdump_machdesc);
103 notes.data = &machdesc;
104
105 machdesc.flags = MRDUMP_TYPE_FULL_MEMORY;
106 machdesc.nr_cpus = kparams->nr_cpus;
107 machdesc.phys_offset = kparams->phys_offset;
108 machdesc.page_offset = kparams->page_offset;
109 machdesc.high_memory = kparams->high_memory;
110 machdesc.kimage_vaddr = kparams->kimage_vaddr;
111 machdesc.modules_start = kparams->modules_start;
112 machdesc.modules_end = kparams->modules_end;
113 machdesc.vmalloc_start = kparams->vmalloc_start;
114 machdesc.vmalloc_end = kparams->vmalloc_end;
115 machdesc.master_page_table = kparams->master_page_table;
116
117 nhdr->p_filesz += notesize(&notes);
118 return storenote(&notes, bufp);
119}
120
121static uint8_t *mrdump_elf64_write_vmcoreinfo(const struct mrdump_control_block *mrdump_cb, struct elf64_phdr *nhdr, uint8_t *bufp)
122{
123 struct memelfnote notes;
124 const struct mrdump_machdesc *kparams = &mrdump_cb->machdesc;
125 char vmcoreinfo[512];
126
127 memset(vmcoreinfo, 0, sizeof(vmcoreinfo));
128
129 notes.name = "VMCOREINFO";
130 notes.type = 0;
131 notes.datasz = 0;
132 notes.data = &vmcoreinfo;
133 snprintf(vmcoreinfo, sizeof(vmcoreinfo),
134 "PAGESIZE=4096\n"
135 "NUMBER(kimage_voffset)=0x%llx\n"
136 "SYMBOL(_stext)=0x%llx\n"
137 "NUMBER(VA_BITS)=%d\n"
138 "NUMBER(PHYS_OFFSET)=0x%llx\n",
139 (uint64_t)kparams->kimage_voffset,
140 (uint64_t)kparams->kimage_stext_real,
141 39,
142 (uint64_t)kparams->phys_offset);
143 notes.datasz = strlen(vmcoreinfo);
144
145 nhdr->p_filesz += notesize(&notes);
146 return storenote(&notes, bufp);
147}
148
149static uint8_t *kdump_core_write_mrdump_cb(const struct mrdump_control_block *mrdump_cb, struct elf64_phdr *nhdr, uint8_t *bufp)
150{
151 struct memelfnote notes;
152 uint64_t mrdump_cb_paddr = (uint64_t)(uintptr_t)kvaddr_to_paddr((void *)mrdump_cb);
153
154 notes.name = MRDUMP_GO_DUMP;
155 notes.type = NT_MRDUMP_CBLOCK;
156 notes.datasz = sizeof(mrdump_cb_paddr);
157 notes.data = &mrdump_cb_paddr;
158
159 nhdr->p_filesz += notesize(&notes);
160 return storenote(&notes, bufp);
161}
162
163void kdump_core64_header_init(const struct mrdump_control_block *mrdump_cb, const struct kzip_addlist *memlist)
164{
165 struct elf64_phdr *nhdr, *phdr;
166 struct elf64_hdr *elf;
167 off_t offset = 0;
168 const struct mrdump_machdesc *kparams = &mrdump_cb->machdesc;
169
170 uint8_t *bufp = (uint8_t *)(uintptr_t)memlist[0].address;
171
172 elf = (struct elf64_hdr *) bufp;
173 bufp += sizeof(struct elf64_hdr);
174 offset += sizeof(struct elf64_hdr);
175
176 nhdr = (struct elf64_phdr *) bufp;
177 bufp += sizeof(struct elf64_phdr);
178 offset += sizeof(struct elf64_phdr);
179 memset(nhdr, 0, sizeof(struct elf64_phdr));
180 nhdr->p_type = PT_NOTE;
181
182 unsigned long long foffset = KDUMP_CORE_HEADER_SIZE;
183 int i;
184 for (i = 1; memlist[i].address != 0; i++) {
185 phdr = (struct elf64_phdr *) bufp;
186 bufp += sizeof(struct elf64_phdr);
187 offset += sizeof(struct elf64_phdr);
188
189 phdr->p_type = PT_LOAD;
190 phdr->p_flags = PF_R|PF_W|PF_X;
191 phdr->p_offset = foffset;
192 phdr->p_vaddr = 0;
193 phdr->p_paddr = (uint64_t)kvaddr_to_paddr((void *)memlist[i].address);
194 phdr->p_filesz = memlist[i].size;
195 phdr->p_memsz = memlist[i].size;
196 phdr->p_align = 0;
197
198 foffset += phdr->p_filesz;
199 }
200
201 mrdump_elf_setup_eident(elf->e_ident, ELFCLASS64);
202 mrdump_elf_setup_elfhdr(elf, EM_AARCH64, struct elf64_hdr, struct elf64_phdr, i);
203 dprintf(CRITICAL, "%s after\n", __func__);
204
205 nhdr->p_offset = offset;
206
207 /* NT_PRPSINFO */
208 struct elf_prpsinfo64 prpsinfo;
209 struct memelfnote notes;
210 /* set up the process info */
211 notes.name = CORE_STR;
212 notes.type = NT_PRPSINFO;
213 notes.datasz = sizeof(struct elf_prpsinfo64);
214 notes.data = &prpsinfo;
215
216 memset(&prpsinfo, 0, sizeof(struct elf_prpsinfo64));
217 prpsinfo.pr_state = 0;
218 prpsinfo.pr_sname = 'R';
219 prpsinfo.pr_zomb = 0;
220 prpsinfo.pr_gid = prpsinfo.pr_uid = mrdump_cb->crash_record.fault_cpu + 1;
221 strlcpy(prpsinfo.pr_fname, "vmlinux", sizeof(prpsinfo.pr_fname));
222 strlcpy(prpsinfo.pr_psargs, "vmlinux", ELF_PRARGSZ);
223
224 nhdr->p_filesz += notesize(&notes);
225 bufp = storenote(&notes, bufp);
226
227 bufp = kdump_core_write_machdesc(mrdump_cb, nhdr, bufp);
228 bufp = mrdump_elf64_write_vmcoreinfo(mrdump_cb, nhdr, bufp);
229
230 /* Store pre-cpu backtrace */
231 bufp = kdump_core_write_cpu_note(mrdump_cb, mrdump_cb->crash_record.fault_cpu, nhdr, bufp);
232 for (unsigned int cpu = 0; cpu < kparams->nr_cpus; cpu++) {
233 if (cpu != mrdump_cb->crash_record.fault_cpu) {
234 bufp = kdump_core_write_cpu_note(mrdump_cb, cpu, nhdr, bufp);
235 }
236 }
237 dprintf(CRITICAL, "%s %d\n", __func__, __LINE__);
238
239 /* store mrdump control block */
240 bufp = kdump_core_write_mrdump_cb(mrdump_cb, nhdr, bufp);
241}