1*32c22cc4SBibo Mao /* 2*32c22cc4SBibo Mao * Support for writing ELF notes for LoongArch architectures 3*32c22cc4SBibo Mao * 4*32c22cc4SBibo Mao * Copyright (c) 2023 Loongarch Technology 5*32c22cc4SBibo Mao * 6*32c22cc4SBibo Mao * This program is free software; you can redistribute it and/or modify it 7*32c22cc4SBibo Mao * under the terms and conditions of the GNU General Public License, 8*32c22cc4SBibo Mao * version 2 or later, as published by the Free Software Foundation. 9*32c22cc4SBibo Mao * 10*32c22cc4SBibo Mao * This program is distributed in the hope it will be useful, but WITHOUT 11*32c22cc4SBibo Mao * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12*32c22cc4SBibo Mao * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13*32c22cc4SBibo Mao * more details. 14*32c22cc4SBibo Mao * 15*32c22cc4SBibo Mao * You should have received a copy of the GNU General Public License along with 16*32c22cc4SBibo Mao * this program. If not, see <http://www.gnu.org/licenses/>. 17*32c22cc4SBibo Mao * 18*32c22cc4SBibo Mao */ 19*32c22cc4SBibo Mao 20*32c22cc4SBibo Mao #include "qemu/osdep.h" 21*32c22cc4SBibo Mao #include "cpu.h" 22*32c22cc4SBibo Mao #include "elf.h" 23*32c22cc4SBibo Mao #include "sysemu/dump.h" 24*32c22cc4SBibo Mao #include "internals.h" 25*32c22cc4SBibo Mao 26*32c22cc4SBibo Mao /* struct user_pt_regs from arch/loongarch/include/uapi/asm/ptrace.h */ 27*32c22cc4SBibo Mao struct loongarch_user_regs { 28*32c22cc4SBibo Mao uint64_t gpr[32]; 29*32c22cc4SBibo Mao uint64_t pad1[1]; 30*32c22cc4SBibo Mao /* Special CSR registers. */ 31*32c22cc4SBibo Mao uint64_t csr_era; 32*32c22cc4SBibo Mao uint64_t csr_badv; 33*32c22cc4SBibo Mao uint64_t pad2[10]; 34*32c22cc4SBibo Mao } QEMU_PACKED; 35*32c22cc4SBibo Mao 36*32c22cc4SBibo Mao QEMU_BUILD_BUG_ON(sizeof(struct loongarch_user_regs) != 360); 37*32c22cc4SBibo Mao 38*32c22cc4SBibo Mao /* struct elf_prstatus from include/uapi/linux/elfcore.h */ 39*32c22cc4SBibo Mao struct loongarch_elf_prstatus { 40*32c22cc4SBibo Mao char pad1[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */ 41*32c22cc4SBibo Mao uint32_t pr_pid; 42*32c22cc4SBibo Mao /* 43*32c22cc4SBibo Mao * 76 == offsetof(struct elf_prstatus, pr_reg) - 44*32c22cc4SBibo Mao * offsetof(struct elf_prstatus, pr_ppid) 45*32c22cc4SBibo Mao */ 46*32c22cc4SBibo Mao char pad2[76]; 47*32c22cc4SBibo Mao struct loongarch_user_regs pr_reg; 48*32c22cc4SBibo Mao uint32_t pr_fpvalid; 49*32c22cc4SBibo Mao char pad3[4]; 50*32c22cc4SBibo Mao } QEMU_PACKED; 51*32c22cc4SBibo Mao 52*32c22cc4SBibo Mao QEMU_BUILD_BUG_ON(sizeof(struct loongarch_elf_prstatus) != 480); 53*32c22cc4SBibo Mao 54*32c22cc4SBibo Mao /* struct user_fp_state from arch/loongarch/include/uapi/asm/ptrace.h */ 55*32c22cc4SBibo Mao struct loongarch_fpu_struct { 56*32c22cc4SBibo Mao uint64_t fpr[32]; 57*32c22cc4SBibo Mao uint64_t fcc; 58*32c22cc4SBibo Mao unsigned int fcsr; 59*32c22cc4SBibo Mao } QEMU_PACKED; 60*32c22cc4SBibo Mao 61*32c22cc4SBibo Mao QEMU_BUILD_BUG_ON(sizeof(struct loongarch_fpu_struct) != 268); 62*32c22cc4SBibo Mao 63*32c22cc4SBibo Mao struct loongarch_note { 64*32c22cc4SBibo Mao Elf64_Nhdr hdr; 65*32c22cc4SBibo Mao char name[8]; /* align_up(sizeof("CORE"), 4) */ 66*32c22cc4SBibo Mao union { 67*32c22cc4SBibo Mao struct loongarch_elf_prstatus prstatus; 68*32c22cc4SBibo Mao struct loongarch_fpu_struct fpu; 69*32c22cc4SBibo Mao }; 70*32c22cc4SBibo Mao } QEMU_PACKED; 71*32c22cc4SBibo Mao 72*32c22cc4SBibo Mao #define LOONGARCH_NOTE_HEADER_SIZE offsetof(struct loongarch_note, prstatus) 73*32c22cc4SBibo Mao #define LOONGARCH_PRSTATUS_NOTE_SIZE \ 74*32c22cc4SBibo Mao (LOONGARCH_NOTE_HEADER_SIZE + sizeof(struct loongarch_elf_prstatus)) 75*32c22cc4SBibo Mao #define LOONGARCH_PRFPREG_NOTE_SIZE \ 76*32c22cc4SBibo Mao (LOONGARCH_NOTE_HEADER_SIZE + sizeof(struct loongarch_fpu_struct)) 77*32c22cc4SBibo Mao 78*32c22cc4SBibo Mao static void loongarch_note_init(struct loongarch_note *note, DumpState *s, 79*32c22cc4SBibo Mao const char *name, Elf64_Word namesz, 80*32c22cc4SBibo Mao Elf64_Word type, Elf64_Word descsz) 81*32c22cc4SBibo Mao { 82*32c22cc4SBibo Mao memset(note, 0, sizeof(*note)); 83*32c22cc4SBibo Mao 84*32c22cc4SBibo Mao note->hdr.n_namesz = cpu_to_dump32(s, namesz); 85*32c22cc4SBibo Mao note->hdr.n_descsz = cpu_to_dump32(s, descsz); 86*32c22cc4SBibo Mao note->hdr.n_type = cpu_to_dump32(s, type); 87*32c22cc4SBibo Mao 88*32c22cc4SBibo Mao memcpy(note->name, name, namesz); 89*32c22cc4SBibo Mao } 90*32c22cc4SBibo Mao 91*32c22cc4SBibo Mao static int loongarch_write_elf64_fprpreg(WriteCoreDumpFunction f, 92*32c22cc4SBibo Mao CPULoongArchState *env, int cpuid, 93*32c22cc4SBibo Mao DumpState *s) 94*32c22cc4SBibo Mao { 95*32c22cc4SBibo Mao struct loongarch_note note; 96*32c22cc4SBibo Mao int ret, i; 97*32c22cc4SBibo Mao 98*32c22cc4SBibo Mao loongarch_note_init(¬e, s, "CORE", 5, NT_PRFPREG, sizeof(note.fpu)); 99*32c22cc4SBibo Mao note.fpu.fcsr = cpu_to_dump64(s, env->fcsr0); 100*32c22cc4SBibo Mao 101*32c22cc4SBibo Mao for (i = 0; i < 8; i++) { 102*32c22cc4SBibo Mao note.fpu.fcc |= env->cf[i] << (8 * i); 103*32c22cc4SBibo Mao } 104*32c22cc4SBibo Mao note.fpu.fcc = cpu_to_dump64(s, note.fpu.fcc); 105*32c22cc4SBibo Mao 106*32c22cc4SBibo Mao for (i = 0; i < 32; ++i) { 107*32c22cc4SBibo Mao note.fpu.fpr[i] = cpu_to_dump64(s, env->fpr[i].vreg.UD[0]); 108*32c22cc4SBibo Mao } 109*32c22cc4SBibo Mao 110*32c22cc4SBibo Mao ret = f(¬e, LOONGARCH_PRFPREG_NOTE_SIZE, s); 111*32c22cc4SBibo Mao if (ret < 0) { 112*32c22cc4SBibo Mao return -1; 113*32c22cc4SBibo Mao } 114*32c22cc4SBibo Mao 115*32c22cc4SBibo Mao return 0; 116*32c22cc4SBibo Mao } 117*32c22cc4SBibo Mao 118*32c22cc4SBibo Mao int loongarch_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, 119*32c22cc4SBibo Mao int cpuid, DumpState *s) 120*32c22cc4SBibo Mao { 121*32c22cc4SBibo Mao struct loongarch_note note; 122*32c22cc4SBibo Mao CPULoongArchState *env = &LOONGARCH_CPU(cs)->env; 123*32c22cc4SBibo Mao int ret, i; 124*32c22cc4SBibo Mao 125*32c22cc4SBibo Mao loongarch_note_init(¬e, s, "CORE", 5, NT_PRSTATUS, 126*32c22cc4SBibo Mao sizeof(note.prstatus)); 127*32c22cc4SBibo Mao note.prstatus.pr_pid = cpu_to_dump32(s, cpuid); 128*32c22cc4SBibo Mao note.prstatus.pr_fpvalid = cpu_to_dump32(s, 1); 129*32c22cc4SBibo Mao 130*32c22cc4SBibo Mao for (i = 0; i < 32; ++i) { 131*32c22cc4SBibo Mao note.prstatus.pr_reg.gpr[i] = cpu_to_dump64(s, env->gpr[i]); 132*32c22cc4SBibo Mao } 133*32c22cc4SBibo Mao note.prstatus.pr_reg.csr_era = cpu_to_dump64(s, env->CSR_ERA); 134*32c22cc4SBibo Mao note.prstatus.pr_reg.csr_badv = cpu_to_dump64(s, env->CSR_BADV); 135*32c22cc4SBibo Mao ret = f(¬e, LOONGARCH_PRSTATUS_NOTE_SIZE, s); 136*32c22cc4SBibo Mao if (ret < 0) { 137*32c22cc4SBibo Mao return -1; 138*32c22cc4SBibo Mao } 139*32c22cc4SBibo Mao 140*32c22cc4SBibo Mao ret = loongarch_write_elf64_fprpreg(f, env, cpuid, s); 141*32c22cc4SBibo Mao if (ret < 0) { 142*32c22cc4SBibo Mao return -1; 143*32c22cc4SBibo Mao } 144*32c22cc4SBibo Mao 145*32c22cc4SBibo Mao return ret; 146*32c22cc4SBibo Mao } 147*32c22cc4SBibo Mao 148*32c22cc4SBibo Mao int cpu_get_dump_info(ArchDumpInfo *info, 149*32c22cc4SBibo Mao const GuestPhysBlockList *guest_phys_blocks) 150*32c22cc4SBibo Mao { 151*32c22cc4SBibo Mao info->d_machine = EM_LOONGARCH; 152*32c22cc4SBibo Mao info->d_endian = ELFDATA2LSB; 153*32c22cc4SBibo Mao info->d_class = ELFCLASS64; 154*32c22cc4SBibo Mao 155*32c22cc4SBibo Mao return 0; 156*32c22cc4SBibo Mao } 157*32c22cc4SBibo Mao 158*32c22cc4SBibo Mao ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) 159*32c22cc4SBibo Mao { 160*32c22cc4SBibo Mao size_t note_size = 0; 161*32c22cc4SBibo Mao 162*32c22cc4SBibo Mao if (class == ELFCLASS64) { 163*32c22cc4SBibo Mao note_size = LOONGARCH_PRSTATUS_NOTE_SIZE + LOONGARCH_PRFPREG_NOTE_SIZE; 164*32c22cc4SBibo Mao } 165*32c22cc4SBibo Mao 166*32c22cc4SBibo Mao return note_size * nr_cpus; 167*32c22cc4SBibo Mao } 168