diff mbox series

[v4,10/20] hw/arm/allwinner-h3: add Boot ROM support

Message ID 20200119005102.3847-11-nieklinnenbank@gmail.com
State New
Headers show
Series Add Allwinner H3 SoC and Orange Pi PC Machine | expand

Commit Message

Niek Linnenbank Jan. 19, 2020, 12:50 a.m. UTC
A real Allwinner H3 SoC contains a Boot ROM which is the
first code that runs right after the SoC is powered on.
The Boot ROM is responsible for loading user code (e.g. a bootloader)
from any of the supported external devices and writing the downloaded
code to internal SRAM. After loading the SoC begins executing the code
written to SRAM.

This commits adds emulation of the Boot ROM firmware setup functionality
by loading user code from SD card in the A1 SRAM. While the A1 SRAM is
64KiB, we limit the size to 32KiB because the real H3 Boot ROM also rejects
sizes larger than 32KiB. For reference, this behaviour is documented
by the Linux Sunxi project wiki at:

  https://linux-sunxi.org/BROM#U-Boot_SPL_limitations

Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
---
 include/hw/arm/allwinner-h3.h | 23 +++++++++++++++++++++++
 hw/arm/allwinner-h3.c         | 28 ++++++++++++++++++++++++++++
 hw/arm/orangepi.c             |  5 +++++
 3 files changed, 56 insertions(+)

Comments

Philippe Mathieu-Daudé Jan. 19, 2020, 7:14 p.m. UTC | #1
On 1/19/20 1:50 AM, Niek Linnenbank wrote:
> A real Allwinner H3 SoC contains a Boot ROM which is the
> first code that runs right after the SoC is powered on.
> The Boot ROM is responsible for loading user code (e.g. a bootloader)
> from any of the supported external devices and writing the downloaded
> code to internal SRAM. After loading the SoC begins executing the code
> written to SRAM.
> 
> This commits adds emulation of the Boot ROM firmware setup functionality
> by loading user code from SD card in the A1 SRAM. While the A1 SRAM is
> 64KiB, we limit the size to 32KiB because the real H3 Boot ROM also rejects
> sizes larger than 32KiB. For reference, this behaviour is documented
> by the Linux Sunxi project wiki at:
> 
>    https://linux-sunxi.org/BROM#U-Boot_SPL_limitations
> 
> Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
> ---
>   include/hw/arm/allwinner-h3.h | 23 +++++++++++++++++++++++
>   hw/arm/allwinner-h3.c         | 28 ++++++++++++++++++++++++++++
>   hw/arm/orangepi.c             |  5 +++++
>   3 files changed, 56 insertions(+)
> 
> diff --git a/include/hw/arm/allwinner-h3.h b/include/hw/arm/allwinner-h3.h
> index f9b9a02373..f5e16266cd 100644
> --- a/include/hw/arm/allwinner-h3.h
> +++ b/include/hw/arm/allwinner-h3.h
> @@ -46,6 +46,7 @@
>   #include "hw/sd/allwinner-sdhost.h"
>   #include "hw/net/allwinner-sun8i-emac.h"
>   #include "target/arm/cpu.h"
> +#include "sysemu/block-backend.h"
>   
>   /**
>    * Allwinner H3 device list
> @@ -129,4 +130,26 @@ typedef struct AwH3State {
>       MemoryRegion sram_c;
>   } AwH3State;
>   
> +/**
> + * Emulate Boot ROM firmware setup functionality.
> + *
> + * A real Allwinner H3 SoC contains a Boot ROM
> + * which is the first code that runs right after
> + * the SoC is powered on. The Boot ROM is responsible
> + * for loading user code (e.g. a bootloader) from any
> + * of the supported external devices and writing the
> + * downloaded code to internal SRAM. After loading the SoC
> + * begins executing the code written to SRAM.
> + *
> + * This function emulates the Boot ROM by copying 32 KiB
> + * of data from the given block device and writes it to
> + * the start of the first internal SRAM memory.
> + *
> + * @s: Allwinner H3 state object pointer
> + * @blk: Block backend device object pointer
> + * @errp: Error object pointer for raising errors
> + */
> +void allwinner_h3_bootrom_setup(AwH3State *s, BlockBackend *blk,
> +                                Error **errp);
> +
>   #endif /* HW_ARM_ALLWINNER_H3_H */
> diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
> index 1085223812..3d0470825a 100644
> --- a/hw/arm/allwinner-h3.c
> +++ b/hw/arm/allwinner-h3.c
> @@ -29,6 +29,7 @@
>   #include "hw/char/serial.h"
>   #include "hw/misc/unimp.h"
>   #include "hw/usb/hcd-ehci.h"
> +#include "hw/loader.h"
>   #include "sysemu/sysemu.h"
>   #include "hw/arm/allwinner-h3.h"
>   
> @@ -170,6 +171,33 @@ enum {
>       AW_H3_GIC_NUM_SPI       = 128
>   };
>   
> +void allwinner_h3_bootrom_setup(AwH3State *s, BlockBackend *blk, Error **errp)
> +{
> +    uint8_t *buffer;
> +    int64_t rom_size = 32 * KiB;
> +
> +    int64_t blk_size = blk_getlength(blk);
> +    if (blk_size <= 0) {
> +        error_setg(errp, "%s: failed to get BlockBackend size", __func__);
> +        return;
> +    }
> +
> +    if (rom_size > blk_size) {
> +        rom_size = blk_size;

This doesn't seem correct, have you tried to use a 1MB file?

This can't be bigger than the SRAM size, 64KB.

> +    }
> +
> +    buffer = g_new0(uint8_t, rom_size);
> +    if (blk_pread(blk, 8 * KiB, buffer, rom_size) < 0) {
> +        error_setg(errp, "%s: failed to read BlockBackend data", __func__);
> +        return;
> +    }
> +
> +    rom_add_blob("allwinner-h3.bootrom", buffer, rom_size,
> +                  rom_size, s->memmap[AW_H3_SRAM_A1],
> +                  NULL, NULL, NULL, NULL, false);
> +    g_free(buffer);
> +}
> +
>   static void allwinner_h3_init(Object *obj)
>   {
>       AwH3State *s = AW_H3(obj);
> diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
> index 25bf85f8fc..9d4c79885e 100644
> --- a/hw/arm/orangepi.c
> +++ b/hw/arm/orangepi.c
> @@ -95,6 +95,11 @@ static void orangepi_init(MachineState *machine)
>       memory_region_add_subregion(get_system_memory(), s->h3->memmap[AW_H3_SDRAM],
>                                   &s->sdram);
>   
> +    /* Load target kernel or start using BootROM */
> +    if (!machine->kernel_filename && blk_is_available(blk)) {
> +        /* Use Boot ROM to copy data from SD card to SRAM */
> +        allwinner_h3_bootrom_setup(s->h3, blk, &error_fatal);
allwinner_h3_bootrom_setup() doesn't need the errp argument, you can use 
error_fatal directly there.

> +    }
>       orangepi_binfo.loader_start = s->h3->memmap[AW_H3_SDRAM];
>       orangepi_binfo.ram_size = machine->ram_size;
>       arm_load_kernel(ARM_CPU(first_cpu), machine, &orangepi_binfo);
>
Niek Linnenbank Feb. 2, 2020, 10:11 p.m. UTC | #2
On Sun, Jan 19, 2020 at 8:14 PM Philippe Mathieu-Daudé <philmd@redhat.com>
wrote:

> On 1/19/20 1:50 AM, Niek Linnenbank wrote:
> > A real Allwinner H3 SoC contains a Boot ROM which is the
> > first code that runs right after the SoC is powered on.
> > The Boot ROM is responsible for loading user code (e.g. a bootloader)
> > from any of the supported external devices and writing the downloaded
> > code to internal SRAM. After loading the SoC begins executing the code
> > written to SRAM.
> >
> > This commits adds emulation of the Boot ROM firmware setup functionality
> > by loading user code from SD card in the A1 SRAM. While the A1 SRAM is
> > 64KiB, we limit the size to 32KiB because the real H3 Boot ROM also
> rejects
> > sizes larger than 32KiB. For reference, this behaviour is documented
> > by the Linux Sunxi project wiki at:
> >
> >    https://linux-sunxi.org/BROM#U-Boot_SPL_limitations
> >
> > Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
> > ---
> >   include/hw/arm/allwinner-h3.h | 23 +++++++++++++++++++++++
> >   hw/arm/allwinner-h3.c         | 28 ++++++++++++++++++++++++++++
> >   hw/arm/orangepi.c             |  5 +++++
> >   3 files changed, 56 insertions(+)
> >
> > diff --git a/include/hw/arm/allwinner-h3.h
> b/include/hw/arm/allwinner-h3.h
> > index f9b9a02373..f5e16266cd 100644
> > --- a/include/hw/arm/allwinner-h3.h
> > +++ b/include/hw/arm/allwinner-h3.h
> > @@ -46,6 +46,7 @@
> >   #include "hw/sd/allwinner-sdhost.h"
> >   #include "hw/net/allwinner-sun8i-emac.h"
> >   #include "target/arm/cpu.h"
> > +#include "sysemu/block-backend.h"
> >
> >   /**
> >    * Allwinner H3 device list
> > @@ -129,4 +130,26 @@ typedef struct AwH3State {
> >       MemoryRegion sram_c;
> >   } AwH3State;
> >
> > +/**
> > + * Emulate Boot ROM firmware setup functionality.
> > + *
> > + * A real Allwinner H3 SoC contains a Boot ROM
> > + * which is the first code that runs right after
> > + * the SoC is powered on. The Boot ROM is responsible
> > + * for loading user code (e.g. a bootloader) from any
> > + * of the supported external devices and writing the
> > + * downloaded code to internal SRAM. After loading the SoC
> > + * begins executing the code written to SRAM.
> > + *
> > + * This function emulates the Boot ROM by copying 32 KiB
> > + * of data from the given block device and writes it to
> > + * the start of the first internal SRAM memory.
> > + *
> > + * @s: Allwinner H3 state object pointer
> > + * @blk: Block backend device object pointer
> > + * @errp: Error object pointer for raising errors
> > + */
> > +void allwinner_h3_bootrom_setup(AwH3State *s, BlockBackend *blk,
> > +                                Error **errp);
> > +
> >   #endif /* HW_ARM_ALLWINNER_H3_H */
> > diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
> > index 1085223812..3d0470825a 100644
> > --- a/hw/arm/allwinner-h3.c
> > +++ b/hw/arm/allwinner-h3.c
> > @@ -29,6 +29,7 @@
> >   #include "hw/char/serial.h"
> >   #include "hw/misc/unimp.h"
> >   #include "hw/usb/hcd-ehci.h"
> > +#include "hw/loader.h"
> >   #include "sysemu/sysemu.h"
> >   #include "hw/arm/allwinner-h3.h"
> >
> > @@ -170,6 +171,33 @@ enum {
> >       AW_H3_GIC_NUM_SPI       = 128
> >   };
> >
> > +void allwinner_h3_bootrom_setup(AwH3State *s, BlockBackend *blk, Error
> **errp)
> > +{
> > +    uint8_t *buffer;
> > +    int64_t rom_size = 32 * KiB;
> > +
> > +    int64_t blk_size = blk_getlength(blk);
> > +    if (blk_size <= 0) {
> > +        error_setg(errp, "%s: failed to get BlockBackend size",
> __func__);
> > +        return;
> > +    }
> > +
> > +    if (rom_size > blk_size) {
> > +        rom_size = blk_size;
>
> This doesn't seem correct, have you tried to use a 1MB file?
>
> This can't be bigger than the SRAM size, 64KB.
>

This check was supposed to take into account the possibility that
the BlockBackend is smaller than the rom_size. However, if the rom cannot
be read from the BlockBackend it will return an error code anyway.

So the check can simply be removed. Thanks!


>
> > +    }
> > +
> > +    buffer = g_new0(uint8_t, rom_size);
> > +    if (blk_pread(blk, 8 * KiB, buffer, rom_size) < 0) {
> > +        error_setg(errp, "%s: failed to read BlockBackend data",
> __func__);
> > +        return;
> > +    }
> > +
> > +    rom_add_blob("allwinner-h3.bootrom", buffer, rom_size,
> > +                  rom_size, s->memmap[AW_H3_SRAM_A1],
> > +                  NULL, NULL, NULL, NULL, false);
> > +    g_free(buffer);
> > +}
> > +
> >   static void allwinner_h3_init(Object *obj)
> >   {
> >       AwH3State *s = AW_H3(obj);
> > diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
> > index 25bf85f8fc..9d4c79885e 100644
> > --- a/hw/arm/orangepi.c
> > +++ b/hw/arm/orangepi.c
> > @@ -95,6 +95,11 @@ static void orangepi_init(MachineState *machine)
> >       memory_region_add_subregion(get_system_memory(),
> s->h3->memmap[AW_H3_SDRAM],
> >                                   &s->sdram);
> >
> > +    /* Load target kernel or start using BootROM */
> > +    if (!machine->kernel_filename && blk_is_available(blk)) {
> > +        /* Use Boot ROM to copy data from SD card to SRAM */
> > +        allwinner_h3_bootrom_setup(s->h3, blk, &error_fatal);
> allwinner_h3_bootrom_setup() doesn't need the errp argument, you can use
> error_fatal directly there.
>

OK, I'll use error_fatal and remove the errp argument.

Regards,
Niek


>
> > +    }
> >       orangepi_binfo.loader_start = s->h3->memmap[AW_H3_SDRAM];
> >       orangepi_binfo.ram_size = machine->ram_size;
> >       arm_load_kernel(ARM_CPU(first_cpu), machine, &orangepi_binfo);
> >
>
>
diff mbox series

Patch

diff --git a/include/hw/arm/allwinner-h3.h b/include/hw/arm/allwinner-h3.h
index f9b9a02373..f5e16266cd 100644
--- a/include/hw/arm/allwinner-h3.h
+++ b/include/hw/arm/allwinner-h3.h
@@ -46,6 +46,7 @@ 
 #include "hw/sd/allwinner-sdhost.h"
 #include "hw/net/allwinner-sun8i-emac.h"
 #include "target/arm/cpu.h"
+#include "sysemu/block-backend.h"
 
 /**
  * Allwinner H3 device list
@@ -129,4 +130,26 @@  typedef struct AwH3State {
     MemoryRegion sram_c;
 } AwH3State;
 
+/**
+ * Emulate Boot ROM firmware setup functionality.
+ *
+ * A real Allwinner H3 SoC contains a Boot ROM
+ * which is the first code that runs right after
+ * the SoC is powered on. The Boot ROM is responsible
+ * for loading user code (e.g. a bootloader) from any
+ * of the supported external devices and writing the
+ * downloaded code to internal SRAM. After loading the SoC
+ * begins executing the code written to SRAM.
+ *
+ * This function emulates the Boot ROM by copying 32 KiB
+ * of data from the given block device and writes it to
+ * the start of the first internal SRAM memory.
+ *
+ * @s: Allwinner H3 state object pointer
+ * @blk: Block backend device object pointer
+ * @errp: Error object pointer for raising errors
+ */
+void allwinner_h3_bootrom_setup(AwH3State *s, BlockBackend *blk,
+                                Error **errp);
+
 #endif /* HW_ARM_ALLWINNER_H3_H */
diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
index 1085223812..3d0470825a 100644
--- a/hw/arm/allwinner-h3.c
+++ b/hw/arm/allwinner-h3.c
@@ -29,6 +29,7 @@ 
 #include "hw/char/serial.h"
 #include "hw/misc/unimp.h"
 #include "hw/usb/hcd-ehci.h"
+#include "hw/loader.h"
 #include "sysemu/sysemu.h"
 #include "hw/arm/allwinner-h3.h"
 
@@ -170,6 +171,33 @@  enum {
     AW_H3_GIC_NUM_SPI       = 128
 };
 
+void allwinner_h3_bootrom_setup(AwH3State *s, BlockBackend *blk, Error **errp)
+{
+    uint8_t *buffer;
+    int64_t rom_size = 32 * KiB;
+
+    int64_t blk_size = blk_getlength(blk);
+    if (blk_size <= 0) {
+        error_setg(errp, "%s: failed to get BlockBackend size", __func__);
+        return;
+    }
+
+    if (rom_size > blk_size) {
+        rom_size = blk_size;
+    }
+
+    buffer = g_new0(uint8_t, rom_size);
+    if (blk_pread(blk, 8 * KiB, buffer, rom_size) < 0) {
+        error_setg(errp, "%s: failed to read BlockBackend data", __func__);
+        return;
+    }
+
+    rom_add_blob("allwinner-h3.bootrom", buffer, rom_size,
+                  rom_size, s->memmap[AW_H3_SRAM_A1],
+                  NULL, NULL, NULL, NULL, false);
+    g_free(buffer);
+}
+
 static void allwinner_h3_init(Object *obj)
 {
     AwH3State *s = AW_H3(obj);
diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
index 25bf85f8fc..9d4c79885e 100644
--- a/hw/arm/orangepi.c
+++ b/hw/arm/orangepi.c
@@ -95,6 +95,11 @@  static void orangepi_init(MachineState *machine)
     memory_region_add_subregion(get_system_memory(), s->h3->memmap[AW_H3_SDRAM],
                                 &s->sdram);
 
+    /* Load target kernel or start using BootROM */
+    if (!machine->kernel_filename && blk_is_available(blk)) {
+        /* Use Boot ROM to copy data from SD card to SRAM */
+        allwinner_h3_bootrom_setup(s->h3, blk, &error_fatal);
+    }
     orangepi_binfo.loader_start = s->h3->memmap[AW_H3_SDRAM];
     orangepi_binfo.ram_size = machine->ram_size;
     arm_load_kernel(ARM_CPU(first_cpu), machine, &orangepi_binfo);