qemu-arm
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-arm] [PATCH 3/4] aspeed/smc: add a new memory region dedicated to


From: Cédric Le Goater
Subject: [Qemu-arm] [PATCH 3/4] aspeed/smc: add a new memory region dedicated to MMIO execution
Date: Wed, 30 May 2018 09:50:01 +0200

The Aspeed SoC are generally booted from one of the flash modules
behind the FMC controller. The FMC CS0 flash module is mapped at a
specific address depending on the SoC revision and also at 0x0, the
default boot-up address.

To support this second mapping, we add a new 'ROM' like memory region
under the FMC flash module model and activate support for MMIO
execution with a 'request_ptr' handler. The latter fills up a cache of
flash content to be executed or read by the boot up process.

Also add a 'mmio_exec' bool to activate the feature which still has
some issues.

Signed-off-by: Cédric Le Goater <address@hidden>
---
 include/hw/ssi/aspeed_smc.h |   7 +++
 hw/ssi/aspeed_smc.c         | 122 +++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 128 insertions(+), 1 deletion(-)

diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h
index 1f557313fa93..5e853afe725d 100644
--- a/include/hw/ssi/aspeed_smc.h
+++ b/include/hw/ssi/aspeed_smc.h
@@ -48,6 +48,8 @@ typedef struct AspeedSMCController {
     uint32_t nregs;
 } AspeedSMCController;
 
+#define ASPEED_SMC_CACHE_SIZE    1024  /* 1K is the minimum */
+
 typedef struct AspeedSMCFlash {
     struct AspeedSMCState *controller;
 
@@ -56,6 +58,10 @@ typedef struct AspeedSMCFlash {
 
     MemoryRegion mmio;
     DeviceState *flash;
+
+    MemoryRegion mmio_rom;
+    uint8_t cache[ASPEED_SMC_CACHE_SIZE];
+    hwaddr cache_addr;
 } AspeedSMCFlash;
 
 #define TYPE_ASPEED_SMC "aspeed.smc"
@@ -79,6 +85,7 @@ typedef struct AspeedSMCState {
 
     MemoryRegion mmio;
     MemoryRegion mmio_flash;
+    bool mmio_exec;
 
     qemu_irq irq;
     int irqline;
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index 5808181568c4..d599eebc7d21 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -604,6 +604,96 @@ static const MemoryRegionOps aspeed_smc_flash_ops = {
     },
 };
 
+static bool aspeed_smc_flash_rom_is_cached(AspeedSMCFlash *fl, hwaddr addr)
+{
+    return (addr >= fl->cache_addr &&
+            addr <= fl->cache_addr + ASPEED_SMC_CACHE_SIZE - 4);
+}
+
+static void aspeed_smc_flash_rom_load_cache(AspeedSMCFlash *fl, hwaddr addr)
+{
+    AspeedSMCState *s = fl->controller;
+    hwaddr cache_addr = addr & ~(ASPEED_SMC_CACHE_SIZE - 1);
+    int i;
+
+    if (fl->cache_addr != ~0ULL) {
+        memory_region_invalidate_mmio_ptr(&fl->mmio_rom, fl->cache_addr,
+                                          ASPEED_SMC_CACHE_SIZE);
+    }
+
+    aspeed_smc_flash_select(fl);
+    aspeed_smc_flash_setup(fl, cache_addr);
+
+    for (i = 0; i < ASPEED_SMC_CACHE_SIZE; i++) {
+        fl->cache[i] = ssi_transfer(s->spi, 0x0);
+    }
+
+    aspeed_smc_flash_unselect(fl);
+
+    fl->cache_addr = cache_addr;
+}
+
+static void *aspeed_smc_flash_rom_request_ptr(void *opaque, hwaddr addr,
+                                              unsigned *size, unsigned *offset)
+{
+    AspeedSMCFlash *fl = opaque;
+
+    if (!aspeed_smc_flash_rom_is_cached(fl, addr)) {
+        aspeed_smc_flash_rom_load_cache(fl, addr);
+    }
+
+    *size = ASPEED_SMC_CACHE_SIZE;
+    *offset = fl->cache_addr;
+    return fl->cache;
+}
+
+static uint64_t aspeed_smc_flash_rom_read(void *opaque, hwaddr addr,
+                                          unsigned size)
+{
+    AspeedSMCFlash *fl = opaque;
+    AspeedSMCState *s = fl->controller;
+    uint64_t ret = 0;
+    int i;
+
+    /*
+     * Transfer or use the cache if possible. Reloading the cache
+     * while loading from the flash can break the TCG execution flow.
+     */
+    if (!aspeed_smc_flash_rom_is_cached(fl, addr)) {
+        aspeed_smc_flash_select(fl);
+        aspeed_smc_flash_setup(fl, addr);
+
+        for (i = 0; i < size; i++) {
+            ret |= (uint64_t) ssi_transfer(s->spi, 0x0) << (8 * i);
+        }
+
+        aspeed_smc_flash_unselect(fl);
+    } else {
+        for (i = 0; i < size; i++) {
+            ret |= (uint64_t) fl->cache[addr - fl->cache_addr + i] << (8 * i);
+        }
+    }
+    return ret;
+}
+
+static void aspeed_smc_flash_rom_write(void *opaque, hwaddr addr, uint64_t 
data,
+                                       unsigned size)
+{
+    qemu_log_mask(LOG_GUEST_ERROR, "%s: flash is not writable at 0x%"
+                  HWADDR_PRIx "\n", __func__, addr);
+}
+
+static const MemoryRegionOps aspeed_smc_flash_rom_ops = {
+    .read = aspeed_smc_flash_rom_read,
+    .write = aspeed_smc_flash_rom_write,
+    .request_ptr = aspeed_smc_flash_rom_request_ptr,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+};
+
 static void aspeed_smc_flash_update_cs(AspeedSMCFlash *fl)
 {
     const AspeedSMCState *s = fl->controller;
@@ -778,21 +868,51 @@ static void aspeed_smc_realize(DeviceState *dev, Error 
**errp)
                               fl, name, fl->size);
         memory_region_add_subregion(&s->mmio_flash, offset, &fl->mmio);
         offset += fl->size;
+
+        /*
+         * The system is generally booted from one of the flash
+         * modules behind the FMC controller. Initialize the 'ROM'
+         * region which supports MMIO execution and let the board
+         * decide how to use them.
+         */
+        if ((s->ctrl->segments == aspeed_segments_ast2500_fmc ||
+             s->ctrl->segments == aspeed_segments_fmc) && s->mmio_exec) {
+            snprintf(name, sizeof(name), "%s.%d-rom", s->ctrl->name, i);
+
+            memory_region_init_io(&fl->mmio_rom, OBJECT(s),
+                                  &aspeed_smc_flash_rom_ops,
+                                  fl, name, fl->size);
+            fl->cache_addr = ~0ULL;
+        }
     }
 }
 
+static const VMStateDescription vmstate_aspeed_smc_flash = {
+    .name = TYPE_ASPEED_SMC "/flash",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT8_ARRAY(cache, AspeedSMCFlash, ASPEED_SMC_CACHE_SIZE),
+        VMSTATE_UINT64(cache_addr, AspeedSMCFlash),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
 static const VMStateDescription vmstate_aspeed_smc = {
-    .name = "aspeed.smc",
+    .name = TYPE_ASPEED_SMC,
     .version_id = 1,
     .minimum_version_id = 1,
     .fields = (VMStateField[]) {
         VMSTATE_UINT32_ARRAY(regs, AspeedSMCState, ASPEED_SMC_R_MAX),
+        VMSTATE_STRUCT_VARRAY_POINTER_UINT32(flashes, AspeedSMCState, num_cs,
+                                     vmstate_aspeed_smc_flash, AspeedSMCFlash),
         VMSTATE_END_OF_LIST()
     }
 };
 
 static Property aspeed_smc_properties[] = {
     DEFINE_PROP_UINT32("num-cs", AspeedSMCState, num_cs, 1),
+    DEFINE_PROP_BOOL("mmio-exec", AspeedSMCState, mmio_exec, false),
     DEFINE_PROP_END_OF_LIST(),
 };
 
-- 
2.13.6




reply via email to

[Prev in Thread] Current Thread [Next in Thread]