blob: 620b8a85403ba2475c9f565909314caa3abb24ca [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <lib/console.h>
#include <arch/arm64/mp.h>
#include <arch/arm64/periphmap.h>
#include <dev/coresight/rom_table.h>
#include <hwreg/mmio.h>
#include <vm/pmm.h>
#include <vm/vm_aspace.h>
namespace {
using coresight::ComponentIDRegister;
using coresight::DeviceAffinityRegister;
using coresight::DeviceArchRegister;
using coresight::DeviceTypeRegister;
// At the time of writing this, all observed ROM tables on the supported ARM
// boards fit within an 8MiB address range. Increase as needed.
constexpr uint32_t kViewSize = 0x80'0000;
// Prints information about a generic CoreSight component.
void DumpComponentInfo(uintptr_t component) {
hwreg::RegisterMmio mmio(reinterpret_cast<void*>(component));
paddr_t paddr = vaddr_to_paddr(reinterpret_cast<void*>(component));
printf("address: %#" PRIxPTR "\n", paddr);
const ComponentIDRegister::Class classid = ComponentIDRegister::Get().ReadFrom(&mmio).classid();
const uint16_t partid = coresight::GetPartID(mmio);
// Morally a CoreSight component, if not one technically, ARM puts them in ROM tables.
if (classid == ComponentIDRegister::Class::kNonStandard &&
partid == coresight::arm::partid::kTimestampGenerator) {
printf("type: N/A\n");
printf("affinity: cluster\n");
printf("architect: ARM\n");
printf("architecture: Timestamp Generator\n");
return;
} else if (classid != ComponentIDRegister::Class::kCoreSight) {
std::string_view classid_str = coresight::ToString(classid);
printf("unexpected component found; (class, part number) = (%#x (%.*s), %#x)\n",
static_cast<uint8_t>(classid), static_cast<int>(classid_str.size()), classid_str.data(),
partid);
return;
}
const DeviceTypeRegister::Type type = DeviceTypeRegister::Get().ReadFrom(&mmio).type();
std::string_view type_str = coresight::ToString(type);
printf("type: %.*s\n", static_cast<int>(type_str.size()), type_str.data());
const uint64_t affinity = DeviceAffinityRegister::Get().ReadFrom(&mmio).reg_value();
printf("affinity: ");
if (affinity == 0) {
printf("cluster\n");
} else if (cpu_num_t cpu_num = arm64_mpidr_to_cpu_num(affinity); cpu_num != INVALID_CPU) {
printf("CPU #%u (%#lx)\n", cpu_num, affinity);
} else {
printf("%#lx\n", affinity);
}
const DeviceArchRegister arch_reg = DeviceArchRegister::Get().ReadFrom(&mmio);
const auto archid = static_cast<uint16_t>(arch_reg.archid());
const auto revision = static_cast<uint16_t>(arch_reg.revision());
// The device architecture register might not be populated; in this case, we
// consult the designer designation.
const auto architect = arch_reg.architect() ? static_cast<uint16_t>(arch_reg.architect())
: coresight::GetDesigner(mmio);
if (architect == coresight::arm::kArchitect) {
printf("architect: ARM\n");
} else {
printf("architect: unknown (%#x)\n", architect);
printf("archid: %#x\n", archid);
printf("part number: %#x\n", partid);
return; // Not much more we can say.
}
printf("architecture: ");
switch (archid) {
case coresight::arm::archid::kCTI:
printf("Cross-Trigger Matrix (CTI)\n");
return;
case coresight::arm::archid::kETMv3:
printf("Embedded Trace Monitor (ETM) v3.%u\n", revision);
return;
case coresight::arm::archid::kETMv4:
printf("Embedded Trace Monitor (ETM) v4.%u\n", revision);
return;
case coresight::arm::archid::kPMUv2:
printf("Performance Monitor Unit (PMU) v2.%u\n", revision);
return;
case coresight::arm::archid::kPMUv3:
printf("Performance Monitor Unit (PMU) v3.%u\n", revision);
return;
case coresight::arm::archid::kROMTable:
printf("0x9 ROM Table\n");
return;
case coresight::arm::archid::kV8Dot0A:
printf("ARM v8.0-A Core Debug Interface\n");
return;
case coresight::arm::archid::kV8Dot1A:
printf("ARM v8.1-A Core Debug Interface\n");
return;
case coresight::arm::archid::kV8Dot2A:
printf("ARM v8.2-A Core Debug Interface\n");
return;
};
// Sometimes no architecture ID is populated; fall back to part ID.
switch (partid) {
case coresight::arm::partid::kETB:
printf("Embedded Trace Buffer (ETB)\n");
return;
case coresight::arm::partid::kCTI400:
printf("Cross-Trigger Matrix (CTI) (SoC400 generation)\n");
return;
case coresight::arm::partid::kCTI600:
printf("Cross-Trigger Matrix (CTI) (SoC600 generation)\n");
return;
case coresight::arm::partid::kTMC:
printf("Trace Memory Controller (TMC) (SoC400 generation)\n");
return;
case coresight::arm::partid::kTPIU:
printf("Trace Port Interface Unit (TPIU)\n");
return;
case coresight::arm::partid::kTraceFunnel:
printf("Trace Funnel (SoC400 generation)\n");
return;
case coresight::arm::partid::kTraceReplicator:
printf("Trace Replicator (SoC400 generation)\n");
return;
};
printf("unknown: (archid, part number) = (%#x, %#x)\n", archid, partid);
}
int WalkROMTable(uintptr_t addr, uint32_t view_size) {
hwreg::RegisterMmio mmio(reinterpret_cast<void*>(addr));
coresight::ROMTable table(addr, view_size);
auto result = table.Walk(mmio, [](uintptr_t component) {
printf("\n----------------------------------------\n");
DumpComponentInfo(component);
});
if (result.is_error()) {
printf("error: %s\n", result.error_value().data());
}
return 0;
}
int cmd_coresight(int argc, const cmd_args* argv, uint32_t flags) {
auto usage = [&argv]() {
printf("usage:\n");
printf("k %s help\n", argv[0].str);
printf("k %s walk <ROM table physical address>\n", argv[0].str);
};
if (argc < 2) {
usage();
return 1;
} else if (!strcmp(argv[1].str, "help")) {
usage();
} else if (!strcmp(argv[1].str, "walk")) {
if (argc < 3) {
printf("too few arguments\n");
usage();
return 1;
}
paddr_t paddr = argv[2].u;
printf("attempting to walk a ROM table at %#" PRIxPTR "...\n", paddr);
void* virt = nullptr;
zx_status_t status = VmAspace::kernel_aspace()->AllocPhysical(
"k coresight walk",
kViewSize, // Range size
&virt, // Requested virtual address
PAGE_SIZE_SHIFT, // Alignment log2
paddr, // Physical address
0, // VMM flags
ARCH_MMU_FLAG_PERM_READ | ARCH_MMU_FLAG_UNCACHED_DEVICE); // MMU flags
if (status != ZX_OK || !virt) {
printf("failed to map address range starting at %#" PRIxPTR ": %d\n", paddr, status);
return 1;
}
printf("virtual address: %p\n", virt);
return WalkROMTable(reinterpret_cast<uintptr_t>(virt), kViewSize);
} else {
printf("unrecognized command: %s\n", argv[1].str);
usage();
return 1;
}
return 0;
}
STATIC_COMMAND_START
STATIC_COMMAND("coresight", "access information within a CoreSight system", &cmd_coresight)
STATIC_COMMAND_END(coresight)
} // namespace