diff mbox

[v4] hw/pc: Support system flash memory with -pflash parameter

Message ID 1310153845-4373-1-git-send-email-jordan.l.justen@intel.com
State New
Headers show

Commit Message

jordan.l.justen@intel.com July 8, 2011, 7:37 p.m. UTC
If -pflash is specified and -bios is specified then pflash will
be mapped just below the system rom using hw/pflash_cfi01.c.

If -pflash is specified on the command line, but -bios is
not specified, then 'bios.bin' will NOT be loaded, and
instead the -pflash flash image will be mapped just below
4GB in place of the normal rom image.

Signed-off-by: Jordan Justen <jordan.l.justen@intel.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
---
 default-configs/i386-softmmu.mak   |    1 +
 default-configs/x86_64-softmmu.mak |    1 +
 hw/pc.c                            |  161 +++++++++++++++++++++++++++---------
 3 files changed, 125 insertions(+), 38 deletions(-)

Comments

Jordan Justen July 16, 2011, 12:16 a.m. UTC | #1
Hi all,

Are there any concerns with this patch?

I haven't heard much feedback, except:
* Jes Sorensen - March 28 - code style
* Aurelien Jarno - April 18 - Reviewed-by

Thanks,

-Jordan

On Fri, Jul 8, 2011 at 12:37, Jordan Justen <jordan.l.justen@intel.com> wrote:
> If -pflash is specified and -bios is specified then pflash will
> be mapped just below the system rom using hw/pflash_cfi01.c.
>
> If -pflash is specified on the command line, but -bios is
> not specified, then 'bios.bin' will NOT be loaded, and
> instead the -pflash flash image will be mapped just below
> 4GB in place of the normal rom image.
>
> Signed-off-by: Jordan Justen <jordan.l.justen@intel.com>
> Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
> ---
>  default-configs/i386-softmmu.mak   |    1 +
>  default-configs/x86_64-softmmu.mak |    1 +
>  hw/pc.c                            |  161 +++++++++++++++++++++++++++---------
>  3 files changed, 125 insertions(+), 38 deletions(-)
>
> diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
> index 55589fa..8697cd4 100644
> --- a/default-configs/i386-softmmu.mak
> +++ b/default-configs/i386-softmmu.mak
> @@ -21,3 +21,4 @@ CONFIG_PIIX_PCI=y
>  CONFIG_SOUND=y
>  CONFIG_HPET=y
>  CONFIG_APPLESMC=y
> +CONFIG_PFLASH_CFI01=y
> diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
> index 8895028..eca9284 100644
> --- a/default-configs/x86_64-softmmu.mak
> +++ b/default-configs/x86_64-softmmu.mak
> @@ -21,3 +21,4 @@ CONFIG_PIIX_PCI=y
>  CONFIG_SOUND=y
>  CONFIG_HPET=y
>  CONFIG_APPLESMC=y
> +CONFIG_PFLASH_CFI01=y
> diff --git a/hw/pc.c b/hw/pc.c
> index a3e8539..e25354f 100644
> --- a/hw/pc.c
> +++ b/hw/pc.c
> @@ -41,6 +41,7 @@
>  #include "sysemu.h"
>  #include "blockdev.h"
>  #include "ui/qemu-spice.h"
> +#include "flash.h"
>
>  /* output Bochs bios info messages */
>  //#define DEBUG_BIOS
> @@ -957,70 +958,154 @@ void pc_cpus_init(const char *cpu_model)
>     }
>  }
>
> -void pc_memory_init(const char *kernel_filename,
> -                    const char *kernel_cmdline,
> -                    const char *initrd_filename,
> -                    ram_addr_t below_4g_mem_size,
> -                    ram_addr_t above_4g_mem_size)
> +static void pc_isa_bios_init(ram_addr_t ram_offset, int ram_size)
>  {
> -    char *filename;
> -    int ret, linux_boot, i;
> -    ram_addr_t ram_addr, bios_offset, option_rom_offset;
> -    int bios_size, isa_bios_size;
> -    void *fw_cfg;
> -
> -    linux_boot = (kernel_filename != NULL);
> +    int isa_bios_size;
>
> -    /* allocate RAM */
> -    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
> -                              below_4g_mem_size + above_4g_mem_size);
> -    cpu_register_physical_memory(0, 0xa0000, ram_addr);
> -    cpu_register_physical_memory(0x100000,
> -                 below_4g_mem_size - 0x100000,
> -                 ram_addr + 0x100000);
> -    if (above_4g_mem_size > 0) {
> -        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
> -                                     ram_addr + below_4g_mem_size);
> +    /* map the last 128KB of the BIOS in ISA space */
> +    isa_bios_size = ram_size;
> +    if (isa_bios_size > (128 * 1024)) {
> +        isa_bios_size = 128 * 1024;
>     }
> +    ram_offset = ram_offset + ram_size - isa_bios_size;
> +    cpu_register_physical_memory(0x100000 - isa_bios_size,
> +                                 isa_bios_size,
> +                                 ram_offset | IO_MEM_ROM);
> +}
> +
> +static int pc_system_rom_init(void)
> +{
> +    int ret;
> +    int bios_size;
> +    ram_addr_t bios_offset;
> +    char *filename;
>
>     /* BIOS load */
> -    if (bios_name == NULL)
> +    if (bios_name == NULL) {
>         bios_name = BIOS_FILENAME;
> +    }
>     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
>     if (filename) {
>         bios_size = get_image_size(filename);
>     } else {
>         bios_size = -1;
>     }
> -    if (bios_size <= 0 ||
> -        (bios_size % 65536) != 0) {
> -        goto bios_error;
> +
> +    if (bios_size <= 0 || (bios_size % 65536) != 0) {
> +        ret = -1;
> +    } else {
> +        bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
> +        ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
>     }
> -    bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
> -    ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
> +
>     if (ret != 0) {
> -    bios_error:
>         fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name);
>         exit(1);
>     }
> +
>     if (filename) {
>         qemu_free(filename);
>     }
> -    /* map the last 128KB of the BIOS in ISA space */
> -    isa_bios_size = bios_size;
> -    if (isa_bios_size > (128 * 1024))
> -        isa_bios_size = 128 * 1024;
> -    cpu_register_physical_memory(0x100000 - isa_bios_size,
> -                                 isa_bios_size,
> -                                 (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
>
> -    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
> -    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE, option_rom_offset);
> +    pc_isa_bios_init(bios_offset, bios_size);
>
>     /* map all the bios at the top of memory */
>     cpu_register_physical_memory((uint32_t)(-bios_size),
>                                  bios_size, bios_offset | IO_MEM_ROM);
>
> +    return bios_size;
> +}
> +
> +static void pc_system_flash_init(DriveInfo *pflash_drv, int rom_size)
> +{
> +    BlockDriverState *bdrv;
> +    int64_t size;
> +    target_phys_addr_t phys_addr;
> +    ram_addr_t addr;
> +    int sector_bits, sector_size;
> +
> +    bdrv = NULL;
> +
> +    bdrv = pflash_drv->bdrv;
> +    size = bdrv_getlength(pflash_drv->bdrv);
> +    sector_bits = 12;
> +    sector_size = 1 << sector_bits;
> +
> +    if ((size % sector_size) != 0) {
> +        fprintf(stderr,
> +                "qemu: -pflash size must be a multiple of 0x%x\n",
> +                sector_size);
> +        exit(1);
> +    }
> +
> +    phys_addr = 0x100000000ULL - rom_size - size;
> +    addr = qemu_ram_alloc(NULL, "system.flash", size);
> +    DPRINTF("flash addr: 0x%lx\n", (int64_t)phys_addr);
> +    pflash_cfi01_register(phys_addr, addr, bdrv,
> +                          sector_size, size >> sector_bits,
> +                          4, 0x0000, 0x0000, 0x0000, 0x0000, 0);
> +
> +    if (rom_size == 0) {
> +        pc_isa_bios_init(addr, size);
> +    }
> +}
> +
> +static void pc_system_firmware_init(void)
> +{
> +    int flash_present, rom_present;
> +    int rom_size;
> +    DriveInfo *pflash_drv;
> +
> +    pflash_drv = drive_get(IF_PFLASH, 0, 0);
> +    flash_present = (pflash_drv != NULL);
> +
> +    /* Load rom if -bios is used or if -pflash is not used */
> +    rom_present = ((bios_name != NULL) || !flash_present);
> +
> +    /* If rom is present, then it is mapped just below 4GB */
> +    if (rom_present) {
> +        rom_size = pc_system_rom_init();
> +    } else {
> +        rom_size = 0;
> +    }
> +
> +    /* If flash is present, then it is mapped just below the rom, or
> +     * just below 4GB when rom is not present. */
> +    if (flash_present) {
> +        pc_system_flash_init(pflash_drv, rom_size);
> +    }
> +}
> +
> +void pc_memory_init(const char *kernel_filename,
> +                    const char *kernel_cmdline,
> +                    const char *initrd_filename,
> +                    ram_addr_t below_4g_mem_size,
> +                    ram_addr_t above_4g_mem_size)
> +{
> +    int linux_boot, i;
> +    ram_addr_t ram_addr, option_rom_offset;
> +    void *fw_cfg;
> +
> +    linux_boot = (kernel_filename != NULL);
> +
> +    /* allocate RAM */
> +    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
> +                              below_4g_mem_size + above_4g_mem_size);
> +    cpu_register_physical_memory(0, 0xa0000, ram_addr);
> +    cpu_register_physical_memory(0x100000,
> +                 below_4g_mem_size - 0x100000,
> +                 ram_addr + 0x100000);
> +    if (above_4g_mem_size > 0) {
> +        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
> +                                     ram_addr + below_4g_mem_size);
> +    }
> +
> +    /* Initialize ROM or flash ranges for PC firmware */
> +    pc_system_firmware_init();
> +
> +    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
> +    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE, option_rom_offset);
> +
>     fw_cfg = bochs_bios_init();
>     rom_set_fw(fw_cfg);
>
> --
> 1.7.1
>
>
>
Anthony Liguori July 23, 2011, 3:51 p.m. UTC | #2
On 07/08/2011 02:37 PM, Jordan Justen wrote:
> If -pflash is specified and -bios is specified then pflash will
> be mapped just below the system rom using hw/pflash_cfi01.c.
>
> If -pflash is specified on the command line, but -bios is
> not specified, then 'bios.bin' will NOT be loaded, and
> instead the -pflash flash image will be mapped just below
> 4GB in place of the normal rom image.

This is way too tied to the pc platform to be this generic.

I think a better approach would be to default to having unit=0 of 
IF_PFLASH default to a read-only BDS that points to bios.bin.  -bios 
would just be a short cut to use a different file name but you should be 
able to override with -drive too.

And to really simplify things, you could add a readonly flag to -bios 
such that you could do:

-bios foo.img,readonly=off

Which is what I think you're looking for semantically.

Regards,

Anthony Liguori

>
> Signed-off-by: Jordan Justen<jordan.l.justen@intel.com>
> Reviewed-by: Aurelien Jarno<aurelien@aurel32.net>



> ---
>   default-configs/i386-softmmu.mak   |    1 +
>   default-configs/x86_64-softmmu.mak |    1 +
>   hw/pc.c                            |  161 +++++++++++++++++++++++++++---------
>   3 files changed, 125 insertions(+), 38 deletions(-)
>
> diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
> index 55589fa..8697cd4 100644
> --- a/default-configs/i386-softmmu.mak
> +++ b/default-configs/i386-softmmu.mak
> @@ -21,3 +21,4 @@ CONFIG_PIIX_PCI=y
>   CONFIG_SOUND=y
>   CONFIG_HPET=y
>   CONFIG_APPLESMC=y
> +CONFIG_PFLASH_CFI01=y
> diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
> index 8895028..eca9284 100644
> --- a/default-configs/x86_64-softmmu.mak
> +++ b/default-configs/x86_64-softmmu.mak
> @@ -21,3 +21,4 @@ CONFIG_PIIX_PCI=y
>   CONFIG_SOUND=y
>   CONFIG_HPET=y
>   CONFIG_APPLESMC=y
> +CONFIG_PFLASH_CFI01=y
> diff --git a/hw/pc.c b/hw/pc.c
> index a3e8539..e25354f 100644
> --- a/hw/pc.c
> +++ b/hw/pc.c
> @@ -41,6 +41,7 @@
>   #include "sysemu.h"
>   #include "blockdev.h"
>   #include "ui/qemu-spice.h"
> +#include "flash.h"
>
>   /* output Bochs bios info messages */
>   //#define DEBUG_BIOS
> @@ -957,70 +958,154 @@ void pc_cpus_init(const char *cpu_model)
>       }
>   }
>
> -void pc_memory_init(const char *kernel_filename,
> -                    const char *kernel_cmdline,
> -                    const char *initrd_filename,
> -                    ram_addr_t below_4g_mem_size,
> -                    ram_addr_t above_4g_mem_size)
> +static void pc_isa_bios_init(ram_addr_t ram_offset, int ram_size)
>   {
> -    char *filename;
> -    int ret, linux_boot, i;
> -    ram_addr_t ram_addr, bios_offset, option_rom_offset;
> -    int bios_size, isa_bios_size;
> -    void *fw_cfg;
> -
> -    linux_boot = (kernel_filename != NULL);
> +    int isa_bios_size;
>
> -    /* allocate RAM */
> -    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
> -                              below_4g_mem_size + above_4g_mem_size);
> -    cpu_register_physical_memory(0, 0xa0000, ram_addr);
> -    cpu_register_physical_memory(0x100000,
> -                 below_4g_mem_size - 0x100000,
> -                 ram_addr + 0x100000);
> -    if (above_4g_mem_size>  0) {
> -        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
> -                                     ram_addr + below_4g_mem_size);
> +    /* map the last 128KB of the BIOS in ISA space */
> +    isa_bios_size = ram_size;
> +    if (isa_bios_size>  (128 * 1024)) {
> +        isa_bios_size = 128 * 1024;
>       }
> +    ram_offset = ram_offset + ram_size - isa_bios_size;
> +    cpu_register_physical_memory(0x100000 - isa_bios_size,
> +                                 isa_bios_size,
> +                                 ram_offset | IO_MEM_ROM);
> +}
> +
> +static int pc_system_rom_init(void)
> +{
> +    int ret;
> +    int bios_size;
> +    ram_addr_t bios_offset;
> +    char *filename;
>
>       /* BIOS load */
> -    if (bios_name == NULL)
> +    if (bios_name == NULL) {
>           bios_name = BIOS_FILENAME;
> +    }
>       filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
>       if (filename) {
>           bios_size = get_image_size(filename);
>       } else {
>           bios_size = -1;
>       }
> -    if (bios_size<= 0 ||
> -        (bios_size % 65536) != 0) {
> -        goto bios_error;
> +
> +    if (bios_size<= 0 || (bios_size % 65536) != 0) {
> +        ret = -1;
> +    } else {
> +        bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
> +        ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
>       }
> -    bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
> -    ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
> +
>       if (ret != 0) {
> -    bios_error:
>           fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name);
>           exit(1);
>       }
> +
>       if (filename) {
>           qemu_free(filename);
>       }
> -    /* map the last 128KB of the BIOS in ISA space */
> -    isa_bios_size = bios_size;
> -    if (isa_bios_size>  (128 * 1024))
> -        isa_bios_size = 128 * 1024;
> -    cpu_register_physical_memory(0x100000 - isa_bios_size,
> -                                 isa_bios_size,
> -                                 (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
>
> -    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
> -    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE, option_rom_offset);
> +    pc_isa_bios_init(bios_offset, bios_size);
>
>       /* map all the bios at the top of memory */
>       cpu_register_physical_memory((uint32_t)(-bios_size),
>                                    bios_size, bios_offset | IO_MEM_ROM);
>
> +    return bios_size;
> +}
> +
> +static void pc_system_flash_init(DriveInfo *pflash_drv, int rom_size)
> +{
> +    BlockDriverState *bdrv;
> +    int64_t size;
> +    target_phys_addr_t phys_addr;
> +    ram_addr_t addr;
> +    int sector_bits, sector_size;
> +
> +    bdrv = NULL;
> +
> +    bdrv = pflash_drv->bdrv;
> +    size = bdrv_getlength(pflash_drv->bdrv);
> +    sector_bits = 12;
> +    sector_size = 1<<  sector_bits;
> +
> +    if ((size % sector_size) != 0) {
> +        fprintf(stderr,
> +                "qemu: -pflash size must be a multiple of 0x%x\n",
> +                sector_size);
> +        exit(1);
> +    }
> +
> +    phys_addr = 0x100000000ULL - rom_size - size;
> +    addr = qemu_ram_alloc(NULL, "system.flash", size);
> +    DPRINTF("flash addr: 0x%lx\n", (int64_t)phys_addr);
> +    pflash_cfi01_register(phys_addr, addr, bdrv,
> +                          sector_size, size>>  sector_bits,
> +                          4, 0x0000, 0x0000, 0x0000, 0x0000, 0);
> +
> +    if (rom_size == 0) {
> +        pc_isa_bios_init(addr, size);
> +    }
> +}
> +
> +static void pc_system_firmware_init(void)
> +{
> +    int flash_present, rom_present;
> +    int rom_size;
> +    DriveInfo *pflash_drv;
> +
> +    pflash_drv = drive_get(IF_PFLASH, 0, 0);
> +    flash_present = (pflash_drv != NULL);
> +
> +    /* Load rom if -bios is used or if -pflash is not used */
> +    rom_present = ((bios_name != NULL) || !flash_present);
> +
> +    /* If rom is present, then it is mapped just below 4GB */
> +    if (rom_present) {
> +        rom_size = pc_system_rom_init();
> +    } else {
> +        rom_size = 0;
> +    }
> +
> +    /* If flash is present, then it is mapped just below the rom, or
> +     * just below 4GB when rom is not present. */
> +    if (flash_present) {
> +        pc_system_flash_init(pflash_drv, rom_size);
> +    }
> +}
> +
> +void pc_memory_init(const char *kernel_filename,
> +                    const char *kernel_cmdline,
> +                    const char *initrd_filename,
> +                    ram_addr_t below_4g_mem_size,
> +                    ram_addr_t above_4g_mem_size)
> +{
> +    int linux_boot, i;
> +    ram_addr_t ram_addr, option_rom_offset;
> +    void *fw_cfg;
> +
> +    linux_boot = (kernel_filename != NULL);
> +
> +    /* allocate RAM */
> +    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
> +                              below_4g_mem_size + above_4g_mem_size);
> +    cpu_register_physical_memory(0, 0xa0000, ram_addr);
> +    cpu_register_physical_memory(0x100000,
> +                 below_4g_mem_size - 0x100000,
> +                 ram_addr + 0x100000);
> +    if (above_4g_mem_size>  0) {
> +        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
> +                                     ram_addr + below_4g_mem_size);
> +    }
> +
> +    /* Initialize ROM or flash ranges for PC firmware */
> +    pc_system_firmware_init();
> +
> +    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
> +    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE, option_rom_offset);
> +
>       fw_cfg = bochs_bios_init();
>       rom_set_fw(fw_cfg);
>
Jordan Justen July 23, 2011, 8:19 p.m. UTC | #3
On Sat, Jul 23, 2011 at 08:51, Anthony Liguori <anthony@codemonkey.ws> wrote:
> On 07/08/2011 02:37 PM, Jordan Justen wrote:
>>
>> If -pflash is specified and -bios is specified then pflash will
>> be mapped just below the system rom using hw/pflash_cfi01.c.
>>
>> If -pflash is specified on the command line, but -bios is
>> not specified, then 'bios.bin' will NOT be loaded, and
>> instead the -pflash flash image will be mapped just below
>> 4GB in place of the normal rom image.
>
> This is way too tied to the pc platform to be this generic.
>
> I think a better approach would be to default to having unit=0 of IF_PFLASH
> default to a read-only BDS that points to bios.bin.  -bios would just be a
> short cut to use a different file name but you should be able to override
> with -drive too.
>
> And to really simplify things, you could add a readonly flag to -bios such
> that you could do:
>
> -bios foo.img,readonly=off
>
> Which is what I think you're looking for semantically.

There seemed to be some feedback on the list interested in preserving
a read-only firmware, and just adding a flash region.

So, for example, the firmware could be read from a common system
location like is generally done with bios.bin today, and VM instance
specific flash region could still be added.

If the entire firmware is moved to a separate VM instance specific
flash, then firmware update also gets complicated.  It is no longer
just a matter of updating the qemu firmware package in your distro's
package management system.

What about taking your idea, but adding a second drive that would be
mapped just below the 1st if it is specified with -drive?

Thanks,

-Jordan

>
> Regards,
>
> Anthony Liguori
>
>>
>> Signed-off-by: Jordan Justen<jordan.l.justen@intel.com>
>> Reviewed-by: Aurelien Jarno<aurelien@aurel32.net>
>
>
>
>> ---
>>  default-configs/i386-softmmu.mak   |    1 +
>>  default-configs/x86_64-softmmu.mak |    1 +
>>  hw/pc.c                            |  161
>> +++++++++++++++++++++++++++---------
>>  3 files changed, 125 insertions(+), 38 deletions(-)
>>
>> diff --git a/default-configs/i386-softmmu.mak
>> b/default-configs/i386-softmmu.mak
>> index 55589fa..8697cd4 100644
>> --- a/default-configs/i386-softmmu.mak
>> +++ b/default-configs/i386-softmmu.mak
>> @@ -21,3 +21,4 @@ CONFIG_PIIX_PCI=y
>>  CONFIG_SOUND=y
>>  CONFIG_HPET=y
>>  CONFIG_APPLESMC=y
>> +CONFIG_PFLASH_CFI01=y
>> diff --git a/default-configs/x86_64-softmmu.mak
>> b/default-configs/x86_64-softmmu.mak
>> index 8895028..eca9284 100644
>> --- a/default-configs/x86_64-softmmu.mak
>> +++ b/default-configs/x86_64-softmmu.mak
>> @@ -21,3 +21,4 @@ CONFIG_PIIX_PCI=y
>>  CONFIG_SOUND=y
>>  CONFIG_HPET=y
>>  CONFIG_APPLESMC=y
>> +CONFIG_PFLASH_CFI01=y
>> diff --git a/hw/pc.c b/hw/pc.c
>> index a3e8539..e25354f 100644
>> --- a/hw/pc.c
>> +++ b/hw/pc.c
>> @@ -41,6 +41,7 @@
>>  #include "sysemu.h"
>>  #include "blockdev.h"
>>  #include "ui/qemu-spice.h"
>> +#include "flash.h"
>>
>>  /* output Bochs bios info messages */
>>  //#define DEBUG_BIOS
>> @@ -957,70 +958,154 @@ void pc_cpus_init(const char *cpu_model)
>>      }
>>  }
>>
>> -void pc_memory_init(const char *kernel_filename,
>> -                    const char *kernel_cmdline,
>> -                    const char *initrd_filename,
>> -                    ram_addr_t below_4g_mem_size,
>> -                    ram_addr_t above_4g_mem_size)
>> +static void pc_isa_bios_init(ram_addr_t ram_offset, int ram_size)
>>  {
>> -    char *filename;
>> -    int ret, linux_boot, i;
>> -    ram_addr_t ram_addr, bios_offset, option_rom_offset;
>> -    int bios_size, isa_bios_size;
>> -    void *fw_cfg;
>> -
>> -    linux_boot = (kernel_filename != NULL);
>> +    int isa_bios_size;
>>
>> -    /* allocate RAM */
>> -    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
>> -                              below_4g_mem_size + above_4g_mem_size);
>> -    cpu_register_physical_memory(0, 0xa0000, ram_addr);
>> -    cpu_register_physical_memory(0x100000,
>> -                 below_4g_mem_size - 0x100000,
>> -                 ram_addr + 0x100000);
>> -    if (above_4g_mem_size>  0) {
>> -        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
>> -                                     ram_addr + below_4g_mem_size);
>> +    /* map the last 128KB of the BIOS in ISA space */
>> +    isa_bios_size = ram_size;
>> +    if (isa_bios_size>  (128 * 1024)) {
>> +        isa_bios_size = 128 * 1024;
>>      }
>> +    ram_offset = ram_offset + ram_size - isa_bios_size;
>> +    cpu_register_physical_memory(0x100000 - isa_bios_size,
>> +                                 isa_bios_size,
>> +                                 ram_offset | IO_MEM_ROM);
>> +}
>> +
>> +static int pc_system_rom_init(void)
>> +{
>> +    int ret;
>> +    int bios_size;
>> +    ram_addr_t bios_offset;
>> +    char *filename;
>>
>>      /* BIOS load */
>> -    if (bios_name == NULL)
>> +    if (bios_name == NULL) {
>>          bios_name = BIOS_FILENAME;
>> +    }
>>      filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
>>      if (filename) {
>>          bios_size = get_image_size(filename);
>>      } else {
>>          bios_size = -1;
>>      }
>> -    if (bios_size<= 0 ||
>> -        (bios_size % 65536) != 0) {
>> -        goto bios_error;
>> +
>> +    if (bios_size<= 0 || (bios_size % 65536) != 0) {
>> +        ret = -1;
>> +    } else {
>> +        bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
>> +        ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
>>      }
>> -    bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
>> -    ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
>> +
>>      if (ret != 0) {
>> -    bios_error:
>>          fprintf(stderr, "qemu: could not load PC BIOS '%s'\n",
>> bios_name);
>>          exit(1);
>>      }
>> +
>>      if (filename) {
>>          qemu_free(filename);
>>      }
>> -    /* map the last 128KB of the BIOS in ISA space */
>> -    isa_bios_size = bios_size;
>> -    if (isa_bios_size>  (128 * 1024))
>> -        isa_bios_size = 128 * 1024;
>> -    cpu_register_physical_memory(0x100000 - isa_bios_size,
>> -                                 isa_bios_size,
>> -                                 (bios_offset + bios_size -
>> isa_bios_size) | IO_MEM_ROM);
>>
>> -    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
>> -    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE,
>> option_rom_offset);
>> +    pc_isa_bios_init(bios_offset, bios_size);
>>
>>      /* map all the bios at the top of memory */
>>      cpu_register_physical_memory((uint32_t)(-bios_size),
>>                                   bios_size, bios_offset | IO_MEM_ROM);
>>
>> +    return bios_size;
>> +}
>> +
>> +static void pc_system_flash_init(DriveInfo *pflash_drv, int rom_size)
>> +{
>> +    BlockDriverState *bdrv;
>> +    int64_t size;
>> +    target_phys_addr_t phys_addr;
>> +    ram_addr_t addr;
>> +    int sector_bits, sector_size;
>> +
>> +    bdrv = NULL;
>> +
>> +    bdrv = pflash_drv->bdrv;
>> +    size = bdrv_getlength(pflash_drv->bdrv);
>> +    sector_bits = 12;
>> +    sector_size = 1<<  sector_bits;
>> +
>> +    if ((size % sector_size) != 0) {
>> +        fprintf(stderr,
>> +                "qemu: -pflash size must be a multiple of 0x%x\n",
>> +                sector_size);
>> +        exit(1);
>> +    }
>> +
>> +    phys_addr = 0x100000000ULL - rom_size - size;
>> +    addr = qemu_ram_alloc(NULL, "system.flash", size);
>> +    DPRINTF("flash addr: 0x%lx\n", (int64_t)phys_addr);
>> +    pflash_cfi01_register(phys_addr, addr, bdrv,
>> +                          sector_size, size>>  sector_bits,
>> +                          4, 0x0000, 0x0000, 0x0000, 0x0000, 0);
>> +
>> +    if (rom_size == 0) {
>> +        pc_isa_bios_init(addr, size);
>> +    }
>> +}
>> +
>> +static void pc_system_firmware_init(void)
>> +{
>> +    int flash_present, rom_present;
>> +    int rom_size;
>> +    DriveInfo *pflash_drv;
>> +
>> +    pflash_drv = drive_get(IF_PFLASH, 0, 0);
>> +    flash_present = (pflash_drv != NULL);
>> +
>> +    /* Load rom if -bios is used or if -pflash is not used */
>> +    rom_present = ((bios_name != NULL) || !flash_present);
>> +
>> +    /* If rom is present, then it is mapped just below 4GB */
>> +    if (rom_present) {
>> +        rom_size = pc_system_rom_init();
>> +    } else {
>> +        rom_size = 0;
>> +    }
>> +
>> +    /* If flash is present, then it is mapped just below the rom, or
>> +     * just below 4GB when rom is not present. */
>> +    if (flash_present) {
>> +        pc_system_flash_init(pflash_drv, rom_size);
>> +    }
>> +}
>> +
>> +void pc_memory_init(const char *kernel_filename,
>> +                    const char *kernel_cmdline,
>> +                    const char *initrd_filename,
>> +                    ram_addr_t below_4g_mem_size,
>> +                    ram_addr_t above_4g_mem_size)
>> +{
>> +    int linux_boot, i;
>> +    ram_addr_t ram_addr, option_rom_offset;
>> +    void *fw_cfg;
>> +
>> +    linux_boot = (kernel_filename != NULL);
>> +
>> +    /* allocate RAM */
>> +    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
>> +                              below_4g_mem_size + above_4g_mem_size);
>> +    cpu_register_physical_memory(0, 0xa0000, ram_addr);
>> +    cpu_register_physical_memory(0x100000,
>> +                 below_4g_mem_size - 0x100000,
>> +                 ram_addr + 0x100000);
>> +    if (above_4g_mem_size>  0) {
>> +        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
>> +                                     ram_addr + below_4g_mem_size);
>> +    }
>> +
>> +    /* Initialize ROM or flash ranges for PC firmware */
>> +    pc_system_firmware_init();
>> +
>> +    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
>> +    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE,
>> option_rom_offset);
>> +
>>      fw_cfg = bochs_bios_init();
>>      rom_set_fw(fw_cfg);
>>
>
>
>
Anthony Liguori July 23, 2011, 9:25 p.m. UTC | #4
On 07/23/2011 03:19 PM, Jordan Justen wrote:
> On Sat, Jul 23, 2011 at 08:51, Anthony Liguori<anthony@codemonkey.ws>  wrote:
>> On 07/08/2011 02:37 PM, Jordan Justen wrote:
>>>
>>> If -pflash is specified and -bios is specified then pflash will
>>> be mapped just below the system rom using hw/pflash_cfi01.c.
>>>
>>> If -pflash is specified on the command line, but -bios is
>>> not specified, then 'bios.bin' will NOT be loaded, and
>>> instead the -pflash flash image will be mapped just below
>>> 4GB in place of the normal rom image.
>>
>> This is way too tied to the pc platform to be this generic.
>>
>> I think a better approach would be to default to having unit=0 of IF_PFLASH
>> default to a read-only BDS that points to bios.bin.  -bios would just be a
>> short cut to use a different file name but you should be able to override
>> with -drive too.
>>
>> And to really simplify things, you could add a readonly flag to -bios such
>> that you could do:
>>
>> -bios foo.img,readonly=off
>>
>> Which is what I think you're looking for semantically.
>
> There seemed to be some feedback on the list interested in preserving
> a read-only firmware, and just adding a flash region.
>
> So, for example, the firmware could be read from a common system
> location like is generally done with bios.bin today, and VM instance
> specific flash region could still be added.

You can have multiple flash regions.

You're introducing two modes.  In one mode, we emulate a flash device 
and expose it for the BIOS ROM.  In the second mode, we don't emulate a 
device but we expose the BIOS ROM based on a file in a shared read-only 
location.

I'm suggesting always emulating a flash device, but by default make the 
device read-only and have it be loaded from a file in a shared read-only 
location.

That means we have a single code path and a consistent view from a 
management tooling perspective.  IOW, management tools will always see 
that there is a BIOS block device, and they need to worry about making 
sure that BIOS block device is there.

>
> If the entire firmware is moved to a separate VM instance specific
> flash, then firmware update also gets complicated.  It is no longer
> just a matter of updating the qemu firmware package in your distro's
> package management system.

I think the bit your misunderstanding is that you should default the 
firmware to be created from a common file as a read-only device.

Regards,

Anthony Liguori

>
> What about taking your idea, but adding a second drive that would be
> mapped just below the 1st if it is specified with -drive?
>
> Thanks,
>
> -Jordan
>
>>
>> Regards,
>>
>> Anthony Liguori
>>
>>>
>>> Signed-off-by: Jordan Justen<jordan.l.justen@intel.com>
>>> Reviewed-by: Aurelien Jarno<aurelien@aurel32.net>
>>
>>
>>
>>> ---
>>>   default-configs/i386-softmmu.mak   |    1 +
>>>   default-configs/x86_64-softmmu.mak |    1 +
>>>   hw/pc.c                            |  161
>>> +++++++++++++++++++++++++++---------
>>>   3 files changed, 125 insertions(+), 38 deletions(-)
>>>
>>> diff --git a/default-configs/i386-softmmu.mak
>>> b/default-configs/i386-softmmu.mak
>>> index 55589fa..8697cd4 100644
>>> --- a/default-configs/i386-softmmu.mak
>>> +++ b/default-configs/i386-softmmu.mak
>>> @@ -21,3 +21,4 @@ CONFIG_PIIX_PCI=y
>>>   CONFIG_SOUND=y
>>>   CONFIG_HPET=y
>>>   CONFIG_APPLESMC=y
>>> +CONFIG_PFLASH_CFI01=y
>>> diff --git a/default-configs/x86_64-softmmu.mak
>>> b/default-configs/x86_64-softmmu.mak
>>> index 8895028..eca9284 100644
>>> --- a/default-configs/x86_64-softmmu.mak
>>> +++ b/default-configs/x86_64-softmmu.mak
>>> @@ -21,3 +21,4 @@ CONFIG_PIIX_PCI=y
>>>   CONFIG_SOUND=y
>>>   CONFIG_HPET=y
>>>   CONFIG_APPLESMC=y
>>> +CONFIG_PFLASH_CFI01=y
>>> diff --git a/hw/pc.c b/hw/pc.c
>>> index a3e8539..e25354f 100644
>>> --- a/hw/pc.c
>>> +++ b/hw/pc.c
>>> @@ -41,6 +41,7 @@
>>>   #include "sysemu.h"
>>>   #include "blockdev.h"
>>>   #include "ui/qemu-spice.h"
>>> +#include "flash.h"
>>>
>>>   /* output Bochs bios info messages */
>>>   //#define DEBUG_BIOS
>>> @@ -957,70 +958,154 @@ void pc_cpus_init(const char *cpu_model)
>>>       }
>>>   }
>>>
>>> -void pc_memory_init(const char *kernel_filename,
>>> -                    const char *kernel_cmdline,
>>> -                    const char *initrd_filename,
>>> -                    ram_addr_t below_4g_mem_size,
>>> -                    ram_addr_t above_4g_mem_size)
>>> +static void pc_isa_bios_init(ram_addr_t ram_offset, int ram_size)
>>>   {
>>> -    char *filename;
>>> -    int ret, linux_boot, i;
>>> -    ram_addr_t ram_addr, bios_offset, option_rom_offset;
>>> -    int bios_size, isa_bios_size;
>>> -    void *fw_cfg;
>>> -
>>> -    linux_boot = (kernel_filename != NULL);
>>> +    int isa_bios_size;
>>>
>>> -    /* allocate RAM */
>>> -    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
>>> -                              below_4g_mem_size + above_4g_mem_size);
>>> -    cpu_register_physical_memory(0, 0xa0000, ram_addr);
>>> -    cpu_register_physical_memory(0x100000,
>>> -                 below_4g_mem_size - 0x100000,
>>> -                 ram_addr + 0x100000);
>>> -    if (above_4g_mem_size>    0) {
>>> -        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
>>> -                                     ram_addr + below_4g_mem_size);
>>> +    /* map the last 128KB of the BIOS in ISA space */
>>> +    isa_bios_size = ram_size;
>>> +    if (isa_bios_size>    (128 * 1024)) {
>>> +        isa_bios_size = 128 * 1024;
>>>       }
>>> +    ram_offset = ram_offset + ram_size - isa_bios_size;
>>> +    cpu_register_physical_memory(0x100000 - isa_bios_size,
>>> +                                 isa_bios_size,
>>> +                                 ram_offset | IO_MEM_ROM);
>>> +}
>>> +
>>> +static int pc_system_rom_init(void)
>>> +{
>>> +    int ret;
>>> +    int bios_size;
>>> +    ram_addr_t bios_offset;
>>> +    char *filename;
>>>
>>>       /* BIOS load */
>>> -    if (bios_name == NULL)
>>> +    if (bios_name == NULL) {
>>>           bios_name = BIOS_FILENAME;
>>> +    }
>>>       filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
>>>       if (filename) {
>>>           bios_size = get_image_size(filename);
>>>       } else {
>>>           bios_size = -1;
>>>       }
>>> -    if (bios_size<= 0 ||
>>> -        (bios_size % 65536) != 0) {
>>> -        goto bios_error;
>>> +
>>> +    if (bios_size<= 0 || (bios_size % 65536) != 0) {
>>> +        ret = -1;
>>> +    } else {
>>> +        bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
>>> +        ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
>>>       }
>>> -    bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
>>> -    ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
>>> +
>>>       if (ret != 0) {
>>> -    bios_error:
>>>           fprintf(stderr, "qemu: could not load PC BIOS '%s'\n",
>>> bios_name);
>>>           exit(1);
>>>       }
>>> +
>>>       if (filename) {
>>>           qemu_free(filename);
>>>       }
>>> -    /* map the last 128KB of the BIOS in ISA space */
>>> -    isa_bios_size = bios_size;
>>> -    if (isa_bios_size>    (128 * 1024))
>>> -        isa_bios_size = 128 * 1024;
>>> -    cpu_register_physical_memory(0x100000 - isa_bios_size,
>>> -                                 isa_bios_size,
>>> -                                 (bios_offset + bios_size -
>>> isa_bios_size) | IO_MEM_ROM);
>>>
>>> -    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
>>> -    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE,
>>> option_rom_offset);
>>> +    pc_isa_bios_init(bios_offset, bios_size);
>>>
>>>       /* map all the bios at the top of memory */
>>>       cpu_register_physical_memory((uint32_t)(-bios_size),
>>>                                    bios_size, bios_offset | IO_MEM_ROM);
>>>
>>> +    return bios_size;
>>> +}
>>> +
>>> +static void pc_system_flash_init(DriveInfo *pflash_drv, int rom_size)
>>> +{
>>> +    BlockDriverState *bdrv;
>>> +    int64_t size;
>>> +    target_phys_addr_t phys_addr;
>>> +    ram_addr_t addr;
>>> +    int sector_bits, sector_size;
>>> +
>>> +    bdrv = NULL;
>>> +
>>> +    bdrv = pflash_drv->bdrv;
>>> +    size = bdrv_getlength(pflash_drv->bdrv);
>>> +    sector_bits = 12;
>>> +    sector_size = 1<<    sector_bits;
>>> +
>>> +    if ((size % sector_size) != 0) {
>>> +        fprintf(stderr,
>>> +                "qemu: -pflash size must be a multiple of 0x%x\n",
>>> +                sector_size);
>>> +        exit(1);
>>> +    }
>>> +
>>> +    phys_addr = 0x100000000ULL - rom_size - size;
>>> +    addr = qemu_ram_alloc(NULL, "system.flash", size);
>>> +    DPRINTF("flash addr: 0x%lx\n", (int64_t)phys_addr);
>>> +    pflash_cfi01_register(phys_addr, addr, bdrv,
>>> +                          sector_size, size>>    sector_bits,
>>> +                          4, 0x0000, 0x0000, 0x0000, 0x0000, 0);
>>> +
>>> +    if (rom_size == 0) {
>>> +        pc_isa_bios_init(addr, size);
>>> +    }
>>> +}
>>> +
>>> +static void pc_system_firmware_init(void)
>>> +{
>>> +    int flash_present, rom_present;
>>> +    int rom_size;
>>> +    DriveInfo *pflash_drv;
>>> +
>>> +    pflash_drv = drive_get(IF_PFLASH, 0, 0);
>>> +    flash_present = (pflash_drv != NULL);
>>> +
>>> +    /* Load rom if -bios is used or if -pflash is not used */
>>> +    rom_present = ((bios_name != NULL) || !flash_present);
>>> +
>>> +    /* If rom is present, then it is mapped just below 4GB */
>>> +    if (rom_present) {
>>> +        rom_size = pc_system_rom_init();
>>> +    } else {
>>> +        rom_size = 0;
>>> +    }
>>> +
>>> +    /* If flash is present, then it is mapped just below the rom, or
>>> +     * just below 4GB when rom is not present. */
>>> +    if (flash_present) {
>>> +        pc_system_flash_init(pflash_drv, rom_size);
>>> +    }
>>> +}
>>> +
>>> +void pc_memory_init(const char *kernel_filename,
>>> +                    const char *kernel_cmdline,
>>> +                    const char *initrd_filename,
>>> +                    ram_addr_t below_4g_mem_size,
>>> +                    ram_addr_t above_4g_mem_size)
>>> +{
>>> +    int linux_boot, i;
>>> +    ram_addr_t ram_addr, option_rom_offset;
>>> +    void *fw_cfg;
>>> +
>>> +    linux_boot = (kernel_filename != NULL);
>>> +
>>> +    /* allocate RAM */
>>> +    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
>>> +                              below_4g_mem_size + above_4g_mem_size);
>>> +    cpu_register_physical_memory(0, 0xa0000, ram_addr);
>>> +    cpu_register_physical_memory(0x100000,
>>> +                 below_4g_mem_size - 0x100000,
>>> +                 ram_addr + 0x100000);
>>> +    if (above_4g_mem_size>    0) {
>>> +        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
>>> +                                     ram_addr + below_4g_mem_size);
>>> +    }
>>> +
>>> +    /* Initialize ROM or flash ranges for PC firmware */
>>> +    pc_system_firmware_init();
>>> +
>>> +    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
>>> +    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE,
>>> option_rom_offset);
>>> +
>>>       fw_cfg = bochs_bios_init();
>>>       rom_set_fw(fw_cfg);
>>>
>>
>>
>>
>
Jordan Justen July 23, 2011, 10:06 p.m. UTC | #5
On Sat, Jul 23, 2011 at 14:25, Anthony Liguori <anthony@codemonkey.ws> wrote:
> On 07/23/2011 03:19 PM, Jordan Justen wrote:
>>
>> On Sat, Jul 23, 2011 at 08:51, Anthony Liguori<anthony@codemonkey.ws>
>>  wrote:
>>>
>>> On 07/08/2011 02:37 PM, Jordan Justen wrote:
>>>>
>>>> If -pflash is specified and -bios is specified then pflash will
>>>> be mapped just below the system rom using hw/pflash_cfi01.c.
>>>>
>>>> If -pflash is specified on the command line, but -bios is
>>>> not specified, then 'bios.bin' will NOT be loaded, and
>>>> instead the -pflash flash image will be mapped just below
>>>> 4GB in place of the normal rom image.
>>>
>>> This is way too tied to the pc platform to be this generic.
>>>
>>> I think a better approach would be to default to having unit=0 of
>>> IF_PFLASH
>>> default to a read-only BDS that points to bios.bin.  -bios would just be
>>> a
>>> short cut to use a different file name but you should be able to override
>>> with -drive too.
>>>
>>> And to really simplify things, you could add a readonly flag to -bios
>>> such
>>> that you could do:
>>>
>>> -bios foo.img,readonly=off
>>>
>>> Which is what I think you're looking for semantically.
>>
>> There seemed to be some feedback on the list interested in preserving
>> a read-only firmware, and just adding a flash region.
>>
>> So, for example, the firmware could be read from a common system
>> location like is generally done with bios.bin today, and VM instance
>> specific flash region could still be added.
>
> You can have multiple flash regions.

So, is your recommendation that we support N pflash images in
x86/x86-64?  Instance/index 0 is mapped just under 4GB, and the rest
follow below this?

This seems like a good plan, although I can't see a usage for more
than 2 instances.

-Jordan

> You're introducing two modes.  In one mode, we emulate a flash device and
> expose it for the BIOS ROM.  In the second mode, we don't emulate a device
> but we expose the BIOS ROM based on a file in a shared read-only location.
>
> I'm suggesting always emulating a flash device, but by default make the
> device read-only and have it be loaded from a file in a shared read-only
> location.
>
> That means we have a single code path and a consistent view from a
> management tooling perspective.  IOW, management tools will always see that
> there is a BIOS block device, and they need to worry about making sure that
> BIOS block device is there.
>
>>
>> If the entire firmware is moved to a separate VM instance specific
>> flash, then firmware update also gets complicated.  It is no longer
>> just a matter of updating the qemu firmware package in your distro's
>> package management system.
>
> I think the bit your misunderstanding is that you should default the
> firmware to be created from a common file as a read-only device.
>
> Regards,
>
> Anthony Liguori
>
>>
>> What about taking your idea, but adding a second drive that would be
>> mapped just below the 1st if it is specified with -drive?
>>
>> Thanks,
>>
>> -Jordan
>>
>>>
>>> Regards,
>>>
>>> Anthony Liguori
>>>
>>>>
>>>> Signed-off-by: Jordan Justen<jordan.l.justen@intel.com>
>>>> Reviewed-by: Aurelien Jarno<aurelien@aurel32.net>
>>>
>>>
>>>
>>>> ---
>>>>  default-configs/i386-softmmu.mak   |    1 +
>>>>  default-configs/x86_64-softmmu.mak |    1 +
>>>>  hw/pc.c                            |  161
>>>> +++++++++++++++++++++++++++---------
>>>>  3 files changed, 125 insertions(+), 38 deletions(-)
>>>>
>>>> diff --git a/default-configs/i386-softmmu.mak
>>>> b/default-configs/i386-softmmu.mak
>>>> index 55589fa..8697cd4 100644
>>>> --- a/default-configs/i386-softmmu.mak
>>>> +++ b/default-configs/i386-softmmu.mak
>>>> @@ -21,3 +21,4 @@ CONFIG_PIIX_PCI=y
>>>>  CONFIG_SOUND=y
>>>>  CONFIG_HPET=y
>>>>  CONFIG_APPLESMC=y
>>>> +CONFIG_PFLASH_CFI01=y
>>>> diff --git a/default-configs/x86_64-softmmu.mak
>>>> b/default-configs/x86_64-softmmu.mak
>>>> index 8895028..eca9284 100644
>>>> --- a/default-configs/x86_64-softmmu.mak
>>>> +++ b/default-configs/x86_64-softmmu.mak
>>>> @@ -21,3 +21,4 @@ CONFIG_PIIX_PCI=y
>>>>  CONFIG_SOUND=y
>>>>  CONFIG_HPET=y
>>>>  CONFIG_APPLESMC=y
>>>> +CONFIG_PFLASH_CFI01=y
>>>> diff --git a/hw/pc.c b/hw/pc.c
>>>> index a3e8539..e25354f 100644
>>>> --- a/hw/pc.c
>>>> +++ b/hw/pc.c
>>>> @@ -41,6 +41,7 @@
>>>>  #include "sysemu.h"
>>>>  #include "blockdev.h"
>>>>  #include "ui/qemu-spice.h"
>>>> +#include "flash.h"
>>>>
>>>>  /* output Bochs bios info messages */
>>>>  //#define DEBUG_BIOS
>>>> @@ -957,70 +958,154 @@ void pc_cpus_init(const char *cpu_model)
>>>>      }
>>>>  }
>>>>
>>>> -void pc_memory_init(const char *kernel_filename,
>>>> -                    const char *kernel_cmdline,
>>>> -                    const char *initrd_filename,
>>>> -                    ram_addr_t below_4g_mem_size,
>>>> -                    ram_addr_t above_4g_mem_size)
>>>> +static void pc_isa_bios_init(ram_addr_t ram_offset, int ram_size)
>>>>  {
>>>> -    char *filename;
>>>> -    int ret, linux_boot, i;
>>>> -    ram_addr_t ram_addr, bios_offset, option_rom_offset;
>>>> -    int bios_size, isa_bios_size;
>>>> -    void *fw_cfg;
>>>> -
>>>> -    linux_boot = (kernel_filename != NULL);
>>>> +    int isa_bios_size;
>>>>
>>>> -    /* allocate RAM */
>>>> -    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
>>>> -                              below_4g_mem_size + above_4g_mem_size);
>>>> -    cpu_register_physical_memory(0, 0xa0000, ram_addr);
>>>> -    cpu_register_physical_memory(0x100000,
>>>> -                 below_4g_mem_size - 0x100000,
>>>> -                 ram_addr + 0x100000);
>>>> -    if (above_4g_mem_size>    0) {
>>>> -        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
>>>> -                                     ram_addr + below_4g_mem_size);
>>>> +    /* map the last 128KB of the BIOS in ISA space */
>>>> +    isa_bios_size = ram_size;
>>>> +    if (isa_bios_size>    (128 * 1024)) {
>>>> +        isa_bios_size = 128 * 1024;
>>>>      }
>>>> +    ram_offset = ram_offset + ram_size - isa_bios_size;
>>>> +    cpu_register_physical_memory(0x100000 - isa_bios_size,
>>>> +                                 isa_bios_size,
>>>> +                                 ram_offset | IO_MEM_ROM);
>>>> +}
>>>> +
>>>> +static int pc_system_rom_init(void)
>>>> +{
>>>> +    int ret;
>>>> +    int bios_size;
>>>> +    ram_addr_t bios_offset;
>>>> +    char *filename;
>>>>
>>>>      /* BIOS load */
>>>> -    if (bios_name == NULL)
>>>> +    if (bios_name == NULL) {
>>>>          bios_name = BIOS_FILENAME;
>>>> +    }
>>>>      filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
>>>>      if (filename) {
>>>>          bios_size = get_image_size(filename);
>>>>      } else {
>>>>          bios_size = -1;
>>>>      }
>>>> -    if (bios_size<= 0 ||
>>>> -        (bios_size % 65536) != 0) {
>>>> -        goto bios_error;
>>>> +
>>>> +    if (bios_size<= 0 || (bios_size % 65536) != 0) {
>>>> +        ret = -1;
>>>> +    } else {
>>>> +        bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
>>>> +        ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size),
>>>> -1);
>>>>      }
>>>> -    bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
>>>> -    ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
>>>> +
>>>>      if (ret != 0) {
>>>> -    bios_error:
>>>>          fprintf(stderr, "qemu: could not load PC BIOS '%s'\n",
>>>> bios_name);
>>>>          exit(1);
>>>>      }
>>>> +
>>>>      if (filename) {
>>>>          qemu_free(filename);
>>>>      }
>>>> -    /* map the last 128KB of the BIOS in ISA space */
>>>> -    isa_bios_size = bios_size;
>>>> -    if (isa_bios_size>    (128 * 1024))
>>>> -        isa_bios_size = 128 * 1024;
>>>> -    cpu_register_physical_memory(0x100000 - isa_bios_size,
>>>> -                                 isa_bios_size,
>>>> -                                 (bios_offset + bios_size -
>>>> isa_bios_size) | IO_MEM_ROM);
>>>>
>>>> -    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
>>>> -    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE,
>>>> option_rom_offset);
>>>> +    pc_isa_bios_init(bios_offset, bios_size);
>>>>
>>>>      /* map all the bios at the top of memory */
>>>>      cpu_register_physical_memory((uint32_t)(-bios_size),
>>>>                                   bios_size, bios_offset | IO_MEM_ROM);
>>>>
>>>> +    return bios_size;
>>>> +}
>>>> +
>>>> +static void pc_system_flash_init(DriveInfo *pflash_drv, int rom_size)
>>>> +{
>>>> +    BlockDriverState *bdrv;
>>>> +    int64_t size;
>>>> +    target_phys_addr_t phys_addr;
>>>> +    ram_addr_t addr;
>>>> +    int sector_bits, sector_size;
>>>> +
>>>> +    bdrv = NULL;
>>>> +
>>>> +    bdrv = pflash_drv->bdrv;
>>>> +    size = bdrv_getlength(pflash_drv->bdrv);
>>>> +    sector_bits = 12;
>>>> +    sector_size = 1<<    sector_bits;
>>>> +
>>>> +    if ((size % sector_size) != 0) {
>>>> +        fprintf(stderr,
>>>> +                "qemu: -pflash size must be a multiple of 0x%x\n",
>>>> +                sector_size);
>>>> +        exit(1);
>>>> +    }
>>>> +
>>>> +    phys_addr = 0x100000000ULL - rom_size - size;
>>>> +    addr = qemu_ram_alloc(NULL, "system.flash", size);
>>>> +    DPRINTF("flash addr: 0x%lx\n", (int64_t)phys_addr);
>>>> +    pflash_cfi01_register(phys_addr, addr, bdrv,
>>>> +                          sector_size, size>>    sector_bits,
>>>> +                          4, 0x0000, 0x0000, 0x0000, 0x0000, 0);
>>>> +
>>>> +    if (rom_size == 0) {
>>>> +        pc_isa_bios_init(addr, size);
>>>> +    }
>>>> +}
>>>> +
>>>> +static void pc_system_firmware_init(void)
>>>> +{
>>>> +    int flash_present, rom_present;
>>>> +    int rom_size;
>>>> +    DriveInfo *pflash_drv;
>>>> +
>>>> +    pflash_drv = drive_get(IF_PFLASH, 0, 0);
>>>> +    flash_present = (pflash_drv != NULL);
>>>> +
>>>> +    /* Load rom if -bios is used or if -pflash is not used */
>>>> +    rom_present = ((bios_name != NULL) || !flash_present);
>>>> +
>>>> +    /* If rom is present, then it is mapped just below 4GB */
>>>> +    if (rom_present) {
>>>> +        rom_size = pc_system_rom_init();
>>>> +    } else {
>>>> +        rom_size = 0;
>>>> +    }
>>>> +
>>>> +    /* If flash is present, then it is mapped just below the rom, or
>>>> +     * just below 4GB when rom is not present. */
>>>> +    if (flash_present) {
>>>> +        pc_system_flash_init(pflash_drv, rom_size);
>>>> +    }
>>>> +}
>>>> +
>>>> +void pc_memory_init(const char *kernel_filename,
>>>> +                    const char *kernel_cmdline,
>>>> +                    const char *initrd_filename,
>>>> +                    ram_addr_t below_4g_mem_size,
>>>> +                    ram_addr_t above_4g_mem_size)
>>>> +{
>>>> +    int linux_boot, i;
>>>> +    ram_addr_t ram_addr, option_rom_offset;
>>>> +    void *fw_cfg;
>>>> +
>>>> +    linux_boot = (kernel_filename != NULL);
>>>> +
>>>> +    /* allocate RAM */
>>>> +    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
>>>> +                              below_4g_mem_size + above_4g_mem_size);
>>>> +    cpu_register_physical_memory(0, 0xa0000, ram_addr);
>>>> +    cpu_register_physical_memory(0x100000,
>>>> +                 below_4g_mem_size - 0x100000,
>>>> +                 ram_addr + 0x100000);
>>>> +    if (above_4g_mem_size>    0) {
>>>> +        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
>>>> +                                     ram_addr + below_4g_mem_size);
>>>> +    }
>>>> +
>>>> +    /* Initialize ROM or flash ranges for PC firmware */
>>>> +    pc_system_firmware_init();
>>>> +
>>>> +    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
>>>> +    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE,
>>>> option_rom_offset);
>>>> +
>>>>      fw_cfg = bochs_bios_init();
>>>>      rom_set_fw(fw_cfg);
>>>>
>>>
>>>
>>>
>>
>
>
Anthony Liguori July 23, 2011, 10:26 p.m. UTC | #6
On 07/23/2011 05:06 PM, Jordan Justen wrote:
> On Sat, Jul 23, 2011 at 14:25, Anthony Liguori<anthony@codemonkey.ws>  wrote:
>> On 07/23/2011 03:19 PM, Jordan Justen wrote:
>>>
>>> On Sat, Jul 23, 2011 at 08:51, Anthony Liguori<anthony@codemonkey.ws>
>>>   wrote:
>>>>
>>>> On 07/08/2011 02:37 PM, Jordan Justen wrote:
>>>>>
>>>>> If -pflash is specified and -bios is specified then pflash will
>>>>> be mapped just below the system rom using hw/pflash_cfi01.c.
>>>>>
>>>>> If -pflash is specified on the command line, but -bios is
>>>>> not specified, then 'bios.bin' will NOT be loaded, and
>>>>> instead the -pflash flash image will be mapped just below
>>>>> 4GB in place of the normal rom image.
>>>>
>>>> This is way too tied to the pc platform to be this generic.
>>>>
>>>> I think a better approach would be to default to having unit=0 of
>>>> IF_PFLASH
>>>> default to a read-only BDS that points to bios.bin.  -bios would just be
>>>> a
>>>> short cut to use a different file name but you should be able to override
>>>> with -drive too.
>>>>
>>>> And to really simplify things, you could add a readonly flag to -bios
>>>> such
>>>> that you could do:
>>>>
>>>> -bios foo.img,readonly=off
>>>>
>>>> Which is what I think you're looking for semantically.
>>>
>>> There seemed to be some feedback on the list interested in preserving
>>> a read-only firmware, and just adding a flash region.
>>>
>>> So, for example, the firmware could be read from a common system
>>> location like is generally done with bios.bin today, and VM instance
>>> specific flash region could still be added.
>>
>> You can have multiple flash regions.
>
> So, is your recommendation that we support N pflash images in
> x86/x86-64?  Instance/index 0 is mapped just under 4GB, and the rest
> follow below this?

No.  There should be a flash device, pflash index 0 is fine, but it 
should be mapped under 4GB and also in the legacy BIOS space.

This is the PC firmware flash.  By default it should be read-only and it 
should be created by using ${prefix}/share/bios.bin.  But it should be 
possible to override both the filename and the read-only flag.

In terms of other flash devices, I don't think it's that simple.  Flash 
is tied to the mobo layout so I don't think index > 0 really makes sense 
unless you allow a specific mapping address.  I doubt that's terribly 
useful.

Regards,

Anthony Liguori

>
> This seems like a good plan, although I can't see a usage for more
> than 2 instances.
>
> -Jordan
>
>> You're introducing two modes.  In one mode, we emulate a flash device and
>> expose it for the BIOS ROM.  In the second mode, we don't emulate a device
>> but we expose the BIOS ROM based on a file in a shared read-only location.
>>
>> I'm suggesting always emulating a flash device, but by default make the
>> device read-only and have it be loaded from a file in a shared read-only
>> location.
>>
>> That means we have a single code path and a consistent view from a
>> management tooling perspective.  IOW, management tools will always see that
>> there is a BIOS block device, and they need to worry about making sure that
>> BIOS block device is there.
>>
>>>
>>> If the entire firmware is moved to a separate VM instance specific
>>> flash, then firmware update also gets complicated.  It is no longer
>>> just a matter of updating the qemu firmware package in your distro's
>>> package management system.
>>
>> I think the bit your misunderstanding is that you should default the
>> firmware to be created from a common file as a read-only device.
>>
>> Regards,
>>
>> Anthony Liguori
>>
>>>
>>> What about taking your idea, but adding a second drive that would be
>>> mapped just below the 1st if it is specified with -drive?
>>>
>>> Thanks,
>>>
>>> -Jordan
>>>
>>>>
>>>> Regards,
>>>>
>>>> Anthony Liguori
>>>>
>>>>>
>>>>> Signed-off-by: Jordan Justen<jordan.l.justen@intel.com>
>>>>> Reviewed-by: Aurelien Jarno<aurelien@aurel32.net>
>>>>
>>>>
>>>>
>>>>> ---
>>>>>   default-configs/i386-softmmu.mak   |    1 +
>>>>>   default-configs/x86_64-softmmu.mak |    1 +
>>>>>   hw/pc.c                            |  161
>>>>> +++++++++++++++++++++++++++---------
>>>>>   3 files changed, 125 insertions(+), 38 deletions(-)
>>>>>
>>>>> diff --git a/default-configs/i386-softmmu.mak
>>>>> b/default-configs/i386-softmmu.mak
>>>>> index 55589fa..8697cd4 100644
>>>>> --- a/default-configs/i386-softmmu.mak
>>>>> +++ b/default-configs/i386-softmmu.mak
>>>>> @@ -21,3 +21,4 @@ CONFIG_PIIX_PCI=y
>>>>>   CONFIG_SOUND=y
>>>>>   CONFIG_HPET=y
>>>>>   CONFIG_APPLESMC=y
>>>>> +CONFIG_PFLASH_CFI01=y
>>>>> diff --git a/default-configs/x86_64-softmmu.mak
>>>>> b/default-configs/x86_64-softmmu.mak
>>>>> index 8895028..eca9284 100644
>>>>> --- a/default-configs/x86_64-softmmu.mak
>>>>> +++ b/default-configs/x86_64-softmmu.mak
>>>>> @@ -21,3 +21,4 @@ CONFIG_PIIX_PCI=y
>>>>>   CONFIG_SOUND=y
>>>>>   CONFIG_HPET=y
>>>>>   CONFIG_APPLESMC=y
>>>>> +CONFIG_PFLASH_CFI01=y
>>>>> diff --git a/hw/pc.c b/hw/pc.c
>>>>> index a3e8539..e25354f 100644
>>>>> --- a/hw/pc.c
>>>>> +++ b/hw/pc.c
>>>>> @@ -41,6 +41,7 @@
>>>>>   #include "sysemu.h"
>>>>>   #include "blockdev.h"
>>>>>   #include "ui/qemu-spice.h"
>>>>> +#include "flash.h"
>>>>>
>>>>>   /* output Bochs bios info messages */
>>>>>   //#define DEBUG_BIOS
>>>>> @@ -957,70 +958,154 @@ void pc_cpus_init(const char *cpu_model)
>>>>>       }
>>>>>   }
>>>>>
>>>>> -void pc_memory_init(const char *kernel_filename,
>>>>> -                    const char *kernel_cmdline,
>>>>> -                    const char *initrd_filename,
>>>>> -                    ram_addr_t below_4g_mem_size,
>>>>> -                    ram_addr_t above_4g_mem_size)
>>>>> +static void pc_isa_bios_init(ram_addr_t ram_offset, int ram_size)
>>>>>   {
>>>>> -    char *filename;
>>>>> -    int ret, linux_boot, i;
>>>>> -    ram_addr_t ram_addr, bios_offset, option_rom_offset;
>>>>> -    int bios_size, isa_bios_size;
>>>>> -    void *fw_cfg;
>>>>> -
>>>>> -    linux_boot = (kernel_filename != NULL);
>>>>> +    int isa_bios_size;
>>>>>
>>>>> -    /* allocate RAM */
>>>>> -    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
>>>>> -                              below_4g_mem_size + above_4g_mem_size);
>>>>> -    cpu_register_physical_memory(0, 0xa0000, ram_addr);
>>>>> -    cpu_register_physical_memory(0x100000,
>>>>> -                 below_4g_mem_size - 0x100000,
>>>>> -                 ram_addr + 0x100000);
>>>>> -    if (above_4g_mem_size>      0) {
>>>>> -        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
>>>>> -                                     ram_addr + below_4g_mem_size);
>>>>> +    /* map the last 128KB of the BIOS in ISA space */
>>>>> +    isa_bios_size = ram_size;
>>>>> +    if (isa_bios_size>      (128 * 1024)) {
>>>>> +        isa_bios_size = 128 * 1024;
>>>>>       }
>>>>> +    ram_offset = ram_offset + ram_size - isa_bios_size;
>>>>> +    cpu_register_physical_memory(0x100000 - isa_bios_size,
>>>>> +                                 isa_bios_size,
>>>>> +                                 ram_offset | IO_MEM_ROM);
>>>>> +}
>>>>> +
>>>>> +static int pc_system_rom_init(void)
>>>>> +{
>>>>> +    int ret;
>>>>> +    int bios_size;
>>>>> +    ram_addr_t bios_offset;
>>>>> +    char *filename;
>>>>>
>>>>>       /* BIOS load */
>>>>> -    if (bios_name == NULL)
>>>>> +    if (bios_name == NULL) {
>>>>>           bios_name = BIOS_FILENAME;
>>>>> +    }
>>>>>       filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
>>>>>       if (filename) {
>>>>>           bios_size = get_image_size(filename);
>>>>>       } else {
>>>>>           bios_size = -1;
>>>>>       }
>>>>> -    if (bios_size<= 0 ||
>>>>> -        (bios_size % 65536) != 0) {
>>>>> -        goto bios_error;
>>>>> +
>>>>> +    if (bios_size<= 0 || (bios_size % 65536) != 0) {
>>>>> +        ret = -1;
>>>>> +    } else {
>>>>> +        bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
>>>>> +        ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size),
>>>>> -1);
>>>>>       }
>>>>> -    bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
>>>>> -    ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
>>>>> +
>>>>>       if (ret != 0) {
>>>>> -    bios_error:
>>>>>           fprintf(stderr, "qemu: could not load PC BIOS '%s'\n",
>>>>> bios_name);
>>>>>           exit(1);
>>>>>       }
>>>>> +
>>>>>       if (filename) {
>>>>>           qemu_free(filename);
>>>>>       }
>>>>> -    /* map the last 128KB of the BIOS in ISA space */
>>>>> -    isa_bios_size = bios_size;
>>>>> -    if (isa_bios_size>      (128 * 1024))
>>>>> -        isa_bios_size = 128 * 1024;
>>>>> -    cpu_register_physical_memory(0x100000 - isa_bios_size,
>>>>> -                                 isa_bios_size,
>>>>> -                                 (bios_offset + bios_size -
>>>>> isa_bios_size) | IO_MEM_ROM);
>>>>>
>>>>> -    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
>>>>> -    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE,
>>>>> option_rom_offset);
>>>>> +    pc_isa_bios_init(bios_offset, bios_size);
>>>>>
>>>>>       /* map all the bios at the top of memory */
>>>>>       cpu_register_physical_memory((uint32_t)(-bios_size),
>>>>>                                    bios_size, bios_offset | IO_MEM_ROM);
>>>>>
>>>>> +    return bios_size;
>>>>> +}
>>>>> +
>>>>> +static void pc_system_flash_init(DriveInfo *pflash_drv, int rom_size)
>>>>> +{
>>>>> +    BlockDriverState *bdrv;
>>>>> +    int64_t size;
>>>>> +    target_phys_addr_t phys_addr;
>>>>> +    ram_addr_t addr;
>>>>> +    int sector_bits, sector_size;
>>>>> +
>>>>> +    bdrv = NULL;
>>>>> +
>>>>> +    bdrv = pflash_drv->bdrv;
>>>>> +    size = bdrv_getlength(pflash_drv->bdrv);
>>>>> +    sector_bits = 12;
>>>>> +    sector_size = 1<<      sector_bits;
>>>>> +
>>>>> +    if ((size % sector_size) != 0) {
>>>>> +        fprintf(stderr,
>>>>> +                "qemu: -pflash size must be a multiple of 0x%x\n",
>>>>> +                sector_size);
>>>>> +        exit(1);
>>>>> +    }
>>>>> +
>>>>> +    phys_addr = 0x100000000ULL - rom_size - size;
>>>>> +    addr = qemu_ram_alloc(NULL, "system.flash", size);
>>>>> +    DPRINTF("flash addr: 0x%lx\n", (int64_t)phys_addr);
>>>>> +    pflash_cfi01_register(phys_addr, addr, bdrv,
>>>>> +                          sector_size, size>>      sector_bits,
>>>>> +                          4, 0x0000, 0x0000, 0x0000, 0x0000, 0);
>>>>> +
>>>>> +    if (rom_size == 0) {
>>>>> +        pc_isa_bios_init(addr, size);
>>>>> +    }
>>>>> +}
>>>>> +
>>>>> +static void pc_system_firmware_init(void)
>>>>> +{
>>>>> +    int flash_present, rom_present;
>>>>> +    int rom_size;
>>>>> +    DriveInfo *pflash_drv;
>>>>> +
>>>>> +    pflash_drv = drive_get(IF_PFLASH, 0, 0);
>>>>> +    flash_present = (pflash_drv != NULL);
>>>>> +
>>>>> +    /* Load rom if -bios is used or if -pflash is not used */
>>>>> +    rom_present = ((bios_name != NULL) || !flash_present);
>>>>> +
>>>>> +    /* If rom is present, then it is mapped just below 4GB */
>>>>> +    if (rom_present) {
>>>>> +        rom_size = pc_system_rom_init();
>>>>> +    } else {
>>>>> +        rom_size = 0;
>>>>> +    }
>>>>> +
>>>>> +    /* If flash is present, then it is mapped just below the rom, or
>>>>> +     * just below 4GB when rom is not present. */
>>>>> +    if (flash_present) {
>>>>> +        pc_system_flash_init(pflash_drv, rom_size);
>>>>> +    }
>>>>> +}
>>>>> +
>>>>> +void pc_memory_init(const char *kernel_filename,
>>>>> +                    const char *kernel_cmdline,
>>>>> +                    const char *initrd_filename,
>>>>> +                    ram_addr_t below_4g_mem_size,
>>>>> +                    ram_addr_t above_4g_mem_size)
>>>>> +{
>>>>> +    int linux_boot, i;
>>>>> +    ram_addr_t ram_addr, option_rom_offset;
>>>>> +    void *fw_cfg;
>>>>> +
>>>>> +    linux_boot = (kernel_filename != NULL);
>>>>> +
>>>>> +    /* allocate RAM */
>>>>> +    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
>>>>> +                              below_4g_mem_size + above_4g_mem_size);
>>>>> +    cpu_register_physical_memory(0, 0xa0000, ram_addr);
>>>>> +    cpu_register_physical_memory(0x100000,
>>>>> +                 below_4g_mem_size - 0x100000,
>>>>> +                 ram_addr + 0x100000);
>>>>> +    if (above_4g_mem_size>      0) {
>>>>> +        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
>>>>> +                                     ram_addr + below_4g_mem_size);
>>>>> +    }
>>>>> +
>>>>> +    /* Initialize ROM or flash ranges for PC firmware */
>>>>> +    pc_system_firmware_init();
>>>>> +
>>>>> +    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
>>>>> +    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE,
>>>>> option_rom_offset);
>>>>> +
>>>>>       fw_cfg = bochs_bios_init();
>>>>>       rom_set_fw(fw_cfg);
>>>>>
>>>>
>>>>
>>>>
>>>
>>
>>
>
Jordan Justen July 24, 2011, 12:18 a.m. UTC | #7
On Sat, Jul 23, 2011 at 15:26, Anthony Liguori <anthony@codemonkey.ws> wrote:
> On 07/23/2011 05:06 PM, Jordan Justen wrote:
>>
>> On Sat, Jul 23, 2011 at 14:25, Anthony Liguori<anthony@codemonkey.ws>
>>  wrote:
>>>
>>> On 07/23/2011 03:19 PM, Jordan Justen wrote:
>>>>
>>>> On Sat, Jul 23, 2011 at 08:51, Anthony Liguori<anthony@codemonkey.ws>
>>>>  wrote:
>>>>>
>>>>> On 07/08/2011 02:37 PM, Jordan Justen wrote:
>>>>>>
>>>>>> If -pflash is specified and -bios is specified then pflash will
>>>>>> be mapped just below the system rom using hw/pflash_cfi01.c.
>>>>>>
>>>>>> If -pflash is specified on the command line, but -bios is
>>>>>> not specified, then 'bios.bin' will NOT be loaded, and
>>>>>> instead the -pflash flash image will be mapped just below
>>>>>> 4GB in place of the normal rom image.
>>>>>
>>>>> This is way too tied to the pc platform to be this generic.
>>>>>
>>>>> I think a better approach would be to default to having unit=0 of
>>>>> IF_PFLASH
>>>>> default to a read-only BDS that points to bios.bin.  -bios would just
>>>>> be
>>>>> a
>>>>> short cut to use a different file name but you should be able to
>>>>> override
>>>>> with -drive too.
>>>>>
>>>>> And to really simplify things, you could add a readonly flag to -bios
>>>>> such
>>>>> that you could do:
>>>>>
>>>>> -bios foo.img,readonly=off
>>>>>
>>>>> Which is what I think you're looking for semantically.
>>>>
>>>> There seemed to be some feedback on the list interested in preserving
>>>> a read-only firmware, and just adding a flash region.
>>>>
>>>> So, for example, the firmware could be read from a common system
>>>> location like is generally done with bios.bin today, and VM instance
>>>> specific flash region could still be added.
>>>
>>> You can have multiple flash regions.
>>
>> So, is your recommendation that we support N pflash images in
>> x86/x86-64?  Instance/index 0 is mapped just under 4GB, and the rest
>> follow below this?
>
> No.  There should be a flash device, pflash index 0 is fine, but it should
> be mapped under 4GB and also in the legacy BIOS space.
>
> This is the PC firmware flash.  By default it should be read-only and it
> should be created by using ${prefix}/share/bios.bin.  But it should be
> possible to override both the filename and the read-only flag.
>
> In terms of other flash devices, I don't think it's that simple.  Flash is
> tied to the mobo layout so I don't think index > 0 really makes sense unless
> you allow a specific mapping address.  I doubt that's terribly useful.

I think VM's have a different situation than real hardware.  I'm not
sure an all ROM or all flash decision will work well for qemu.  In
most cases it may work better to make a ROM image available just below
4GB, and add a flash image below this ROM.

This allows the qemu's firmware to be updated as usual in
${prefix}/share/bios.bin, but still allows a flash memory to be
available below this.  (The flash below the ROM could be used only for
storing UEFI variables.)

Otherwise when a new qemu is released along with a new firmware image,
the VM instance using writable flash will continue to use the old
firmware image.

-Jordan

>
> Regards,
>
> Anthony Liguori
>
>>
>> This seems like a good plan, although I can't see a usage for more
>> than 2 instances.
>>
>> -Jordan
>>
>>> You're introducing two modes.  In one mode, we emulate a flash device and
>>> expose it for the BIOS ROM.  In the second mode, we don't emulate a
>>> device
>>> but we expose the BIOS ROM based on a file in a shared read-only
>>> location.
>>>
>>> I'm suggesting always emulating a flash device, but by default make the
>>> device read-only and have it be loaded from a file in a shared read-only
>>> location.
>>>
>>> That means we have a single code path and a consistent view from a
>>> management tooling perspective.  IOW, management tools will always see
>>> that
>>> there is a BIOS block device, and they need to worry about making sure
>>> that
>>> BIOS block device is there.
>>>
>>>>
>>>> If the entire firmware is moved to a separate VM instance specific
>>>> flash, then firmware update also gets complicated.  It is no longer
>>>> just a matter of updating the qemu firmware package in your distro's
>>>> package management system.
>>>
>>> I think the bit your misunderstanding is that you should default the
>>> firmware to be created from a common file as a read-only device.
>>>
>>> Regards,
>>>
>>> Anthony Liguori
>>>
>>>>
>>>> What about taking your idea, but adding a second drive that would be
>>>> mapped just below the 1st if it is specified with -drive?
>>>>
>>>> Thanks,
>>>>
>>>> -Jordan
>>>>
>>>>>
>>>>> Regards,
>>>>>
>>>>> Anthony Liguori
>>>>>
>>>>>>
>>>>>> Signed-off-by: Jordan Justen<jordan.l.justen@intel.com>
>>>>>> Reviewed-by: Aurelien Jarno<aurelien@aurel32.net>
>>>>>
>>>>>
>>>>>
>>>>>> ---
>>>>>>  default-configs/i386-softmmu.mak   |    1 +
>>>>>>  default-configs/x86_64-softmmu.mak |    1 +
>>>>>>  hw/pc.c                            |  161
>>>>>> +++++++++++++++++++++++++++---------
>>>>>>  3 files changed, 125 insertions(+), 38 deletions(-)
>>>>>>
>>>>>> diff --git a/default-configs/i386-softmmu.mak
>>>>>> b/default-configs/i386-softmmu.mak
>>>>>> index 55589fa..8697cd4 100644
>>>>>> --- a/default-configs/i386-softmmu.mak
>>>>>> +++ b/default-configs/i386-softmmu.mak
>>>>>> @@ -21,3 +21,4 @@ CONFIG_PIIX_PCI=y
>>>>>>  CONFIG_SOUND=y
>>>>>>  CONFIG_HPET=y
>>>>>>  CONFIG_APPLESMC=y
>>>>>> +CONFIG_PFLASH_CFI01=y
>>>>>> diff --git a/default-configs/x86_64-softmmu.mak
>>>>>> b/default-configs/x86_64-softmmu.mak
>>>>>> index 8895028..eca9284 100644
>>>>>> --- a/default-configs/x86_64-softmmu.mak
>>>>>> +++ b/default-configs/x86_64-softmmu.mak
>>>>>> @@ -21,3 +21,4 @@ CONFIG_PIIX_PCI=y
>>>>>>  CONFIG_SOUND=y
>>>>>>  CONFIG_HPET=y
>>>>>>  CONFIG_APPLESMC=y
>>>>>> +CONFIG_PFLASH_CFI01=y
>>>>>> diff --git a/hw/pc.c b/hw/pc.c
>>>>>> index a3e8539..e25354f 100644
>>>>>> --- a/hw/pc.c
>>>>>> +++ b/hw/pc.c
>>>>>> @@ -41,6 +41,7 @@
>>>>>>  #include "sysemu.h"
>>>>>>  #include "blockdev.h"
>>>>>>  #include "ui/qemu-spice.h"
>>>>>> +#include "flash.h"
>>>>>>
>>>>>>  /* output Bochs bios info messages */
>>>>>>  //#define DEBUG_BIOS
>>>>>> @@ -957,70 +958,154 @@ void pc_cpus_init(const char *cpu_model)
>>>>>>      }
>>>>>>  }
>>>>>>
>>>>>> -void pc_memory_init(const char *kernel_filename,
>>>>>> -                    const char *kernel_cmdline,
>>>>>> -                    const char *initrd_filename,
>>>>>> -                    ram_addr_t below_4g_mem_size,
>>>>>> -                    ram_addr_t above_4g_mem_size)
>>>>>> +static void pc_isa_bios_init(ram_addr_t ram_offset, int ram_size)
>>>>>>  {
>>>>>> -    char *filename;
>>>>>> -    int ret, linux_boot, i;
>>>>>> -    ram_addr_t ram_addr, bios_offset, option_rom_offset;
>>>>>> -    int bios_size, isa_bios_size;
>>>>>> -    void *fw_cfg;
>>>>>> -
>>>>>> -    linux_boot = (kernel_filename != NULL);
>>>>>> +    int isa_bios_size;
>>>>>>
>>>>>> -    /* allocate RAM */
>>>>>> -    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
>>>>>> -                              below_4g_mem_size + above_4g_mem_size);
>>>>>> -    cpu_register_physical_memory(0, 0xa0000, ram_addr);
>>>>>> -    cpu_register_physical_memory(0x100000,
>>>>>> -                 below_4g_mem_size - 0x100000,
>>>>>> -                 ram_addr + 0x100000);
>>>>>> -    if (above_4g_mem_size>      0) {
>>>>>> -        cpu_register_physical_memory(0x100000000ULL,
>>>>>> above_4g_mem_size,
>>>>>> -                                     ram_addr + below_4g_mem_size);
>>>>>> +    /* map the last 128KB of the BIOS in ISA space */
>>>>>> +    isa_bios_size = ram_size;
>>>>>> +    if (isa_bios_size>      (128 * 1024)) {
>>>>>> +        isa_bios_size = 128 * 1024;
>>>>>>      }
>>>>>> +    ram_offset = ram_offset + ram_size - isa_bios_size;
>>>>>> +    cpu_register_physical_memory(0x100000 - isa_bios_size,
>>>>>> +                                 isa_bios_size,
>>>>>> +                                 ram_offset | IO_MEM_ROM);
>>>>>> +}
>>>>>> +
>>>>>> +static int pc_system_rom_init(void)
>>>>>> +{
>>>>>> +    int ret;
>>>>>> +    int bios_size;
>>>>>> +    ram_addr_t bios_offset;
>>>>>> +    char *filename;
>>>>>>
>>>>>>      /* BIOS load */
>>>>>> -    if (bios_name == NULL)
>>>>>> +    if (bios_name == NULL) {
>>>>>>          bios_name = BIOS_FILENAME;
>>>>>> +    }
>>>>>>      filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
>>>>>>      if (filename) {
>>>>>>          bios_size = get_image_size(filename);
>>>>>>      } else {
>>>>>>          bios_size = -1;
>>>>>>      }
>>>>>> -    if (bios_size<= 0 ||
>>>>>> -        (bios_size % 65536) != 0) {
>>>>>> -        goto bios_error;
>>>>>> +
>>>>>> +    if (bios_size<= 0 || (bios_size % 65536) != 0) {
>>>>>> +        ret = -1;
>>>>>> +    } else {
>>>>>> +        bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
>>>>>> +        ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size),
>>>>>> -1);
>>>>>>      }
>>>>>> -    bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
>>>>>> -    ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
>>>>>> +
>>>>>>      if (ret != 0) {
>>>>>> -    bios_error:
>>>>>>          fprintf(stderr, "qemu: could not load PC BIOS '%s'\n",
>>>>>> bios_name);
>>>>>>          exit(1);
>>>>>>      }
>>>>>> +
>>>>>>      if (filename) {
>>>>>>          qemu_free(filename);
>>>>>>      }
>>>>>> -    /* map the last 128KB of the BIOS in ISA space */
>>>>>> -    isa_bios_size = bios_size;
>>>>>> -    if (isa_bios_size>      (128 * 1024))
>>>>>> -        isa_bios_size = 128 * 1024;
>>>>>> -    cpu_register_physical_memory(0x100000 - isa_bios_size,
>>>>>> -                                 isa_bios_size,
>>>>>> -                                 (bios_offset + bios_size -
>>>>>> isa_bios_size) | IO_MEM_ROM);
>>>>>>
>>>>>> -    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
>>>>>> -    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE,
>>>>>> option_rom_offset);
>>>>>> +    pc_isa_bios_init(bios_offset, bios_size);
>>>>>>
>>>>>>      /* map all the bios at the top of memory */
>>>>>>      cpu_register_physical_memory((uint32_t)(-bios_size),
>>>>>>                                   bios_size, bios_offset |
>>>>>> IO_MEM_ROM);
>>>>>>
>>>>>> +    return bios_size;
>>>>>> +}
>>>>>> +
>>>>>> +static void pc_system_flash_init(DriveInfo *pflash_drv, int rom_size)
>>>>>> +{
>>>>>> +    BlockDriverState *bdrv;
>>>>>> +    int64_t size;
>>>>>> +    target_phys_addr_t phys_addr;
>>>>>> +    ram_addr_t addr;
>>>>>> +    int sector_bits, sector_size;
>>>>>> +
>>>>>> +    bdrv = NULL;
>>>>>> +
>>>>>> +    bdrv = pflash_drv->bdrv;
>>>>>> +    size = bdrv_getlength(pflash_drv->bdrv);
>>>>>> +    sector_bits = 12;
>>>>>> +    sector_size = 1<<      sector_bits;
>>>>>> +
>>>>>> +    if ((size % sector_size) != 0) {
>>>>>> +        fprintf(stderr,
>>>>>> +                "qemu: -pflash size must be a multiple of 0x%x\n",
>>>>>> +                sector_size);
>>>>>> +        exit(1);
>>>>>> +    }
>>>>>> +
>>>>>> +    phys_addr = 0x100000000ULL - rom_size - size;
>>>>>> +    addr = qemu_ram_alloc(NULL, "system.flash", size);
>>>>>> +    DPRINTF("flash addr: 0x%lx\n", (int64_t)phys_addr);
>>>>>> +    pflash_cfi01_register(phys_addr, addr, bdrv,
>>>>>> +                          sector_size, size>>      sector_bits,
>>>>>> +                          4, 0x0000, 0x0000, 0x0000, 0x0000, 0);
>>>>>> +
>>>>>> +    if (rom_size == 0) {
>>>>>> +        pc_isa_bios_init(addr, size);
>>>>>> +    }
>>>>>> +}
>>>>>> +
>>>>>> +static void pc_system_firmware_init(void)
>>>>>> +{
>>>>>> +    int flash_present, rom_present;
>>>>>> +    int rom_size;
>>>>>> +    DriveInfo *pflash_drv;
>>>>>> +
>>>>>> +    pflash_drv = drive_get(IF_PFLASH, 0, 0);
>>>>>> +    flash_present = (pflash_drv != NULL);
>>>>>> +
>>>>>> +    /* Load rom if -bios is used or if -pflash is not used */
>>>>>> +    rom_present = ((bios_name != NULL) || !flash_present);
>>>>>> +
>>>>>> +    /* If rom is present, then it is mapped just below 4GB */
>>>>>> +    if (rom_present) {
>>>>>> +        rom_size = pc_system_rom_init();
>>>>>> +    } else {
>>>>>> +        rom_size = 0;
>>>>>> +    }
>>>>>> +
>>>>>> +    /* If flash is present, then it is mapped just below the rom, or
>>>>>> +     * just below 4GB when rom is not present. */
>>>>>> +    if (flash_present) {
>>>>>> +        pc_system_flash_init(pflash_drv, rom_size);
>>>>>> +    }
>>>>>> +}
>>>>>> +
>>>>>> +void pc_memory_init(const char *kernel_filename,
>>>>>> +                    const char *kernel_cmdline,
>>>>>> +                    const char *initrd_filename,
>>>>>> +                    ram_addr_t below_4g_mem_size,
>>>>>> +                    ram_addr_t above_4g_mem_size)
>>>>>> +{
>>>>>> +    int linux_boot, i;
>>>>>> +    ram_addr_t ram_addr, option_rom_offset;
>>>>>> +    void *fw_cfg;
>>>>>> +
>>>>>> +    linux_boot = (kernel_filename != NULL);
>>>>>> +
>>>>>> +    /* allocate RAM */
>>>>>> +    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
>>>>>> +                              below_4g_mem_size + above_4g_mem_size);
>>>>>> +    cpu_register_physical_memory(0, 0xa0000, ram_addr);
>>>>>> +    cpu_register_physical_memory(0x100000,
>>>>>> +                 below_4g_mem_size - 0x100000,
>>>>>> +                 ram_addr + 0x100000);
>>>>>> +    if (above_4g_mem_size>      0) {
>>>>>> +        cpu_register_physical_memory(0x100000000ULL,
>>>>>> above_4g_mem_size,
>>>>>> +                                     ram_addr + below_4g_mem_size);
>>>>>> +    }
>>>>>> +
>>>>>> +    /* Initialize ROM or flash ranges for PC firmware */
>>>>>> +    pc_system_firmware_init();
>>>>>> +
>>>>>> +    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
>>>>>> +    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE,
>>>>>> option_rom_offset);
>>>>>> +
>>>>>>      fw_cfg = bochs_bios_init();
>>>>>>      rom_set_fw(fw_cfg);
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>
>>>
>>
>
>
Anthony Liguori July 24, 2011, 12:56 a.m. UTC | #8
On 07/23/2011 07:18 PM, Jordan Justen wrote:
>> In terms of other flash devices, I don't think it's that simple.  Flash is
>> tied to the mobo layout so I don't think index>  0 really makes sense unless
>> you allow a specific mapping address.  I doubt that's terribly useful.
>
> I think VM's have a different situation than real hardware.  I'm not
> sure an all ROM or all flash decision will work well for qemu.  In
> most cases it may work better to make a ROM image available just below
> 4GB, and add a flash image below this ROM.
>
> This allows the qemu's firmware to be updated as usual in
> ${prefix}/share/bios.bin, but still allows a flash memory to be
> available below this.  (The flash below the ROM could be used only for
> storing UEFI variables.)
>
> Otherwise when a new qemu is released along with a new firmware image,
> the VM instance using writable flash will continue to use the old
> firmware image.

Yes, that's a feature.

We could have a second nvram for other purposes of course.  That could 
be defined as index=1.

Regards,

Anthony Liguori
diff mbox

Patch

diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 55589fa..8697cd4 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -21,3 +21,4 @@  CONFIG_PIIX_PCI=y
 CONFIG_SOUND=y
 CONFIG_HPET=y
 CONFIG_APPLESMC=y
+CONFIG_PFLASH_CFI01=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index 8895028..eca9284 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -21,3 +21,4 @@  CONFIG_PIIX_PCI=y
 CONFIG_SOUND=y
 CONFIG_HPET=y
 CONFIG_APPLESMC=y
+CONFIG_PFLASH_CFI01=y
diff --git a/hw/pc.c b/hw/pc.c
index a3e8539..e25354f 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -41,6 +41,7 @@ 
 #include "sysemu.h"
 #include "blockdev.h"
 #include "ui/qemu-spice.h"
+#include "flash.h"
 
 /* output Bochs bios info messages */
 //#define DEBUG_BIOS
@@ -957,70 +958,154 @@  void pc_cpus_init(const char *cpu_model)
     }
 }
 
-void pc_memory_init(const char *kernel_filename,
-                    const char *kernel_cmdline,
-                    const char *initrd_filename,
-                    ram_addr_t below_4g_mem_size,
-                    ram_addr_t above_4g_mem_size)
+static void pc_isa_bios_init(ram_addr_t ram_offset, int ram_size)
 {
-    char *filename;
-    int ret, linux_boot, i;
-    ram_addr_t ram_addr, bios_offset, option_rom_offset;
-    int bios_size, isa_bios_size;
-    void *fw_cfg;
-
-    linux_boot = (kernel_filename != NULL);
+    int isa_bios_size;
 
-    /* allocate RAM */
-    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
-                              below_4g_mem_size + above_4g_mem_size);
-    cpu_register_physical_memory(0, 0xa0000, ram_addr);
-    cpu_register_physical_memory(0x100000,
-                 below_4g_mem_size - 0x100000,
-                 ram_addr + 0x100000);
-    if (above_4g_mem_size > 0) {
-        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
-                                     ram_addr + below_4g_mem_size);
+    /* map the last 128KB of the BIOS in ISA space */
+    isa_bios_size = ram_size;
+    if (isa_bios_size > (128 * 1024)) {
+        isa_bios_size = 128 * 1024;
     }
+    ram_offset = ram_offset + ram_size - isa_bios_size;
+    cpu_register_physical_memory(0x100000 - isa_bios_size,
+                                 isa_bios_size,
+                                 ram_offset | IO_MEM_ROM);
+}
+
+static int pc_system_rom_init(void)
+{
+    int ret;
+    int bios_size;
+    ram_addr_t bios_offset;
+    char *filename;
 
     /* BIOS load */
-    if (bios_name == NULL)
+    if (bios_name == NULL) {
         bios_name = BIOS_FILENAME;
+    }
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
     if (filename) {
         bios_size = get_image_size(filename);
     } else {
         bios_size = -1;
     }
-    if (bios_size <= 0 ||
-        (bios_size % 65536) != 0) {
-        goto bios_error;
+
+    if (bios_size <= 0 || (bios_size % 65536) != 0) {
+        ret = -1;
+    } else {
+        bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
+        ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
     }
-    bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
-    ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
+
     if (ret != 0) {
-    bios_error:
         fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name);
         exit(1);
     }
+
     if (filename) {
         qemu_free(filename);
     }
-    /* map the last 128KB of the BIOS in ISA space */
-    isa_bios_size = bios_size;
-    if (isa_bios_size > (128 * 1024))
-        isa_bios_size = 128 * 1024;
-    cpu_register_physical_memory(0x100000 - isa_bios_size,
-                                 isa_bios_size,
-                                 (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
 
-    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
-    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE, option_rom_offset);
+    pc_isa_bios_init(bios_offset, bios_size);
 
     /* map all the bios at the top of memory */
     cpu_register_physical_memory((uint32_t)(-bios_size),
                                  bios_size, bios_offset | IO_MEM_ROM);
 
+    return bios_size;
+}
+
+static void pc_system_flash_init(DriveInfo *pflash_drv, int rom_size)
+{
+    BlockDriverState *bdrv;
+    int64_t size;
+    target_phys_addr_t phys_addr;
+    ram_addr_t addr;
+    int sector_bits, sector_size;
+
+    bdrv = NULL;
+
+    bdrv = pflash_drv->bdrv;
+    size = bdrv_getlength(pflash_drv->bdrv);
+    sector_bits = 12;
+    sector_size = 1 << sector_bits;
+
+    if ((size % sector_size) != 0) {
+        fprintf(stderr,
+                "qemu: -pflash size must be a multiple of 0x%x\n",
+                sector_size);
+        exit(1);
+    }
+
+    phys_addr = 0x100000000ULL - rom_size - size;
+    addr = qemu_ram_alloc(NULL, "system.flash", size);
+    DPRINTF("flash addr: 0x%lx\n", (int64_t)phys_addr);
+    pflash_cfi01_register(phys_addr, addr, bdrv,
+                          sector_size, size >> sector_bits,
+                          4, 0x0000, 0x0000, 0x0000, 0x0000, 0);
+
+    if (rom_size == 0) {
+        pc_isa_bios_init(addr, size);
+    }
+}
+
+static void pc_system_firmware_init(void)
+{
+    int flash_present, rom_present;
+    int rom_size;
+    DriveInfo *pflash_drv;
+
+    pflash_drv = drive_get(IF_PFLASH, 0, 0);
+    flash_present = (pflash_drv != NULL);
+
+    /* Load rom if -bios is used or if -pflash is not used */
+    rom_present = ((bios_name != NULL) || !flash_present);
+
+    /* If rom is present, then it is mapped just below 4GB */
+    if (rom_present) {
+        rom_size = pc_system_rom_init();
+    } else {
+        rom_size = 0;
+    }
+
+    /* If flash is present, then it is mapped just below the rom, or
+     * just below 4GB when rom is not present. */
+    if (flash_present) {
+        pc_system_flash_init(pflash_drv, rom_size);
+    }
+}
+
+void pc_memory_init(const char *kernel_filename,
+                    const char *kernel_cmdline,
+                    const char *initrd_filename,
+                    ram_addr_t below_4g_mem_size,
+                    ram_addr_t above_4g_mem_size)
+{
+    int linux_boot, i;
+    ram_addr_t ram_addr, option_rom_offset;
+    void *fw_cfg;
+
+    linux_boot = (kernel_filename != NULL);
+
+    /* allocate RAM */
+    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
+                              below_4g_mem_size + above_4g_mem_size);
+    cpu_register_physical_memory(0, 0xa0000, ram_addr);
+    cpu_register_physical_memory(0x100000,
+                 below_4g_mem_size - 0x100000,
+                 ram_addr + 0x100000);
+    if (above_4g_mem_size > 0) {
+        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
+                                     ram_addr + below_4g_mem_size);
+    }
+
+    /* Initialize ROM or flash ranges for PC firmware */
+    pc_system_firmware_init();
+
+    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
+    cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE, option_rom_offset);
+
     fw_cfg = bochs_bios_init();
     rom_set_fw(fw_cfg);