mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 08:44:41 +00:00 
			
		
		
		
	um: Fix FP register size for XSTATE/XSAVE
Hard code max size. Taken from https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/common/x86-xstate.h Signed-off-by: Thomas Meyer <thomas@m3y3r.de> Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
		
							parent
							
								
									569dbb88e8
								
							
						
					
					
						commit
						6f602afda7
					
				
					 6 changed files with 27 additions and 19 deletions
				
			
		|  | @ -11,6 +11,7 @@ | ||||||
| #include <asm/types.h> | #include <asm/types.h> | ||||||
| #include <asm/page.h> | #include <asm/page.h> | ||||||
| #include <asm/segment.h> | #include <asm/segment.h> | ||||||
|  | #include <sysdep/ptrace_user.h> | ||||||
| 
 | 
 | ||||||
| struct thread_info { | struct thread_info { | ||||||
| 	struct task_struct	*task;		/* main task structure */ | 	struct task_struct	*task;		/* main task structure */ | ||||||
|  | @ -22,6 +23,8 @@ struct thread_info { | ||||||
| 					 	   0-0xBFFFFFFF for user | 					 	   0-0xBFFFFFFF for user | ||||||
| 						   0-0xFFFFFFFF for kernel */ | 						   0-0xFFFFFFFF for kernel */ | ||||||
| 	struct thread_info	*real_thread;    /* Points to non-IRQ stack */ | 	struct thread_info	*real_thread;    /* Points to non-IRQ stack */ | ||||||
|  | 	unsigned long aux_fp_regs[FP_SIZE];	/* auxiliary fp_regs to save/restore
 | ||||||
|  | 						   them out-of-band */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #define INIT_THREAD_INFO(tsk)			\ | #define INIT_THREAD_INFO(tsk)			\ | ||||||
|  |  | ||||||
|  | @ -278,7 +278,7 @@ extern int protect(struct mm_id * mm_idp, unsigned long addr, | ||||||
| extern int is_skas_winch(int pid, int fd, void *data); | extern int is_skas_winch(int pid, int fd, void *data); | ||||||
| extern int start_userspace(unsigned long stub_stack); | extern int start_userspace(unsigned long stub_stack); | ||||||
| extern int copy_context_skas0(unsigned long stack, int pid); | extern int copy_context_skas0(unsigned long stack, int pid); | ||||||
| extern void userspace(struct uml_pt_regs *regs); | extern void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs); | ||||||
| extern int map_stub_pages(int fd, unsigned long code, unsigned long data, | extern int map_stub_pages(int fd, unsigned long code, unsigned long data, | ||||||
| 			  unsigned long stack); | 			  unsigned long stack); | ||||||
| extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)); | extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)); | ||||||
|  |  | ||||||
|  | @ -131,7 +131,7 @@ void new_thread_handler(void) | ||||||
| 	 * callback returns only if the kernel thread execs a process | 	 * callback returns only if the kernel thread execs a process | ||||||
| 	 */ | 	 */ | ||||||
| 	n = fn(arg); | 	n = fn(arg); | ||||||
| 	userspace(¤t->thread.regs.regs); | 	userspace(¤t->thread.regs.regs, current_thread_info()->aux_fp_regs); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Called magically, see new_thread_handler above */ | /* Called magically, see new_thread_handler above */ | ||||||
|  | @ -150,7 +150,7 @@ void fork_handler(void) | ||||||
| 
 | 
 | ||||||
| 	current->thread.prev_sched = NULL; | 	current->thread.prev_sched = NULL; | ||||||
| 
 | 
 | ||||||
| 	userspace(¤t->thread.regs.regs); | 	userspace(¤t->thread.regs.regs, current_thread_info()->aux_fp_regs); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int copy_thread(unsigned long clone_flags, unsigned long sp, | int copy_thread(unsigned long clone_flags, unsigned long sp, | ||||||
|  |  | ||||||
|  | @ -88,12 +88,11 @@ bad_wait: | ||||||
| 
 | 
 | ||||||
| extern unsigned long current_stub_stack(void); | extern unsigned long current_stub_stack(void); | ||||||
| 
 | 
 | ||||||
| static void get_skas_faultinfo(int pid, struct faultinfo *fi) | static void get_skas_faultinfo(int pid, struct faultinfo *fi, unsigned long *aux_fp_regs) | ||||||
| { | { | ||||||
| 	int err; | 	int err; | ||||||
| 	unsigned long fpregs[FP_SIZE]; |  | ||||||
| 
 | 
 | ||||||
| 	err = get_fp_registers(pid, fpregs); | 	err = get_fp_registers(pid, aux_fp_regs); | ||||||
| 	if (err < 0) { | 	if (err < 0) { | ||||||
| 		printk(UM_KERN_ERR "save_fp_registers returned %d\n", | 		printk(UM_KERN_ERR "save_fp_registers returned %d\n", | ||||||
| 		       err); | 		       err); | ||||||
|  | @ -113,7 +112,7 @@ static void get_skas_faultinfo(int pid, struct faultinfo *fi) | ||||||
| 	 */ | 	 */ | ||||||
| 	memcpy(fi, (void *)current_stub_stack(), sizeof(*fi)); | 	memcpy(fi, (void *)current_stub_stack(), sizeof(*fi)); | ||||||
| 
 | 
 | ||||||
| 	err = put_fp_registers(pid, fpregs); | 	err = put_fp_registers(pid, aux_fp_regs); | ||||||
| 	if (err < 0) { | 	if (err < 0) { | ||||||
| 		printk(UM_KERN_ERR "put_fp_registers returned %d\n", | 		printk(UM_KERN_ERR "put_fp_registers returned %d\n", | ||||||
| 		       err); | 		       err); | ||||||
|  | @ -121,9 +120,9 @@ static void get_skas_faultinfo(int pid, struct faultinfo *fi) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void handle_segv(int pid, struct uml_pt_regs * regs) | static void handle_segv(int pid, struct uml_pt_regs *regs, unsigned long *aux_fp_regs) | ||||||
| { | { | ||||||
| 	get_skas_faultinfo(pid, ®s->faultinfo); | 	get_skas_faultinfo(pid, ®s->faultinfo, aux_fp_regs); | ||||||
| 	segv(regs->faultinfo, 0, 1, NULL); | 	segv(regs->faultinfo, 0, 1, NULL); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -332,7 +331,7 @@ int start_userspace(unsigned long stub_stack) | ||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void userspace(struct uml_pt_regs *regs) | void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs) | ||||||
| { | { | ||||||
| 	int err, status, op, pid = userspace_pid[0]; | 	int err, status, op, pid = userspace_pid[0]; | ||||||
| 	/* To prevent races if using_sysemu changes under us.*/ | 	/* To prevent races if using_sysemu changes under us.*/ | ||||||
|  | @ -407,11 +406,11 @@ void userspace(struct uml_pt_regs *regs) | ||||||
| 			case SIGSEGV: | 			case SIGSEGV: | ||||||
| 				if (PTRACE_FULL_FAULTINFO) { | 				if (PTRACE_FULL_FAULTINFO) { | ||||||
| 					get_skas_faultinfo(pid, | 					get_skas_faultinfo(pid, | ||||||
| 							   ®s->faultinfo); | 							   ®s->faultinfo, aux_fp_regs); | ||||||
| 					(*sig_info[SIGSEGV])(SIGSEGV, (struct siginfo *)&si, | 					(*sig_info[SIGSEGV])(SIGSEGV, (struct siginfo *)&si, | ||||||
| 							     regs); | 							     regs); | ||||||
| 				} | 				} | ||||||
| 				else handle_segv(pid, regs); | 				else handle_segv(pid, regs, aux_fp_regs); | ||||||
| 				break; | 				break; | ||||||
| 			case SIGTRAP + 0x80: | 			case SIGTRAP + 0x80: | ||||||
| 			        handle_trap(pid, regs, local_using_sysemu); | 			        handle_trap(pid, regs, local_using_sysemu); | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
|  | #include <stdlib.h> | ||||||
| #include <sys/ptrace.h> | #include <sys/ptrace.h> | ||||||
| #ifdef __i386__ | #ifdef __i386__ | ||||||
| #include <sys/user.h> | #include <sys/user.h> | ||||||
|  | @ -31,7 +32,7 @@ int save_fp_registers(int pid, unsigned long *fp_regs) | ||||||
| 
 | 
 | ||||||
| 	if (have_xstate_support) { | 	if (have_xstate_support) { | ||||||
| 		iov.iov_base = fp_regs; | 		iov.iov_base = fp_regs; | ||||||
| 		iov.iov_len = sizeof(struct _xstate); | 		iov.iov_len = FP_SIZE * sizeof(unsigned long); | ||||||
| 		if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0) | 		if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0) | ||||||
| 			return -errno; | 			return -errno; | ||||||
| 		return 0; | 		return 0; | ||||||
|  | @ -51,10 +52,9 @@ int restore_fp_registers(int pid, unsigned long *fp_regs) | ||||||
| { | { | ||||||
| #ifdef PTRACE_SETREGSET | #ifdef PTRACE_SETREGSET | ||||||
| 	struct iovec iov; | 	struct iovec iov; | ||||||
| 
 |  | ||||||
| 	if (have_xstate_support) { | 	if (have_xstate_support) { | ||||||
| 		iov.iov_base = fp_regs; | 		iov.iov_base = fp_regs; | ||||||
| 		iov.iov_len = sizeof(struct _xstate); | 		iov.iov_len = FP_SIZE * sizeof(unsigned long); | ||||||
| 		if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0) | 		if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0) | ||||||
| 			return -errno; | 			return -errno; | ||||||
| 		return 0; | 		return 0; | ||||||
|  | @ -125,13 +125,19 @@ int put_fp_registers(int pid, unsigned long *regs) | ||||||
| void arch_init_registers(int pid) | void arch_init_registers(int pid) | ||||||
| { | { | ||||||
| #ifdef PTRACE_GETREGSET | #ifdef PTRACE_GETREGSET | ||||||
| 	struct _xstate fp_regs; | 	void * fp_regs; | ||||||
| 	struct iovec iov; | 	struct iovec iov; | ||||||
| 
 | 
 | ||||||
| 	iov.iov_base = &fp_regs; | 	fp_regs = malloc(FP_SIZE * sizeof(unsigned long)); | ||||||
| 	iov.iov_len = sizeof(struct _xstate); | 	if(fp_regs == NULL) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	iov.iov_base = fp_regs; | ||||||
|  | 	iov.iov_len = FP_SIZE * sizeof(unsigned long); | ||||||
| 	if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0) | 	if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0) | ||||||
| 		have_xstate_support = 1; | 		have_xstate_support = 1; | ||||||
|  | 
 | ||||||
|  | 	free(fp_regs); | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -51,7 +51,7 @@ void foo(void) | ||||||
| 	DEFINE(HOST_ORIG_AX, ORIG_EAX); | 	DEFINE(HOST_ORIG_AX, ORIG_EAX); | ||||||
| #else | #else | ||||||
| #ifdef FP_XSTATE_MAGIC1 | #ifdef FP_XSTATE_MAGIC1 | ||||||
| 	DEFINE(HOST_FP_SIZE, sizeof(struct _xstate) / sizeof(unsigned long)); | 	DEFINE_LONGS(HOST_FP_SIZE, 2696); | ||||||
| #else | #else | ||||||
| 	DEFINE(HOST_FP_SIZE, sizeof(struct _fpstate) / sizeof(unsigned long)); | 	DEFINE(HOST_FP_SIZE, sizeof(struct _fpstate) / sizeof(unsigned long)); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Thomas Meyer
						Thomas Meyer