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(¬e, 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(¬e, 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(¬e, 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(¬e, 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