Skip to content

Commit

Permalink
[PATCH] uml: implement {get,set}_thread_area for i386
Browse files Browse the repository at this point in the history
Implement sys_[gs]et_thread_area and the corresponding ptrace operations for
UML.  This is the main chunk, additional parts follow.  This implementation is
now well tested and has run reliably for some time, and we've understood all
the previously existing problems.

Their implementation saves the new GDT content and then forwards the call to
the host when appropriate, i.e.  immediately when the target process is
running or on context switch otherwise (i.e.  on fork and on ptrace() calls).

In SKAS mode, we must switch registers on each context switch (because SKAS
does not switches tls_array together with current->mm).

Also, added get_cpu() locking; this has been done for SKAS mode, since TT does
not need it (it does not use smp_processor_id()).

Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Acked-by: Jeff Dike <jdike@addtoit.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Paolo 'Blaisorblade' Giarrusso authored and Linus Torvalds committed Mar 31, 2006
1 parent 972410b commit aa6758d
Show file tree
Hide file tree
Showing 21 changed files with 580 additions and 61 deletions.
4 changes: 4 additions & 0 deletions arch/um/include/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@ extern int run_helper_thread(int (*proc)(void *), void *arg,
int stack_order);
extern int helper_wait(int pid);


/* tls.c */
extern int os_set_thread_area(void *data, int pid);
extern int os_get_thread_area(void *data, int pid);
/* umid.c */

extern int umid_file_name(char *name, char *buf, int len);
Expand Down
12 changes: 1 addition & 11 deletions arch/um/kernel/exec_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

void flush_thread(void)
{
arch_flush_thread(&current->thread.arch);
CHOOSE_MODE(flush_thread_tt(), flush_thread_skas());
}

Expand Down Expand Up @@ -74,14 +75,3 @@ long sys_execve(char __user *file, char __user *__user *argv,
unlock_kernel();
return(error);
}

/*
* 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:
*/
20 changes: 18 additions & 2 deletions arch/um/kernel/process_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,25 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
unsigned long stack_top, struct task_struct * p,
struct pt_regs *regs)
{
int ret;

p->thread = (struct thread_struct) INIT_THREAD;
return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr,
clone_flags, sp, stack_top, p, regs));
ret = CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr,
clone_flags, sp, stack_top, p, regs);

if (ret || !current->thread.forking)
goto out;

clear_flushed_tls(p);

/*
* Set a new TLS for the child thread?
*/
if (clone_flags & CLONE_SETTLS)
ret = arch_copy_tls(p);

out:
return ret;
}

void initial_thread_cb(void (*proc)(void *), void *arg)
Expand Down
10 changes: 10 additions & 0 deletions arch/um/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
ret = set_fpxregs(data, child);
break;
#endif
case PTRACE_GET_THREAD_AREA:
ret = ptrace_get_thread_area(child, addr,
(struct user_desc __user *) data);
break;

case PTRACE_SET_THREAD_AREA:
ret = ptrace_set_thread_area(child, addr,
(struct user_desc __user *) data);
break;

case PTRACE_FAULTINFO: {
/* Take the info from thread->arch->faultinfo,
* but transfer max. sizeof(struct ptrace_faultinfo).
Expand Down
2 changes: 2 additions & 0 deletions arch/um/kernel/skas/process_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp;

handler = fork_handler;

arch_copy_thread(&current->thread.arch, &p->thread.arch);
}
else {
init_thread_registers(&p->thread.regs.regs);
Expand Down
4 changes: 2 additions & 2 deletions arch/um/os-Linux/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
#

obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o sigio.o \
signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o \
signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o tls.o \
user_syms.o util.o drivers/ sys-$(SUBARCH)/

obj-$(CONFIG_MODE_SKAS) += skas/
obj-$(CONFIG_TTY_LOG) += tty_log.o
user-objs-$(CONFIG_TTY_LOG) += tty_log.o

USER_OBJS := $(user-objs-y) aio.o elf_aux.o file.o helper.o irq.o main.o mem.o \
process.o sigio.o signal.o start_up.o time.o trap.o tt.o tty.o \
process.o sigio.o signal.o start_up.o time.o trap.o tt.o tty.o tls.o \
uaccess.o umid.o util.o

CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
Expand Down
77 changes: 77 additions & 0 deletions arch/um/os-Linux/tls.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include <errno.h>
#include <sys/ptrace.h>
#include <asm/ldt.h>
#include "uml-config.h"

/* TLS support - we basically rely on the host's one.*/

/* In TT mode, this should be called only by the tracing thread, and makes sense
* only for PTRACE_SET_THREAD_AREA. In SKAS mode, it's used normally.
*
*/

#ifndef PTRACE_GET_THREAD_AREA
#define PTRACE_GET_THREAD_AREA 25
#endif

#ifndef PTRACE_SET_THREAD_AREA
#define PTRACE_SET_THREAD_AREA 26
#endif

int os_set_thread_area(void *data, int pid)
{
struct user_desc *info = data;
int ret;

ret = ptrace(PTRACE_SET_THREAD_AREA, pid, info->entry_number,
(unsigned long) info);
if (ret < 0)
ret = -errno;
return ret;
}

#ifdef UML_CONFIG_MODE_SKAS

int os_get_thread_area(void *data, int pid)
{
struct user_desc *info = data;
int ret;

ret = ptrace(PTRACE_GET_THREAD_AREA, pid, info->entry_number,
(unsigned long) info);
if (ret < 0)
ret = -errno;
return ret;
}

#endif

#ifdef UML_CONFIG_MODE_TT
#include "linux/unistd.h"

_syscall1(int, get_thread_area, struct user_desc *, u_info);
_syscall1(int, set_thread_area, struct user_desc *, u_info);

int do_set_thread_area_tt(struct user_desc *info)
{
int ret;

ret = set_thread_area(info);
if (ret < 0) {
ret = -errno;
}
return ret;
}

int do_get_thread_area_tt(struct user_desc *info)
{
int ret;

ret = get_thread_area(info);
if (ret < 0) {
ret = -errno;
}
return ret;
}

#endif /* UML_CONFIG_MODE_TT */
3 changes: 2 additions & 1 deletion arch/um/sys-i386/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
obj-y = bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
ptrace_user.o signal.o sigcontext.o syscalls.o sysrq.o sys_call_table.o
ptrace_user.o signal.o sigcontext.o syscalls.o sysrq.o \
sys_call_table.o tls.o

obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o

Expand Down
2 changes: 2 additions & 0 deletions arch/um/sys-i386/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
void arch_switch_to_tt(struct task_struct *from, struct task_struct *to)
{
update_debugregs(to->thread.arch.debugregs_seq);
arch_switch_tls_tt(from, to);
}

void arch_switch_to_skas(struct task_struct *from, struct task_struct *to)
{
arch_switch_tls_skas(from, to);
}

int is_syscall(unsigned long addr)
Expand Down
2 changes: 0 additions & 2 deletions arch/um/sys-i386/sys_call_table.S
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

#define sys_vm86old sys_ni_syscall
#define sys_vm86 sys_ni_syscall
#define sys_set_thread_area sys_ni_syscall
#define sys_get_thread_area sys_ni_syscall

#define sys_stime um_stime
#define sys_time um_time
Expand Down
14 changes: 10 additions & 4 deletions arch/um/sys-i386/syscalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,21 +61,27 @@ long old_select(struct sel_arg_struct __user *arg)
return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
}

/* The i386 version skips reading from %esi, the fourth argument. So we must do
* this, too.
/*
* The prototype on i386 is:
*
* int clone(int flags, void * child_stack, int * parent_tidptr, struct user_desc * newtls, int * child_tidptr)
*
* and the "newtls" arg. on i386 is read by copy_thread directly from the
* register saved on the stack.
*/
long sys_clone(unsigned long clone_flags, unsigned long newsp,
int __user *parent_tid, int unused, int __user *child_tid)
int __user *parent_tid, void *newtls, int __user *child_tid)
{
long ret;

if (!newsp)
newsp = UPT_SP(&current->thread.regs.regs);

current->thread.forking = 1;
ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
child_tid);
current->thread.forking = 0;
return(ret);
return ret;
}

/*
Expand Down
Loading

0 comments on commit aa6758d

Please sign in to comment.