xref: /openbmc/qemu/linux-user/mips/elfload.c (revision a10631b0cf04ce7daf26648840df3f15bc36724e)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "qemu/osdep.h"
4 #include "qemu.h"
5 #include "loader.h"
6 #include "elf.h"
7 #include "target_elf.h"
8 
9 
10 const char *get_elf_cpu_model(uint32_t eflags)
11 {
12 #ifdef TARGET_MIPS64
13     switch (eflags & EF_MIPS_MACH) {
14     case EF_MIPS_MACH_OCTEON:
15     case EF_MIPS_MACH_OCTEON2:
16     case EF_MIPS_MACH_OCTEON3:
17         return "Octeon68XX";
18     case EF_MIPS_MACH_LS2E:
19         return "Loongson-2E";
20     case EF_MIPS_MACH_LS2F:
21         return "Loongson-2F";
22     case EF_MIPS_MACH_LS3A:
23         return "Loongson-3A1000";
24     default:
25         break;
26     }
27     switch (eflags & EF_MIPS_ARCH) {
28     case EF_MIPS_ARCH_64R6:
29         return "I6400";
30     case EF_MIPS_ARCH_64R2:
31         return "MIPS64R2-generic";
32     default:
33         break;
34     }
35     return "5KEf";
36 #else
37     if ((eflags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6) {
38         return "mips32r6-generic";
39     }
40     if ((eflags & EF_MIPS_ARCH_ASE) == EF_MIPS_ARCH_ASE_MICROMIPS) {
41         return "M14Kc";
42     }
43     if ((eflags & EF_MIPS_ARCH_ASE) == EF_MIPS_ARCH_ASE_M16) {
44         return "74Kf";
45     }
46     if (eflags & EF_MIPS_NAN2008) {
47         return "P5600";
48     }
49     return "24Kf";
50 #endif
51 }
52 
53 /* See arch/mips/include/uapi/asm/hwcap.h.  */
54 enum {
55     HWCAP_MIPS_R6           = (1 << 0),
56     HWCAP_MIPS_MSA          = (1 << 1),
57     HWCAP_MIPS_CRC32        = (1 << 2),
58     HWCAP_MIPS_MIPS16       = (1 << 3),
59     HWCAP_MIPS_MDMX         = (1 << 4),
60     HWCAP_MIPS_MIPS3D       = (1 << 5),
61     HWCAP_MIPS_SMARTMIPS    = (1 << 6),
62     HWCAP_MIPS_DSP          = (1 << 7),
63     HWCAP_MIPS_DSP2         = (1 << 8),
64     HWCAP_MIPS_DSP3         = (1 << 9),
65     HWCAP_MIPS_MIPS16E2     = (1 << 10),
66     HWCAP_LOONGSON_MMI      = (1 << 11),
67     HWCAP_LOONGSON_EXT      = (1 << 12),
68     HWCAP_LOONGSON_EXT2     = (1 << 13),
69     HWCAP_LOONGSON_CPUCFG   = (1 << 14),
70 };
71 
72 #define GET_FEATURE_INSN(_flag, _hwcap) \
73     do { if (cpu->env.insn_flags & (_flag)) { hwcaps |= _hwcap; } } while (0)
74 
75 #define GET_FEATURE_REG_SET(_reg, _mask, _hwcap) \
76     do { if (cpu->env._reg & (_mask)) { hwcaps |= _hwcap; } } while (0)
77 
78 #define GET_FEATURE_REG_EQU(_reg, _start, _length, _val, _hwcap) \
79     do { \
80         if (extract32(cpu->env._reg, (_start), (_length)) == (_val)) { \
81             hwcaps |= _hwcap; \
82         } \
83     } while (0)
84 
85 abi_ulong get_elf_hwcap(CPUState *cs)
86 {
87     MIPSCPU *cpu = MIPS_CPU(cs);
88     abi_ulong hwcaps = 0;
89 
90     GET_FEATURE_REG_EQU(CP0_Config0, CP0C0_AR, CP0C0_AR_LENGTH,
91                         2, HWCAP_MIPS_R6);
92     GET_FEATURE_REG_SET(CP0_Config3, 1 << CP0C3_MSAP, HWCAP_MIPS_MSA);
93     GET_FEATURE_INSN(ASE_LMMI, HWCAP_LOONGSON_MMI);
94     GET_FEATURE_INSN(ASE_LEXT, HWCAP_LOONGSON_EXT);
95 
96     return hwcaps;
97 }
98 
99 #undef GET_FEATURE_REG_EQU
100 #undef GET_FEATURE_REG_SET
101 #undef GET_FEATURE_INSN
102 
103 #define MATCH_PLATFORM_INSN(_flags, _base_platform)      \
104     do { if ((cpu->env.insn_flags & (_flags)) == _flags) \
105     { return _base_platform; } } while (0)
106 
107 const char *get_elf_base_platform(CPUState *cs)
108 {
109     MIPSCPU *cpu = MIPS_CPU(cs);
110 
111     /* 64 bit ISAs goes first */
112     MATCH_PLATFORM_INSN(CPU_MIPS64R6, "mips64r6");
113     MATCH_PLATFORM_INSN(CPU_MIPS64R5, "mips64r5");
114     MATCH_PLATFORM_INSN(CPU_MIPS64R2, "mips64r2");
115     MATCH_PLATFORM_INSN(CPU_MIPS64R1, "mips64");
116     MATCH_PLATFORM_INSN(CPU_MIPS5, "mips5");
117     MATCH_PLATFORM_INSN(CPU_MIPS4, "mips4");
118     MATCH_PLATFORM_INSN(CPU_MIPS3, "mips3");
119 
120     /* 32 bit ISAs */
121     MATCH_PLATFORM_INSN(CPU_MIPS32R6, "mips32r6");
122     MATCH_PLATFORM_INSN(CPU_MIPS32R5, "mips32r5");
123     MATCH_PLATFORM_INSN(CPU_MIPS32R2, "mips32r2");
124     MATCH_PLATFORM_INSN(CPU_MIPS32R1, "mips32");
125     MATCH_PLATFORM_INSN(CPU_MIPS2, "mips2");
126 
127     /* Fallback */
128     return "mips";
129 }
130 
131 #undef MATCH_PLATFORM_INSN
132 
133 /* See linux kernel: arch/mips/kernel/process.c:elf_dump_regs.  */
134 void elf_core_copy_regs(target_elf_gregset_t *r, const CPUMIPSState *env)
135 {
136     for (int i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) {
137         r->pt.regs[i] = tswapl(env->active_tc.gpr[i]);
138     }
139 
140     r->pt.regs[26] = 0;
141     r->pt.regs[27] = 0;
142     r->pt.lo = tswapl(env->active_tc.LO[0]);
143     r->pt.hi = tswapl(env->active_tc.HI[0]);
144     r->pt.cp0_epc = tswapl(env->active_tc.PC);
145     r->pt.cp0_badvaddr = tswapl(env->CP0_BadVAddr);
146     r->pt.cp0_status = tswapl(env->CP0_Status);
147     r->pt.cp0_cause = tswapl(env->CP0_Cause);
148 }
149