diff --git a/sys/conf/files.x86 b/sys/conf/files.x86 --- a/sys/conf/files.x86 +++ b/sys/conf/files.x86 @@ -333,6 +333,7 @@ x86/x86/busdma_bounce.c standard x86/x86/busdma_machdep.c standard x86/x86/cpu_machdep.c standard +x86/x86/cpu_ptrace.c standard x86/x86/dbreg.c optional ddb | gdb x86/x86/dump_machdep.c standard x86/x86/fdt_machdep.c optional fdt diff --git a/sys/sys/elf_common.h b/sys/sys/elf_common.h --- a/sys/sys/elf_common.h +++ b/sys/sys/elf_common.h @@ -824,6 +824,7 @@ #define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ #define NT_X86_SEGBASES 0x200 /* x86 FS/GS base addresses. */ #define NT_X86_XSTATE 0x202 /* x86 XSAVE extended state. */ +#define NT_X86_CPUID 0x205 /* x86 CPUID leaves. */ #define NT_ARM_VFP 0x400 /* ARM VFP registers */ #define NT_ARM_TLS 0x401 /* ARM TLS register */ #define NT_ARM_ADDR_MASK 0x406 /* arm64 address mask (e.g. for TBI) */ diff --git a/sys/x86/include/ptrace.h b/sys/x86/include/ptrace.h --- a/sys/x86/include/ptrace.h +++ b/sys/x86/include/ptrace.h @@ -63,4 +63,14 @@ uint32_t xsave_len; }; +/* Structure for entries in NT_X86_CPUID. */ +struct ptrace_cpuid { + uint32_t leaf; + uint32_t subleaf; + uint32_t eax; + uint32_t ebx; + uint32_t ecx; + uint32_t edx; +}; + #endif diff --git a/sys/x86/x86/cpu_ptrace.c b/sys/x86/x86/cpu_ptrace.c new file mode 100644 --- /dev/null +++ b/sys/x86/x86/cpu_ptrace.c @@ -0,0 +1,112 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 John Baldwin + */ + +#include +#include +#include +#include +#include +#include +#include + +static struct ptrace_cpuid *nt_x86_cpuid; + +static bool +get_x86_cpuid(struct regset *rs, struct thread *td, void *buf, + size_t *sizep); + +static struct regset regset_cpuid = { + .note = NT_X86_CPUID, + .size = 0, + .get = get_x86_cpuid, +}; + +static void +populate_cpuid_leaf(struct ptrace_cpuid *pc, uint32_t eax, uint32_t ecx) +{ + uint32_t regs[4]; + + cpuid_count(eax, ecx, regs); + pc->leaf = eax; + pc->subleaf = ecx; + pc->eax = regs[0]; + pc->ebx = regs[1]; + pc->ecx = regs[2]; + pc->edx = regs[3]; +} + +/* + * Allocate and initialize CPUID leaves saved in NT_X86_CPUID. For + * now this just contains leaves describing the layout of the XSAVE + * area. + */ +static void +init_nt_x86_cpuid(void *arg __unused) +{ + struct ptrace_cpuid *pc; + uint64_t mask; + u_int count, i; + + count = 0; + if (use_xsave) { + /* Main leaf 0 and sub-leaf 1. */ + count += 2; + + /* Include the sub-leaf for each bit >= 2 set in XCR0. */ + count += bitcount64(xsave_mask & ~(uint64_t)3); + } + + if (count == 0) + return; + + regset_cpuid.size = count * sizeof(*nt_x86_cpuid); + nt_x86_cpuid = mallocarray(count, sizeof(*nt_x86_cpuid), M_DEVBUF, + M_WAITOK); + + pc = nt_x86_cpuid; + if (use_xsave) { + /* Sub-leaves 0 and 1. */ + populate_cpuid_leaf(pc, 0xd, 0x0); + pc++; + populate_cpuid_leaf(pc, 0xd, 0x1); + pc++; + + /* Sub-leaves for bits >= 2. */ + mask = xsave_mask >> 2; + i = 2; + while (mask != 0) { + if ((mask & 1) == 1) { + populate_cpuid_leaf(pc, 0xd, i); + pc++; + } + mask >>= 1; + i++; + } + } + + KASSERT(pc - nt_x86_cpuid == count, ("%s: mismatch", __func__)); +} +SYSINIT(init_nt_x86_cpuid, SI_SUB_EXEC, SI_ORDER_FIRST, init_nt_x86_cpuid, + NULL); + +static bool +get_x86_cpuid(struct regset *rs, struct thread *td, void *buf, + size_t *sizep) +{ + if (buf != NULL) { + KASSERT(*sizep == regset_cpuid.size, + ("%s: invalid size", __func__)); + + memcpy(buf, nt_x86_cpuid, *sizep); + } + *sizep = regset_cpuid.size; + return (true); +} + +ELF_REGSET(regset_cpuid); +#ifdef COMPAT_FREEBSD32 +ELF32_REGSET(regset_cpuid); +#endif