xref: /qemu/hw/mips/bootloader.c (revision cd5066f8618bc6c80ec9088923c58f4a42ab0e7a)
13ebbf861SJiaxun Yang /*
23ebbf861SJiaxun Yang  * Utility for QEMU MIPS to generate it's simple bootloader
33ebbf861SJiaxun Yang  *
43ebbf861SJiaxun Yang  * Instructions used here are carefully selected to keep compatibility with
53ebbf861SJiaxun Yang  * MIPS Release 6.
63ebbf861SJiaxun Yang  *
73ebbf861SJiaxun Yang  * Copyright (C) 2020 Jiaxun Yang <jiaxun.yang@flygoat.com>
83ebbf861SJiaxun Yang  *
93ebbf861SJiaxun Yang  * SPDX-License-Identifier: GPL-2.0-or-later
103ebbf861SJiaxun Yang  */
113ebbf861SJiaxun Yang 
123ebbf861SJiaxun Yang #include "qemu/osdep.h"
133ebbf861SJiaxun Yang #include "qemu/bitops.h"
143ebbf861SJiaxun Yang #include "cpu.h"
153ebbf861SJiaxun Yang #include "hw/mips/bootloader.h"
163ebbf861SJiaxun Yang 
173ebbf861SJiaxun Yang typedef enum bl_reg {
183ebbf861SJiaxun Yang     BL_REG_ZERO = 0,
193ebbf861SJiaxun Yang     BL_REG_AT = 1,
203ebbf861SJiaxun Yang     BL_REG_V0 = 2,
213ebbf861SJiaxun Yang     BL_REG_V1 = 3,
223ebbf861SJiaxun Yang     BL_REG_A0 = 4,
233ebbf861SJiaxun Yang     BL_REG_A1 = 5,
243ebbf861SJiaxun Yang     BL_REG_A2 = 6,
253ebbf861SJiaxun Yang     BL_REG_A3 = 7,
263ebbf861SJiaxun Yang     BL_REG_T0 = 8,
273ebbf861SJiaxun Yang     BL_REG_T1 = 9,
283ebbf861SJiaxun Yang     BL_REG_T2 = 10,
293ebbf861SJiaxun Yang     BL_REG_T3 = 11,
303ebbf861SJiaxun Yang     BL_REG_T4 = 12,
313ebbf861SJiaxun Yang     BL_REG_T5 = 13,
323ebbf861SJiaxun Yang     BL_REG_T6 = 14,
333ebbf861SJiaxun Yang     BL_REG_T7 = 15,
343ebbf861SJiaxun Yang     BL_REG_S0 = 16,
353ebbf861SJiaxun Yang     BL_REG_S1 = 17,
363ebbf861SJiaxun Yang     BL_REG_S2 = 18,
373ebbf861SJiaxun Yang     BL_REG_S3 = 19,
383ebbf861SJiaxun Yang     BL_REG_S4 = 20,
393ebbf861SJiaxun Yang     BL_REG_S5 = 21,
403ebbf861SJiaxun Yang     BL_REG_S6 = 22,
413ebbf861SJiaxun Yang     BL_REG_S7 = 23,
423ebbf861SJiaxun Yang     BL_REG_T8 = 24,
433ebbf861SJiaxun Yang     BL_REG_T9 = 25,
443ebbf861SJiaxun Yang     BL_REG_K0 = 26,
453ebbf861SJiaxun Yang     BL_REG_K1 = 27,
463ebbf861SJiaxun Yang     BL_REG_GP = 28,
473ebbf861SJiaxun Yang     BL_REG_SP = 29,
483ebbf861SJiaxun Yang     BL_REG_FP = 30,
493ebbf861SJiaxun Yang     BL_REG_RA = 31,
503ebbf861SJiaxun Yang } bl_reg;
513ebbf861SJiaxun Yang 
523ebbf861SJiaxun Yang static bool bootcpu_supports_isa(uint64_t isa_mask)
533ebbf861SJiaxun Yang {
543ebbf861SJiaxun Yang     return cpu_supports_isa(&MIPS_CPU(first_cpu)->env, isa_mask);
553ebbf861SJiaxun Yang }
563ebbf861SJiaxun Yang 
573ebbf861SJiaxun Yang /* Base types */
58*cd5066f8SPhilippe Mathieu-Daudé static void bl_gen_nop(void **ptr)
593ebbf861SJiaxun Yang {
60*cd5066f8SPhilippe Mathieu-Daudé     uint32_t *p = *ptr;
61*cd5066f8SPhilippe Mathieu-Daudé 
62*cd5066f8SPhilippe Mathieu-Daudé     stl_p(p, 0);
63*cd5066f8SPhilippe Mathieu-Daudé     p++;
64*cd5066f8SPhilippe Mathieu-Daudé     *ptr = p;
653ebbf861SJiaxun Yang }
663ebbf861SJiaxun Yang 
67*cd5066f8SPhilippe Mathieu-Daudé static void bl_gen_r_type(void **ptr, uint8_t opcode,
683ebbf861SJiaxun Yang                           bl_reg rs, bl_reg rt, bl_reg rd,
693ebbf861SJiaxun Yang                           uint8_t shift, uint8_t funct)
703ebbf861SJiaxun Yang {
71*cd5066f8SPhilippe Mathieu-Daudé     uint32_t *p = *ptr;
723ebbf861SJiaxun Yang     uint32_t insn = 0;
733ebbf861SJiaxun Yang 
743ebbf861SJiaxun Yang     insn = deposit32(insn, 26, 6, opcode);
753ebbf861SJiaxun Yang     insn = deposit32(insn, 21, 5, rs);
763ebbf861SJiaxun Yang     insn = deposit32(insn, 16, 5, rt);
773ebbf861SJiaxun Yang     insn = deposit32(insn, 11, 5, rd);
783ebbf861SJiaxun Yang     insn = deposit32(insn, 6, 5, shift);
793ebbf861SJiaxun Yang     insn = deposit32(insn, 0, 6, funct);
803ebbf861SJiaxun Yang 
81*cd5066f8SPhilippe Mathieu-Daudé     stl_p(p, insn);
82*cd5066f8SPhilippe Mathieu-Daudé     p++;
83*cd5066f8SPhilippe Mathieu-Daudé 
84*cd5066f8SPhilippe Mathieu-Daudé     *ptr = p;
853ebbf861SJiaxun Yang }
863ebbf861SJiaxun Yang 
87*cd5066f8SPhilippe Mathieu-Daudé static void bl_gen_i_type(void **ptr, uint8_t opcode,
883ebbf861SJiaxun Yang                           bl_reg rs, bl_reg rt, uint16_t imm)
893ebbf861SJiaxun Yang {
90*cd5066f8SPhilippe Mathieu-Daudé     uint32_t *p = *ptr;
913ebbf861SJiaxun Yang     uint32_t insn = 0;
923ebbf861SJiaxun Yang 
933ebbf861SJiaxun Yang     insn = deposit32(insn, 26, 6, opcode);
943ebbf861SJiaxun Yang     insn = deposit32(insn, 21, 5, rs);
953ebbf861SJiaxun Yang     insn = deposit32(insn, 16, 5, rt);
963ebbf861SJiaxun Yang     insn = deposit32(insn, 0, 16, imm);
973ebbf861SJiaxun Yang 
98*cd5066f8SPhilippe Mathieu-Daudé     stl_p(p, insn);
99*cd5066f8SPhilippe Mathieu-Daudé     p++;
100*cd5066f8SPhilippe Mathieu-Daudé 
101*cd5066f8SPhilippe Mathieu-Daudé     *ptr = p;
1023ebbf861SJiaxun Yang }
1033ebbf861SJiaxun Yang 
1043ebbf861SJiaxun Yang /* Single instructions */
105*cd5066f8SPhilippe Mathieu-Daudé static void bl_gen_dsll(void **p, bl_reg rd, bl_reg rt, uint8_t sa)
1063ebbf861SJiaxun Yang {
1073ebbf861SJiaxun Yang     if (bootcpu_supports_isa(ISA_MIPS3)) {
1083ebbf861SJiaxun Yang         bl_gen_r_type(p, 0, 0, rt, rd, sa, 0x38);
1093ebbf861SJiaxun Yang     } else {
1103ebbf861SJiaxun Yang         g_assert_not_reached(); /* unsupported */
1113ebbf861SJiaxun Yang     }
1123ebbf861SJiaxun Yang }
1133ebbf861SJiaxun Yang 
114*cd5066f8SPhilippe Mathieu-Daudé static void bl_gen_jalr(void **p, bl_reg rs)
1153ebbf861SJiaxun Yang {
1163ebbf861SJiaxun Yang     bl_gen_r_type(p, 0, rs, 0, BL_REG_RA, 0, 0x09);
1173ebbf861SJiaxun Yang }
1183ebbf861SJiaxun Yang 
119*cd5066f8SPhilippe Mathieu-Daudé static void bl_gen_lui(void **p, bl_reg rt, uint16_t imm)
1203ebbf861SJiaxun Yang {
1213ebbf861SJiaxun Yang     /* R6: It's a alias of AUI with RS = 0 */
1223ebbf861SJiaxun Yang     bl_gen_i_type(p, 0x0f, 0, rt, imm);
1233ebbf861SJiaxun Yang }
1243ebbf861SJiaxun Yang 
125*cd5066f8SPhilippe Mathieu-Daudé static void bl_gen_ori(void **p, bl_reg rt, bl_reg rs, uint16_t imm)
1263ebbf861SJiaxun Yang {
1273ebbf861SJiaxun Yang     bl_gen_i_type(p, 0x0d, rs, rt, imm);
1283ebbf861SJiaxun Yang }
1293ebbf861SJiaxun Yang 
130*cd5066f8SPhilippe Mathieu-Daudé static void bl_gen_sw(void **p, bl_reg rt, uint8_t base, uint16_t offset)
1313ebbf861SJiaxun Yang {
1323ebbf861SJiaxun Yang     bl_gen_i_type(p, 0x2b, base, rt, offset);
1333ebbf861SJiaxun Yang }
1343ebbf861SJiaxun Yang 
135*cd5066f8SPhilippe Mathieu-Daudé static void bl_gen_sd(void **p, bl_reg rt, uint8_t base, uint16_t offset)
1363ebbf861SJiaxun Yang {
1373ebbf861SJiaxun Yang     if (bootcpu_supports_isa(ISA_MIPS3)) {
1383ebbf861SJiaxun Yang         bl_gen_i_type(p, 0x3f, base, rt, offset);
1393ebbf861SJiaxun Yang     } else {
1403ebbf861SJiaxun Yang         g_assert_not_reached(); /* unsupported */
1413ebbf861SJiaxun Yang     }
1423ebbf861SJiaxun Yang }
1433ebbf861SJiaxun Yang 
1443ebbf861SJiaxun Yang /* Pseudo instructions */
145*cd5066f8SPhilippe Mathieu-Daudé static void bl_gen_li(void **p, bl_reg rt, uint32_t imm)
1463ebbf861SJiaxun Yang {
1473ebbf861SJiaxun Yang     bl_gen_lui(p, rt, extract32(imm, 16, 16));
1483ebbf861SJiaxun Yang     bl_gen_ori(p, rt, rt, extract32(imm, 0, 16));
1493ebbf861SJiaxun Yang }
1503ebbf861SJiaxun Yang 
151*cd5066f8SPhilippe Mathieu-Daudé static void bl_gen_dli(void **p, bl_reg rt, uint64_t imm)
1523ebbf861SJiaxun Yang {
1533ebbf861SJiaxun Yang     bl_gen_li(p, rt, extract64(imm, 32, 32));
1543ebbf861SJiaxun Yang     bl_gen_dsll(p, rt, rt, 16);
1553ebbf861SJiaxun Yang     bl_gen_ori(p, rt, rt, extract64(imm, 16, 16));
1563ebbf861SJiaxun Yang     bl_gen_dsll(p, rt, rt, 16);
1573ebbf861SJiaxun Yang     bl_gen_ori(p, rt, rt, extract64(imm, 0, 16));
1583ebbf861SJiaxun Yang }
1593ebbf861SJiaxun Yang 
160*cd5066f8SPhilippe Mathieu-Daudé static void bl_gen_load_ulong(void **p, bl_reg rt, target_ulong imm)
1613ebbf861SJiaxun Yang {
1623ebbf861SJiaxun Yang     if (bootcpu_supports_isa(ISA_MIPS3)) {
1633ebbf861SJiaxun Yang         bl_gen_dli(p, rt, imm); /* 64bit */
1643ebbf861SJiaxun Yang     } else {
1653ebbf861SJiaxun Yang         bl_gen_li(p, rt, imm); /* 32bit */
1663ebbf861SJiaxun Yang     }
1673ebbf861SJiaxun Yang }
1683ebbf861SJiaxun Yang 
1693ebbf861SJiaxun Yang /* Helpers */
170*cd5066f8SPhilippe Mathieu-Daudé void bl_gen_jump_to(void **p, target_ulong jump_addr)
1713ebbf861SJiaxun Yang {
1723ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_T9, jump_addr);
1733ebbf861SJiaxun Yang     bl_gen_jalr(p, BL_REG_T9);
1743ebbf861SJiaxun Yang     bl_gen_nop(p); /* delay slot */
1753ebbf861SJiaxun Yang }
1763ebbf861SJiaxun Yang 
177*cd5066f8SPhilippe Mathieu-Daudé void bl_gen_jump_kernel(void **p,
17836d7487bSPhilippe Mathieu-Daudé                         bool set_sp, target_ulong sp,
17936d7487bSPhilippe Mathieu-Daudé                         bool set_a0, target_ulong a0,
18036d7487bSPhilippe Mathieu-Daudé                         bool set_a1, target_ulong a1,
18136d7487bSPhilippe Mathieu-Daudé                         bool set_a2, target_ulong a2,
18236d7487bSPhilippe Mathieu-Daudé                         bool set_a3, target_ulong a3,
1833ebbf861SJiaxun Yang                         target_ulong kernel_addr)
1843ebbf861SJiaxun Yang {
18536d7487bSPhilippe Mathieu-Daudé     if (set_sp) {
1863ebbf861SJiaxun Yang         bl_gen_load_ulong(p, BL_REG_SP, sp);
18736d7487bSPhilippe Mathieu-Daudé     }
18836d7487bSPhilippe Mathieu-Daudé     if (set_a0) {
1893ebbf861SJiaxun Yang         bl_gen_load_ulong(p, BL_REG_A0, a0);
19036d7487bSPhilippe Mathieu-Daudé     }
19136d7487bSPhilippe Mathieu-Daudé     if (set_a1) {
1923ebbf861SJiaxun Yang         bl_gen_load_ulong(p, BL_REG_A1, a1);
19336d7487bSPhilippe Mathieu-Daudé     }
19436d7487bSPhilippe Mathieu-Daudé     if (set_a2) {
1953ebbf861SJiaxun Yang         bl_gen_load_ulong(p, BL_REG_A2, a2);
19636d7487bSPhilippe Mathieu-Daudé     }
19736d7487bSPhilippe Mathieu-Daudé     if (set_a3) {
1983ebbf861SJiaxun Yang         bl_gen_load_ulong(p, BL_REG_A3, a3);
19936d7487bSPhilippe Mathieu-Daudé     }
2003ebbf861SJiaxun Yang 
2013ebbf861SJiaxun Yang     bl_gen_jump_to(p, kernel_addr);
2023ebbf861SJiaxun Yang }
2033ebbf861SJiaxun Yang 
204*cd5066f8SPhilippe Mathieu-Daudé void bl_gen_write_ulong(void **p, target_ulong addr, target_ulong val)
2053ebbf861SJiaxun Yang {
2063ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_K0, val);
2073ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_K1, addr);
20824ade8c5SJiaxun Yang     if (bootcpu_supports_isa(ISA_MIPS3)) {
2093ebbf861SJiaxun Yang         bl_gen_sd(p, BL_REG_K0, BL_REG_K1, 0x0);
21024ade8c5SJiaxun Yang     } else {
21124ade8c5SJiaxun Yang         bl_gen_sw(p, BL_REG_K0, BL_REG_K1, 0x0);
21224ade8c5SJiaxun Yang     }
2133ebbf861SJiaxun Yang }
2143ebbf861SJiaxun Yang 
215*cd5066f8SPhilippe Mathieu-Daudé void bl_gen_write_u32(void **p, target_ulong addr, uint32_t val)
2163ebbf861SJiaxun Yang {
2173ebbf861SJiaxun Yang     bl_gen_li(p, BL_REG_K0, val);
2183ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_K1, addr);
2193ebbf861SJiaxun Yang     bl_gen_sw(p, BL_REG_K0, BL_REG_K1, 0x0);
2203ebbf861SJiaxun Yang }
2213ebbf861SJiaxun Yang 
222*cd5066f8SPhilippe Mathieu-Daudé void bl_gen_write_u64(void **p, target_ulong addr, uint64_t val)
2233ebbf861SJiaxun Yang {
2243ebbf861SJiaxun Yang     bl_gen_dli(p, BL_REG_K0, val);
2253ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_K1, addr);
2263ebbf861SJiaxun Yang     bl_gen_sd(p, BL_REG_K0, BL_REG_K1, 0x0);
2273ebbf861SJiaxun Yang }
228