1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2023-2025 Ruslan Bukin <br@bsdpad.com> 5 * 6 * This work was supported by Innovate UK project 105694, "Digital Security 7 * by Design (DSbD) Technology Platform Prototype". 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 /* Hardware Trace (HWT) framework. */ 32 33 #include <sys/param.h> 34 #include <sys/kernel.h> 35 #include <sys/malloc.h> 36 #include <sys/mutex.h> 37 #include <sys/hwt.h> 38 39 #include <dev/hwt/hwt_hook.h> 40 #include <dev/hwt/hwt_context.h> 41 #include <dev/hwt/hwt_config.h> 42 #include <dev/hwt/hwt_thread.h> 43 #include <dev/hwt/hwt_backend.h> 44 45 #define HWT_BACKEND_DEBUG 46 #undef HWT_BACKEND_DEBUG 47 48 #ifdef HWT_BACKEND_DEBUG 49 #define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) 50 #else 51 #define dprintf(fmt, ...) 52 #endif 53 54 static struct mtx hwt_backend_mtx; 55 56 struct hwt_backend_entry { 57 struct hwt_backend *backend; 58 LIST_ENTRY(hwt_backend_entry) next; 59 }; 60 61 static LIST_HEAD(, hwt_backend_entry) hwt_backends; 62 63 static MALLOC_DEFINE(M_HWT_BACKEND, "hwt_backend", "HWT backend"); 64 65 int 66 hwt_backend_init(struct hwt_context *ctx) 67 { 68 int error; 69 70 dprintf("%s\n", __func__); 71 72 error = ctx->hwt_backend->ops->hwt_backend_init(ctx); 73 74 return (error); 75 } 76 77 void 78 hwt_backend_deinit(struct hwt_context *ctx) 79 { 80 81 dprintf("%s\n", __func__); 82 83 ctx->hwt_backend->ops->hwt_backend_deinit(ctx); 84 } 85 86 int 87 hwt_backend_configure(struct hwt_context *ctx, int cpu_id, int thread_id) 88 { 89 int error; 90 91 dprintf("%s\n", __func__); 92 93 error = ctx->hwt_backend->ops->hwt_backend_configure(ctx, cpu_id, 94 thread_id); 95 96 return (error); 97 } 98 99 void 100 hwt_backend_enable(struct hwt_context *ctx, int cpu_id) 101 { 102 103 dprintf("%s\n", __func__); 104 105 ctx->hwt_backend->ops->hwt_backend_enable(ctx, cpu_id); 106 } 107 108 void 109 hwt_backend_disable(struct hwt_context *ctx, int cpu_id) 110 { 111 112 dprintf("%s\n", __func__); 113 114 ctx->hwt_backend->ops->hwt_backend_disable(ctx, cpu_id); 115 } 116 117 void 118 hwt_backend_enable_smp(struct hwt_context *ctx) 119 { 120 121 dprintf("%s\n", __func__); 122 123 ctx->hwt_backend->ops->hwt_backend_enable_smp(ctx); 124 } 125 126 void 127 hwt_backend_disable_smp(struct hwt_context *ctx) 128 { 129 130 dprintf("%s\n", __func__); 131 132 ctx->hwt_backend->ops->hwt_backend_disable_smp(ctx); 133 } 134 135 void __unused 136 hwt_backend_dump(struct hwt_context *ctx, int cpu_id) 137 { 138 139 dprintf("%s\n", __func__); 140 141 ctx->hwt_backend->ops->hwt_backend_dump(cpu_id); 142 } 143 144 int 145 hwt_backend_read(struct hwt_context *ctx, struct hwt_vm *vm, int *ident, 146 vm_offset_t *offset, uint64_t *data) 147 { 148 int error; 149 150 dprintf("%s\n", __func__); 151 152 error = ctx->hwt_backend->ops->hwt_backend_read(vm, ident, 153 offset, data); 154 155 return (error); 156 } 157 158 struct hwt_backend * 159 hwt_backend_lookup(const char *name) 160 { 161 struct hwt_backend_entry *entry; 162 struct hwt_backend *backend; 163 164 HWT_BACKEND_LOCK(); 165 LIST_FOREACH(entry, &hwt_backends, next) { 166 backend = entry->backend; 167 if (strcmp(backend->name, name) == 0) { 168 HWT_BACKEND_UNLOCK(); 169 return (backend); 170 } 171 } 172 HWT_BACKEND_UNLOCK(); 173 174 return (NULL); 175 } 176 177 int 178 hwt_backend_register(struct hwt_backend *backend) 179 { 180 struct hwt_backend_entry *entry; 181 182 if (backend == NULL || 183 backend->name == NULL || 184 backend->ops == NULL) 185 return (EINVAL); 186 187 entry = malloc(sizeof(struct hwt_backend_entry), M_HWT_BACKEND, 188 M_WAITOK | M_ZERO); 189 entry->backend = backend; 190 191 HWT_BACKEND_LOCK(); 192 LIST_INSERT_HEAD(&hwt_backends, entry, next); 193 HWT_BACKEND_UNLOCK(); 194 195 return (0); 196 } 197 198 int 199 hwt_backend_unregister(struct hwt_backend *backend) 200 { 201 struct hwt_backend_entry *entry, *tmp; 202 203 if (backend == NULL) 204 return (EINVAL); 205 206 /* TODO: check if not in use */ 207 208 HWT_BACKEND_LOCK(); 209 LIST_FOREACH_SAFE(entry, &hwt_backends, next, tmp) { 210 if (entry->backend == backend) { 211 LIST_REMOVE(entry, next); 212 HWT_BACKEND_UNLOCK(); 213 free(entry, M_HWT_BACKEND); 214 return (0); 215 } 216 } 217 HWT_BACKEND_UNLOCK(); 218 219 return (ENOENT); 220 } 221 222 void 223 hwt_backend_load(void) 224 { 225 226 mtx_init(&hwt_backend_mtx, "hwt backend", NULL, MTX_DEF); 227 LIST_INIT(&hwt_backends); 228 } 229 230 void 231 hwt_backend_unload(void) 232 { 233 234 /* TODO: ensure all unregistered */ 235 236 mtx_destroy(&hwt_backend_mtx); 237 } 238 239 void 240 hwt_backend_stop(struct hwt_context *ctx) 241 { 242 dprintf("%s\n", __func__); 243 244 ctx->hwt_backend->ops->hwt_backend_stop(ctx); 245 } 246 247 int 248 hwt_backend_svc_buf(struct hwt_context *ctx, void *data, size_t data_size, 249 int data_version) 250 { 251 int error; 252 253 dprintf("%s\n", __func__); 254 255 error = ctx->hwt_backend->ops->hwt_backend_svc_buf(ctx, data, data_size, 256 data_version); 257 258 return (error); 259 } 260 261 int 262 hwt_backend_thread_alloc(struct hwt_context *ctx, struct hwt_thread *thr) 263 { 264 int error; 265 266 dprintf("%s\n", __func__); 267 268 if (ctx->hwt_backend->ops->hwt_backend_thread_alloc == NULL) 269 return (0); 270 KASSERT(thr->private == NULL, 271 ("%s: thread private data is not NULL\n", __func__)); 272 error = ctx->hwt_backend->ops->hwt_backend_thread_alloc(thr); 273 274 return (error); 275 } 276 277 void 278 hwt_backend_thread_free(struct hwt_thread *thr) 279 { 280 dprintf("%s\n", __func__); 281 282 if (thr->backend->ops->hwt_backend_thread_free == NULL) 283 return; 284 KASSERT(thr->private != NULL, 285 ("%s: thread private data is NULL\n", __func__)); 286 thr->backend->ops->hwt_backend_thread_free(thr); 287 288 return; 289 } 290