blob: 84ea9cf5c82c9139828e5eb001f0b8f42e398e72 [file] [log] [blame]
Jens Wiklander254a3e32019-01-31 12:25:08 +01001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2019, Linaro Limited
4 */
5
Jens Wiklander254a3e32019-01-31 12:25:08 +01006#include <dirent.h>
7#include <err.h>
8#include <errno.h>
9#include <fnmatch.h>
10#include <inttypes.h>
11#include <stdbool.h>
12#include <stdint.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/stat.h>
17#include <sys/types.h>
18#include <tee_client_api.h>
19#include <unistd.h>
20#include "xtest_test.h"
21#include "stats.h"
22
23#define STATS_UUID { 0xd96a5b40, 0xe2c7, 0xb1af, \
24 { 0x87, 0x94, 0x10, 0x02, 0xa5, 0xd5, 0xc6, 0x1b } }
25
26#define STATS_CMD_PAGER_STATS 0
27#define STATS_CMD_ALLOC_STATS 1
28#define STATS_CMD_MEMLEAK_STATS 2
29
30#define TEE_ALLOCATOR_DESC_LENGTH 32
31struct malloc_stats {
32 char desc[TEE_ALLOCATOR_DESC_LENGTH];
33 uint32_t allocated; /* Bytes currently allocated */
34 uint32_t max_allocated; /* Tracks max value of allocated */
35 uint32_t size; /* Total size for this allocator */
36 uint32_t num_alloc_fail; /* Number of failed alloc requests */
37 uint32_t biggest_alloc_fail; /* Size of biggest failed alloc */
38 uint32_t biggest_alloc_fail_used; /* Alloc bytes when above occurred */
39};
40
41static const char *stats_progname = "xtest --stats";
42
43static int usage(void)
44{
45 fprintf(stderr, "Usage: %s [OPTION]\n", stats_progname);
46 fprintf(stderr, "Displays statistics from OP-TEE\n");
47 fprintf(stderr, "Options:\n");
48 fprintf(stderr, " -h|--help Print this help and exit\n");
49 fprintf(stderr, " --pager Print pager statistics\n");
50 fprintf(stderr, " --alloc Print allocation statistics\n");
51 fprintf(stderr, " --memleak Dump memory leak data on secure console\n");
52
53 return EXIT_FAILURE;
54}
55
56static void open_sess(TEEC_Context *ctx, TEEC_Session *sess)
57{
58 TEEC_UUID uuid = STATS_UUID;
59 TEEC_Result res = TEEC_ERROR_GENERIC;
60 uint32_t eo = 0;
61
62 res = TEEC_InitializeContext(NULL, ctx);
63 if (res)
64 errx(EXIT_FAILURE, "TEEC_InitializeContext: %#"PRIx32, res);
65
66 res = TEEC_OpenSession(ctx, sess, &uuid, TEEC_LOGIN_PUBLIC, NULL,
67 NULL, &eo);
68 if (res)
69 errx(EXIT_FAILURE,
70 "TEEC_OpenSession: res %#"PRIx32" err_orig %#"PRIx32,
71 res, eo);
72}
73
74static int close_sess(TEEC_Context *ctx, TEEC_Session *sess)
75{
76 TEEC_CloseSession(sess);
77 TEEC_FinalizeContext(ctx);
78
79 return EXIT_SUCCESS;
80}
81
Jerome Forissier659e2212020-10-27 18:39:05 +010082static int stat_pager(int argc, char *argv[])
Jens Wiklander254a3e32019-01-31 12:25:08 +010083{
Etienne Carrieree4ec9e42019-03-28 13:30:21 +010084 TEEC_Context ctx = { };
85 TEEC_Session sess = { };
Jens Wiklander254a3e32019-01-31 12:25:08 +010086 TEEC_Result res = TEEC_ERROR_GENERIC;
87 uint32_t eo = 0;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +010088 TEEC_Operation op = { };
Jens Wiklander254a3e32019-01-31 12:25:08 +010089
90 if (argc != 1)
91 return usage();
92
93 open_sess(&ctx, &sess);
94
Jens Wiklander254a3e32019-01-31 12:25:08 +010095 op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_VALUE_OUTPUT,
96 TEEC_VALUE_OUTPUT, TEEC_NONE);
97
98 res = TEEC_InvokeCommand(&sess, STATS_CMD_PAGER_STATS, &op, &eo);
99 if (res)
100 errx(EXIT_FAILURE,
101 "TEEC_InvokeCommand: res %#"PRIx32" err_orig %#"PRIx32,
102 res, eo);
103
104 printf("Pager statistics (Number of):\n");
105 printf("Available physical pages: %"PRId32"\n", op.params[0].value.a);
106 printf("Faults: %"PRId32"\n", op.params[0].value.b);
107 printf("R/O faults: %"PRId32"\n", op.params[1].value.a);
108 printf("R/W faults: %"PRId32"\n", op.params[1].value.b);
109 printf("Hidden faults: %"PRId32"\n", op.params[2].value.a);
110 printf("Zi pages released: %"PRId32"\n", op.params[2].value.b);
111
112 return close_sess(&ctx, &sess);
113}
114
Jerome Forissier659e2212020-10-27 18:39:05 +0100115static int stat_alloc(int argc, char *argv[])
Jens Wiklander254a3e32019-01-31 12:25:08 +0100116{
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100117 TEEC_Context ctx = { };
118 TEEC_Session sess = { };
Jens Wiklander254a3e32019-01-31 12:25:08 +0100119 TEEC_Result res = TEEC_ERROR_GENERIC;
120 uint32_t eo = 0;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100121 TEEC_Operation op = { };
Jens Wiklander254a3e32019-01-31 12:25:08 +0100122 struct malloc_stats *stats = NULL;
123 size_t stats_size_bytes = 0;
124 size_t n = 0;
125
126 if (argc != 1)
127 return usage();
128
129 open_sess(&ctx, &sess);
130
Jens Wiklander254a3e32019-01-31 12:25:08 +0100131 op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
132 TEEC_MEMREF_TEMP_OUTPUT,
133 TEEC_NONE, TEEC_NONE);
134 res = TEEC_InvokeCommand(&sess, STATS_CMD_ALLOC_STATS, &op, &eo);
135 if (res != TEEC_ERROR_SHORT_BUFFER)
136 errx(EXIT_FAILURE,
137 "TEEC_InvokeCommand: res %#"PRIx32" err_orig %#"PRIx32,
138 res, eo);
139
140 stats_size_bytes = op.params[1].tmpref.size;
141 if (stats_size_bytes % sizeof(*stats))
142 errx(EXIT_FAILURE,
143 "STATS_CMD_PAGER_STATS: %zu not a multiple of %zu",
144 stats_size_bytes, sizeof(*stats));
145 stats = calloc(1, stats_size_bytes);
146 if (!stats)
147 err(EXIT_FAILURE, "calloc(1, %zu)", stats_size_bytes);
148
149 op.params[1].tmpref.buffer = stats;
150 op.params[1].tmpref.size = stats_size_bytes;
151 res = TEEC_InvokeCommand(&sess, STATS_CMD_ALLOC_STATS, &op, &eo);
152 if (res)
153 errx(EXIT_FAILURE,
154 "TEEC_InvokeCommand: res %#"PRIx32" err_orig %#"PRIx32,
155 res, eo);
156
157 if (op.params[1].tmpref.size != stats_size_bytes)
158 errx(EXIT_FAILURE,
159 "STATS_CMD_PAGER_STATS: expected size %zu, got %zu",
160 stats_size_bytes, op.params[1].tmpref.size);
161
162 for (n = 0; n < stats_size_bytes / sizeof(*stats); n++) {
163 if (n)
164 printf("\n");
165 printf("Pool: %*s\n",
166 (int)strnlen(stats[n].desc, sizeof(stats[n].desc)),
167 stats[n].desc);
168 printf("Bytes allocated: %"PRId32"\n",
169 stats[n].allocated);
170 printf("Max bytes allocated: %"PRId32"\n",
171 stats[n].max_allocated);
172 printf("Size of pool: %"PRId32"\n",
173 stats[n].size);
174 printf("Number of failed allocations: %"PRId32"\n",
175 stats[n].num_alloc_fail);
176 printf("Size of larges allocation failure: %"PRId32"\n",
177 stats[n].biggest_alloc_fail);
178 printf("Total bytes allocated at that failure: %"PRId32"\n",
179 stats[n].biggest_alloc_fail_used);
180 }
181
182 free(stats);
183
184 return close_sess(&ctx, &sess);
185}
186
Jerome Forissier659e2212020-10-27 18:39:05 +0100187static int stat_memleak(int argc, char *argv[])
Jens Wiklander254a3e32019-01-31 12:25:08 +0100188{
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100189 TEEC_Context ctx = { };
190 TEEC_Session sess = { };
Jens Wiklander254a3e32019-01-31 12:25:08 +0100191 TEEC_Result res = TEEC_ERROR_GENERIC;
192 uint32_t eo = 0;
193
194 if (argc != 1)
195 return usage();
196
197 open_sess(&ctx, &sess);
198
199 res = TEEC_InvokeCommand(&sess, STATS_CMD_MEMLEAK_STATS, NULL, &eo);
200 if (res)
201 errx(EXIT_FAILURE,
202 "TEEC_InvokeCommand: res %#"PRIx32" err_orig %#"PRIx32,
203 res, eo);
204
205 return close_sess(&ctx, &sess);
206}
207
208int stats_runner_cmd_parser(int argc, char *argv[])
209{
210 if (argc > 1) {
211 if (!strcmp(argv[1], "--pager"))
212 return stat_pager(argc - 1, argv + 1);
213 if (!strcmp(argv[1], "--alloc"))
214 return stat_alloc(argc - 1, argv + 1);
215 if (!strcmp(argv[1], "--memleak"))
216 return stat_memleak(argc - 1, argv + 1);
217 }
218
219 return usage();
220}