Page MenuHomeFreeBSD

D40466.id125360.diff
No OneTemporary

D40466.id125360.diff

Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -1911,6 +1911,19 @@
dev/hwpmc/hwpmc_logging.c optional hwpmc
dev/hwpmc/hwpmc_mod.c optional hwpmc
dev/hwpmc/hwpmc_soft.c optional hwpmc
+dev/hwt/hwt.c optional hwt
+dev/hwt/hwt_backend.c optional hwt
+dev/hwt/hwt_config.c optional hwt
+dev/hwt/hwt_context.c optional hwt
+dev/hwt/hwt_contexthash.c optional hwt
+dev/hwt/hwt_cpu.c optional hwt
+dev/hwt/hwt_hook.c optional hwt
+dev/hwt/hwt_ioctl.c optional hwt
+dev/hwt/hwt_owner.c optional hwt
+dev/hwt/hwt_ownerhash.c optional hwt
+dev/hwt/hwt_record.c optional hwt
+dev/hwt/hwt_thread.c optional hwt
+dev/hwt/hwt_vm.c optional hwt
dev/ichiic/ig4_acpi.c optional ig4 acpi iicbus
dev/ichiic/ig4_iic.c optional ig4 iicbus
dev/ichiic/ig4_pci.c optional ig4 pci iicbus
@@ -3894,6 +3907,7 @@
kern/kern_flag.c standard
kern/kern_fork.c standard
kern/kern_hhook.c standard
+kern/kern_hwt.c standard
kern/kern_idle.c standard
kern/kern_intr.c standard
kern/kern_jail.c standard
Index: sys/conf/options
===================================================================
--- sys/conf/options
+++ sys/conf/options
@@ -906,6 +906,9 @@
HWPMC_HOOKS
HWPMC_MIPS_BACKTRACE opt_hwpmc_hooks.h
+# Hardware Trace (HWT) framework options
+HWT_HOOKS
+
# 802.11 support layer
IEEE80211_DEBUG opt_wlan.h
IEEE80211_DEBUG_REFCNT opt_wlan.h
Index: sys/dev/hwt/hwt.c
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt.c
@@ -0,0 +1,229 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Hardware Tracing framework.
+ *
+ * The framework manages hardware tracing units that collect information
+ * about software execution and store it as events in highly compressed format
+ * into DRAM. The events cover information about control flow changes of a
+ * program, whether branches taken or not, exceptions taken, timing information,
+ * cycles elapsed and more. That allows us to restore entire program flow of a
+ * given application without performance impact.
+ *
+ * Design overview.
+ *
+ * The framework provides character devices for mmap(2) and ioctl(2) system
+ * calls to allow user to manage CPU (hardware) tracing units.
+ *
+ * /dev/hwt:
+ * .ioctl:
+ * hwt_ioctl():
+ * a) HWT_IOC_ALLOC
+ * Allocates kernel tracing context ctx for a given pid,
+ * and for required mode of operation (CPU or Thread mode),
+ * returns unique ident.
+ * Creates a new character device for ctx management.
+ *
+ * /dev/hwt_%d[_%d], ident[, thread_id]
+ * .mmap
+ * Maps tracing buffers of the corresponding thread to userspace.
+ * .ioctl
+ * hwt_thread_ioctl():
+ * a) HWT_IOC_START
+ * Enables tracing unit for a given context.
+ * b) HWT_IOC_RECORD_GET
+ * Transfers (small) record entries collected during program
+ * execution for a given context to userspace, such as mmaping
+ * tables of executable and dynamic libraries, interpreter,
+ * tid of threads created, etc.
+ * c) HWT_IOC_SET_CONFIG
+ * This allows to set backend-specific configuration of the
+ * trace unit.
+ * d) HWT_IOC_WAKEUP
+ * This wakes up a thread that is currently sleeping.
+ * e) HWT_IOC_BUFPTR_GET
+ * Transfers current hardware pointer in the filling buffer
+ * to userspace.
+ *
+ * HWT context lifecycle:
+ * 1. User invokes HWT_IOC_ALLOC ioctl with information about pid to trace and
+ * size of the buffers for the trace data to allocate.
+ * Some architectures may have different tracing units supported, so user
+ * also provides backend name to use for this context, e.g. "coresight".
+ * 2. Kernel allocates context, lookups the proc for the given pid. Creates
+ * first hwt_thread in the context and allocates trace buffers for it.
+ * Immediately, kernel initializes tracing backend.
+ * Kernel creates character device and returns unique identificator of
+ * trace context.
+ * 3. User opens new character device to operate with the new context.
+ * User invokes HWT_IOC_START ioctl, kernel marks context as RUNNING.
+ * At this point any HWT hook invocation by scheduler enables/disables
+ * tracing for threads associated with the context (threads of the proc).
+ * Any new threads creation (of the target proc) procedures will be invoking
+ * corresponding hooks in HWT framework, so that new hwt_thread and buffers
+ * allocated, character device for mmap(2) created on the fly.
+ * 4. User issues HWT_IOC_RECORD_GET ioctl to fetch information about mmaping
+ * tables and threads created during application startup.
+ * 5. User mmaps tracing buffers of each thread to userspace (using
+ * /dev/hwt_%d_%d % (ident, thread_id) character devices).
+ * 6. User can repeat 4 if expected thread is not yet created during target
+ * application execution.
+ * 7. User issues HWT_IOC_BUFPTR_GET ioctl to get current filling level of the
+ * hardware buffer of a given thread.
+ * 8. User invokes trace decoder library to process available data and see the
+ * results in human readable form.
+ * 9. User repeates 7 if needed.
+ */
+
+#include <sys/param.h>
+#include <sys/eventhandler.h>
+#include <sys/ioccom.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+
+#include <dev/hwt/hwt_context.h>
+#include <dev/hwt/hwt_contexthash.h>
+#include <dev/hwt/hwt_thread.h>
+#include <dev/hwt/hwt_owner.h>
+#include <dev/hwt/hwt_ownerhash.h>
+#include <dev/hwt/hwt_backend.h>
+#include <dev/hwt/hwt_ioctl.h>
+#include <dev/hwt/hwt_hook.h>
+
+#define HWT_DEBUG
+#undef HWT_DEBUG
+
+#ifdef HWT_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+static eventhandler_tag hwt_exit_tag;
+static struct cdev *hwt_cdev;
+static struct cdevsw hwt_cdevsw = {
+ .d_version = D_VERSION,
+ .d_name = "hwt",
+ .d_mmap_single = NULL,
+ .d_ioctl = hwt_ioctl
+};
+
+static void
+hwt_process_exit(void *arg __unused, struct proc *p)
+{
+ struct hwt_owner *ho;
+
+ /* Stop HWTs associated with exiting owner, if any. */
+ ho = hwt_ownerhash_lookup(p);
+ if (ho)
+ hwt_owner_shutdown(ho);
+}
+
+static int
+hwt_load(void)
+{
+ struct make_dev_args args;
+ int error;
+
+ make_dev_args_init(&args);
+ args.mda_devsw = &hwt_cdevsw;
+ args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK;
+ args.mda_uid = UID_ROOT;
+ args.mda_gid = GID_WHEEL;
+ args.mda_mode = 0660;
+ args.mda_si_drv1 = NULL;
+
+ hwt_backend_load();
+ hwt_ctx_load();
+ hwt_contexthash_load();
+ hwt_ownerhash_load();
+
+ error = make_dev_s(&args, &hwt_cdev, "hwt");
+ if (error != 0)
+ return (error);
+
+ hwt_exit_tag = EVENTHANDLER_REGISTER(process_exit, hwt_process_exit,
+ NULL, EVENTHANDLER_PRI_ANY);
+
+ hwt_hook_load();
+
+ return (0);
+}
+
+static int
+hwt_unload(void)
+{
+
+ hwt_hook_unload();
+ EVENTHANDLER_DEREGISTER(process_exit, hwt_exit_tag);
+ destroy_dev(hwt_cdev);
+ hwt_ownerhash_unload();
+ hwt_contexthash_unload();
+ hwt_ctx_unload();
+ hwt_backend_unload();
+
+ return (0);
+}
+
+static int
+hwt_modevent(module_t mod, int type, void *data)
+{
+ int error;
+
+ switch (type) {
+ case MOD_LOAD:
+ error = hwt_load();
+ break;
+ case MOD_UNLOAD:
+ error = hwt_unload();
+ break;
+ default:
+ error = 0;
+ break;
+ }
+
+ return (error);
+}
+
+static moduledata_t hwt_mod = {
+ "hwt",
+ hwt_modevent,
+ NULL
+};
+
+DECLARE_MODULE(hwt, hwt_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
+MODULE_VERSION(hwt, 1);
Index: sys/dev/hwt/hwt_backend.h
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_backend.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_HWT_HWT_BACKEND_H_
+#define _DEV_HWT_HWT_BACKEND_H_
+
+struct hwt_backend_ops {
+ int (*hwt_backend_init)(struct hwt_context *);
+ void (*hwt_backend_deinit)(void);
+ int (*hwt_backend_configure)(struct hwt_context *, int cpu_id,
+ int thread_id);
+ void (*hwt_backend_enable)(int cpu_id);
+ void (*hwt_backend_disable)(int cpu_id);
+ int (*hwt_backend_read)(int cpu_id, int *curpage,
+ vm_offset_t *curpage_offset);
+
+ /* Debugging only. */
+ void (*hwt_backend_dump)(int cpu_id);
+};
+
+struct hwt_backend {
+ const char *name;
+ struct hwt_backend_ops *ops;
+};
+
+int hwt_backend_init(struct hwt_context *ctx);
+void hwt_backend_deinit(struct hwt_context *ctx);
+int hwt_backend_configure(struct hwt_context *ctx, int cpu_id, int thread_id);
+void hwt_backend_enable(struct hwt_context *ctx, int cpu_id);
+void hwt_backend_disable(struct hwt_context *ctx, int cpu_id);
+void hwt_backend_dump(struct hwt_context *ctx, int cpu_id);
+int hwt_backend_read(struct hwt_context *ctx, int cpu_id, int *curpage,
+ vm_offset_t *curpage_offset);
+int hwt_backend_register(struct hwt_backend *);
+int hwt_backend_unregister(struct hwt_backend *);
+struct hwt_backend * hwt_backend_lookup(const char *name);
+
+void hwt_backend_load(void);
+void hwt_backend_unload(void);
+
+#define HWT_BACKEND_LOCK() mtx_lock_spin(&hwt_backend_mtx)
+#define HWT_BACKEND_UNLOCK() mtx_unlock_spin(&hwt_backend_mtx)
+
+#endif /* !_DEV_HWT_HWT_BACKEND_H_ */
+
Index: sys/dev/hwt/hwt_backend.c
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_backend.c
@@ -0,0 +1,230 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Hardware Trace (HWT) framework. */
+
+#include <sys/param.h>
+#include <sys/eventhandler.h>
+#include <sys/ioccom.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/hwt.h>
+
+#include <dev/hwt/hwt_hook.h>
+#include <dev/hwt/hwt_context.h>
+#include <dev/hwt/hwt_config.h>
+#include <dev/hwt/hwt_thread.h>
+#include <dev/hwt/hwt_backend.h>
+
+#define HWT_BACKEND_DEBUG
+#undef HWT_BACKEND_DEBUG
+
+#ifdef HWT_BACKEND_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+static struct mtx hwt_backend_mtx;
+
+struct hwt_backend_entry {
+ struct hwt_backend *backend;
+ LIST_ENTRY(hwt_backend_entry) next;
+};
+
+static LIST_HEAD(, hwt_backend_entry) hwt_backends;
+
+static MALLOC_DEFINE(M_HWT_BACKEND, "hwt_backend", "HWT backend");
+
+int
+hwt_backend_init(struct hwt_context *ctx)
+{
+ int error;
+
+ dprintf("%s\n", __func__);
+
+ error = ctx->hwt_backend->ops->hwt_backend_init(ctx);
+
+ return (error);
+}
+
+void
+hwt_backend_deinit(struct hwt_context *ctx)
+{
+
+ dprintf("%s\n", __func__);
+
+ ctx->hwt_backend->ops->hwt_backend_deinit();
+}
+
+int
+hwt_backend_configure(struct hwt_context *ctx, int cpu_id, int thread_id)
+{
+ int error;
+
+ dprintf("%s\n", __func__);
+
+ error = ctx->hwt_backend->ops->hwt_backend_configure(ctx, cpu_id,
+ thread_id);
+
+ return (error);
+}
+
+void
+hwt_backend_enable(struct hwt_context *ctx, int cpu_id)
+{
+
+ dprintf("%s\n", __func__);
+
+ ctx->hwt_backend->ops->hwt_backend_enable(cpu_id);
+}
+
+void
+hwt_backend_disable(struct hwt_context *ctx, int cpu_id)
+{
+
+ dprintf("%s\n", __func__);
+
+ ctx->hwt_backend->ops->hwt_backend_disable(cpu_id);
+}
+
+void __unused
+hwt_backend_dump(struct hwt_context *ctx, int cpu_id)
+{
+
+ dprintf("%s\n", __func__);
+
+ ctx->hwt_backend->ops->hwt_backend_dump(cpu_id);
+}
+
+int
+hwt_backend_read(struct hwt_context *ctx, int cpu_id, int *curpage,
+ vm_offset_t *curpage_offset)
+{
+ int error;
+
+ dprintf("%s\n", __func__);
+
+ error = ctx->hwt_backend->ops->hwt_backend_read(cpu_id, curpage,
+ curpage_offset);
+
+ return (error);
+}
+
+struct hwt_backend *
+hwt_backend_lookup(const char *name)
+{
+ struct hwt_backend_entry *entry;
+ struct hwt_backend *backend;
+
+ HWT_BACKEND_LOCK();
+ LIST_FOREACH(entry, &hwt_backends, next) {
+ backend = entry->backend;
+ if (strcmp(backend->name, name) == 0) {
+ HWT_BACKEND_UNLOCK();
+ return (backend);
+ }
+ }
+ HWT_BACKEND_UNLOCK();
+
+ return (NULL);
+}
+
+int
+hwt_backend_register(struct hwt_backend *backend)
+{
+ struct hwt_backend_entry *entry;
+
+ if (backend == NULL ||
+ backend->name == NULL ||
+ backend->ops == NULL)
+ return (EINVAL);
+
+#if 0
+ mtx_init(&entry->mtx, "BKND", NULL, MTX_DEF);
+#endif
+
+ entry = malloc(sizeof(struct hwt_backend_entry), M_HWT_BACKEND,
+ M_WAITOK | M_ZERO);
+ entry->backend = backend;
+
+ HWT_BACKEND_LOCK();
+ LIST_INSERT_HEAD(&hwt_backends, entry, next);
+ HWT_BACKEND_UNLOCK();
+
+ return (0);
+}
+
+int
+hwt_backend_unregister(struct hwt_backend *backend)
+{
+ struct hwt_backend_entry *entry, *tmp;
+
+ if (backend == NULL)
+ return (EINVAL);
+
+ /* TODO: check if not in use */
+
+ HWT_BACKEND_LOCK();
+ LIST_FOREACH_SAFE(entry, &hwt_backends, next, tmp) {
+ if (entry->backend == backend) {
+ LIST_REMOVE(entry, next);
+ HWT_BACKEND_UNLOCK();
+ free(entry, M_HWT_BACKEND);
+ return (0);
+ }
+ }
+ HWT_BACKEND_UNLOCK();
+
+ return (ENOENT);
+}
+
+void
+hwt_backend_load(void)
+{
+
+ mtx_init(&hwt_backend_mtx, "hwt backend", NULL, MTX_SPIN);
+ LIST_INIT(&hwt_backends);
+}
+
+void
+hwt_backend_unload(void)
+{
+
+ /* TODO: ensure all unregistered */
+
+ mtx_destroy(&hwt_backend_mtx);
+}
Index: sys/dev/hwt/hwt_config.h
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_config.h
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_HWT_HWT_CONFIG_H_
+#define _DEV_HWT_HWT_CONFIG_H_
+
+int hwt_config_set(struct thread *td, struct hwt_context *ctx,
+ struct hwt_set_config *sconf);
+void hwt_config_free(struct hwt_context *ctx);
+
+#endif /* !_DEV_HWT_HWT_CONFIG_H_ */
Index: sys/dev/hwt/hwt_config.c
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_config.c
@@ -0,0 +1,107 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/hwt.h>
+
+#include <vm/vm.h>
+
+#include <dev/hwt/hwt_hook.h>
+#include <dev/hwt/hwt_context.h>
+#include <dev/hwt/hwt_contexthash.h>
+#include <dev/hwt/hwt_config.h>
+#include <dev/hwt/hwt_thread.h>
+#include <dev/hwt/hwt_record.h>
+
+#define HWT_MAXCONFIGSIZE PAGE_SIZE
+
+#define HWT_CONFIG_DEBUG
+#undef HWT_CONFIG_DEBUG
+
+#ifdef HWT_CONFIG_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+static MALLOC_DEFINE(M_HWT_CONFIG, "hwt_config", "HWT config");
+
+int
+hwt_config_set(struct thread *td, struct hwt_context *ctx,
+ struct hwt_set_config *sconf)
+{
+ size_t config_size;
+ void *old_config;
+ void *config;
+ int error;
+
+ config_size = sconf->config_size;
+ if (config_size == 0)
+ return (0);
+
+ if (config_size > HWT_MAXCONFIGSIZE)
+ return (EFBIG);
+
+ config = malloc(config_size, M_HWT_CONFIG, M_WAITOK | M_ZERO);
+
+ error = copyin(sconf->config, config, config_size);
+ if (error) {
+ free(config, M_HWT_CONFIG);
+ return (error);
+ }
+
+ HWT_CTX_LOCK(ctx);
+ old_config = ctx->config;
+ ctx->config = config;
+ ctx->config_size = sconf->config_size;
+ ctx->config_version = sconf->config_version;
+ HWT_CTX_UNLOCK(ctx);
+
+ if (old_config != NULL)
+ free(old_config, M_HWT_CONFIG);
+
+ return (error);
+}
+
+void
+hwt_config_free(struct hwt_context *ctx)
+{
+
+ if (ctx->config == NULL)
+ return;
+
+ free(ctx->config, M_HWT_CONFIG);
+
+ ctx->config = NULL;
+}
Index: sys/dev/hwt/hwt_context.h
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_context.h
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_HWT_HWT_CONTEXT_H_
+#define _DEV_HWT_HWT_CONTEXT_H_
+
+struct hwt_context {
+ LIST_HEAD(, hwt_record_entry) records;
+
+ LIST_ENTRY(hwt_context) next_hch; /* Entry in contexthash. */
+ LIST_ENTRY(hwt_context) next_hwts; /* Entry in ho->hwts. */
+
+ int mode;
+ int ident;
+
+ /* CPU mode. */
+ cpuset_t cpu_map;
+ TAILQ_HEAD(, hwt_cpu) cpus;
+
+ /* Thread mode. */
+ struct proc *proc; /* Target proc. */
+ pid_t pid; /* Target pid. */
+ TAILQ_HEAD(, hwt_thread) threads;
+ int thread_counter;
+ int pause_on_mmap;
+
+ size_t bufsize; /* Trace bufsize for each vm.*/
+ void *config;
+ size_t config_size;
+ int config_version;
+
+ struct hwt_owner *hwt_owner;
+ struct hwt_backend *hwt_backend;
+
+ struct mtx mtx;
+ int state;
+#define CTX_STATE_RUNNING (1 << 0)
+};
+
+#define HWT_CTX_LOCK(ctx) mtx_lock_spin(&(ctx)->mtx)
+#define HWT_CTX_UNLOCK(ctx) mtx_unlock_spin(&(ctx)->mtx)
+#define HWT_CTX_ASSERT_LOCKED(ctx) mtx_assert(&(ctx)->mtx, MA_OWNED)
+
+struct hwt_context * hwt_ctx_alloc(void);
+void hwt_ctx_free(struct hwt_context *ctx);
+
+void hwt_ctx_load(void);
+void hwt_ctx_unload(void);
+
+#endif /* !_DEV_HWT_HWT_CONTEXT_H_ */
Index: sys/dev/hwt/hwt_context.c
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_context.c
@@ -0,0 +1,140 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/bitstring.h>
+#include <sys/eventhandler.h>
+#include <sys/ioccom.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/hwt.h>
+
+#include <dev/hwt/hwt_hook.h>
+#include <dev/hwt/hwt_context.h>
+#include <dev/hwt/hwt_config.h>
+#include <dev/hwt/hwt_thread.h>
+#include <dev/hwt/hwt_owner.h>
+
+#define HWT_DEBUG
+#undef HWT_DEBUG
+
+#ifdef HWT_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+static MALLOC_DEFINE(M_HWT_CTX, "hwt_ctx", "Hardware Trace");
+
+static bitstr_t *ident_set;
+static int ident_set_size;
+static struct mtx ident_set_mutex;
+
+static int
+hwt_ctx_ident_alloc(int *new_ident)
+{
+
+ mtx_lock_spin(&ident_set_mutex);
+ bit_ffc(ident_set, ident_set_size, new_ident);
+ if (*new_ident == -1) {
+ mtx_unlock_spin(&ident_set_mutex);
+ return (ENOMEM);
+ }
+ bit_set(ident_set, *new_ident);
+ mtx_unlock_spin(&ident_set_mutex);
+
+ return (0);
+}
+
+static void
+hwt_ctx_ident_free(int ident)
+{
+
+ mtx_lock_spin(&ident_set_mutex);
+ bit_clear(ident_set, ident);
+ mtx_unlock_spin(&ident_set_mutex);
+}
+
+struct hwt_context *
+hwt_ctx_alloc(void)
+{
+ struct hwt_context *ctx;
+ int error;
+
+ ctx = malloc(sizeof(struct hwt_context), M_HWT_CTX, M_WAITOK | M_ZERO);
+ ctx->thread_counter = 0;
+
+ LIST_INIT(&ctx->records);
+ TAILQ_INIT(&ctx->threads);
+ TAILQ_INIT(&ctx->cpus);
+ mtx_init(&ctx->mtx, "ctx", NULL, MTX_SPIN);
+
+ hwt_ctx_ident_alloc(&ctx->ident);
+
+ error = hwt_ctx_ident_alloc(&ctx->ident);
+ if (error) {
+ printf("could not allocate ident bit str\n");
+ return (NULL);
+ }
+
+ return (ctx);
+}
+
+void
+hwt_ctx_free(struct hwt_context *ctx)
+{
+
+ hwt_config_free(ctx);
+ hwt_ctx_ident_free(ctx->ident);
+ free(ctx, M_HWT_CTX);
+}
+
+void
+hwt_ctx_load(void)
+{
+
+ ident_set_size = (1 << 8);
+ ident_set = bit_alloc(ident_set_size, M_HWT_CTX, M_WAITOK);
+ mtx_init(&ident_set_mutex, "ident set", NULL, MTX_SPIN);
+}
+
+void
+hwt_ctx_unload(void)
+{
+
+ mtx_destroy(&ident_set_mutex);
+ free(ident_set, M_HWT_CTX);
+}
Index: sys/dev/hwt/hwt_contexthash.h
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_contexthash.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_HWT_HWT_CONTEXTHASH_H_
+#define _DEV_HWT_HWT_CONTEXTHASH_H_
+
+struct hwt_context * hwt_contexthash_lookup(struct proc *p);
+void hwt_contexthash_insert(struct hwt_context *ctx);
+void hwt_contexthash_remove(struct hwt_context *ctx);
+
+void hwt_contexthash_load(void);
+void hwt_contexthash_unload(void);
+
+#define HWT_CTXHASH_LOCK() mtx_lock_spin(&hwt_contexthash_mtx)
+#define HWT_CTXHASH_UNLOCK() mtx_unlock_spin(&hwt_contexthash_mtx)
+
+#endif /* !_DEV_HWT_HWT_CONTEXTHASH_H_ */
Index: sys/dev/hwt/hwt_contexthash.c
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_contexthash.c
@@ -0,0 +1,139 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/eventhandler.h>
+#include <sys/ioccom.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/hwt.h>
+
+#include <dev/hwt/hwt_context.h>
+#include <dev/hwt/hwt_contexthash.h>
+#include <dev/hwt/hwt_config.h>
+
+#define HWT_DEBUG
+#undef HWT_DEBUG
+
+#ifdef HWT_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+#define HWT_CONTEXTHASH_SIZE 1024
+
+static MALLOC_DEFINE(M_HWT_CONTEXTHASH, "hwt_chash", "Hardware Trace");
+
+/*
+ * Hash function. Discard the lower 2 bits of the pointer since
+ * these are always zero for our uses. The hash multiplier is
+ * round((2^LONG_BIT) * ((sqrt(5)-1)/2)).
+ */
+
+#define _HWT_HM 11400714819323198486u /* hash multiplier */
+#define HWT_HASH_PTR(P, M) ((((unsigned long) (P) >> 2) * _HWT_HM) & (M))
+
+static struct mtx hwt_contexthash_mtx;
+static u_long hwt_contexthashmask;
+static LIST_HEAD(hwt_contexthash, hwt_context) *hwt_contexthash;
+
+/*
+ * To use by hwt_switch_in/out() and hwt_record() only.
+ * This function returns mtx locked.
+ */
+struct hwt_context *
+hwt_contexthash_lookup(struct proc *p)
+{
+ struct hwt_contexthash *hch;
+ struct hwt_context *ctx;
+ int hindex;
+
+ hindex = HWT_HASH_PTR(p, hwt_contexthashmask);
+ hch = &hwt_contexthash[hindex];
+
+ HWT_CTXHASH_LOCK();
+ LIST_FOREACH(ctx, hch, next_hch) {
+ if (ctx->proc == p) {
+ HWT_CTX_LOCK(ctx);
+ HWT_CTXHASH_UNLOCK();
+ return (ctx);
+ }
+ }
+ HWT_CTXHASH_UNLOCK();
+
+ return (NULL);
+}
+
+void
+hwt_contexthash_insert(struct hwt_context *ctx)
+{
+ struct hwt_contexthash *hch;
+ int hindex;
+
+ hindex = HWT_HASH_PTR(ctx->proc, hwt_contexthashmask);
+ hch = &hwt_contexthash[hindex];
+
+ HWT_CTXHASH_LOCK();
+ LIST_INSERT_HEAD(hch, ctx, next_hch);
+ HWT_CTXHASH_UNLOCK();
+}
+
+void
+hwt_contexthash_remove(struct hwt_context *ctx)
+{
+
+ HWT_CTXHASH_LOCK();
+ LIST_REMOVE(ctx, next_hch);
+ HWT_CTXHASH_UNLOCK();
+}
+
+void
+hwt_contexthash_load(void)
+{
+
+ hwt_contexthash = hashinit(HWT_CONTEXTHASH_SIZE, M_HWT_CONTEXTHASH,
+ &hwt_contexthashmask);
+ mtx_init(&hwt_contexthash_mtx, "hwt ctx hash", "hwt ctx", MTX_SPIN);
+}
+
+void
+hwt_contexthash_unload(void)
+{
+
+ mtx_destroy(&hwt_contexthash_mtx);
+ hashdestroy(hwt_contexthash, M_HWT_CONTEXTHASH, hwt_contexthashmask);
+}
Index: sys/dev/hwt/hwt_cpu.h
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_cpu.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_HWT_HWT_CPU_H_
+#define _DEV_HWT_HWT_CPU_H_
+
+struct hwt_cpu {
+ int cpu_id;
+ struct hwt_vm *vm;
+ TAILQ_ENTRY(hwt_cpu) next;
+};
+
+struct hwt_cpu * hwt_cpu_alloc(void);
+void hwt_cpu_free(struct hwt_cpu *cpu);
+
+struct hwt_cpu * hwt_cpu_first(struct hwt_context *ctx);
+void hwt_cpu_insert(struct hwt_context *ctx, struct hwt_cpu *cpu);
+
+#endif /* !_DEV_HWT_HWT_CPU_H_ */
Index: sys/dev/hwt/hwt_cpu.c
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_cpu.c
@@ -0,0 +1,98 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/hwt.h>
+
+#include <vm/vm.h>
+
+#include <dev/hwt/hwt_hook.h>
+#include <dev/hwt/hwt_context.h>
+#include <dev/hwt/hwt_contexthash.h>
+#include <dev/hwt/hwt_config.h>
+#include <dev/hwt/hwt_thread.h>
+#include <dev/hwt/hwt_record.h>
+#include <dev/hwt/hwt_cpu.h>
+
+#define HWT_CPU_DEBUG
+#undef HWT_CPU_DEBUG
+
+#ifdef HWT_CPU_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+static MALLOC_DEFINE(M_HWT_CPU, "hwt_cpu", "HWT cpu");
+
+struct hwt_cpu *
+hwt_cpu_alloc(void)
+{
+ struct hwt_cpu *cpu;
+
+ cpu = malloc(sizeof(struct hwt_cpu), M_HWT_CPU, M_WAITOK | M_ZERO);
+
+ return (cpu);
+}
+
+void
+hwt_cpu_free(struct hwt_cpu *cpu)
+{
+
+ free(cpu, M_HWT_CPU);
+}
+
+struct hwt_cpu *
+hwt_cpu_first(struct hwt_context *ctx)
+{
+ struct hwt_cpu *cpu;
+
+ HWT_CTX_ASSERT_LOCKED(ctx);
+
+ cpu = TAILQ_FIRST(&ctx->cpus);
+
+ KASSERT(cpu != NULL, ("cpu is NULL"));
+
+ return (cpu);
+}
+
+void
+hwt_cpu_insert(struct hwt_context *ctx, struct hwt_cpu *cpu)
+{
+
+ HWT_CTX_ASSERT_LOCKED(ctx);
+
+ TAILQ_INSERT_TAIL(&ctx->cpus, cpu, next);
+}
Index: sys/dev/hwt/hwt_hook.h
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_hook.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/hwt_record.h>
+
+#ifndef _DEV_HWT_HWT_HOOK_H_
+#define _DEV_HWT_HWT_HOOK_H_
+
+#define HWT_SWITCH_IN 0
+#define HWT_SWITCH_OUT 1
+#define HWT_THREAD_EXIT 2
+#define HWT_THREAD_CREATE 3
+#define HWT_THREAD_SET_NAME 4
+#define HWT_RECORD 5
+#define HWT_MMAP 6
+#define HWT_EXEC 7
+
+#define HWT_CALL_HOOK(td, func, arg) \
+do { \
+ if (hwt_hook != NULL) \
+ (hwt_hook)((td), (func), (arg)); \
+} while (0)
+
+extern void (*hwt_hook)(struct thread *td, int func, void *arg);
+
+void hwt_hook_load(void);
+void hwt_hook_unload(void);
+
+#endif /* !_DEV_HWT_HWT_HOOK_H_ */
Index: sys/dev/hwt/hwt_hook.c
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_hook.c
@@ -0,0 +1,259 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Hardware Trace (HWT) framework. */
+
+#include <sys/param.h>
+#include <sys/eventhandler.h>
+#include <sys/ioccom.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/refcount.h>
+#include <sys/rwlock.h>
+#include <sys/hwt.h>
+
+#include <dev/hwt/hwt_hook.h>
+#include <dev/hwt/hwt_context.h>
+#include <dev/hwt/hwt_contexthash.h>
+#include <dev/hwt/hwt_config.h>
+#include <dev/hwt/hwt_thread.h>
+#include <dev/hwt/hwt_owner.h>
+#include <dev/hwt/hwt_backend.h>
+#include <dev/hwt/hwt_record.h>
+
+#define HWT_DEBUG
+#undef HWT_DEBUG
+
+#ifdef HWT_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+static void
+hwt_switch_in(struct thread *td)
+{
+ struct hwt_context *ctx;
+ struct hwt_thread *thr;
+ struct proc *p;
+ int cpu_id;
+
+ p = td->td_proc;
+
+ cpu_id = PCPU_GET(cpuid);
+
+ ctx = hwt_contexthash_lookup(p);
+ if (ctx == NULL)
+ return;
+
+ if (ctx->state != CTX_STATE_RUNNING) {
+ HWT_CTX_UNLOCK(ctx);
+ return;
+ }
+
+ thr = hwt_thread_lookup(ctx, td);
+ if (thr == NULL) {
+ HWT_CTX_UNLOCK(ctx);
+ return;
+ }
+
+ dprintf("%s: thr %p index %d tid %d on cpu_id %d\n", __func__, thr,
+ thr->thread_id, td->td_tid, cpu_id);
+
+ hwt_backend_configure(ctx, cpu_id, thr->thread_id);
+ hwt_backend_enable(ctx, cpu_id);
+
+ HWT_THR_UNLOCK(thr);
+}
+
+static void
+hwt_switch_out(struct thread *td)
+{
+ struct hwt_context *ctx;
+ struct hwt_thread *thr;
+ struct proc *p;
+ int cpu_id;
+
+ p = td->td_proc;
+
+ cpu_id = PCPU_GET(cpuid);
+
+ ctx = hwt_contexthash_lookup(p);
+ if (ctx == NULL)
+ return;
+
+ if (ctx->state != CTX_STATE_RUNNING) {
+ HWT_CTX_UNLOCK(ctx);
+ return;
+ }
+ thr = hwt_thread_lookup(ctx, td);
+ if (thr == NULL) {
+ HWT_CTX_UNLOCK(ctx);
+ return;
+ }
+
+ dprintf("%s: thr %p index %d tid %d on cpu_id %d\n", __func__, thr,
+ thr->thread_id, td->td_tid, cpu_id);
+
+ hwt_backend_disable(ctx, cpu_id);
+ HWT_THR_UNLOCK(thr);
+}
+
+static void
+hwt_thread_exit(struct thread *td)
+{
+ struct hwt_context *ctx;
+ struct hwt_thread *thr;
+ struct proc *p;
+ int cpu_id;
+
+ p = td->td_proc;
+
+ cpu_id = PCPU_GET(cpuid);
+
+ ctx = hwt_contexthash_lookup(p);
+ if (ctx == NULL)
+ return;
+
+ if (ctx->state != CTX_STATE_RUNNING) {
+ HWT_CTX_UNLOCK(ctx);
+ return;
+ }
+ thr = hwt_thread_lookup(ctx, td);
+ if (thr == NULL) {
+ HWT_CTX_UNLOCK(ctx);
+ return;
+ }
+
+ thr->state = HWT_THREAD_STATE_EXITED;
+
+ dprintf("%s: thr %p index %d tid %d on cpu_id %d\n", __func__, thr,
+ thr->thread_id, td->td_tid, cpu_id);
+
+ hwt_backend_disable(ctx, cpu_id);
+ HWT_THR_UNLOCK(thr);
+}
+
+static void
+hwt_hook_mmap(struct thread *td)
+{
+ struct hwt_context *ctx;
+ struct hwt_thread *thr;
+ struct proc *p;
+ int pause;
+
+ p = td->td_proc;
+
+ ctx = hwt_contexthash_lookup(p);
+ if (ctx == NULL)
+ return;
+
+ /* The ctx state could be any here. */
+
+ pause = ctx->pause_on_mmap ? 1 : 0;
+
+ thr = hwt_thread_lookup(ctx, td);
+ if (thr == NULL) {
+ HWT_CTX_UNLOCK(ctx);
+ return;
+ }
+
+ /*
+ * msleep(9) atomically releases the mtx lock, so take refcount
+ * to ensure that thr is not destroyed.
+ */
+ refcount_acquire(&thr->refcnt);
+
+ if (pause)
+ msleep_spin(thr, &thr->mtx, "hwt-mmap", 0);
+
+ HWT_THR_UNLOCK(thr);
+
+ if (refcount_release(&thr->refcnt))
+ hwt_thread_free(thr);
+}
+
+static void
+hwt_hook_handler(struct thread *td, int func, void *arg)
+{
+ struct proc *p;
+
+ p = td->td_proc;
+ if ((p->p_flag2 & P2_HWT) == 0)
+ return;
+
+ switch (func) {
+ case HWT_SWITCH_IN:
+ hwt_switch_in(td);
+ break;
+ case HWT_SWITCH_OUT:
+ hwt_switch_out(td);
+ break;
+ case HWT_THREAD_CREATE:
+ hwt_thread_create(td);
+ break;
+ case HWT_THREAD_SET_NAME:
+ /* TODO. */
+ break;
+ case HWT_THREAD_EXIT:
+ hwt_thread_exit(td);
+ break;
+ case HWT_EXEC:
+ hwt_record(td, arg);
+ hwt_hook_mmap(td);
+ break;
+ case HWT_MMAP:
+ hwt_record(td, arg);
+ hwt_hook_mmap(td);
+ break;
+ case HWT_RECORD:
+ hwt_record(td, arg);
+ break;
+ };
+}
+
+void
+hwt_hook_load(void)
+{
+
+ hwt_hook = hwt_hook_handler;
+}
+
+void
+hwt_hook_unload(void)
+{
+
+ hwt_hook = NULL;
+}
Index: sys/dev/hwt/hwt_ioctl.h
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_ioctl.h
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_HWT_HWT_IOCTL_H
+#define _DEV_HWT_HWT_IOCTL_H
+
+int hwt_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
+ struct thread *td);
+
+#endif /* !_DEV_HWT_HWT_IOCTL_H */
Index: sys/dev/hwt/hwt_ioctl.c
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_ioctl.c
@@ -0,0 +1,366 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Hardware Trace (HWT) framework. */
+
+#include <sys/param.h>
+#include <sys/eventhandler.h>
+#include <sys/ioccom.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/smp.h>
+#include <sys/hwt.h>
+
+#include <dev/hwt/hwt_hook.h>
+#include <dev/hwt/hwt_context.h>
+#include <dev/hwt/hwt_contexthash.h>
+#include <dev/hwt/hwt_config.h>
+#include <dev/hwt/hwt_cpu.h>
+#include <dev/hwt/hwt_thread.h>
+#include <dev/hwt/hwt_owner.h>
+#include <dev/hwt/hwt_ownerhash.h>
+#include <dev/hwt/hwt_backend.h>
+#include <dev/hwt/hwt_record.h>
+#include <dev/hwt/hwt_ioctl.h>
+#include <dev/hwt/hwt_vm.h>
+
+#define HWT_IOCTL_DEBUG
+#undef HWT_IOCTL_DEBUG
+
+#ifdef HWT_IOCTL_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+/* No real reason for these limitations just sanity checks. */
+#define HWT_MAXBUFSIZE (32UL * 1024 * 1024 * 1024) /* 32 GB */
+
+static MALLOC_DEFINE(M_HWT_IOCTL, "hwt_ioctl", "Hardware Trace");
+
+/*
+ * Check if owner process *o can trace target process *t.
+ */
+
+static int
+hwt_priv_check(struct proc *o, struct proc *t)
+{
+ struct ucred *oc, *tc;
+ int error;
+ int i;
+
+ PROC_LOCK(o);
+ oc = o->p_ucred;
+ crhold(oc);
+ PROC_UNLOCK(o);
+
+ PROC_LOCK_ASSERT(t, MA_OWNED);
+ tc = t->p_ucred;
+ crhold(tc);
+
+ error = 0;
+
+ /*
+ * The effective uid of the HWT owner should match at least one
+ * of the effective / real / saved uids of the target process.
+ */
+
+ if (oc->cr_uid != tc->cr_uid &&
+ oc->cr_uid != tc->cr_svuid &&
+ oc->cr_uid != tc->cr_ruid) {
+ error = EPERM;
+ goto done;
+ }
+
+ /*
+ * Everyone of the target's group ids must be in the owner's
+ * group list.
+ */
+ for (i = 0; i < tc->cr_ngroups; i++)
+ if (!groupmember(tc->cr_groups[i], oc)) {
+ error = EPERM;
+ goto done;
+ }
+
+ /* Check the read and saved GIDs too. */
+ if (!groupmember(tc->cr_rgid, oc) ||
+ !groupmember(tc->cr_svgid, oc)) {
+ error = EPERM;
+ goto done;
+ }
+
+done:
+ crfree(tc);
+ crfree(oc);
+
+ return (error);
+}
+
+static int
+hwt_ioctl_alloc_mode_thread(struct thread *td, struct hwt_owner *ho,
+ struct hwt_backend *backend, struct hwt_alloc *halloc)
+{
+ char path[MAXPATHLEN];
+ struct hwt_context *ctx;
+ struct hwt_thread *thr;
+ struct proc *p;
+ int thread_id;
+ int error;
+
+ /* Check if the owner have this pid configured already. */
+ ctx = hwt_owner_lookup_ctx(ho, halloc->pid);
+ if (ctx)
+ return (EEXIST);
+
+ /* Allocate a new HWT context. */
+ ctx = hwt_ctx_alloc();
+ ctx->bufsize = halloc->bufsize;
+ ctx->pid = halloc->pid;
+ ctx->hwt_backend = backend;
+ ctx->hwt_owner = ho;
+ ctx->mode = HWT_MODE_THREAD;
+
+ error = copyout(&ctx->ident, halloc->ident, sizeof(int));
+ if (error) {
+ hwt_ctx_free(ctx);
+ return (error);
+ }
+
+ thread_id = atomic_fetchadd_int(&ctx->thread_counter, 1);
+
+ /* Allocate first thread and buffers. */
+ sprintf(path, "hwt_%d_%d", ctx->ident, thread_id);
+ error = hwt_thread_alloc(&thr, path, ctx->bufsize);
+ if (error) {
+ hwt_ctx_free(ctx);
+ return (error);
+ }
+ thr->vm->ctx = ctx;
+
+ /* Since we done with malloc, now get the victim proc. */
+ p = pfind(halloc->pid);
+ if (p == NULL) {
+ hwt_thread_free(thr);
+ hwt_ctx_free(ctx);
+ return (ENXIO);
+ }
+
+ /* Ensure we can trace it. */
+ error = hwt_priv_check(td->td_proc, p);
+ if (error) {
+ hwt_thread_free(thr);
+ hwt_ctx_free(ctx);
+ PROC_UNLOCK(p);
+ return (error);
+ }
+ p->p_flag2 |= P2_HWT;
+ thr->td = FIRST_THREAD_IN_PROC(p);
+ ctx->proc = p;
+ PROC_UNLOCK(p);
+
+ /* All good. */
+ thr->ctx = ctx;
+ thr->thread_id = thread_id;
+
+ HWT_CTX_LOCK(ctx);
+ hwt_thread_insert(ctx, thr);
+ HWT_CTX_UNLOCK(ctx);
+
+ error = hwt_backend_init(ctx);
+ if (error) {
+ hwt_thread_free(thr);
+ hwt_ctx_free(ctx);
+ /* TODO: remove P2_HWT from proc, if it is still there. */
+ return (error);
+ }
+
+ /* hwt_owner_insert_ctx? */
+ mtx_lock(&ho->mtx);
+ LIST_INSERT_HEAD(&ho->hwts, ctx, next_hwts);
+ mtx_unlock(&ho->mtx);
+
+ /*
+ * Hooks are now in action after this, but the ctx is not in RUNNING
+ * state.
+ */
+ hwt_contexthash_insert(ctx);
+
+ return (0);
+}
+
+static int
+hwt_ioctl_alloc_mode_cpu(struct thread *td, struct hwt_owner *ho,
+ struct hwt_backend *backend, struct hwt_alloc *halloc)
+{
+ struct hwt_context *ctx;
+ struct hwt_cpu *cpu;
+ struct hwt_vm *vm;
+ char path[MAXPATHLEN];
+ int error;
+ int cpu_id;
+
+ CPU_FOREACH(cpu_id) {
+ if (!CPU_ISSET(cpu_id, &halloc->cpu_map))
+ continue;
+ /* Ensure CPU is not halted. */
+ if (CPU_ISSET(cpu_id, &hlt_cpus_mask))
+ return (ENXIO);
+#if 0
+ /* TODO: Check if the owner have this cpu configured already. */
+ ctx = hwt_owner_lookup_ctx_by_cpu(ho, halloc->cpu);
+ if (ctx)
+ return (EEXIST);
+#endif
+ }
+
+ /* Allocate a new HWT context. */
+ ctx = hwt_ctx_alloc();
+ ctx->bufsize = halloc->bufsize;
+ ctx->hwt_backend = backend;
+ ctx->hwt_owner = ho;
+ ctx->mode = HWT_MODE_CPU;
+ ctx->cpu_map = halloc->cpu_map;
+
+ error = copyout(&ctx->ident, halloc->ident, sizeof(int));
+ if (error) {
+ hwt_ctx_free(ctx);
+ return (error);
+ }
+
+ CPU_FOREACH(cpu_id) {
+ if (!CPU_ISSET(cpu_id, &halloc->cpu_map))
+ continue;
+
+ sprintf(path, "hwt_%d_%d", ctx->ident, cpu_id);
+ error = hwt_vm_alloc(ctx->bufsize, path, &vm);
+ if (error) {
+ /* TODO: remove all allocated cpus. */
+ hwt_ctx_free(ctx);
+ return (error);
+ }
+
+ cpu = hwt_cpu_alloc();
+ cpu->cpu_id = cpu_id;
+ cpu->vm = vm;
+
+ vm->cpu = cpu;
+ vm->ctx = ctx;
+
+ HWT_CTX_LOCK(ctx);
+ hwt_cpu_insert(ctx, cpu);
+ HWT_CTX_UNLOCK(ctx);
+ }
+
+ error = hwt_backend_init(ctx);
+ if (error) {
+ /* TODO: remove all allocated cpus. */
+ hwt_ctx_free(ctx);
+ return (error);
+ }
+
+ /* hwt_owner_insert_ctx? */
+ mtx_lock(&ho->mtx);
+ LIST_INSERT_HEAD(&ho->hwts, ctx, next_hwts);
+ mtx_unlock(&ho->mtx);
+
+ hwt_record_kernel_objects(ctx);
+
+ return (0);
+}
+
+static int
+hwt_ioctl_alloc(struct thread *td, struct hwt_alloc *halloc)
+{
+ char backend_name[HWT_BACKEND_MAXNAMELEN];
+ struct hwt_backend *backend;
+ struct hwt_owner *ho;
+ int error;
+
+ if (halloc->bufsize > HWT_MAXBUFSIZE)
+ return (EINVAL);
+ if (halloc->bufsize % PAGE_SIZE)
+ return (EINVAL);
+ if (halloc->backend_name == NULL)
+ return (EINVAL);
+
+ error = copyinstr(halloc->backend_name, (void *)backend_name,
+ HWT_BACKEND_MAXNAMELEN, NULL);
+ if (error)
+ return (error);
+
+ backend = hwt_backend_lookup(backend_name);
+ if (backend == NULL)
+ return (ENODEV);
+
+ /* First get the owner. */
+ ho = hwt_ownerhash_lookup(td->td_proc);
+ if (ho == NULL) {
+ /* Create a new owner. */
+ ho = hwt_owner_alloc(td->td_proc);
+ if (ho == NULL)
+ return (ENOMEM);
+ hwt_ownerhash_insert(ho);
+ }
+
+ switch (halloc->mode) {
+ case HWT_MODE_THREAD:
+ error = hwt_ioctl_alloc_mode_thread(td, ho, backend, halloc);
+ break;
+ case HWT_MODE_CPU:
+ error = hwt_ioctl_alloc_mode_cpu(td, ho, backend, halloc);
+ break;
+ default:
+ error = ENXIO;
+ };
+
+ return (error);
+}
+
+int
+hwt_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
+ struct thread *td)
+{
+ int error;
+
+ switch (cmd) {
+ case HWT_IOC_ALLOC:
+ /* Allocate HWT context. */
+ error = hwt_ioctl_alloc(td, (struct hwt_alloc *)addr);
+ return (error);
+ default:
+ return (ENXIO);
+ };
+}
Index: sys/dev/hwt/hwt_owner.h
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_owner.h
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_HWT_HWT_OWNER_H_
+#define _DEV_HWT_HWT_OWNER_H_
+
+struct hwt_owner {
+ struct proc *p;
+ struct mtx mtx; /* Protects hwts. */
+ LIST_HEAD(, hwt_context) hwts; /* Owned HWTs. */
+ LIST_ENTRY(hwt_owner) next; /* Entry in hwt owner hash. */
+};
+
+
+struct hwt_context * hwt_owner_lookup_ctx(struct hwt_owner *ho, pid_t pid);
+struct hwt_owner * hwt_owner_alloc(struct proc *p);
+void hwt_owner_shutdown(struct hwt_owner *ho);
+struct hwt_context * hwt_owner_lookup_ctx_by_cpu(struct hwt_owner *ho, int cpu);
+
+#endif /* !_DEV_HWT_HWT_OWNER_H_ */
Index: sys/dev/hwt/hwt_owner.c
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_owner.c
@@ -0,0 +1,218 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/eventhandler.h>
+#include <sys/ioccom.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/refcount.h>
+#include <sys/rwlock.h>
+#include <sys/hwt.h>
+
+#include <dev/hwt/hwt_hook.h>
+#include <dev/hwt/hwt_context.h>
+#include <dev/hwt/hwt_contexthash.h>
+#include <dev/hwt/hwt_config.h>
+#include <dev/hwt/hwt_cpu.h>
+#include <dev/hwt/hwt_thread.h>
+#include <dev/hwt/hwt_owner.h>
+#include <dev/hwt/hwt_ownerhash.h>
+#include <dev/hwt/hwt_backend.h>
+#include <dev/hwt/hwt_vm.h>
+#include <dev/hwt/hwt_record.h>
+
+#define HWT_DEBUG
+#undef HWT_DEBUG
+
+#ifdef HWT_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+static MALLOC_DEFINE(M_HWT_OWNER, "hwt_owner", "Hardware Trace");
+
+struct hwt_context *
+hwt_owner_lookup_ctx(struct hwt_owner *ho, pid_t pid)
+{
+ struct hwt_context *ctx;
+
+ mtx_lock(&ho->mtx);
+ LIST_FOREACH(ctx, &ho->hwts, next_hwts) {
+ if (ctx->pid == pid) {
+ mtx_unlock(&ho->mtx);
+ return (ctx);
+ }
+ }
+ mtx_unlock(&ho->mtx);
+
+ return (NULL);
+}
+
+#if 0
+struct hwt_context *
+hwt_owner_lookup_ctx_by_cpu(struct hwt_owner *ho, int cpu)
+{
+ struct hwt_context *ctx;
+
+ mtx_lock(&ho->mtx);
+ LIST_FOREACH(ctx, &ho->hwts, next_hwts) {
+ if (ctx->cpu == cpu) {
+ mtx_unlock(&ho->mtx);
+ return (ctx);
+ }
+ }
+ mtx_unlock(&ho->mtx);
+
+ return (NULL);
+}
+#endif
+
+struct hwt_owner *
+hwt_owner_alloc(struct proc *p)
+{
+ struct hwt_owner *ho;
+
+ ho = malloc(sizeof(struct hwt_owner), M_HWT_OWNER,
+ M_WAITOK | M_ZERO);
+ ho->p = p;
+
+ LIST_INIT(&ho->hwts);
+ mtx_init(&ho->mtx, "hwts", NULL, MTX_DEF);
+
+ return (ho);
+}
+
+static void
+hwt_owner_free_cpus(struct hwt_context *ctx)
+{
+ struct hwt_cpu *cpu;
+
+ do {
+ HWT_CTX_LOCK(ctx);
+ cpu = TAILQ_FIRST(&ctx->cpus);
+ if (cpu)
+ TAILQ_REMOVE(&ctx->cpus, cpu, next);
+ HWT_CTX_UNLOCK(ctx);
+
+ if (cpu == NULL)
+ break;
+
+ hwt_vm_free(cpu->vm);
+ hwt_cpu_free(cpu);
+ } while (1);
+}
+
+static void
+hwt_owner_free_threads(struct hwt_context *ctx)
+{
+ struct hwt_thread *thr;
+
+ dprintf("%s: remove threads\n", __func__);
+
+ do {
+ HWT_CTX_LOCK(ctx);
+ thr = TAILQ_FIRST(&ctx->threads);
+ if (thr) {
+ TAILQ_REMOVE(&ctx->threads, thr, next);
+ HWT_THR_LOCK(thr);
+ }
+ HWT_CTX_UNLOCK(ctx);
+
+ if (thr == NULL)
+ break;
+
+ wakeup(thr);
+
+ HWT_THR_UNLOCK(thr);
+
+ if (refcount_release(&thr->refcnt))
+ hwt_thread_free(thr);
+ } while (1);
+}
+
+void
+hwt_owner_shutdown(struct hwt_owner *ho)
+{
+ struct hwt_context *ctx;
+ struct hwt_thread *thr;
+
+ dprintf("%s: stopping hwt owner\n", __func__);
+
+ while (1) {
+ mtx_lock(&ho->mtx);
+ ctx = LIST_FIRST(&ho->hwts);
+ if (ctx)
+ LIST_REMOVE(ctx, next_hwts);
+ mtx_unlock(&ho->mtx);
+
+ if (ctx == NULL)
+ break;
+
+ if (ctx->mode == HWT_MODE_THREAD)
+ hwt_contexthash_remove(ctx);
+
+ /*
+ * It could be that a hook has this ctx locked right here.
+ */
+
+ HWT_CTX_LOCK(ctx);
+ ctx->state = 0;
+ /*
+ * Ensure hook invocation is now completed.
+ */
+ TAILQ_FOREACH(thr, &ctx->threads, next) {
+ HWT_THR_LOCK(thr);
+ HWT_THR_UNLOCK(thr);
+ }
+ HWT_CTX_UNLOCK(ctx);
+
+ /* Note that a thread could be still sleeping on msleep_spin. */
+
+ hwt_backend_deinit(ctx);
+
+ if (ctx->mode == HWT_MODE_CPU)
+ hwt_owner_free_cpus(ctx);
+ else
+ hwt_owner_free_threads(ctx);
+
+ hwt_record_free_all(ctx);
+ hwt_ctx_free(ctx);
+ }
+
+ hwt_ownerhash_remove(ho);
+ free(ho, M_HWT_OWNER);
+}
Index: sys/dev/hwt/hwt_ownerhash.h
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_ownerhash.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_HWT_HWT_OWNERHASH_H_
+#define _DEV_HWT_HWT_OWNERHASH_H_
+
+struct hwt_owner * hwt_ownerhash_lookup(struct proc *p);
+void hwt_ownerhash_insert(struct hwt_owner *ho);
+void hwt_ownerhash_remove(struct hwt_owner *ho);
+
+void hwt_ownerhash_load(void);
+void hwt_ownerhash_unload(void);
+
+#define HWT_OWNERHASH_LOCK() mtx_lock_spin(&hwt_ownerhash_mtx)
+#define HWT_OWNERHASH_UNLOCK() mtx_unlock_spin(&hwt_ownerhash_mtx)
+
+#endif /* !_DEV_HWT_HWT_OWNERHASH_H_ */
Index: sys/dev/hwt/hwt_ownerhash.c
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_ownerhash.c
@@ -0,0 +1,147 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/eventhandler.h>
+#include <sys/ioccom.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/hwt.h>
+
+#include <dev/hwt/hwt_owner.h>
+#include <dev/hwt/hwt_ownerhash.h>
+
+#define HWT_DEBUG
+#undef HWT_DEBUG
+
+#ifdef HWT_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+#define HWT_OWNERHASH_SIZE 1024
+
+static MALLOC_DEFINE(M_HWT_OWNERHASH, "hwt_ohash", "Hardware Trace");
+
+/*
+ * Hash function. Discard the lower 2 bits of the pointer since
+ * these are always zero for our uses. The hash multiplier is
+ * round((2^LONG_BIT) * ((sqrt(5)-1)/2)).
+ */
+
+#define _HWT_HM 11400714819323198486u /* hash multiplier */
+#define HWT_HASH_PTR(P, M) ((((unsigned long) (P) >> 2) * _HWT_HM) & (M))
+
+static struct mtx hwt_ownerhash_mtx;
+static u_long hwt_ownerhashmask;
+static LIST_HEAD(hwt_ownerhash, hwt_owner) *hwt_ownerhash;
+
+struct hwt_owner *
+hwt_ownerhash_lookup(struct proc *p)
+{
+ struct hwt_ownerhash *hoh;
+ struct hwt_owner *ho;
+ int hindex;
+
+ hindex = HWT_HASH_PTR(p, hwt_ownerhashmask);
+ hoh = &hwt_ownerhash[hindex];
+
+ HWT_OWNERHASH_LOCK();
+ LIST_FOREACH(ho, hoh, next) {
+ if (ho->p == p) {
+ HWT_OWNERHASH_UNLOCK();
+ return (ho);
+ }
+ }
+ HWT_OWNERHASH_UNLOCK();
+
+ return (NULL);
+}
+
+void
+hwt_ownerhash_insert(struct hwt_owner *ho)
+{
+ struct hwt_ownerhash *hoh;
+ int hindex;
+
+ hindex = HWT_HASH_PTR(ho->p, hwt_ownerhashmask);
+ hoh = &hwt_ownerhash[hindex];
+
+ HWT_OWNERHASH_LOCK();
+ LIST_INSERT_HEAD(hoh, ho, next);
+ HWT_OWNERHASH_UNLOCK();
+}
+
+void
+hwt_ownerhash_remove(struct hwt_owner *ho)
+{
+
+ /* Destroy hwt owner. */
+ HWT_OWNERHASH_LOCK();
+ LIST_REMOVE(ho, next);
+ HWT_OWNERHASH_UNLOCK();
+}
+
+void
+hwt_ownerhash_load(void)
+{
+
+ hwt_ownerhash = hashinit(HWT_OWNERHASH_SIZE, M_HWT_OWNERHASH,
+ &hwt_ownerhashmask);
+ mtx_init(&hwt_ownerhash_mtx, "hwt-owner-hash", "hwt-owner", MTX_SPIN);
+}
+
+void
+hwt_ownerhash_unload(void)
+{
+#if 0
+ struct hwt_ownerhash *hoh;
+ struct hwt_owner *ho, *tmp;
+
+ HWT_OWNERHASH_LOCK();
+ for (hoh = hwt_ownerhash;
+ hoh <= &hwt_ownerhash[hwt_ownerhashmask];
+ hoh++) {
+ LIST_FOREACH_SAFE(ho, hoh, next, tmp) {
+ LIST_REMOVE(ho, next);
+ }
+ }
+ HWT_OWNERHASH_UNLOCK();
+#endif
+ mtx_destroy(&hwt_ownerhash_mtx);
+ hashdestroy(hwt_ownerhash, M_HWT_OWNERHASH, hwt_ownerhashmask);
+}
Index: sys/dev/hwt/hwt_record.h
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_record.h
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_HWT_HWT_RECORD_H_
+#define _DEV_HWT_HWT_RECORD_H_
+
+int hwt_record_send(struct hwt_context *ctx, struct hwt_record_get *record_get);
+void hwt_record(struct thread *td, struct hwt_record_entry *ent);
+
+struct hwt_record_entry * hwt_record_entry_alloc(void);
+void hwt_record_entry_free(struct hwt_record_entry *entry);
+void hwt_record_kernel_objects(struct hwt_context *ctx);
+void hwt_record_free_all(struct hwt_context *ctx);
+
+#endif /* !_DEV_HWT_HWT_RECORD_H_ */
Index: sys/dev/hwt/hwt_record.c
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_record.c
@@ -0,0 +1,213 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/hwt.h>
+#include <sys/linker.h>
+#include <sys/pmckern.h> /* linker_hwpmc_list_objects */
+
+#include <vm/vm.h>
+
+#include <dev/hwt/hwt_hook.h>
+#include <dev/hwt/hwt_context.h>
+#include <dev/hwt/hwt_contexthash.h>
+#include <dev/hwt/hwt_config.h>
+#include <dev/hwt/hwt_thread.h>
+#include <dev/hwt/hwt_record.h>
+
+#define HWT_RECORD_DEBUG
+#undef HWT_RECORD_DEBUG
+
+#ifdef HWT_RECORD_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+static MALLOC_DEFINE(M_HWT_RECORD, "hwt_record", "Hardware Trace");
+
+void
+hwt_record(struct thread *td, struct hwt_record_entry *ent)
+{
+ struct hwt_record_entry *entry;
+ struct hwt_context *ctx;
+ struct proc *p;
+
+ p = td->td_proc;
+
+ KASSERT(ent != NULL, ("ent is NULL"));
+ KASSERT(ent->fullpath != NULL, ("fullpath is NULL"));
+
+ entry = malloc(sizeof(struct hwt_record_entry), M_HWT_RECORD, M_WAITOK);
+ entry->record_type = ent->record_type;
+ entry->thread_id = -1;
+ entry->fullpath = strdup(ent->fullpath, M_HWT_RECORD);
+ entry->addr = ent->addr;
+
+ ctx = hwt_contexthash_lookup(p);
+ if (ctx == NULL) {
+ free(entry->fullpath, M_HWT_RECORD);
+ free(entry, M_HWT_RECORD);
+ return;
+ }
+ LIST_INSERT_HEAD(&ctx->records, entry, next);
+ HWT_CTX_UNLOCK(ctx);
+}
+
+struct hwt_record_entry *
+hwt_record_entry_alloc(void)
+{
+ struct hwt_record_entry *entry;
+
+ entry = malloc(sizeof(struct hwt_record_entry), M_HWT_RECORD,
+ M_WAITOK | M_ZERO);
+
+ return (entry);
+}
+
+void
+hwt_record_entry_free(struct hwt_record_entry *entry)
+{
+
+ free(entry, M_HWT_RECORD);
+}
+
+static int
+hwt_record_grab(struct hwt_context *ctx,
+ struct hwt_record_user_entry *user_entry, int nitems_req)
+{
+ struct hwt_record_entry *entry;
+ int i;
+
+ for (i = 0; i < nitems_req; i++) {
+ HWT_CTX_LOCK(ctx);
+ entry = LIST_FIRST(&ctx->records);
+ if (entry)
+ LIST_REMOVE(entry, next);
+ HWT_CTX_UNLOCK(ctx);
+
+ if (entry == NULL)
+ break;
+
+ user_entry[i].addr = entry->addr;
+ user_entry[i].record_type = entry->record_type;
+ user_entry[i].thread_id = entry->thread_id;
+ if (entry->fullpath != NULL) {
+ strncpy(user_entry[i].fullpath, entry->fullpath,
+ MAXPATHLEN);
+ free(entry->fullpath, M_HWT_RECORD);
+ }
+
+ free(entry, M_HWT_RECORD);
+ }
+
+ return (i);
+}
+
+void
+hwt_record_free_all(struct hwt_context *ctx)
+{
+ struct hwt_record_entry *entry;
+
+ while (1) {
+ HWT_CTX_LOCK(ctx);
+ entry = LIST_FIRST(&ctx->records);
+ if (entry)
+ LIST_REMOVE(entry, next);
+ HWT_CTX_UNLOCK(ctx);
+
+ if (entry == NULL)
+ break;
+
+ if (entry->fullpath != NULL)
+ free(entry->fullpath, M_HWT_RECORD);
+
+ free(entry, M_HWT_RECORD);
+ }
+}
+
+int
+hwt_record_send(struct hwt_context *ctx, struct hwt_record_get *record_get)
+{
+ struct hwt_record_user_entry *user_entry;
+ int nitems_req;
+ int error;
+ int i;
+
+ nitems_req = 0;
+
+ error = copyin(record_get->nentries, &nitems_req, sizeof(int));
+ if (error)
+ return (error);
+
+ if (nitems_req < 1 || nitems_req > 1024)
+ return (ENXIO);
+
+ user_entry = malloc(sizeof(struct hwt_record_user_entry) * nitems_req,
+ M_HWT_RECORD, M_WAITOK | M_ZERO);
+
+ i = hwt_record_grab(ctx, user_entry, nitems_req);
+ if (i > 0)
+ error = copyout(user_entry, record_get->records,
+ sizeof(struct hwt_record_user_entry) * i);
+
+ if (error == 0)
+ error = copyout(&i, record_get->nentries, sizeof(int));
+
+ free(user_entry, M_HWT_RECORD);
+
+ return (error);
+}
+
+void
+hwt_record_kernel_objects(struct hwt_context *ctx)
+{
+ struct hwt_record_entry *entry;
+ struct pmckern_map_in *kobase;
+ int i;
+
+ kobase = linker_hwpmc_list_objects();
+ for (i = 0; kobase[i].pm_file != NULL; i++) {
+ entry = malloc(sizeof(struct hwt_record_entry), M_HWT_RECORD,
+ M_WAITOK);
+ entry->record_type = HWT_RECORD_KERNEL;
+ entry->fullpath = strdup(kobase[i].pm_file, M_HWT_RECORD);
+ entry->addr = kobase[i].pm_address;
+
+ HWT_CTX_LOCK(ctx);
+ LIST_INSERT_HEAD(&ctx->records, entry, next);
+ HWT_CTX_UNLOCK(ctx);
+ }
+ free(kobase, M_LINKER);
+}
Index: sys/dev/hwt/hwt_thread.h
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_thread.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_HWT_HWT_THREAD_H_
+#define _DEV_HWT_HWT_THREAD_H_
+
+struct hwt_thread {
+ struct hwt_vm *vm;
+ struct hwt_context *ctx;
+ struct thread *td;
+ TAILQ_ENTRY(hwt_thread) next;
+ int thread_id;
+ int state;
+#define HWT_THREAD_STATE_EXITED (1 << 0)
+ struct mtx mtx;
+ u_int refcnt;
+ int cpu_id; /* last cpu_id */
+};
+
+/* Thread allocation. */
+int hwt_thread_alloc(struct hwt_thread **thr0, char *path, size_t bufsize);
+int hwt_thread_create(struct thread *td);
+
+/* Thread de-allocation. */
+void hwt_thread_free(struct hwt_thread *thr);
+
+/* Thread list mgt. */
+void hwt_thread_insert(struct hwt_context *ctx, struct hwt_thread *thr);
+struct hwt_thread * hwt_thread_first(struct hwt_context *ctx);
+struct hwt_thread * hwt_thread_lookup(struct hwt_context *ctx,
+ struct thread *td);
+
+#define HWT_THR_LOCK(thr) mtx_lock_spin(&(thr)->mtx)
+#define HWT_THR_UNLOCK(thr) mtx_unlock_spin(&(thr)->mtx)
+#define HWT_THR_ASSERT_LOCKED(thr) mtx_assert(&(thr)->mtx, MA_OWNED)
+
+#endif /* !_DEV_HWT_HWT_THREAD_H_ */
Index: sys/dev/hwt/hwt_thread.c
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_thread.c
@@ -0,0 +1,215 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/eventhandler.h>
+#include <sys/ioccom.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/refcount.h>
+#include <sys/rwlock.h>
+#include <sys/hwt.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_object.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_pageout.h>
+#include <vm/vm_phys.h>
+
+#include <dev/hwt/hwt_hook.h>
+#include <dev/hwt/hwt_context.h>
+#include <dev/hwt/hwt_contexthash.h>
+#include <dev/hwt/hwt_config.h>
+#include <dev/hwt/hwt_thread.h>
+#include <dev/hwt/hwt_owner.h>
+#include <dev/hwt/hwt_ownerhash.h>
+#include <dev/hwt/hwt_backend.h>
+#include <dev/hwt/hwt_vm.h>
+#include <dev/hwt/hwt_record.h>
+
+#define HWT_THREAD_DEBUG
+#undef HWT_THREAD_DEBUG
+
+#ifdef HWT_THREAD_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+static MALLOC_DEFINE(M_HWT_THREAD, "hwt_thread", "Hardware Trace");
+
+struct hwt_thread *
+hwt_thread_first(struct hwt_context *ctx)
+{
+ struct hwt_thread *thr;
+
+ HWT_CTX_ASSERT_LOCKED(ctx);
+
+ thr = TAILQ_FIRST(&ctx->threads);
+
+ KASSERT(thr != NULL, ("thr is NULL"));
+
+ return (thr);
+}
+
+/*
+ * To use by hwt_switch_in/out() only.
+ */
+struct hwt_thread *
+hwt_thread_lookup(struct hwt_context *ctx, struct thread *td)
+{
+ struct hwt_thread *thr;
+
+ HWT_CTX_ASSERT_LOCKED(ctx);
+
+ TAILQ_FOREACH(thr, &ctx->threads, next) {
+ if (thr->td == td) {
+ HWT_THR_LOCK(thr);
+ HWT_CTX_UNLOCK(ctx);
+ return (thr);
+ }
+ }
+
+ /*
+ * We are here because the hook on thread creation failed to allocate
+ * a thread.
+ */
+
+ return (NULL);
+}
+
+int
+hwt_thread_alloc(struct hwt_thread **thr0, char *path, size_t bufsize)
+{
+ struct hwt_thread *thr;
+ struct hwt_vm *vm;
+ int error;
+
+ error = hwt_vm_alloc(bufsize, path, &vm);
+ if (error)
+ return (error);
+
+ thr = malloc(sizeof(struct hwt_thread), M_HWT_THREAD,
+ M_WAITOK | M_ZERO);
+ thr->vm = vm;
+
+ mtx_init(&thr->mtx, "thr", NULL, MTX_SPIN);
+
+ refcount_init(&thr->refcnt, 1);
+
+ vm->thr = thr;
+
+ *thr0 = thr;
+
+ return (0);
+}
+
+void
+hwt_thread_free(struct hwt_thread *thr)
+{
+
+ hwt_vm_free(thr->vm);
+
+ free(thr, M_HWT_THREAD);
+}
+
+void
+hwt_thread_insert(struct hwt_context *ctx, struct hwt_thread *thr)
+{
+
+ HWT_CTX_ASSERT_LOCKED(ctx);
+
+ TAILQ_INSERT_TAIL(&ctx->threads, thr, next);
+}
+
+/*
+ * This is called by hooks only.
+ * TODO: Move to hwt_hook.c ?
+ */
+int
+hwt_thread_create(struct thread *td)
+{
+ struct hwt_record_entry *entry;
+ struct hwt_context *ctx;
+ struct hwt_thread *thr;
+ struct proc *p;
+ size_t bufsize;
+ char path[MAXPATHLEN];
+ int error;
+ int thread_id;
+
+ p = td->td_proc;
+
+ /* 1. First find our ctx and collect some information from it. */
+ ctx = hwt_contexthash_lookup(p);
+ if (ctx == NULL)
+ return (ENXIO);
+ bufsize = ctx->bufsize;
+ thread_id = atomic_fetchadd_int(&ctx->thread_counter, 1);
+ sprintf(path, "hwt_%d_%d", ctx->ident, thread_id);
+ HWT_CTX_UNLOCK(ctx);
+
+ /* 2. Now we can allocate some memory. */
+ error = hwt_thread_alloc(&thr, path, bufsize);
+ if (error) {
+ printf("%s: could not allocate thread, error %d\n",
+ __func__, error);
+ return (error);
+ }
+
+ entry = hwt_record_entry_alloc();
+ entry->record_type = HWT_RECORD_THREAD_CREATE;
+ entry->thread_id = thread_id;
+
+ /* 3. Take ctx again, as it may gone during previous step. */
+ ctx = hwt_contexthash_lookup(p);
+ if (ctx == NULL) {
+ hwt_record_entry_free(entry);
+ hwt_thread_free(thr);
+ return (ENXIO);
+ }
+ thr->vm->ctx = ctx;
+ thr->ctx = ctx;
+ thr->thread_id = thread_id;
+ thr->td = td;
+ TAILQ_INSERT_TAIL(&ctx->threads, thr, next);
+ LIST_INSERT_HEAD(&ctx->records, entry, next);
+ HWT_CTX_UNLOCK(ctx);
+
+ return (0);
+}
Index: sys/dev/hwt/hwt_vm.h
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_vm.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_HWT_HWT_VM_H_
+#define _DEV_HWT_HWT_VM_H_
+
+struct hwt_vm {
+ vm_page_t *pages;
+ int npages;
+ vm_object_t obj;
+ struct cdev *cdev;
+
+ struct hwt_context *ctx;
+ struct hwt_cpu *cpu; /* cpu mode only. */
+ struct hwt_thread *thr; /* thr mode only. */
+};
+
+int hwt_vm_alloc(size_t bufsize, char *path, struct hwt_vm **vm0);
+void hwt_vm_free(struct hwt_vm *vm);
+
+#endif /* !_DEV_HWT_HWT_VM_H_ */
Index: sys/dev/hwt/hwt_vm.c
===================================================================
--- /dev/null
+++ sys/dev/hwt/hwt_vm.c
@@ -0,0 +1,418 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/eventhandler.h>
+#include <sys/ioccom.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/refcount.h>
+#include <sys/rwlock.h>
+#include <sys/hwt.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_object.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_pageout.h>
+#include <vm/vm_phys.h>
+
+#include <dev/hwt/hwt_hook.h>
+#include <dev/hwt/hwt_context.h>
+#include <dev/hwt/hwt_contexthash.h>
+#include <dev/hwt/hwt_config.h>
+#include <dev/hwt/hwt_cpu.h>
+#include <dev/hwt/hwt_owner.h>
+#include <dev/hwt/hwt_ownerhash.h>
+#include <dev/hwt/hwt_thread.h>
+#include <dev/hwt/hwt_backend.h>
+#include <dev/hwt/hwt_vm.h>
+#include <dev/hwt/hwt_record.h>
+
+#define HWT_THREAD_DEBUG
+#undef HWT_THREAD_DEBUG
+
+#ifdef HWT_THREAD_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
+static MALLOC_DEFINE(M_HWT_VM, "hwt_vm", "Hardware Trace");
+
+static int
+hwt_vm_fault(vm_object_t vm_obj, vm_ooffset_t offset,
+ int prot, vm_page_t *mres)
+{
+
+ return (0);
+}
+
+static int
+hwt_vm_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot,
+ vm_ooffset_t foff, struct ucred *cred, u_short *color)
+{
+
+ *color = 0;
+
+ return (0);
+}
+
+static void
+hwt_vm_dtor(void *handle)
+{
+
+}
+
+static struct cdev_pager_ops hwt_vm_pager_ops = {
+ .cdev_pg_fault = hwt_vm_fault,
+ .cdev_pg_ctor = hwt_vm_ctor,
+ .cdev_pg_dtor = hwt_vm_dtor
+};
+
+static int
+hwt_vm_alloc_pages(struct hwt_vm *vm)
+{
+ vm_paddr_t low, high, boundary;
+ vm_memattr_t memattr;
+ vm_pointer_t va;
+ int alignment;
+ vm_page_t m;
+ int pflags;
+ int tries;
+ int i;
+
+ alignment = PAGE_SIZE;
+ low = 0;
+ high = -1UL;
+ boundary = 0;
+ pflags = VM_ALLOC_NORMAL | VM_ALLOC_NOBUSY | VM_ALLOC_WIRED |
+ VM_ALLOC_ZERO;
+ memattr = VM_MEMATTR_DEVICE;
+
+ vm->obj = cdev_pager_allocate(vm, OBJT_MGTDEVICE,
+ &hwt_vm_pager_ops, vm->npages * PAGE_SIZE, PROT_READ, 0,
+ curthread->td_ucred);
+
+ for (i = 0; i < vm->npages; i++) {
+ tries = 0;
+retry:
+ m = vm_page_alloc_noobj_contig(pflags, 1, low, high,
+ alignment, boundary, memattr);
+ if (m == NULL) {
+ if (tries < 3) {
+ if (!vm_page_reclaim_contig(pflags, 1, low,
+ high, alignment, boundary))
+ vm_wait(NULL);
+ tries++;
+ goto retry;
+ }
+
+ return (ENOMEM);
+ }
+
+#if 0
+ /* TODO: could not clean device memory on arm64. */
+ if ((m->flags & PG_ZERO) == 0)
+ pmap_zero_page(m);
+#endif
+
+ va = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m));
+ cpu_dcache_wb_range(va, PAGE_SIZE);
+
+ m->valid = VM_PAGE_BITS_ALL;
+ m->oflags &= ~VPO_UNMANAGED;
+ m->flags |= PG_FICTITIOUS;
+ vm->pages[i] = m;
+
+ VM_OBJECT_WLOCK(vm->obj);
+ vm_page_insert(m, vm->obj, i);
+ VM_OBJECT_WUNLOCK(vm->obj);
+ }
+
+ return (0);
+}
+
+static int
+hwt_vm_open(struct cdev *cdev, int oflags, int devtype, struct thread *td)
+{
+
+ dprintf("%s\n", __func__);
+
+ return (0);
+}
+
+static int
+hwt_vm_mmap_single(struct cdev *cdev, vm_ooffset_t *offset,
+ vm_size_t mapsize, struct vm_object **objp, int nprot)
+{
+ struct hwt_vm *vm;
+
+ vm = cdev->si_drv1;
+
+ if (nprot != PROT_READ || *offset != 0)
+ return (ENXIO);
+
+ *objp = vm->obj;
+
+ return (0);
+}
+
+static int
+hwt_vm_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
+ struct thread *td)
+{
+ struct hwt_record_get *rget;
+ struct hwt_set_config *sconf;
+ struct hwt_bufptr_get *ptr_get;
+
+ struct hwt_context *ctx;
+ struct hwt_vm *vm;
+ struct hwt_owner *ho;
+ struct hwt_cpu *cpu;
+
+ vm_offset_t curpage_offset;
+ int cpu_id;
+ int curpage;
+ int error;
+
+ vm = dev->si_drv1;
+ KASSERT(vm != NULL, ("si_drv1 is NULL"));
+
+ ctx = vm->ctx;
+
+ /* Ensure process is registered owner of this HWT. */
+ ho = hwt_ownerhash_lookup(td->td_proc);
+ if (ho == NULL)
+ return (ENXIO);
+
+ if (ctx->hwt_owner != ho)
+ return (EPERM);
+
+ switch (cmd) {
+ case HWT_IOC_START:
+ /* Start tracing. */
+ dprintf("%s: start\n", __func__);
+
+ HWT_CTX_LOCK(ctx);
+ if (ctx->state == CTX_STATE_RUNNING) {
+ /* Already running ? */
+ HWT_CTX_UNLOCK(ctx);
+ return (ENXIO);
+ }
+ ctx->state = CTX_STATE_RUNNING;
+ HWT_CTX_UNLOCK(ctx);
+
+ if (ctx->mode == HWT_MODE_CPU) {
+ cpu = vm->cpu;
+ hwt_backend_configure(ctx, cpu->cpu_id, cpu->cpu_id);
+ hwt_backend_enable(ctx, cpu->cpu_id);
+ } else {
+ /*
+ * Tracing backend will be configured and enabled
+ * during hook invocation. See hwt_hook.c.
+ */
+ }
+
+ break;
+
+ case HWT_IOC_STOP:
+ /* TODO */
+ break;
+
+ case HWT_IOC_RECORD_GET:
+ rget = (struct hwt_record_get *)addr;
+ error = hwt_record_send(ctx, rget);
+ if (error)
+ return (error);
+ break;
+
+ case HWT_IOC_SET_CONFIG:
+ sconf = (struct hwt_set_config *)addr;
+ error = hwt_config_set(td, ctx, sconf);
+ if (error)
+ return (error);
+ ctx->pause_on_mmap = sconf->pause_on_mmap ? 1 : 0;
+ break;
+
+ case HWT_IOC_WAKEUP:
+
+ if (ctx->mode == HWT_MODE_CPU)
+ return (ENXIO);
+
+ KASSERT(vm->thr != NULL, ("thr is NULL"));
+
+ wakeup(vm->thr);
+
+ break;
+
+ case HWT_IOC_BUFPTR_GET:
+ ptr_get = (struct hwt_bufptr_get *)addr;
+
+ if (ctx->mode == HWT_MODE_THREAD)
+ cpu_id = vm->thr->cpu_id;
+ else
+ cpu_id = vm->cpu->cpu_id;
+
+ error = hwt_backend_read(ctx, cpu_id, &curpage,
+ &curpage_offset);
+ if (error)
+ return (error);
+
+ error = copyout(&curpage, ptr_get->curpage, sizeof(int));
+ if (error)
+ return (error);
+ error = copyout(&curpage_offset, ptr_get->curpage_offset,
+ sizeof(vm_offset_t));
+ if (error)
+ return (error);
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+static struct cdevsw hwt_vm_cdevsw = {
+ .d_version = D_VERSION,
+ .d_name = "hwt",
+ .d_open = hwt_vm_open,
+ .d_mmap_single = hwt_vm_mmap_single,
+ .d_ioctl = hwt_vm_ioctl,
+};
+
+static int
+hwt_vm_create_cdev(struct hwt_vm *vm, char *path)
+{
+ struct make_dev_args args;
+ int error;
+
+ dprintf("%s: path %s\n", __func__, path);
+
+ make_dev_args_init(&args);
+ args.mda_devsw = &hwt_vm_cdevsw;
+ args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK;
+ args.mda_uid = UID_ROOT;
+ args.mda_gid = GID_WHEEL;
+ args.mda_mode = 0660;
+ args.mda_si_drv1 = vm;
+
+ error = make_dev_s(&args, &vm->cdev, "%s", path);
+ if (error != 0)
+ return (error);
+
+ return (0);
+}
+
+static int
+hwt_vm_alloc_buffers(struct hwt_vm *vm)
+{
+ int error;
+
+ vm->pages = malloc(sizeof(struct vm_page *) * vm->npages,
+ M_HWT_VM, M_WAITOK | M_ZERO);
+
+ error = hwt_vm_alloc_pages(vm);
+ if (error) {
+ printf("%s: could not alloc pages\n", __func__);
+ return (error);
+ }
+
+ return (0);
+}
+
+static void
+hwt_vm_destroy_buffers(struct hwt_vm *vm)
+{
+ vm_page_t m;
+ int i;
+
+ VM_OBJECT_WLOCK(vm->obj);
+ for (i = 0; i < vm->npages; i++) {
+ m = vm->pages[i];
+ if (m == NULL)
+ break;
+
+ vm_page_busy_acquire(m, 0);
+ cdev_pager_free_page(vm->obj, m);
+ m->flags &= ~PG_FICTITIOUS;
+ vm_page_unwire_noq(m);
+ vm_page_free(m);
+
+ }
+ vm_pager_deallocate(vm->obj);
+ VM_OBJECT_WUNLOCK(vm->obj);
+
+ free(vm->pages, M_HWT_VM);
+}
+
+void
+hwt_vm_free(struct hwt_vm *vm)
+{
+
+ if (vm->cdev)
+ destroy_dev_sched(vm->cdev);
+ hwt_vm_destroy_buffers(vm);
+ free(vm, M_HWT_VM);
+}
+
+int
+hwt_vm_alloc(size_t bufsize, char *path, struct hwt_vm **vm0)
+{
+ struct hwt_vm *vm;
+ int error;
+
+ vm = malloc(sizeof(struct hwt_vm), M_HWT_VM, M_WAITOK | M_ZERO);
+ vm->npages = bufsize / PAGE_SIZE;
+
+ error = hwt_vm_alloc_buffers(vm);
+ if (error) {
+ free(vm, M_HWT_VM);
+ return (error);
+ }
+
+ error = hwt_vm_create_cdev(vm, path);
+ if (error) {
+ hwt_vm_free(vm);
+ return (error);
+ }
+
+ *vm0 = vm;
+
+ return (0);
+}
Index: sys/kern/imgact_elf.c
===================================================================
--- sys/kern/imgact_elf.c
+++ sys/kern/imgact_elf.c
@@ -35,6 +35,7 @@
__FBSDID("$FreeBSD$");
#include "opt_capsicum.h"
+#include "opt_hwt_hooks.h"
#include <sys/param.h>
#include <sys/capsicum.h>
@@ -84,6 +85,10 @@
#include <vm/vm_object.h>
#include <vm/vm_extern.h>
+#ifdef HWT_HOOKS
+#include <dev/hwt/hwt_hook.h>
+#endif
+
#if __has_feature(capabilities)
#include <cheri/cheri.h>
#endif
@@ -1603,6 +1608,17 @@
imgp->interp_start = 0;
imgp->interp_end = 0;
+#ifdef HWT_HOOKS
+ /* HWT: record main binary. */
+ struct hwt_record_entry ent;
+ if (td->td_proc->p_flag2 & P2_HWT) {
+ ent.fullpath = imgp->execpath;
+ ent.addr = (uintptr_t)entry;
+ ent.record_type = HWT_RECORD_EXECUTABLE;
+ HWT_CALL_HOOK(td, HWT_EXEC, &ent);
+ }
+#endif
+
if (interp != NULL) {
VOP_UNLOCK(imgp->vp);
if ((map->flags & MAP_ASLR) != 0) {
@@ -1618,6 +1634,17 @@
vn_lock(imgp->vp, LK_SHARED | LK_RETRY);
if (error != 0)
goto ret;
+
+#ifdef HWT_HOOKS
+ /* HWT: Record interp. */
+ struct hwt_record_entry ent;
+ if (td->td_proc->p_flag2 & P2_HWT) {
+ ent.fullpath = interp;
+ ent.addr = (uintptr_t)imgp->entry_addr;
+ ent.record_type = HWT_RECORD_INTERP;
+ HWT_CALL_HOOK(td, HWT_EXEC, &ent);
+ }
+#endif
} else
addr = imgp->et_dyn_addr;
Index: sys/kern/kern_hwt.c
===================================================================
--- /dev/null
+++ sys/kern/kern_hwt.c
@@ -0,0 +1,46 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/eventhandler.h>
+#include <sys/ioccom.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mman.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/hwt.h>
+
+#include <dev/hwt/hwt_hook.h>
+
+void __read_mostly (*hwt_hook)(struct thread *td, int func, void *arg) = NULL;
Index: sys/kern/kern_linker.c
===================================================================
--- sys/kern/kern_linker.c
+++ sys/kern/kern_linker.c
@@ -32,6 +32,7 @@
#include "opt_ddb.h"
#include "opt_kld.h"
#include "opt_hwpmc_hooks.h"
+#include "opt_hwt_hooks.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -66,7 +67,7 @@
#include "linker_if.h"
-#ifdef HWPMC_HOOKS
+#if defined(HWPMC_HOOKS) || defined(HWT_HOOKS)
#include <sys/pmckern.h>
#endif
@@ -2131,7 +2132,7 @@
return (filename);
}
-#ifdef HWPMC_HOOKS
+#if defined(HWPMC_HOOKS) || defined(HWT_HOOKS)
/*
* Inform hwpmc about the set of kernel modules currently loaded.
*/
Index: sys/kern/kern_thr.c
===================================================================
--- sys/kern/kern_thr.c
+++ sys/kern/kern_thr.c
@@ -31,6 +31,7 @@
#include "opt_posix.h"
#include "opt_hwpmc_hooks.h"
+#include "opt_hwt_hooks.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/lock.h>
@@ -59,6 +60,9 @@
#ifdef HWPMC_HOOKS
#include <sys/pmckern.h>
#endif
+#ifdef HWT_HOOKS
+#include <dev/hwt/hwt_hook.h>
+#endif
#include <machine/frame.h>
@@ -269,6 +273,10 @@
PMC_CALL_HOOK_UNLOCKED(newtd, PMC_FN_THR_CREATE_LOG, NULL);
#endif
+#ifdef HWT_HOOKS
+ HWT_CALL_HOOK(newtd, HWT_THREAD_CREATE, NULL);
+#endif
+
tidhash_add(newtd);
/* ignore timesharing class */
@@ -611,6 +619,9 @@
if (PMC_PROC_IS_USING_PMCS(p) || PMC_SYSTEM_SAMPLING_ACTIVE())
PMC_CALL_HOOK_UNLOCKED(ttd, PMC_FN_THR_CREATE_LOG, NULL);
#endif
+#ifdef HWT_HOOKS
+ HWT_CALL_HOOK(ttd, HWT_THREAD_SET_NAME, NULL);
+#endif
#ifdef KTR
sched_clear_tdname(ttd);
#endif
Index: sys/kern/kern_thread.c
===================================================================
--- sys/kern/kern_thread.c
+++ sys/kern/kern_thread.c
@@ -30,6 +30,7 @@
#include "opt_witness.h"
#include "opt_hwpmc_hooks.h"
+#include "opt_hwt_hooks.h"
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -63,6 +64,9 @@
#ifdef HWPMC_HOOKS
#include <sys/pmckern.h>
#endif
+#ifdef HWT_HOOKS
+#include <dev/hwt/hwt_hook.h>
+#endif
#include <sys/priv.h>
#include <security/audit/audit.h>
@@ -971,6 +975,11 @@
} else if (PMC_SYSTEM_SAMPLING_ACTIVE())
PMC_CALL_HOOK_UNLOCKED(td, PMC_FN_THR_EXIT_LOG, NULL);
#endif
+
+#ifdef HWT_HOOKS
+ HWT_CALL_HOOK(td, HWT_THREAD_EXIT, NULL);
+#endif
+
PROC_UNLOCK(p);
PROC_STATLOCK(p);
thread_lock(td);
Index: sys/kern/sched_ule.c
===================================================================
--- sys/kern/sched_ule.c
+++ sys/kern/sched_ule.c
@@ -41,6 +41,7 @@
__FBSDID("$FreeBSD$");
#include "opt_hwpmc_hooks.h"
+#include "opt_hwt_hooks.h"
#include "opt_sched.h"
#include <sys/param.h>
@@ -70,6 +71,10 @@
#include <sys/pmckern.h>
#endif
+#ifdef HWT_HOOKS
+#include <dev/hwt/hwt_hook.h>
+#endif
+
#ifdef KDTRACE_HOOKS
#include <sys/dtrace_bsd.h>
int __read_mostly dtrace_vtime_active;
@@ -2294,6 +2299,12 @@
if (dtrace_vtime_active)
(*dtrace_vtime_switch_func)(newtd);
#endif
+
+#ifdef HWT_HOOKS
+ HWT_CALL_HOOK(td, HWT_SWITCH_OUT, NULL);
+ HWT_CALL_HOOK(newtd, HWT_SWITCH_IN, NULL);
+#endif
+
td->td_oncpu = NOCPU;
cpu_switch(td, newtd, mtx);
cpuid = td->td_oncpu = PCPU_GET(cpuid);
@@ -3123,6 +3134,10 @@
newtd = sched_throw_grab(tdq);
+#ifdef HWT_HOOKS
+ HWT_CALL_HOOK(newtd, HWT_SWITCH_IN, NULL);
+#endif
+
/* doesn't return */
cpu_throw(NULL, newtd);
}
@@ -3149,6 +3164,10 @@
newtd = sched_throw_grab(tdq);
+#ifdef HWT_HOOKS
+ HWT_CALL_HOOK(newtd, HWT_SWITCH_IN, NULL);
+#endif
+
/* doesn't return */
cpu_switch(td, newtd, TDQ_LOCKPTR(tdq));
}
Index: sys/kern/vfs_vnops.c
===================================================================
--- sys/kern/vfs_vnops.c
+++ sys/kern/vfs_vnops.c
@@ -46,6 +46,7 @@
__FBSDID("$FreeBSD$");
#include "opt_hwpmc_hooks.h"
+#include "opt_hwt_hooks.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -97,6 +98,10 @@
#include <sys/pmckern.h>
#endif
+#ifdef HWT_HOOKS
+#include <dev/hwt/hwt_hook.h>
+#endif
+
static fo_rdwr_t vn_read;
static fo_rdwr_t vn_write;
static fo_rdwr_t vn_io_fault;
@@ -2922,6 +2927,25 @@
}
}
#endif
+
+#ifdef HWT_HOOKS
+ /* HWT: record dynamic libs. */
+ struct hwt_record_entry ent;
+ char *fullpath;
+ char *freepath;
+
+ if ((prot & VM_PROT_EXECUTE) != 0 && error == 0) {
+ if (vn_fullpath(vp, &fullpath, &freepath) == 0) {
+ ent.fullpath = fullpath;
+ ent.addr = (uintptr_t) *addr;
+ ent.record_type = HWT_RECORD_MMAP;
+ HWT_CALL_HOOK(td, HWT_MMAP, &ent);
+ if (freepath != NULL)
+ free(freepath, M_TEMP);
+ }
+ }
+#endif
+
return (error);
}
Index: sys/modules/hwt/Makefile
===================================================================
--- /dev/null
+++ sys/modules/hwt/Makefile
@@ -0,0 +1,23 @@
+# $FreeBSD$
+
+.PATH: ${SRCTOP}/sys/dev/hwt
+
+KMOD = hwt
+SRCS = \
+ hwt.c \
+ hwt_backend.c \
+ hwt_config.c \
+ hwt_context.c \
+ hwt_contexthash.c \
+ hwt_cpu.c \
+ hwt_hook.c \
+ hwt_ioctl.c \
+ hwt_owner.c \
+ hwt_ownerhash.c \
+ hwt_record.c \
+ hwt_thread.c \
+ hwt_vm.c
+
+# EXPORT_SYMS= hwt_backend_register
+
+.include <bsd.kmod.mk>
Index: sys/sys/hwt.h
===================================================================
--- /dev/null
+++ sys/sys/hwt.h
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/* User-visible header. */
+
+#include <sys/param.h>
+#include <sys/cpuset.h>
+#include <sys/types.h>
+#include <sys/hwt_record.h>
+
+#ifndef _SYS_HWT_H_
+#define _SYS_HWT_H_
+
+#define HWT_MAGIC 0x42
+#define HWT_IOC_ALLOC _IOW(HWT_MAGIC, 0x00, struct hwt_alloc)
+#define HWT_IOC_START _IOW(HWT_MAGIC, 0x01, struct hwt_start)
+#define HWT_IOC_STOP _IOW(HWT_MAGIC, 0x02, struct hwt_stop)
+#define HWT_IOC_RECORD_GET _IOW(HWT_MAGIC, 0x03, struct hwt_record_get)
+#define HWT_IOC_BUFPTR_GET _IOW(HWT_MAGIC, 0x04, struct hwt_bufptr_get)
+#define HWT_IOC_SET_CONFIG _IOW(HWT_MAGIC, 0x05, struct hwt_set_config)
+#define HWT_IOC_WAKEUP _IOW(HWT_MAGIC, 0x06, struct hwt_wakeup)
+
+#define HWT_BACKEND_MAXNAMELEN 256
+
+#define HWT_MODE_THREAD 1
+#define HWT_MODE_CPU 2
+
+struct hwt_alloc {
+ size_t bufsize;
+ int mode;
+ pid_t pid; /* thread mode */
+ cpuset_t cpu_map; /* cpu mode only */
+ const char *backend_name;
+ int *ident;
+} __aligned(16);
+
+struct hwt_start {
+ int reserved;
+} __aligned(16);
+
+struct hwt_stop {
+ int reserved;
+} __aligned(16);
+
+struct hwt_wakeup {
+ int reserved;
+} __aligned(16);
+
+struct hwt_record_user_entry {
+ enum hwt_record_type record_type;
+ char fullpath[MAXPATHLEN];
+ uintptr_t addr;
+ int thread_id;
+} __aligned(16);
+
+struct hwt_record_get {
+ struct hwt_record_user_entry *records;
+ int *nentries;
+} __aligned(16);
+
+struct hwt_bufptr_get {
+ int *curpage;
+ vm_offset_t *curpage_offset;
+} __aligned(16);
+
+struct hwt_set_config {
+ /* Configuration of ctx. */
+ int pause_on_mmap;
+
+ /* The following passed to backend as is. */
+ void *config;
+ size_t config_size;
+ int config_version;
+} __aligned(16);
+
+#endif /* !_SYS_HWT_H_ */
Index: sys/sys/hwt_record.h
===================================================================
--- /dev/null
+++ sys/sys/hwt_record.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2023 Ruslan Bukin <br@bsdpad.com>
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/* User-visible header. */
+
+#ifndef _SYS_HWT_RECORD_H_
+#define _SYS_HWT_RECORD_H_
+
+enum hwt_record_type {
+ HWT_RECORD_MMAP,
+ HWT_RECORD_MUNMAP,
+ HWT_RECORD_EXECUTABLE,
+ HWT_RECORD_INTERP,
+ HWT_RECORD_THREAD_CREATE,
+ HWT_RECORD_THREAD_SET_NAME,
+ HWT_RECORD_KERNEL,
+};
+
+#ifdef _KERNEL
+struct hwt_record_entry {
+ enum hwt_record_type record_type;
+ LIST_ENTRY(hwt_record_entry) next;
+ char *fullpath;
+ int thread_id;
+ uintptr_t addr;
+};
+#endif
+
+#endif /* !_SYS_HWT_RECORD_H_ */
Index: sys/sys/proc.h
===================================================================
--- sys/sys/proc.h
+++ sys/sys/proc.h
@@ -886,6 +886,7 @@
#define P2_WEXIT 0x00040000 /* exit just started, no
external thread_single() is
permitted */
+#define P2_HWT 0x00080000 /* Process is using HWT. */
/* Flags protected by proctree_lock, kept in p_treeflags. */
#define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */
Index: sys/vm/vm_mmap.c
===================================================================
--- sys/vm/vm_mmap.c
+++ sys/vm/vm_mmap.c
@@ -110,6 +110,10 @@
#include <sys/pmckern.h>
#endif
+#ifdef HWT_HOOKS
+#include <dev/hwt/hwt_hook.h>
+#endif
+
#if __has_feature(capabilities)
#include <cheri/cheric.h>
#endif
@@ -1054,6 +1058,16 @@
#endif
rv = vm_map_remove_locked(map, addr, addr + size);
+#ifdef HWT_HOOKS
+ struct hwt_record_entry ent;
+ if (rv == KERN_SUCCESS) {
+ ent.addr = (uintptr_t) addr;
+ ent.size = (size_t) size;
+ ent.record_type = HWT_RECORD_MUNMAP;
+ HWT_CALL_HOOK(td, HWT_RECORD, &ent);
+ }
+#endif
+
#ifdef HWPMC_HOOKS
if (rv == KERN_SUCCESS && __predict_false(pmc_handled)) {
/* downgrade the lock to prevent a LOR with the pmc-sx lock */

File Metadata

Mime Type
text/plain
Expires
Wed, Nov 6, 11:23 PM (19 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14501728
Default Alt Text
D40466.id125360.diff (115 KB)

Event Timeline