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