xref: /linux/arch/x86/um/os-Linux/registers.c (revision 6f602afda7275c24c20ba38b5b6cd4ed08561fff)
15c48b108SAl Viro /*
25c48b108SAl Viro  * Copyright (C) 2004 PathScale, Inc
35c48b108SAl Viro  * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
45c48b108SAl Viro  * Licensed under the GPL
55c48b108SAl Viro  */
65c48b108SAl Viro 
75c48b108SAl Viro #include <errno.h>
8*6f602afdSThomas Meyer #include <stdlib.h>
95c48b108SAl Viro #include <sys/ptrace.h>
1038b64aedSRichard Weinberger #ifdef __i386__
115c48b108SAl Viro #include <sys/user.h>
1238b64aedSRichard Weinberger #endif
1337185b33SAl Viro #include <longjmp.h>
1437185b33SAl Viro #include <sysdep/ptrace_user.h>
15a78ff111SEli Cooper #include <sys/uio.h>
16a78ff111SEli Cooper #include <asm/sigcontext.h>
17a78ff111SEli Cooper #include <linux/elf.h>
185c48b108SAl Viro 
19a78ff111SEli Cooper int have_xstate_support;
20a78ff111SEli Cooper 
21a78ff111SEli Cooper int save_i387_registers(int pid, unsigned long *fp_regs)
225c48b108SAl Viro {
235c48b108SAl Viro 	if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0)
245c48b108SAl Viro 		return -errno;
255c48b108SAl Viro 	return 0;
265c48b108SAl Viro }
275c48b108SAl Viro 
28a78ff111SEli Cooper int save_fp_registers(int pid, unsigned long *fp_regs)
29a78ff111SEli Cooper {
300a987645SFlorian Fainelli #ifdef PTRACE_GETREGSET
31a78ff111SEli Cooper 	struct iovec iov;
32a78ff111SEli Cooper 
33a78ff111SEli Cooper 	if (have_xstate_support) {
34a78ff111SEli Cooper 		iov.iov_base = fp_regs;
35*6f602afdSThomas Meyer 		iov.iov_len = FP_SIZE * sizeof(unsigned long);
36a78ff111SEli Cooper 		if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
37a78ff111SEli Cooper 			return -errno;
38a78ff111SEli Cooper 		return 0;
390a987645SFlorian Fainelli 	} else
400a987645SFlorian Fainelli #endif
41a78ff111SEli Cooper 		return save_i387_registers(pid, fp_regs);
42a78ff111SEli Cooper }
43a78ff111SEli Cooper 
44a78ff111SEli Cooper int restore_i387_registers(int pid, unsigned long *fp_regs)
455c48b108SAl Viro {
465c48b108SAl Viro 	if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0)
475c48b108SAl Viro 		return -errno;
485c48b108SAl Viro 	return 0;
495c48b108SAl Viro }
505c48b108SAl Viro 
51a78ff111SEli Cooper int restore_fp_registers(int pid, unsigned long *fp_regs)
52a78ff111SEli Cooper {
530a987645SFlorian Fainelli #ifdef PTRACE_SETREGSET
54a78ff111SEli Cooper 	struct iovec iov;
55a78ff111SEli Cooper 	if (have_xstate_support) {
56a78ff111SEli Cooper 		iov.iov_base = fp_regs;
57*6f602afdSThomas Meyer 		iov.iov_len = FP_SIZE * sizeof(unsigned long);
58a78ff111SEli Cooper 		if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0)
59a78ff111SEli Cooper 			return -errno;
60a78ff111SEli Cooper 		return 0;
610a987645SFlorian Fainelli 	} else
620a987645SFlorian Fainelli #endif
63a78ff111SEli Cooper 		return restore_i387_registers(pid, fp_regs);
64a78ff111SEli Cooper }
65a78ff111SEli Cooper 
665c48b108SAl Viro #ifdef __i386__
675c48b108SAl Viro int have_fpx_regs = 1;
685c48b108SAl Viro int save_fpx_registers(int pid, unsigned long *fp_regs)
695c48b108SAl Viro {
705c48b108SAl Viro 	if (ptrace(PTRACE_GETFPXREGS, pid, 0, fp_regs) < 0)
715c48b108SAl Viro 		return -errno;
725c48b108SAl Viro 	return 0;
735c48b108SAl Viro }
745c48b108SAl Viro 
755c48b108SAl Viro int restore_fpx_registers(int pid, unsigned long *fp_regs)
765c48b108SAl Viro {
775c48b108SAl Viro 	if (ptrace(PTRACE_SETFPXREGS, pid, 0, fp_regs) < 0)
785c48b108SAl Viro 		return -errno;
795c48b108SAl Viro 	return 0;
805c48b108SAl Viro }
815c48b108SAl Viro 
825c48b108SAl Viro int get_fp_registers(int pid, unsigned long *regs)
835c48b108SAl Viro {
845c48b108SAl Viro 	if (have_fpx_regs)
855c48b108SAl Viro 		return save_fpx_registers(pid, regs);
865c48b108SAl Viro 	else
875c48b108SAl Viro 		return save_fp_registers(pid, regs);
885c48b108SAl Viro }
895c48b108SAl Viro 
905c48b108SAl Viro int put_fp_registers(int pid, unsigned long *regs)
915c48b108SAl Viro {
925c48b108SAl Viro 	if (have_fpx_regs)
935c48b108SAl Viro 		return restore_fpx_registers(pid, regs);
945c48b108SAl Viro 	else
955c48b108SAl Viro 		return restore_fp_registers(pid, regs);
965c48b108SAl Viro }
975c48b108SAl Viro 
985c48b108SAl Viro void arch_init_registers(int pid)
995c48b108SAl Viro {
1005c48b108SAl Viro 	struct user_fpxregs_struct fpx_regs;
1015c48b108SAl Viro 	int err;
1025c48b108SAl Viro 
1035c48b108SAl Viro 	err = ptrace(PTRACE_GETFPXREGS, pid, 0, &fpx_regs);
1045c48b108SAl Viro 	if (!err)
1055c48b108SAl Viro 		return;
1065c48b108SAl Viro 
1075c48b108SAl Viro 	if (errno != EIO)
1085c48b108SAl Viro 		panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d",
1095c48b108SAl Viro 		      errno);
1105c48b108SAl Viro 
1115c48b108SAl Viro 	have_fpx_regs = 0;
1125c48b108SAl Viro }
1135c48b108SAl Viro #else
1145c48b108SAl Viro 
1155c48b108SAl Viro int get_fp_registers(int pid, unsigned long *regs)
1165c48b108SAl Viro {
1175c48b108SAl Viro 	return save_fp_registers(pid, regs);
1185c48b108SAl Viro }
1195c48b108SAl Viro 
1205c48b108SAl Viro int put_fp_registers(int pid, unsigned long *regs)
1215c48b108SAl Viro {
1225c48b108SAl Viro 	return restore_fp_registers(pid, regs);
1235c48b108SAl Viro }
1245c48b108SAl Viro 
125a78ff111SEli Cooper void arch_init_registers(int pid)
126a78ff111SEli Cooper {
1270a987645SFlorian Fainelli #ifdef PTRACE_GETREGSET
128*6f602afdSThomas Meyer 	void * fp_regs;
129a78ff111SEli Cooper 	struct iovec iov;
130a78ff111SEli Cooper 
131*6f602afdSThomas Meyer 	fp_regs = malloc(FP_SIZE * sizeof(unsigned long));
132*6f602afdSThomas Meyer 	if(fp_regs == NULL)
133*6f602afdSThomas Meyer 		return;
134*6f602afdSThomas Meyer 
135*6f602afdSThomas Meyer 	iov.iov_base = fp_regs;
136*6f602afdSThomas Meyer 	iov.iov_len = FP_SIZE * sizeof(unsigned long);
137a78ff111SEli Cooper 	if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0)
138a78ff111SEli Cooper 		have_xstate_support = 1;
139*6f602afdSThomas Meyer 
140*6f602afdSThomas Meyer 	free(fp_regs);
1410a987645SFlorian Fainelli #endif
142a78ff111SEli Cooper }
1435c48b108SAl Viro #endif
1445c48b108SAl Viro 
1455c48b108SAl Viro unsigned long get_thread_reg(int reg, jmp_buf *buf)
1465c48b108SAl Viro {
1475c48b108SAl Viro 	switch (reg) {
1485c48b108SAl Viro #ifdef __i386__
149a10c95d8SAl Viro 	case HOST_IP:
1505c48b108SAl Viro 		return buf[0]->__eip;
151a10c95d8SAl Viro 	case HOST_SP:
1525c48b108SAl Viro 		return buf[0]->__esp;
153a10c95d8SAl Viro 	case HOST_BP:
1545c48b108SAl Viro 		return buf[0]->__ebp;
1555c48b108SAl Viro #else
156a10c95d8SAl Viro 	case HOST_IP:
1575c48b108SAl Viro 		return buf[0]->__rip;
158a10c95d8SAl Viro 	case HOST_SP:
1595c48b108SAl Viro 		return buf[0]->__rsp;
160a10c95d8SAl Viro 	case HOST_BP:
1615c48b108SAl Viro 		return buf[0]->__rbp;
1625c48b108SAl Viro #endif
1635c48b108SAl Viro 	default:
1645c48b108SAl Viro 		printk(UM_KERN_ERR "get_thread_regs - unknown register %d\n",
1655c48b108SAl Viro 		       reg);
1665c48b108SAl Viro 		return 0;
1675c48b108SAl Viro 	}
1685c48b108SAl Viro }
169