All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Philippe Mathieu-Daudé" <f4bug@amsat.org>
To: Michael Clark <mjc@sifive.com>, qemu-devel@nongnu.org
Cc: patches@groups.riscv.org,
	Alistair Francis <Alistair.Francis@wdc.com>,
	Palmer Dabbelt <palmer@sifive.com>
Subject: Re: [Qemu-devel] [PATCH v1 30/30] RISC-V: Support separate firmware and kernel payload
Date: Wed, 23 May 2018 09:49:12 -0300	[thread overview]
Message-ID: <65f3d9c9-4522-41d4-4ae9-fd54745412d8@amsat.org> (raw)
In-Reply-To: <1527034517-7851-31-git-send-email-mjc@sifive.com>

On 05/22/2018 09:15 PM, Michael Clark wrote:
> Support for separate firmware and kernel payload is added
> by updating BBL to read optional preloaded kernel address
> attributes from device-tree using a similar mechanism to
> that used to pass init ramdisk addresses to linux kernel.
> 
>     chosen {
>         riscv,kernel-start = <0x00000000 0x80200000>;
>         riscv,kernel-end = <0x00000000 0x80590634>;
>     };
> 
> These attributes are added by QEMU and read by BBL when combining
> -bios <firmware-image> and -kernel <kernel-image> options. e.g.
> 
> $ qemu-system-riscv64 -machine virt -bios bbl -kernel vmlinux
> 
> With this change, bbl can be compiled without --with-payload
> and the dummy payload alignment is altered to make the memory
> footprint of the firmware-only bbl smaller. The dummy payload
> message is updated to indicate the alternative load method.
> 
> This load method could also be supported by a first stage boot
> loader that reads seperate firmware and kernel from SPI flash.
> The main advantage of this new mechanism is that it eases kernel
> development by avoiding the riscv-pk packaging step after kernel
> builds, makes building per repository artefacts for CI simpler,
> and mimics bootloaders on other platforms that can load a kernel
> image file directly. Ultimately BBL should use an SPI driver to
> load the kernel image however this mechanism supports use cases
> such such as QEMU's -bios, -kernel and -initrd options following
> examples from other platforms that pass kernel entry to firmware
> via device-tree.
> 
> The board is also changed to use the firmware address from the
> loaded firmware or combined firmware+kernel. This is normally
> equal to the DRAM base address of 0x8000_0000, however now it
> is possible to boot firmware at different load addresses because
> the reset code jumps to the actual firmware entry address.
> 
> Cc: Palmer Dabbelt <palmer@sifive.com>
> Cc: Alistair Francis <Alistair.Francis@wdc.com>
> Signed-off-by: Michael Clark <mjc@sifive.com>
> ---
>  hw/riscv/Makefile.objs  |   1 +
>  hw/riscv/boot.c         | 172 ++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/riscv/virt.c         |  67 +++----------------

This patch would be easier to review split in 2, one dumb moving out to
separate and another with the interesting changes.

>  include/hw/riscv/boot.h |  30 +++++++++
>  4 files changed, 213 insertions(+), 57 deletions(-)
>  create mode 100644 hw/riscv/boot.c
>  create mode 100644 include/hw/riscv/boot.h
> 
> diff --git a/hw/riscv/Makefile.objs b/hw/riscv/Makefile.objs
> index 1dde01d39dcc..d36b004ab0f9 100644
> --- a/hw/riscv/Makefile.objs
> +++ b/hw/riscv/Makefile.objs
> @@ -1,3 +1,4 @@
> +obj-y += boot.o
>  obj-y += riscv_htif.o
>  obj-y += riscv_hart.o
>  obj-y += sifive_e.o
> diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c
> new file mode 100644
> index 000000000000..cf4e5d594638
> --- /dev/null
> +++ b/hw/riscv/boot.c
> @@ -0,0 +1,172 @@
> +/*
> + * QEMU RISCV firmware and kernel loader
> + *
> + * Copyright (c) 2017-2018 SiFive, Inc.
> + *
> + * Holds the state of a heterogenous array of RISC-V harts
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "qemu/error-report.h"
> +#include "hw/loader.h"
> +#include "hw/boards.h"
> +#include "sysemu/device_tree.h"
> +#include "elf.h"
> +#include "hw/riscv/boot.h"
> +
> +#define RISCV_BOOT_DEBUG 0
> +
> +#define boot_debug(fs, ...) \
> +    if (RISCV_BOOT_DEBUG) { \
> +        fprintf(stderr, "boot: %s: "fs, __func__, ##__VA_ARGS__); \
> +    }
> +
> +static uint64_t kernel_offset;
> +
> +static uint64_t kernel_translate(void *opaque, uint64_t addr)
> +{
> +    /* mask kernel virtual address and offset by load address */
> +    if (kernel_offset) {
> +        return (addr & 0x7fffffff) + kernel_offset;
> +    } else {
> +        return addr;
> +    }
> +}
> +
> +hwaddr riscv_load_firmware(const char *filename)
> +{
> +    uint64_t firmware_entry, firmware_start, firmware_end;
> +
> +    if (load_elf(filename, NULL, NULL,
> +                 &firmware_entry, &firmware_start, &firmware_end,
> +                 0, EM_RISCV, 1, 0) < 0) {
> +        error_report("riscv_boot: could not load firmware '%s'", filename);
> +        exit(1);
> +    }
> +
> +    /* align kernel load address to the megapage after the firmware */
> +#if defined(TARGET_RISCV32)
> +    kernel_offset = (firmware_end + 0x3fffff) & ~0x3fffff;
> +#else
> +    kernel_offset = (firmware_end + 0x1fffff) & ~0x1fffff;
> +#endif
> +
> +    boot_debug("entry=0x" TARGET_FMT_plx " start=0x" TARGET_FMT_plx " "
> +               "end=0x" TARGET_FMT_plx " kernel_offset=0x" TARGET_FMT_plx "\n",
> +               firmware_entry, firmware_start, firmware_end, kernel_offset);
> +
> +    return firmware_entry;
> +}
> +
> +hwaddr riscv_load_kernel(const char *filename, void *fdt)
> +{
> +    uint64_t kernel_entry, kernel_start, kernel_end;
> +
> +    if (load_elf(filename, kernel_translate, NULL,
> +                 &kernel_entry, &kernel_start, &kernel_end,
> +                 0, EM_RISCV, 1, 0) < 0) {
> +        error_report("riscv_boot: could not load kernel '%s'", filename);
> +        exit(1);
> +    }
> +
> +    boot_debug("entry=0x" TARGET_FMT_plx " start=0x" TARGET_FMT_plx " "
> +               "end=0x" TARGET_FMT_plx "\n", kernel_entry, kernel_start,
> +               kernel_end);
> +
> +    /*
> +     * pass kernel load address via device-tree to firmware
> +     *
> +     * BBL reads the kernel address from device-tree
> +     */
> +    if (fdt) {
> +        qemu_fdt_setprop_cells(fdt, "/chosen", "riscv,kernel-end",
> +                               kernel_end >> 32, kernel_end);
> +        qemu_fdt_setprop_cells(fdt, "/chosen", "riscv,kernel-start",
> +                               kernel_start >> 32, kernel_start);
> +    }
> +
> +    return kernel_entry;
> +}
> +
> +void riscv_load_initrd(const char *filename, uint64_t mem_size,
> +                       hwaddr firmware_entry, void *fdt)
> +{
> +    uint64_t start, size;
> +
> +    /* We want to put the initrd far enough into RAM that when the
> +     * kernel is uncompressed it will not clobber the initrd. However
> +     * on boards without much RAM we must ensure that we still leave
> +     * enough room for a decent sized initrd, and on boards with large
> +     * amounts of RAM we must avoid the initrd being so far up in RAM
> +     * that it is outside lowmem and inaccessible to the kernel.
> +     * So for boards with less  than 256MB of RAM we put the initrd
> +     * halfway into RAM, and for boards with 256MB of RAM or more we put
> +     * the initrd at 128MB.
> +     */
> +    start = firmware_entry + MIN(mem_size / 2, 128 * 1024 * 1024);
> +
> +    size = load_ramdisk(filename, start, mem_size - start);
> +    if (size == -1) {
> +        size = load_image_targphys(filename, start, mem_size - start);
> +        if (size == -1) {
> +            error_report("riscv_boot: could not load ramdisk '%s'", filename);
> +            exit(1);
> +        }
> +    }
> +
> +    boot_debug("start=0x" TARGET_FMT_plx " end=0x" TARGET_FMT_plx "\n",
> +               start, start + size);
> +
> +    /*
> +     * pass initrd load address via device-tree to kernel
> +     *
> +     * linux-kernel reads the initrd address from device-tree
> +     */
> +    if (fdt) {
> +        qemu_fdt_setprop_cells(fdt, "/chosen", "linux,initrd-end",
> +                               (start + size) >> 32, start + size);
> +        qemu_fdt_setprop_cells(fdt, "/chosen", "linux,initrd-start",
> +                               start >> 32, start);
> +    }
> +}
> +
> +hwaddr riscv_load_firmware_kernel_initrd(MachineState *machine, void *fdt)
> +{
> +    hwaddr firmware_entry = 0;
> +
> +    /* load firmware e.g. -bios bbl */
> +    if (machine->firmware) {
> +        firmware_entry = riscv_load_firmware(machine->firmware);
> +    }
> +
> +    /* load combined bbl+kernel or separate kernel */
> +    if (machine->kernel_filename) {
> +        if (machine->firmware) {
> +            /* load separate bios and kernel e.g. -bios bbl -kernel vmlinux */
> +            riscv_load_kernel(machine->kernel_filename, fdt);
> +        } else {
> +            /* load traditional combined bbl+kernel e.g. -kernel bbl_vmlimux */
> +            firmware_entry = riscv_load_kernel(machine->kernel_filename, NULL);
> +        }
> +        if (machine->initrd_filename) {
> +            /* load separate initrd */
> +            riscv_load_initrd(machine->initrd_filename, machine->ram_size,
> +                              firmware_entry, fdt);
> +        }
> +    }
> +
> +    return firmware_entry;
> +}
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index c889aa3cd269..984ddf0635fd 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -33,6 +33,7 @@
>  #include "hw/riscv/sifive_plic.h"
>  #include "hw/riscv/sifive_clint.h"
>  #include "hw/riscv/sifive_test.h"
> +#include "hw/riscv/boot.h"
>  #include "hw/riscv/virt.h"
>  #include "chardev/char.h"
>  #include "sysemu/arch_init.h"
> @@ -56,47 +57,6 @@ static const struct MemmapEntry {
>      [VIRT_DRAM] =     { 0x80000000,        0x0 },
>  };
>  
> -static uint64_t load_kernel(const char *kernel_filename)
> -{
> -    uint64_t kernel_entry, kernel_high;
> -
> -    if (load_elf(kernel_filename, NULL, NULL,
> -                 &kernel_entry, NULL, &kernel_high,
> -                 0, EM_RISCV, 1, 0) < 0) {
> -        error_report("qemu: could not load kernel '%s'", kernel_filename);
> -        exit(1);
> -    }
> -    return kernel_entry;
> -}
> -
> -static hwaddr load_initrd(const char *filename, uint64_t mem_size,
> -                          uint64_t kernel_entry, hwaddr *start)
> -{
> -    int size;
> -
> -    /* We want to put the initrd far enough into RAM that when the
> -     * kernel is uncompressed it will not clobber the initrd. However
> -     * on boards without much RAM we must ensure that we still leave
> -     * enough room for a decent sized initrd, and on boards with large
> -     * amounts of RAM we must avoid the initrd being so far up in RAM
> -     * that it is outside lowmem and inaccessible to the kernel.
> -     * So for boards with less  than 256MB of RAM we put the initrd
> -     * halfway into RAM, and for boards with 256MB of RAM or more we put
> -     * the initrd at 128MB.
> -     */
> -    *start = kernel_entry + MIN(mem_size / 2, 128 * 1024 * 1024);
> -
> -    size = load_ramdisk(filename, *start, mem_size - *start);
> -    if (size == -1) {
> -        size = load_image_targphys(filename, *start, mem_size - *start);
> -        if (size == -1) {
> -            error_report("qemu: could not load ramdisk '%s'", filename);
> -            exit(1);
> -        }
> -    }
> -    return *start + size;
> -}
> -
>  static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
>      uint64_t mem_size, const char *cmdline)
>  {
> @@ -273,6 +233,7 @@ static void riscv_virt_board_init(MachineState *machine)
>      size_t plic_hart_config_len;
>      int i;
>      void *fdt;
> +    hwaddr firmware_entry;
>  
>      /* Initialize SOC */
>      object_initialize(&s->soc, sizeof(s->soc), TYPE_RISCV_HART_ARRAY);
> @@ -300,20 +261,12 @@ static void riscv_virt_board_init(MachineState *machine)
>      memory_region_add_subregion(system_memory, memmap[VIRT_MROM].base,
>                                  mask_rom);
>  
> -    if (machine->kernel_filename) {
> -        uint64_t kernel_entry = load_kernel(machine->kernel_filename);
> -
> -        if (machine->initrd_filename) {
> -            hwaddr start;
> -            hwaddr end = load_initrd(machine->initrd_filename,
> -                                     machine->ram_size, kernel_entry,
> -                                     &start);
> -            qemu_fdt_setprop_cell(fdt, "/chosen",
> -                                  "linux,initrd-start", start);
> -            qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
> -                                  end);
> -        }
> -    }
> +    /*
> +     * combined firmware and kernel: -kernel bbl_vmlimux
> +     * separate firmware and kernel: -bios bbl -kernel vmlinux
> +     * firmware, kernel and ramdisk: -bios bbl -kernel vmlinux -initrd initramfs
> +     */
> +    firmware_entry = riscv_load_firmware_kernel_initrd(machine, fdt);
>  
>      /* reset vector */
>      uint32_t reset_vec[8] = {
> @@ -327,8 +280,8 @@ static void riscv_virt_board_init(MachineState *machine)
>  #endif
>          0x00028067,                  /*     jr     t0 */
>          0x00000000,
> -        memmap[VIRT_DRAM].base,      /* start: .dword memmap[VIRT_DRAM].base */
> -        0x00000000,
> +        firmware_entry,              /* .word firmware_entry */
> +        firmware_entry >> 32,
>                                       /* dtb: */
>      };
>  
> diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h
> new file mode 100644
> index 000000000000..aa30bf1c45b2
> --- /dev/null
> +++ b/include/hw/riscv/boot.h
> @@ -0,0 +1,30 @@
> +/*
> + * QEMU RISCV firmware and kernel loader interface
> + *
> + * Copyright (c) 2017-2018 SiFive, Inc.
> + *
> + * Holds the state of a heterogenous array of RISC-V harts
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef HW_RISCV_BOOT_H
> +#define HW_RISCV_BOOT_H
> +
> +hwaddr riscv_load_firmware(const char *filename);
> +hwaddr riscv_load_kernel(const char *filename, void *fdt);
> +void riscv_load_initrd(const char *filename, uint64_t mem_size,
> +                       hwaddr firmware_entry, void *fdt);
> +hwaddr riscv_load_firmware_kernel_initrd(MachineState *machine, void *fdt);
> +
> +#endif
> 

      reply	other threads:[~2018-05-23 12:49 UTC|newest]

Thread overview: 61+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-05-23  0:14 [Qemu-devel] [PATCH v1 00/30] QEMU 2.13 RISC-V updates Michael Clark
2018-05-23  0:14 ` [Qemu-devel] [PATCH v1 01/30] RISC-V: Update address bits to support sv39 and sv48 Michael Clark
2018-05-25 15:07   ` Richard Henderson
2018-05-23  0:14 ` [Qemu-devel] [PATCH v1 02/30] RISC-V: Improve page table walker spec compliance Michael Clark
2018-05-23 22:31   ` Michael Clark
2018-05-23  0:14 ` [Qemu-devel] [PATCH v1 03/30] RISC-V: Use atomic_cmpxchg to update PLIC bitmaps Michael Clark
2018-05-29 23:32   ` Alistair Francis
2018-05-23  0:14 ` [Qemu-devel] [PATCH v1 04/30] RISC-V: Simplify riscv_cpu_local_irqs_pending Michael Clark
2018-05-25 15:15   ` Richard Henderson
2018-05-23  0:14 ` [Qemu-devel] [PATCH v1 05/30] RISC-V: Allow setting and clearing multiple irqs Michael Clark
2018-05-23 23:55   ` Alistair Francis
2018-05-25 15:19   ` Richard Henderson
2018-05-23  0:14 ` [Qemu-devel] [PATCH v1 06/30] RISC-V: Move non-ops from op_helper to cpu_helper Michael Clark
2018-05-23 12:23   ` Philippe Mathieu-Daudé
2018-05-25 15:20   ` Richard Henderson
2018-05-23  0:14 ` [Qemu-devel] [PATCH v1 07/30] RISC-V: Update CSR and interrupt definitions Michael Clark
2018-05-23  0:14 ` [Qemu-devel] [PATCH v1 08/30] RISC-V: Implement modular CSR helper interface Michael Clark
2018-05-23  0:14 ` [Qemu-devel] [PATCH v1 09/30] RISC-V: Implement atomic mip/sip CSR updates Michael Clark
2018-05-29 23:34   ` Alistair Francis
2018-05-23  0:14 ` [Qemu-devel] [PATCH v1 10/30] RISC-V: Implement existential predicates for CSRs Michael Clark
2018-05-23  0:14 ` [Qemu-devel] [PATCH v1 11/30] RISC-V: Split out mstatus_fs from tb_flags Michael Clark
2018-05-23 12:25   ` Philippe Mathieu-Daudé
2018-05-29 23:40   ` Alistair Francis
2018-05-23  0:14 ` [Qemu-devel] [PATCH v1 12/30] RISC-V: Mark mstatus.fs dirty Michael Clark
2018-05-29 23:38   ` Alistair Francis
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 13/30] RISC-V: Implement mstatus.TSR/TW/TVM Michael Clark
2018-05-23 12:26   ` Philippe Mathieu-Daudé
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 14/30] RISC-V: Add public API for the CSR dispatch table Michael Clark
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 15/30] RISC-V: Add hartid and \n to interrupt logging Michael Clark
2018-05-23 12:33   ` Philippe Mathieu-Daudé
2018-05-24 22:47     ` Alistair Francis
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 16/30] RISC-V: Use riscv prefix consistently on cpu helpers Michael Clark
2018-05-23 12:36   ` Philippe Mathieu-Daudé
2018-05-29 23:43   ` Alistair Francis
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 17/30] RISC-V: Replace __builtin_popcount with ctpop8 in PLIC Michael Clark
2018-05-23 12:37   ` Philippe Mathieu-Daudé
2018-05-29 23:47   ` Alistair Francis
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 18/30] RISC-V: Add missing free for plic_hart_config Michael Clark
2018-05-23 12:40   ` Philippe Mathieu-Daudé
2018-05-24 22:43     ` Alistair Francis
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 19/30] RISC-V: Allow interrupt controllers to claim interrupts Michael Clark
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 20/30] RISC-V: Add misa to DisasContext Michael Clark
2018-05-23 12:42   ` Philippe Mathieu-Daudé
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 21/30] RISC-V: Add misa.MAFD checks to translate Michael Clark
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 22/30] RISC-V: Add misa runtime write support Michael Clark
2018-05-25 18:53   ` Richard Henderson
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 23/30] RISC-V: Fix CLINT timecmp low 32-bit writes Michael Clark
2018-05-25 22:40   ` Alistair Francis
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 24/30] RISC-V: Fix PLIC pending bitfield reads Michael Clark
2018-05-25 22:38   ` Alistair Francis
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 25/30] RISC-V: Enable second UART on sifive_e and sifive_u Michael Clark
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 26/30] RISC-V: Remove unnecessary disassembler constraints Michael Clark
2018-05-24 22:45   ` Alistair Francis
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 27/30] elf: Add RISC-V PSABI ELF header defines Michael Clark
2018-05-23  6:44   ` Laurent Vivier
2018-05-25  7:17     ` Michael Clark
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 28/30] RISC-V: linux-user support for RVE ABI Michael Clark
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 29/30] RISC-V: Don't add NULL bootargs to device-tree Michael Clark
2018-05-23 12:45   ` Philippe Mathieu-Daudé
2018-05-23  0:15 ` [Qemu-devel] [PATCH v1 30/30] RISC-V: Support separate firmware and kernel payload Michael Clark
2018-05-23 12:49   ` Philippe Mathieu-Daudé [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=65f3d9c9-4522-41d4-4ae9-fd54745412d8@amsat.org \
    --to=f4bug@amsat.org \
    --cc=Alistair.Francis@wdc.com \
    --cc=mjc@sifive.com \
    --cc=palmer@sifive.com \
    --cc=patches@groups.riscv.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.