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
28
29
30
31#include "qemu/osdep.h"
32#include "qemu/units.h"
33#include "qemu/datadir.h"
34#include "qemu/option.h"
35#include "qemu/config-file.h"
36#include "qemu/error-report.h"
37#include "qemu/guest-random.h"
38#include "sysemu/device_tree.h"
39#include "sysemu/reset.h"
40#include "hw/boards.h"
41#include "hw/loader.h"
42#include "elf.h"
43
44#include "boot.h"
45
46#include <libfdt.h>
47
48#define NIOS2_MAGIC 0x534f494e
49
50static struct nios2_boot_info {
51 void (*machine_cpu_reset)(Nios2CPU *);
52 uint32_t bootstrap_pc;
53 uint32_t cmdline;
54 uint32_t initrd_start;
55 uint32_t initrd_end;
56 uint32_t fdt;
57} boot_info;
58
59static void main_cpu_reset(void *opaque)
60{
61 Nios2CPU *cpu = opaque;
62 CPUState *cs = CPU(cpu);
63 CPUNios2State *env = &cpu->env;
64
65 cpu_reset(CPU(cpu));
66
67 env->regs[R_ARG0] = NIOS2_MAGIC;
68 env->regs[R_ARG1] = boot_info.initrd_start;
69 env->regs[R_ARG2] = boot_info.fdt;
70 env->regs[R_ARG3] = boot_info.cmdline;
71
72 cpu_set_pc(cs, boot_info.bootstrap_pc);
73 if (boot_info.machine_cpu_reset) {
74 boot_info.machine_cpu_reset(cpu);
75 }
76}
77
78static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
79{
80 return addr - 0xc0000000LL;
81}
82
83static int nios2_load_dtb(struct nios2_boot_info bi, const uint32_t ramsize,
84 const char *kernel_cmdline, const char *dtb_filename)
85{
86 MachineState *machine = MACHINE(qdev_get_machine());
87 int fdt_size;
88 void *fdt = NULL;
89 int r;
90 uint8_t rng_seed[32];
91
92 if (dtb_filename) {
93 fdt = load_device_tree(dtb_filename, &fdt_size);
94 }
95 if (!fdt) {
96 return 0;
97 }
98
99 qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
100 qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
101
102 if (kernel_cmdline) {
103 r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
104 kernel_cmdline);
105 if (r < 0) {
106 fprintf(stderr, "couldn't set /chosen/bootargs\n");
107 }
108 }
109
110 if (bi.initrd_start) {
111 qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
112 translate_kernel_address(NULL, bi.initrd_start));
113
114 qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
115 translate_kernel_address(NULL, bi.initrd_end));
116 }
117
118 cpu_physical_memory_write(bi.fdt, fdt, fdt_size);
119
120
121 machine->fdt = fdt;
122
123 return fdt_size;
124}
125
126void nios2_load_kernel(Nios2CPU *cpu, hwaddr ddr_base,
127 uint32_t ramsize,
128 const char *initrd_filename,
129 const char *dtb_filename,
130 void (*machine_cpu_reset)(Nios2CPU *))
131{
132 const char *kernel_filename;
133 const char *kernel_cmdline;
134 const char *dtb_arg;
135 char *filename = NULL;
136
137 kernel_filename = current_machine->kernel_filename;
138 kernel_cmdline = current_machine->kernel_cmdline;
139 dtb_arg = current_machine->dtb;
140
141 if (!dtb_arg) {
142 filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename);
143 }
144
145 boot_info.machine_cpu_reset = machine_cpu_reset;
146 qemu_register_reset(main_cpu_reset, cpu);
147
148 if (kernel_filename) {
149 int kernel_size, fdt_size;
150 uint64_t entry, high;
151 int big_endian = 0;
152
153#if TARGET_BIG_ENDIAN
154 big_endian = 1;
155#endif
156
157
158 kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
159 &entry, NULL, &high, NULL,
160 big_endian, EM_ALTERA_NIOS2, 0, 0);
161 if ((uint32_t)entry == 0xc0000000) {
162
163
164
165
166
167
168 kernel_size = load_elf(kernel_filename, NULL,
169 translate_kernel_address, NULL,
170 &entry, NULL, NULL, NULL,
171 big_endian, EM_ALTERA_NIOS2, 0, 0);
172 boot_info.bootstrap_pc = ddr_base + 0xc0000000 +
173 (entry & 0x07ffffff);
174 } else {
175
176 boot_info.bootstrap_pc = (uint32_t)entry;
177 }
178
179
180 if (kernel_size < 0) {
181 hwaddr uentry, loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
182
183 kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0,
184 NULL, NULL);
185 boot_info.bootstrap_pc = uentry;
186 high = loadaddr + kernel_size;
187 }
188
189
190 if (kernel_size < 0) {
191 kernel_size = load_image_targphys(kernel_filename, ddr_base,
192 ramsize);
193 boot_info.bootstrap_pc = ddr_base;
194 high = ddr_base + kernel_size;
195 }
196
197 high = ROUND_UP(high, 1 * MiB);
198
199
200 if (initrd_filename) {
201 int initrd_size;
202 uint32_t initrd_offset;
203
204 boot_info.initrd_start = high;
205 initrd_offset = boot_info.initrd_start - ddr_base;
206
207 initrd_size = load_ramdisk(initrd_filename,
208 boot_info.initrd_start,
209 ramsize - initrd_offset);
210 if (initrd_size < 0) {
211 initrd_size = load_image_targphys(initrd_filename,
212 boot_info.initrd_start,
213 ramsize - initrd_offset);
214 }
215 if (initrd_size < 0) {
216 error_report("could not load initrd '%s'",
217 initrd_filename);
218 exit(EXIT_FAILURE);
219 }
220 high += initrd_size;
221 }
222 high = ROUND_UP(high, 4);
223 boot_info.initrd_end = high;
224
225
226 boot_info.fdt = high;
227 fdt_size = nios2_load_dtb(boot_info, ramsize, kernel_cmdline,
228
229 dtb_arg ? dtb_arg : filename);
230 high += fdt_size;
231
232
233 boot_info.cmdline = ROUND_UP(high, 4 * KiB);
234 if (kernel_cmdline && strlen(kernel_cmdline)) {
235 pstrcpy_targphys("cmdline", boot_info.cmdline, 256, kernel_cmdline);
236 }
237 }
238 g_free(filename);
239}
240