Commit 39b896fd authored by Jeff Dike's avatar Jeff Dike Committed by Linus Torvalds

[PATCH] UML: Factor out register saving and restoring

This moves the register shuffling code into arch/um/os-Linux/sys-$(SUBARCH),
making it purely userspace code.  It also adds an x86_64 implementation of
registers.c.
Signed-off-by: default avatarJeff Dike <jdike@addtoit.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 0c8e90d5
/*
* Copyright (C) 2004 PathScale, Inc
* Licensed under the GPL
*/
#ifndef __REGISTERS_H
#define __REGISTERS_H
#include "sysdep/ptrace.h"
extern void init_thread_registers(union uml_pt_regs *to);
extern void save_registers(int pid, union uml_pt_regs *regs);
extern void restore_registers(int pid, union uml_pt_regs *regs);
extern void init_registers(int pid);
#endif
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#ifdef UML_CONFIG_MODE_SKAS #ifdef UML_CONFIG_MODE_SKAS
#include "skas.h" #include "skas.h"
#include "skas_ptrace.h" #include "skas_ptrace.h"
#include "registers.h"
#endif #endif
void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
......
...@@ -29,10 +29,7 @@ extern int protect(int fd, unsigned long addr, unsigned long len, ...@@ -29,10 +29,7 @@ extern int protect(int fd, unsigned long addr, unsigned long len,
int r, int w, int x, int must_succeed); int r, int w, int x, int must_succeed);
extern void user_signal(int sig, union uml_pt_regs *regs); extern void user_signal(int sig, union uml_pt_regs *regs);
extern int new_mm(int from); extern int new_mm(int from);
extern void save_registers(union uml_pt_regs *regs);
extern void restore_registers(union uml_pt_regs *regs);
extern void start_userspace(int cpu); extern void start_userspace(int cpu);
extern void init_registers(int pid);
#endif #endif
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "skas_ptrace.h" #include "skas_ptrace.h"
#include "chan_user.h" #include "chan_user.h"
#include "signal_user.h" #include "signal_user.h"
#include "registers.h"
int is_skas_winch(int pid, int fd, void *data) int is_skas_winch(int pid, int fd, void *data)
{ {
...@@ -38,13 +39,6 @@ int is_skas_winch(int pid, int fd, void *data) ...@@ -38,13 +39,6 @@ int is_skas_winch(int pid, int fd, void *data)
return(1); return(1);
} }
/* These are set once at boot time and not changed thereafter */
unsigned long exec_regs[FRAME_SIZE];
unsigned long exec_fp_regs[HOST_FP_SIZE];
unsigned long exec_fpx_regs[HOST_XFP_SIZE];
int have_fpx_regs = 1;
static void handle_segv(int pid) static void handle_segv(int pid)
{ {
struct ptrace_faultinfo fault; struct ptrace_faultinfo fault;
...@@ -143,7 +137,7 @@ void userspace(union uml_pt_regs *regs) ...@@ -143,7 +137,7 @@ void userspace(union uml_pt_regs *regs)
int err, status, op, pid = userspace_pid[0]; int err, status, op, pid = userspace_pid[0];
int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/ int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/
restore_registers(regs); restore_registers(pid, regs);
local_using_sysemu = get_using_sysemu(); local_using_sysemu = get_using_sysemu();
...@@ -160,7 +154,7 @@ void userspace(union uml_pt_regs *regs) ...@@ -160,7 +154,7 @@ void userspace(union uml_pt_regs *regs)
errno); errno);
regs->skas.is_user = 1; regs->skas.is_user = 1;
save_registers(regs); save_registers(pid, regs);
UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
if(WIFSTOPPED(status)){ if(WIFSTOPPED(status)){
...@@ -192,7 +186,7 @@ void userspace(union uml_pt_regs *regs) ...@@ -192,7 +186,7 @@ void userspace(union uml_pt_regs *regs)
PT_SYSCALL_NR(regs->skas.regs) = -1; PT_SYSCALL_NR(regs->skas.regs) = -1;
} }
restore_registers(regs); restore_registers(pid, regs);
/*Now we ended the syscall, so re-read local_using_sysemu.*/ /*Now we ended the syscall, so re-read local_using_sysemu.*/
local_using_sysemu = get_using_sysemu(); local_using_sysemu = get_using_sysemu();
...@@ -243,58 +237,6 @@ void thread_wait(void *sw, void *fb) ...@@ -243,58 +237,6 @@ void thread_wait(void *sw, void *fb)
siglongjmp(*fork_buf, 1); siglongjmp(*fork_buf, 1);
} }
static int move_registers(int pid, int int_op, int fp_op,
union uml_pt_regs *regs, unsigned long *fp_regs)
{
if(ptrace(int_op, pid, 0, regs->skas.regs) < 0)
return(-errno);
if(ptrace(fp_op, pid, 0, fp_regs) < 0)
return(-errno);
return(0);
}
void save_registers(union uml_pt_regs *regs)
{
unsigned long *fp_regs;
int err, fp_op;
if(have_fpx_regs){
fp_op = PTRACE_GETFPXREGS;
fp_regs = regs->skas.xfp;
}
else {
fp_op = PTRACE_GETFPREGS;
fp_regs = regs->skas.fp;
}
err = move_registers(userspace_pid[0], PTRACE_GETREGS, fp_op, regs,
fp_regs);
if(err)
panic("save_registers - saving registers failed, errno = %d\n",
-err);
}
void restore_registers(union uml_pt_regs *regs)
{
unsigned long *fp_regs;
int err, fp_op;
if(have_fpx_regs){
fp_op = PTRACE_SETFPXREGS;
fp_regs = regs->skas.xfp;
}
else {
fp_op = PTRACE_SETFPREGS;
fp_regs = regs->skas.fp;
}
err = move_registers(userspace_pid[0], PTRACE_SETREGS, fp_op, regs,
fp_regs);
if(err)
panic("restore_registers - saving registers failed, "
"errno = %d\n", -err);
}
void switch_threads(void *me, void *next) void switch_threads(void *me, void *next)
{ {
sigjmp_buf my_buf, **me_ptr = me, *next_buf = next; sigjmp_buf my_buf, **me_ptr = me, *next_buf = next;
...@@ -394,29 +336,6 @@ void kill_off_processes_skas(void) ...@@ -394,29 +336,6 @@ void kill_off_processes_skas(void)
os_kill_ptraced_process(userspace_pid[0], 1); os_kill_ptraced_process(userspace_pid[0], 1);
} }
void init_registers(int pid)
{
int err;
if(ptrace(PTRACE_GETREGS, pid, 0, exec_regs) < 0)
panic("check_ptrace : PTRACE_GETREGS failed, errno = %d",
errno);
err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs);
if(!err)
return;
have_fpx_regs = 0;
if(errno != EIO)
panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d",
errno);
err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs);
if(err)
panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d",
errno);
}
/* /*
* Overrides for Emacs so that we follow Linus's tabbing style. * Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically * Emacs will notice this stuff at the end of the file and automatically
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "kern.h" #include "kern.h"
#include "mode.h" #include "mode.h"
#include "proc_mm.h" #include "proc_mm.h"
#include "registers.h"
void *switch_to_skas(void *prev, void *next) void *switch_to_skas(void *prev, void *next)
{ {
...@@ -118,12 +119,7 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, ...@@ -118,12 +119,7 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
handler = fork_handler; handler = fork_handler;
} }
else { else {
memcpy(p->thread.regs.regs.skas.regs, exec_regs, init_thread_registers(&p->thread.regs.regs);
sizeof(p->thread.regs.regs.skas.regs));
memcpy(p->thread.regs.regs.skas.fp, exec_fp_regs,
sizeof(p->thread.regs.regs.skas.fp));
memcpy(p->thread.regs.regs.skas.xfp, exec_fpx_regs,
sizeof(p->thread.regs.regs.skas.xfp));
p->thread.request.u.thread = current->thread.request.u.thread; p->thread.request.u.thread = current->thread.request.u.thread;
handler = new_thread_handler; handler = new_thread_handler;
} }
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
# Licensed under the GPL # Licensed under the GPL
# #
obj-y = elf_aux.o file.o process.o time.o tty.o user_syms.o drivers/ obj-y = elf_aux.o file.o process.o time.o tty.o user_syms.o drivers/ \
sys-$(SUBARCH)/
USER_OBJS := elf_aux.o file.o process.o time.o tty.o USER_OBJS := elf_aux.o file.o process.o time.o tty.o
USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
......
#
# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
# Licensed under the GPL
#
obj-$(CONFIG_MODE_SKAS) = registers.o
USER_OBJS := $(foreach file,$(obj-y),$(obj)/$(file))
$(USER_OBJS) : %.o: %.c
$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
/*
* Copyright (C) 2004 PathScale, Inc
* Licensed under the GPL
*/
#include <errno.h>
#include <string.h>
#include <sys/ptrace.h>
#include "sysdep/ptrace.h"
#include "uml-config.h"
#include "skas_ptregs.h"
#include "registers.h"
#include "user.h"
/* These are set once at boot time and not changed thereafter */
static unsigned long exec_regs[HOST_FRAME_SIZE];
static unsigned long exec_fp_regs[HOST_FP_SIZE];
static unsigned long exec_fpx_regs[HOST_XFP_SIZE];
static int have_fpx_regs = 1;
void init_thread_registers(union uml_pt_regs *to)
{
memcpy(to->skas.regs, exec_regs, sizeof(to->skas.regs));
memcpy(to->skas.fp, exec_fp_regs, sizeof(to->skas.fp));
if(have_fpx_regs)
memcpy(to->skas.xfp, exec_fpx_regs, sizeof(to->skas.xfp));
}
static int move_registers(int pid, int int_op, union uml_pt_regs *regs,
int fp_op, unsigned long *fp_regs)
{
if(ptrace(int_op, pid, 0, regs->skas.regs) < 0)
return(-errno);
if(ptrace(fp_op, pid, 0, fp_regs) < 0)
return(-errno);
return(0);
}
void save_registers(int pid, union uml_pt_regs *regs)
{
unsigned long *fp_regs;
int err, fp_op;
if(have_fpx_regs){
fp_op = PTRACE_GETFPXREGS;
fp_regs = regs->skas.xfp;
}
else {
fp_op = PTRACE_GETFPREGS;
fp_regs = regs->skas.fp;
}
err = move_registers(pid, PTRACE_GETREGS, regs, fp_op, fp_regs);
if(err)
panic("save_registers - saving registers failed, errno = %d\n",
-err);
}
void restore_registers(int pid, union uml_pt_regs *regs)
{
unsigned long *fp_regs;
int err, fp_op;
if(have_fpx_regs){
fp_op = PTRACE_SETFPXREGS;
fp_regs = regs->skas.xfp;
}
else {
fp_op = PTRACE_SETFPREGS;
fp_regs = regs->skas.fp;
}
err = move_registers(pid, PTRACE_SETREGS, regs, fp_op, fp_regs);
if(err)
panic("restore_registers - saving registers failed, "
"errno = %d\n", -err);
}
void init_registers(int pid)
{
int err;
err = ptrace(PTRACE_GETREGS, pid, 0, exec_regs);
if(err)
panic("check_ptrace : PTRACE_GETREGS failed, errno = %d",
err);
err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs);
if(!err)
return;
have_fpx_regs = 0;
if(err != EIO)
panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d",
err);
err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs);
if(err)
panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d",
err);
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/
#
# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
# Licensed under the GPL
#
obj-$(CONFIG_MODE_SKAS) = registers.o
USER_OBJS := $(foreach file,$(obj-y),$(obj)/$(file))
$(USER_OBJS) : %.o: %.c
$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
/*
* Copyright (C) 2004 PathScale, Inc
* Licensed under the GPL
*/
#include <errno.h>
#include <string.h>
#include <sys/ptrace.h>
#include "sysdep/ptrace.h"
#include "uml-config.h"
#include "skas_ptregs.h"
#include "registers.h"
#include "user.h"
/* These are set once at boot time and not changed thereafter */
static unsigned long exec_regs[HOST_FRAME_SIZE];
static unsigned long exec_fp_regs[HOST_FP_SIZE];
void init_thread_registers(union uml_pt_regs *to)
{
memcpy(to->skas.regs, exec_regs, sizeof(to->skas.regs));
memcpy(to->skas.fp, exec_fp_regs, sizeof(to->skas.fp));
}
static int move_registers(int pid, int int_op, int fp_op,
union uml_pt_regs *regs)
{
if(ptrace(int_op, pid, 0, regs->skas.regs) < 0)
return(-errno);
if(ptrace(fp_op, pid, 0, regs->skas.fp) < 0)
return(-errno);
return(0);
}
void save_registers(int pid, union uml_pt_regs *regs)
{
int err;
err = move_registers(pid, PTRACE_GETREGS, PTRACE_GETFPREGS, regs);
if(err)
panic("save_registers - saving registers failed, errno = %d\n",
-err);
}
void restore_registers(int pid, union uml_pt_regs *regs)
{
int err;
err = move_registers(pid, PTRACE_SETREGS, PTRACE_SETFPREGS, regs);
if(err)
panic("restore_registers - saving registers failed, "
"errno = %d\n", -err);
}
void init_registers(int pid)
{
int err;
err = ptrace(PTRACE_GETREGS, pid, 0, exec_regs);
if(err)
panic("check_ptrace : PTRACE_GETREGS failed, errno = %d",
err);
err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs);
if(err)
panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d",
err);
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment