Add resource table entry for address translation

To avoid having to use a hardcoded memory map to translate between the
Linux physical addresses and device addresses, a new entry type has been
added to the resource table where the host can provide the memory map to
use for the translation.

Change-Id: I668bba3aeac27c358647c969c5504326e1c91d24
Signed-off-by: Mikael Olsson <mikael.olsson@arm.com>
diff --git a/applications/message_handler_openamp/main.cpp b/applications/message_handler_openamp/main.cpp
index 7b755b9..62bdc97 100644
--- a/applications/message_handler_openamp/main.cpp
+++ b/applications/message_handler_openamp/main.cpp
@@ -84,12 +84,24 @@
     },
     // Offset
     {
+        offsetof(ResourceTable, mapping),
 #if defined(REMOTEPROC_TRACE_BUFFER)
         offsetof(ResourceTable, trace),
 #endif
         offsetof(ResourceTable, vdev),
         offsetof(ResourceTable, carveout),
-        },
+    },
+    // Mappings
+    {
+        RSC_MAPPING,
+        ResourceTable::NUM_RANGES,
+        {}
+    },
+    // Ranges
+    {
+        { 0, 0, 0 },
+        { 0, 0, 0 },
+    },
     // Trace buffer
 #if defined(REMOTEPROC_TRACE_BUFFER)
     {
@@ -163,8 +175,7 @@
 int main() {
     printf("Ethos-U Message Handler OpenAMP\n");
 
-    auto mem            = std::make_shared<MetalIO>();
-    auto rproc          = std::make_shared<RProc>(mailbox, resourceTable.table, sizeof(resourceTable), *mem);
+    auto rproc          = std::make_shared<RProc>(mailbox, resourceTable.table, sizeof(resourceTable));
     auto messageHandler = std::make_shared<MessageHandler>(*rproc, "ethos-u-0.0");
 
     printf("TFLM arena. pa=%" PRIx32 ", da=%" PRIx32 ", len=%" PRIx32 "\n",
diff --git a/applications/message_handler_openamp/remoteproc.cpp b/applications/message_handler_openamp/remoteproc.cpp
index f355634..8fda69b 100644
--- a/applications/message_handler_openamp/remoteproc.cpp
+++ b/applications/message_handler_openamp/remoteproc.cpp
@@ -1,6 +1,5 @@
 /*
  * SPDX-FileCopyrightText: Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
- *
  * SPDX-License-Identifier: Apache-2.0
  *
  * Licensed under the Apache License, Version 2.0 (the License); you may
@@ -26,66 +25,39 @@
 
 #include <ethosu_log.h>
 
-/*****************************************************************************
- * MetalIO
- *****************************************************************************/
+namespace {
+void setupRProcMem(remoteproc &rproc,
+                   metal_phys_addr_t pa,
+                   metal_phys_addr_t da,
+                   size_t size,
+                   remoteproc_mem &mem,
+                   metal_io_region &region) {
 
-extern "C" {
-
-__attribute__((weak)) void *ethosu_phys_to_virt(const uint64_t pa) {
-    return reinterpret_cast<void *>(pa);
+    remoteproc_init_mem(&mem, nullptr, pa, da, size, &region);
+    metal_io_init(&region, (void *)da, &mem.pa, size, -1, 0, nullptr);
+    remoteproc_add_mem(&rproc, &mem);
 }
-}
-
-MetalIO::MetalIO() :
-    ops{.read           = nullptr,
-        .write          = nullptr,
-        .block_read     = nullptr,
-        .block_write    = nullptr,
-        .block_set      = nullptr,
-        .close          = nullptr,
-        .offset_to_phys = nullptr,
-        .phys_to_offset = physToOffset} {
-    remoteproc_init_mem(&mem, "shm", 0, 0, 0xffffffff, &region);
-
-    metal_io_init(&region,
-                  reinterpret_cast<void *>(0), /* virt */
-                  &mem.pa,                     /* physmap */
-                  0xffffffff,                  /* size */
-                  -1L,                         /* pagemask */
-                  0,                           /* attributes */
-                  &ops);                       /* ops */
-}
-
-remoteproc_mem *MetalIO::operator&() {
-    return &mem;
-}
-
-unsigned long MetalIO::physToOffset(metal_io_region *io, metal_phys_addr_t pa) {
-    auto offset = reinterpret_cast<unsigned long>(ethosu_phys_to_virt(pa));
-    LOG_DEBUG("Translate PA to offset. pa=%lx, offset=%lx", pa, offset);
-    return offset;
-}
+}; // namespace
 
 /*****************************************************************************
  * RProc
  *****************************************************************************/
 
-RProc::RProc(Mailbox::Mailbox &_mailbox, resource_table &table, size_t tableSize, MetalIO &_mem) :
-    mailbox(_mailbox), mem(_mem),
+RProc::RProc(Mailbox::Mailbox &_mailbox, resource_table &table, size_t tableSize) :
+    mailbox(_mailbox),
     ops{
-        .init       = init,    // initialize the remoteproc instance
-        .remove     = remove,  // remove the remoteproc instance
-        .mmap       = nullptr, // memory mapped the memory with physical address as input
-        .handle_rsc = nullptr, // handle the vendor specific resource
-        .config     = nullptr, // configure the remoteproc to make it ready to load and run executable
-        .start      = nullptr, // kick the remoteproc to run application
+        .init       = init,       // initialize the remoteproc instance
+        .remove     = remove,     // remove the remoteproc instance
+        .mmap       = nullptr,    // memory mapped the memory with physical address as input
+        .handle_rsc = handle_rsc, // handle the vendor specific resource
+        .config     = nullptr,    // configure the remoteproc to make it ready to load and run executable
+        .start      = nullptr,    // kick the remoteproc to run application
         .stop = nullptr, // stop the remoteproc from running application, the resource such as memory may not be off.
         .shutdown = nullptr, // shutdown the remoteproc and release its resources.
         .notify   = notify,  // notify the remote
         .get_mem  = nullptr, // get remoteproc memory I/O region.
     },
-    vdev(nullptr), notifySemaphore(xSemaphoreCreateBinary()) {
+    vdev(nullptr), mems(), regions(), notifySemaphore(xSemaphoreCreateBinary()) {
     mailbox.registerCallback(mailboxCallback, static_cast<void *>(this));
 
     if (!remoteproc_init(&rproc, &ops, this)) {
@@ -93,6 +65,12 @@
         abort();
     }
 
+    // Setup memory region for resource table
+    const metal_phys_addr_t rsc_addr = reinterpret_cast<metal_phys_addr_t>(&table);
+    // No translation is needed for rsc_addr because it already contains the DA
+    // so PA is set to DA
+    setupRProcMem(rproc, rsc_addr, rsc_addr, tableSize, rsc_mem, rsc_region);
+
     int ret = remoteproc_set_rsc_table(&rproc, &table, tableSize);
     if (ret) {
         LOG_ERR("Failed to set resource table. ret=%d", ret);
@@ -148,15 +126,33 @@
 struct remoteproc *RProc::init(remoteproc *rproc, const remoteproc_ops *ops, void *arg) {
     LOG_DEBUG("");
 
-    auto _this = static_cast<RProc *>(arg);
-
     rproc->ops  = ops;
     rproc->priv = arg;
-    remoteproc_add_mem(rproc, &_this->mem);
 
     return rproc;
 }
 
+int RProc::handle_rsc(remoteproc *rproc, void *rsc, size_t len) {
+    auto _this                     = static_cast<RProc *>(rproc->priv);
+    struct fw_rsc_mapping *mapping = static_cast<fw_rsc_mapping *>(rsc);
+
+    if (mapping->type != RSC_MAPPING) {
+        LOG_ERR("Unknown resource type %" PRIu32, mapping->type);
+        return -RPROC_ERR_RSC_TAB_NS;
+    }
+
+    for (uint32_t i = 0; i < mapping->num_ranges; ++i) {
+        const fw_rsc_map_range *range = &mapping->range[i];
+        if (range->len == 0) {
+            LOG_DEBUG("Ignored zero length memory map range[%" PRIu32 "]", i);
+            continue;
+        }
+        setupRProcMem(*rproc, range->pa, range->da, range->len, _this->mems[i], _this->regions[i]);
+    }
+
+    return 0;
+}
+
 void RProc::remove(remoteproc *rproc) {
     LOG_DEBUG("");
 }
@@ -174,14 +170,15 @@
  *****************************************************************************/
 
 Rpmsg::Rpmsg(RProc &rproc, const char *const name) {
+    struct virtio_device *vdev = rproc.getVDev();
 
-    metal_io_region *region = remoteproc_get_io_with_name(rproc.getRProc(), "shm");
-    if (!region) {
-        LOG_ERR("Failed to get shared mem region");
+    if (vdev->vrings_num != ResourceTable::NUM_VRINGS) {
+        LOG_ERR("Invalid number of vrings");
         abort();
     }
 
-    if (rpmsg_init_vdev(&rvdev, rproc.getVDev(), nullptr, region, nullptr)) {
+    // Vdev can use the same IO region for translations as the vring
+    if (rpmsg_init_vdev(&rvdev, vdev, nullptr, vdev->vrings_info[0].io, nullptr)) {
         LOG_ERR("Failed to initialize rpmsg vdev");
         abort();
     }
diff --git a/applications/message_handler_openamp/remoteproc.hpp b/applications/message_handler_openamp/remoteproc.hpp
index eec7b44..090a3ea 100644
--- a/applications/message_handler_openamp/remoteproc.hpp
+++ b/applications/message_handler_openamp/remoteproc.hpp
@@ -1,6 +1,5 @@
 /*
  * SPDX-FileCopyrightText: Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
- *
  * SPDX-License-Identifier: Apache-2.0
  *
  * Licensed under the Apache License, Version 2.0 (the License); you may
@@ -36,13 +35,47 @@
  * Resource table
  *****************************************************************************/
 
+static constexpr uint32_t RSC_MAPPING = RSC_VENDOR_START + 1;
+
+/**
+ * struct fw_rsc_map_range - memory map range
+ * @da: Start device address of the memory address range
+ * @pa: Start physical address of the memory address range
+ * @len: length of memory address range
+ *
+ * Memory range to translate between physical and device addresses.
+ */
+METAL_PACKED_BEGIN
+struct fw_rsc_map_range {
+    uint32_t da;
+    uint32_t pa;
+    uint32_t len;
+} METAL_PACKED_END;
+
+/**
+ * struct fw_rsc_mapping - memory map for address translation
+ * @type: RSC_MAPPING
+ * @num_ranges: Number of ranges in the memory map
+ * @range: Array of the ranges in the memory map
+ *
+ * This resource entry requests the host to provide information for how to
+ * translate between physical and device addresses.
+ */
+METAL_PACKED_BEGIN
+struct fw_rsc_mapping {
+    uint32_t type;
+    uint8_t num_ranges;
+    struct fw_rsc_map_range range[0];
+} METAL_PACKED_END;
+
 struct ResourceTable {
     static constexpr uint32_t VERSION = 1;
 #if defined(REMOTEPROC_TRACE_BUFFER)
-    static constexpr uint32_t NUM_RESOURCES = 3;
+    static constexpr uint32_t NUM_RESOURCES = 4;
 #else
-    static constexpr uint32_t NUM_RESOURCES = 2;
+    static constexpr uint32_t NUM_RESOURCES = 3;
 #endif
+    static constexpr uint32_t NUM_RANGES  = 2;
     static constexpr uint32_t NUM_VRINGS  = 2;
     static constexpr uint32_t VRING_ALIGN = 0x100;
     static constexpr uint32_t VRING_SIZE  = 0x08;
@@ -50,6 +83,8 @@
 
     resource_table table;
     uint32_t offset[NUM_RESOURCES];
+    fw_rsc_mapping mapping;
+    fw_rsc_map_range range[NUM_RANGES];
 #if defined(REMOTEPROC_TRACE_BUFFER)
     fw_rsc_trace trace;
 #endif
@@ -59,31 +94,12 @@
 } __attribute__((packed));
 
 /*****************************************************************************
- * MetalIO
- *****************************************************************************/
-
-class MetalIO {
-public:
-    MetalIO();
-
-    remoteproc_mem *operator&();
-
-private:
-    static metal_phys_addr_t offsetToPhys(metal_io_region *io, unsigned long offset);
-    static unsigned long physToOffset(metal_io_region *io, metal_phys_addr_t phys);
-
-    metal_io_ops ops;
-    metal_io_region region;
-    remoteproc_mem mem;
-};
-
-/*****************************************************************************
  * RProc
  *****************************************************************************/
 
 class RProc {
 public:
-    RProc(Mailbox::Mailbox &_mailbox, resource_table &table, size_t tableSize, MetalIO &_mem);
+    RProc(Mailbox::Mailbox &_mailbox, resource_table &table, size_t tableSize);
     ~RProc();
 
     remoteproc *getRProc();
@@ -99,30 +115,25 @@
     // Remote proc ops
     static struct remoteproc *init(remoteproc *rproc, const remoteproc_ops *ops, void *arg);
     static void remove(remoteproc *rproc);
-    static void *mmap(remoteproc *rproc,
-                      metal_phys_addr_t *pa,
-                      metal_phys_addr_t *da,
-                      size_t size,
-                      unsigned int attribute,
-                      metal_io_region **io);
+    static int handle_rsc(struct remoteproc *rproc, void *rsc, size_t len);
     static int notify(remoteproc *rproc, uint32_t id);
-    static struct remoteproc_mem *getMem(remoteproc *rproc,
-                                         const char *name,
-                                         metal_phys_addr_t pa,
-                                         metal_phys_addr_t da,
-                                         void *va,
-                                         size_t size,
-                                         remoteproc_mem *buf);
 
     // IRQ notification
     Mailbox::Mailbox &mailbox;
 
     // Remoteproc
-    MetalIO &mem;
     remoteproc rproc;
     remoteproc_ops ops;
     virtio_device *vdev;
 
+    // Resource table memory region
+    remoteproc_mem rsc_mem;
+    metal_io_region rsc_region;
+
+    // Host provided memory regions
+    remoteproc_mem mems[ResourceTable::NUM_RANGES];
+    metal_io_region regions[ResourceTable::NUM_RANGES];
+
     // FreeRTOS
     SemaphoreHandle_t notifySemaphore;
     TaskHandle_t notifyHandle;