Commit 3f17fed2 authored by Benjamin Berg's avatar Benjamin Berg Committed by Johannes Berg
Browse files

um: switch to regset API and depend on XSTATE



The PTRACE_GETREGSET API has now existed since Linux 2.6.33. The XSAVE
CPU feature should also be sufficiently common to be able to rely on it.

With this, define our internal FP state to be the hosts XSAVE data. Add
discovery for the hosts XSAVE size and place the FP registers at the end
of task_struct so that we can adjust the size at runtime.

Next we can implement the regset API on top and update the signal
handling as well as ptrace APIs to use them. Also switch coredump
creation to use the regset API and finally set HAVE_ARCH_TRACEHOOK.

This considerably improves the signal frames. Previously they might not
have contained all the registers (i386) and also did not have the
sizes and magic values set to the correct values to permit userspace to
decode the frame.

As a side effect, this will permit UML to run on hosts with newer CPU
extensions (such as AMX) that need even more register state.

Signed-off-by: default avatarBenjamin Berg <benjamin.berg@intel.com>
Link: https://patch.msgid.link/20241023094120.4083426-1-benjamin@sipsolutions.net


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 0b8b2668
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ menu "UML-specific options"
config UML
	bool
	default y
	select ARCH_WANTS_DYNAMIC_TASK_STRUCT
	select ARCH_HAS_CPU_FINALIZE_INIT
	select ARCH_HAS_FORTIFY_SOURCE
	select ARCH_HAS_GCOV_PROFILE_ALL
@@ -32,6 +33,7 @@ config UML
	select HAVE_ARCH_VMAP_STACK
	select HAVE_RUST
	select ARCH_HAS_UBSAN
	select HAVE_ARCH_TRACEHOOK

config MMU
	bool
+3 −1
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ struct task_struct;
struct mm_struct;

struct thread_struct {
	struct pt_regs regs;
	struct pt_regs *segv_regs;
	struct task_struct *prev_sched;
	struct arch_thread arch;
@@ -31,6 +30,9 @@ struct thread_struct {
			void *arg;
		} thread;
	} request;

	/* Contains variable sized FP registers */
	struct pt_regs regs;
};

#define INIT_THREAD \
+7 −15
Original line number Diff line number Diff line
@@ -187,6 +187,13 @@ void initial_thread_cb(void (*proc)(void *), void *arg)
	kmalloc_ok = save_kmalloc_ok;
}

int arch_dup_task_struct(struct task_struct *dst,
			 struct task_struct *src)
{
	memcpy(dst, src, arch_task_struct_size);
	return 0;
}

void um_idle_sleep(void)
{
	if (time_travel_mode != TT_MODE_OFF)
@@ -287,18 +294,3 @@ unsigned long __get_wchan(struct task_struct *p)

	return 0;
}

int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
{
#ifdef CONFIG_X86_32
	extern int have_fpx_regs;

	/* FIXME: A plain copy does not work on i386 with have_fpx_regs */
	if (have_fpx_regs)
		return 0;
#endif
	memcpy(fpu, &t->thread.regs.regs.fp, sizeof(*fpu));

	return 1;
}
+2 −0
Original line number Diff line number Diff line
@@ -402,6 +402,8 @@ int __init linux_main(int argc, char **argv, char **envp)
		os_info("Kernel virtual memory size shrunk to %lu bytes\n",
			virtmem_size);

	arch_task_struct_size = sizeof(struct task_struct) + host_fp_size;

	os_flush_stdout();

	return start_uml();
+8 −3
Original line number Diff line number Diff line
@@ -10,11 +10,12 @@
#include <sysdep/ptrace.h>
#include <sysdep/ptrace_user.h>
#include <registers.h>
#include <stdlib.h>

/* This is set once at boot time and not changed thereafter */

static unsigned long exec_regs[MAX_REG_NR];
static unsigned long exec_fp_regs[FP_SIZE];
static unsigned long *exec_fp_regs;

int init_pid_registers(int pid)
{
@@ -24,7 +25,11 @@ int init_pid_registers(int pid)
	if (err < 0)
		return -errno;

	arch_init_registers(pid);
	err = arch_init_registers(pid);
	if (err < 0)
		return err;

	exec_fp_regs = malloc(host_fp_size);
	get_fp_registers(pid, exec_fp_regs);
	return 0;
}
@@ -34,5 +39,5 @@ void get_safe_registers(unsigned long *regs, unsigned long *fp_regs)
	memcpy(regs, exec_regs, sizeof(exec_regs));

	if (fp_regs)
		memcpy(fp_regs, exec_fp_regs, sizeof(exec_fp_regs));
		memcpy(fp_regs, exec_fp_regs, host_fp_size);
}
Loading