nixos-riscv/tools/plictool.c

132 lines
2.7 KiB
C

/* Copyright (c) 2024 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: MIT
* Author: Rodrigo Arias Mallo <rodrigo.arias@bsc.es> */
/* Small utility to dump the state of the PLIC. */
/* Changelog:
* v0.0.1 (2024-09-03): Initial version.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
const char *plic_address_str = "0x40800000";
long ncontexts = 15872L;
long maxsources = 1024L;
long nsources = 1024L;
static void
usage(void)
{
printf("plictool v0.0.1 - Rodrigo Arias Mallo <rodrigo.arias@bsc.es>\n");
printf(
"Usage: plictool [-a addr] [-s nsources] [-c ncontexts]\n");
exit(1);
}
void dump_sources(void *base)
{
for (long s = 0; s < nsources; s++) {
int printed_source = 0;
uint32_t *pending_reg = base + 0x1000L + (s / 32L) * 4L;
long shift = s % 32L;
uint32_t pending = ((*pending_reg) >> shift) & 1;
uint32_t *priority_reg = base + 0x0000L + (s * 4L);
uint32_t priority = *priority_reg;
const char *fmt =
"src=%ld pend=%u prio=%u";
if (pending || priority) {
printf(fmt, s, pending, priority);
printed_source = 1;
}
int first_context = 1;
for (long c = 0; c < ncontexts; c++) {
uint32_t *enable_reg = base + 0x2000L + 0x80L * c + (s / 32L) * 4L;
uint32_t enabled = ((*enable_reg) >> shift) & 1;
uint32_t *threshold_reg = base + 0x200000L + (c * 0x1000L);
uint32_t threshold = *threshold_reg;
if (!enabled)
continue;
if (!printed_source) {
printf(fmt, s, pending, priority);
printed_source = 1;
}
printf(" ctx=%ld thre=%u", c, threshold);
}
if (printed_source)
printf("\n");
}
}
int main(int argc, char *argv[])
{
int opt;
while ((opt = getopt(argc, argv, "a:hs:c:")) != -1) {
switch (opt) {
case 'a':
plic_address_str = optarg;
break;
case 's':
nsources = atol(optarg);
break;
case 'c':
ncontexts = atol(optarg);
break;
case 'h':
default: /* '?' */
usage();
}
}
off_t plic_address = (off_t) strtoll(plic_address_str, NULL, 16);
printf("plic=0x%08x nsources=%ld ncontexts=%ld\n",
plic_address, nsources, ncontexts);
int fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd == -1) {
perror("cannot open /dev/mem");
exit(1);
}
size_t map_size = 0x4000000UL;
void *map_base = mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, plic_address);
if (map_base == MAP_FAILED) {
perror("mmap failed");
if (errno == EPERM) {
fprintf(stderr, "Have you disabled 'CONFIG_STRICT_DEVMEM' and "
"'CONFIG_IO_STRICT_DEVMEM' in the kernel config?\n"
"Hint: zgrep STRICT_DEVMEM /proc/config.gz\n");
}
exit(1);
}
dump_sources(map_base);
munmap(map_base, map_size);
close(fd);
return 0;
}