[RFC PATCH 1/6] x86: Introduce basic PKRU hardware wrappers

Jacky Li <[email protected]>
Newsgroups gmane.comp.emulators.kvm.devel,gmane.comp.emulators.qemu
Message-ID <[email protected]>
Introduce basic hardware instruction wrappers and helper functions for
interacting with x86 Protection Keys for Userspace (PKRU / MPK) in QEMU.

Signed-off-by: Jacky Li <[email protected]>
---
 MAINTAINERS |  1 +
 util/pkey.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index b51f5c3e60..5a31c45963 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -156,6 +156,7 @@ F: target/i386/meson.build
 F: tools/i386/
 F: tests/functional/i386/
 F: tests/functional/x86_64/
+F: util/pkey.c
 
 X86 VM file descriptor change on reset test
 M: Ani Sinha <[email protected]>
diff --git a/util/pkey.c b/util/pkey.c
new file mode 100644
index 0000000000..4f14a72151
--- /dev/null
+++ b/util/pkey.c
@@ -0,0 +1,96 @@
+/*
+ * QEMU guest memory protection key helpers
+ *
+ * Copyright (c) 2026 Google LLC
+ *
+ * Author:
+ *  Jacky Li <[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "exec/cpu-common.h"
+#include "qemu/error-report.h"
+
+#if defined(HOST_X86_64) && defined(CONFIG_LINUX)
+#include <asm/unistd.h>
+#include <cpuid.h>
+#include <immintrin.h>
+#include <linux/kvm.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+
+#include "qemu/atomic.h"
+
+#ifndef PR_SET_SPECULATION_CTRL
+#define PR_SET_SPECULATION_CTRL 53
+#endif
+#ifndef PR_SPEC_INDIRECT_BRANCH
+#define PR_SPEC_INDIRECT_BRANCH 1
+#endif
+#ifndef PR_SPEC_DISABLE
+#define PR_SPEC_DISABLE (1UL << 2)
+#endif
+
+#ifndef PKEY_DISABLE_ACCESS
+#define PKEY_DISABLE_ACCESS 0x1
+#endif
+
+/* Each protection key occupies exactly 2 bits in the PKRU register. */
+#define BITS_PER_KEY 2
+/* The mask used to extract/write the 2-bit permission flags. */
+#define KEY_MASK 3U
+/* Max protection keys supported on x86_64 */
+#define KEY_COUNT 16
+
+static inline __attribute__((target("pku"), always_inline))
+uint32_t rdpkru(void)
+{
+    return _rdpkru_u32();
+}
+
+static inline __attribute__((target("pku"), always_inline)) void wrpkru(
+        uint32_t pkru)
+{
+    _wrpkru(pkru);
+}
+
+static inline __attribute__((target("pku"), always_inline)) int inline_pkey_get(
+        int pkey)
+{
+    uint32_t pkru = rdpkru();
+    return (pkru >> (pkey * BITS_PER_KEY)) & KEY_MASK;
+}
+
+static inline __attribute__((target("pku"), always_inline)) void
+inline_pkey_set(int pkey, unsigned int access_rights)
+{
+    uint32_t pkru = rdpkru();
+    pkru &= ~(KEY_MASK << (pkey * BITS_PER_KEY));
+    pkru |= ((access_rights & KEY_MASK) << (pkey * BITS_PER_KEY));
+    wrpkru(pkru);
+}
+
+static inline __attribute__((always_inline)) intptr_t local_syscall3(
+        intptr_t num, intptr_t arg1, intptr_t arg2, intptr_t arg3)
+{
+    intptr_t ret = num;
+    asm volatile("syscall\n"
+               : "+a"(ret)
+               : "D"(arg1), "S"(arg2), "d"(arg3)
+               : "rcx", "r11", "memory");
+    return ret;
+}
+
+#else
+/* Dummy implementations for all other configurations (non-x86_64 Linux, */
+/* Windows, macOS, etc.) */
+#if defined(CONFIG_LINUX)
+#include <linux/kvm.h>
+#include <sys/ioctl.h>
+#endif
+#endif

-- 
2.55.0.737.g08866a6d13-goog
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.