Skip to content

Commit cc4ba2c

Browse files
FlyGoatbibo-mao
authored andcommitted
hw/loongarch/boot: Support Linux raw boot image
Support booting such image by parsing header as per Linux's specification [1]. This enabled booting vmlinux.efi/vmlinuz.efi shipped by distros without supplying BIOS. [1]: https://docs.kernel.org/arch/loongarch/booting.html Signed-off-by: Jiaxun Yang <[email protected]> Signed-off-by: Bibo Mao <[email protected]> Reviewed-by: Bibo Mao <[email protected]>
1 parent e3526d0 commit cc4ba2c

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed

hw/loongarch/boot.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,26 @@
1515
#include "system/reset.h"
1616
#include "system/qtest.h"
1717

18+
/*
19+
* Linux Image Format
20+
* https://docs.kernel.org/arch/loongarch/booting.html
21+
*/
22+
#define LINUX_PE_MAGIC 0x818223cd
23+
#define MZ_MAGIC 0x5a4d /* "MZ" */
24+
25+
struct loongarch_linux_hdr {
26+
uint32_t mz_magic;
27+
uint32_t res0;
28+
uint64_t kernel_entry;
29+
uint64_t kernel_size;
30+
uint64_t load_offset;
31+
uint64_t res1;
32+
uint64_t res2;
33+
uint64_t res3;
34+
uint32_t linux_pe_magic;
35+
uint32_t pe_header_offset;
36+
} QEMU_PACKED;
37+
1838
struct memmap_entry *memmap_table;
1939
unsigned memmap_entries;
2040

@@ -171,6 +191,50 @@ static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
171191
return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
172192
}
173193

194+
static int64_t load_loongarch_linux_image(const char *filename,
195+
uint64_t *kernel_entry,
196+
uint64_t *kernel_low,
197+
uint64_t *kernel_high)
198+
{
199+
gsize len;
200+
ssize_t size;
201+
uint8_t *buffer;
202+
struct loongarch_linux_hdr *hdr;
203+
204+
/* Load as raw file otherwise */
205+
if (!g_file_get_contents(filename, (char **)&buffer, &len, NULL)) {
206+
return -1;
207+
}
208+
size = len;
209+
210+
/* Unpack the image if it is a EFI zboot image */
211+
if (unpack_efi_zboot_image(&buffer, &size) < 0) {
212+
g_free(buffer);
213+
return -1;
214+
}
215+
216+
hdr = (struct loongarch_linux_hdr *)buffer;
217+
218+
if (extract32(le32_to_cpu(hdr->mz_magic), 0, 16) != MZ_MAGIC ||
219+
le32_to_cpu(hdr->linux_pe_magic) != LINUX_PE_MAGIC) {
220+
g_free(buffer);
221+
return -1;
222+
}
223+
224+
/* Early kernel versions may have those fields in virtual address */
225+
*kernel_entry = extract64(le64_to_cpu(hdr->kernel_entry),
226+
0, TARGET_PHYS_ADDR_SPACE_BITS);
227+
*kernel_low = extract64(le64_to_cpu(hdr->load_offset),
228+
0, TARGET_PHYS_ADDR_SPACE_BITS);
229+
*kernel_high = *kernel_low + size;
230+
231+
rom_add_blob_fixed(filename, buffer, size, *kernel_low);
232+
233+
g_free(buffer);
234+
235+
return size;
236+
}
237+
174238
static int64_t load_kernel_info(struct loongarch_boot_info *info)
175239
{
176240
uint64_t kernel_entry, kernel_low, kernel_high;
@@ -181,6 +245,11 @@ static int64_t load_kernel_info(struct loongarch_boot_info *info)
181245
&kernel_entry, &kernel_low,
182246
&kernel_high, NULL, 0,
183247
EM_LOONGARCH, 1, 0);
248+
if (kernel_size < 0) {
249+
kernel_size = load_loongarch_linux_image(info->kernel_filename,
250+
&kernel_entry, &kernel_low,
251+
&kernel_high);
252+
}
184253

185254
if (kernel_size < 0) {
186255
error_report("could not load kernel '%s': %s",

0 commit comments

Comments
 (0)