xref: /openbmc/qemu/target/riscv/arch_dump.c (revision a9fe9e191b4305b88c356a1ed9ac3baf89eb18aa)
1*3b57254dSWeiwei Li /*
2*3b57254dSWeiwei Li  * Support for writing ELF notes for RISC-V architectures
343a96588SYifei Jiang  *
443a96588SYifei Jiang  * Copyright (C) 2021 Huawei Technologies Co., Ltd
543a96588SYifei Jiang  *
643a96588SYifei Jiang  * This program is free software; you can redistribute it and/or modify it
743a96588SYifei Jiang  * under the terms and conditions of the GNU General Public License,
843a96588SYifei Jiang  * version 2 or later, as published by the Free Software Foundation.
943a96588SYifei Jiang  *
1043a96588SYifei Jiang  * This program is distributed in the hope it will be useful, but WITHOUT
1143a96588SYifei Jiang  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1243a96588SYifei Jiang  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
1343a96588SYifei Jiang  * more details.
1443a96588SYifei Jiang  *
1543a96588SYifei Jiang  * You should have received a copy of the GNU General Public License along with
1643a96588SYifei Jiang  * this program.  If not, see <http://www.gnu.org/licenses/>.
1743a96588SYifei Jiang  */
1843a96588SYifei Jiang 
1943a96588SYifei Jiang #include "qemu/osdep.h"
2043a96588SYifei Jiang #include "cpu.h"
2143a96588SYifei Jiang #include "elf.h"
2243a96588SYifei Jiang #include "sysemu/dump.h"
2343a96588SYifei Jiang 
2443a96588SYifei Jiang /* struct user_regs_struct from arch/riscv/include/uapi/asm/ptrace.h */
2543a96588SYifei Jiang struct riscv64_user_regs {
2643a96588SYifei Jiang     uint64_t pc;
2743a96588SYifei Jiang     uint64_t regs[31];
2843a96588SYifei Jiang } QEMU_PACKED;
2943a96588SYifei Jiang 
3043a96588SYifei Jiang QEMU_BUILD_BUG_ON(sizeof(struct riscv64_user_regs) != 256);
3143a96588SYifei Jiang 
3243a96588SYifei Jiang /* struct elf_prstatus from include/linux/elfcore.h */
3343a96588SYifei Jiang struct riscv64_elf_prstatus {
3443a96588SYifei Jiang     char pad1[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */
3543a96588SYifei Jiang     uint32_t pr_pid;
3643a96588SYifei Jiang     char pad2[76]; /* 76 == offsetof(struct elf_prstatus, pr_reg) -
3743a96588SYifei Jiang                             offsetof(struct elf_prstatus, pr_ppid) */
3843a96588SYifei Jiang     struct riscv64_user_regs pr_reg;
3943a96588SYifei Jiang     char pad3[8];
4043a96588SYifei Jiang } QEMU_PACKED;
4143a96588SYifei Jiang 
4243a96588SYifei Jiang QEMU_BUILD_BUG_ON(sizeof(struct riscv64_elf_prstatus) != 376);
4343a96588SYifei Jiang 
4443a96588SYifei Jiang struct riscv64_note {
4543a96588SYifei Jiang     Elf64_Nhdr hdr;
4643a96588SYifei Jiang     char name[8]; /* align_up(sizeof("CORE"), 4) */
4743a96588SYifei Jiang     struct riscv64_elf_prstatus prstatus;
4843a96588SYifei Jiang } QEMU_PACKED;
4943a96588SYifei Jiang 
5043a96588SYifei Jiang #define RISCV64_NOTE_HEADER_SIZE offsetof(struct riscv64_note, prstatus)
5143a96588SYifei Jiang #define RISCV64_PRSTATUS_NOTE_SIZE \
5243a96588SYifei Jiang             (RISCV64_NOTE_HEADER_SIZE + sizeof(struct riscv64_elf_prstatus))
5343a96588SYifei Jiang 
riscv64_note_init(struct riscv64_note * note,DumpState * s,const char * name,Elf64_Word namesz,Elf64_Word type,Elf64_Word descsz)5443a96588SYifei Jiang static void riscv64_note_init(struct riscv64_note *note, DumpState *s,
5543a96588SYifei Jiang                               const char *name, Elf64_Word namesz,
5643a96588SYifei Jiang                               Elf64_Word type, Elf64_Word descsz)
5743a96588SYifei Jiang {
5843a96588SYifei Jiang     memset(note, 0, sizeof(*note));
5943a96588SYifei Jiang 
6043a96588SYifei Jiang     note->hdr.n_namesz = cpu_to_dump32(s, namesz);
6143a96588SYifei Jiang     note->hdr.n_descsz = cpu_to_dump32(s, descsz);
6243a96588SYifei Jiang     note->hdr.n_type = cpu_to_dump32(s, type);
6343a96588SYifei Jiang 
6443a96588SYifei Jiang     memcpy(note->name, name, namesz);
6543a96588SYifei Jiang }
6643a96588SYifei Jiang 
riscv_cpu_write_elf64_note(WriteCoreDumpFunction f,CPUState * cs,int cpuid,DumpState * s)6743a96588SYifei Jiang int riscv_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
681af0006aSJanosch Frank                                int cpuid, DumpState *s)
6943a96588SYifei Jiang {
7043a96588SYifei Jiang     struct riscv64_note note;
7143a96588SYifei Jiang     RISCVCPU *cpu = RISCV_CPU(cs);
7243a96588SYifei Jiang     CPURISCVState *env = &cpu->env;
7343a96588SYifei Jiang     int ret, i = 0;
7443a96588SYifei Jiang     const char name[] = "CORE";
7543a96588SYifei Jiang 
7643a96588SYifei Jiang     riscv64_note_init(&note, s, name, sizeof(name),
7743a96588SYifei Jiang                       NT_PRSTATUS, sizeof(note.prstatus));
7843a96588SYifei Jiang 
7943a96588SYifei Jiang     note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
8043a96588SYifei Jiang 
8143a96588SYifei Jiang     note.prstatus.pr_reg.pc = cpu_to_dump64(s, env->pc);
8243a96588SYifei Jiang 
8343a96588SYifei Jiang     for (i = 0; i < 31; i++) {
8443a96588SYifei Jiang         note.prstatus.pr_reg.regs[i] = cpu_to_dump64(s, env->gpr[i + 1]);
8543a96588SYifei Jiang     }
8643a96588SYifei Jiang 
8743a96588SYifei Jiang     ret = f(&note, RISCV64_PRSTATUS_NOTE_SIZE, s);
8843a96588SYifei Jiang     if (ret < 0) {
8943a96588SYifei Jiang         return -1;
9043a96588SYifei Jiang     }
9143a96588SYifei Jiang 
9243a96588SYifei Jiang     return ret;
9343a96588SYifei Jiang }
9443a96588SYifei Jiang 
9543a96588SYifei Jiang struct riscv32_user_regs {
9643a96588SYifei Jiang     uint32_t pc;
9743a96588SYifei Jiang     uint32_t regs[31];
9843a96588SYifei Jiang } QEMU_PACKED;
9943a96588SYifei Jiang 
10043a96588SYifei Jiang QEMU_BUILD_BUG_ON(sizeof(struct riscv32_user_regs) != 128);
10143a96588SYifei Jiang 
10243a96588SYifei Jiang struct riscv32_elf_prstatus {
10343a96588SYifei Jiang     char pad1[24]; /* 24 == offsetof(struct elf_prstatus, pr_pid) */
10443a96588SYifei Jiang     uint32_t pr_pid;
10543a96588SYifei Jiang     char pad2[44]; /* 44 == offsetof(struct elf_prstatus, pr_reg) -
10643a96588SYifei Jiang                             offsetof(struct elf_prstatus, pr_ppid) */
10743a96588SYifei Jiang     struct riscv32_user_regs pr_reg;
10843a96588SYifei Jiang     char pad3[4];
10943a96588SYifei Jiang } QEMU_PACKED;
11043a96588SYifei Jiang 
11143a96588SYifei Jiang QEMU_BUILD_BUG_ON(sizeof(struct riscv32_elf_prstatus) != 204);
11243a96588SYifei Jiang 
11343a96588SYifei Jiang struct riscv32_note {
11443a96588SYifei Jiang     Elf32_Nhdr hdr;
11543a96588SYifei Jiang     char name[8]; /* align_up(sizeof("CORE"), 4) */
11643a96588SYifei Jiang     struct riscv32_elf_prstatus prstatus;
11743a96588SYifei Jiang } QEMU_PACKED;
11843a96588SYifei Jiang 
11943a96588SYifei Jiang #define RISCV32_NOTE_HEADER_SIZE offsetof(struct riscv32_note, prstatus)
12043a96588SYifei Jiang #define RISCV32_PRSTATUS_NOTE_SIZE \
12143a96588SYifei Jiang             (RISCV32_NOTE_HEADER_SIZE + sizeof(struct riscv32_elf_prstatus))
12243a96588SYifei Jiang 
riscv32_note_init(struct riscv32_note * note,DumpState * s,const char * name,Elf32_Word namesz,Elf32_Word type,Elf32_Word descsz)12343a96588SYifei Jiang static void riscv32_note_init(struct riscv32_note *note, DumpState *s,
12443a96588SYifei Jiang                               const char *name, Elf32_Word namesz,
12543a96588SYifei Jiang                               Elf32_Word type, Elf32_Word descsz)
12643a96588SYifei Jiang {
12743a96588SYifei Jiang     memset(note, 0, sizeof(*note));
12843a96588SYifei Jiang 
12943a96588SYifei Jiang     note->hdr.n_namesz = cpu_to_dump32(s, namesz);
13043a96588SYifei Jiang     note->hdr.n_descsz = cpu_to_dump32(s, descsz);
13143a96588SYifei Jiang     note->hdr.n_type = cpu_to_dump32(s, type);
13243a96588SYifei Jiang 
13343a96588SYifei Jiang     memcpy(note->name, name, namesz);
13443a96588SYifei Jiang }
13543a96588SYifei Jiang 
riscv_cpu_write_elf32_note(WriteCoreDumpFunction f,CPUState * cs,int cpuid,DumpState * s)13643a96588SYifei Jiang int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
1371af0006aSJanosch Frank                                int cpuid, DumpState *s)
13843a96588SYifei Jiang {
13943a96588SYifei Jiang     struct riscv32_note note;
14043a96588SYifei Jiang     RISCVCPU *cpu = RISCV_CPU(cs);
14143a96588SYifei Jiang     CPURISCVState *env = &cpu->env;
14243a96588SYifei Jiang     int ret, i;
14343a96588SYifei Jiang     const char name[] = "CORE";
14443a96588SYifei Jiang 
14543a96588SYifei Jiang     riscv32_note_init(&note, s, name, sizeof(name),
14643a96588SYifei Jiang                       NT_PRSTATUS, sizeof(note.prstatus));
14743a96588SYifei Jiang 
14843a96588SYifei Jiang     note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
14943a96588SYifei Jiang 
15043a96588SYifei Jiang     note.prstatus.pr_reg.pc = cpu_to_dump32(s, env->pc);
15143a96588SYifei Jiang 
15243a96588SYifei Jiang     for (i = 0; i < 31; i++) {
15343a96588SYifei Jiang         note.prstatus.pr_reg.regs[i] = cpu_to_dump32(s, env->gpr[i + 1]);
15443a96588SYifei Jiang     }
15543a96588SYifei Jiang 
15643a96588SYifei Jiang     ret = f(&note, RISCV32_PRSTATUS_NOTE_SIZE, s);
15743a96588SYifei Jiang     if (ret < 0) {
15843a96588SYifei Jiang         return -1;
15943a96588SYifei Jiang     }
16043a96588SYifei Jiang 
16143a96588SYifei Jiang     return ret;
16243a96588SYifei Jiang }
16343a96588SYifei Jiang 
cpu_get_dump_info(ArchDumpInfo * info,const GuestPhysBlockList * guest_phys_blocks)16443a96588SYifei Jiang int cpu_get_dump_info(ArchDumpInfo *info,
16543a96588SYifei Jiang                       const GuestPhysBlockList *guest_phys_blocks)
16643a96588SYifei Jiang {
16743a96588SYifei Jiang     RISCVCPU *cpu;
16843a96588SYifei Jiang     CPURISCVState *env;
16943a96588SYifei Jiang 
17043a96588SYifei Jiang     if (first_cpu == NULL) {
17143a96588SYifei Jiang         return -1;
17243a96588SYifei Jiang     }
17343a96588SYifei Jiang     cpu = RISCV_CPU(first_cpu);
17443a96588SYifei Jiang     env = &cpu->env;
17543a96588SYifei Jiang 
17643a96588SYifei Jiang     info->d_machine = EM_RISCV;
17743a96588SYifei Jiang 
17843a96588SYifei Jiang #if defined(TARGET_RISCV64)
17943a96588SYifei Jiang     info->d_class = ELFCLASS64;
18043a96588SYifei Jiang #else
18143a96588SYifei Jiang     info->d_class = ELFCLASS32;
18243a96588SYifei Jiang #endif
18343a96588SYifei Jiang 
184c45eff30SWeiwei Li     info->d_endian = (env->mstatus & MSTATUS_UBE) != 0 ?
185c45eff30SWeiwei Li                      ELFDATA2MSB : ELFDATA2LSB;
18643a96588SYifei Jiang 
18743a96588SYifei Jiang     return 0;
18843a96588SYifei Jiang }
18943a96588SYifei Jiang 
cpu_get_note_size(int class,int machine,int nr_cpus)19043a96588SYifei Jiang ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
19143a96588SYifei Jiang {
19243a96588SYifei Jiang     size_t note_size;
19343a96588SYifei Jiang 
19443a96588SYifei Jiang     if (class == ELFCLASS64) {
19543a96588SYifei Jiang         note_size = RISCV64_PRSTATUS_NOTE_SIZE;
19643a96588SYifei Jiang     } else {
19743a96588SYifei Jiang         note_size = RISCV32_PRSTATUS_NOTE_SIZE;
19843a96588SYifei Jiang     }
19943a96588SYifei Jiang 
20043a96588SYifei Jiang     return note_size * nr_cpus;
20143a96588SYifei Jiang }
202