qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [PATCH] Support load kernel(vmlinux)/dtb/initrd separat


From: Aleksandar Markovic
Subject: Re: [Qemu-devel] [PATCH] Support load kernel(vmlinux)/dtb/initrd separately for Boston in QEMU.
Date: Mon, 29 Jul 2019 12:56:48 +0200

ping

On Mon, Apr 1, 2019 at 11:26 AM Archer Yan <address@hidden> wrote:

> Currently boston in QEMU only supports boot with FIT format. Since ELF file
> can provide symbol infomation in debug, this patch enables Boston boot from
> vmlinux&dtb.
>
> Signed-off-by: Archer Yan <address@hidden>
> ---
>  hw/mips/boston.c | 224 ++++++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 201 insertions(+), 23 deletions(-)
>
>
Hi, Paul,

Note that we now have 2 proposals dealing with this topic: this one and

https://lists.gnu.org/archive/html/qemu-devel/2018-10/msg05108.html

I think it would be cool to integrate this support in 4.2.

Yours,
Aleksandar





> diff --git a/hw/mips/boston.c b/hw/mips/boston.c
> index e5bab3cadc..5910ffdc8a 100644
> --- a/hw/mips/boston.c
> +++ b/hw/mips/boston.c
> @@ -39,6 +39,10 @@
>  #include "sysemu/device_tree.h"
>  #include "sysemu/sysemu.h"
>  #include "sysemu/qtest.h"
> +#include "elf.h"
> +#include "sysemu/kvm.h"
> +#include "hw/mips/mips.h"
> +#include "qemu/option.h"
>
>  #include <libfdt.h>
>
> @@ -58,6 +62,11 @@ typedef struct {
>
>      hwaddr kernel_entry;
>      hwaddr fdt_base;
> +    long kernel_size;
> +
> +    uint64_t initrd_size;
> +    uint64_t initrd_start;
> +    uint64_t initrd_offset;
>  } BostonState;
>
>  enum boston_plat_reg {
> @@ -328,31 +337,59 @@ static void gen_firmware(uint32_t *p, hwaddr
> kernel_entry, hwaddr fdt_addr,
>      stl_p(p++, 0x03200009);                     /* jr   $25 */
>  }
>
> -static const void *boston_fdt_filter(void *opaque, const void *fdt_orig,
> -                                     const void *match_data, hwaddr
> *load_addr)
> +typedef uint64_t (*xlate_to_kseg0)(void *, uint64_t);
> +static xlate_to_kseg0 get_xlate_to_kseg0_fn(BostonState *s)
> +{
> +    /* Check where the kernel has been linked */
> +    if (s->kernel_entry & 0x80000000ll) {
> +        if (kvm_enabled()) {
> +            error_report("KVM guest kernels must be linked in useg. "
> +                         "Did you forget to enable CONFIG_KVM_GUEST?");
> +            return NULL;
> +        }
> +        return cpu_mips_phys_to_kseg0;
> +    } else {
> +        /* if kernel entry is in useg it is probably a KVM T&E kernel */
> +        mips_um_ksegs_enable();
> +        return cpu_mips_kvm_um_phys_to_kseg0;
> +    }
> +}
> +
> +/*Adapt fdt to insert initrd parameters*/
> +static int boston_initrd_fdt(BostonState *s, void *fdt)
>  {
> -    BostonState *s = BOSTON(opaque);
> -    MachineState *machine = s->mach;
>      const char *cmdline;
> +    char *args_str = NULL;
> +    MachineState *machine = s->mach;
> +    int initrd_args_len = 64;
>      int err;
> -    void *fdt;
> -    size_t fdt_sz, ram_low_sz, ram_high_sz;
> +    size_t ram_low_sz, ram_high_sz;
> +    uint64_t (*xlate_to_kseg0_fn) (void *opaque, uint64_t addr);
>
> -    fdt_sz = fdt_totalsize(fdt_orig) * 2;
> -    fdt = g_malloc0(fdt_sz);
> +    cmdline = (machine->kernel_cmdline && machine->kernel_cmdline[0])
> +            ? machine->kernel_cmdline : " ";
> +    xlate_to_kseg0_fn = get_xlate_to_kseg0_fn(s);
> +    if (NULL == xlate_to_kseg0_fn) {
> +        fprintf(stderr, "couldn't get xlate_to_kseg0\n");
> +        return -1;
> +    }
>
> -    err = fdt_open_into(fdt_orig, fdt, fdt_sz);
> -    if (err) {
> -        fprintf(stderr, "unable to open FDT\n");
> -        return NULL;
> +    s->initrd_start = xlate_to_kseg0_fn(NULL, s->initrd_offset);
> +
> +    if (s->initrd_size) {
> +        args_str = g_malloc(strlen(cmdline) + initrd_args_len);
> +        if (args_str != NULL) {
> +            sprintf((char *)args_str, "rd_start=0x%lx rd_size=0x%lx %s",
> +                    s->initrd_start, s->initrd_size, cmdline);
> +            cmdline = args_str;
> +        }
>      }
>
> -    cmdline = (machine->kernel_cmdline && machine->kernel_cmdline[0])
> -            ? machine->kernel_cmdline : " ";
>      err = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
>      if (err < 0) {
>          fprintf(stderr, "couldn't set /chosen/bootargs\n");
> -        return NULL;
> +        g_free(args_str);
> +        return -1;
>      }
>
>      ram_low_sz = MIN(256 * MiB, machine->ram_size);
> @@ -360,10 +397,41 @@ static const void *boston_fdt_filter(void *opaque,
> const void *fdt_orig,
>      qemu_fdt_setprop_sized_cells(fdt, "/memory@0", "reg",
>                                   1, 0x00000000, 1, ram_low_sz,
>                                   1, 0x90000000, 1, ram_high_sz);
> +    g_free(args_str);
> +    return 0;
> +}
>
> -    fdt = g_realloc(fdt, fdt_totalsize(fdt));
> -    qemu_fdt_dumpdtb(fdt, fdt_sz);
> +static const void *boston_fdt_filter(void *opaque, const void *fdt_orig,
> +                                     const void *match_data, hwaddr
> *load_addr)
> +{
> +    BostonState *s = BOSTON(opaque);
> +    MachineState *machine = s->mach;
> +    int err;
> +    void *fdt;
> +    int fdt_sz;
> +    if (machine->dtb) {
> +        /*Use QEMU cmd specified dtb*/
> +        fdt = load_device_tree(machine->dtb, &fdt_sz);
> +    } else {
> +        /*Use default dtb contained in FIT image*/
> +        fdt_sz = fdt_totalsize(fdt_orig) * 2;
> +        fdt = g_malloc0(fdt_sz);
> +
> +        err = fdt_open_into(fdt_orig, fdt, fdt_sz);
> +        if (err) {
> +            fprintf(stderr, "unable to open FDT\n");
> +            return NULL;
> +        }
> +
> +        fdt = g_realloc(fdt, fdt_totalsize(fdt));
> +    }
>
> +    err = boston_initrd_fdt(s, fdt);
> +    if (err) {
> +        return NULL;
> +    }
> +
> +    qemu_fdt_dumpdtb(fdt, fdt_sz);
>      s->fdt_base = *load_addr;
>
>      return fdt;
> @@ -391,6 +459,99 @@ static const struct fit_loader boston_fit_loader = {
>      .kernel_filter = boston_kernel_filter,
>  };
>
> +static int boston_load_dtb(BostonState *s)
> +{
> +    void *fdt = NULL;
> +    int size = 0;
> +    int err;
> +    MachineState *machine = s->mach;
> +    hwaddr load_addr;
> +    hwaddr kernel_end = 0xffffffff80100000 + s->kernel_size;
> +
> +    fdt = load_device_tree(machine->dtb, &size);
> +    if (!fdt) {
> +        fprintf(stderr, "Couldn't open dtb file %s\n", machine->dtb);
> +        return -1;
> +    }
> +    load_addr = ROUND_UP(kernel_end, 64 * KiB) + (10 * MiB);
> +    err = boston_initrd_fdt(s, fdt);
> +    if (err) {
> +        return -1;
> +    }
> +
> +    qemu_fdt_dumpdtb(fdt, size);
> +
> +    s->fdt_base = load_addr;
> +    load_addr = cpu_mips_kseg0_to_phys(s, load_addr);
> +    rom_add_blob_fixed("fdt@boston", fdt, size, load_addr);
> +
> +    return 0;
> +
> +}
> +
> +static int boston_load_initrd(BostonState *s)
> +{
> +    int64_t initrd_size = 0;
> +    ram_addr_t initrd_offset = 0;
> +    int ram_low_size;
> +    MachineState *machine = s->mach;
> +    ram_low_size = MIN(machine->ram_size, 256 * MiB);
> +    if (machine->initrd_filename) {
> +        initrd_size = get_image_size(machine->initrd_filename);
> +        if (initrd_size > 0) {
> +            /*
> +             * The kernel allocates the bootmap memory in the low memory
> after
> +             *  the initrd.  It takes at most 128kiB for 2GB RAM and 4kiB
> +             *  pages.
> +             */
> +            initrd_offset = (ram_low_size - initrd_size
> +                             - (128 * KiB)
> +                             - ~INITRD_PAGE_MASK) & INITRD_PAGE_MASK;
> +
> +            initrd_size = load_image_targphys(machine->initrd_filename,
> +                                              initrd_offset,
> +                                              ram_size - initrd_offset);
> +        }
> +        if (initrd_size == (target_ulong) -1) {
> +            error_report("could not load initial ram disk '%s'",
> +                         machine->initrd_filename);
> +            return -1;
> +        }
> +    }
> +    s->initrd_offset = initrd_offset;
> +    s->initrd_size = initrd_size;
> +    return 0;
> +}
> +
> +static int boston_load_kernel(BostonState *s)
> +{
> +    int64_t kernel_entry, kernel_high;
> +    long kernel_size;
> +    int big_endian;
> +    MachineState *machine = s->mach;
> +
> +#ifdef TARGET_WORDS_BIGENDIAN
> +    big_endian = 1;
> +#else
> +    big_endian = 0;
> +#endif
> +
> +    kernel_size = load_elf(machine->kernel_filename, NULL,
> +                           cpu_mips_kseg0_to_phys,  NULL,
> +                           (uint64_t *)&kernel_entry, NULL,
> +                           (uint64_t *)&kernel_high, big_endian, EM_MIPS,
> 1, 0);
> +    if (kernel_size < 0) {
> +        error_report("could not load kernel '%s': %s",
> +                     machine->kernel_filename,
> +                     load_elf_strerror(kernel_size));
> +        return -1;
> +    }
> +
> +    s->kernel_entry = kernel_entry;
> +    s->kernel_size = kernel_size;
> +    return 0;
> +}
> +
>  static inline XilinxPCIEHost *
>  xilinx_pcie_init(MemoryRegion *sys_mem, uint32_t bus_nr,
>                   hwaddr cfg_base, uint64_t cfg_size,
> @@ -433,7 +594,7 @@ static void boston_mach_init(MachineState *machine)
>      PCIDevice *ahci;
>      DriveInfo *hd[6];
>      Chardev *chr;
> -    int fw_size, fit_err;
> +    int fw_size, load_err;
>      bool is_64b;
>
>      if ((machine->ram_size % GiB) ||
> @@ -533,12 +694,29 @@ static void boston_mach_init(MachineState *machine)
>              exit(1);
>          }
>      } else if (machine->kernel_filename) {
> -        fit_err = load_fit(&boston_fit_loader, machine->kernel_filename,
> s);
> -        if (fit_err) {
> -            error_printf("unable to load FIT image\n");
> -            exit(1);
> +        if (machine->initrd_filename) {
> +            load_err = boston_load_initrd(s);
> +            if (load_err) {
> +                error_printf("unable to separately load initrd image\n");
> +                exit(1);
> +            }
> +        }
> +        load_err = load_fit(&boston_fit_loader, machine->kernel_filename,
> s);
> +        if (load_err) {
> +            error_printf("unable to load FIT image, try load as ELF\n");
> +            load_err = boston_load_kernel(s);
> +            if (load_err) {
> +                error_printf("unable to separately load kernel image\n");
> +                exit(1);
> +            }
> +            if (machine->dtb) {
> +                load_err = boston_load_dtb(s);
> +                if (load_err) {
> +                    error_printf("unable to separately load dtb image\n");
> +                    exit(1);
> +                }
> +            }
>          }
> -
>          gen_firmware(memory_region_get_ram_ptr(flash) + 0x7c00000,
>                       s->kernel_entry, s->fdt_base, is_64b);
>      } else if (!qtest_enabled()) {
> --
> 2.17.1
>
>
>


reply via email to

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