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