132c22cc4SBibo Mao /*
232c22cc4SBibo Mao * Support for writing ELF notes for LoongArch architectures
332c22cc4SBibo Mao *
432c22cc4SBibo Mao * Copyright (c) 2023 Loongarch Technology
532c22cc4SBibo Mao *
632c22cc4SBibo Mao * This program is free software; you can redistribute it and/or modify it
732c22cc4SBibo Mao * under the terms and conditions of the GNU General Public License,
832c22cc4SBibo Mao * version 2 or later, as published by the Free Software Foundation.
932c22cc4SBibo Mao *
1032c22cc4SBibo Mao * This program is distributed in the hope it will be useful, but WITHOUT
1132c22cc4SBibo Mao * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1232c22cc4SBibo Mao * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
1332c22cc4SBibo Mao * more details.
1432c22cc4SBibo Mao *
1532c22cc4SBibo Mao * You should have received a copy of the GNU General Public License along with
1632c22cc4SBibo Mao * this program. If not, see <http://www.gnu.org/licenses/>.
1732c22cc4SBibo Mao *
1832c22cc4SBibo Mao */
1932c22cc4SBibo Mao
2032c22cc4SBibo Mao #include "qemu/osdep.h"
2132c22cc4SBibo Mao #include "cpu.h"
2232c22cc4SBibo Mao #include "elf.h"
2332c22cc4SBibo Mao #include "sysemu/dump.h"
2432c22cc4SBibo Mao #include "internals.h"
2532c22cc4SBibo Mao
2632c22cc4SBibo Mao /* struct user_pt_regs from arch/loongarch/include/uapi/asm/ptrace.h */
2732c22cc4SBibo Mao struct loongarch_user_regs {
2832c22cc4SBibo Mao uint64_t gpr[32];
2932c22cc4SBibo Mao uint64_t pad1[1];
3032c22cc4SBibo Mao /* Special CSR registers. */
3132c22cc4SBibo Mao uint64_t csr_era;
3232c22cc4SBibo Mao uint64_t csr_badv;
3332c22cc4SBibo Mao uint64_t pad2[10];
3432c22cc4SBibo Mao } QEMU_PACKED;
3532c22cc4SBibo Mao
3632c22cc4SBibo Mao QEMU_BUILD_BUG_ON(sizeof(struct loongarch_user_regs) != 360);
3732c22cc4SBibo Mao
3832c22cc4SBibo Mao /* struct elf_prstatus from include/uapi/linux/elfcore.h */
3932c22cc4SBibo Mao struct loongarch_elf_prstatus {
4032c22cc4SBibo Mao char pad1[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */
4132c22cc4SBibo Mao uint32_t pr_pid;
4232c22cc4SBibo Mao /*
4332c22cc4SBibo Mao * 76 == offsetof(struct elf_prstatus, pr_reg) -
4432c22cc4SBibo Mao * offsetof(struct elf_prstatus, pr_ppid)
4532c22cc4SBibo Mao */
4632c22cc4SBibo Mao char pad2[76];
4732c22cc4SBibo Mao struct loongarch_user_regs pr_reg;
4832c22cc4SBibo Mao uint32_t pr_fpvalid;
4932c22cc4SBibo Mao char pad3[4];
5032c22cc4SBibo Mao } QEMU_PACKED;
5132c22cc4SBibo Mao
5232c22cc4SBibo Mao QEMU_BUILD_BUG_ON(sizeof(struct loongarch_elf_prstatus) != 480);
5332c22cc4SBibo Mao
5432c22cc4SBibo Mao /* struct user_fp_state from arch/loongarch/include/uapi/asm/ptrace.h */
5532c22cc4SBibo Mao struct loongarch_fpu_struct {
5632c22cc4SBibo Mao uint64_t fpr[32];
5732c22cc4SBibo Mao uint64_t fcc;
5832c22cc4SBibo Mao unsigned int fcsr;
5932c22cc4SBibo Mao } QEMU_PACKED;
6032c22cc4SBibo Mao
6132c22cc4SBibo Mao QEMU_BUILD_BUG_ON(sizeof(struct loongarch_fpu_struct) != 268);
6232c22cc4SBibo Mao
6332c22cc4SBibo Mao struct loongarch_note {
6432c22cc4SBibo Mao Elf64_Nhdr hdr;
6532c22cc4SBibo Mao char name[8]; /* align_up(sizeof("CORE"), 4) */
6632c22cc4SBibo Mao union {
6732c22cc4SBibo Mao struct loongarch_elf_prstatus prstatus;
6832c22cc4SBibo Mao struct loongarch_fpu_struct fpu;
6932c22cc4SBibo Mao };
7032c22cc4SBibo Mao } QEMU_PACKED;
7132c22cc4SBibo Mao
7232c22cc4SBibo Mao #define LOONGARCH_NOTE_HEADER_SIZE offsetof(struct loongarch_note, prstatus)
7332c22cc4SBibo Mao #define LOONGARCH_PRSTATUS_NOTE_SIZE \
7432c22cc4SBibo Mao (LOONGARCH_NOTE_HEADER_SIZE + sizeof(struct loongarch_elf_prstatus))
7532c22cc4SBibo Mao #define LOONGARCH_PRFPREG_NOTE_SIZE \
7632c22cc4SBibo Mao (LOONGARCH_NOTE_HEADER_SIZE + sizeof(struct loongarch_fpu_struct))
7732c22cc4SBibo Mao
loongarch_note_init(struct loongarch_note * note,DumpState * s,const char * name,Elf64_Word namesz,Elf64_Word type,Elf64_Word descsz)7832c22cc4SBibo Mao static void loongarch_note_init(struct loongarch_note *note, DumpState *s,
7932c22cc4SBibo Mao const char *name, Elf64_Word namesz,
8032c22cc4SBibo Mao Elf64_Word type, Elf64_Word descsz)
8132c22cc4SBibo Mao {
8232c22cc4SBibo Mao memset(note, 0, sizeof(*note));
8332c22cc4SBibo Mao
8432c22cc4SBibo Mao note->hdr.n_namesz = cpu_to_dump32(s, namesz);
8532c22cc4SBibo Mao note->hdr.n_descsz = cpu_to_dump32(s, descsz);
8632c22cc4SBibo Mao note->hdr.n_type = cpu_to_dump32(s, type);
8732c22cc4SBibo Mao
8832c22cc4SBibo Mao memcpy(note->name, name, namesz);
8932c22cc4SBibo Mao }
9032c22cc4SBibo Mao
loongarch_write_elf64_fprpreg(WriteCoreDumpFunction f,CPULoongArchState * env,int cpuid,DumpState * s)9132c22cc4SBibo Mao static int loongarch_write_elf64_fprpreg(WriteCoreDumpFunction f,
9232c22cc4SBibo Mao CPULoongArchState *env, int cpuid,
9332c22cc4SBibo Mao DumpState *s)
9432c22cc4SBibo Mao {
9532c22cc4SBibo Mao struct loongarch_note note;
9632c22cc4SBibo Mao int ret, i;
9732c22cc4SBibo Mao
9832c22cc4SBibo Mao loongarch_note_init(¬e, s, "CORE", 5, NT_PRFPREG, sizeof(note.fpu));
9932c22cc4SBibo Mao note.fpu.fcsr = cpu_to_dump64(s, env->fcsr0);
100*4521167fSBibo Mao note.fpu.fcc = cpu_to_dump64(s, read_fcc(env));
10132c22cc4SBibo Mao
10232c22cc4SBibo Mao for (i = 0; i < 32; ++i) {
10332c22cc4SBibo Mao note.fpu.fpr[i] = cpu_to_dump64(s, env->fpr[i].vreg.UD[0]);
10432c22cc4SBibo Mao }
10532c22cc4SBibo Mao
10632c22cc4SBibo Mao ret = f(¬e, LOONGARCH_PRFPREG_NOTE_SIZE, s);
10732c22cc4SBibo Mao if (ret < 0) {
10832c22cc4SBibo Mao return -1;
10932c22cc4SBibo Mao }
11032c22cc4SBibo Mao
11132c22cc4SBibo Mao return 0;
11232c22cc4SBibo Mao }
11332c22cc4SBibo Mao
loongarch_cpu_write_elf64_note(WriteCoreDumpFunction f,CPUState * cs,int cpuid,DumpState * s)11432c22cc4SBibo Mao int loongarch_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
11532c22cc4SBibo Mao int cpuid, DumpState *s)
11632c22cc4SBibo Mao {
11732c22cc4SBibo Mao struct loongarch_note note;
11832c22cc4SBibo Mao CPULoongArchState *env = &LOONGARCH_CPU(cs)->env;
11932c22cc4SBibo Mao int ret, i;
12032c22cc4SBibo Mao
12132c22cc4SBibo Mao loongarch_note_init(¬e, s, "CORE", 5, NT_PRSTATUS,
12232c22cc4SBibo Mao sizeof(note.prstatus));
12332c22cc4SBibo Mao note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
12432c22cc4SBibo Mao note.prstatus.pr_fpvalid = cpu_to_dump32(s, 1);
12532c22cc4SBibo Mao
12632c22cc4SBibo Mao for (i = 0; i < 32; ++i) {
12732c22cc4SBibo Mao note.prstatus.pr_reg.gpr[i] = cpu_to_dump64(s, env->gpr[i]);
12832c22cc4SBibo Mao }
12932c22cc4SBibo Mao note.prstatus.pr_reg.csr_era = cpu_to_dump64(s, env->CSR_ERA);
13032c22cc4SBibo Mao note.prstatus.pr_reg.csr_badv = cpu_to_dump64(s, env->CSR_BADV);
13132c22cc4SBibo Mao ret = f(¬e, LOONGARCH_PRSTATUS_NOTE_SIZE, s);
13232c22cc4SBibo Mao if (ret < 0) {
13332c22cc4SBibo Mao return -1;
13432c22cc4SBibo Mao }
13532c22cc4SBibo Mao
13632c22cc4SBibo Mao ret = loongarch_write_elf64_fprpreg(f, env, cpuid, s);
13732c22cc4SBibo Mao if (ret < 0) {
13832c22cc4SBibo Mao return -1;
13932c22cc4SBibo Mao }
14032c22cc4SBibo Mao
14132c22cc4SBibo Mao return ret;
14232c22cc4SBibo Mao }
14332c22cc4SBibo Mao
cpu_get_dump_info(ArchDumpInfo * info,const GuestPhysBlockList * guest_phys_blocks)14432c22cc4SBibo Mao int cpu_get_dump_info(ArchDumpInfo *info,
14532c22cc4SBibo Mao const GuestPhysBlockList *guest_phys_blocks)
14632c22cc4SBibo Mao {
14732c22cc4SBibo Mao info->d_machine = EM_LOONGARCH;
14832c22cc4SBibo Mao info->d_endian = ELFDATA2LSB;
14932c22cc4SBibo Mao info->d_class = ELFCLASS64;
15032c22cc4SBibo Mao
15132c22cc4SBibo Mao return 0;
15232c22cc4SBibo Mao }
15332c22cc4SBibo Mao
cpu_get_note_size(int class,int machine,int nr_cpus)15432c22cc4SBibo Mao ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
15532c22cc4SBibo Mao {
15632c22cc4SBibo Mao size_t note_size = 0;
15732c22cc4SBibo Mao
15832c22cc4SBibo Mao if (class == ELFCLASS64) {
15932c22cc4SBibo Mao note_size = LOONGARCH_PRSTATUS_NOTE_SIZE + LOONGARCH_PRFPREG_NOTE_SIZE;
16032c22cc4SBibo Mao }
16132c22cc4SBibo Mao
16232c22cc4SBibo Mao return note_size * nr_cpus;
16332c22cc4SBibo Mao }
164