diff mbox series

[v3,10/17] hw/arm/allwinner-h3: add Boot ROM support

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

Commit Message

Niek Linnenbank Jan. 8, 2020, 8 p.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.

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             |  3 +++
 3 files changed, 54 insertions(+)

Comments

Philippe Mathieu-Daudé Jan. 13, 2020, 11:28 p.m. UTC | #1
On 1/8/20 9:00 PM, 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.
> 
> 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             |  3 +++
>   3 files changed, 54 insertions(+)
> 
> diff --git a/include/hw/arm/allwinner-h3.h b/include/hw/arm/allwinner-h3.h
> index 5d74cca28e..4b66227ac4 100644
> --- a/include/hw/arm/allwinner-h3.h
> +++ b/include/hw/arm/allwinner-h3.h
> @@ -50,6 +50,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
> @@ -130,4 +131,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 e692432b4e..e7b768ad5b 100644
> --- a/hw/arm/allwinner-h3.c
> +++ b/hw/arm/allwinner-h3.c
> @@ -27,6 +27,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"
>   
> @@ -168,6 +169,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;

Why restrict to 32K? The A1 SRAM is 64K.

> +
> +    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 0eb52eb813..b722f49485 100644
> --- a/hw/arm/orangepi.c
> +++ b/hw/arm/orangepi.c
> @@ -93,6 +93,9 @@ static void orangepi_init(MachineState *machine)
>       if (bios_name) {
>           error_report("BIOS not supported for this machine");
>           exit(1);
> +    } else 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;
>
Niek Linnenbank Jan. 14, 2020, 11:10 p.m. UTC | #2
On Tue, Jan 14, 2020 at 12:28 AM Philippe Mathieu-Daudé <philmd@redhat.com>
wrote:

> On 1/8/20 9:00 PM, 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.
> >
> > 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             |  3 +++
> >   3 files changed, 54 insertions(+)
> >
> > diff --git a/include/hw/arm/allwinner-h3.h
> b/include/hw/arm/allwinner-h3.h
> > index 5d74cca28e..4b66227ac4 100644
> > --- a/include/hw/arm/allwinner-h3.h
> > +++ b/include/hw/arm/allwinner-h3.h
> > @@ -50,6 +50,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
> > @@ -130,4 +131,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 e692432b4e..e7b768ad5b 100644
> > --- a/hw/arm/allwinner-h3.c
> > +++ b/hw/arm/allwinner-h3.c
> > @@ -27,6 +27,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"
> >
> > @@ -168,6 +169,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;
>
> Why restrict to 32K? The A1 SRAM is 64K.
>

The reason is that the actual Boot ROM on the H3 also uses 32K:
    https://linux-sunxi.org/BROM

See the 'U-Boot SPL Limitations' table at the end of the page.

You can see the comment in the table there regarding the 32 KiB:
  "Sizes larger than 32 KiB are rejected by the BROM. Exactly 32 KiB is
fine, as verified by writing a special pattern at the end of the SPL and
checking it in the SRAM."

Probably it would not harm to increase it to the full size of the SRAM, but
I tried to model
the behavior as close to the real hardware as possible.

Regards,
Niek


> > +
> > +    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 0eb52eb813..b722f49485 100644
> > --- a/hw/arm/orangepi.c
> > +++ b/hw/arm/orangepi.c
> > @@ -93,6 +93,9 @@ static void orangepi_init(MachineState *machine)
> >       if (bios_name) {
> >           error_report("BIOS not supported for this machine");
> >           exit(1);
> > +    } else 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;
> >
>
>
Philippe Mathieu-Daudé Jan. 18, 2020, 9:09 a.m. UTC | #3
On 1/15/20 12:10 AM, Niek Linnenbank wrote:
> On Tue, Jan 14, 2020 at 12:28 AM Philippe Mathieu-Daudé 
> <philmd@redhat.com <mailto:philmd@redhat.com>> wrote:
> 
>     On 1/8/20 9:00 PM, 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.
>      >
>      > Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com
>     <mailto:nieklinnenbank@gmail.com>>
>      > ---
>      >   include/hw/arm/allwinner-h3.h | 23 +++++++++++++++++++++++
>      >   hw/arm/allwinner-h3.c         | 28 ++++++++++++++++++++++++++++
>      >   hw/arm/orangepi.c             |  3 +++
>      >   3 files changed, 54 insertions(+)
>      >
>      > diff --git a/include/hw/arm/allwinner-h3.h
>     b/include/hw/arm/allwinner-h3.h
>      > index 5d74cca28e..4b66227ac4 100644
>      > --- a/include/hw/arm/allwinner-h3.h
>      > +++ b/include/hw/arm/allwinner-h3.h
>      > @@ -50,6 +50,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
>      > @@ -130,4 +131,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 e692432b4e..e7b768ad5b 100644
>      > --- a/hw/arm/allwinner-h3.c
>      > +++ b/hw/arm/allwinner-h3.c
>      > @@ -27,6 +27,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"
>      >
>      > @@ -168,6 +169,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;
> 
>     Why restrict to 32K? The A1 SRAM is 64K.
> 
> 
> The reason is that the actual Boot ROM on the H3 also uses 32K:
> https://linux-sunxi.org/BROM
> 
> See the 'U-Boot SPL Limitations' table at the end of the page.
> 
> You can see the comment in the table there regarding the 32 KiB:
>    "Sizes larger than 32 KiB are rejected by the BROM. Exactly 32 KiB is 
> fine, as verified by writing a special pattern at the end of the SPL and 
> checking it in the SRAM."
> Probably it would not harm to increase it to the full size of the SRAM, 
> but I tried to model
> the behavior as close to the real hardware as possible.

OK, then please document this difference in the commit description - 
such "While the A1 SRAM is 64K, we limit to 32K because ..." - and add a 
reference to https://linux-sunxi.org/BROM#U-Boot_SPL_limitations
Niek Linnenbank Jan. 18, 2020, 10:28 p.m. UTC | #4
On Sat, Jan 18, 2020 at 10:09 AM Philippe Mathieu-Daudé <philmd@redhat.com>
wrote:

> On 1/15/20 12:10 AM, Niek Linnenbank wrote:
> > On Tue, Jan 14, 2020 at 12:28 AM Philippe Mathieu-Daudé
> > <philmd@redhat.com <mailto:philmd@redhat.com>> wrote:
> >
> >     On 1/8/20 9:00 PM, 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.
> >      >
> >      > Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com
> >     <mailto:nieklinnenbank@gmail.com>>
> >      > ---
> >      >   include/hw/arm/allwinner-h3.h | 23 +++++++++++++++++++++++
> >      >   hw/arm/allwinner-h3.c         | 28 ++++++++++++++++++++++++++++
> >      >   hw/arm/orangepi.c             |  3 +++
> >      >   3 files changed, 54 insertions(+)
> >      >
> >      > diff --git a/include/hw/arm/allwinner-h3.h
> >     b/include/hw/arm/allwinner-h3.h
> >      > index 5d74cca28e..4b66227ac4 100644
> >      > --- a/include/hw/arm/allwinner-h3.h
> >      > +++ b/include/hw/arm/allwinner-h3.h
> >      > @@ -50,6 +50,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
> >      > @@ -130,4 +131,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 e692432b4e..e7b768ad5b 100644
> >      > --- a/hw/arm/allwinner-h3.c
> >      > +++ b/hw/arm/allwinner-h3.c
> >      > @@ -27,6 +27,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"
> >      >
> >      > @@ -168,6 +169,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;
> >
> >     Why restrict to 32K? The A1 SRAM is 64K.
> >
> >
> > The reason is that the actual Boot ROM on the H3 also uses 32K:
> > https://linux-sunxi.org/BROM
> >
> > See the 'U-Boot SPL Limitations' table at the end of the page.
> >
> > You can see the comment in the table there regarding the 32 KiB:
> >    "Sizes larger than 32 KiB are rejected by the BROM. Exactly 32 KiB is
> > fine, as verified by writing a special pattern at the end of the SPL and
> > checking it in the SRAM."
> > Probably it would not harm to increase it to the full size of the SRAM,
> > but I tried to model
> > the behavior as close to the real hardware as possible.
>
> OK, then please document this difference in the commit description -
> such "While the A1 SRAM is 64K, we limit to 32K because ..." - and add a
> reference to https://linux-sunxi.org/BROM#U-Boot_SPL_limitations
>
> Agreed, I'll add this to the commit message.
diff mbox series

Patch

diff --git a/include/hw/arm/allwinner-h3.h b/include/hw/arm/allwinner-h3.h
index 5d74cca28e..4b66227ac4 100644
--- a/include/hw/arm/allwinner-h3.h
+++ b/include/hw/arm/allwinner-h3.h
@@ -50,6 +50,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
@@ -130,4 +131,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 e692432b4e..e7b768ad5b 100644
--- a/hw/arm/allwinner-h3.c
+++ b/hw/arm/allwinner-h3.c
@@ -27,6 +27,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"
 
@@ -168,6 +169,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 0eb52eb813..b722f49485 100644
--- a/hw/arm/orangepi.c
+++ b/hw/arm/orangepi.c
@@ -93,6 +93,9 @@  static void orangepi_init(MachineState *machine)
     if (bios_name) {
         error_report("BIOS not supported for this machine");
         exit(1);
+    } else 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;