xref: /qemu/hw/mips/bootloader.c (revision 3ebbf86128f5607831ba5a3dec8bac02271a9390)
1*3ebbf861SJiaxun Yang /*
2*3ebbf861SJiaxun Yang  * Utility for QEMU MIPS to generate it's simple bootloader
3*3ebbf861SJiaxun Yang  *
4*3ebbf861SJiaxun Yang  * Instructions used here are carefully selected to keep compatibility with
5*3ebbf861SJiaxun Yang  * MIPS Release 6.
6*3ebbf861SJiaxun Yang  *
7*3ebbf861SJiaxun Yang  * Copyright (C) 2020 Jiaxun Yang <jiaxun.yang@flygoat.com>
8*3ebbf861SJiaxun Yang  *
9*3ebbf861SJiaxun Yang  * SPDX-License-Identifier: GPL-2.0-or-later
10*3ebbf861SJiaxun Yang  */
11*3ebbf861SJiaxun Yang 
12*3ebbf861SJiaxun Yang #include "qemu/osdep.h"
13*3ebbf861SJiaxun Yang #include "qemu/bitops.h"
14*3ebbf861SJiaxun Yang #include "cpu.h"
15*3ebbf861SJiaxun Yang #include "hw/mips/bootloader.h"
16*3ebbf861SJiaxun Yang 
17*3ebbf861SJiaxun Yang typedef enum bl_reg {
18*3ebbf861SJiaxun Yang     BL_REG_ZERO = 0,
19*3ebbf861SJiaxun Yang     BL_REG_AT = 1,
20*3ebbf861SJiaxun Yang     BL_REG_V0 = 2,
21*3ebbf861SJiaxun Yang     BL_REG_V1 = 3,
22*3ebbf861SJiaxun Yang     BL_REG_A0 = 4,
23*3ebbf861SJiaxun Yang     BL_REG_A1 = 5,
24*3ebbf861SJiaxun Yang     BL_REG_A2 = 6,
25*3ebbf861SJiaxun Yang     BL_REG_A3 = 7,
26*3ebbf861SJiaxun Yang     BL_REG_T0 = 8,
27*3ebbf861SJiaxun Yang     BL_REG_T1 = 9,
28*3ebbf861SJiaxun Yang     BL_REG_T2 = 10,
29*3ebbf861SJiaxun Yang     BL_REG_T3 = 11,
30*3ebbf861SJiaxun Yang     BL_REG_T4 = 12,
31*3ebbf861SJiaxun Yang     BL_REG_T5 = 13,
32*3ebbf861SJiaxun Yang     BL_REG_T6 = 14,
33*3ebbf861SJiaxun Yang     BL_REG_T7 = 15,
34*3ebbf861SJiaxun Yang     BL_REG_S0 = 16,
35*3ebbf861SJiaxun Yang     BL_REG_S1 = 17,
36*3ebbf861SJiaxun Yang     BL_REG_S2 = 18,
37*3ebbf861SJiaxun Yang     BL_REG_S3 = 19,
38*3ebbf861SJiaxun Yang     BL_REG_S4 = 20,
39*3ebbf861SJiaxun Yang     BL_REG_S5 = 21,
40*3ebbf861SJiaxun Yang     BL_REG_S6 = 22,
41*3ebbf861SJiaxun Yang     BL_REG_S7 = 23,
42*3ebbf861SJiaxun Yang     BL_REG_T8 = 24,
43*3ebbf861SJiaxun Yang     BL_REG_T9 = 25,
44*3ebbf861SJiaxun Yang     BL_REG_K0 = 26,
45*3ebbf861SJiaxun Yang     BL_REG_K1 = 27,
46*3ebbf861SJiaxun Yang     BL_REG_GP = 28,
47*3ebbf861SJiaxun Yang     BL_REG_SP = 29,
48*3ebbf861SJiaxun Yang     BL_REG_FP = 30,
49*3ebbf861SJiaxun Yang     BL_REG_RA = 31,
50*3ebbf861SJiaxun Yang } bl_reg;
51*3ebbf861SJiaxun Yang 
52*3ebbf861SJiaxun Yang static bool bootcpu_supports_isa(uint64_t isa_mask)
53*3ebbf861SJiaxun Yang {
54*3ebbf861SJiaxun Yang     return cpu_supports_isa(&MIPS_CPU(first_cpu)->env, isa_mask);
55*3ebbf861SJiaxun Yang }
56*3ebbf861SJiaxun Yang 
57*3ebbf861SJiaxun Yang /* Base types */
58*3ebbf861SJiaxun Yang static void bl_gen_nop(uint32_t **p)
59*3ebbf861SJiaxun Yang {
60*3ebbf861SJiaxun Yang     stl_p(*p, 0);
61*3ebbf861SJiaxun Yang     *p = *p + 1;
62*3ebbf861SJiaxun Yang }
63*3ebbf861SJiaxun Yang 
64*3ebbf861SJiaxun Yang static void bl_gen_r_type(uint32_t **p, uint8_t opcode,
65*3ebbf861SJiaxun Yang                           bl_reg rs, bl_reg rt, bl_reg rd,
66*3ebbf861SJiaxun Yang                           uint8_t shift, uint8_t funct)
67*3ebbf861SJiaxun Yang {
68*3ebbf861SJiaxun Yang     uint32_t insn = 0;
69*3ebbf861SJiaxun Yang 
70*3ebbf861SJiaxun Yang     insn = deposit32(insn, 26, 6, opcode);
71*3ebbf861SJiaxun Yang     insn = deposit32(insn, 21, 5, rs);
72*3ebbf861SJiaxun Yang     insn = deposit32(insn, 16, 5, rt);
73*3ebbf861SJiaxun Yang     insn = deposit32(insn, 11, 5, rd);
74*3ebbf861SJiaxun Yang     insn = deposit32(insn, 6, 5, shift);
75*3ebbf861SJiaxun Yang     insn = deposit32(insn, 0, 6, funct);
76*3ebbf861SJiaxun Yang 
77*3ebbf861SJiaxun Yang     stl_p(*p, insn);
78*3ebbf861SJiaxun Yang     *p = *p + 1;
79*3ebbf861SJiaxun Yang }
80*3ebbf861SJiaxun Yang 
81*3ebbf861SJiaxun Yang static void bl_gen_i_type(uint32_t **p, uint8_t opcode,
82*3ebbf861SJiaxun Yang                           bl_reg rs, bl_reg rt, uint16_t imm)
83*3ebbf861SJiaxun Yang {
84*3ebbf861SJiaxun Yang     uint32_t insn = 0;
85*3ebbf861SJiaxun Yang 
86*3ebbf861SJiaxun Yang     insn = deposit32(insn, 26, 6, opcode);
87*3ebbf861SJiaxun Yang     insn = deposit32(insn, 21, 5, rs);
88*3ebbf861SJiaxun Yang     insn = deposit32(insn, 16, 5, rt);
89*3ebbf861SJiaxun Yang     insn = deposit32(insn, 0, 16, imm);
90*3ebbf861SJiaxun Yang 
91*3ebbf861SJiaxun Yang     stl_p(*p, insn);
92*3ebbf861SJiaxun Yang     *p = *p + 1;
93*3ebbf861SJiaxun Yang }
94*3ebbf861SJiaxun Yang 
95*3ebbf861SJiaxun Yang /* Single instructions */
96*3ebbf861SJiaxun Yang static void bl_gen_dsll(uint32_t **p, bl_reg rd, bl_reg rt, uint8_t sa)
97*3ebbf861SJiaxun Yang {
98*3ebbf861SJiaxun Yang     if (bootcpu_supports_isa(ISA_MIPS3)) {
99*3ebbf861SJiaxun Yang         bl_gen_r_type(p, 0, 0, rt, rd, sa, 0x38);
100*3ebbf861SJiaxun Yang     } else {
101*3ebbf861SJiaxun Yang         g_assert_not_reached(); /* unsupported */
102*3ebbf861SJiaxun Yang     }
103*3ebbf861SJiaxun Yang }
104*3ebbf861SJiaxun Yang 
105*3ebbf861SJiaxun Yang static void bl_gen_jalr(uint32_t **p, bl_reg rs)
106*3ebbf861SJiaxun Yang {
107*3ebbf861SJiaxun Yang     bl_gen_r_type(p, 0, rs, 0, BL_REG_RA, 0, 0x09);
108*3ebbf861SJiaxun Yang }
109*3ebbf861SJiaxun Yang 
110*3ebbf861SJiaxun Yang static void bl_gen_lui(uint32_t **p, bl_reg rt, uint16_t imm)
111*3ebbf861SJiaxun Yang {
112*3ebbf861SJiaxun Yang     /* R6: It's a alias of AUI with RS = 0 */
113*3ebbf861SJiaxun Yang     bl_gen_i_type(p, 0x0f, 0, rt, imm);
114*3ebbf861SJiaxun Yang }
115*3ebbf861SJiaxun Yang 
116*3ebbf861SJiaxun Yang static void bl_gen_ori(uint32_t **p, bl_reg rt, bl_reg rs, uint16_t imm)
117*3ebbf861SJiaxun Yang {
118*3ebbf861SJiaxun Yang     bl_gen_i_type(p, 0x0d, rs, rt, imm);
119*3ebbf861SJiaxun Yang }
120*3ebbf861SJiaxun Yang 
121*3ebbf861SJiaxun Yang static void bl_gen_sw(uint32_t **p, bl_reg rt, uint8_t base, uint16_t offset)
122*3ebbf861SJiaxun Yang {
123*3ebbf861SJiaxun Yang     bl_gen_i_type(p, 0x2b, base, rt, offset);
124*3ebbf861SJiaxun Yang }
125*3ebbf861SJiaxun Yang 
126*3ebbf861SJiaxun Yang static void bl_gen_sd(uint32_t **p, bl_reg rt, uint8_t base, uint16_t offset)
127*3ebbf861SJiaxun Yang {
128*3ebbf861SJiaxun Yang     if (bootcpu_supports_isa(ISA_MIPS3)) {
129*3ebbf861SJiaxun Yang         bl_gen_i_type(p, 0x3f, base, rt, offset);
130*3ebbf861SJiaxun Yang     } else {
131*3ebbf861SJiaxun Yang         g_assert_not_reached(); /* unsupported */
132*3ebbf861SJiaxun Yang     }
133*3ebbf861SJiaxun Yang }
134*3ebbf861SJiaxun Yang 
135*3ebbf861SJiaxun Yang /* Pseudo instructions */
136*3ebbf861SJiaxun Yang static void bl_gen_li(uint32_t **p, bl_reg rt, uint32_t imm)
137*3ebbf861SJiaxun Yang {
138*3ebbf861SJiaxun Yang     bl_gen_lui(p, rt, extract32(imm, 16, 16));
139*3ebbf861SJiaxun Yang     bl_gen_ori(p, rt, rt, extract32(imm, 0, 16));
140*3ebbf861SJiaxun Yang }
141*3ebbf861SJiaxun Yang 
142*3ebbf861SJiaxun Yang static void bl_gen_dli(uint32_t **p, bl_reg rt, uint64_t imm)
143*3ebbf861SJiaxun Yang {
144*3ebbf861SJiaxun Yang     bl_gen_li(p, rt, extract64(imm, 32, 32));
145*3ebbf861SJiaxun Yang     bl_gen_dsll(p, rt, rt, 16);
146*3ebbf861SJiaxun Yang     bl_gen_ori(p, rt, rt, extract64(imm, 16, 16));
147*3ebbf861SJiaxun Yang     bl_gen_dsll(p, rt, rt, 16);
148*3ebbf861SJiaxun Yang     bl_gen_ori(p, rt, rt, extract64(imm, 0, 16));
149*3ebbf861SJiaxun Yang }
150*3ebbf861SJiaxun Yang 
151*3ebbf861SJiaxun Yang static void bl_gen_load_ulong(uint32_t **p, bl_reg rt, target_ulong imm)
152*3ebbf861SJiaxun Yang {
153*3ebbf861SJiaxun Yang     if (bootcpu_supports_isa(ISA_MIPS3)) {
154*3ebbf861SJiaxun Yang         bl_gen_dli(p, rt, imm); /* 64bit */
155*3ebbf861SJiaxun Yang     } else {
156*3ebbf861SJiaxun Yang         bl_gen_li(p, rt, imm); /* 32bit */
157*3ebbf861SJiaxun Yang     }
158*3ebbf861SJiaxun Yang }
159*3ebbf861SJiaxun Yang 
160*3ebbf861SJiaxun Yang /* Helpers */
161*3ebbf861SJiaxun Yang void bl_gen_jump_to(uint32_t **p, target_ulong jump_addr)
162*3ebbf861SJiaxun Yang {
163*3ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_T9, jump_addr);
164*3ebbf861SJiaxun Yang     bl_gen_jalr(p, BL_REG_T9);
165*3ebbf861SJiaxun Yang     bl_gen_nop(p); /* delay slot */
166*3ebbf861SJiaxun Yang }
167*3ebbf861SJiaxun Yang 
168*3ebbf861SJiaxun Yang void bl_gen_jump_kernel(uint32_t **p, target_ulong sp, target_ulong a0,
169*3ebbf861SJiaxun Yang                         target_ulong a1, target_ulong a2, target_ulong a3,
170*3ebbf861SJiaxun Yang                         target_ulong kernel_addr)
171*3ebbf861SJiaxun Yang {
172*3ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_SP, sp);
173*3ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_A0, a0);
174*3ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_A1, a1);
175*3ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_A2, a2);
176*3ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_A3, a3);
177*3ebbf861SJiaxun Yang 
178*3ebbf861SJiaxun Yang     bl_gen_jump_to(p, kernel_addr);
179*3ebbf861SJiaxun Yang }
180*3ebbf861SJiaxun Yang 
181*3ebbf861SJiaxun Yang void bl_gen_write_ulong(uint32_t **p, target_ulong addr, target_ulong val)
182*3ebbf861SJiaxun Yang {
183*3ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_K0, val);
184*3ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_K1, addr);
185*3ebbf861SJiaxun Yang     bl_gen_sd(p, BL_REG_K0, BL_REG_K1, 0x0);
186*3ebbf861SJiaxun Yang }
187*3ebbf861SJiaxun Yang 
188*3ebbf861SJiaxun Yang void bl_gen_write_u32(uint32_t **p, target_ulong addr, uint32_t val)
189*3ebbf861SJiaxun Yang {
190*3ebbf861SJiaxun Yang     bl_gen_li(p, BL_REG_K0, val);
191*3ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_K1, addr);
192*3ebbf861SJiaxun Yang     bl_gen_sw(p, BL_REG_K0, BL_REG_K1, 0x0);
193*3ebbf861SJiaxun Yang }
194*3ebbf861SJiaxun Yang 
195*3ebbf861SJiaxun Yang void bl_gen_write_u64(uint32_t **p, target_ulong addr, uint64_t val)
196*3ebbf861SJiaxun Yang {
197*3ebbf861SJiaxun Yang     bl_gen_dli(p, BL_REG_K0, val);
198*3ebbf861SJiaxun Yang     bl_gen_load_ulong(p, BL_REG_K1, addr);
199*3ebbf861SJiaxun Yang     bl_gen_sd(p, BL_REG_K0, BL_REG_K1, 0x0);
200*3ebbf861SJiaxun Yang }
201