hw/ppc/e500: Implement pflash handling
Allows e500 boards to have their root file system reside on flash using only builtin devices located in the eLBC memory region. Note that the flash memory area is only created when a -pflash argument is given, and that the size is determined by the given file. The idea is to put users into control. Signed-off-by: Bernhard Beschow <shentey@gmail.com> Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-Id: <20221018210146.193159-6-shentey@gmail.com> [danielhb: use memory_region_size() in mmio_size] Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
This commit is contained in:
parent
1e76667f7a
commit
63e4bf8e84
@ -165,3 +165,18 @@ if “-device eTSEC” is given to QEMU:
|
|||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
-netdev tap,ifname=tap0,script=no,downscript=no,id=net0 -device eTSEC,netdev=net0
|
-netdev tap,ifname=tap0,script=no,downscript=no,id=net0 -device eTSEC,netdev=net0
|
||||||
|
|
||||||
|
Root file system on flash drive
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
Rather than using a root file system on ram disk, it is possible to have it on
|
||||||
|
CFI flash. Given an ext2 image whose size must be a power of two, it can be used
|
||||||
|
as follows:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ qemu-system-ppc64 -M ppce500 -cpu e500mc -smp 4 -m 2G \
|
||||||
|
-display none -serial stdio \
|
||||||
|
-kernel vmlinux \
|
||||||
|
-drive if=pflash,file=/path/to/rootfs.ext2,format=raw \
|
||||||
|
-append "rootwait root=/dev/mtdblock0"
|
||||||
|
@ -126,6 +126,7 @@ config E500
|
|||||||
select ETSEC
|
select ETSEC
|
||||||
select GPIO_MPC8XXX
|
select GPIO_MPC8XXX
|
||||||
select OPENPIC
|
select OPENPIC
|
||||||
|
select PFLASH_CFI01
|
||||||
select PLATFORM_BUS
|
select PLATFORM_BUS
|
||||||
select PPCE500_PCI
|
select PPCE500_PCI
|
||||||
select SERIAL
|
select SERIAL
|
||||||
|
@ -23,8 +23,10 @@
|
|||||||
#include "e500-ccsr.h"
|
#include "e500-ccsr.h"
|
||||||
#include "net/net.h"
|
#include "net/net.h"
|
||||||
#include "qemu/config-file.h"
|
#include "qemu/config-file.h"
|
||||||
|
#include "hw/block/flash.h"
|
||||||
#include "hw/char/serial.h"
|
#include "hw/char/serial.h"
|
||||||
#include "hw/pci/pci.h"
|
#include "hw/pci/pci.h"
|
||||||
|
#include "sysemu/block-backend-io.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
#include "sysemu/reset.h"
|
#include "sysemu/reset.h"
|
||||||
@ -267,6 +269,31 @@ static void sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void create_devtree_flash(SysBusDevice *sbdev,
|
||||||
|
PlatformDevtreeData *data)
|
||||||
|
{
|
||||||
|
g_autofree char *name = NULL;
|
||||||
|
uint64_t num_blocks = object_property_get_uint(OBJECT(sbdev),
|
||||||
|
"num-blocks",
|
||||||
|
&error_fatal);
|
||||||
|
uint64_t sector_length = object_property_get_uint(OBJECT(sbdev),
|
||||||
|
"sector-length",
|
||||||
|
&error_fatal);
|
||||||
|
uint64_t bank_width = object_property_get_uint(OBJECT(sbdev),
|
||||||
|
"width",
|
||||||
|
&error_fatal);
|
||||||
|
hwaddr flashbase = 0;
|
||||||
|
hwaddr flashsize = num_blocks * sector_length;
|
||||||
|
void *fdt = data->fdt;
|
||||||
|
|
||||||
|
name = g_strdup_printf("%s/nor@%" PRIx64, data->node, flashbase);
|
||||||
|
qemu_fdt_add_subnode(fdt, name);
|
||||||
|
qemu_fdt_setprop_string(fdt, name, "compatible", "cfi-flash");
|
||||||
|
qemu_fdt_setprop_sized_cells(fdt, name, "reg",
|
||||||
|
1, flashbase, 1, flashsize);
|
||||||
|
qemu_fdt_setprop_cell(fdt, name, "bank-width", bank_width);
|
||||||
|
}
|
||||||
|
|
||||||
static void platform_bus_create_devtree(PPCE500MachineState *pms,
|
static void platform_bus_create_devtree(PPCE500MachineState *pms,
|
||||||
void *fdt, const char *mpic)
|
void *fdt, const char *mpic)
|
||||||
{
|
{
|
||||||
@ -276,6 +303,8 @@ static void platform_bus_create_devtree(PPCE500MachineState *pms,
|
|||||||
uint64_t addr = pmc->platform_bus_base;
|
uint64_t addr = pmc->platform_bus_base;
|
||||||
uint64_t size = pmc->platform_bus_size;
|
uint64_t size = pmc->platform_bus_size;
|
||||||
int irq_start = pmc->platform_bus_first_irq;
|
int irq_start = pmc->platform_bus_first_irq;
|
||||||
|
SysBusDevice *sbdev;
|
||||||
|
bool ambiguous;
|
||||||
|
|
||||||
/* Create a /platform node that we can put all devices into */
|
/* Create a /platform node that we can put all devices into */
|
||||||
|
|
||||||
@ -302,6 +331,13 @@ static void platform_bus_create_devtree(PPCE500MachineState *pms,
|
|||||||
/* Loop through all dynamic sysbus devices and create nodes for them */
|
/* Loop through all dynamic sysbus devices and create nodes for them */
|
||||||
foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data);
|
foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data);
|
||||||
|
|
||||||
|
sbdev = SYS_BUS_DEVICE(object_resolve_path_type("", TYPE_PFLASH_CFI01,
|
||||||
|
&ambiguous));
|
||||||
|
if (sbdev) {
|
||||||
|
assert(!ambiguous);
|
||||||
|
create_devtree_flash(sbdev, &data);
|
||||||
|
}
|
||||||
|
|
||||||
g_free(node);
|
g_free(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -856,6 +892,7 @@ void ppce500_init(MachineState *machine)
|
|||||||
unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
|
unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
|
||||||
IrqLines *irqs;
|
IrqLines *irqs;
|
||||||
DeviceState *dev, *mpicdev;
|
DeviceState *dev, *mpicdev;
|
||||||
|
DriveInfo *dinfo;
|
||||||
CPUPPCState *firstenv = NULL;
|
CPUPPCState *firstenv = NULL;
|
||||||
MemoryRegion *ccsr_addr_space;
|
MemoryRegion *ccsr_addr_space;
|
||||||
SysBusDevice *s;
|
SysBusDevice *s;
|
||||||
@ -1024,6 +1061,48 @@ void ppce500_init(MachineState *machine)
|
|||||||
pmc->platform_bus_base,
|
pmc->platform_bus_base,
|
||||||
&pms->pbus_dev->mmio);
|
&pms->pbus_dev->mmio);
|
||||||
|
|
||||||
|
dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||||
|
if (dinfo) {
|
||||||
|
BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
|
||||||
|
BlockDriverState *bs = blk_bs(blk);
|
||||||
|
uint64_t mmio_size = memory_region_size(&pms->pbus_dev->mmio);
|
||||||
|
uint64_t size = bdrv_getlength(bs);
|
||||||
|
uint32_t sector_len = 64 * KiB;
|
||||||
|
|
||||||
|
if (!is_power_of_2(size)) {
|
||||||
|
error_report("Size of pflash file must be a power of two.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size > mmio_size) {
|
||||||
|
error_report("Size of pflash file must not be bigger than %" PRIu64
|
||||||
|
" bytes.", mmio_size);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!QEMU_IS_ALIGNED(size, sector_len)) {
|
||||||
|
error_report("Size of pflash file must be a multiple of %" PRIu32
|
||||||
|
".", sector_len);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = qdev_new(TYPE_PFLASH_CFI01);
|
||||||
|
qdev_prop_set_drive(dev, "drive", blk);
|
||||||
|
qdev_prop_set_uint32(dev, "num-blocks", size / sector_len);
|
||||||
|
qdev_prop_set_uint64(dev, "sector-length", sector_len);
|
||||||
|
qdev_prop_set_uint8(dev, "width", 2);
|
||||||
|
qdev_prop_set_bit(dev, "big-endian", true);
|
||||||
|
qdev_prop_set_uint16(dev, "id0", 0x89);
|
||||||
|
qdev_prop_set_uint16(dev, "id1", 0x18);
|
||||||
|
qdev_prop_set_uint16(dev, "id2", 0x0000);
|
||||||
|
qdev_prop_set_uint16(dev, "id3", 0x0);
|
||||||
|
qdev_prop_set_string(dev, "name", "e500.flash");
|
||||||
|
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||||
|
|
||||||
|
memory_region_add_subregion(&pms->pbus_dev->mmio, 0,
|
||||||
|
pflash_cfi01_get_memory(PFLASH_CFI01(dev)));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Smart firmware defaults ahead!
|
* Smart firmware defaults ahead!
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user