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 | } |