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 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 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 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 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 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