1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * LoongArch boot helper functions. 4 * 5 * Copyright (c) 2023 Loongson Technology Corporation Limited 6 */ 7 8 #include "qemu/osdep.h" 9 #include "qemu/units.h" 10 #include "target/loongarch/cpu.h" 11 #include "hw/loongarch/virt.h" 12 #include "hw/loader.h" 13 #include "elf.h" 14 #include "qemu/error-report.h" 15 #include "sysemu/reset.h" 16 #include "sysemu/qtest.h" 17 18 static const unsigned int slave_boot_code[] = { 19 /* Configure reset ebase. */ 20 0x0400302c, /* csrwr $t0, LOONGARCH_CSR_EENTRY */ 21 22 /* Disable interrupt. */ 23 0x0380100c, /* ori $t0, $zero,0x4 */ 24 0x04000180, /* csrxchg $zero, $t0, LOONGARCH_CSR_CRMD */ 25 26 /* Clear mailbox. */ 27 0x1400002d, /* lu12i.w $t1, 1(0x1) */ 28 0x038081ad, /* ori $t1, $t1, CORE_BUF_20 */ 29 0x06481da0, /* iocsrwr.d $zero, $t1 */ 30 31 /* Enable IPI interrupt. */ 32 0x1400002c, /* lu12i.w $t0, 1(0x1) */ 33 0x0400118c, /* csrxchg $t0, $t0, LOONGARCH_CSR_ECFG */ 34 0x02fffc0c, /* addi.d $t0, $r0,-1(0xfff) */ 35 0x1400002d, /* lu12i.w $t1, 1(0x1) */ 36 0x038011ad, /* ori $t1, $t1, CORE_EN_OFF */ 37 0x064819ac, /* iocsrwr.w $t0, $t1 */ 38 0x1400002d, /* lu12i.w $t1, 1(0x1) */ 39 0x038081ad, /* ori $t1, $t1, CORE_BUF_20 */ 40 41 /* Wait for wakeup <.L11>: */ 42 0x06488000, /* idle 0x0 */ 43 0x03400000, /* andi $zero, $zero, 0x0 */ 44 0x064809ac, /* iocsrrd.w $t0, $t1 */ 45 0x43fff59f, /* beqz $t0, -12(0x7ffff4) # 48 <.L11> */ 46 47 /* Read and clear IPI interrupt. */ 48 0x1400002d, /* lu12i.w $t1, 1(0x1) */ 49 0x064809ac, /* iocsrrd.w $t0, $t1 */ 50 0x1400002d, /* lu12i.w $t1, 1(0x1) */ 51 0x038031ad, /* ori $t1, $t1, CORE_CLEAR_OFF */ 52 0x064819ac, /* iocsrwr.w $t0, $t1 */ 53 54 /* Disable IPI interrupt. */ 55 0x1400002c, /* lu12i.w $t0, 1(0x1) */ 56 0x04001180, /* csrxchg $zero, $t0, LOONGARCH_CSR_ECFG */ 57 58 /* Read mail buf and jump to specified entry */ 59 0x1400002d, /* lu12i.w $t1, 1(0x1) */ 60 0x038081ad, /* ori $t1, $t1, CORE_BUF_20 */ 61 0x06480dac, /* iocsrrd.d $t0, $t1 */ 62 0x00150181, /* move $ra, $t0 */ 63 0x4c000020, /* jirl $zero, $ra,0 */ 64 }; 65 66 static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) 67 { 68 return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS); 69 } 70 71 static int64_t load_kernel_info(struct loongarch_boot_info *info) 72 { 73 uint64_t kernel_entry, kernel_low, kernel_high, initrd_size; 74 ram_addr_t initrd_offset; 75 ssize_t kernel_size; 76 77 kernel_size = load_elf(info->kernel_filename, NULL, 78 cpu_loongarch_virt_to_phys, NULL, 79 &kernel_entry, &kernel_low, 80 &kernel_high, NULL, 0, 81 EM_LOONGARCH, 1, 0); 82 83 if (kernel_size < 0) { 84 error_report("could not load kernel '%s': %s", 85 info->kernel_filename, 86 load_elf_strerror(kernel_size)); 87 exit(1); 88 } 89 90 if (info->initrd_filename) { 91 initrd_size = get_image_size(info->initrd_filename); 92 if (initrd_size > 0) { 93 initrd_offset = ROUND_UP(kernel_high + 4 * kernel_size, 64 * KiB); 94 95 if (initrd_offset + initrd_size > info->ram_size) { 96 error_report("memory too small for initial ram disk '%s'", 97 info->initrd_filename); 98 exit(1); 99 } 100 101 initrd_size = load_image_targphys(info->initrd_filename, initrd_offset, 102 info->ram_size - initrd_offset); 103 } 104 105 if (initrd_size == (target_ulong)-1) { 106 error_report("could not load initial ram disk '%s'", 107 info->initrd_filename); 108 exit(1); 109 } 110 } else { 111 initrd_size = 0; 112 } 113 114 return kernel_entry; 115 } 116 117 static void reset_load_elf(void *opaque) 118 { 119 LoongArchCPU *cpu = opaque; 120 CPULoongArchState *env = &cpu->env; 121 122 cpu_reset(CPU(cpu)); 123 if (env->load_elf) { 124 cpu_set_pc(CPU(cpu), env->elf_address); 125 } 126 } 127 128 static void fw_cfg_add_kernel_info(struct loongarch_boot_info *info, 129 FWCfgState *fw_cfg) 130 { 131 /* 132 * Expose the kernel, the command line, and the initrd in fw_cfg. 133 * We don't process them here at all, it's all left to the 134 * firmware. 135 */ 136 load_image_to_fw_cfg(fw_cfg, 137 FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA, 138 info->kernel_filename, 139 false); 140 141 if (info->initrd_filename) { 142 load_image_to_fw_cfg(fw_cfg, 143 FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA, 144 info->initrd_filename, false); 145 } 146 147 if (info->kernel_cmdline) { 148 fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 149 strlen(info->kernel_cmdline) + 1); 150 fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, 151 info->kernel_cmdline); 152 } 153 } 154 155 static void loongarch_firmware_boot(LoongArchMachineState *lams, 156 struct loongarch_boot_info *info) 157 { 158 fw_cfg_add_kernel_info(info, lams->fw_cfg); 159 } 160 161 static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info) 162 { 163 int64_t kernel_addr = 0; 164 LoongArchCPU *lacpu; 165 CPUState *cs; 166 167 if (info->kernel_filename) { 168 kernel_addr = load_kernel_info(info); 169 } else { 170 if(!qtest_enabled()) { 171 error_report("Need kernel filename\n"); 172 exit(1); 173 } 174 } 175 176 /* Load slave boot code at pflash0 . */ 177 void *boot_code = g_malloc0(VIRT_FLASH0_SIZE); 178 memcpy(boot_code, &slave_boot_code, sizeof(slave_boot_code)); 179 rom_add_blob_fixed("boot_code", boot_code, VIRT_FLASH0_SIZE, VIRT_FLASH0_BASE); 180 181 CPU_FOREACH(cs) { 182 lacpu = LOONGARCH_CPU(cs); 183 lacpu->env.load_elf = true; 184 if (cs == first_cpu) { 185 lacpu->env.elf_address = kernel_addr; 186 } else { 187 lacpu->env.elf_address = VIRT_FLASH0_BASE; 188 } 189 lacpu->env.boot_info = info; 190 } 191 192 g_free(boot_code); 193 } 194 195 void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info) 196 { 197 LoongArchMachineState *lams = LOONGARCH_MACHINE(ms); 198 int i; 199 200 /* register reset function */ 201 for (i = 0; i < ms->smp.cpus; i++) { 202 qemu_register_reset(reset_load_elf, LOONGARCH_CPU(qemu_get_cpu(i))); 203 } 204 205 info->kernel_filename = ms->kernel_filename; 206 info->kernel_cmdline = ms->kernel_cmdline; 207 info->initrd_filename = ms->initrd_filename; 208 209 if (lams->bios_loaded) { 210 loongarch_firmware_boot(lams, info); 211 } else { 212 loongarch_direct_kernel_boot(info); 213 } 214 } 215