qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 2/4] hw/i386: define a struct for Linux boot protocol data


From: Paolo Bonzini
Subject: [PATCH 2/4] hw/i386: define a struct for Linux boot protocol data
Date: Thu, 21 Jul 2022 14:29:35 +0200

In preparation for moving parts of x86_load_linux to separate function,
define a struct with the data that needs to be passed back and forth.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/i386/x86.c | 116 +++++++++++++++++++++++++++-----------------------
 1 file changed, 62 insertions(+), 54 deletions(-)

diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index 449edb076e..253a6ff536 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -819,22 +819,30 @@ static bool load_pvh(X86MachineState *x86ms, FWCfgState 
*fw_cfg, const char *ker
     return true;
 }
 
+typedef struct LinuxBootData {
+    uint16_t protocol;
+    uint8_t header[8192];
+    hwaddr prot_addr;
+    size_t kernel_size;
+    uint8_t *kernel;
+    size_t setup_data_offset;
+} LinuxBootData;
+
 void x86_load_linux(X86MachineState *x86ms,
                     FWCfgState *fw_cfg,
                     int acpi_data_size,
                     bool pvh_enabled)
 {
     bool linuxboot_dma_enabled = 
X86_MACHINE_GET_CLASS(x86ms)->fwcfg_dma_enabled;
-    uint16_t protocol;
-    int setup_size, kernel_size, cmdline_size;
-    int dtb_size, setup_data_offset;
+    int setup_size, cmdline_size;
+    int dtb_size;
     uint32_t initrd_max;
-    uint8_t header[8192], *setup, *kernel;
-    hwaddr real_addr, prot_addr, cmdline_addr;
+    uint8_t *setup;
+    hwaddr real_addr, cmdline_addr;
     FILE *f;
     char *vmode;
     MachineState *machine = MACHINE(x86ms);
-    struct setup_data *setup_data;
+    LinuxBootData data = { 0 };
     const char *kernel_filename = machine->kernel_filename;
     const char *initrd_filename = machine->initrd_filename;
     const char *dtb_filename = machine->dtb;
@@ -854,17 +862,17 @@ void x86_load_linux(X86MachineState *x86ms,
         exit(1);
     }
 
-    kernel_size = get_file_size(f);
-    if (!kernel_size ||
-        fread(header, 1, MIN(ARRAY_SIZE(header), kernel_size), f) !=
-        MIN(ARRAY_SIZE(header), kernel_size)) {
+    data.kernel_size = get_file_size(f);
+    if (!data.kernel_size ||
+        fread(data.header, 1, MIN(ARRAY_SIZE(data.header), data.kernel_size), 
f) !=
+        MIN(ARRAY_SIZE(data.header), data.kernel_size)) {
         fprintf(stderr, "qemu: could not load kernel '%s': %s\n",
                 kernel_filename, strerror(errno));
         exit(1);
     }
 
     /* kernel protocol version */
-    if (ldl_p(header + 0x202) != 0x53726448) {
+    if (ldl_p(data.header + 0x202) != 0x53726448) {
         /*
          * This could be a multiboot kernel. If it is, let's stop treating it
          * like a Linux kernel.
@@ -873,7 +881,7 @@ void x86_load_linux(X86MachineState *x86ms,
          * header before to load it.
          */
         if (load_multiboot(x86ms, fw_cfg, f, kernel_filename, initrd_filename,
-                           kernel_cmdline, kernel_size, header)) {
+                           kernel_cmdline, data.kernel_size, data.header)) {
             return;
         }
         /*
@@ -883,35 +891,35 @@ void x86_load_linux(X86MachineState *x86ms,
          */
         if (pvh_enabled &&
             load_pvh(x86ms, fw_cfg, kernel_filename, initrd_filename,
-                     initrd_max, kernel_cmdline, kernel_size, header)) {
+                     initrd_max, kernel_cmdline, data.kernel_size, 
data.header)) {
             fclose(f);
             return;
             }
-        protocol = 0;
+        data.protocol = 0;
     } else  {
-        protocol = lduw_p(header + 0x206);
+        data.protocol = lduw_p(data.header + 0x206);
     }
 
-    if (protocol < 0x200 || !(header[0x211] & 0x01)) {
+    if (data.protocol < 0x200 || !(data.header[0x211] & 0x01)) {
         /* Low kernel */
         real_addr    = 0x90000;
         cmdline_addr = 0x9a000 - cmdline_size;
-        prot_addr    = 0x10000;
-    } else if (protocol < 0x202) {
+        data.prot_addr = 0x10000;
+    } else if (data.protocol < 0x202) {
         /* High but ancient kernel */
         real_addr    = 0x90000;
         cmdline_addr = 0x9a000 - cmdline_size;
-        prot_addr    = 0x100000;
+        data.prot_addr = 0x100000;
     } else {
         /* High and recent kernel */
         real_addr    = 0x10000;
         cmdline_addr = 0x20000;
-        prot_addr    = 0x100000;
+        data.prot_addr = 0x100000;
     }
 
     /* highest address for loading the initrd */
-    if (protocol >= 0x20c &&
-        lduw_p(header + 0x236) & XLF_CAN_BE_LOADED_ABOVE_4G) {
+    if (data.protocol >= 0x20c &&
+        lduw_p(data.header + 0x236) & XLF_CAN_BE_LOADED_ABOVE_4G) {
         /*
          * Linux has supported initrd up to 4 GB for a very long time (2007,
          * long before XLF_CAN_BE_LOADED_ABOVE_4G which was added in 2013),
@@ -928,8 +936,8 @@ void x86_load_linux(X86MachineState *x86ms,
          *
          * Therefore here just limit initrd_max to the available memory below 
4G.
          */
-    } else if (protocol >= 0x203) {
-        initrd_max = MIN(initrd_max, ldl_p(header + 0x22c));
+    } else if (data.protocol >= 0x203) {
+        initrd_max = MIN(initrd_max, ldl_p(data.header + 0x22c));
     } else {
         initrd_max = MIN(initrd_max, 0x37ffffff);
     }
@@ -940,11 +948,11 @@ void x86_load_linux(X86MachineState *x86ms,
     sev_load_ctx.cmdline_data = (char *)kernel_cmdline;
     sev_load_ctx.cmdline_size = strlen(kernel_cmdline) + 1;
 
-    if (protocol >= 0x202) {
-        stl_p(header + 0x228, cmdline_addr);
+    if (data.protocol >= 0x202) {
+        stl_p(data.header + 0x228, cmdline_addr);
     } else {
-        stw_p(header + 0x20, 0xA33F);
-        stw_p(header + 0x22, cmdline_addr - real_addr);
+        stw_p(data.header + 0x20, 0xA33F);
+        stw_p(data.header + 0x22, cmdline_addr - real_addr);
     }
 
     /* handle vga= parameter */
@@ -968,7 +976,7 @@ void x86_load_linux(X86MachineState *x86ms,
                 exit(1);
             }
         }
-        stw_p(header + 0x1fa, video_mode);
+        stw_p(data.header + 0x1fa, video_mode);
     }
 
     /* loader type */
@@ -977,13 +985,13 @@ void x86_load_linux(X86MachineState *x86ms,
      * If this code is substantially changed, you may want to consider
      * incrementing the revision.
      */
-    if (protocol >= 0x200) {
-        header[0x210] = 0xB0;
+    if (data.protocol >= 0x200) {
+        data.header[0x210] = 0xB0;
     }
     /* heap */
-    if (protocol >= 0x201) {
-        header[0x211] |= 0x80; /* CAN_USE_HEAP */
-        stw_p(header + 0x224, cmdline_addr - real_addr - 0x200);
+    if (data.protocol >= 0x201) {
+        data.header[0x211] |= 0x80; /* CAN_USE_HEAP */
+        stw_p(data.header + 0x224, cmdline_addr - real_addr - 0x200);
     }
 
     /* load initrd */
@@ -993,7 +1001,7 @@ void x86_load_linux(X86MachineState *x86ms,
         gchar *initrd_data;
         GError *gerr = NULL;
 
-        if (protocol < 0x200) {
+        if (data.protocol < 0x200) {
             fprintf(stderr, "qemu: linux kernel too old to load a ram disk\n");
             exit(1);
         }
@@ -1023,30 +1031,30 @@ void x86_load_linux(X86MachineState *x86ms,
         sev_load_ctx.initrd_data = initrd_data;
         sev_load_ctx.initrd_size = initrd_size;
 
-        stl_p(header + 0x218, initrd_addr);
-        stl_p(header + 0x21c, initrd_size);
+        stl_p(data.header + 0x218, initrd_addr);
+        stl_p(data.header + 0x21c, initrd_size);
     }
 
     /* load kernel and setup */
-    setup_size = header[0x1f1];
+    setup_size = data.header[0x1f1];
     if (setup_size == 0) {
         setup_size = 4;
     }
     setup_size = (setup_size + 1) * 512;
-    if (setup_size > kernel_size) {
+    if (setup_size > data.kernel_size) {
         fprintf(stderr, "qemu: invalid kernel header\n");
         exit(1);
     }
-    kernel_size -= setup_size;
+    data.kernel_size -= setup_size;
 
     setup  = g_malloc(setup_size);
-    kernel = g_malloc(kernel_size);
+    data.kernel = g_malloc(data.kernel_size);
     fseek(f, 0, SEEK_SET);
     if (fread(setup, 1, setup_size, f) != setup_size) {
         fprintf(stderr, "fread() failed\n");
         exit(1);
     }
-    if (fread(kernel, 1, kernel_size, f) != kernel_size) {
+    if (fread(data.kernel, 1, data.kernel_size, f) != data.kernel_size) {
         fprintf(stderr, "fread() failed\n");
         exit(1);
     }
@@ -1054,7 +1062,7 @@ void x86_load_linux(X86MachineState *x86ms,
 
     /* append dtb to kernel */
     if (dtb_filename) {
-        if (protocol < 0x209) {
+        if (data.protocol < 0x209) {
             fprintf(stderr, "qemu: Linux kernel too old to load a dtb\n");
             exit(1);
         }
@@ -1066,13 +1074,13 @@ void x86_load_linux(X86MachineState *x86ms,
             exit(1);
         }
 
-        setup_data_offset = QEMU_ALIGN_UP(kernel_size, 16);
-        kernel_size = setup_data_offset + sizeof(struct setup_data) + dtb_size;
-        kernel = g_realloc(kernel, kernel_size);
+        data.setup_data_offset = QEMU_ALIGN_UP(data.kernel_size, 16);
+        data.kernel_size = data.setup_data_offset + sizeof(struct setup_data) 
+ dtb_size;
+        data.kernel = g_realloc(data.kernel, data.kernel_size);
 
-        stq_p(header + 0x250, prot_addr + setup_data_offset);
+        stq_p(data.header + 0x250, data.prot_addr + data.setup_data_offset);
 
-        setup_data = (struct setup_data *)(kernel + setup_data_offset);
+        struct setup_data *setup_data = (struct setup_data *)(data.kernel + 
data.setup_data_offset);
         setup_data->next = 0;
         setup_data->type = cpu_to_le32(SETUP_DTB);
         setup_data->len = cpu_to_le32(dtb_size);
@@ -1088,14 +1096,14 @@ void x86_load_linux(X86MachineState *x86ms,
      * file the user passed in.
      */
     if (!sev_enabled()) {
-        memcpy(setup, header, MIN(sizeof(header), setup_size));
+        memcpy(setup, data.header, MIN(sizeof(data.header), setup_size));
     }
 
-    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr);
-    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
-    fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size);
-    sev_load_ctx.kernel_data = (char *)kernel;
-    sev_load_ctx.kernel_size = kernel_size;
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, data.prot_addr);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, data.kernel_size);
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, data.kernel, 
data.kernel_size);
+    sev_load_ctx.kernel_data = (char *)data.kernel;
+    sev_load_ctx.kernel_size = data.kernel_size;
 
     fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr);
     fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size);
-- 
2.36.1





reply via email to

[Prev in Thread] Current Thread [Next in Thread]