[RFC PATCH 5/6] x86: Add xstate parsing and PKRU offset detection

Jacky Li <[email protected]>
Newsgroups gmane.comp.emulators.kvm.devel,gmane.comp.emulators.qemu
Message-ID <[email protected]>
Add data structures and CPUID detection routines to locate the PKRU
register inside the Linux x86_64 signal frame extended state (`xstate`).

Signed-off-by: Jacky Li <[email protected]>
---
 util/pkey.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/util/pkey.c b/util/pkey.c
index 2e42da7d9c..21b41f928e 100644
--- a/util/pkey.c
+++ b/util/pkey.c
@@ -88,6 +88,59 @@ static inline __attribute__((always_inline)) intptr_t local_syscall3(
     return ret;
 }
 
+/*
+ * Custom structures to parse FPU xstate and extract the PKRU register.
+ * These match the Linux kernel x86_64 signal frame ABI.
+ */
+struct fpstate_64 {
+    uint16_t cwd;
+    uint16_t swd;
+    uint16_t twd;
+    uint16_t fop;
+    uint64_t rip;
+    uint64_t rdp;
+    uint32_t mxcsr;
+    uint32_t mxcsr_mask;
+    uint32_t st_space[32];  /*  8x  FP registers, 16 bytes each */
+    uint32_t xmm_space[64]; /* 16x XMM registers, 16 bytes each */
+    uint32_t reserved1[12];
+    union {
+        uint32_t reserved2[12];
+        struct {
+            uint32_t magic1;
+            uint32_t extended_size;
+            uint64_t xstate_bv;
+            uint32_t xstate_size;
+            uint32_t padding[7];
+        } sw_reserved; /* Extended state is encoded here */
+    };
+};
+
+#define FP_XSTATE_MAGIC1 0x46505853U
+#define FP_XSTATE_MAGIC2 0x46505845U
+#define XFEATURE_PKRU 9
+#define XSTATE_PKRU (1ULL << XFEATURE_PKRU)
+
+static int pkru_offset = -2; /* -2 means uninitialized */
+
+static int __attribute__((unused)) get_pkru_offset(void)
+{
+    uint32_t eax, ebx, ecx, edx;
+    __cpuid_count(0xd, XFEATURE_PKRU, eax, ebx, ecx, edx);
+    if (ebx == 0) {
+        return -1;
+    }
+    return (int)ebx;
+}
+
+static int __attribute__((unused)) qemu_get_pkru_offset(void)
+{
+    if (pkru_offset == -2) {
+        pkru_offset = get_pkru_offset();
+    }
+    return pkru_offset;
+}
+
 __attribute__((target("pku"))) void qemu_init_guest_memory_pkey(void)
 {
     if (guest_memory_pkey != -1) {

-- 
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.