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