blob: c24a813a97cd1157c4e74e101ba8f6695d05a4b3 [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_elf.h"
31
32/* An ELF note in memory */
33struct memelfnote {
34 const char *name;
35 int type;
36 unsigned int datasz;
37 void *data;
38};
39
40static int notesize(struct memelfnote *en)
41{
42 int sz;
43
44 sz = sizeof(struct elf_note);
45 sz += ROUNDUP((strlen(en->name) + 1), 4);
46 sz += ROUNDUP(en->datasz, 4);
47
48 return sz;
49}
50
51static uint8_t *storenote(struct memelfnote *men, uint8_t *bufp)
52{
53 struct elf_note en;
54 en.n_namesz = strlen(men->name) + 1;
55 en.n_descsz = men->datasz;
56 en.n_type = men->type;
57
58 memcpy(bufp, &en, sizeof(en));
59 bufp += sizeof(en);
60
61 memcpy(bufp, men->name, en.n_namesz);
62 bufp += en.n_namesz;
63
64 bufp = (uint8_t *) ROUNDUP((unsigned long)bufp, 4);
65 memcpy(bufp, men->data, men->datasz);
66 bufp += men->datasz;
67
68 bufp = (uint8_t *) ROUNDUP((unsigned long)bufp, 4);
69 return bufp;
70}
71
72static uint8_t *kdump_core_write_cpu_note(const struct mrdump_control_block *mrdump_cb, int cpu, struct elf32_phdr *nhdr, uint8_t *bufp)
73{
74 struct memelfnote notes;
75 struct elf32_arm_prstatus prstatus;
76 char cpustr[16];
77
78 memset(&prstatus, 0, sizeof(struct elf32_arm_prstatus));
79
80 snprintf(cpustr, sizeof(cpustr), "CPU%d", cpu);
81 /* set up the process status */
82 notes.name = cpustr;
83 notes.type = NT_PRSTATUS;
84 notes.datasz = sizeof(struct elf32_arm_prstatus);
85 notes.data = &prstatus;
86
87 prstatus.pr_pid = cpu + 1;
88 memcpy(&prstatus.pr_reg, (unsigned long *)&mrdump_cb->crash_record.cpu_regs[cpu].arm32_regs, sizeof(elf_arm_gregset_t));
89
90 nhdr->p_filesz += notesize(&notes);
91 return storenote(&notes, bufp);
92}
93
94static uint8_t *kdump_core_write_machdesc(const struct mrdump_control_block *mrdump_cb, struct elf32_phdr *nhdr, uint8_t *bufp)
95{
96 struct memelfnote notes;
97 struct elf_mrdump_machdesc machdesc;
98 const struct mrdump_machdesc *kparams = &mrdump_cb->machdesc;
99
100 memset(&machdesc, 0, sizeof(struct elf_mrdump_machdesc));
101
102 notes.name = "MRDUMP01";
103 notes.type = NT_MRDUMP_MACHDESC;
104 notes.datasz = sizeof(struct elf_mrdump_machdesc);
105 notes.data = &machdesc;
106
107 machdesc.flags = MRDUMP_TYPE_FULL_MEMORY;
108 machdesc.nr_cpus = kparams->nr_cpus;
109 machdesc.phys_offset = kparams->phys_offset;
110 machdesc.page_offset = kparams->page_offset;
111 machdesc.high_memory = kparams->high_memory;
112 machdesc.kimage_vaddr = kparams->kimage_vaddr;
113 machdesc.modules_start = kparams->modules_start;
114 machdesc.modules_end = kparams->modules_end;
115 machdesc.vmalloc_start = kparams->vmalloc_start;
116 machdesc.vmalloc_end = kparams->vmalloc_end;
117 machdesc.master_page_table = kparams->master_page_table;
118
119 nhdr->p_filesz += notesize(&notes);
120 return storenote(&notes, bufp);
121}
122
123static uint8_t *kdump_core_write_mrdump_cb(const struct mrdump_control_block *mrdump_cb, struct elf32_phdr *nhdr, uint8_t *bufp)
124{
125 struct memelfnote notes;
126 uint64_t mrdump_cb_paddr = (uint64_t)(uintptr_t)kvaddr_to_paddr((void *)mrdump_cb);
127
128 notes.name = MRDUMP_GO_DUMP;
129 notes.type = NT_MRDUMP_CBLOCK;
130 notes.datasz = sizeof(mrdump_cb_paddr);
131 notes.data = &mrdump_cb_paddr;
132
133 nhdr->p_filesz += notesize(&notes);
134 return storenote(&notes, bufp);
135}
136
137void kdump_core32_header_init(const struct mrdump_control_block *mrdump_cb, const struct kzip_addlist *memlist)
138{
139 struct elf32_phdr *nhdr, *phdr;
140 struct elf32_hdr *elf;
141 off_t offset = 0;
142 const struct mrdump_machdesc *kparams = &mrdump_cb->machdesc;
143
144 uint8_t *bufp = (uint8_t *)(uintptr_t)memlist[0].address;
145
146 elf = (struct elf32_hdr *) bufp;
147 bufp += sizeof(struct elf32_hdr);
148 offset += sizeof(struct elf32_hdr);
149
150 nhdr = (struct elf32_phdr *) bufp;
151 bufp += sizeof(struct elf32_phdr);
152 offset += sizeof(struct elf32_phdr);
153 memset(nhdr, 0, sizeof(struct elf32_phdr));
154 nhdr->p_type = PT_NOTE;
155
156 unsigned long long foffset = KDUMP_CORE_HEADER_SIZE;
157 int i;
158 for (i = 1; memlist[i].address != 0; i++) {
159 phdr = (struct elf32_phdr *) bufp;
160 bufp += sizeof(struct elf32_phdr);
161 offset += sizeof(struct elf32_phdr);
162
163 phdr->p_type = PT_LOAD;
164 phdr->p_flags = PF_R|PF_W|PF_X;
165 phdr->p_offset = foffset;
166 phdr->p_vaddr = 0;
167 phdr->p_paddr = (Elf32_Addr)kvaddr_to_paddr((void *)memlist[i].address);
168 phdr->p_filesz = memlist[i].size;
169 phdr->p_memsz = memlist[i].size;
170 phdr->p_align = 0;
171
172 foffset += phdr->p_filesz;
173 }
174
175 mrdump_elf_setup_eident(elf->e_ident, ELFCLASS32);
176 mrdump_elf_setup_elfhdr(elf, EM_ARM, struct elf32_hdr, struct elf32_phdr, i);
177
178 nhdr->p_offset = offset;
179
180 /* NT_PRPSINFO */
181 struct elf32_prpsinfo prpsinfo;
182 struct memelfnote notes;
183 /* set up the process info */
184 notes.name = CORE_STR;
185 notes.type = NT_PRPSINFO;
186 notes.datasz = sizeof(struct elf32_prpsinfo);
187 notes.data = &prpsinfo;
188
189 memset(&prpsinfo, 0, sizeof(struct elf32_prpsinfo));
190 prpsinfo.pr_state = 0;
191 prpsinfo.pr_sname = 'R';
192 prpsinfo.pr_zomb = 0;
193 prpsinfo.pr_gid = prpsinfo.pr_uid = mrdump_cb->crash_record.fault_cpu + 1;
194 strlcpy(prpsinfo.pr_fname, "vmlinux", sizeof(prpsinfo.pr_fname));
195 strlcpy(prpsinfo.pr_psargs, "vmlinux", ELF_PRARGSZ);
196
197 nhdr->p_filesz += notesize(&notes);
198 bufp = storenote(&notes, bufp);
199
200 bufp = kdump_core_write_machdesc(mrdump_cb, nhdr, bufp);
201
202 /* Store pre-cpu backtrace */
203 bufp = kdump_core_write_cpu_note(mrdump_cb, mrdump_cb->crash_record.fault_cpu, nhdr, bufp);
204 for (unsigned int cpu = 0; cpu < kparams->nr_cpus; cpu++) {
205 if (cpu != mrdump_cb->crash_record.fault_cpu) {
206 bufp = kdump_core_write_cpu_note(mrdump_cb, cpu, nhdr, bufp);
207 }
208 }
209
210 /* store mrdump control block */
211 bufp = kdump_core_write_mrdump_cb(mrdump_cb, nhdr, bufp);
212}