root / hw / microblaze_boot.c @ 03a6b667
History | View | Annotate | Download (5.9 kB)
1 | d94e7434 | Peter A. G. Crosthwaite | /*
|
---|---|---|---|
2 | d94e7434 | Peter A. G. Crosthwaite | * Microblaze kernel loader
|
3 | d94e7434 | Peter A. G. Crosthwaite | *
|
4 | d94e7434 | Peter A. G. Crosthwaite | * Copyright (c) 2012 Peter Crosthwaite <peter.crosthwaite@petalogix.com>
|
5 | d94e7434 | Peter A. G. Crosthwaite | * Copyright (c) 2012 PetaLogix
|
6 | d94e7434 | Peter A. G. Crosthwaite | * Copyright (c) 2009 Edgar E. Iglesias.
|
7 | d94e7434 | Peter A. G. Crosthwaite | *
|
8 | d94e7434 | Peter A. G. Crosthwaite | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
9 | d94e7434 | Peter A. G. Crosthwaite | * of this software and associated documentation files (the "Software"), to deal
|
10 | d94e7434 | Peter A. G. Crosthwaite | * in the Software without restriction, including without limitation the rights
|
11 | d94e7434 | Peter A. G. Crosthwaite | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12 | d94e7434 | Peter A. G. Crosthwaite | * copies of the Software, and to permit persons to whom the Software is
|
13 | d94e7434 | Peter A. G. Crosthwaite | * furnished to do so, subject to the following conditions:
|
14 | d94e7434 | Peter A. G. Crosthwaite | *
|
15 | d94e7434 | Peter A. G. Crosthwaite | * The above copyright notice and this permission notice shall be included in
|
16 | d94e7434 | Peter A. G. Crosthwaite | * all copies or substantial portions of the Software.
|
17 | d94e7434 | Peter A. G. Crosthwaite | *
|
18 | d94e7434 | Peter A. G. Crosthwaite | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19 | d94e7434 | Peter A. G. Crosthwaite | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20 | d94e7434 | Peter A. G. Crosthwaite | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
21 | d94e7434 | Peter A. G. Crosthwaite | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22 | d94e7434 | Peter A. G. Crosthwaite | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23 | d94e7434 | Peter A. G. Crosthwaite | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
24 | d94e7434 | Peter A. G. Crosthwaite | * THE SOFTWARE.
|
25 | d94e7434 | Peter A. G. Crosthwaite | */
|
26 | d94e7434 | Peter A. G. Crosthwaite | |
27 | d94e7434 | Peter A. G. Crosthwaite | #include "qemu-option.h" |
28 | d94e7434 | Peter A. G. Crosthwaite | #include "qemu-config.h" |
29 | d94e7434 | Peter A. G. Crosthwaite | #include "qemu-common.h" |
30 | d94e7434 | Peter A. G. Crosthwaite | #include "device_tree.h" |
31 | d94e7434 | Peter A. G. Crosthwaite | #include "loader.h" |
32 | d94e7434 | Peter A. G. Crosthwaite | #include "elf.h" |
33 | d94e7434 | Peter A. G. Crosthwaite | |
34 | d94e7434 | Peter A. G. Crosthwaite | #include "microblaze_boot.h" |
35 | d94e7434 | Peter A. G. Crosthwaite | |
36 | d94e7434 | Peter A. G. Crosthwaite | static struct |
37 | d94e7434 | Peter A. G. Crosthwaite | { |
38 | bf494367 | Andreas Färber | void (*machine_cpu_reset)(MicroBlazeCPU *);
|
39 | d94e7434 | Peter A. G. Crosthwaite | uint32_t bootstrap_pc; |
40 | d94e7434 | Peter A. G. Crosthwaite | uint32_t cmdline; |
41 | d94e7434 | Peter A. G. Crosthwaite | uint32_t fdt; |
42 | d94e7434 | Peter A. G. Crosthwaite | } boot_info; |
43 | d94e7434 | Peter A. G. Crosthwaite | |
44 | d94e7434 | Peter A. G. Crosthwaite | static void main_cpu_reset(void *opaque) |
45 | d94e7434 | Peter A. G. Crosthwaite | { |
46 | bf494367 | Andreas Färber | MicroBlazeCPU *cpu = opaque; |
47 | bf494367 | Andreas Färber | CPUMBState *env = &cpu->env; |
48 | d94e7434 | Peter A. G. Crosthwaite | |
49 | bf494367 | Andreas Färber | cpu_reset(CPU(cpu)); |
50 | d94e7434 | Peter A. G. Crosthwaite | env->regs[5] = boot_info.cmdline;
|
51 | d94e7434 | Peter A. G. Crosthwaite | env->regs[7] = boot_info.fdt;
|
52 | d94e7434 | Peter A. G. Crosthwaite | env->sregs[SR_PC] = boot_info.bootstrap_pc; |
53 | d94e7434 | Peter A. G. Crosthwaite | if (boot_info.machine_cpu_reset) {
|
54 | bf494367 | Andreas Färber | boot_info.machine_cpu_reset(cpu); |
55 | d94e7434 | Peter A. G. Crosthwaite | } |
56 | d94e7434 | Peter A. G. Crosthwaite | } |
57 | d94e7434 | Peter A. G. Crosthwaite | |
58 | d94e7434 | Peter A. G. Crosthwaite | static int microblaze_load_dtb(target_phys_addr_t addr, |
59 | d94e7434 | Peter A. G. Crosthwaite | uint32_t ramsize, |
60 | d94e7434 | Peter A. G. Crosthwaite | const char *kernel_cmdline, |
61 | d94e7434 | Peter A. G. Crosthwaite | const char *dtb_filename) |
62 | d94e7434 | Peter A. G. Crosthwaite | { |
63 | d94e7434 | Peter A. G. Crosthwaite | int fdt_size;
|
64 | d94e7434 | Peter A. G. Crosthwaite | #ifdef CONFIG_FDT
|
65 | da71ebd1 | Peter A. G. Crosthwaite | void *fdt = NULL; |
66 | d94e7434 | Peter A. G. Crosthwaite | int r;
|
67 | d94e7434 | Peter A. G. Crosthwaite | |
68 | da71ebd1 | Peter A. G. Crosthwaite | if (dtb_filename) {
|
69 | da71ebd1 | Peter A. G. Crosthwaite | fdt = load_device_tree(dtb_filename, &fdt_size); |
70 | da71ebd1 | Peter A. G. Crosthwaite | } |
71 | d94e7434 | Peter A. G. Crosthwaite | if (!fdt) {
|
72 | da71ebd1 | Peter A. G. Crosthwaite | return 0; |
73 | d94e7434 | Peter A. G. Crosthwaite | } |
74 | d94e7434 | Peter A. G. Crosthwaite | |
75 | d94e7434 | Peter A. G. Crosthwaite | if (kernel_cmdline) {
|
76 | d94e7434 | Peter A. G. Crosthwaite | r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", |
77 | d94e7434 | Peter A. G. Crosthwaite | kernel_cmdline); |
78 | d94e7434 | Peter A. G. Crosthwaite | if (r < 0) { |
79 | d94e7434 | Peter A. G. Crosthwaite | fprintf(stderr, "couldn't set /chosen/bootargs\n");
|
80 | d94e7434 | Peter A. G. Crosthwaite | } |
81 | d94e7434 | Peter A. G. Crosthwaite | } |
82 | d94e7434 | Peter A. G. Crosthwaite | |
83 | d94e7434 | Peter A. G. Crosthwaite | cpu_physical_memory_write(addr, (void *)fdt, fdt_size);
|
84 | d94e7434 | Peter A. G. Crosthwaite | #else
|
85 | d94e7434 | Peter A. G. Crosthwaite | /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob
|
86 | d94e7434 | Peter A. G. Crosthwaite | to the kernel. */
|
87 | da71ebd1 | Peter A. G. Crosthwaite | if (dtb_filename) {
|
88 | da71ebd1 | Peter A. G. Crosthwaite | fdt_size = load_image_targphys(dtb_filename, addr, 0x10000);
|
89 | d94e7434 | Peter A. G. Crosthwaite | } |
90 | d94e7434 | Peter A. G. Crosthwaite | if (kernel_cmdline) {
|
91 | d94e7434 | Peter A. G. Crosthwaite | fprintf(stderr, |
92 | d94e7434 | Peter A. G. Crosthwaite | "Warning: missing libfdt, cannot pass cmdline to kernel!\n");
|
93 | d94e7434 | Peter A. G. Crosthwaite | } |
94 | d94e7434 | Peter A. G. Crosthwaite | #endif
|
95 | d94e7434 | Peter A. G. Crosthwaite | return fdt_size;
|
96 | d94e7434 | Peter A. G. Crosthwaite | } |
97 | d94e7434 | Peter A. G. Crosthwaite | |
98 | d94e7434 | Peter A. G. Crosthwaite | static uint64_t translate_kernel_address(void *opaque, uint64_t addr) |
99 | d94e7434 | Peter A. G. Crosthwaite | { |
100 | d94e7434 | Peter A. G. Crosthwaite | return addr - 0x30000000LL; |
101 | d94e7434 | Peter A. G. Crosthwaite | } |
102 | d94e7434 | Peter A. G. Crosthwaite | |
103 | bf494367 | Andreas Färber | void microblaze_load_kernel(MicroBlazeCPU *cpu, target_phys_addr_t ddr_base,
|
104 | d94e7434 | Peter A. G. Crosthwaite | uint32_t ramsize, const char *dtb_filename, |
105 | bf494367 | Andreas Färber | void (*machine_cpu_reset)(MicroBlazeCPU *))
|
106 | d94e7434 | Peter A. G. Crosthwaite | { |
107 | d94e7434 | Peter A. G. Crosthwaite | QemuOpts *machine_opts; |
108 | d94e7434 | Peter A. G. Crosthwaite | const char *kernel_filename = NULL; |
109 | d94e7434 | Peter A. G. Crosthwaite | const char *kernel_cmdline = NULL; |
110 | d94e7434 | Peter A. G. Crosthwaite | |
111 | d94e7434 | Peter A. G. Crosthwaite | machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); |
112 | d94e7434 | Peter A. G. Crosthwaite | if (machine_opts) {
|
113 | da71ebd1 | Peter A. G. Crosthwaite | const char *dtb_arg; |
114 | d94e7434 | Peter A. G. Crosthwaite | kernel_filename = qemu_opt_get(machine_opts, "kernel");
|
115 | d94e7434 | Peter A. G. Crosthwaite | kernel_cmdline = qemu_opt_get(machine_opts, "append");
|
116 | da71ebd1 | Peter A. G. Crosthwaite | dtb_arg = qemu_opt_get(machine_opts, "dtb");
|
117 | da71ebd1 | Peter A. G. Crosthwaite | if (dtb_arg) { /* Preference a -dtb argument */ |
118 | da71ebd1 | Peter A. G. Crosthwaite | dtb_filename = dtb_arg; |
119 | da71ebd1 | Peter A. G. Crosthwaite | } else { /* default to pcbios dtb as passed by machine_init */ |
120 | da71ebd1 | Peter A. G. Crosthwaite | dtb_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename); |
121 | da71ebd1 | Peter A. G. Crosthwaite | } |
122 | d94e7434 | Peter A. G. Crosthwaite | } |
123 | d94e7434 | Peter A. G. Crosthwaite | |
124 | d94e7434 | Peter A. G. Crosthwaite | boot_info.machine_cpu_reset = machine_cpu_reset; |
125 | bf494367 | Andreas Färber | qemu_register_reset(main_cpu_reset, cpu); |
126 | d94e7434 | Peter A. G. Crosthwaite | |
127 | d94e7434 | Peter A. G. Crosthwaite | if (kernel_filename) {
|
128 | d94e7434 | Peter A. G. Crosthwaite | int kernel_size;
|
129 | d94e7434 | Peter A. G. Crosthwaite | uint64_t entry, low, high; |
130 | d94e7434 | Peter A. G. Crosthwaite | uint32_t base32; |
131 | d94e7434 | Peter A. G. Crosthwaite | int big_endian = 0; |
132 | d94e7434 | Peter A. G. Crosthwaite | |
133 | d94e7434 | Peter A. G. Crosthwaite | #ifdef TARGET_WORDS_BIGENDIAN
|
134 | d94e7434 | Peter A. G. Crosthwaite | big_endian = 1;
|
135 | d94e7434 | Peter A. G. Crosthwaite | #endif
|
136 | d94e7434 | Peter A. G. Crosthwaite | |
137 | d94e7434 | Peter A. G. Crosthwaite | /* Boots a kernel elf binary. */
|
138 | d94e7434 | Peter A. G. Crosthwaite | kernel_size = load_elf(kernel_filename, NULL, NULL, |
139 | d94e7434 | Peter A. G. Crosthwaite | &entry, &low, &high, |
140 | d94e7434 | Peter A. G. Crosthwaite | big_endian, ELF_MACHINE, 0);
|
141 | d94e7434 | Peter A. G. Crosthwaite | base32 = entry; |
142 | d94e7434 | Peter A. G. Crosthwaite | if (base32 == 0xc0000000) { |
143 | d94e7434 | Peter A. G. Crosthwaite | kernel_size = load_elf(kernel_filename, translate_kernel_address, |
144 | d94e7434 | Peter A. G. Crosthwaite | NULL, &entry, NULL, NULL, |
145 | d94e7434 | Peter A. G. Crosthwaite | big_endian, ELF_MACHINE, 0);
|
146 | d94e7434 | Peter A. G. Crosthwaite | } |
147 | d94e7434 | Peter A. G. Crosthwaite | /* Always boot into physical ram. */
|
148 | d94e7434 | Peter A. G. Crosthwaite | boot_info.bootstrap_pc = ddr_base + (entry & 0x0fffffff);
|
149 | d94e7434 | Peter A. G. Crosthwaite | |
150 | d94e7434 | Peter A. G. Crosthwaite | /* If it wasn't an ELF image, try an u-boot image. */
|
151 | d94e7434 | Peter A. G. Crosthwaite | if (kernel_size < 0) { |
152 | d94e7434 | Peter A. G. Crosthwaite | target_phys_addr_t uentry, loadaddr; |
153 | d94e7434 | Peter A. G. Crosthwaite | |
154 | d94e7434 | Peter A. G. Crosthwaite | kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0);
|
155 | d94e7434 | Peter A. G. Crosthwaite | boot_info.bootstrap_pc = uentry; |
156 | d94e7434 | Peter A. G. Crosthwaite | high = (loadaddr + kernel_size + 3) & ~3; |
157 | d94e7434 | Peter A. G. Crosthwaite | } |
158 | d94e7434 | Peter A. G. Crosthwaite | |
159 | d94e7434 | Peter A. G. Crosthwaite | /* Not an ELF image nor an u-boot image, try a RAW image. */
|
160 | d94e7434 | Peter A. G. Crosthwaite | if (kernel_size < 0) { |
161 | d94e7434 | Peter A. G. Crosthwaite | kernel_size = load_image_targphys(kernel_filename, ddr_base, |
162 | d94e7434 | Peter A. G. Crosthwaite | ram_size); |
163 | d94e7434 | Peter A. G. Crosthwaite | boot_info.bootstrap_pc = ddr_base; |
164 | d94e7434 | Peter A. G. Crosthwaite | high = (ddr_base + kernel_size + 3) & ~3; |
165 | d94e7434 | Peter A. G. Crosthwaite | } |
166 | d94e7434 | Peter A. G. Crosthwaite | |
167 | d94e7434 | Peter A. G. Crosthwaite | boot_info.cmdline = high + 4096;
|
168 | d94e7434 | Peter A. G. Crosthwaite | if (kernel_cmdline && strlen(kernel_cmdline)) {
|
169 | d94e7434 | Peter A. G. Crosthwaite | pstrcpy_targphys("cmdline", boot_info.cmdline, 256, kernel_cmdline); |
170 | d94e7434 | Peter A. G. Crosthwaite | } |
171 | d94e7434 | Peter A. G. Crosthwaite | /* Provide a device-tree. */
|
172 | d94e7434 | Peter A. G. Crosthwaite | boot_info.fdt = boot_info.cmdline + 4096;
|
173 | d94e7434 | Peter A. G. Crosthwaite | microblaze_load_dtb(boot_info.fdt, ram_size, kernel_cmdline, |
174 | d94e7434 | Peter A. G. Crosthwaite | dtb_filename); |
175 | d94e7434 | Peter A. G. Crosthwaite | } |
176 | d94e7434 | Peter A. G. Crosthwaite | |
177 | d94e7434 | Peter A. G. Crosthwaite | } |