xref: /qemu/hw/mips/bootloader.c (revision 24ade8c5decd092bde5e863bc542db45d924ae12)
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 */
583ebbf861SJiaxun Yang static void bl_gen_nop(uint32_t **p)
593ebbf861SJiaxun Yang {
603ebbf861SJiaxun Yang     stl_p(*p, 0);
613ebbf861SJiaxun Yang     *p = *p + 1;
623ebbf861SJiaxun Yang }
633ebbf861SJiaxun Yang 
643ebbf861SJiaxun Yang static void bl_gen_r_type(uint32_t **p, uint8_t opcode,
653ebbf861SJiaxun Yang                           bl_reg rs, bl_reg rt, bl_reg rd,
663ebbf861SJiaxun Yang                           uint8_t shift, uint8_t funct)
673ebbf861SJiaxun Yang {
683ebbf861SJiaxun Yang     uint32_t insn = 0;
693ebbf861SJiaxun Yang 
703ebbf861SJiaxun Yang     insn = deposit32(insn, 26, 6, opcode);
713ebbf861SJiaxun Yang     insn = deposit32(insn, 21, 5, rs);
723ebbf861SJiaxun Yang     insn = deposit32(insn, 16, 5, rt);
733ebbf861SJiaxun Yang     insn = deposit32(insn, 11, 5, rd);
743ebbf861SJiaxun Yang     insn = deposit32(insn, 6, 5, shift);
753ebbf861SJiaxun Yang     insn = deposit32(insn, 0, 6, funct);
763ebbf861SJiaxun Yang 
773ebbf861SJiaxun Yang     stl_p(*p, insn);
783ebbf861SJiaxun Yang     *p = *p + 1;
793ebbf861SJiaxun Yang }
803ebbf861SJiaxun Yang 
813ebbf861SJiaxun Yang static void bl_gen_i_type(uint32_t **p, uint8_t opcode,
823ebbf861SJiaxun Yang                           bl_reg rs, bl_reg rt, uint16_t imm)
833ebbf861SJiaxun Yang {
843ebbf861SJiaxun Yang     uint32_t insn = 0;
853ebbf861SJiaxun Yang 
863ebbf861SJiaxun Yang     insn = deposit32(insn, 26, 6, opcode);
873ebbf861SJiaxun Yang     insn = deposit32(insn, 21, 5, rs);
883ebbf861SJiaxun Yang     insn = deposit32(insn, 16, 5, rt);
893ebbf861SJiaxun Yang     insn = deposit32(insn, 0, 16, imm);
903ebbf861SJiaxun Yang 
913ebbf861SJiaxun Yang     stl_p(*p, insn);
923ebbf861SJiaxun Yang     *p = *p + 1;
933ebbf861SJiaxun Yang }
943ebbf861SJiaxun Yang 
953ebbf861SJiaxun Yang /* Single instructions */
963ebbf861SJiaxun Yang static void bl_gen_dsll(uint32_t **p, bl_reg rd, bl_reg rt, uint8_t sa)
973ebbf861SJiaxun Yang {
983ebbf861SJiaxun Yang     if (bootcpu_supports_isa(ISA_MIPS3)) {
993ebbf861SJiaxun Yang         bl_gen_r_type(p, 0, 0, rt, rd, sa, 0x38);
1003ebbf861SJiaxun Yang     } else {
1013ebbf861SJiaxun Yang         g_assert_not_reached(); /* unsupported */
1023ebbf861SJiaxun Yang     }
1033ebbf861SJiaxun Yang }
1043ebbf861SJiaxun Yang 
1053ebbf861SJiaxun Yang static void bl_gen_jalr(uint32_t **p, bl_reg rs)
1063ebbf861SJiaxun Yang {
1073ebbf861SJiaxun Yang     bl_gen_r_type(p, 0, rs, 0, BL_REG_RA, 0, 0x09);
1083ebbf861SJiaxun Yang }
1093ebbf861SJiaxun Yang 
1103ebbf861SJiaxun Yang static void bl_gen_lui(uint32_t **p, bl_reg rt, uint16_t imm)
1113ebbf861SJiaxun Yang {
1123ebbf861SJiaxun Yang     /* R6: It's a alias of AUI with RS = 0 */
1133ebbf861SJiaxun Yang     bl_gen_i_type(p, 0x0f, 0, rt, imm);
1143ebbf861SJiaxun Yang }
1153ebbf861SJiaxun Yang 
1163ebbf861SJiaxun Yang static void bl_gen_ori(uint32_t **p, bl_reg rt, bl_reg rs, uint16_t imm)
1173ebbf861SJiaxun Yang {
1183ebbf861SJiaxun Yang     bl_gen_i_type(p, 0x0d, rs, rt, imm);
1193ebbf861SJiaxun Yang }
1203ebbf861SJiaxun Yang 
1213ebbf861SJiaxun Yang static void bl_gen_sw(uint32_t **p, bl_reg rt, uint8_t base, uint16_t offset)
1223ebbf861SJiaxun Yang {
1233ebbf861SJiaxun Yang     bl_gen_i_type(p, 0x2b, base, rt, offset);
1243ebbf861SJiaxun Yang }
1253ebbf861SJiaxun Yang 
1263ebbf861SJiaxun Yang static void bl_gen_sd(uint32_t **p, bl_reg rt, uint8_t base, uint16_t offset)
1273ebbf861SJiaxun Yang {
1283ebbf861SJiaxun Yang     if (bootcpu_supports_isa(ISA_MIPS3)) {
1293ebbf861SJiaxun Yang         bl_gen_i_type(p, 0x3f, base, rt, offset);
1303ebbf861SJiaxun Yang     } else {
1313ebbf861SJiaxun Yang         g_assert_not_reached(); /* unsupported */
1323ebbf861SJiaxun Yang     }
1333ebbf861SJiaxun Yang }
1343ebbf861SJiaxun Yang 
1353ebbf861SJiaxun Yang /* Pseudo instructions */
1363ebbf861SJiaxun Yang static void bl_gen_li(uint32_t **p, bl_reg rt, uint32_t imm)
1373ebbf861SJiaxun Yang {
1383ebbf861SJiaxun Yang     bl_gen_lui(p, rt, extract32(imm, 16, 16));
1393ebbf861SJiaxun Yang     bl_gen_ori(p, rt, rt, extract32(imm, 0, 16));
1403ebbf861SJiaxun Yang }
1413ebbf861SJiaxun Yang 
1423ebbf861SJiaxun Yang static void bl_gen_dli(uint32_t **p, bl_reg rt, uint64_t imm)
1433ebbf861SJiaxun Yang {
1443ebbf861SJiaxun Yang     bl_gen_li(p, rt, extract64(imm, 32, 32));
1453ebbf861SJiaxun Yang     bl_gen_dsll(p, rt, rt, 16);
1463ebbf861SJiaxun Yang     bl_gen_ori(p, rt, rt, extract64(imm, 16, 16));
1473ebbf861SJiaxun Yang     bl_gen_dsll(p, rt, rt, 16);
1483ebbf861SJiaxun Yang     bl_gen_ori(p, rt, rt, extract64(imm, 0, 16));
1493ebbf861SJiaxun Yang }
1503ebbf861SJiaxun Yang 
1513ebbf861SJiaxun Yang static void bl_gen_load_ulong(uint32_t **p, bl_reg rt, target_ulong imm)
1523ebbf861SJiaxun Yang {
1533ebbf861SJiaxun Yang     if (bootcpu_supports_isa(ISA_MIPS3)) {
1543ebbf861SJiaxun Yang         bl_gen_dli(p, rt, imm); /* 64bit */
1553ebbf861SJiaxun Yang     } else {
1563ebbf861SJiaxun Yang         bl_gen_li(p, rt, imm); /* 32bit */
1573ebbf861SJiaxun Yang     }
1583ebbf861SJiaxun Yang }
1593ebbf861SJiaxun Yang 
1603ebbf861SJiaxun Yang /* Helpers */
1613ebbf861SJiaxun Yang void bl_gen_jump_to(uint32_t **p, target_ulong jump_addr)
1623ebbf861SJiaxun Yang {
1633ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_T9, jump_addr);
1643ebbf861SJiaxun Yang     bl_gen_jalr(p, BL_REG_T9);
1653ebbf861SJiaxun Yang     bl_gen_nop(p); /* delay slot */
1663ebbf861SJiaxun Yang }
1673ebbf861SJiaxun Yang 
1683ebbf861SJiaxun Yang void bl_gen_jump_kernel(uint32_t **p, target_ulong sp, target_ulong a0,
1693ebbf861SJiaxun Yang                         target_ulong a1, target_ulong a2, target_ulong a3,
1703ebbf861SJiaxun Yang                         target_ulong kernel_addr)
1713ebbf861SJiaxun Yang {
1723ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_SP, sp);
1733ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_A0, a0);
1743ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_A1, a1);
1753ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_A2, a2);
1763ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_A3, a3);
1773ebbf861SJiaxun Yang 
1783ebbf861SJiaxun Yang     bl_gen_jump_to(p, kernel_addr);
1793ebbf861SJiaxun Yang }
1803ebbf861SJiaxun Yang 
1813ebbf861SJiaxun Yang void bl_gen_write_ulong(uint32_t **p, target_ulong addr, target_ulong val)
1823ebbf861SJiaxun Yang {
1833ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_K0, val);
1843ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_K1, addr);
185*24ade8c5SJiaxun Yang     if (bootcpu_supports_isa(ISA_MIPS3)) {
1863ebbf861SJiaxun Yang         bl_gen_sd(p, BL_REG_K0, BL_REG_K1, 0x0);
187*24ade8c5SJiaxun Yang     } else {
188*24ade8c5SJiaxun Yang         bl_gen_sw(p, BL_REG_K0, BL_REG_K1, 0x0);
189*24ade8c5SJiaxun Yang     }
1903ebbf861SJiaxun Yang }
1913ebbf861SJiaxun Yang 
1923ebbf861SJiaxun Yang void bl_gen_write_u32(uint32_t **p, target_ulong addr, uint32_t val)
1933ebbf861SJiaxun Yang {
1943ebbf861SJiaxun Yang     bl_gen_li(p, BL_REG_K0, val);
1953ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_K1, addr);
1963ebbf861SJiaxun Yang     bl_gen_sw(p, BL_REG_K0, BL_REG_K1, 0x0);
1973ebbf861SJiaxun Yang }
1983ebbf861SJiaxun Yang 
1993ebbf861SJiaxun Yang void bl_gen_write_u64(uint32_t **p, target_ulong addr, uint64_t val)
2003ebbf861SJiaxun Yang {
2013ebbf861SJiaxun Yang     bl_gen_dli(p, BL_REG_K0, val);
2023ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_K1, addr);
2033ebbf861SJiaxun Yang     bl_gen_sd(p, BL_REG_K0, BL_REG_K1, 0x0);
2043ebbf861SJiaxun Yang }
205