Merge tag 'v9.0.0-rc3'
[qemu/ar7.git] / hw / mips / bootloader.c
blob1dd6ef2096807951bc1bec895bbe3cd13b17e3b3
1 /*
2 * Utility for QEMU MIPS to generate it's simple bootloader
4 * Instructions used here are carefully selected to keep compatibility with
5 * MIPS Release 6.
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"
14 #include "cpu.h"
15 #include "hw/mips/bootloader.h"
17 typedef enum bl_reg {
18 BL_REG_ZERO = 0,
19 BL_REG_AT = 1,
20 BL_REG_V0 = 2,
21 BL_REG_V1 = 3,
22 BL_REG_A0 = 4,
23 BL_REG_A1 = 5,
24 BL_REG_A2 = 6,
25 BL_REG_A3 = 7,
26 BL_REG_T0 = 8,
27 BL_REG_T1 = 9,
28 BL_REG_T2 = 10,
29 BL_REG_T3 = 11,
30 BL_REG_T4 = 12,
31 BL_REG_T5 = 13,
32 BL_REG_T6 = 14,
33 BL_REG_T7 = 15,
34 BL_REG_S0 = 16,
35 BL_REG_S1 = 17,
36 BL_REG_S2 = 18,
37 BL_REG_S3 = 19,
38 BL_REG_S4 = 20,
39 BL_REG_S5 = 21,
40 BL_REG_S6 = 22,
41 BL_REG_S7 = 23,
42 BL_REG_T8 = 24,
43 BL_REG_T9 = 25,
44 BL_REG_K0 = 26,
45 BL_REG_K1 = 27,
46 BL_REG_GP = 28,
47 BL_REG_SP = 29,
48 BL_REG_FP = 30,
49 BL_REG_RA = 31,
50 } bl_reg;
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)
59 uint16_t *p = *ptr;
61 stw_p(p, insn >> 16);
62 p++;
63 stw_p(p, insn >> 0);
64 p++;
66 *ptr = p;
69 /* Base types */
70 static void bl_gen_nop(void **ptr)
72 if (bootcpu_supports_isa(ISA_NANOMIPS32)) {
73 st_nm32_p(ptr, 0x8000c000);
74 } else {
75 uint32_t *p = *ptr;
77 stl_p(p, 0);
78 p++;
79 *ptr = p;
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)
87 uint32_t *p = *ptr;
88 uint32_t insn = 0;
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);
97 stl_p(p, insn);
98 p++;
100 *ptr = p;
103 static void bl_gen_i_type(void **ptr, uint8_t opcode,
104 bl_reg rs, bl_reg rt, uint16_t imm)
106 uint32_t *p = *ptr;
107 uint32_t insn = 0;
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);
114 stl_p(p, insn);
115 p++;
117 *ptr = p;
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);
125 } else {
126 g_assert_not_reached(); /* unsupported */
130 static void bl_gen_jalr(void **p, bl_reg rs)
132 if (bootcpu_supports_isa(ISA_NANOMIPS32)) {
133 uint32_t insn = 0;
135 insn = deposit32(insn, 26, 6, 0b010010); /* JALRC */
136 insn = deposit32(insn, 21, 5, BL_REG_RA);
137 insn = deposit32(insn, 16, 5, rs);
139 st_nm32_p(p, insn);
140 } else {
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)
147 uint32_t insn = 0;
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)
167 uint32_t insn = 0;
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)
185 uint32_t insn = 0;
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);
201 } else {
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);
210 } else {
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));
221 } else {
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 */
240 } else {
241 bl_gen_li(p, rt, imm); /* 32bit */
245 /* Helpers */
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)
261 if (set_sp) {
262 bl_gen_load_ulong(p, BL_REG_SP, sp);
264 if (set_a0) {
265 bl_gen_load_ulong(p, BL_REG_A0, a0);
267 if (set_a1) {
268 bl_gen_load_ulong(p, BL_REG_A1, a1);
270 if (set_a2) {
271 bl_gen_load_ulong(p, BL_REG_A2, a2);
273 if (set_a3) {
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);
286 } else {
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);