arm_adi_v5: check for calloc() return value
[fw/openocd] / src / target / arm_adi_v5.c
index 4d24e8f2fc5ca7f8caebd43383ad618d06732754..4d5f02b328a875a03d710c2450e101d734b3158a 100644 (file)
@@ -1002,7 +1002,7 @@ int dap_find_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_a
        return ERROR_FAIL;
 }
 
-int dap_get_debugbase(struct adiv5_ap *ap,
+static int dap_get_debugbase(struct adiv5_ap *ap,
                        target_addr_t *dbgbase, uint32_t *apid)
 {
        struct adiv5_dap *dap = ap->dap;
@@ -1038,64 +1038,10 @@ int dap_get_debugbase(struct adiv5_ap *ap,
        return ERROR_OK;
 }
 
-int dap_lookup_cs_component(struct adiv5_ap *ap,
-                       target_addr_t dbgbase, uint8_t type, target_addr_t *addr, int32_t *idx)
-{
-       uint32_t romentry, entry_offset = 0, devtype;
-       target_addr_t component_base;
-       int retval;
-
-       dbgbase &= 0xFFFFFFFFFFFFF000ull;
-       *addr = 0;
-
-       do {
-               retval = mem_ap_read_atomic_u32(ap, dbgbase |
-                                               entry_offset, &romentry);
-               if (retval != ERROR_OK)
-                       return retval;
-
-               component_base = dbgbase + (target_addr_t)(romentry & ARM_CS_ROMENTRY_OFFSET_MASK);
-
-               if (romentry & ARM_CS_ROMENTRY_PRESENT) {
-                       uint32_t c_cid1;
-                       retval = mem_ap_read_atomic_u32(ap, component_base + ARM_CS_CIDR1, &c_cid1);
-                       if (retval != ERROR_OK) {
-                               LOG_ERROR("Can't read component with base address " TARGET_ADDR_FMT
-                                         ", the corresponding core might be turned off", component_base);
-                               return retval;
-                       }
-                       unsigned int class = (c_cid1 & ARM_CS_CIDR1_CLASS_MASK) >> ARM_CS_CIDR1_CLASS_SHIFT;
-                       if (class == ARM_CS_CLASS_0X1_ROM_TABLE) {
-                               retval = dap_lookup_cs_component(ap, component_base,
-                                                       type, addr, idx);
-                               if (retval == ERROR_OK)
-                                       break;
-                               if (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
-                                       return retval;
-                       }
-
-                       retval = mem_ap_read_atomic_u32(ap, component_base + ARM_CS_C9_DEVTYPE, &devtype);
-                       if (retval != ERROR_OK)
-                               return retval;
-                       if ((devtype & ARM_CS_C9_DEVTYPE_MASK) == type) {
-                               if (!*idx) {
-                                       *addr = component_base;
-                                       break;
-                               } else
-                                       (*idx)--;
-                       }
-               }
-               entry_offset += 4;
-       } while ((romentry > 0) && (entry_offset < 0xf00));
-
-       if (!*addr)
-               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-
-       return ERROR_OK;
-}
-
-/** Holds registers of a CoreSight component */
+/** Holds registers and coordinates of a CoreSight component */
 struct cs_component_vals {
+       struct adiv5_ap *ap;
+       target_addr_t component_base;
        uint64_t pid;
        uint32_t cid;
        uint32_t devarch;
@@ -1122,6 +1068,9 @@ static int rtp_read_cs_regs(struct adiv5_ap *ap, target_addr_t component_base,
        uint32_t pid0, pid1, pid2, pid3, pid4;
        int retval = ERROR_OK;
 
+       v->ap = ap;
+       v->component_base = component_base;
+
        /* sort by offset to gain speed */
 
        /*
@@ -1477,51 +1426,164 @@ static int dap_devtype_display(struct command_invocation *cmd, uint32_t devtype)
        return ERROR_OK;
 }
 
-static int rtp_cs_component(struct command_invocation *cmd,
+/**
+ * Actions/operations to be executed while parsing ROM tables.
+ */
+struct rtp_ops {
+       /**
+        * Executed at the start of a new MEM-AP, typically to print the MEM-AP header.
+        * @param retval    Error encountered while reading AP.
+        * @param ap        Pointer to AP.
+        * @param dbgbase   Value of MEM-AP Debug Base Address register.
+        * @param apid      Value of MEM-AP IDR Identification Register.
+        * @param priv      Pointer to private data.
+        * @return          ERROR_OK on success, else a fault code.
+        */
+       int (*mem_ap_header)(int retval, struct adiv5_ap *ap, uint64_t dbgbase,
+                       uint32_t apid, void *priv);
+       /**
+        * Executed when a CoreSight component is parsed, typically to print
+        * information on the component.
+        * @param retval    Error encountered while reading component's registers.
+        * @param v         Pointer to a container of the component's registers.
+        * @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 (*cs_component)(int retval, struct cs_component_vals *v, int depth, void *priv);
+       /**
+        * Executed for each entry of a ROM table, typically to print the entry
+        * and information about validity or end-of-table mark.
+        * @param retval    Error encountered while reading the ROM table entry.
+        * @param depth     The current depth level of ROM table.
+        * @param offset    The offset of the entry in the ROM table.
+        * @param romentry  The value of the ROM table entry.
+        * @param priv      Pointer to private data.
+        * @return          ERROR_OK on success, else a fault code.
+        */
+       int (*rom_table_entry)(int retval, int depth, unsigned int offset, uint64_t romentry,
+                       void *priv);
+       /**
+        * Private data
+        */
+       void *priv;
+};
+
+/**
+ * Wrapper around struct rtp_ops::mem_ap_header.
+ * Input parameter @a retval is propagated.
+ */
+static int rtp_ops_mem_ap_header(const struct rtp_ops *ops,
+               int retval, struct adiv5_ap *ap, uint64_t dbgbase, uint32_t apid)
+{
+       if (!ops->mem_ap_header)
+               return retval;
+
+       int retval1 = ops->mem_ap_header(retval, ap, dbgbase, apid, ops->priv);
+       if (retval != ERROR_OK)
+               return retval;
+       return retval1;
+}
+
+/**
+ * Wrapper around struct rtp_ops::cs_component.
+ * Input parameter @a retval is propagated.
+ */
+static int rtp_ops_cs_component(const struct rtp_ops *ops,
+               int retval, struct cs_component_vals *v, int depth)
+{
+       if (!ops->cs_component)
+               return retval;
+
+       int retval1 = ops->cs_component(retval, v, depth, ops->priv);
+       if (retval != ERROR_OK)
+               return retval;
+       return retval1;
+}
+
+/**
+ * Wrapper around struct rtp_ops::rom_table_entry.
+ * Input parameter @a retval is propagated.
+ */
+static int rtp_ops_rom_table_entry(const struct rtp_ops *ops,
+               int retval, int depth, unsigned int offset, uint64_t romentry)
+{
+       if (!ops->rom_table_entry)
+               return retval;
+
+       int retval1 = ops->rom_table_entry(retval, depth, offset, romentry, ops->priv);
+       if (retval != ERROR_OK)
+               return retval;
+       return retval1;
+}
+
+/* Broken ROM tables can have circular references. Stop after a while */
+#define ROM_TABLE_MAX_DEPTH (16)
+
+/**
+ * Value used only during lookup of a CoreSight component in ROM table.
+ * Return CORESIGHT_COMPONENT_FOUND when component is found.
+ * Return ERROR_OK when component is not found yet.
+ * Return any other ERROR_* in case of error.
+ */
+#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_rom_loop(struct command_invocation *cmd,
+static int rtp_rom_loop(const struct rtp_ops *ops,
                struct adiv5_ap *ap, target_addr_t base_address, int depth,
-               unsigned int max_entries)
+               unsigned int width, unsigned int max_entries)
 {
        assert(IS_ALIGNED(base_address, ARM_CS_ALIGN));
 
-       char tabs[16] = "";
-
-       if (depth)
-               snprintf(tabs, sizeof(tabs), "[L%02d] ", depth);
-
        unsigned int offset = 0;
        while (max_entries--) {
-               uint32_t romentry;
+               uint64_t romentry;
+               uint32_t romentry_low, romentry_high;
+               target_addr_t component_base;
                unsigned int saved_offset = offset;
 
-               int retval = mem_ap_read_atomic_u32(ap, base_address + offset, &romentry);
+               int retval = mem_ap_read_u32(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);
+                       offset += 4;
+               }
+               if (retval == ERROR_OK)
+                       retval = dap_run(ap->dap);
                if (retval != ERROR_OK) {
                        LOG_DEBUG("Failed read ROM table entry");
-                       command_print(cmd, "\t%sROMTABLE[0x%x] Read error", tabs, saved_offset);
-                       command_print(cmd, "\t\tUnable to continue");
-                       command_print(cmd, "\t%s\tStop parsing of ROM table", tabs);
                        return retval;
                }
 
-               command_print(cmd, "\t%sROMTABLE[0x%x] = 0x%08" PRIx32,
-                               tabs, saved_offset, romentry);
+               if (width == 64) {
+                       romentry = (((uint64_t)romentry_high) << 32) | romentry_low;
+                       component_base = base_address +
+                               ((((uint64_t)romentry_high) << 32) | (romentry_low & ARM_CS_ROMENTRY_OFFSET_MASK));
+               } else {
+                       romentry = romentry_low;
+                       /* "romentry" is signed */
+                       component_base = base_address + (int32_t)(romentry_low & ARM_CS_ROMENTRY_OFFSET_MASK);
+                       if (!is_64bit_ap(ap))
+                               component_base = (uint32_t)component_base;
+               }
+               retval = rtp_ops_rom_table_entry(ops, retval, depth, saved_offset, romentry);
+               if (retval != ERROR_OK)
+                       return retval;
 
                if (romentry == 0) {
-                       command_print(cmd, "\t%s\tEnd of ROM table", tabs);
+                       /* End of ROM table */
                        break;
                }
 
-               if (!(romentry & ARM_CS_ROMENTRY_PRESENT)) {
-                       command_print(cmd, "\t\tComponent not present");
+               if (!(romentry & ARM_CS_ROMENTRY_PRESENT))
                        continue;
-               }
 
-               /* Recurse. "romentry" is signed */
-               target_addr_t component_base = base_address + (int32_t)(romentry & ARM_CS_ROMENTRY_OFFSET_MASK);
-               retval = rtp_cs_component(cmd, ap, component_base, depth + 1);
+               /* Recurse */
+               retval = rtp_cs_component(ops, ap, component_base, depth + 1);
+               if (retval == CORESIGHT_COMPONENT_FOUND)
+                       return CORESIGHT_COMPONENT_FOUND;
                if (retval != ERROR_OK) {
                        /* TODO: do we need to send an ABORT before continuing? */
                        LOG_DEBUG("Ignore error parsing CoreSight component");
@@ -1532,48 +1594,168 @@ static int rtp_rom_loop(struct command_invocation *cmd,
        return ERROR_OK;
 }
 
-static int rtp_cs_component(struct command_invocation *cmd,
+static int rtp_cs_component(const struct rtp_ops *ops,
                struct adiv5_ap *ap, target_addr_t base_address, int depth)
 {
        struct cs_component_vals v;
        int retval;
-       char tabs[16] = "";
 
        assert(IS_ALIGNED(base_address, ARM_CS_ALIGN));
 
-       if (depth > 16) {
-               command_print(cmd, "\tTables too deep");
+       if (depth > ROM_TABLE_MAX_DEPTH)
+               retval = ERROR_FAIL;
+       else
+               retval = rtp_read_cs_regs(ap, base_address, &v);
+
+       retval = rtp_ops_cs_component(ops, retval, &v, depth);
+       if (retval == CORESIGHT_COMPONENT_FOUND)
+               return CORESIGHT_COMPONENT_FOUND;
+       if (retval != ERROR_OK)
+               return ERROR_OK; /* Don't abort recursion */
+
+       if (!is_valid_arm_cs_cidr(v.cid))
+               return ERROR_OK; /* Don't abort recursion */
+
+       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);
+
+       if (class == ARM_CS_CLASS_0X9_CS_COMPONENT) {
+               if ((v.devarch & ARM_CS_C9_DEVARCH_PRESENT) == 0)
+                       return ERROR_OK;
+
+               /* 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);
+               else
+                       return rtp_rom_loop(ops, ap, base_address, depth, 32, 512);
+       }
+
+       /* Class other than 0x1 and 0x9 */
+       return ERROR_OK;
+}
+
+static int rtp_ap(const struct rtp_ops *ops, struct adiv5_ap *ap)
+{
+       int retval;
+       uint32_t apid;
+       target_addr_t dbgbase, invalid_entry;
+
+       /* Now we read ROM table ID registers, ref. ARM IHI 0029B sec  */
+       retval = dap_get_debugbase(ap, &dbgbase, &apid);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = rtp_ops_mem_ap_header(ops, retval, ap, dbgbase, apid);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (apid == 0)
                return ERROR_FAIL;
+
+       /* NOTE: a MEM-AP may have a single CoreSight component that's
+        * not a ROM table ... or have no such components at all.
+        */
+       const unsigned int class = (apid & AP_REG_IDR_CLASS_MASK) >> AP_REG_IDR_CLASS_SHIFT;
+
+       if (class == AP_REG_IDR_CLASS_MEM_AP) {
+               if (is_64bit_ap(ap))
+                       invalid_entry = 0xFFFFFFFFFFFFFFFFull;
+               else
+                       invalid_entry = 0xFFFFFFFFul;
+
+               if (dbgbase != invalid_entry && (dbgbase & 0x3) != 0x2) {
+                       retval = rtp_cs_component(ops, ap, dbgbase & 0xFFFFFFFFFFFFF000ull, 0);
+                       if (retval == CORESIGHT_COMPONENT_FOUND)
+                               return CORESIGHT_COMPONENT_FOUND;
+               }
        }
 
-       if (depth)
-               snprintf(tabs, sizeof(tabs), "[L%02d] ", depth);
+       return ERROR_OK;
+}
+
+/* Actions for command "dap info" */
+
+static int dap_info_mem_ap_header(int retval, struct adiv5_ap *ap,
+               target_addr_t dbgbase, uint32_t apid, void *priv)
+{
+       struct command_invocation *cmd = priv;
+       target_addr_t invalid_entry;
 
-       command_print(cmd, "\t\tComponent base address " TARGET_ADDR_FMT, base_address);
+       if (retval != ERROR_OK) {
+               command_print(cmd, "\t\tCan't read MEM-AP, the corresponding core might be turned off");
+               return retval;
+       }
+
+       command_print(cmd, "AP ID register 0x%8.8" PRIx32, apid);
+       if (apid == 0) {
+               command_print(cmd, "No AP found at this ap 0x%x", ap->ap_num);
+               return ERROR_FAIL;
+       }
+
+       command_print(cmd, "\tType is %s", ap_type_to_description(apid & AP_TYPE_MASK));
+
+       /* NOTE: a MEM-AP may have a single CoreSight component that's
+        * not a ROM table ... or have no such components at all.
+        */
+       const unsigned int class = (apid & AP_REG_IDR_CLASS_MASK) >> AP_REG_IDR_CLASS_SHIFT;
+
+       if (class == AP_REG_IDR_CLASS_MEM_AP) {
+               if (is_64bit_ap(ap))
+                       invalid_entry = 0xFFFFFFFFFFFFFFFFull;
+               else
+                       invalid_entry = 0xFFFFFFFFul;
+
+               command_print(cmd, "MEM-AP BASE " TARGET_ADDR_FMT, dbgbase);
+
+               if (dbgbase == invalid_entry || (dbgbase & 0x3) == 0x2) {
+                       command_print(cmd, "\tNo ROM table present");
+               } else {
+                       if (dbgbase & 0x01)
+                               command_print(cmd, "\tValid ROM table present");
+                       else
+                               command_print(cmd, "\tROM table in legacy format");
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int dap_info_cs_component(int retval, struct cs_component_vals *v, 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, "\t\tComponent base address " TARGET_ADDR_FMT, v->component_base);
 
-       retval = rtp_read_cs_regs(ap, base_address, &v);
        if (retval != ERROR_OK) {
                command_print(cmd, "\t\tCan't read component, the corresponding core might be turned off");
-               return ERROR_OK; /* Don't abort recursion */
+               return retval;
        }
 
-       if (!is_valid_arm_cs_cidr(v.cid)) {
-               command_print(cmd, "\t\tInvalid CID 0x%08" PRIx32, v.cid);
+       if (!is_valid_arm_cs_cidr(v->cid)) {
+               command_print(cmd, "\t\tInvalid CID 0x%08" PRIx32, v->cid);
                return ERROR_OK; /* Don't abort recursion */
        }
 
        /* component may take multiple 4K pages */
-       uint32_t size = ARM_CS_PIDR_SIZE(v.pid);
+       uint32_t size = ARM_CS_PIDR_SIZE(v->pid);
        if (size > 0)
-               command_print(cmd, "\t\tStart address " TARGET_ADDR_FMT, base_address - 0x1000 * size);
+               command_print(cmd, "\t\tStart address " TARGET_ADDR_FMT, v->component_base - 0x1000 * size);
 
-       command_print(cmd, "\t\tPeripheral ID 0x%010" PRIx64, v.pid);
+       command_print(cmd, "\t\tPeripheral ID 0x%010" PRIx64, v->pid);
 
-       const unsigned int class = ARM_CS_CIDR_CLASS(v.cid);
-       const unsigned int part_num = ARM_CS_PIDR_PART(v.pid);
-       unsigned int designer_id = ARM_CS_PIDR_DESIGNER(v.pid);
+       const unsigned int part_num = ARM_CS_PIDR_PART(v->pid);
+       unsigned int designer_id = ARM_CS_PIDR_DESIGNER(v->pid);
 
-       if (v.pid & ARM_CS_PIDR_JEDEC) {
+       if (v->pid & ARM_CS_PIDR_JEDEC) {
                /* JEP106 code */
                command_print(cmd, "\t\tDesigner is 0x%03x, %s",
                                designer_id, jep106_manufacturer(designer_id));
@@ -1586,95 +1768,156 @@ static int rtp_cs_component(struct command_invocation *cmd,
 
        const struct dap_part_nums *partnum = pidr_to_part_num(designer_id, part_num);
        command_print(cmd, "\t\tPart is 0x%03x, %s %s", part_num, partnum->type, partnum->full);
+
+       const unsigned int class = ARM_CS_CIDR_CLASS(v->cid);
        command_print(cmd, "\t\tComponent class is 0x%x, %s", class, class_description[class]);
 
        if (class == ARM_CS_CLASS_0X1_ROM_TABLE) {
-               if (v.devtype_memtype & ARM_CS_C1_MEMTYPE_SYSMEM_MASK)
+               if (v->devtype_memtype & ARM_CS_C1_MEMTYPE_SYSMEM_MASK)
                        command_print(cmd, "\t\tMEMTYPE system memory present on bus");
                else
                        command_print(cmd, "\t\tMEMTYPE system memory not present: dedicated debug bus");
-
-               return rtp_rom_loop(cmd, ap, base_address, depth, 960);
+               return ERROR_OK;
        }
 
        if (class == ARM_CS_CLASS_0X9_CS_COMPONENT) {
-               retval = dap_devtype_display(cmd, v.devtype_memtype);
-               if (retval != ERROR_OK)
-                       return retval;
+               dap_devtype_display(cmd, v->devtype_memtype);
 
                /* REVISIT also show ARM_CS_C9_DEVID */
 
-               if ((v.devarch & ARM_CS_C9_DEVARCH_PRESENT) == 0)
+               if ((v->devarch & ARM_CS_C9_DEVARCH_PRESENT) == 0)
                        return ERROR_OK;
 
-               unsigned int architect_id = (v.devarch & ARM_CS_C9_DEVARCH_ARCHITECT_MASK) >> ARM_CS_C9_DEVARCH_ARCHITECT_SHIFT;
-               unsigned int revision = (v.devarch & ARM_CS_C9_DEVARCH_REVISION_MASK) >> ARM_CS_C9_DEVARCH_REVISION_SHIFT;
-               command_print(cmd, "\t\tDev Arch is 0x%08" PRIx32 ", %s \"%s\" rev.%u", v.devarch,
-                               jep106_manufacturer(architect_id), class0x9_devarch_description(v.devarch),
+               unsigned int architect_id = ARM_CS_C9_DEVARCH_ARCHITECT(v->devarch);
+               unsigned int revision = ARM_CS_C9_DEVARCH_REVISION(v->devarch);
+               command_print(cmd, "\t\tDev Arch is 0x%08" PRIx32 ", %s \"%s\" rev.%u", v->devarch,
+                               jep106_manufacturer(architect_id), class0x9_devarch_description(v->devarch),
                                revision);
-               /* 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_SYSMEM_MASK)
-                       command_print(cmd, "\t\tMEMTYPE system memory present on bus");
-               else
-                       command_print(cmd, "\t\tMEMTYPE system memory not present: dedicated debug bus");
+               if ((v->devarch & DEVARCH_ID_MASK) == DEVARCH_ROM_C_0X9) {
+                       command_print(cmd, "\t\tType is ROM table");
 
-               return rtp_rom_loop(cmd, ap, base_address, depth, 512);
+                       if (v->devid & ARM_CS_C9_DEVID_SYSMEM_MASK)
+                               command_print(cmd, "\t\tMEMTYPE system memory present on bus");
+                       else
+                               command_print(cmd, "\t\tMEMTYPE system memory not present: dedicated debug bus");
+               }
+               return ERROR_OK;
        }
 
        /* Class other than 0x1 and 0x9 */
        return ERROR_OK;
 }
 
-int dap_info_command(struct command_invocation *cmd,
-               struct adiv5_ap *ap)
+static int dap_info_rom_table_entry(int retval, int depth,
+               unsigned int offset, uint64_t romentry, void *priv)
 {
-       int retval;
-       uint32_t apid;
-       target_addr_t dbgbase;
-       target_addr_t dbgaddr;
+       struct command_invocation *cmd = priv;
+       char tabs[16] = "";
 
-       /* Now we read ROM table ID registers, ref. ARM IHI 0029B sec  */
-       retval = dap_get_debugbase(ap, &dbgbase, &apid);
-       if (retval != ERROR_OK)
+       if (depth)
+               snprintf(tabs, sizeof(tabs), "[L%02d] ", depth);
+
+       if (retval != ERROR_OK) {
+               command_print(cmd, "\t%sROMTABLE[0x%x] Read error", tabs, offset);
+               command_print(cmd, "\t\tUnable to continue");
+               command_print(cmd, "\t%s\tStop parsing of ROM table", tabs);
                return retval;
+       }
 
-       command_print(cmd, "AP ID register 0x%8.8" PRIx32, apid);
-       if (apid == 0) {
-               command_print(cmd, "No AP found at this ap 0x%x", ap->ap_num);
-               return ERROR_FAIL;
+       command_print(cmd, "\t%sROMTABLE[0x%x] = 0x%08" PRIx64,
+                       tabs, offset, romentry);
+
+       if (romentry == 0) {
+               command_print(cmd, "\t%s\tEnd of ROM table", tabs);
+               return ERROR_OK;
        }
 
-       command_print(cmd, "\tType is %s", ap_type_to_description(apid & AP_TYPE_MASK));
+       if (!(romentry & ARM_CS_ROMENTRY_PRESENT)) {
+               command_print(cmd, "\t\tComponent not present");
+               return ERROR_OK;
+       }
 
-       /* NOTE: a MEM-AP may have a single CoreSight component that's
-        * not a ROM table ... or have no such components at all.
-        */
-       const unsigned int class = (apid & AP_REG_IDR_CLASS_MASK) >> AP_REG_IDR_CLASS_SHIFT;
+       return ERROR_OK;
+}
 
-       if (class == AP_REG_IDR_CLASS_MEM_AP) {
-               if (is_64bit_ap(ap))
-                       dbgaddr = 0xFFFFFFFFFFFFFFFFull;
-               else
-                       dbgaddr = 0xFFFFFFFFul;
+int dap_info_command(struct command_invocation *cmd, struct adiv5_ap *ap)
+{
+       struct rtp_ops dap_info_ops = {
+               .mem_ap_header   = dap_info_mem_ap_header,
+               .cs_component    = dap_info_cs_component,
+               .rom_table_entry = dap_info_rom_table_entry,
+               .priv            = cmd,
+       };
 
-               command_print(cmd, "MEM-AP BASE " TARGET_ADDR_FMT, dbgbase);
+       return rtp_ap(&dap_info_ops, ap);
+}
 
-               if (dbgbase == dbgaddr || (dbgbase & 0x3) == 0x2) {
-                       command_print(cmd, "\tNo ROM table present");
-               } else {
-                       if (dbgbase & 0x01)
-                               command_print(cmd, "\tValid ROM table present");
-                       else
-                               command_print(cmd, "\tROM table in legacy format");
+/* Actions for dap_lookup_cs_component() */
 
-                       rtp_cs_component(cmd, ap, dbgbase & 0xFFFFFFFFFFFFF000ull, 0);
-               }
+struct dap_lookup_data {
+       /* input */
+       unsigned int idx;
+       unsigned int type;
+       /* output */
+       uint64_t component_base;
+};
+
+static int dap_lookup_cs_component_cs_component(int retval,
+               struct cs_component_vals *v, int depth, void *priv)
+{
+       struct dap_lookup_data *lookup = priv;
+
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (!is_valid_arm_cs_cidr(v->cid))
+               return ERROR_OK;
+
+       const unsigned int class = ARM_CS_CIDR_CLASS(v->cid);
+       if (class != ARM_CS_CLASS_0X9_CS_COMPONENT)
+               return ERROR_OK;
+
+       if ((v->devtype_memtype & ARM_CS_C9_DEVTYPE_MASK) != lookup->type)
+               return ERROR_OK;
+
+       if (lookup->idx) {
+               /* search for next one */
+               --lookup->idx;
+               return ERROR_OK;
        }
 
-       return ERROR_OK;
+       /* Found! */
+       lookup->component_base = v->component_base;
+       return CORESIGHT_COMPONENT_FOUND;
+}
+
+int dap_lookup_cs_component(struct adiv5_ap *ap, uint8_t type,
+               target_addr_t *addr, int32_t core_id)
+{
+       struct dap_lookup_data lookup = {
+               .type = type,
+               .idx  = core_id,
+       };
+       struct rtp_ops dap_lookup_cs_component_ops = {
+               .mem_ap_header   = NULL,
+               .cs_component    = dap_lookup_cs_component_cs_component,
+               .rom_table_entry = NULL,
+               .priv            = &lookup,
+       };
+
+       int retval = rtp_ap(&dap_lookup_cs_component_ops, ap);
+       if (retval == CORESIGHT_COMPONENT_FOUND) {
+               LOG_DEBUG("CS lookup found at 0x%" PRIx64, lookup.component_base);
+               *addr = lookup.component_base;
+               return ERROR_OK;
+       }
+       if (retval != ERROR_OK) {
+               LOG_DEBUG("CS lookup error %d", retval);
+               return retval;
+       }
+       LOG_DEBUG("CS lookup not found");
+       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
 }
 
 enum adiv5_cfg_param {
@@ -1695,6 +1938,8 @@ static const struct jim_nvp nvp_config_opts[] = {
 static int adiv5_jim_spot_configure(struct jim_getopt_info *goi,
                struct adiv5_dap **dap_p, int *ap_num_p, uint32_t *base_p)
 {
+       assert(dap_p && ap_num_p);
+
        if (!goi->argc)
                return JIM_OK;
 
@@ -1799,6 +2044,10 @@ int adiv5_jim_configure(struct target *target, struct jim_getopt_info *goi)
        pc = (struct adiv5_private_config *)target->private_config;
        if (!pc) {
                pc = calloc(1, sizeof(struct adiv5_private_config));
+               if (!pc) {
+                       LOG_ERROR("Out of memory");
+                       return JIM_ERR;
+               }
                pc->ap_num = DP_APSEL_INVALID;
                target->private_config = pc;
        }