2 * Utility for QEMU MIPS to generate it's simple bootloader
4 * Instructions used here are carefully selected to keep compatibility with
7 * Copyright (C) 2020 Jiaxun Yang <jiaxun.yang@flygoat.com>
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include "qemu/osdep.h"
13 #include "qemu/bitops.h"
15 #include "hw/mips/bootloader.h"
52 static bool bootcpu_supports_isa(uint64_t isa_mask
)
54 return cpu_supports_isa(&MIPS_CPU(first_cpu
)->env
, isa_mask
);
57 static void st_nm32_p(void **ptr
, uint32_t insn
)
70 static void bl_gen_nop(void **ptr
)
72 if (bootcpu_supports_isa(ISA_NANOMIPS32
)) {
73 st_nm32_p(ptr
, 0x8000c000);
83 static void bl_gen_r_type(void **ptr
, uint8_t opcode
,
84 bl_reg rs
, bl_reg rt
, bl_reg rd
,
85 uint8_t shift
, uint8_t funct
)
90 insn
= deposit32(insn
, 26, 6, opcode
);
91 insn
= deposit32(insn
, 21, 5, rs
);
92 insn
= deposit32(insn
, 16, 5, rt
);
93 insn
= deposit32(insn
, 11, 5, rd
);
94 insn
= deposit32(insn
, 6, 5, shift
);
95 insn
= deposit32(insn
, 0, 6, funct
);
103 static void bl_gen_i_type(void **ptr
, uint8_t opcode
,
104 bl_reg rs
, bl_reg rt
, uint16_t imm
)
109 insn
= deposit32(insn
, 26, 6, opcode
);
110 insn
= deposit32(insn
, 21, 5, rs
);
111 insn
= deposit32(insn
, 16, 5, rt
);
112 insn
= deposit32(insn
, 0, 16, imm
);
120 /* Single instructions */
121 static void bl_gen_dsll(void **p
, bl_reg rd
, bl_reg rt
, uint8_t sa
)
123 if (bootcpu_supports_isa(ISA_MIPS3
)) {
124 bl_gen_r_type(p
, 0, 0, rt
, rd
, sa
, 0x38);
126 g_assert_not_reached(); /* unsupported */
130 static void bl_gen_jalr(void **p
, bl_reg rs
)
132 if (bootcpu_supports_isa(ISA_NANOMIPS32
)) {
135 insn
= deposit32(insn
, 26, 6, 0b010010); /* JALRC */
136 insn
= deposit32(insn
, 21, 5, BL_REG_RA
);
137 insn
= deposit32(insn
, 16, 5, rs
);
141 bl_gen_r_type(p
, 0, rs
, 0, BL_REG_RA
, 0, 0x09);
145 static void bl_gen_lui_nm(void **ptr
, bl_reg rt
, uint32_t imm20
)
149 assert(extract32(imm20
, 0, 20) == imm20
);
150 insn
= deposit32(insn
, 26, 6, 0b111000);
151 insn
= deposit32(insn
, 21, 5, rt
);
152 insn
= deposit32(insn
, 12, 9, extract32(imm20
, 0, 9));
153 insn
= deposit32(insn
, 2, 10, extract32(imm20
, 9, 10));
154 insn
= deposit32(insn
, 0, 1, sextract32(imm20
, 19, 1));
156 st_nm32_p(ptr
, insn
);
159 static void bl_gen_lui(void **p
, bl_reg rt
, uint16_t imm
)
161 /* R6: It's a alias of AUI with RS = 0 */
162 bl_gen_i_type(p
, 0x0f, 0, rt
, imm
);
165 static void bl_gen_ori_nm(void **ptr
, bl_reg rt
, bl_reg rs
, uint16_t imm12
)
169 assert(extract32(imm12
, 0, 12) == imm12
);
170 insn
= deposit32(insn
, 26, 6, 0b100000);
171 insn
= deposit32(insn
, 21, 5, rt
);
172 insn
= deposit32(insn
, 16, 5, rs
);
173 insn
= deposit32(insn
, 0, 12, imm12
);
175 st_nm32_p(ptr
, insn
);
178 static void bl_gen_ori(void **p
, bl_reg rt
, bl_reg rs
, uint16_t imm
)
180 bl_gen_i_type(p
, 0x0d, rs
, rt
, imm
);
183 static void bl_gen_sw_nm(void **ptr
, bl_reg rt
, uint8_t rs
, uint16_t ofs12
)
187 assert(extract32(ofs12
, 0, 12) == ofs12
);
188 insn
= deposit32(insn
, 26, 6, 0b100001);
189 insn
= deposit32(insn
, 21, 5, rt
);
190 insn
= deposit32(insn
, 16, 5, rs
);
191 insn
= deposit32(insn
, 12, 4, 0b1001);
192 insn
= deposit32(insn
, 0, 12, ofs12
);
194 st_nm32_p(ptr
, insn
);
197 static void bl_gen_sw(void **p
, bl_reg rt
, uint8_t base
, uint16_t offset
)
199 if (bootcpu_supports_isa(ISA_NANOMIPS32
)) {
200 bl_gen_sw_nm(p
, rt
, base
, offset
);
202 bl_gen_i_type(p
, 0x2b, base
, rt
, offset
);
206 static void bl_gen_sd(void **p
, bl_reg rt
, uint8_t base
, uint16_t offset
)
208 if (bootcpu_supports_isa(ISA_MIPS3
)) {
209 bl_gen_i_type(p
, 0x3f, base
, rt
, offset
);
211 g_assert_not_reached(); /* unsupported */
215 /* Pseudo instructions */
216 static void bl_gen_li(void **p
, bl_reg rt
, uint32_t imm
)
218 if (bootcpu_supports_isa(ISA_NANOMIPS32
)) {
219 bl_gen_lui_nm(p
, rt
, extract32(imm
, 12, 20));
220 bl_gen_ori_nm(p
, rt
, rt
, extract32(imm
, 0, 12));
222 bl_gen_lui(p
, rt
, extract32(imm
, 16, 16));
223 bl_gen_ori(p
, rt
, rt
, extract32(imm
, 0, 16));
227 static void bl_gen_dli(void **p
, bl_reg rt
, uint64_t imm
)
229 bl_gen_li(p
, rt
, extract64(imm
, 32, 32));
230 bl_gen_dsll(p
, rt
, rt
, 16);
231 bl_gen_ori(p
, rt
, rt
, extract64(imm
, 16, 16));
232 bl_gen_dsll(p
, rt
, rt
, 16);
233 bl_gen_ori(p
, rt
, rt
, extract64(imm
, 0, 16));
236 static void bl_gen_load_ulong(void **p
, bl_reg rt
, target_ulong imm
)
238 if (bootcpu_supports_isa(ISA_MIPS3
)) {
239 bl_gen_dli(p
, rt
, imm
); /* 64bit */
241 bl_gen_li(p
, rt
, imm
); /* 32bit */
246 void bl_gen_jump_to(void **p
, target_ulong jump_addr
)
248 bl_gen_load_ulong(p
, BL_REG_T9
, jump_addr
);
249 bl_gen_jalr(p
, BL_REG_T9
);
250 bl_gen_nop(p
); /* delay slot */
253 void bl_gen_jump_kernel(void **p
,
254 bool set_sp
, target_ulong sp
,
255 bool set_a0
, target_ulong a0
,
256 bool set_a1
, target_ulong a1
,
257 bool set_a2
, target_ulong a2
,
258 bool set_a3
, target_ulong a3
,
259 target_ulong kernel_addr
)
262 bl_gen_load_ulong(p
, BL_REG_SP
, sp
);
265 bl_gen_load_ulong(p
, BL_REG_A0
, a0
);
268 bl_gen_load_ulong(p
, BL_REG_A1
, a1
);
271 bl_gen_load_ulong(p
, BL_REG_A2
, a2
);
274 bl_gen_load_ulong(p
, BL_REG_A3
, a3
);
277 bl_gen_jump_to(p
, kernel_addr
);
280 void bl_gen_write_ulong(void **p
, target_ulong addr
, target_ulong val
)
282 bl_gen_load_ulong(p
, BL_REG_K0
, val
);
283 bl_gen_load_ulong(p
, BL_REG_K1
, addr
);
284 if (bootcpu_supports_isa(ISA_MIPS3
)) {
285 bl_gen_sd(p
, BL_REG_K0
, BL_REG_K1
, 0x0);
287 bl_gen_sw(p
, BL_REG_K0
, BL_REG_K1
, 0x0);
291 void bl_gen_write_u32(void **p
, target_ulong addr
, uint32_t val
)
293 bl_gen_li(p
, BL_REG_K0
, val
);
294 bl_gen_load_ulong(p
, BL_REG_K1
, addr
);
295 bl_gen_sw(p
, BL_REG_K0
, BL_REG_K1
, 0x0);
298 void bl_gen_write_u64(void **p
, target_ulong addr
, uint64_t val
)
300 bl_gen_dli(p
, BL_REG_K0
, val
);
301 bl_gen_load_ulong(p
, BL_REG_K1
, addr
);
302 bl_gen_sd(p
, BL_REG_K0
, BL_REG_K1
, 0x0);