qemu/hw/mips/bootloader.c
<<
>>
Prefs
   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
  17typedef 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
  52static bool bootcpu_supports_isa(uint64_t isa_mask)
  53{
  54    return cpu_supports_isa(&MIPS_CPU(first_cpu)->env, isa_mask);
  55}
  56
  57/* Base types */
  58static void bl_gen_nop(uint32_t **p)
  59{
  60    stl_p(*p, 0);
  61    *p = *p + 1;
  62}
  63
  64static void bl_gen_r_type(uint32_t **p, uint8_t opcode,
  65                          bl_reg rs, bl_reg rt, bl_reg rd,
  66                          uint8_t shift, uint8_t funct)
  67{
  68    uint32_t insn = 0;
  69
  70    insn = deposit32(insn, 26, 6, opcode);
  71    insn = deposit32(insn, 21, 5, rs);
  72    insn = deposit32(insn, 16, 5, rt);
  73    insn = deposit32(insn, 11, 5, rd);
  74    insn = deposit32(insn, 6, 5, shift);
  75    insn = deposit32(insn, 0, 6, funct);
  76
  77    stl_p(*p, insn);
  78    *p = *p + 1;
  79}
  80
  81static void bl_gen_i_type(uint32_t **p, uint8_t opcode,
  82                          bl_reg rs, bl_reg rt, uint16_t imm)
  83{
  84    uint32_t insn = 0;
  85
  86    insn = deposit32(insn, 26, 6, opcode);
  87    insn = deposit32(insn, 21, 5, rs);
  88    insn = deposit32(insn, 16, 5, rt);
  89    insn = deposit32(insn, 0, 16, imm);
  90
  91    stl_p(*p, insn);
  92    *p = *p + 1;
  93}
  94
  95/* Single instructions */
  96static void bl_gen_dsll(uint32_t **p, bl_reg rd, bl_reg rt, uint8_t sa)
  97{
  98    if (bootcpu_supports_isa(ISA_MIPS3)) {
  99        bl_gen_r_type(p, 0, 0, rt, rd, sa, 0x38);
 100    } else {
 101        g_assert_not_reached(); /* unsupported */
 102    }
 103}
 104
 105static void bl_gen_jalr(uint32_t **p, bl_reg rs)
 106{
 107    bl_gen_r_type(p, 0, rs, 0, BL_REG_RA, 0, 0x09);
 108}
 109
 110static void bl_gen_lui(uint32_t **p, bl_reg rt, uint16_t imm)
 111{
 112    /* R6: It's a alias of AUI with RS = 0 */
 113    bl_gen_i_type(p, 0x0f, 0, rt, imm);
 114}
 115
 116static void bl_gen_ori(uint32_t **p, bl_reg rt, bl_reg rs, uint16_t imm)
 117{
 118    bl_gen_i_type(p, 0x0d, rs, rt, imm);
 119}
 120
 121static void bl_gen_sw(uint32_t **p, bl_reg rt, uint8_t base, uint16_t offset)
 122{
 123    bl_gen_i_type(p, 0x2b, base, rt, offset);
 124}
 125
 126static void bl_gen_sd(uint32_t **p, bl_reg rt, uint8_t base, uint16_t offset)
 127{
 128    if (bootcpu_supports_isa(ISA_MIPS3)) {
 129        bl_gen_i_type(p, 0x3f, base, rt, offset);
 130    } else {
 131        g_assert_not_reached(); /* unsupported */
 132    }
 133}
 134
 135/* Pseudo instructions */
 136static void bl_gen_li(uint32_t **p, bl_reg rt, uint32_t imm)
 137{
 138    bl_gen_lui(p, rt, extract32(imm, 16, 16));
 139    bl_gen_ori(p, rt, rt, extract32(imm, 0, 16));
 140}
 141
 142static void bl_gen_dli(uint32_t **p, bl_reg rt, uint64_t imm)
 143{
 144    bl_gen_li(p, rt, extract64(imm, 32, 32));
 145    bl_gen_dsll(p, rt, rt, 16);
 146    bl_gen_ori(p, rt, rt, extract64(imm, 16, 16));
 147    bl_gen_dsll(p, rt, rt, 16);
 148    bl_gen_ori(p, rt, rt, extract64(imm, 0, 16));
 149}
 150
 151static void bl_gen_load_ulong(uint32_t **p, bl_reg rt, target_ulong imm)
 152{
 153    if (bootcpu_supports_isa(ISA_MIPS3)) {
 154        bl_gen_dli(p, rt, imm); /* 64bit */
 155    } else {
 156        bl_gen_li(p, rt, imm); /* 32bit */
 157    }
 158}
 159
 160/* Helpers */
 161void bl_gen_jump_to(uint32_t **p, target_ulong jump_addr)
 162{
 163    bl_gen_load_ulong(p, BL_REG_T9, jump_addr);
 164    bl_gen_jalr(p, BL_REG_T9);
 165    bl_gen_nop(p); /* delay slot */
 166}
 167
 168void bl_gen_jump_kernel(uint32_t **p, target_ulong sp, target_ulong a0,
 169                        target_ulong a1, target_ulong a2, target_ulong a3,
 170                        target_ulong kernel_addr)
 171{
 172    bl_gen_load_ulong(p, BL_REG_SP, sp);
 173    bl_gen_load_ulong(p, BL_REG_A0, a0);
 174    bl_gen_load_ulong(p, BL_REG_A1, a1);
 175    bl_gen_load_ulong(p, BL_REG_A2, a2);
 176    bl_gen_load_ulong(p, BL_REG_A3, a3);
 177
 178    bl_gen_jump_to(p, kernel_addr);
 179}
 180
 181void bl_gen_write_ulong(uint32_t **p, target_ulong addr, target_ulong val)
 182{
 183    bl_gen_load_ulong(p, BL_REG_K0, val);
 184    bl_gen_load_ulong(p, BL_REG_K1, addr);
 185    bl_gen_sd(p, BL_REG_K0, BL_REG_K1, 0x0);
 186}
 187
 188void bl_gen_write_u32(uint32_t **p, target_ulong addr, uint32_t val)
 189{
 190    bl_gen_li(p, BL_REG_K0, val);
 191    bl_gen_load_ulong(p, BL_REG_K1, addr);
 192    bl_gen_sw(p, BL_REG_K0, BL_REG_K1, 0x0);
 193}
 194
 195void bl_gen_write_u64(uint32_t **p, target_ulong addr, uint64_t val)
 196{
 197    bl_gen_dli(p, BL_REG_K0, val);
 198    bl_gen_load_ulong(p, BL_REG_K1, addr);
 199    bl_gen_sd(p, BL_REG_K0, BL_REG_K1, 0x0);
 200}
 201