1*b3372aa6SHuibin Hong /*
2*b3372aa6SHuibin Hong * (C) Copyright 2023 Rockchip Electronics Co., Ltd.
3*b3372aa6SHuibin Hong *
4*b3372aa6SHuibin Hong * SPDX-License-Identifier: GPL-2.0+
5*b3372aa6SHuibin Hong */
6*b3372aa6SHuibin Hong
7*b3372aa6SHuibin Hong #include <common.h>
8*b3372aa6SHuibin Hong #include <linux/types.h>
9*b3372aa6SHuibin Hong #include <asm/io.h>
10*b3372aa6SHuibin Hong #include <rk_mini_dump.h>
11*b3372aa6SHuibin Hong
12*b3372aa6SHuibin Hong /* don't modify it, it is behind pstore memory space */
13*b3372aa6SHuibin Hong #ifdef CONFIG_ROCKCHIP_MINIDUMP_SMEM_BASE
14*b3372aa6SHuibin Hong #define SMEM_BASE CONFIG_ROCKCHIP_MINIDUMP_SMEM_BASE
15*b3372aa6SHuibin Hong #else
16*b3372aa6SHuibin Hong #define SMEM_BASE 0x1f0000
17*b3372aa6SHuibin Hong #endif
18*b3372aa6SHuibin Hong
19*b3372aa6SHuibin Hong #ifdef CONFIG_ROCKCHIP_MINIDUMP_MAX_ELF_SIZE
20*b3372aa6SHuibin Hong #define MAX_ELF_SIZE CONFIG_ROCKCHIP_MINIDUMP_MAX_ELF_SIZE
21*b3372aa6SHuibin Hong #else
22*b3372aa6SHuibin Hong #define MAX_ELF_SIZE 0x2000000
23*b3372aa6SHuibin Hong #endif
24*b3372aa6SHuibin Hong
25*b3372aa6SHuibin Hong #ifdef CONFIG_ROCKCHIP_MINIDUMP_MAX_ENTRIES
26*b3372aa6SHuibin Hong #define MAX_NUM_ENTRIES (CONFIG_ROCKCHIP_MINIDUMP_MAX_ENTRIES + 1)
27*b3372aa6SHuibin Hong #else
28*b3372aa6SHuibin Hong #define MAX_NUM_ENTRIES 129
29*b3372aa6SHuibin Hong #endif
30*b3372aa6SHuibin Hong
31*b3372aa6SHuibin Hong /* Bootloader has 16 byte support, 4 bytes reserved for itself */
32*b3372aa6SHuibin Hong #define MAX_REGION_NAME_LENGTH 16
33*b3372aa6SHuibin Hong #define MAX_STRTBL_SIZE (MAX_NUM_ENTRIES * MAX_REGION_NAME_LENGTH)
34*b3372aa6SHuibin Hong
35*b3372aa6SHuibin Hong /**
36*b3372aa6SHuibin Hong * md_table : Local Minidump toc holder
37*b3372aa6SHuibin Hong * @num_regions : Number of regions requested
38*b3372aa6SHuibin Hong * @md_ss_toc : HLOS toc pointer
39*b3372aa6SHuibin Hong * @md_gbl_toc : Global toc pointer
40*b3372aa6SHuibin Hong * @md_regions : HLOS regions base pointer
41*b3372aa6SHuibin Hong * @entry : array of HLOS regions requested
42*b3372aa6SHuibin Hong */
43*b3372aa6SHuibin Hong struct md_table {
44*b3372aa6SHuibin Hong u32 revision;
45*b3372aa6SHuibin Hong u32 num_regions;
46*b3372aa6SHuibin Hong struct md_ss_toc *md_ss_toc;
47*b3372aa6SHuibin Hong struct md_global_toc *md_gbl_toc;
48*b3372aa6SHuibin Hong struct md_ss_region *md_regions;
49*b3372aa6SHuibin Hong struct md_region entry[MAX_NUM_ENTRIES];
50*b3372aa6SHuibin Hong };
51*b3372aa6SHuibin Hong
52*b3372aa6SHuibin Hong #define MAX_NUM_OF_SS 2
53*b3372aa6SHuibin Hong
54*b3372aa6SHuibin Hong /**
55*b3372aa6SHuibin Hong * md_ss_toc: Sub system SMEM Table of content
56*b3372aa6SHuibin Hong * @md_ss_toc_init : SS toc init status
57*b3372aa6SHuibin Hong * @md_ss_enable_status : if set to 1, Bootloader would dump this SS regions
58*b3372aa6SHuibin Hong * @encryption_status: Encryption status for this subsystem
59*b3372aa6SHuibin Hong * @encryption_required : Decides to encrypt the SS regions or not
60*b3372aa6SHuibin Hong * @ss_region_count : Number of regions added in this SS toc
61*b3372aa6SHuibin Hong * @md_ss_smem_regions_baseptr : regions base pointer of the Subsystem
62*b3372aa6SHuibin Hong * @elf_header : base pointer of the minidump elf header
63*b3372aa6SHuibin Hong * @minidump_table : base pointer of the minidump_table
64*b3372aa6SHuibin Hong */
65*b3372aa6SHuibin Hong struct md_ss_toc {
66*b3372aa6SHuibin Hong u32 md_ss_toc_init;
67*b3372aa6SHuibin Hong u32 md_ss_enable_status;
68*b3372aa6SHuibin Hong u32 encryption_status;
69*b3372aa6SHuibin Hong u32 encryption_required;
70*b3372aa6SHuibin Hong u32 ss_region_count;
71*b3372aa6SHuibin Hong u64 md_ss_smem_regions_baseptr;
72*b3372aa6SHuibin Hong u64 elf_header;
73*b3372aa6SHuibin Hong u64 elf_size;
74*b3372aa6SHuibin Hong u64 minidump_table;
75*b3372aa6SHuibin Hong };
76*b3372aa6SHuibin Hong
77*b3372aa6SHuibin Hong /**
78*b3372aa6SHuibin Hong * md_global_toc: Global Table of Content
79*b3372aa6SHuibin Hong * @md_toc_init : Global Minidump init status
80*b3372aa6SHuibin Hong * @md_revision : Minidump revision
81*b3372aa6SHuibin Hong * @md_enable_status : Minidump enable status
82*b3372aa6SHuibin Hong * @md_ss_toc : Array of subsystems toc
83*b3372aa6SHuibin Hong */
84*b3372aa6SHuibin Hong struct md_global_toc {
85*b3372aa6SHuibin Hong u32 md_toc_init;
86*b3372aa6SHuibin Hong u32 md_revision;
87*b3372aa6SHuibin Hong u32 md_enable_status;
88*b3372aa6SHuibin Hong struct md_ss_toc md_ss_toc[MAX_NUM_OF_SS];
89*b3372aa6SHuibin Hong };
90*b3372aa6SHuibin Hong
91*b3372aa6SHuibin Hong /* Bootloader has 16 byte support, 4 bytes reserved for itself */
92*b3372aa6SHuibin Hong #define MAX_REGION_NAME_LENGTH 16
93*b3372aa6SHuibin Hong
94*b3372aa6SHuibin Hong #define MD_REGION_VALID ('V' << 24 | 'A' << 16 | 'L' << 8 | 'I' << 0)
95*b3372aa6SHuibin Hong #define MD_REGION_INVALID ('I' << 24 | 'N' << 16 | 'V' << 8 | 'A' << 0)
96*b3372aa6SHuibin Hong #define MD_REGION_INIT ('I' << 24 | 'N' << 16 | 'I' << 8 | 'T' << 0)
97*b3372aa6SHuibin Hong #define MD_REGION_NOINIT 0
98*b3372aa6SHuibin Hong
99*b3372aa6SHuibin Hong #define MD_SS_ENCR_REQ (0 << 24 | 'Y' << 16 | 'E' << 8 | 'S' << 0)
100*b3372aa6SHuibin Hong #define MD_SS_ENCR_NOTREQ (0 << 24 | 0 << 16 | 'N' << 8 | 'R' << 0)
101*b3372aa6SHuibin Hong #define MD_SS_ENCR_NONE ('N' << 24 | 'O' << 16 | 'N' << 8 | 'E' << 0)
102*b3372aa6SHuibin Hong #define MD_SS_ENCR_DONE ('D' << 24 | 'O' << 16 | 'N' << 8 | 'E' << 0)
103*b3372aa6SHuibin Hong #define MD_SS_ENCR_START ('S' << 24 | 'T' << 16 | 'R' << 8 | 'T' << 0)
104*b3372aa6SHuibin Hong #define MD_SS_ENABLED ('E' << 24 | 'N' << 16 | 'B' << 8 | 'L' << 0)
105*b3372aa6SHuibin Hong #define MD_SS_DISABLED ('D' << 24 | 'S' << 16 | 'B' << 8 | 'L' << 0)
106*b3372aa6SHuibin Hong
107*b3372aa6SHuibin Hong #define EM_AARCH64 183 /* ARM 64 bit */
108*b3372aa6SHuibin Hong
109*b3372aa6SHuibin Hong /**
110*b3372aa6SHuibin Hong * md_ss_region - Minidump region
111*b3372aa6SHuibin Hong * @name : Name of the region to be dumped
112*b3372aa6SHuibin Hong * @seq_num: : Use to differentiate regions with same name.
113*b3372aa6SHuibin Hong * @md_valid : This entry to be dumped (if set to 1)
114*b3372aa6SHuibin Hong * @region_base_address : Physical address of region to be dumped
115*b3372aa6SHuibin Hong * @region_size : Size of the region
116*b3372aa6SHuibin Hong */
117*b3372aa6SHuibin Hong struct md_ss_region {
118*b3372aa6SHuibin Hong char name[MAX_REGION_NAME_LENGTH];
119*b3372aa6SHuibin Hong u32 seq_num;
120*b3372aa6SHuibin Hong u32 md_valid;
121*b3372aa6SHuibin Hong u64 region_base_address;
122*b3372aa6SHuibin Hong u64 region_size;
123*b3372aa6SHuibin Hong };
124*b3372aa6SHuibin Hong
125*b3372aa6SHuibin Hong #define NO_FAULT_TAG 0x55aa55aa
126*b3372aa6SHuibin Hong static u32 no_fault;
127*b3372aa6SHuibin Hong static struct md_table *minidump_table;
128*b3372aa6SHuibin Hong
md_no_fault_handler(struct pt_regs * pt_regs,unsigned int esr)129*b3372aa6SHuibin Hong u32 md_no_fault_handler(struct pt_regs *pt_regs, unsigned int esr)
130*b3372aa6SHuibin Hong {
131*b3372aa6SHuibin Hong if (no_fault == NO_FAULT_TAG) {
132*b3372aa6SHuibin Hong no_fault = 0;
133*b3372aa6SHuibin Hong return 1;
134*b3372aa6SHuibin Hong }
135*b3372aa6SHuibin Hong return 0;
136*b3372aa6SHuibin Hong }
137*b3372aa6SHuibin Hong
138*b3372aa6SHuibin Hong #if defined(CONFIG_ROCKCHIP_RK3588)
md_is_ddr_addr(void * addr)139*b3372aa6SHuibin Hong static u32 md_is_ddr_addr(void *addr)
140*b3372aa6SHuibin Hong {
141*b3372aa6SHuibin Hong /* peripheral address space */
142*b3372aa6SHuibin Hong if (addr >= (void *)0xf0000000 && addr <= (void *)0x100000000)
143*b3372aa6SHuibin Hong return 0;
144*b3372aa6SHuibin Hong /* pcie address space */
145*b3372aa6SHuibin Hong if (addr > (void *)0x800000000)
146*b3372aa6SHuibin Hong return 0;
147*b3372aa6SHuibin Hong return 1;
148*b3372aa6SHuibin Hong }
149*b3372aa6SHuibin Hong #else
md_is_ddr_addr(void * addr)150*b3372aa6SHuibin Hong static u32 md_is_ddr_addr(void *addr)
151*b3372aa6SHuibin Hong {
152*b3372aa6SHuibin Hong return 1;
153*b3372aa6SHuibin Hong }
154*b3372aa6SHuibin Hong #endif
155*b3372aa6SHuibin Hong
md_is_uboot_addr(void * addr)156*b3372aa6SHuibin Hong static u32 md_is_uboot_addr(void *addr)
157*b3372aa6SHuibin Hong {
158*b3372aa6SHuibin Hong volatile u32 *p_no_fault = &no_fault;
159*b3372aa6SHuibin Hong
160*b3372aa6SHuibin Hong if(!md_is_ddr_addr(addr))
161*b3372aa6SHuibin Hong return 0;
162*b3372aa6SHuibin Hong
163*b3372aa6SHuibin Hong *p_no_fault = NO_FAULT_TAG;
164*b3372aa6SHuibin Hong readb(addr);
165*b3372aa6SHuibin Hong return *p_no_fault;
166*b3372aa6SHuibin Hong }
167*b3372aa6SHuibin Hong
md_get_region(char * name)168*b3372aa6SHuibin Hong struct md_region *md_get_region(char *name)
169*b3372aa6SHuibin Hong {
170*b3372aa6SHuibin Hong struct md_region *mdr;
171*b3372aa6SHuibin Hong int i, regno;
172*b3372aa6SHuibin Hong
173*b3372aa6SHuibin Hong if (!md_is_uboot_addr((void *)minidump_table))
174*b3372aa6SHuibin Hong return NULL;
175*b3372aa6SHuibin Hong
176*b3372aa6SHuibin Hong regno = minidump_table->num_regions;
177*b3372aa6SHuibin Hong for (i = 0; i < regno; i++) {
178*b3372aa6SHuibin Hong mdr = &minidump_table->entry[i];
179*b3372aa6SHuibin Hong if (!strcmp(mdr->name, name))
180*b3372aa6SHuibin Hong return mdr;
181*b3372aa6SHuibin Hong }
182*b3372aa6SHuibin Hong return NULL;
183*b3372aa6SHuibin Hong }
184*b3372aa6SHuibin Hong
185*b3372aa6SHuibin Hong #ifdef CONFIG_ARM64
rk_dump_elf64_image_phdr(void * ram_image,Elf64_Addr ehaddr,Elf64_Xword ehsize)186*b3372aa6SHuibin Hong static Elf64_Xword rk_dump_elf64_image_phdr(void *ram_image,
187*b3372aa6SHuibin Hong Elf64_Addr ehaddr, Elf64_Xword ehsize)
188*b3372aa6SHuibin Hong {
189*b3372aa6SHuibin Hong Elf64_Ehdr *ehdr = (Elf64_Ehdr *)ehaddr;
190*b3372aa6SHuibin Hong Elf64_Phdr *phdr = NULL, *phdr_next = NULL;
191*b3372aa6SHuibin Hong Elf64_Shdr *shdr = NULL, *shdr_next = NULL;
192*b3372aa6SHuibin Hong unsigned int i = 0, error = 0, phdr_off = 0, strtbl_off = 0;
193*b3372aa6SHuibin Hong unsigned int size = 0, elf_size = ehsize;
194*b3372aa6SHuibin Hong
195*b3372aa6SHuibin Hong if (!md_is_uboot_addr((void *)ehdr))
196*b3372aa6SHuibin Hong return 0;
197*b3372aa6SHuibin Hong
198*b3372aa6SHuibin Hong if (!md_is_uboot_addr((void *)ram_image) ||
199*b3372aa6SHuibin Hong !md_is_uboot_addr((void *)ram_image + MAX_ELF_SIZE - 4))
200*b3372aa6SHuibin Hong return 0;
201*b3372aa6SHuibin Hong
202*b3372aa6SHuibin Hong memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
203*b3372aa6SHuibin Hong ehdr->e_ident[EI_CLASS] = ELFCLASS64;
204*b3372aa6SHuibin Hong ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
205*b3372aa6SHuibin Hong ehdr->e_ident[EI_VERSION] = EV_CURRENT;
206*b3372aa6SHuibin Hong ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
207*b3372aa6SHuibin Hong
208*b3372aa6SHuibin Hong if (ehdr->e_type != ET_CORE) {
209*b3372aa6SHuibin Hong error++;
210*b3372aa6SHuibin Hong ehdr->e_type = ET_CORE;
211*b3372aa6SHuibin Hong }
212*b3372aa6SHuibin Hong if (ehdr->e_machine != EM_AARCH64) {
213*b3372aa6SHuibin Hong error++;
214*b3372aa6SHuibin Hong ehdr->e_machine = EM_AARCH64;
215*b3372aa6SHuibin Hong }
216*b3372aa6SHuibin Hong if (ehdr->e_version != EV_CURRENT) {
217*b3372aa6SHuibin Hong error++;
218*b3372aa6SHuibin Hong ehdr->e_version = EV_CURRENT;
219*b3372aa6SHuibin Hong }
220*b3372aa6SHuibin Hong if (ehdr->e_ehsize != sizeof(*ehdr)) {
221*b3372aa6SHuibin Hong error++;
222*b3372aa6SHuibin Hong ehdr->e_ehsize = sizeof(*ehdr);
223*b3372aa6SHuibin Hong }
224*b3372aa6SHuibin Hong if (ehdr->e_phentsize != sizeof(*phdr)) {
225*b3372aa6SHuibin Hong error++;
226*b3372aa6SHuibin Hong ehdr->e_phentsize = sizeof(*phdr);
227*b3372aa6SHuibin Hong }
228*b3372aa6SHuibin Hong if (ehdr->e_shentsize != sizeof(*shdr)) {
229*b3372aa6SHuibin Hong error++;
230*b3372aa6SHuibin Hong ehdr->e_shentsize = sizeof(*shdr);
231*b3372aa6SHuibin Hong }
232*b3372aa6SHuibin Hong if (ehdr->e_shoff != sizeof(*ehdr)) {
233*b3372aa6SHuibin Hong error++;
234*b3372aa6SHuibin Hong ehdr->e_shoff = sizeof(*ehdr);
235*b3372aa6SHuibin Hong }
236*b3372aa6SHuibin Hong
237*b3372aa6SHuibin Hong phdr_off = sizeof(*ehdr) + (sizeof(*shdr) * MAX_NUM_ENTRIES);
238*b3372aa6SHuibin Hong
239*b3372aa6SHuibin Hong if (ehdr->e_phoff != phdr_off) {
240*b3372aa6SHuibin Hong error++;
241*b3372aa6SHuibin Hong ehdr->e_phoff = phdr_off;
242*b3372aa6SHuibin Hong }
243*b3372aa6SHuibin Hong
244*b3372aa6SHuibin Hong printf("Minidump header error:0x%x\n", error);
245*b3372aa6SHuibin Hong /* If there are much error, maybe ehdr address is wrong */
246*b3372aa6SHuibin Hong if (error > 6)
247*b3372aa6SHuibin Hong return 0;
248*b3372aa6SHuibin Hong
249*b3372aa6SHuibin Hong ehdr->e_shstrndx = 1;
250*b3372aa6SHuibin Hong phdr = (Elf64_Phdr *)(ehaddr + ehdr->e_phoff);
251*b3372aa6SHuibin Hong shdr = (Elf64_Shdr *)(ehaddr + ehdr->e_shoff);
252*b3372aa6SHuibin Hong
253*b3372aa6SHuibin Hong shdr->sh_name = 0;
254*b3372aa6SHuibin Hong shdr->sh_type = 0;
255*b3372aa6SHuibin Hong shdr->sh_flags = 0;
256*b3372aa6SHuibin Hong shdr->sh_addr = 0;
257*b3372aa6SHuibin Hong shdr->sh_offset = 0;
258*b3372aa6SHuibin Hong shdr->sh_size = 0;
259*b3372aa6SHuibin Hong shdr->sh_link = 0;
260*b3372aa6SHuibin Hong shdr->sh_info = 0;
261*b3372aa6SHuibin Hong shdr->sh_addralign = 0;
262*b3372aa6SHuibin Hong shdr->sh_entsize = 0;
263*b3372aa6SHuibin Hong
264*b3372aa6SHuibin Hong shdr++;
265*b3372aa6SHuibin Hong if (shdr->sh_name >= MAX_STRTBL_SIZE)
266*b3372aa6SHuibin Hong shdr->sh_name = 0;
267*b3372aa6SHuibin Hong shdr->sh_type = SHT_STRTAB;
268*b3372aa6SHuibin Hong shdr->sh_flags = 0;
269*b3372aa6SHuibin Hong shdr->sh_addr = 0;
270*b3372aa6SHuibin Hong shdr->sh_offset = phdr_off + (sizeof(*phdr) * MAX_NUM_ENTRIES);
271*b3372aa6SHuibin Hong shdr->sh_size = MAX_STRTBL_SIZE;
272*b3372aa6SHuibin Hong shdr->sh_link = 0;
273*b3372aa6SHuibin Hong shdr->sh_info = 0;
274*b3372aa6SHuibin Hong shdr->sh_addralign = 0;
275*b3372aa6SHuibin Hong shdr->sh_entsize = 0;
276*b3372aa6SHuibin Hong
277*b3372aa6SHuibin Hong shdr++;
278*b3372aa6SHuibin Hong /* 3rd section is for minidump_table VA, used by parsers */
279*b3372aa6SHuibin Hong if (shdr->sh_name >= MAX_STRTBL_SIZE)
280*b3372aa6SHuibin Hong shdr->sh_name = 0;
281*b3372aa6SHuibin Hong shdr->sh_type = SHT_PROGBITS;
282*b3372aa6SHuibin Hong shdr->sh_flags = 0;
283*b3372aa6SHuibin Hong shdr->sh_offset = 0;
284*b3372aa6SHuibin Hong shdr->sh_size = 0;
285*b3372aa6SHuibin Hong shdr->sh_link = 0;
286*b3372aa6SHuibin Hong shdr->sh_info = 0;
287*b3372aa6SHuibin Hong shdr->sh_addralign = 0;
288*b3372aa6SHuibin Hong shdr->sh_entsize = 0;
289*b3372aa6SHuibin Hong
290*b3372aa6SHuibin Hong shdr++;
291*b3372aa6SHuibin Hong shdr->sh_flags = 0;
292*b3372aa6SHuibin Hong shdr->sh_link = 0;
293*b3372aa6SHuibin Hong shdr->sh_info = 0;
294*b3372aa6SHuibin Hong shdr->sh_addralign = 0;
295*b3372aa6SHuibin Hong shdr->sh_entsize = 0;
296*b3372aa6SHuibin Hong
297*b3372aa6SHuibin Hong strtbl_off = phdr_off + (sizeof(*phdr) * MAX_NUM_ENTRIES);
298*b3372aa6SHuibin Hong strtbl_off += MAX_STRTBL_SIZE;
299*b3372aa6SHuibin Hong
300*b3372aa6SHuibin Hong if (phdr->p_offset != strtbl_off)
301*b3372aa6SHuibin Hong phdr->p_offset = strtbl_off;
302*b3372aa6SHuibin Hong if (shdr->sh_offset != strtbl_off)
303*b3372aa6SHuibin Hong shdr->sh_offset = strtbl_off;
304*b3372aa6SHuibin Hong
305*b3372aa6SHuibin Hong phdr->p_filesz &= GENMASK(23, 0); /* 16MB */
306*b3372aa6SHuibin Hong phdr->p_memsz &= GENMASK(23, 0); /* 16MB */
307*b3372aa6SHuibin Hong shdr->sh_size &= GENMASK(23, 0); /* 16MB */
308*b3372aa6SHuibin Hong
309*b3372aa6SHuibin Hong if (phdr->p_filesz == phdr->p_memsz) {
310*b3372aa6SHuibin Hong size = phdr->p_filesz;
311*b3372aa6SHuibin Hong shdr->sh_size = size;
312*b3372aa6SHuibin Hong } else if (phdr->p_filesz == shdr->sh_size) {
313*b3372aa6SHuibin Hong size = phdr->p_filesz;
314*b3372aa6SHuibin Hong phdr->p_memsz = size;
315*b3372aa6SHuibin Hong } else if (phdr->p_memsz == shdr->sh_size) {
316*b3372aa6SHuibin Hong size = phdr->p_memsz;
317*b3372aa6SHuibin Hong phdr->p_filesz = size;
318*b3372aa6SHuibin Hong } else {
319*b3372aa6SHuibin Hong printf("Minidump error first phdr p_filesz:0x%llx p_memsz:0x%llx sh_size:0x%llx\n",
320*b3372aa6SHuibin Hong phdr->p_filesz, phdr->p_memsz, shdr->sh_size);
321*b3372aa6SHuibin Hong return 0;
322*b3372aa6SHuibin Hong }
323*b3372aa6SHuibin Hong
324*b3372aa6SHuibin Hong phdr++;
325*b3372aa6SHuibin Hong shdr++;
326*b3372aa6SHuibin Hong phdr_next = phdr + 1;
327*b3372aa6SHuibin Hong shdr_next = shdr + 1;
328*b3372aa6SHuibin Hong
329*b3372aa6SHuibin Hong memset(ram_image, 0x0, 0x18000);
330*b3372aa6SHuibin Hong
331*b3372aa6SHuibin Hong phdr->p_offset &= MAX_ELF_SIZE - 1;
332*b3372aa6SHuibin Hong shdr->sh_offset &= MAX_ELF_SIZE - 1;
333*b3372aa6SHuibin Hong elf_size &= MAX_ELF_SIZE - 1;
334*b3372aa6SHuibin Hong if (phdr->p_offset == shdr->sh_offset) {
335*b3372aa6SHuibin Hong elf_size = phdr->p_offset;
336*b3372aa6SHuibin Hong } else if (phdr->p_offset == elf_size) {
337*b3372aa6SHuibin Hong shdr->sh_offset = phdr->p_offset;
338*b3372aa6SHuibin Hong } else if (elf_size == shdr->sh_offset) {
339*b3372aa6SHuibin Hong phdr->p_offset = shdr->sh_offset;
340*b3372aa6SHuibin Hong } else {
341*b3372aa6SHuibin Hong printf("Minidump error phdr[1] p_offset:0x%llx sh_offset:0x%llx elf_size:0x%x\n",
342*b3372aa6SHuibin Hong phdr->p_offset, shdr->sh_offset, elf_size);
343*b3372aa6SHuibin Hong return 0;
344*b3372aa6SHuibin Hong }
345*b3372aa6SHuibin Hong
346*b3372aa6SHuibin Hong /* save phdr space */
347*b3372aa6SHuibin Hong for (i = 1; i < MAX_NUM_ENTRIES; i++) {
348*b3372aa6SHuibin Hong void *src = NULL;
349*b3372aa6SHuibin Hong void *dst = NULL;
350*b3372aa6SHuibin Hong
351*b3372aa6SHuibin Hong if (phdr->p_vaddr == 0 || shdr->sh_addr == 0)
352*b3372aa6SHuibin Hong break;
353*b3372aa6SHuibin Hong
354*b3372aa6SHuibin Hong phdr->p_offset &= MAX_ELF_SIZE - 1;
355*b3372aa6SHuibin Hong shdr->sh_offset &= MAX_ELF_SIZE - 1;
356*b3372aa6SHuibin Hong
357*b3372aa6SHuibin Hong if (phdr->p_offset != elf_size)
358*b3372aa6SHuibin Hong phdr->p_offset = elf_size;
359*b3372aa6SHuibin Hong
360*b3372aa6SHuibin Hong if (shdr->sh_offset != elf_size)
361*b3372aa6SHuibin Hong shdr->sh_offset = elf_size;
362*b3372aa6SHuibin Hong
363*b3372aa6SHuibin Hong phdr->p_paddr &= GENMASK(34, 0); /* 32GB */
364*b3372aa6SHuibin Hong phdr->p_align &= GENMASK(34, 0); /* 32GB */
365*b3372aa6SHuibin Hong shdr->sh_info &= GENMASK(34, 0); /* 32GB */
366*b3372aa6SHuibin Hong
367*b3372aa6SHuibin Hong if (phdr->p_paddr != phdr->p_align && phdr->p_align == shdr->sh_entsize)
368*b3372aa6SHuibin Hong phdr->p_paddr = phdr->p_align;
369*b3372aa6SHuibin Hong
370*b3372aa6SHuibin Hong phdr->p_type &= 0xf;
371*b3372aa6SHuibin Hong phdr->p_flags &= 0xf;
372*b3372aa6SHuibin Hong phdr->p_filesz &= GENMASK(23, 0); /* 16MB */
373*b3372aa6SHuibin Hong phdr->p_memsz &= GENMASK(23, 0); /* 16MB */
374*b3372aa6SHuibin Hong phdr->p_align = 0;
375*b3372aa6SHuibin Hong
376*b3372aa6SHuibin Hong if (phdr->p_vaddr != shdr->sh_addr) {
377*b3372aa6SHuibin Hong if (shdr->sh_addr == shdr->sh_addralign)
378*b3372aa6SHuibin Hong phdr->p_vaddr = shdr->sh_addr;
379*b3372aa6SHuibin Hong else if (phdr->p_vaddr == shdr->sh_addralign)
380*b3372aa6SHuibin Hong shdr->sh_addr = phdr->p_vaddr;
381*b3372aa6SHuibin Hong else
382*b3372aa6SHuibin Hong printf("Minidump error phdr[%d] p_vaddr:0x%llx sh_addr:0x%llx sh_addralign:0x%llx\n",
383*b3372aa6SHuibin Hong i, phdr->p_vaddr, shdr->sh_addr, shdr->sh_addralign);
384*b3372aa6SHuibin Hong }
385*b3372aa6SHuibin Hong
386*b3372aa6SHuibin Hong if (shdr->sh_name >= MAX_STRTBL_SIZE)
387*b3372aa6SHuibin Hong shdr->sh_name = 0;
388*b3372aa6SHuibin Hong shdr->sh_type = SHT_PROGBITS;
389*b3372aa6SHuibin Hong shdr->sh_flags = SHF_WRITE;
390*b3372aa6SHuibin Hong shdr->sh_size &= GENMASK(23, 0); /* 16MB */
391*b3372aa6SHuibin Hong shdr->sh_link = 0;
392*b3372aa6SHuibin Hong shdr->sh_info = 0;
393*b3372aa6SHuibin Hong shdr->sh_addralign = 0;
394*b3372aa6SHuibin Hong shdr->sh_entsize = 0;
395*b3372aa6SHuibin Hong
396*b3372aa6SHuibin Hong if (phdr->p_filesz == phdr->p_memsz) {
397*b3372aa6SHuibin Hong size = phdr->p_filesz;
398*b3372aa6SHuibin Hong shdr->sh_size = size;
399*b3372aa6SHuibin Hong } else if (phdr->p_filesz == shdr->sh_size) {
400*b3372aa6SHuibin Hong size = phdr->p_filesz;
401*b3372aa6SHuibin Hong phdr->p_memsz = size;
402*b3372aa6SHuibin Hong } else if (phdr->p_memsz == shdr->sh_size) {
403*b3372aa6SHuibin Hong size = phdr->p_memsz;
404*b3372aa6SHuibin Hong phdr->p_filesz = size;
405*b3372aa6SHuibin Hong } else {
406*b3372aa6SHuibin Hong if ((phdr_next->p_offset == shdr_next->sh_offset) &&
407*b3372aa6SHuibin Hong (phdr_next->p_offset != 0)) {
408*b3372aa6SHuibin Hong size = phdr_next->p_offset - phdr->p_offset;
409*b3372aa6SHuibin Hong phdr->p_filesz = size;
410*b3372aa6SHuibin Hong phdr->p_memsz = size;
411*b3372aa6SHuibin Hong shdr->sh_size = size;
412*b3372aa6SHuibin Hong } else {
413*b3372aa6SHuibin Hong printf("Minidump error phdr[%d] p_filesz:0x%llx p_memsz:0x%llx sh_size:0x%llx",
414*b3372aa6SHuibin Hong i, phdr->p_filesz, phdr->p_memsz, shdr->sh_size);
415*b3372aa6SHuibin Hong printf("p_offset:0x%llx sh_offset:0x%llx\n", phdr_next->p_offset,
416*b3372aa6SHuibin Hong shdr_next->sh_offset);
417*b3372aa6SHuibin Hong return 0;
418*b3372aa6SHuibin Hong }
419*b3372aa6SHuibin Hong }
420*b3372aa6SHuibin Hong
421*b3372aa6SHuibin Hong elf_size += size;
422*b3372aa6SHuibin Hong src = (void *)(Elf64_Addr)phdr->p_paddr;
423*b3372aa6SHuibin Hong dst = ram_image + phdr->p_offset;
424*b3372aa6SHuibin Hong
425*b3372aa6SHuibin Hong if (size > MAX_ELF_SIZE / 2)
426*b3372aa6SHuibin Hong goto donot_cpy;
427*b3372aa6SHuibin Hong
428*b3372aa6SHuibin Hong if (!md_is_uboot_addr(src) || !md_is_uboot_addr(src + size - 1)) {
429*b3372aa6SHuibin Hong printf("Minidump error src 0x%p-0x%p\n", src, src + size - 1);
430*b3372aa6SHuibin Hong goto donot_cpy;
431*b3372aa6SHuibin Hong }
432*b3372aa6SHuibin Hong if (!md_is_uboot_addr(dst) || !md_is_uboot_addr(dst + size - 1)) {
433*b3372aa6SHuibin Hong printf("Minidump error dst 0x%p-0x%p\n", dst, dst + size - 1);
434*b3372aa6SHuibin Hong goto donot_cpy;
435*b3372aa6SHuibin Hong }
436*b3372aa6SHuibin Hong if (size)
437*b3372aa6SHuibin Hong memcpy(dst, src, size);
438*b3372aa6SHuibin Hong donot_cpy:
439*b3372aa6SHuibin Hong phdr++;
440*b3372aa6SHuibin Hong shdr++;
441*b3372aa6SHuibin Hong phdr_next++;
442*b3372aa6SHuibin Hong shdr_next++;
443*b3372aa6SHuibin Hong }
444*b3372aa6SHuibin Hong
445*b3372aa6SHuibin Hong if (ehdr->e_phnum != i)
446*b3372aa6SHuibin Hong ehdr->e_phnum = i;
447*b3372aa6SHuibin Hong if ((ehdr->e_phnum + 3) != ehdr->e_shnum)
448*b3372aa6SHuibin Hong ehdr->e_shnum = ehdr->e_phnum + 3;
449*b3372aa6SHuibin Hong
450*b3372aa6SHuibin Hong /* copy ehdr to ram image */
451*b3372aa6SHuibin Hong memcpy(ram_image, (void *)ehdr, ehsize);
452*b3372aa6SHuibin Hong flush_cache((unsigned long)ram_image, elf_size);
453*b3372aa6SHuibin Hong printf("Minidump.elf 0x%x@0x%p\n", elf_size, ram_image);
454*b3372aa6SHuibin Hong return elf_size;
455*b3372aa6SHuibin Hong }
456*b3372aa6SHuibin Hong #else
rk_dump_elf32_image_phdr(void * ram_image,Elf32_Addr ehaddr,Elf32_Word ehsize)457*b3372aa6SHuibin Hong static Elf32_Word rk_dump_elf32_image_phdr(void *ram_image, Elf32_Addr ehaddr,
458*b3372aa6SHuibin Hong Elf32_Word ehsize)
459*b3372aa6SHuibin Hong {
460*b3372aa6SHuibin Hong Elf32_Ehdr *ehdr = (Elf32_Ehdr *)ehaddr;
461*b3372aa6SHuibin Hong Elf32_Phdr *phdr = (Elf32_Phdr *)(ehaddr + ehdr->e_phoff);
462*b3372aa6SHuibin Hong Elf32_Word ram_image_size = 0;
463*b3372aa6SHuibin Hong int i;
464*b3372aa6SHuibin Hong
465*b3372aa6SHuibin Hong /* copy ehdr to ram image */
466*b3372aa6SHuibin Hong memcpy(ram_image, (void *)ehdr, ehsize);
467*b3372aa6SHuibin Hong
468*b3372aa6SHuibin Hong /* save phdr space */
469*b3372aa6SHuibin Hong for (i = 0; i < ehdr->e_phnum; ++i) {
470*b3372aa6SHuibin Hong void *src = (void *)(Elf32_Addr)phdr->p_paddr;
471*b3372aa6SHuibin Hong void *dst = ram_image + phdr->p_offset;
472*b3372aa6SHuibin Hong
473*b3372aa6SHuibin Hong if (phdr->p_filesz)
474*b3372aa6SHuibin Hong memcpy(dst, src, phdr->p_filesz);
475*b3372aa6SHuibin Hong if (phdr->p_filesz != phdr->p_memsz)
476*b3372aa6SHuibin Hong memset(dst + phdr->p_filesz, 0x00,
477*b3372aa6SHuibin Hong phdr->p_memsz - phdr->p_filesz);
478*b3372aa6SHuibin Hong ++phdr;
479*b3372aa6SHuibin Hong }
480*b3372aa6SHuibin Hong
481*b3372aa6SHuibin Hong phdr--;
482*b3372aa6SHuibin Hong ram_image_size = phdr->p_memsz + phdr->p_offset;
483*b3372aa6SHuibin Hong printf("Minidump.elf 0x%llx@0x%p\n", ram_image_size, ram_image);
484*b3372aa6SHuibin Hong return ram_image_size;
485*b3372aa6SHuibin Hong }
486*b3372aa6SHuibin Hong #endif
487*b3372aa6SHuibin Hong
rk_minidump_init(void)488*b3372aa6SHuibin Hong void rk_minidump_init(void)
489*b3372aa6SHuibin Hong {
490*b3372aa6SHuibin Hong struct md_global_toc *mdg_toc = (struct md_global_toc *)SMEM_BASE;
491*b3372aa6SHuibin Hong struct md_ss_toc *md_ss_toc = &mdg_toc->md_ss_toc[0];
492*b3372aa6SHuibin Hong struct md_ss_region *mdreg;
493*b3372aa6SHuibin Hong
494*b3372aa6SHuibin Hong printf("Minidump: init...\n");
495*b3372aa6SHuibin Hong mdg_toc->md_toc_init = 1;
496*b3372aa6SHuibin Hong mdg_toc->md_revision = 1;
497*b3372aa6SHuibin Hong mdg_toc->md_enable_status = 0;
498*b3372aa6SHuibin Hong
499*b3372aa6SHuibin Hong if (md_ss_toc->md_ss_enable_status == MD_SS_ENABLED) {
500*b3372aa6SHuibin Hong /* linux would set it 1, so we set it 0 here */
501*b3372aa6SHuibin Hong md_ss_toc->md_ss_enable_status = 0;
502*b3372aa6SHuibin Hong flush_cache((unsigned long)md_ss_toc, 8);
503*b3372aa6SHuibin Hong mdreg = (struct md_ss_region *)md_ss_toc->md_ss_smem_regions_baseptr;
504*b3372aa6SHuibin Hong minidump_table = (struct md_table *)md_ss_toc->minidump_table;
505*b3372aa6SHuibin Hong #ifdef CONFIG_ARM64
506*b3372aa6SHuibin Hong md_ss_toc->elf_size = rk_dump_elf64_image_phdr((void *)md_ss_toc->elf_header,
507*b3372aa6SHuibin Hong (Elf64_Addr)mdreg->region_base_address,
508*b3372aa6SHuibin Hong (Elf64_Xword)mdreg->region_size);
509*b3372aa6SHuibin Hong #else
510*b3372aa6SHuibin Hong md_ss_toc->elf_size = rk_dump_elf32_image_phdr((void *)md_ss_toc->elf_header,
511*b3372aa6SHuibin Hong (Elf32_Addr)mdreg->region_base_address,
512*b3372aa6SHuibin Hong (Elf32_Word)mdreg->region_size);
513*b3372aa6SHuibin Hong #endif
514*b3372aa6SHuibin Hong }
515*b3372aa6SHuibin Hong }
516*b3372aa6SHuibin Hong
517*b3372aa6SHuibin Hong #ifdef CONFIG_ARM64
rk_minidump_get_el64(void ** ram_image_addr,Elf64_Xword * ram_image_size)518*b3372aa6SHuibin Hong void rk_minidump_get_el64(void **ram_image_addr, Elf64_Xword *ram_image_size)
519*b3372aa6SHuibin Hong {
520*b3372aa6SHuibin Hong struct md_global_toc *mdg_toc = (struct md_global_toc *)SMEM_BASE;
521*b3372aa6SHuibin Hong struct md_ss_toc *md_ss_toc = &mdg_toc->md_ss_toc[0];
522*b3372aa6SHuibin Hong
523*b3372aa6SHuibin Hong *ram_image_addr = (void *)md_ss_toc->elf_header;
524*b3372aa6SHuibin Hong *ram_image_size = md_ss_toc->elf_size;
525*b3372aa6SHuibin Hong }
526*b3372aa6SHuibin Hong #else
rk_minidump_get_el32(void ** ram_image_addr,Elf32_Word * ram_image_size)527*b3372aa6SHuibin Hong void rk_minidump_get_el32(void **ram_image_addr, Elf32_Word *ram_image_size)
528*b3372aa6SHuibin Hong {
529*b3372aa6SHuibin Hong struct md_global_toc *mdg_toc = (struct md_global_toc *)SMEM_BASE;
530*b3372aa6SHuibin Hong struct md_ss_toc *md_ss_toc = &mdg_toc->md_ss_toc[0];
531*b3372aa6SHuibin Hong
532*b3372aa6SHuibin Hong *ram_image_addr = (void *)md_ss_toc->elf_header;
533*b3372aa6SHuibin Hong *ram_image_size = md_ss_toc->elf_size;
534*b3372aa6SHuibin Hong }
535*b3372aa6SHuibin Hong #endif
536