adiv6: add support for ROM tables in AP 67/6467/5
authorAntonio Borneo <borneo.antonio@gmail.com>
Wed, 11 Aug 2021 13:29:45 +0000 (15:29 +0200)
committerAntonio Borneo <borneo.antonio@gmail.com>
Fri, 24 Jun 2022 21:38:52 +0000 (21:38 +0000)
ADIv6 adds AP that only contain a ROM table in the AP itself, that
can point to other AP containing either another AP level ROM table
or a MEM-AP to be parsed as usual.

Add support for parsing AP level ROM tables.

Change-Id: Ic25863b16463b8a6adc3b15e26db7fdca858d6df
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/6467
Tested-by: jenkins
src/target/arm_adi_v5.c

index ad4d7a7254416d0d9c87c466ad55c18e7b3ab703..84518b0a10199e856ddcb73a204fe0d12e2e7c8c 100644 (file)
@@ -928,6 +928,7 @@ static const struct {
 };
 
 #define DEVARCH_ID_MASK         (ARM_CS_C9_DEVARCH_ARCHITECT_MASK | ARM_CS_C9_DEVARCH_ARCHID_MASK)
+#define DEVARCH_MEM_AP          ARCH_ID(ARM_ID, 0x0A17)
 #define DEVARCH_ROM_C_0X9       ARCH_ID(ARM_ID, 0x0AF7)
 
 static const char *class0x9_devarch_description(uint32_t devarch)
@@ -1180,6 +1181,17 @@ int adiv6_dap_read_baseptr(struct command_invocation *cmd, struct adiv5_dap *dap
        return ERROR_OK;
 }
 
+/**
+ * Method to access the CoreSight component.
+ * On ADIv5, CoreSight components are on the bus behind a MEM-AP.
+ * On ADIv6, CoreSight components can either be on the bus behind a MEM-AP
+ * or directly in the AP.
+ */
+enum coresight_access_mode {
+       CS_ACCESS_AP,
+       CS_ACCESS_MEM_AP,
+};
+
 /** Holds registers and coordinates of a CoreSight component */
 struct cs_component_vals {
        struct adiv5_ap *ap;
@@ -1189,19 +1201,43 @@ struct cs_component_vals {
        uint32_t devarch;
        uint32_t devid;
        uint32_t devtype_memtype;
+       enum coresight_access_mode mode;
 };
 
+/**
+ * Helper to read CoreSight component's registers, either on the bus
+ * behind a MEM-AP or directly in the AP.
+ *
+ * @param mode           Method to access the component (AP or MEM-AP).
+ * @param ap             Pointer to AP containing the component.
+ * @param component_base On MEM-AP access method, base address of the component.
+ * @param reg            Offset of the component's register to read.
+ * @param value          Pointer to the store the read value.
+ *
+ * @return ERROR_OK on success, else a fault code.
+ */
+static int dap_queue_read_reg(enum coresight_access_mode mode, struct adiv5_ap *ap,
+               uint64_t component_base, unsigned int reg, uint32_t *value)
+{
+       if (mode == CS_ACCESS_AP)
+               return dap_queue_ap_read(ap, reg, value);
+
+       /* mode == CS_ACCESS_MEM_AP */
+       return mem_ap_read_u32(ap, component_base + reg, value);
+}
+
 /**
  * Read the CoreSight registers needed during ROM Table Parsing (RTP).
  *
+ * @param mode           Method to access the component (AP or MEM-AP).
  * @param ap             Pointer to AP containing the component.
  * @param component_base On MEM-AP access method, base address of the component.
  * @param v              Pointer to the struct holding the value of registers.
  *
  * @return ERROR_OK on success, else a fault code.
  */
-static int rtp_read_cs_regs(struct adiv5_ap *ap, target_addr_t component_base,
-               struct cs_component_vals *v)
+static int rtp_read_cs_regs(enum coresight_access_mode mode, struct adiv5_ap *ap,
+               target_addr_t component_base, struct cs_component_vals *v)
 {
        assert(IS_ALIGNED(component_base, ARM_CS_ALIGN));
        assert(ap && v);
@@ -1212,6 +1248,7 @@ static int rtp_read_cs_regs(struct adiv5_ap *ap, target_addr_t component_base,
 
        v->ap = ap;
        v->component_base = component_base;
+       v->mode = mode;
 
        /* sort by offset to gain speed */
 
@@ -1221,35 +1258,35 @@ static int rtp_read_cs_regs(struct adiv5_ap *ap, target_addr_t component_base,
         * without triggering error. Read them for eventual use on Class 0x9.
         */
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_C9_DEVARCH, &v->devarch);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_C9_DEVARCH, &v->devarch);
 
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_C9_DEVID, &v->devid);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_C9_DEVID, &v->devid);
 
        /* Same address as ARM_CS_C1_MEMTYPE */
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_C9_DEVTYPE, &v->devtype_memtype);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_C9_DEVTYPE, &v->devtype_memtype);
 
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR4, &pid4);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR4, &pid4);
 
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR0, &pid0);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR0, &pid0);
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR1, &pid1);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR1, &pid1);
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR2, &pid2);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR2, &pid2);
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR3, &pid3);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_PIDR3, &pid3);
 
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR0, &cid0);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_CIDR0, &cid0);
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR1, &cid1);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_CIDR1, &cid1);
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR2, &cid2);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_CIDR2, &cid2);
        if (retval == ERROR_OK)
-               retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR3, &cid3);
+               retval = dap_queue_read_reg(mode, ap, component_base, ARM_CS_CIDR3, &cid3);
 
        if (retval == ERROR_OK)
                retval = dap_run(ap->dap);
@@ -1572,6 +1609,14 @@ static int dap_devtype_display(struct command_invocation *cmd, uint32_t devtype)
  * Actions/operations to be executed while parsing ROM tables.
  */
 struct rtp_ops {
+       /**
+        * Executed at the start of a new AP, typically to print the AP header.
+        * @param ap        Pointer to AP.
+        * @param depth     The current depth level of ROM table.
+        * @param priv      Pointer to private data.
+        * @return          ERROR_OK on success, else a fault code.
+        */
+       int (*ap_header)(struct adiv5_ap *ap, int depth, void *priv);
        /**
         * Executed at the start of a new MEM-AP, typically to print the MEM-AP header.
         * @param retval    Error encountered while reading AP.
@@ -1612,6 +1657,18 @@ struct rtp_ops {
        void *priv;
 };
 
+/**
+ * Wrapper around struct rtp_ops::ap_header.
+ */
+static int rtp_ops_ap_header(const struct rtp_ops *ops,
+               struct adiv5_ap *ap, int depth)
+{
+       if (ops->ap_header)
+               return ops->ap_header(ap, depth, ops->priv);
+
+       return ERROR_OK;
+}
+
 /**
  * Wrapper around struct rtp_ops::mem_ap_header.
  * Input parameter @a retval is propagated.
@@ -1671,13 +1728,18 @@ static int rtp_ops_rom_table_entry(const struct rtp_ops *ops,
  */
 #define CORESIGHT_COMPONENT_FOUND (1)
 
-static int rtp_cs_component(const struct rtp_ops *ops,
-               struct adiv5_ap *ap, target_addr_t dbgbase, int depth);
+static int rtp_ap(const struct rtp_ops *ops, struct adiv5_ap *ap, int depth);
+static int rtp_cs_component(enum coresight_access_mode mode, const struct rtp_ops *ops,
+               struct adiv5_ap *ap, target_addr_t dbgbase, bool *is_mem_ap, int depth);
 
-static int rtp_rom_loop(const struct rtp_ops *ops,
+static int rtp_rom_loop(enum coresight_access_mode mode, const struct rtp_ops *ops,
                struct adiv5_ap *ap, target_addr_t base_address, int depth,
                unsigned int width, unsigned int max_entries)
 {
+       /* ADIv6 AP ROM table provide offset from current AP */
+       if (mode == CS_ACCESS_AP)
+               base_address = ap->ap_num;
+
        assert(IS_ALIGNED(base_address, ARM_CS_ALIGN));
 
        unsigned int offset = 0;
@@ -1687,10 +1749,10 @@ static int rtp_rom_loop(const struct rtp_ops *ops,
                target_addr_t component_base;
                unsigned int saved_offset = offset;
 
-               int retval = mem_ap_read_u32(ap, base_address + offset, &romentry_low);
+               int retval = dap_queue_read_reg(mode, ap, base_address, offset, &romentry_low);
                offset += 4;
                if (retval == ERROR_OK && width == 64) {
-                       retval = mem_ap_read_u32(ap, base_address + offset, &romentry_high);
+                       retval = dap_queue_read_reg(mode, ap, base_address, offset, &romentry_high);
                        offset += 4;
                }
                if (retval == ERROR_OK)
@@ -1724,7 +1786,18 @@ static int rtp_rom_loop(const struct rtp_ops *ops,
                        continue;
 
                /* Recurse */
-               retval = rtp_cs_component(ops, ap, component_base, depth + 1);
+               if (mode == CS_ACCESS_AP) {
+                       struct adiv5_ap *next_ap = dap_get_ap(ap->dap, component_base);
+                       if (!next_ap) {
+                               LOG_DEBUG("Wrong AP # 0x%" PRIx64, component_base);
+                               continue;
+                       }
+                       retval = rtp_ap(ops, next_ap, depth + 1);
+                       dap_put_ap(next_ap);
+               } else {
+                       /* mode == CS_ACCESS_MEM_AP */
+                       retval = rtp_cs_component(mode, ops, ap, component_base, NULL, depth + 1);
+               }
                if (retval == CORESIGHT_COMPONENT_FOUND)
                        return CORESIGHT_COMPONENT_FOUND;
                if (retval != ERROR_OK) {
@@ -1737,18 +1810,21 @@ static int rtp_rom_loop(const struct rtp_ops *ops,
        return ERROR_OK;
 }
 
-static int rtp_cs_component(const struct rtp_ops *ops,
-               struct adiv5_ap *ap, target_addr_t base_address, int depth)
+static int rtp_cs_component(enum coresight_access_mode mode, const struct rtp_ops *ops,
+               struct adiv5_ap *ap, target_addr_t base_address, bool *is_mem_ap, int depth)
 {
        struct cs_component_vals v;
        int retval;
 
        assert(IS_ALIGNED(base_address, ARM_CS_ALIGN));
 
+       if (is_mem_ap)
+               *is_mem_ap = false;
+
        if (depth > ROM_TABLE_MAX_DEPTH)
                retval = ERROR_FAIL;
        else
-               retval = rtp_read_cs_regs(ap, base_address, &v);
+               retval = rtp_read_cs_regs(mode, ap, base_address, &v);
 
        retval = rtp_ops_cs_component(ops, retval, &v, depth);
        if (retval == CORESIGHT_COMPONENT_FOUND)
@@ -1762,20 +1838,23 @@ static int rtp_cs_component(const struct rtp_ops *ops,
        const unsigned int class = ARM_CS_CIDR_CLASS(v.cid);
 
        if (class == ARM_CS_CLASS_0X1_ROM_TABLE)
-               return rtp_rom_loop(ops, ap, base_address, depth, 32, 960);
+               return rtp_rom_loop(mode, ops, ap, base_address, depth, 32, 960);
 
        if (class == ARM_CS_CLASS_0X9_CS_COMPONENT) {
                if ((v.devarch & ARM_CS_C9_DEVARCH_PRESENT) == 0)
                        return ERROR_OK;
 
+               if (is_mem_ap && (v.devarch & DEVARCH_ID_MASK) == DEVARCH_MEM_AP)
+                       *is_mem_ap = true;
+
                /* quit if not ROM table */
                if ((v.devarch & DEVARCH_ID_MASK) != DEVARCH_ROM_C_0X9)
                        return ERROR_OK;
 
                if ((v.devid & ARM_CS_C9_DEVID_FORMAT_MASK) == ARM_CS_C9_DEVID_FORMAT_64BIT)
-                       return rtp_rom_loop(ops, ap, base_address, depth, 64, 256);
+                       return rtp_rom_loop(mode, ops, ap, base_address, depth, 64, 256);
                else
-                       return rtp_rom_loop(ops, ap, base_address, depth, 32, 512);
+                       return rtp_rom_loop(mode, ops, ap, base_address, depth, 32, 512);
        }
 
        /* Class other than 0x1 and 0x9 */
@@ -1784,10 +1863,26 @@ static int rtp_cs_component(const struct rtp_ops *ops,
 
 static int rtp_ap(const struct rtp_ops *ops, struct adiv5_ap *ap, int depth)
 {
-       int retval;
        uint32_t apid;
        target_addr_t dbgbase, invalid_entry;
 
+       int retval = rtp_ops_ap_header(ops, ap, depth);
+       if (retval != ERROR_OK || depth > ROM_TABLE_MAX_DEPTH)
+               return ERROR_OK; /* Don't abort recursion */
+
+       if (is_adiv6(ap->dap)) {
+               bool is_mem_ap;
+               retval = rtp_cs_component(CS_ACCESS_AP, ops, ap, 0, &is_mem_ap, depth);
+               if (retval == CORESIGHT_COMPONENT_FOUND)
+                       return CORESIGHT_COMPONENT_FOUND;
+               if (retval != ERROR_OK)
+                       return ERROR_OK; /* Don't abort recursion */
+
+               if (!is_mem_ap)
+                       return ERROR_OK;
+               /* Continue for an ADIv6 MEM-AP */
+       }
+
        /* Now we read ROM table ID registers, ref. ARM IHI 0029B sec  */
        retval = dap_get_debugbase(ap, &dbgbase, &apid);
        if (retval != ERROR_OK)
@@ -1811,7 +1906,8 @@ static int rtp_ap(const struct rtp_ops *ops, struct adiv5_ap *ap, int depth)
                        invalid_entry = 0xFFFFFFFFul;
 
                if (dbgbase != invalid_entry && (dbgbase & 0x3) != 0x2) {
-                       retval = rtp_cs_component(ops, ap, dbgbase & 0xFFFFFFFFFFFFF000ull, depth);
+                       retval = rtp_cs_component(CS_ACCESS_MEM_AP, ops, ap,
+                                       dbgbase & 0xFFFFFFFFFFFFF000ull, NULL, depth);
                        if (retval == CORESIGHT_COMPONENT_FOUND)
                                return CORESIGHT_COMPONENT_FOUND;
                }
@@ -1822,6 +1918,19 @@ static int rtp_ap(const struct rtp_ops *ops, struct adiv5_ap *ap, int depth)
 
 /* Actions for command "dap info" */
 
+static int dap_info_ap_header(struct adiv5_ap *ap, int depth, void *priv)
+{
+       struct command_invocation *cmd = priv;
+
+       if (depth > ROM_TABLE_MAX_DEPTH) {
+               command_print(cmd, "\tTables too deep");
+               return ERROR_FAIL;
+       }
+
+       command_print(cmd, "%sAP # 0x%" PRIx64, (depth) ? "\t\t" : "", ap->ap_num);
+       return ERROR_OK;
+}
+
 static int dap_info_mem_ap_header(int retval, struct adiv5_ap *ap,
                target_addr_t dbgbase, uint32_t apid, int depth, void *priv)
 {
@@ -1842,8 +1951,6 @@ static int dap_info_mem_ap_header(int retval, struct adiv5_ap *ap,
        if (depth)
                snprintf(tabs, sizeof(tabs), "\t[L%02d] ", depth);
 
-       command_print(cmd, "%sAP # 0x%" PRIx64, tabs, ap->ap_num);
-
        command_print(cmd, "\t\tAP ID register 0x%8.8" PRIx32, apid);
        if (apid == 0) {
                command_print(cmd, "\t\tNo AP found at this AP#0x%" PRIx64, ap->ap_num);
@@ -1887,7 +1994,8 @@ static int dap_info_cs_component(int retval, struct cs_component_vals *v, int de
                return ERROR_FAIL;
        }
 
-       command_print(cmd, "\t\tComponent base address " TARGET_ADDR_FMT, v->component_base);
+       if (v->mode == CS_ACCESS_MEM_AP)
+               command_print(cmd, "\t\tComponent base address " TARGET_ADDR_FMT, v->component_base);
 
        if (retval != ERROR_OK) {
                command_print(cmd, "\t\tCan't read component, the corresponding core might be turned off");
@@ -1998,6 +2106,7 @@ static int dap_info_rom_table_entry(int retval, int depth,
 int dap_info_command(struct command_invocation *cmd, struct adiv5_ap *ap)
 {
        struct rtp_ops dap_info_ops = {
+               .ap_header       = dap_info_ap_header,
                .mem_ap_header   = dap_info_mem_ap_header,
                .cs_component    = dap_info_cs_component,
                .rom_table_entry = dap_info_rom_table_entry,
@@ -2054,6 +2163,7 @@ int dap_lookup_cs_component(struct adiv5_ap *ap, uint8_t type,
                .idx  = core_id,
        };
        struct rtp_ops dap_lookup_cs_component_ops = {
+               .ap_header       = NULL,
                .mem_ap_header   = NULL,
                .cs_component    = dap_lookup_cs_component_cs_component,
                .rom_table_entry = NULL,

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)