summaryrefslogtreecommitdiffstats
path: root/tools/rmtool/src/mem.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/rmtool/src/mem.c')
-rw-r--r--tools/rmtool/src/mem.c146
1 files changed, 146 insertions, 0 deletions
diff --git a/tools/rmtool/src/mem.c b/tools/rmtool/src/mem.c
new file mode 100644
index 0000000..a85bd70
--- /dev/null
+++ b/tools/rmtool/src/mem.c
@@ -0,0 +1,146 @@
+/* mem.c - rmtool mem stats: read-only FB/heap/BAR1 information.
+ *
+ * Allocation, mapping, pinning and arbitrary-handle inspection are
+ * deliberately not implemented: they are write operations against the live
+ * driver and are out of scope for this read-only oracle.
+ */
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rmtool.h"
+
+static const NvU32 fb_indices[] = {
+ NV2080_CTRL_FB_INFO_INDEX_TOTAL_RAM_SIZE,
+ NV2080_CTRL_FB_INFO_INDEX_USABLE_RAM_SIZE,
+ NV2080_CTRL_FB_INFO_INDEX_HEAP_SIZE,
+ NV2080_CTRL_FB_INFO_INDEX_HEAP_FREE,
+ NV2080_CTRL_FB_INFO_INDEX_LARGEST_FREE_REGION_SIZE_KB,
+ NV2080_CTRL_FB_INFO_INDEX_BAR1_SIZE,
+ NV2080_CTRL_FB_INFO_INDEX_BAR1_AVAIL_SIZE,
+};
+
+static const char *fb_names[] = {
+ "vram_total_kib",
+ "vram_usable_kib",
+ "heap_size_kib",
+ "heap_free_kib",
+ "largest_free_region_kib",
+ "bar1_size_kib",
+ "bar1_avail_kib",
+};
+
+#define FB_N (sizeof(fb_indices) / sizeof(fb_indices[0]))
+
+static void usage(void)
+{
+ printf("usage: rmtool mem stats [-d N|BDF] [--format=...]\n"
+ " rmtool mem info -h HANDLE (not implemented: write "
+ "path)\n"
+ "rmtool is read-only; alloc/map/unmap/pin are refused.\n");
+}
+
+static int mem_stats(struct rm_ctx *ctx)
+{
+ NvU32 values[FB_N];
+ struct rm_kv kv[FB_N + 4];
+ char v[FB_N + 4][128];
+ NvU32 status;
+ int rc, n = 0;
+ unsigned int i;
+
+ rc = rm_ctx_open(ctx);
+ if (rc != 0) {
+ fprintf(stderr, "rmtool: cannot open RM client: rc=%d\n", rc);
+ return 2;
+ }
+ memset(values, 0, sizeof(values));
+ status = rm_query_fb(ctx, fb_indices, values, FB_N);
+ if (status != 0) {
+ fprintf(stderr, "rmtool: FB_GET_INFO_V2: %s\n",
+ rm_status_str(status));
+ return 2;
+ }
+ for (i = 0; i < FB_N; i++) {
+ char human[32];
+
+ rm_human_kib(values[i], human, sizeof(human));
+ snprintf(v[n], sizeof(v[n]), "%u (%s)", values[i], human);
+ kv[n].key = fb_names[i];
+ kv[n].value = v[n];
+ n++;
+ }
+ if (values[2] >= values[3]) {
+ unsigned int used = values[2] - values[3];
+ char human[32];
+
+ rm_human_kib(used, human, sizeof(human));
+ snprintf(v[n], sizeof(v[n]), "%u (%s)", used, human);
+ kv[n].key = "heap_used_kib (derived)";
+ kv[n].value = v[n];
+ n++;
+ }
+ rm_print_kv("VRAM / heap (FB_GET_INFO_V2, KiB units)", kv, n,
+ ctx->format);
+ return 0;
+}
+
+static int parse_common(int argc, char **argv, struct rm_ctx *ctx)
+{
+ static const struct option long_opts[] = {
+ { "device-spec", required_argument, NULL, 'd' },
+ { "format", required_argument, NULL, 'f' },
+ { "device", required_argument, NULL, 1000 },
+ { "help", no_argument, NULL, 'h' },
+ { NULL, 0, NULL, 0 },
+ };
+ int opt;
+
+ optind = 1;
+ opterr = 0;
+ while ((opt = getopt_long(argc, argv, "d:f:h", long_opts, NULL)) != -1) {
+ int rc;
+
+ if (opt == 'h')
+ return 1;
+ rc = rm_apply_common_opt(ctx, opt, optarg);
+ if (rc < 0)
+ return -1;
+ }
+ return 0;
+}
+
+int cmd_mem(int argc, char **argv, struct rm_ctx *ctx)
+{
+ int rc;
+
+ if (argc < 2) {
+ usage();
+ return 2;
+ }
+ if (strcmp(argv[1], "stats") == 0) {
+ rc = parse_common(argc - 1, argv + 1, ctx);
+ if (rc < 0)
+ return 2;
+ if (rc == 1) {
+ usage();
+ return 0;
+ }
+ return mem_stats(ctx);
+ }
+ if (strcmp(argv[1], "alloc") == 0 ||
+ strcmp(argv[1], "map") == 0 ||
+ strcmp(argv[1], "unmap") == 0 ||
+ strcmp(argv[1], "pin") == 0 ||
+ strcmp(argv[1], "info") == 0) {
+ fprintf(stderr,
+ "rmtool: 'mem %s' is a write/ownership operation and "
+ "is refused by policy (read-only host oracle). "
+ "See debug/risc-v-gsp-rm-vm/docs/17-RM-HARNESS.md.\n",
+ argv[1]);
+ return 4;
+ }
+ usage();
+ return 2;
+}