| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | |
| 17 | |
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 | |
| 25 | |
| 26 | |
| 27 | #include "qemu-option.h" |
| 28 | #include "qemu-config.h" |
| 29 | #include "qemu-common.h" |
| 30 | #include "device_tree.h" |
| 31 | #include "loader.h" |
| 32 | #include "elf.h" |
| 33 | |
| 34 | #include "microblaze_boot.h" |
| 35 | |
| 36 | static struct |
| 37 | { |
| 38 | void (*machine_cpu_reset)(MicroBlazeCPU *); |
| 39 | uint32_t bootstrap_pc; |
| 40 | uint32_t cmdline; |
| 41 | uint32_t fdt; |
| 42 | } boot_info; |
| 43 | |
| 44 | static void main_cpu_reset(void *opaque) |
| 45 | { |
| 46 | MicroBlazeCPU *cpu = opaque; |
| 47 | CPUMBState *env = &cpu->env; |
| 48 | |
| 49 | cpu_reset(CPU(cpu)((CPUState *)object_dynamic_cast_assert(((Object *)((cpu))), ( "cpu")))); |
| 50 | env->regs[5] = boot_info.cmdline; |
| 51 | env->regs[7] = boot_info.fdt; |
| 52 | env->sregs[SR_PC0] = boot_info.bootstrap_pc; |
| 53 | if (boot_info.machine_cpu_reset) { |
| 54 | boot_info.machine_cpu_reset(cpu); |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | static int microblaze_load_dtb(target_phys_addr_t addr, |
| 59 | uint32_t ramsize, |
| 60 | const char *kernel_cmdline, |
| 61 | const char *dtb_filename) |
| 62 | { |
| 63 | int fdt_size; |
| 1 | Variable 'fdt_size' declared without an initial value |
|
| 64 | #ifdef CONFIG_FDT |
| 65 | void *fdt = NULL((void*)0); |
| 66 | int r; |
| 67 | |
| 68 | if (dtb_filename) { |
| 69 | fdt = load_device_tree(dtb_filename, &fdt_size); |
| 70 | } |
| 71 | if (!fdt) { |
| 72 | return 0; |
| 73 | } |
| 74 | |
| 75 | if (kernel_cmdline) { |
| 76 | r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", |
| 77 | kernel_cmdline); |
| 78 | if (r < 0) { |
| 79 | fprintf(stderrstderr, "couldn't set /chosen/bootargs\n"); |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | cpu_physical_memory_write(addr, (void *)fdt, fdt_size); |
| 84 | #else |
| 85 | |
| 86 | |
| 87 | if (dtb_filename) { |
| |
| 88 | fdt_size = load_image_targphys(dtb_filename, addr, 0x10000); |
| 89 | } |
| 90 | if (kernel_cmdline) { |
| |
| 91 | fprintf(stderrstderr, |
| 92 | "Warning: missing libfdt, cannot pass cmdline to kernel!\n"); |
| 93 | } |
| 94 | #endif |
| 95 | return fdt_size; |
| 4 | Undefined or garbage value returned to caller |
|
| 96 | } |
| 97 | |
| 98 | static uint64_t translate_kernel_address(void *opaque, uint64_t addr) |
| 99 | { |
| 100 | return addr - 0x30000000LL; |
| 101 | } |
| 102 | |
| 103 | void microblaze_load_kernel(MicroBlazeCPU *cpu, target_phys_addr_t ddr_base, |
| 104 | uint32_t ramsize, const char *dtb_filename, |
| 105 | void (*machine_cpu_reset)(MicroBlazeCPU *)) |
| 106 | { |
| 107 | QemuOpts *machine_opts; |
| 108 | const char *kernel_filename = NULL((void*)0); |
| 109 | const char *kernel_cmdline = NULL((void*)0); |
| 110 | |
| 111 | machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); |
| 112 | if (machine_opts) { |
| 113 | const char *dtb_arg; |
| 114 | kernel_filename = qemu_opt_get(machine_opts, "kernel"); |
| 115 | kernel_cmdline = qemu_opt_get(machine_opts, "append"); |
| 116 | dtb_arg = qemu_opt_get(machine_opts, "dtb"); |
| 117 | if (dtb_arg) { |
| 118 | dtb_filename = dtb_arg; |
| 119 | } else { |
| 120 | dtb_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS0, dtb_filename); |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | boot_info.machine_cpu_reset = machine_cpu_reset; |
| 125 | qemu_register_reset(main_cpu_reset, cpu); |
| 126 | |
| 127 | if (kernel_filename) { |
| 128 | int kernel_size; |
| 129 | uint64_t entry, low, high; |
| 130 | uint32_t base32; |
| 131 | int big_endian = 0; |
| 132 | |
| 133 | #ifdef TARGET_WORDS_BIGENDIAN |
| 134 | big_endian = 1; |
| 135 | #endif |
| 136 | |
| 137 | |
| 138 | kernel_size = load_elf(kernel_filename, NULL((void*)0), NULL((void*)0), |
| 139 | &entry, &low, &high, |
| 140 | big_endian, ELF_MACHINE189, 0); |
| 141 | base32 = entry; |
| 142 | if (base32 == 0xc0000000) { |
| 143 | kernel_size = load_elf(kernel_filename, translate_kernel_address, |
| 144 | NULL((void*)0), &entry, NULL((void*)0), NULL((void*)0), |
| 145 | big_endian, ELF_MACHINE189, 0); |
| 146 | } |
| 147 | |
| 148 | boot_info.bootstrap_pc = ddr_base + (entry & 0x0fffffff); |
| 149 | |
| 150 | |
| 151 | if (kernel_size < 0) { |
| 152 | target_phys_addr_t uentry, loadaddr; |
| 153 | |
| 154 | kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0); |
| 155 | boot_info.bootstrap_pc = uentry; |
| 156 | high = (loadaddr + kernel_size + 3) & ~3; |
| 157 | } |
| 158 | |
| 159 | |
| 160 | if (kernel_size < 0) { |
| 161 | kernel_size = load_image_targphys(kernel_filename, ddr_base, |
| 162 | ram_size); |
| 163 | boot_info.bootstrap_pc = ddr_base; |
| 164 | high = (ddr_base + kernel_size + 3) & ~3; |
| 165 | } |
| 166 | |
| 167 | boot_info.cmdline = high + 4096; |
| 168 | if (kernel_cmdline && strlen(kernel_cmdline)) { |
| 169 | pstrcpy_targphys("cmdline", boot_info.cmdline, 256, kernel_cmdline); |
| 170 | } |
| 171 | |
| 172 | boot_info.fdt = boot_info.cmdline + 4096; |
| 173 | microblaze_load_dtb(boot_info.fdt, ram_size, kernel_cmdline, |
| 174 | dtb_filename); |
| 175 | } |
| 176 | |
| 177 | } |