qemu

Форк
0
/
bootloader.c 
303 строки · 7.3 Кб
1
/*
2
 * Utility for QEMU MIPS to generate it's simple bootloader
3
 *
4
 * Instructions used here are carefully selected to keep compatibility with
5
 * MIPS Release 6.
6
 *
7
 * Copyright (C) 2020 Jiaxun Yang <jiaxun.yang@flygoat.com>
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11

12
#include "qemu/osdep.h"
13
#include "qemu/bitops.h"
14
#include "cpu.h"
15
#include "hw/mips/bootloader.h"
16

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

52
static bool bootcpu_supports_isa(uint64_t isa_mask)
53
{
54
    return cpu_supports_isa(&MIPS_CPU(first_cpu)->env, isa_mask);
55
}
56

57
static void st_nm32_p(void **ptr, uint32_t insn)
58
{
59
    uint16_t *p = *ptr;
60

61
    stw_p(p, insn >> 16);
62
    p++;
63
    stw_p(p, insn >> 0);
64
    p++;
65

66
    *ptr = p;
67
}
68

69
/* Base types */
70
static void bl_gen_nop(void **ptr)
71
{
72
    if (bootcpu_supports_isa(ISA_NANOMIPS32)) {
73
        st_nm32_p(ptr, 0x8000c000);
74
    } else {
75
        uint32_t *p = *ptr;
76

77
        stl_p(p, 0);
78
        p++;
79
        *ptr = p;
80
    }
81
}
82

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)
86
{
87
    uint32_t *p = *ptr;
88
    uint32_t insn = 0;
89

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

97
    stl_p(p, insn);
98
    p++;
99

100
    *ptr = p;
101
}
102

103
static void bl_gen_i_type(void **ptr, uint8_t opcode,
104
                          bl_reg rs, bl_reg rt, uint16_t imm)
105
{
106
    uint32_t *p = *ptr;
107
    uint32_t insn = 0;
108

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

114
    stl_p(p, insn);
115
    p++;
116

117
    *ptr = p;
118
}
119

120
/* Single instructions */
121
static void bl_gen_dsll(void **p, bl_reg rd, bl_reg rt, uint8_t sa)
122
{
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 */
127
    }
128
}
129

130
static void bl_gen_jalr(void **p, bl_reg rs)
131
{
132
    if (bootcpu_supports_isa(ISA_NANOMIPS32)) {
133
        uint32_t insn = 0;
134

135
        insn = deposit32(insn, 26, 6, 0b010010); /* JALRC */
136
        insn = deposit32(insn, 21, 5, BL_REG_RA);
137
        insn = deposit32(insn, 16, 5, rs);
138

139
        st_nm32_p(p, insn);
140
    } else {
141
        bl_gen_r_type(p, 0, rs, 0, BL_REG_RA, 0, 0x09);
142
    }
143
}
144

145
static void bl_gen_lui_nm(void **ptr, bl_reg rt, uint32_t imm20)
146
{
147
    uint32_t insn = 0;
148

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

156
    st_nm32_p(ptr, insn);
157
}
158

159
static void bl_gen_lui(void **p, bl_reg rt, uint16_t imm)
160
{
161
    /* R6: It's a alias of AUI with RS = 0 */
162
    bl_gen_i_type(p, 0x0f, 0, rt, imm);
163
}
164

165
static void bl_gen_ori_nm(void **ptr, bl_reg rt, bl_reg rs, uint16_t imm12)
166
{
167
    uint32_t insn = 0;
168

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

175
    st_nm32_p(ptr, insn);
176
}
177

178
static void bl_gen_ori(void **p, bl_reg rt, bl_reg rs, uint16_t imm)
179
{
180
    bl_gen_i_type(p, 0x0d, rs, rt, imm);
181
}
182

183
static void bl_gen_sw_nm(void **ptr, bl_reg rt, uint8_t rs, uint16_t ofs12)
184
{
185
    uint32_t insn = 0;
186

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

194
    st_nm32_p(ptr, insn);
195
}
196

197
static void bl_gen_sw(void **p, bl_reg rt, uint8_t base, uint16_t offset)
198
{
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);
203
    }
204
}
205

206
static void bl_gen_sd(void **p, bl_reg rt, uint8_t base, uint16_t offset)
207
{
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 */
212
    }
213
}
214

215
/* Pseudo instructions */
216
static void bl_gen_li(void **p, bl_reg rt, uint32_t imm)
217
{
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));
224
    }
225
}
226

227
static void bl_gen_dli(void **p, bl_reg rt, uint64_t imm)
228
{
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));
234
}
235

236
static void bl_gen_load_ulong(void **p, bl_reg rt, target_ulong imm)
237
{
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 */
242
    }
243
}
244

245
/* Helpers */
246
void bl_gen_jump_to(void **p, target_ulong jump_addr)
247
{
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 */
251
}
252

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)
260
{
261
    if (set_sp) {
262
        bl_gen_load_ulong(p, BL_REG_SP, sp);
263
    }
264
    if (set_a0) {
265
        bl_gen_load_ulong(p, BL_REG_A0, a0);
266
    }
267
    if (set_a1) {
268
        bl_gen_load_ulong(p, BL_REG_A1, a1);
269
    }
270
    if (set_a2) {
271
        bl_gen_load_ulong(p, BL_REG_A2, a2);
272
    }
273
    if (set_a3) {
274
        bl_gen_load_ulong(p, BL_REG_A3, a3);
275
    }
276

277
    bl_gen_jump_to(p, kernel_addr);
278
}
279

280
void bl_gen_write_ulong(void **p, target_ulong addr, target_ulong val)
281
{
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);
288
    }
289
}
290

291
void bl_gen_write_u32(void **p, target_ulong addr, uint32_t val)
292
{
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);
296
}
297

298
void bl_gen_write_u64(void **p, target_ulong addr, uint64_t val)
299
{
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);
303
}
304

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.