1/*
2 * Copyright (C) 2004 PathScale, Inc
3 * Licensed under the GPL
4 */
5
6#include <errno.h>
7#include <string.h>
8#include "sysdep/ptrace_user.h"
9#include "sysdep/ptrace.h"
10#include "uml-config.h"
11#include "skas_ptregs.h"
12#include "registers.h"
13#include "longjmp.h"
14#include "user.h"
15
16/* These are set once at boot time and not changed thereafter */
17
18static unsigned long exec_regs[MAX_REG_NR];
19static unsigned long exec_fp_regs[HOST_FP_SIZE];
20static unsigned long exec_fpx_regs[HOST_XFP_SIZE];
21static int have_fpx_regs = 1;
22
23void init_thread_registers(union uml_pt_regs *to)
24{
25	memcpy(to->skas.regs, exec_regs, sizeof(to->skas.regs));
26	memcpy(to->skas.fp, exec_fp_regs, sizeof(to->skas.fp));
27	if(have_fpx_regs)
28		memcpy(to->skas.xfp, exec_fpx_regs, sizeof(to->skas.xfp));
29}
30
31int save_fp_registers(int pid, unsigned long *fp_regs)
32{
33	if(ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0)
34		return -errno;
35	return 0;
36}
37
38int restore_fp_registers(int pid, unsigned long *fp_regs)
39{
40	if(ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0)
41		return -errno;
42	return 0;
43}
44
45static int move_registers(int pid, int int_op, union uml_pt_regs *regs,
46			  int fp_op, unsigned long *fp_regs)
47{
48	if(ptrace(int_op, pid, 0, regs->skas.regs) < 0)
49		return -errno;
50
51	if(ptrace(fp_op, pid, 0, fp_regs) < 0)
52		return -errno;
53
54	return 0;
55}
56
57void save_registers(int pid, union uml_pt_regs *regs)
58{
59	unsigned long *fp_regs;
60	int err, fp_op;
61
62	if(have_fpx_regs){
63		fp_op = PTRACE_GETFPXREGS;
64		fp_regs = regs->skas.xfp;
65	}
66	else {
67		fp_op = PTRACE_GETFPREGS;
68		fp_regs = regs->skas.fp;
69	}
70
71	err = move_registers(pid, PTRACE_GETREGS, regs, fp_op, fp_regs);
72	if(err)
73		panic("save_registers - saving registers failed, errno = %d\n",
74		      -err);
75}
76
77void restore_registers(int pid, union uml_pt_regs *regs)
78{
79	unsigned long *fp_regs;
80	int err, fp_op;
81
82	if(have_fpx_regs){
83		fp_op = PTRACE_SETFPXREGS;
84		fp_regs = regs->skas.xfp;
85	}
86	else {
87		fp_op = PTRACE_SETFPREGS;
88		fp_regs = regs->skas.fp;
89	}
90
91	err = move_registers(pid, PTRACE_SETREGS, regs, fp_op, fp_regs);
92	if(err)
93		panic("restore_registers - saving registers failed, "
94		      "errno = %d\n", -err);
95}
96
97void init_registers(int pid)
98{
99	int err;
100
101	memset(exec_regs, 0, sizeof(exec_regs));
102	err = ptrace(PTRACE_GETREGS, pid, 0, exec_regs);
103	if(err)
104		panic("check_ptrace : PTRACE_GETREGS failed, errno = %d",
105		      errno);
106
107	errno = 0;
108	err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs);
109	if(!err)
110		return;
111	if(errno != EIO)
112		panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d",
113		      errno);
114
115	have_fpx_regs = 0;
116
117	err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs);
118	if(err)
119		panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d",
120		      errno);
121}
122
123void get_safe_registers(unsigned long *regs, unsigned long *fp_regs)
124{
125	memcpy(regs, exec_regs, sizeof(exec_regs));
126	if(fp_regs != NULL)
127		memcpy(fp_regs, exec_fp_regs,
128		       HOST_FP_SIZE * sizeof(unsigned long));
129}
130
131unsigned long get_thread_reg(int reg, jmp_buf *buf)
132{
133	switch(reg){
134	case EIP: return buf[0]->__eip;
135	case UESP: return buf[0]->__esp;
136	case EBP: return buf[0]->__ebp;
137	default:
138		printk("get_thread_regs - unknown register %d\n", reg);
139		return 0;
140	}
141}
142