forked from mirrors/linux
		
	uml: throw out CONFIG_MODE_TT
This patchset throws out tt mode, which has been non-functional for a while. This is done in phases, interspersed with code cleanups on the affected files. The removal is done as follows: remove all code, config options, and files which depend on CONFIG_MODE_TT get rid of the CHOOSE_MODE macro, which decided whether to call tt-mode or skas-mode code, and replace invocations with their skas portions replace all now-trivial procedures with their skas equivalents There are now a bunch of now-redundant pieces of data structures, including mode-specific pieces of the thread structure, pt_regs, and mm_context. These are all replaced with their skas-specific contents. As part of the ongoing style compliance project, I made a style pass over all files that were changed. There are three such patches, one for each phase, covering the files affected by that phase but no later ones. I noticed that we weren't freeing the LDT state associated with a process when it exited, so that's fixed in one of the later patches. The last patch is a tidying patch which I've had for a while, but which caused inexplicable crashes under tt mode. Since that is no longer a problem, this can now go in. This patch: Start getting rid of tt mode support. This patch throws out CONFIG_MODE_TT and all config options, code, and files which depend on it. CONFIG_MODE_SKAS is gone and everything that depends on it is included unconditionally. The few changed lines are in re-written Kconfig help, lines which needed something skas-related removed from them, and a few more which weren't strictly deletions. Signed-off-by: Jeff Dike <jdike@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									a1ff5878d2
								
							
						
					
					
						commit
						42fda66387
					
				
					 87 changed files with 34 additions and 4203 deletions
				
			
		|  | @ -62,55 +62,16 @@ config IRQ_RELEASE_METHOD | |||
| 
 | ||||
| menu "UML-specific options" | ||||
| 
 | ||||
| config MODE_TT | ||||
| 	bool "Tracing thread support (DEPRECATED)" | ||||
| 	default n | ||||
| 	depends on BROKEN | ||||
| 	help | ||||
| 	This option controls whether tracing thread support is compiled | ||||
| 	into UML. This option is largely obsolete, given that skas0 provides | ||||
| 	skas security and performance without needing to patch the host. | ||||
| 	It is safe to say 'N' here; saying 'Y' may cause additional problems | ||||
| 	with the resulting binary even if you run UML in SKAS mode, and running | ||||
| 	in TT mode is strongly *NOT RECOMMENDED*. | ||||
| 
 | ||||
| config STATIC_LINK | ||||
| 	bool "Force a static link" | ||||
| 	default n | ||||
| 	depends on !MODE_TT | ||||
| 	help | ||||
| 	If CONFIG_MODE_TT is disabled, then this option gives you the ability | ||||
| 	to force a static link of UML.  Normally, if only skas mode is built | ||||
| 	in to UML, it will be linked as a shared binary.  This is inconvenient | ||||
| 	for use in a chroot jail.  So, if you intend to run UML inside a | ||||
| 	chroot, and you disable CONFIG_MODE_TT, you probably want to say Y | ||||
| 	here. | ||||
| 	This option gives you the ability to force a static link of UML. | ||||
| 	Normally, UML is linked as a shared binary.  This is inconvenient for | ||||
| 	use in a chroot jail.  So, if you intend to run UML inside a chroot, | ||||
| 	you probably want to say Y here. | ||||
| 	Additionally, this option enables using higher memory spaces (up to | ||||
| 	2.75G) for UML - disabling CONFIG_MODE_TT and enabling this option leads | ||||
| 	to best results for this. | ||||
| 
 | ||||
| config KERNEL_HALF_GIGS | ||||
| 	int "Kernel address space size (in .5G units)" | ||||
| 	default "1" | ||||
| 	depends on MODE_TT | ||||
| 	help | ||||
|         This determines the amount of address space that UML will allocate for | ||||
|         its own, measured in half Gigabyte units.  The default is 1. | ||||
|         Change this only if you need to boot UML with an unusually large amount | ||||
|         of physical memory. | ||||
| 
 | ||||
| config MODE_SKAS | ||||
| 	bool "Separate Kernel Address Space support" if MODE_TT | ||||
| 	default y | ||||
| 	help | ||||
| 	This option controls whether skas (separate kernel address space) | ||||
| 	support is compiled in. | ||||
| 	Unless you have specific needs to use TT mode (which applies almost only | ||||
| 	to developers), you should say Y here. | ||||
| 	SKAS mode will make use of the SKAS3 patch if it is applied on the host | ||||
| 	(and your UML will run in SKAS3 mode), but if no SKAS patch is applied | ||||
| 	on the host it will run in SKAS0 mode, which is anyway faster than TT | ||||
| 	mode. | ||||
| 	2.75G) for UML. | ||||
| 
 | ||||
| source "arch/um/Kconfig.arch" | ||||
| source "mm/Kconfig" | ||||
|  | @ -118,7 +79,7 @@ source "mm/Kconfig" | |||
| config LD_SCRIPT_STATIC | ||||
| 	bool | ||||
| 	default y | ||||
| 	depends on MODE_TT || STATIC_LINK | ||||
| 	depends on STATIC_LINK | ||||
| 
 | ||||
| config LD_SCRIPT_DYN | ||||
| 	bool | ||||
|  | @ -220,7 +181,7 @@ config SMP | |||
| 	bool "Symmetric multi-processing support (EXPERIMENTAL)" | ||||
| 	default n | ||||
| 	#SMP_BROKEN is for x86_64. | ||||
| 	depends on MODE_TT && EXPERIMENTAL && (!SMP_BROKEN || (BROKEN && SMP_BROKEN)) | ||||
| 	depends on EXPERIMENTAL && (!SMP_BROKEN || (BROKEN && SMP_BROKEN)) | ||||
| 	help | ||||
| 	This option enables UML SMP support. | ||||
| 	It is NOT related to having a real SMP box. Not directly, at least. | ||||
|  | @ -258,11 +219,6 @@ config NEST_LEVEL | |||
|         inside another UML, set CONFIG_NEST_LEVEL to one more than the host | ||||
|         UML. | ||||
| 
 | ||||
|         Note that if the hosting UML has its CONFIG_KERNEL_HALF_GIGS set to | ||||
|         greater than one, then the guest UML should have its CONFIG_NEST_LEVEL | ||||
|         set to the host's CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS. | ||||
|         Only change this if you are running nested UMLs. | ||||
| 
 | ||||
| config HIGHMEM | ||||
| 	bool "Highmem support (EXPERIMENTAL)" | ||||
| 	depends on !64BIT && EXPERIMENTAL | ||||
|  | @ -271,9 +227,9 @@ config HIGHMEM | |||
| 	This was used to allow UML to run with big amounts of memory. | ||||
| 	Currently it is unstable, so if unsure say N. | ||||
| 
 | ||||
| 	To use big amounts of memory, it is recommended to disable TT mode (i.e. | ||||
| 	CONFIG_MODE_TT) and enable static linking (i.e. CONFIG_STATIC_LINK) - | ||||
| 	this should allow the guest to use up to 2.75G of memory. | ||||
| 	To use big amounts of memory, it is recommended enable static | ||||
| 	linking (i.e. CONFIG_STATIC_LINK) - this should allow the | ||||
| 	guest to use up to 2.75G of memory. | ||||
| 
 | ||||
| config KERNEL_STACK_ORDER | ||||
| 	int "Kernel stack size order" | ||||
|  |  | |||
|  | @ -65,8 +65,6 @@ config XTERM_CHAN | |||
|         This option enables support for attaching UML consoles and serial | ||||
|         lines to xterms.  Each UML device so assigned will be brought up in | ||||
|         its own xterm. | ||||
|         If you disable this option, then CONFIG_PT_PROXY will be disabled as | ||||
|         well, since UML's gdb currently requires an xterm. | ||||
|         It is safe to say 'Y' here. | ||||
| 
 | ||||
| config NOCONFIG_CHAN | ||||
|  |  | |||
|  | @ -2,28 +2,9 @@ menu "Kernel hacking" | |||
| 
 | ||||
| source "lib/Kconfig.debug" | ||||
| 
 | ||||
| config CMDLINE_ON_HOST | ||||
| 	bool "Show command line arguments on the host in TT mode" | ||||
| 	depends on MODE_TT | ||||
| 	default !DEBUG_INFO | ||||
| 	help | ||||
| 	This controls whether arguments in guest processes should be shown on | ||||
| 	the host's ps output. | ||||
| 	Enabling this option hinders debugging on some recent GDB versions | ||||
| 	(because GDB gets "confused" when we do an execvp()). So probably you | ||||
| 	should disable it. | ||||
| 
 | ||||
| config PT_PROXY | ||||
| 	bool "Enable ptrace proxy" | ||||
| 	depends on XTERM_CHAN && DEBUG_INFO && MODE_TT | ||||
| 	help | ||||
| 	This option enables a debugging interface which allows gdb to debug | ||||
| 	the kernel without needing to actually attach to kernel threads. | ||||
| 	If you want to do kernel debugging, say Y here; otherwise say N. | ||||
| 
 | ||||
| config GPROF | ||||
| 	bool "Enable gprof support" | ||||
| 	depends on DEBUG_INFO && MODE_SKAS && !MODE_TT | ||||
| 	depends on DEBUG_INFO | ||||
| 	help | ||||
|         This allows profiling of a User-Mode Linux kernel with the gprof | ||||
|         utility. | ||||
|  | @ -36,7 +17,7 @@ config GPROF | |||
| 
 | ||||
| config GCOV | ||||
| 	bool "Enable gcov support" | ||||
| 	depends on DEBUG_INFO && MODE_SKAS | ||||
| 	depends on DEBUG_INFO | ||||
| 	help | ||||
|         This option allows developers to retrieve coverage data from a UML | ||||
|         session. | ||||
|  |  | |||
|  | @ -31,18 +31,9 @@ SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header)) | |||
| ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \
 | ||||
| 	$(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h | ||||
| 
 | ||||
| um-modes-$(CONFIG_MODE_TT) += tt | ||||
| um-modes-$(CONFIG_MODE_SKAS) += skas | ||||
| MODE_INCLUDE	+= -I$(srctree)/$(ARCH_DIR)/include/skas | ||||
| 
 | ||||
| MODE_INCLUDE	+= $(foreach mode,$(um-modes-y),\
 | ||||
| 		   -I$(srctree)/$(ARCH_DIR)/include/$(mode)) | ||||
| 
 | ||||
| MAKEFILES-INCL	+= $(foreach mode,$(um-modes-y),\
 | ||||
| 		   $(srctree)/$(ARCH_DIR)/Makefile-$(mode)) | ||||
| 
 | ||||
| ifneq ($(MAKEFILES-INCL),) | ||||
|   include $(MAKEFILES-INCL) | ||||
| endif | ||||
| include $(srctree)/$(ARCH_DIR)/Makefile-skas | ||||
| 
 | ||||
| ARCH_INCLUDE	:= -I$(ARCH_DIR)/include | ||||
| ifneq ($(KBUILD_SRC),) | ||||
|  | @ -89,9 +80,8 @@ CFLAGS += $(call cc-option,-fno-unit-at-a-time,) | |||
| # included; the values here are meaningless
 | ||||
| 
 | ||||
| CONFIG_NEST_LEVEL ?= 0 | ||||
| CONFIG_KERNEL_HALF_GIGS ?= 0 | ||||
| 
 | ||||
| SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000) | ||||
| SIZE = ($(CONFIG_NEST_LEVEL) * 0x20000000) | ||||
| 
 | ||||
| PHONY += linux | ||||
| 
 | ||||
|  | @ -124,7 +114,6 @@ CFLAGS_NO_HARDENING := $(call cc-option, -fno-PIC,) $(call cc-option, -fno-pic,) | |||
| 	$(call cc-option, -fno-stack-protector,) \
 | ||||
| 	$(call cc-option, -fno-stack-protector-all,) | ||||
| 
 | ||||
| CPP_MODE-$(CONFIG_MODE_TT) := -DMODE_TT | ||||
| CONFIG_KERNEL_STACK_ORDER ?= 2 | ||||
| STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] ) | ||||
| 
 | ||||
|  | @ -132,11 +121,8 @@ ifndef START | |||
|   START = $(shell echo $$[ $(TOP_ADDR) - $(SIZE) ] ) | ||||
| endif | ||||
| 
 | ||||
| CPPFLAGS_vmlinux.lds = -U$(SUBARCH) \
 | ||||
| 	-DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \
 | ||||
| 	-DELF_FORMAT="$(ELF_FORMAT)" $(CPP_MODE-y) \
 | ||||
| 	-DKERNEL_STACK_SIZE=$(STACK_SIZE) \
 | ||||
| 	-DUNMAP_PATH=arch/um/sys-$(SUBARCH)/unmap.o | ||||
| CPPFLAGS_vmlinux.lds = -U$(SUBARCH) -DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \
 | ||||
| 	-DELF_FORMAT="$(ELF_FORMAT)" -DKERNEL_STACK_SIZE=$(STACK_SIZE) | ||||
| 
 | ||||
| #The wrappers will select whether using "malloc" or the kernel allocator.
 | ||||
| LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc | ||||
|  |  | |||
|  | @ -2,11 +2,7 @@ core-y += arch/um/sys-i386/ arch/x86/crypto/ | |||
| 
 | ||||
| TOP_ADDR := $(CONFIG_TOP_ADDR) | ||||
| 
 | ||||
| ifeq ($(CONFIG_MODE_SKAS),y) | ||||
|   ifneq ($(CONFIG_MODE_TT),y) | ||||
|      START := 0x8048000 | ||||
|   endif | ||||
| endif | ||||
| START := 0x8048000 | ||||
| 
 | ||||
| LDFLAGS			+= -m elf_i386 | ||||
| ELF_ARCH		:= $(SUBARCH) | ||||
|  |  | |||
|  | @ -12,9 +12,7 @@ CONFIG_IRQ_RELEASE_METHOD=y | |||
| # | ||||
| # UML-specific options | ||||
| # | ||||
| # CONFIG_MODE_TT is not set | ||||
| # CONFIG_STATIC_LINK is not set | ||||
| CONFIG_MODE_SKAS=y | ||||
| 
 | ||||
| # | ||||
| # Host processor type and features | ||||
|  |  | |||
|  | @ -735,8 +735,6 @@ void mconsole_sysrq(struct mc_request *req) | |||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_SKAS | ||||
| 
 | ||||
| static void stack_proc(void *arg) | ||||
| { | ||||
| 	struct task_struct *from = current, *to = arg; | ||||
|  | @ -750,7 +748,7 @@ static void stack_proc(void *arg) | |||
|  *  Dumps a stacks registers to the linux console. | ||||
|  *  Usage stack <pid>. | ||||
|  */ | ||||
| static void do_stack_trace(struct mc_request *req) | ||||
| void mconsole_stack(struct mc_request *req) | ||||
| { | ||||
| 	char *ptr = req->request.data; | ||||
| 	int pid_requested= -1; | ||||
|  | @ -781,17 +779,6 @@ static void do_stack_trace(struct mc_request *req) | |||
| 	} | ||||
| 	with_console(req, stack_proc, to); | ||||
| } | ||||
| #endif /* CONFIG_MODE_SKAS */ | ||||
| 
 | ||||
| void mconsole_stack(struct mc_request *req) | ||||
| { | ||||
| 	/* This command doesn't work in TT mode, so let's check and then
 | ||||
| 	 * get out of here | ||||
| 	 */ | ||||
| 	CHOOSE_MODE(mconsole_reply(req, "Sorry, this doesn't work in TT mode", | ||||
| 				   1, 0), | ||||
| 		    do_stack_trace(req)); | ||||
| } | ||||
| 
 | ||||
| /* Changed by mconsole_setup, which is __setup, and called before SMP is
 | ||||
|  * active. | ||||
|  |  | |||
|  | @ -28,7 +28,6 @@ extern unsigned long _unprotected_end; | |||
| extern unsigned long brk_start; | ||||
| 
 | ||||
| extern int linux_main(int argc, char **argv); | ||||
| extern void set_cmdline(char *cmd); | ||||
| 
 | ||||
| extern void (*sig_info[])(int, union uml_pt_regs *); | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,26 +8,8 @@ | |||
| 
 | ||||
| #include "uml-config.h" | ||||
| 
 | ||||
| #if defined(UML_CONFIG_MODE_TT) && defined(UML_CONFIG_MODE_SKAS) | ||||
| #define CHOOSE_MODE(tt, skas) (mode_tt ? (tt) : (skas)) | ||||
| 
 | ||||
| extern int mode_tt; | ||||
| static inline void *__choose_mode(void *tt, void *skas) { | ||||
| 	return mode_tt ? tt : skas; | ||||
| } | ||||
| 
 | ||||
| #define __CHOOSE_MODE(tt, skas) (*( (typeof(tt) *) __choose_mode(&(tt), &(skas)))) | ||||
| 
 | ||||
| #elif defined(UML_CONFIG_MODE_SKAS) | ||||
| #define CHOOSE_MODE(tt, skas) (skas) | ||||
| 
 | ||||
| #elif defined(UML_CONFIG_MODE_TT) | ||||
| #define CHOOSE_MODE(tt, skas) (tt) | ||||
| 
 | ||||
| #else | ||||
| #error CONFIG_MODE_SKAS and CONFIG_MODE_TT are both disabled | ||||
| #endif | ||||
| 
 | ||||
| #define CHOOSE_MODE_PROC(tt, skas, args...) \ | ||||
| 	CHOOSE_MODE(tt(args), skas(args)) | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,9 +1,6 @@ | |||
| /* for use by sys-$SUBARCH/kernel-offsets.c */ | ||||
| 
 | ||||
| DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE); | ||||
| #ifdef CONFIG_MODE_TT | ||||
| OFFSET(HOST_TASK_EXTERN_PID, task_struct, thread.mode.tt.extern_pid); | ||||
| #endif | ||||
| 
 | ||||
| OFFSET(HOST_TASK_REGS, task_struct, thread.regs); | ||||
| OFFSET(HOST_TASK_PID, task_struct, pid); | ||||
|  |  | |||
|  | @ -30,8 +30,4 @@ extern void deactivate_fd(int fd, int irqnum); | |||
| extern int deactivate_all_fds(void); | ||||
| extern int activate_ipi(int fd, int pid); | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_TT | ||||
| extern void forward_interrupts(int pid); | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -34,9 +34,6 @@ extern int nsyscalls; | |||
| 	UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1) | ||||
| 
 | ||||
| extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg); | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| extern unsigned long stack_sp(unsigned long page); | ||||
| #endif | ||||
| extern int kernel_thread_proc(void *data); | ||||
| extern void syscall_segv(int sig); | ||||
| extern int current_pid(void); | ||||
|  | @ -82,9 +79,6 @@ extern void check_stack_overflow(void *ptr); | |||
| extern void relay_signal(int sig, union uml_pt_regs *regs); | ||||
| extern int user_context(unsigned long sp); | ||||
| extern void timer_irq(union uml_pt_regs *regs); | ||||
| #ifdef CONFIG_MODE_TT | ||||
| extern void unprotect_stack(unsigned long stack); | ||||
| #endif | ||||
| extern void do_uml_exitcalls(void); | ||||
| extern int attach_debugger(int idle_pid, int pid, int stop); | ||||
| extern int config_gdb(char *str); | ||||
|  |  | |||
|  | @ -6,25 +6,6 @@ | |||
| #ifndef __MODE_H__ | ||||
| #define __MODE_H__ | ||||
| 
 | ||||
| #include "uml-config.h" | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| #include "mode-tt.h" | ||||
| #endif | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_SKAS | ||||
| #include "mode-skas.h" | ||||
| #endif | ||||
| 
 | ||||
| #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: | ||||
|  */ | ||||
|  |  | |||
|  | @ -6,12 +6,6 @@ | |||
| #ifndef __MODE_KERN_H__ | ||||
| #define __MODE_KERN_H__ | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_TT | ||||
| #include "mode_kern_tt.h" | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_SKAS | ||||
| #include "mode_kern_skas.h" | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -178,11 +178,7 @@ extern void check_host_supports_tls(int *supports_tls, int *tls_min); | |||
| 
 | ||||
| /* Make sure they are clear when running in TT mode. Required by
 | ||||
|  * SEGV_MAYBE_FIXABLE */ | ||||
| #ifdef UML_CONFIG_MODE_SKAS | ||||
| #define clear_can_do_skas() do { ptrace_faultinfo = proc_mm = 0; } while (0) | ||||
| #else | ||||
| #define clear_can_do_skas() do {} while (0) | ||||
| #endif | ||||
| 
 | ||||
| /* mem.c */ | ||||
| extern int create_mem_file(unsigned long long len); | ||||
|  | @ -193,18 +189,11 @@ extern int os_process_parent(int pid); | |||
| extern void os_stop_process(int pid); | ||||
| extern void os_kill_process(int pid, int reap_child); | ||||
| extern void os_kill_ptraced_process(int pid, int reap_child); | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| extern void os_usr1_process(int pid); | ||||
| #endif | ||||
| extern long os_ptrace_ldt(long pid, long addr, long data); | ||||
| 
 | ||||
| extern int os_getpid(void); | ||||
| extern int os_getpgrp(void); | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)); | ||||
| extern void stop(void); | ||||
| #endif | ||||
| extern void init_new_thread_signals(void); | ||||
| extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr); | ||||
| 
 | ||||
|  | @ -217,18 +206,6 @@ extern int os_drop_memory(void *addr, int length); | |||
| extern int can_drop_memory(void); | ||||
| extern void os_flush_stdout(void); | ||||
| 
 | ||||
| /* tt.c
 | ||||
|  * for tt mode only (will be deleted in future...) | ||||
|  */ | ||||
| extern void forward_ipi(int fd, int pid); | ||||
| extern void kill_child_dead(int pid); | ||||
| extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); | ||||
| extern int protect_memory(unsigned long addr, unsigned long len, | ||||
| 			  int r, int w, int x, int must_succeed); | ||||
| extern void forward_pending_sigio(int target); | ||||
| extern int start_fork_tramp(void *arg, unsigned long temp_stack, | ||||
| 			    int clone_flags, int (*tramp)(void *)); | ||||
| 
 | ||||
| /* uaccess.c */ | ||||
| extern unsigned long __do_user_copy(void *to, const void *from, int n, | ||||
| 				    void **fault_addr, void **fault_catcher, | ||||
|  | @ -281,9 +258,6 @@ extern void os_dump_core(void); | |||
| extern void switch_timers(int to_real); | ||||
| extern void idle_sleep(int secs); | ||||
| extern int set_interval(int is_virtual); | ||||
| #ifdef CONFIG_MODE_TT | ||||
| extern void enable_timer(void); | ||||
| #endif | ||||
| extern void disable_timer(void); | ||||
| extern void uml_idle_timer(void); | ||||
| extern unsigned long long os_nsecs(void); | ||||
|  |  | |||
|  | @ -14,12 +14,7 @@ | |||
| #define MAX_REG_NR (UM_FRAME_SIZE / sizeof(unsigned long)) | ||||
| #define MAX_REG_OFFSET (UM_FRAME_SIZE) | ||||
| 
 | ||||
| #ifdef UML_CONFIG_PT_PROXY | ||||
| extern void update_debugregs(int seq); | ||||
| #else | ||||
| static inline void update_debugregs(int seq) {} | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| /* syscall emulation path in ptrace */ | ||||
| 
 | ||||
|  | @ -31,12 +26,6 @@ void set_using_sysemu(int value); | |||
| int get_using_sysemu(void); | ||||
| extern int sysemu_supported; | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| #include "sysdep/sc.h" | ||||
| #endif | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_SKAS | ||||
| 
 | ||||
| #include "skas_ptregs.h" | ||||
| 
 | ||||
| #define REGS_IP(r) ((r)[HOST_IP]) | ||||
|  | @ -60,20 +49,11 @@ extern int sysemu_supported; | |||
| 
 | ||||
| #define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r)) | ||||
| 
 | ||||
| #endif | ||||
| #ifndef PTRACE_SYSEMU_SINGLESTEP | ||||
| #define PTRACE_SYSEMU_SINGLESTEP 32 | ||||
| #endif | ||||
| 
 | ||||
| union uml_pt_regs { | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| 	struct tt_regs { | ||||
| 		long syscall; | ||||
| 		void *sc; | ||||
|                 struct faultinfo faultinfo; | ||||
| 	} tt; | ||||
| #endif | ||||
| #ifdef UML_CONFIG_MODE_SKAS | ||||
| 	struct skas_regs { | ||||
| 		unsigned long regs[MAX_REG_NR]; | ||||
| 		unsigned long fp[HOST_FP_SIZE]; | ||||
|  | @ -82,13 +62,10 @@ union uml_pt_regs { | |||
| 		long syscall; | ||||
| 		int is_user; | ||||
| 	} skas; | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| #define EMPTY_UML_PT_REGS { } | ||||
| 
 | ||||
| extern int mode_tt; | ||||
| 
 | ||||
| #define UPT_SC(r) ((r)->tt.sc) | ||||
| #define UPT_IP(r) \ | ||||
| 	__CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs)) | ||||
|  |  | |||
|  | @ -30,11 +30,7 @@ | |||
| #define SEGV_IS_FIXABLE(fi)	((fi)->trap_no == 14) | ||||
| 
 | ||||
| /* SKAS3 has no trap_no on i386, but get_skas_faultinfo() sets it to 0. */ | ||||
| #ifdef UML_CONFIG_MODE_SKAS | ||||
| #define SEGV_MAYBE_FIXABLE(fi)	((fi)->trap_no == 0 && ptrace_faultinfo) | ||||
| #else | ||||
| #define SEGV_MAYBE_FIXABLE(fi)	0 | ||||
| #endif | ||||
| 
 | ||||
| extern unsigned long *sc_sigmask(void *sc_ptr); | ||||
| extern int sc_get_fpregs(unsigned long buf, void *sc_ptr); | ||||
|  |  | |||
|  | @ -4,8 +4,5 @@ | |||
| #include <kern_constants.h> | ||||
| 
 | ||||
| #define TASK_DEBUGREGS(task) ((unsigned long *) &(((char *) (task))[HOST_TASK_DEBUGREGS])) | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| #define TASK_EXTERN_PID(task) *((int *) &(((char *) (task))[HOST_TASK_EXTERN_PID])) | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| /*
 | ||||
|  * Copyright 2003 PathScale, Inc. | ||||
|  * Copyright (C) 2003 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) | ||||
|  * | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
|  | @ -14,11 +15,6 @@ | |||
| #define MAX_REG_OFFSET (UM_FRAME_SIZE) | ||||
| #define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long)) | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| #include "sysdep/sc.h" | ||||
| #endif | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_SKAS | ||||
| #include "skas_ptregs.h" | ||||
| 
 | ||||
| #define REGS_IP(r) ((r)[HOST_IP]) | ||||
|  | @ -88,21 +84,10 @@ | |||
| 
 | ||||
| #define REGS_ERR(r) ((r)->fault_type) | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| #include "choose-mode.h" | ||||
| 
 | ||||
| /* XXX */ | ||||
| union uml_pt_regs { | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| 	struct tt_regs { | ||||
| 		long syscall; | ||||
| 		unsigned long orig_rax; | ||||
| 		void *sc; | ||||
|                 struct faultinfo faultinfo; | ||||
| 	} tt; | ||||
| #endif | ||||
| #ifdef UML_CONFIG_MODE_SKAS | ||||
| 	struct skas_regs { | ||||
| 		unsigned long regs[MAX_REG_NR]; | ||||
| 		unsigned long fp[HOST_FP_SIZE]; | ||||
|  | @ -110,14 +95,10 @@ union uml_pt_regs { | |||
| 		long syscall; | ||||
| 		int is_user; | ||||
| 	} skas; | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| #define EMPTY_UML_PT_REGS { } | ||||
| 
 | ||||
| /* XXX */ | ||||
| extern int mode_tt; | ||||
| 
 | ||||
| #define UPT_RBX(r) __CHOOSE_MODE(SC_RBX(UPT_SC(r)), REGS_RBX((r)->skas.regs)) | ||||
| #define UPT_RCX(r) __CHOOSE_MODE(SC_RCX(UPT_SC(r)), REGS_RCX((r)->skas.regs)) | ||||
| #define UPT_RDX(r) __CHOOSE_MODE(SC_RDX(UPT_SC(r)), REGS_RDX((r)->skas.regs)) | ||||
|  |  | |||
|  | @ -3,8 +3,4 @@ | |||
| 
 | ||||
| #include <kern_constants.h> | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| #define TASK_EXTERN_PID(task) *((int *) &(((char *) (task))[HOST_TASK_EXTERN_PID])) | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -1,18 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2000, 2001, 2002  Jeff Dike (jdike@karaya.com) and | ||||
|  * Lars Brinkhoff. | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __UML_TT_DEBUG_H | ||||
| #define __UML_TT_DEBUG_H | ||||
| 
 | ||||
| extern int debugger_proxy(int status, pid_t pid); | ||||
| extern void child_proxy(pid_t pid, int status); | ||||
| extern void init_proxy (pid_t pid, int waiting, int status); | ||||
| extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd); | ||||
| extern void fake_child_exit(void); | ||||
| extern int gdb_config(char *str); | ||||
| extern int gdb_remove(int unused); | ||||
| 
 | ||||
| #endif | ||||
|  | @ -1,12 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __TT_MMU_H | ||||
| #define __TT_MMU_H | ||||
| 
 | ||||
| struct mmu_context_tt { | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  | @ -1,23 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __MODE_TT_H__ | ||||
| #define __MODE_TT_H__ | ||||
| 
 | ||||
| #include "sysdep/ptrace.h" | ||||
| 
 | ||||
| enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB }; | ||||
| 
 | ||||
| extern int tracing_pid; | ||||
| 
 | ||||
| extern int tracer(int (*init_proc)(void *), void *sp); | ||||
| extern void sig_handler_common_tt(int sig, void *sc); | ||||
| extern void syscall_handler_tt(int sig, union uml_pt_regs *regs); | ||||
| extern void reboot_tt(void); | ||||
| extern void halt_tt(void); | ||||
| extern int is_tracer_winch(int pid, int fd, void *data); | ||||
| extern void kill_off_processes_tt(void); | ||||
| 
 | ||||
| #endif | ||||
|  | @ -1,40 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __TT_MODE_KERN_H__ | ||||
| #define __TT_MODE_KERN_H__ | ||||
| 
 | ||||
| #include "linux/sched.h" | ||||
| #include "asm/page.h" | ||||
| #include "asm/ptrace.h" | ||||
| #include "asm/uaccess.h" | ||||
| 
 | ||||
| extern void switch_to_tt(void *prev, void *next); | ||||
| extern void flush_thread_tt(void); | ||||
| extern void start_thread_tt(struct pt_regs *regs, unsigned long eip, | ||||
| 			   unsigned long esp); | ||||
| extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, | ||||
| 			  unsigned long stack_top, struct task_struct *p, | ||||
| 			  struct pt_regs *regs); | ||||
| extern void release_thread_tt(struct task_struct *task); | ||||
| extern void initial_thread_cb_tt(void (*proc)(void *), void *arg); | ||||
| extern void init_idle_tt(void); | ||||
| extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end); | ||||
| extern void flush_tlb_kernel_vm_tt(void); | ||||
| extern void __flush_tlb_one_tt(unsigned long addr); | ||||
| extern void flush_tlb_range_tt(struct vm_area_struct *vma, | ||||
| 			       unsigned long start, unsigned long end); | ||||
| extern void flush_tlb_mm_tt(struct mm_struct *mm); | ||||
| extern void force_flush_all_tt(void); | ||||
| extern long execute_syscall_tt(void *r); | ||||
| extern void before_mem_tt(unsigned long brk_start); | ||||
| extern unsigned long set_task_sizes_tt(unsigned long *task_size_out); | ||||
| extern int start_uml_tt(void); | ||||
| extern int external_pid_tt(struct task_struct *task); | ||||
| extern int thread_pid_tt(struct task_struct *task); | ||||
| 
 | ||||
| #define kmem_end_tt (host_task_size - ABOVE_KMEM) | ||||
| 
 | ||||
| #endif | ||||
|  | @ -1,37 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __TT_H__ | ||||
| #define __TT_H__ | ||||
| 
 | ||||
| #include "sysdep/ptrace.h" | ||||
| 
 | ||||
| extern int gdb_pid; | ||||
| extern int debug; | ||||
| extern int debug_stop; | ||||
| extern int debug_trace; | ||||
| 
 | ||||
| extern int honeypot; | ||||
| 
 | ||||
| extern int fork_tramp(void *sig_stack); | ||||
| extern int do_proc_op(void *t, int proc_id); | ||||
| extern int tracer(int (*init_proc)(void *), void *sp); | ||||
| extern void attach_process(int pid); | ||||
| extern void tracer_panic(char *format, ...) | ||||
| 	__attribute__ ((format (printf, 1, 2))); | ||||
| extern void set_init_pid(int pid); | ||||
| extern int set_user_mode(void *task); | ||||
| extern void set_tracing(void *t, int tracing); | ||||
| extern int is_tracing(void *task); | ||||
| extern void syscall_handler(int sig, union uml_pt_regs *regs); | ||||
| extern void exit_kernel(int pid, void *task); | ||||
| extern void do_syscall(void *task, int pid, int local_using_sysemu); | ||||
| extern void do_sigtrap(void *task); | ||||
| extern int is_valid_pid(int pid); | ||||
| extern void remap_data(void *segment_start, void *segment_end, int w); | ||||
| extern long execute_syscall_tt(void *r); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
|  | @ -1,46 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __TT_UACCESS_H | ||||
| #define __TT_UACCESS_H | ||||
| 
 | ||||
| #include "linux/string.h" | ||||
| #include "linux/sched.h" | ||||
| #include "asm/processor.h" | ||||
| #include "asm/errno.h" | ||||
| #include "asm/current.h" | ||||
| #include "asm/a.out.h" | ||||
| #include "uml_uaccess.h" | ||||
| 
 | ||||
| #define ABOVE_KMEM (16 * 1024 * 1024) | ||||
| 
 | ||||
| extern unsigned long end_vm; | ||||
| extern unsigned long uml_physmem; | ||||
| 
 | ||||
| #define is_stack(addr, size) \ | ||||
| 	(((unsigned long) (addr) < STACK_TOP) && \ | ||||
| 	 ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \ | ||||
| 	 (((unsigned long) (addr) + (size)) <= STACK_TOP)) | ||||
| 
 | ||||
| #define access_ok_tt(type, addr, size) \ | ||||
| 	(is_stack(addr, size)) | ||||
| 
 | ||||
| extern int __do_copy_from_user(void *to, const void *from, int n, | ||||
| 			       void **fault_addr, void **fault_catcher); | ||||
| extern int __do_strncpy_from_user(char *dst, const char *src, size_t n, | ||||
| 				  void **fault_addr, void **fault_catcher); | ||||
| extern int __do_clear_user(void *mem, size_t len, void **fault_addr, | ||||
| 			   void **fault_catcher); | ||||
| extern int __do_strnlen_user(const char *str, unsigned long n, | ||||
| 			     void **fault_addr, void **fault_catcher); | ||||
| 
 | ||||
| extern int copy_from_user_tt(void *to, const void __user *from, int n); | ||||
| extern int copy_to_user_tt(void __user *to, const void *from, int n); | ||||
| extern int strncpy_from_user_tt(char *dst, const char __user *src, int count); | ||||
| extern int __clear_user_tt(void __user *mem, int len); | ||||
| extern int clear_user_tt(void __user *mem, int len); | ||||
| extern int strnlen_user_tt(const void __user *str, int len); | ||||
| 
 | ||||
| #endif | ||||
|  | @ -8,33 +8,10 @@ | |||
| 
 | ||||
| #include "uml-config.h" | ||||
| #include "choose-mode.h" | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| #include "mmu-tt.h" | ||||
| #endif | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_SKAS | ||||
| #include "mmu-skas.h" | ||||
| #endif | ||||
| 
 | ||||
| typedef union mm_context { | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| 	struct mmu_context_tt tt; | ||||
| #endif | ||||
| #ifdef UML_CONFIG_MODE_SKAS | ||||
| 	struct mmu_context_skas skas; | ||||
| #endif | ||||
| } mm_context_t; | ||||
| 
 | ||||
| #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: | ||||
|  */ | ||||
|  |  | |||
|  | @ -7,15 +7,7 @@ | |||
| #define __ARCH_UM_UACCESS_H | ||||
| 
 | ||||
| #include "choose-mode.h" | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_TT | ||||
| #include "uaccess-tt.h" | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_SKAS | ||||
| #include "uaccess-skas.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "asm/fixmap.h" | ||||
| 
 | ||||
| #define __under_task_size(addr, size) \ | ||||
|  |  | |||
|  | @ -9,15 +9,12 @@ clean-files := | |||
| obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \
 | ||||
| 	physmem.o process.o ptrace.o reboot.o sigio.o \
 | ||||
| 	signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o uaccess.o \
 | ||||
| 	um_arch.o umid.o | ||||
| 	um_arch.o umid.o skas/ | ||||
| 
 | ||||
| obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o | ||||
| obj-$(CONFIG_GPROF)	+= gprof_syms.o | ||||
| obj-$(CONFIG_GCOV)	+= gmon_syms.o | ||||
| 
 | ||||
| obj-$(CONFIG_MODE_TT) += tt/ | ||||
| obj-$(CONFIG_MODE_SKAS) += skas/ | ||||
| 
 | ||||
| USER_OBJS := config.o | ||||
| 
 | ||||
| include arch/um/scripts/Makefile.rules | ||||
|  |  | |||
|  | @ -10,8 +10,6 @@ SECTIONS | |||
|   PROVIDE (__executable_start = START);
 | ||||
|   . = START + SIZEOF_HEADERS;
 | ||||
|   .interp         : { *(.interp) } | ||||
|   /* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start | ||||
|    * is remapped.*/ | ||||
|   __binary_start = .;
 | ||||
|   . = ALIGN(4096);		/* Init code and data */
 | ||||
|   _text = .;
 | ||||
|  |  | |||
|  | @ -57,7 +57,6 @@ static long execve1(char *file, char __user * __user *argv, | |||
| 		SUBARCH_EXECVE1(¤t->thread.regs.regs); | ||||
| #endif | ||||
| 		task_unlock(current); | ||||
|                 set_cmdline(current_cmd()); | ||||
|         } | ||||
|         return(error); | ||||
| } | ||||
|  |  | |||
|  | @ -46,10 +46,3 @@ union thread_union init_thread_union | |||
| union thread_union cpu0_irqstack | ||||
| 	__attribute__((__section__(".data.init_irqstack"))) = | ||||
| 		{ INIT_THREAD_INFO(init_task) }; | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_TT | ||||
| void unprotect_stack(unsigned long stack) | ||||
| { | ||||
| 	os_protect_memory((void *) stack, THREAD_SIZE, 1, 1, 0); | ||||
| } | ||||
| #endif | ||||
|  |  | |||
|  | @ -339,30 +339,6 @@ int deactivate_all_fds(void) | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_TT | ||||
| void forward_interrupts(int pid) | ||||
| { | ||||
| 	struct irq_fd *irq; | ||||
| 	unsigned long flags; | ||||
| 	int err; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&irq_lock, flags); | ||||
| 	for (irq = active_fds; irq != NULL; irq = irq->next) { | ||||
| 		err = os_set_owner(irq->fd, pid); | ||||
| 		if (err < 0) { | ||||
| 			/* XXX Just remove the irq rather than
 | ||||
| 			 * print out an infinite stream of these | ||||
| 			 */ | ||||
| 			printk("Failed to forward %d to pid %d, err = %d\n", | ||||
| 			       irq->fd, pid, -err); | ||||
| 		} | ||||
| 
 | ||||
| 		irq->pid = pid; | ||||
| 	} | ||||
| 	spin_unlock_irqrestore(&irq_lock, flags); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * do_IRQ handles all normal device IRQ's (the special | ||||
|  * SMP cross-CPU interrupts have their own specific | ||||
|  |  | |||
|  | @ -34,24 +34,14 @@ EXPORT_SYMBOL(get_kmem_end); | |||
| EXPORT_SYMBOL(high_physmem); | ||||
| EXPORT_SYMBOL(empty_zero_page); | ||||
| EXPORT_SYMBOL(um_virt_to_phys); | ||||
| EXPORT_SYMBOL(mode_tt); | ||||
| EXPORT_SYMBOL(handle_page_fault); | ||||
| EXPORT_SYMBOL(find_iomem); | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_TT | ||||
| EXPORT_SYMBOL(stop); | ||||
| EXPORT_SYMBOL(strncpy_from_user_tt); | ||||
| EXPORT_SYMBOL(copy_from_user_tt); | ||||
| EXPORT_SYMBOL(copy_to_user_tt); | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_SKAS | ||||
| EXPORT_SYMBOL(strnlen_user_skas); | ||||
| EXPORT_SYMBOL(strncpy_from_user_skas); | ||||
| EXPORT_SYMBOL(copy_to_user_skas); | ||||
| EXPORT_SYMBOL(copy_from_user_skas); | ||||
| EXPORT_SYMBOL(clear_user_skas); | ||||
| #endif | ||||
| EXPORT_SYMBOL(uml_strdup); | ||||
| 
 | ||||
| EXPORT_SYMBOL(os_stat_fd); | ||||
|  |  | |||
|  | @ -183,13 +183,6 @@ void initial_thread_cb(void (*proc)(void *), void *arg) | |||
| 	kmalloc_ok = save_kmalloc_ok; | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_TT | ||||
| unsigned long stack_sp(unsigned long page) | ||||
| { | ||||
| 	return page + PAGE_SIZE - sizeof(void *); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| void default_idle(void) | ||||
| { | ||||
| 	CHOOSE_MODE(uml_idle_timer(), (void) 0); | ||||
|  |  | |||
|  | @ -14,28 +14,9 @@ | |||
| 
 | ||||
| void (*pm_power_off)(void); | ||||
| 
 | ||||
| #ifdef CONFIG_SMP | ||||
| static void kill_idlers(int me) | ||||
| { | ||||
| #ifdef CONFIG_MODE_TT | ||||
| 	struct task_struct *p; | ||||
| 	int i; | ||||
| 
 | ||||
| 	for(i = 0; i < ARRAY_SIZE(idle_threads); i++){ | ||||
| 		p = idle_threads[i]; | ||||
| 		if((p != NULL) && (p->thread.mode.tt.extern_pid != me)) | ||||
| 			os_kill_process(p->thread.mode.tt.extern_pid, 0); | ||||
| 	} | ||||
| #endif | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static void kill_off_processes(void) | ||||
| { | ||||
| 	CHOOSE_MODE(kill_off_processes_tt(), kill_off_processes_skas()); | ||||
| #ifdef CONFIG_SMP | ||||
| 	kill_idlers(os_getpid()); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void uml_cleanup(void) | ||||
|  |  | |||
|  | @ -95,7 +95,6 @@ static int idle_proc(void *cpup) | |||
| static struct task_struct *idle_thread(int cpu) | ||||
| { | ||||
| 	struct task_struct *new_task; | ||||
| 	unsigned char c; | ||||
| 
 | ||||
| 	current->thread.request.u.thread.proc = idle_proc; | ||||
| 	current->thread.request.u.thread.arg = (void *) cpu; | ||||
|  | @ -108,9 +107,7 @@ static struct task_struct *idle_thread(int cpu) | |||
| 		          { .pid = 	new_task->thread.mode.tt.extern_pid, | ||||
| 			    .task = 	new_task } ); | ||||
| 	idle_threads[cpu] = new_task; | ||||
| 	CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c, | ||||
| 				  sizeof(c)), | ||||
| 		    ({ panic("skas mode doesn't support SMP"); })); | ||||
| 	panic("skas mode doesn't support SMP"); | ||||
| 	return new_task; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -29,9 +29,7 @@ | |||
| #include "sysdep/sigcontext.h" | ||||
| #include "sysdep/ptrace.h" | ||||
| #include "os.h" | ||||
| #ifdef CONFIG_MODE_SKAS | ||||
| #include "skas.h" | ||||
| #endif | ||||
| #include "os.h" | ||||
| 
 | ||||
| /* Note this is constrained to return 0, -EFAULT, -EACCESS, -ENOMEM by segv(). */ | ||||
|  |  | |||
|  | @ -1,14 +0,0 @@ | |||
| # 
 | ||||
| # Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
 | ||||
| # Licensed under the GPL
 | ||||
| #
 | ||||
| 
 | ||||
| obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \
 | ||||
| 	syscall_kern.o syscall_user.o tlb.o tracer.o trap_user.o \
 | ||||
| 	uaccess.o uaccess_user.o | ||||
| 
 | ||||
| obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/ | ||||
| 
 | ||||
| USER_OBJS := gdb.o tracer.o | ||||
| 
 | ||||
| include arch/um/scripts/Makefile.rules | ||||
|  | @ -1,84 +0,0 @@ | |||
| /* 
 | ||||
|  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include "linux/kernel.h" | ||||
| #include "linux/mm.h" | ||||
| #include "asm/signal.h" | ||||
| #include "asm/ptrace.h" | ||||
| #include "asm/uaccess.h" | ||||
| #include "asm/pgalloc.h" | ||||
| #include "asm/tlbflush.h" | ||||
| #include "kern_util.h" | ||||
| #include "irq_user.h" | ||||
| #include "mem_user.h" | ||||
| #include "os.h" | ||||
| #include "tlb.h" | ||||
| #include "mode.h" | ||||
| 
 | ||||
| static int exec_tramp(void *sig_stack) | ||||
| { | ||||
| 	init_new_thread_stack(sig_stack, NULL); | ||||
| 	init_new_thread_signals(); | ||||
| 	os_stop_process(os_getpid()); | ||||
| 	return(0); | ||||
| } | ||||
| 
 | ||||
| void flush_thread_tt(void) | ||||
| { | ||||
| 	unsigned long stack; | ||||
| 	int new_pid; | ||||
| 
 | ||||
| 	stack = alloc_stack(0, 0); | ||||
| 	if(stack == 0){ | ||||
| 		printk(KERN_ERR  | ||||
| 		       "flush_thread : failed to allocate temporary stack\n"); | ||||
| 		do_exit(SIGKILL); | ||||
| 	} | ||||
| 		 | ||||
| 	new_pid = start_fork_tramp(task_stack_page(current), stack, 0, exec_tramp); | ||||
| 	if(new_pid < 0){ | ||||
| 		printk(KERN_ERR  | ||||
| 		       "flush_thread : new thread failed, errno = %d\n", | ||||
| 		       -new_pid); | ||||
| 		do_exit(SIGKILL); | ||||
| 	} | ||||
| 
 | ||||
| 	if(current_thread->cpu == 0) | ||||
| 		forward_interrupts(new_pid); | ||||
| 	current->thread.request.op = OP_EXEC; | ||||
| 	current->thread.request.u.exec.pid = new_pid; | ||||
| 	unprotect_stack((unsigned long) current_thread); | ||||
| 	os_usr1_process(os_getpid()); | ||||
| 	change_sig(SIGUSR1, 1); | ||||
| 
 | ||||
| 	change_sig(SIGUSR1, 0); | ||||
| 	enable_timer(); | ||||
| 	free_page(stack); | ||||
| 	protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); | ||||
| 	stack_protections((unsigned long) current_thread); | ||||
| 	force_flush_all(); | ||||
| 	unblock_signals(); | ||||
| } | ||||
| 
 | ||||
| void start_thread_tt(struct pt_regs *regs, unsigned long eip,  | ||||
| 		     unsigned long esp) | ||||
| { | ||||
| 	set_fs(USER_DS); | ||||
| 	flush_tlb_mm(current->mm); | ||||
| 	PT_REGS_IP(regs) = eip; | ||||
| 	PT_REGS_SP(regs) = esp; | ||||
| 	PT_FIX_EXEC_STACK(esp); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * 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: | ||||
|  */ | ||||
|  | @ -1,56 +0,0 @@ | |||
| /* 
 | ||||
|  * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <stdlib.h> | ||||
| #include <sched.h> | ||||
| #include <errno.h> | ||||
| #include <sys/wait.h> | ||||
| #include <signal.h> | ||||
| #include "kern_util.h" | ||||
| #include "user.h" | ||||
| #include "ptrace_user.h" | ||||
| #include "os.h" | ||||
| 
 | ||||
| void do_exec(int old_pid, int new_pid) | ||||
| { | ||||
| 	unsigned long regs[FRAME_SIZE]; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) || | ||||
| 	   (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0)) | ||||
| 		tracer_panic("do_exec failed to attach proc - errno = %d", | ||||
| 			     errno); | ||||
| 
 | ||||
| 	CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED)); | ||||
| 	if (err < 0) | ||||
| 		tracer_panic("do_exec failed to attach proc in waitpid - errno = %d", | ||||
| 			     errno); | ||||
| 
 | ||||
| 	if(ptrace_getregs(old_pid, regs) < 0) | ||||
| 		tracer_panic("do_exec failed to get registers - errno = %d", | ||||
| 			     errno); | ||||
| 
 | ||||
| 	os_kill_ptraced_process(old_pid, 0); | ||||
| 
 | ||||
| 	if (ptrace(PTRACE_OLDSETOPTIONS, new_pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) | ||||
| 		tracer_panic("do_exec: PTRACE_SETOPTIONS failed, errno = %d", errno); | ||||
| 
 | ||||
| 	if(ptrace_setregs(new_pid, regs) < 0) | ||||
| 		tracer_panic("do_exec failed to start new proc - errno = %d", | ||||
| 			     errno); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * 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: | ||||
|  */ | ||||
|  | @ -1,280 +0,0 @@ | |||
| /* 
 | ||||
|  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <errno.h> | ||||
| #include <string.h> | ||||
| #include <signal.h> | ||||
| #include <sys/types.h> | ||||
| #include "ptrace_user.h" | ||||
| #include "uml-config.h" | ||||
| #include "kern_constants.h" | ||||
| #include "chan_user.h" | ||||
| #include "init.h" | ||||
| #include "user.h" | ||||
| #include "debug.h" | ||||
| #include "kern_util.h" | ||||
| #include "tt.h" | ||||
| #include "sysdep/thread.h" | ||||
| #include "os.h" | ||||
| 
 | ||||
| extern int debugger_pid; | ||||
| extern int debugger_fd; | ||||
| extern int debugger_parent; | ||||
| 
 | ||||
| int detach(int pid, int sig) | ||||
| { | ||||
| 	return(ptrace(PTRACE_DETACH, pid, 0, sig)); | ||||
| } | ||||
| 
 | ||||
| int attach(int pid) | ||||
| { | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = ptrace(PTRACE_ATTACH, pid, 0, 0); | ||||
| 	if(err < 0) return(-errno); | ||||
| 	else return(err); | ||||
| } | ||||
| 
 | ||||
| int cont(int pid) | ||||
| { | ||||
| 	return(ptrace(PTRACE_CONT, pid, 0, 0)); | ||||
| } | ||||
| 
 | ||||
| #ifdef UML_CONFIG_PT_PROXY | ||||
| 
 | ||||
| int debugger_signal(int status, pid_t pid) | ||||
| { | ||||
| 	return(debugger_proxy(status, pid)); | ||||
| } | ||||
| 
 | ||||
| void child_signal(pid_t pid, int status) | ||||
| { | ||||
| 	child_proxy(pid, status); | ||||
| } | ||||
| 
 | ||||
| static void gdb_announce(char *dev_name, int dev) | ||||
| { | ||||
| 	printf("gdb assigned device '%s'\n", dev_name); | ||||
| } | ||||
| 
 | ||||
| static struct chan_opts opts = { | ||||
| 	.announce  	= gdb_announce, | ||||
| 	.xterm_title 	= "UML kernel debugger", | ||||
| 	.raw 		= 0, | ||||
| 	.tramp_stack 	= 0, | ||||
| 	.in_kernel  	= 0, | ||||
| }; | ||||
| 
 | ||||
| /* Accessed by the tracing thread, which automatically serializes access */ | ||||
| static void *xterm_data; | ||||
| static int xterm_fd; | ||||
| 
 | ||||
| extern void *xterm_init(char *, int, struct chan_opts *); | ||||
| extern int xterm_open(int, int, int, void *, char **); | ||||
| extern void xterm_close(int, void *); | ||||
| 
 | ||||
| int open_gdb_chan(void) | ||||
| { | ||||
| 	char stack[UM_KERN_PAGE_SIZE], *dummy; | ||||
| 
 | ||||
| 	opts.tramp_stack = (unsigned long) stack; | ||||
| 	xterm_data = xterm_init("", 0, &opts); | ||||
| 	xterm_fd = xterm_open(1, 1, 1, xterm_data, &dummy); | ||||
| 	return(xterm_fd); | ||||
| } | ||||
| 
 | ||||
| static void exit_debugger_cb(void *unused) | ||||
| { | ||||
| 	if(debugger_pid != -1){ | ||||
| 		if(gdb_pid != -1){ | ||||
| 			fake_child_exit(); | ||||
| 			gdb_pid = -1; | ||||
| 		} | ||||
| 		else kill_child_dead(debugger_pid); | ||||
| 		debugger_pid = -1; | ||||
| 		if(debugger_parent != -1) | ||||
| 			detach(debugger_parent, SIGINT); | ||||
| 	} | ||||
| 	if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data); | ||||
| } | ||||
| 
 | ||||
| static void exit_debugger(void) | ||||
| { | ||||
| 	initial_thread_cb(exit_debugger_cb, NULL); | ||||
| } | ||||
| 
 | ||||
| __uml_exitcall(exit_debugger); | ||||
| 
 | ||||
| struct gdb_data { | ||||
| 	char *str; | ||||
| 	int err; | ||||
| }; | ||||
| 
 | ||||
| extern char *linux_prog; | ||||
| 
 | ||||
| static void config_gdb_cb(void *arg) | ||||
| { | ||||
| 	struct gdb_data *data = arg; | ||||
| 	void *task; | ||||
| 	int pid; | ||||
| 
 | ||||
| 	data->err = -1; | ||||
| 	if(debugger_pid != -1) exit_debugger_cb(NULL); | ||||
| 	if(!strncmp(data->str, "pid,", strlen("pid,"))){ | ||||
| 		data->str += strlen("pid,"); | ||||
| 		pid = strtoul(data->str, NULL, 0); | ||||
| 		task = cpu_tasks[0].task; | ||||
| 		debugger_pid = attach_debugger(TASK_EXTERN_PID(task), pid, 0); | ||||
| 		if(debugger_pid != -1){ | ||||
| 			data->err = 0; | ||||
| 			gdb_pid = pid; | ||||
| 		} | ||||
| 		return; | ||||
| 	} | ||||
| 	data->err = 0; | ||||
| 	debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd); | ||||
| 	init_proxy(debugger_pid, 0, 0); | ||||
| } | ||||
| 
 | ||||
| int gdb_config(char *str, char **error_out) | ||||
| { | ||||
| 	struct gdb_data data; | ||||
| 
 | ||||
| 	if(*str++ != '=') return(-1); | ||||
| 	data.str = str; | ||||
| 	initial_thread_cb(config_gdb_cb, &data); | ||||
| 	return(data.err); | ||||
| } | ||||
| 
 | ||||
| void remove_gdb_cb(void *unused) | ||||
| { | ||||
| 	exit_debugger_cb(NULL); | ||||
| } | ||||
| 
 | ||||
| int gdb_remove(int unused, char **error_out) | ||||
| { | ||||
| 	initial_thread_cb(remove_gdb_cb, NULL); | ||||
|         return 0; | ||||
| } | ||||
| 
 | ||||
| void signal_usr1(int sig) | ||||
| { | ||||
| 	if(debugger_pid != -1){ | ||||
| 		printf("The debugger is already running\n"); | ||||
| 		return; | ||||
| 	} | ||||
| 	debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd); | ||||
| 	init_proxy(debugger_pid, 0, 0); | ||||
| } | ||||
| 
 | ||||
| int init_ptrace_proxy(int idle_pid, int startup, int stop) | ||||
| { | ||||
| 	int pid, status; | ||||
| 
 | ||||
| 	pid = start_debugger(linux_prog, startup, stop, &debugger_fd); | ||||
| 	status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL); | ||||
|  	if(pid < 0){ | ||||
| 		cont(idle_pid); | ||||
| 		return(-1); | ||||
| 	} | ||||
| 	init_proxy(pid, 1, status); | ||||
| 	return(pid); | ||||
| } | ||||
| 
 | ||||
| int attach_debugger(int idle_pid, int pid, int stop) | ||||
| { | ||||
| 	int status = 0, err; | ||||
| 
 | ||||
| 	err = attach(pid); | ||||
| 	if(err < 0){ | ||||
| 		printf("Failed to attach pid %d, errno = %d\n", pid, -err); | ||||
| 		return(-1); | ||||
| 	} | ||||
| 	if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL); | ||||
| 	init_proxy(pid, 1, status); | ||||
| 	return(pid); | ||||
| } | ||||
| 
 | ||||
| #ifdef notdef /* Put this back in when it does something useful */ | ||||
| static int __init uml_gdb_init_setup(char *line, int *add) | ||||
| { | ||||
| 	gdb_init = uml_strdup(line); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| __uml_setup("gdb=", uml_gdb_init_setup,  | ||||
| "gdb=<channel description>\n\n" | ||||
| ); | ||||
| #endif | ||||
| 
 | ||||
| static int __init uml_gdb_pid_setup(char *line, int *add) | ||||
| { | ||||
| 	gdb_pid = strtoul(line, NULL, 0); | ||||
| 	*add = 0; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| __uml_setup("gdb-pid=", uml_gdb_pid_setup,  | ||||
| "gdb-pid=<pid>\n" | ||||
| "    gdb-pid is used to attach an external debugger to UML.  This may be\n" | ||||
| "    an already-running gdb or a debugger-like process like strace.\n\n" | ||||
| ); | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| int debugger_signal(int status, pid_t pid){ return(0); } | ||||
| void child_signal(pid_t pid, int status){ } | ||||
| int init_ptrace_proxy(int idle_pid, int startup, int stop) | ||||
| { | ||||
| 	printf("debug requested when CONFIG_PT_PROXY is off\n"); | ||||
| 	kill_child_dead(idle_pid); | ||||
| 	exit(1); | ||||
| } | ||||
| 
 | ||||
| void signal_usr1(int sig) | ||||
| { | ||||
| 	printf("debug requested when CONFIG_PT_PROXY is off\n"); | ||||
| } | ||||
| 
 | ||||
| int attach_debugger(int idle_pid, int pid, int stop) | ||||
| { | ||||
| 	printf("attach_debugger called when CONFIG_PT_PROXY " | ||||
| 	       "is off\n"); | ||||
| 	return(-1); | ||||
| } | ||||
| 
 | ||||
| int config_gdb(char *str) | ||||
| { | ||||
| 	return(-1); | ||||
| } | ||||
| 
 | ||||
| int remove_gdb(void) | ||||
| { | ||||
| 	return(-1); | ||||
| } | ||||
| 
 | ||||
| int init_parent_proxy(int pid) | ||||
| { | ||||
| 	return(-1); | ||||
| } | ||||
| 
 | ||||
| void debugger_parent_signal(int status, 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: | ||||
|  */ | ||||
|  | @ -1,40 +0,0 @@ | |||
| /* 
 | ||||
|  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include "linux/init.h" | ||||
| #include "mconsole_kern.h" | ||||
| 
 | ||||
| #ifdef CONFIG_MCONSOLE | ||||
| 
 | ||||
| extern int gdb_config(char *str, char **error_out); | ||||
| extern int gdb_remove(int n, char **error_out); | ||||
| 
 | ||||
| static struct mc_device gdb_mc = { | ||||
| 	.list		= INIT_LIST_HEAD(gdb_mc.list), | ||||
| 	.name		= "gdb", | ||||
| 	.config		= gdb_config, | ||||
| 	.remove		= gdb_remove, | ||||
| }; | ||||
| 
 | ||||
| int gdb_mc_init(void) | ||||
| { | ||||
| 	mconsole_register_dev(&gdb_mc); | ||||
| 	return(0); | ||||
| } | ||||
| 
 | ||||
| __initcall(gdb_mc_init); | ||||
| 
 | ||||
| #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: | ||||
|  */ | ||||
|  | @ -1,34 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __MODE_TT_H__ | ||||
| #define __MODE_TT_H__ | ||||
| 
 | ||||
| #include "sysdep/ptrace.h" | ||||
| 
 | ||||
| enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB }; | ||||
| 
 | ||||
| extern int tracing_pid; | ||||
| 
 | ||||
| extern int tracer(int (*init_proc)(void *), void *sp); | ||||
| extern void sig_handler_common_tt(int sig, void *sc); | ||||
| extern void syscall_handler_tt(int sig, union uml_pt_regs *regs); | ||||
| extern void reboot_tt(void); | ||||
| extern void halt_tt(void); | ||||
| extern int is_tracer_winch(int pid, int fd, void *data); | ||||
| extern void kill_off_processes_tt(void); | ||||
| 
 | ||||
| #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: | ||||
|  */ | ||||
|  | @ -1,29 +0,0 @@ | |||
| /* 
 | ||||
|  * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include "linux/module.h" | ||||
| #include "asm/uaccess.h" | ||||
| #include "mode.h" | ||||
| 
 | ||||
| EXPORT_SYMBOL(__do_copy_from_user); | ||||
| EXPORT_SYMBOL(__do_copy_to_user); | ||||
| EXPORT_SYMBOL(__do_strncpy_from_user); | ||||
| EXPORT_SYMBOL(__do_strnlen_user);  | ||||
| EXPORT_SYMBOL(__do_clear_user); | ||||
| EXPORT_SYMBOL(clear_user_tt); | ||||
| 
 | ||||
| EXPORT_SYMBOL(tracing_pid); | ||||
| EXPORT_SYMBOL(honeypot); | ||||
| 
 | ||||
| /*
 | ||||
|  * 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: | ||||
|  */ | ||||
|  | @ -1,34 +0,0 @@ | |||
| /* 
 | ||||
|  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include "linux/stddef.h" | ||||
| #include "linux/mm.h" | ||||
| #include "asm/uaccess.h" | ||||
| #include "mem_user.h" | ||||
| #include "kern_util.h" | ||||
| #include "kern.h" | ||||
| #include "tt.h" | ||||
| 
 | ||||
| void before_mem_tt(unsigned long brk_start) | ||||
| { | ||||
| 	if(debug) | ||||
| 		remap_data(UML_ROUND_DOWN(&_stext), UML_ROUND_UP(&_etext), 1); | ||||
| 	remap_data(UML_ROUND_DOWN(&_sdata), UML_ROUND_UP(&_edata), 1); | ||||
| 	remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(&_end), 1); | ||||
| } | ||||
| 
 | ||||
| #define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000) | ||||
| #define START (CONFIG_TOP_ADDR - SIZE) | ||||
| 
 | ||||
| unsigned long set_task_sizes_tt(unsigned long *task_size_out) | ||||
| { | ||||
| 	unsigned long host_task_size; | ||||
| 
 | ||||
| 	/* Round up to the nearest 4M */ | ||||
| 	host_task_size = ROUND_4M((unsigned long) &host_task_size); | ||||
| 	*task_size_out = START; | ||||
| 
 | ||||
| 	return host_task_size; | ||||
| } | ||||
|  | @ -1,49 +0,0 @@ | |||
| /* 
 | ||||
|  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <string.h> | ||||
| #include <errno.h> | ||||
| #include <sys/mman.h> | ||||
| #include "tt.h" | ||||
| #include "mem_user.h" | ||||
| #include "os.h" | ||||
| 
 | ||||
| void remap_data(void *segment_start, void *segment_end, int w) | ||||
| { | ||||
| 	void *addr; | ||||
| 	unsigned long size; | ||||
| 	int data, prot; | ||||
| 
 | ||||
| 	if(w) prot = PROT_WRITE; | ||||
| 	else prot = 0; | ||||
| 	prot |= PROT_READ | PROT_EXEC; | ||||
| 	size = (unsigned long) segment_end -  | ||||
| 		(unsigned long) segment_start; | ||||
| 	data = create_mem_file(size); | ||||
| 	addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, data, 0); | ||||
| 	if(addr == MAP_FAILED){ | ||||
| 		perror("mapping new data segment"); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	memcpy(addr, segment_start, size); | ||||
| 	if(switcheroo(data, prot, addr, segment_start, size) < 0){ | ||||
| 		printf("switcheroo failed\n"); | ||||
| 		exit(1); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * 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: | ||||
|  */ | ||||
|  | @ -1,461 +0,0 @@ | |||
| /* 
 | ||||
|  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include "linux/sched.h" | ||||
| #include "linux/signal.h" | ||||
| #include "linux/kernel.h" | ||||
| #include "linux/interrupt.h" | ||||
| #include "linux/ptrace.h" | ||||
| #include "asm/system.h" | ||||
| #include "asm/pgalloc.h" | ||||
| #include "asm/ptrace.h" | ||||
| #include "asm/tlbflush.h" | ||||
| #include "irq_user.h" | ||||
| #include "kern_util.h" | ||||
| #include "os.h" | ||||
| #include "kern.h" | ||||
| #include "sigcontext.h" | ||||
| #include "mem_user.h" | ||||
| #include "tlb.h" | ||||
| #include "mode.h" | ||||
| #include "mode_kern.h" | ||||
| #include "init.h" | ||||
| #include "tt.h" | ||||
| 
 | ||||
| void switch_to_tt(void *prev, void *next) | ||||
| { | ||||
| 	struct task_struct *from, *to, *prev_sched; | ||||
| 	unsigned long flags; | ||||
| 	int err, vtalrm, alrm, prof, cpu; | ||||
| 	char c; | ||||
| 
 | ||||
| 	from = prev; | ||||
| 	to = next; | ||||
| 
 | ||||
| 	cpu = task_thread_info(from)->cpu; | ||||
| 	if(cpu == 0) | ||||
| 		forward_interrupts(to->thread.mode.tt.extern_pid); | ||||
| #ifdef CONFIG_SMP | ||||
| 	forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid); | ||||
| #endif | ||||
| 	local_irq_save(flags); | ||||
| 
 | ||||
| 	vtalrm = change_sig(SIGVTALRM, 0); | ||||
| 	alrm = change_sig(SIGALRM, 0); | ||||
| 	prof = change_sig(SIGPROF, 0); | ||||
| 
 | ||||
| 	forward_pending_sigio(to->thread.mode.tt.extern_pid); | ||||
| 
 | ||||
| 	c = 0; | ||||
| 
 | ||||
| 	/* Notice that here we "up" the semaphore on which "to" is waiting, and
 | ||||
| 	 * below (the read) we wait on this semaphore (which is implemented by | ||||
| 	 * switch_pipe) and go sleeping. Thus, after that, we have resumed in | ||||
| 	 * "to", and can't use any more the value of "from" (which is outdated), | ||||
| 	 * nor the value in "to" (since it was the task which stole us the CPU, | ||||
| 	 * which we don't care about). */ | ||||
| 
 | ||||
| 	err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); | ||||
| 	if(err != sizeof(c)) | ||||
| 		panic("write of switch_pipe failed, err = %d", -err); | ||||
| 
 | ||||
| 	if(from->thread.mode.tt.switch_pipe[0] == -1) | ||||
| 		os_kill_process(os_getpid(), 0); | ||||
| 
 | ||||
| 	err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, | ||||
| 			     sizeof(c)); | ||||
| 	if(err != sizeof(c)) | ||||
| 		panic("read of switch_pipe failed, errno = %d", -err); | ||||
| 
 | ||||
| 	/* If the process that we have just scheduled away from has exited,
 | ||||
| 	 * then it needs to be killed here.  The reason is that, even though | ||||
| 	 * it will kill itself when it next runs, that may be too late.  Its | ||||
| 	 * stack will be freed, possibly before then, and if that happens, | ||||
| 	 * we have a use-after-free situation.  So, it gets killed here | ||||
| 	 * in case it has not already killed itself. | ||||
| 	 */ | ||||
| 	prev_sched = current->thread.prev_sched; | ||||
|         if(prev_sched->thread.mode.tt.switch_pipe[0] == -1) | ||||
| 		os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1); | ||||
| 
 | ||||
| 	change_sig(SIGVTALRM, vtalrm); | ||||
| 	change_sig(SIGALRM, alrm); | ||||
| 	change_sig(SIGPROF, prof); | ||||
| 
 | ||||
| 	arch_switch_to_tt(prev_sched, current); | ||||
| 
 | ||||
| 	flush_tlb_all(); | ||||
| 	local_irq_restore(flags); | ||||
| } | ||||
| 
 | ||||
| void release_thread_tt(struct task_struct *task) | ||||
| { | ||||
| 	int pid = task->thread.mode.tt.extern_pid; | ||||
| 
 | ||||
| 	/*
 | ||||
|          * We first have to kill the other process, before | ||||
|          * closing its switch_pipe. Else it might wake up | ||||
|          * and receive "EOF" before we could kill it. | ||||
|          */ | ||||
| 	if(os_getpid() != pid) | ||||
| 		os_kill_process(pid, 0); | ||||
| 
 | ||||
|         os_close_file(task->thread.mode.tt.switch_pipe[0]); | ||||
|         os_close_file(task->thread.mode.tt.switch_pipe[1]); | ||||
| 	/* use switch_pipe as flag: thread is released */ | ||||
|         task->thread.mode.tt.switch_pipe[0] = -1; | ||||
| } | ||||
| 
 | ||||
| void suspend_new_thread(int fd) | ||||
| { | ||||
| 	int err; | ||||
| 	char c; | ||||
| 
 | ||||
| 	os_stop_process(os_getpid()); | ||||
| 	err = os_read_file(fd, &c, sizeof(c)); | ||||
| 	if(err != sizeof(c)) | ||||
| 		panic("read failed in suspend_new_thread, err = %d", -err); | ||||
| } | ||||
| 
 | ||||
| void schedule_tail(struct task_struct *prev); | ||||
| 
 | ||||
| static void new_thread_handler(int sig) | ||||
| { | ||||
| 	unsigned long disable; | ||||
| 	int (*fn)(void *); | ||||
| 	void *arg; | ||||
| 
 | ||||
| 	fn = current->thread.request.u.thread.proc; | ||||
| 	arg = current->thread.request.u.thread.arg; | ||||
| 
 | ||||
| 	UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1); | ||||
| 	disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) | | ||||
| 		(1 << (SIGIO - 1)) | (1 << (SIGPROF - 1)); | ||||
| 	SC_SIGMASK(UPT_SC(¤t->thread.regs.regs)) &= ~disable; | ||||
| 
 | ||||
| 	suspend_new_thread(current->thread.mode.tt.switch_pipe[0]); | ||||
| 
 | ||||
| 	force_flush_all(); | ||||
| 	if(current->thread.prev_sched != NULL) | ||||
| 		schedule_tail(current->thread.prev_sched); | ||||
| 	current->thread.prev_sched = NULL; | ||||
| 
 | ||||
| 	init_new_thread_signals(); | ||||
| 	enable_timer(); | ||||
| 	free_page(current->thread.temp_stack); | ||||
| 	set_cmdline("(kernel thread)"); | ||||
| 
 | ||||
| 	change_sig(SIGUSR1, 1); | ||||
| 	change_sig(SIGPROF, 1); | ||||
| 	local_irq_enable(); | ||||
| 	if(!run_kernel_thread(fn, arg, ¤t->thread.exec_buf)) | ||||
| 		do_exit(0); | ||||
| 
 | ||||
| 	/* XXX No set_user_mode here because a newly execed process will
 | ||||
| 	 * immediately segfault on its non-existent IP, coming straight back | ||||
| 	 * to the signal handler, which will call set_user_mode on its way | ||||
| 	 * out.  This should probably change since it's confusing. | ||||
| 	 */ | ||||
| } | ||||
| 
 | ||||
| static int new_thread_proc(void *stack) | ||||
| { | ||||
| 	/* local_irq_disable is needed to block out signals until this thread is
 | ||||
| 	 * properly scheduled.  Otherwise, the tracing thread will get mighty | ||||
| 	 * upset about any signals that arrive before that. | ||||
| 	 * This has the complication that it sets the saved signal mask in | ||||
| 	 * the sigcontext to block signals.  This gets restored when this | ||||
| 	 * thread (or a descendant, since they get a copy of this sigcontext) | ||||
| 	 * returns to userspace. | ||||
| 	 * So, this is compensated for elsewhere. | ||||
| 	 * XXX There is still a small window until local_irq_disable() actually | ||||
| 	 * finishes where signals are possible - shouldn't be a problem in | ||||
| 	 * practice since SIGIO hasn't been forwarded here yet, and the | ||||
| 	 * local_irq_disable should finish before a SIGVTALRM has time to be | ||||
| 	 * delivered. | ||||
| 	 */ | ||||
| 
 | ||||
| 	local_irq_disable(); | ||||
| 	init_new_thread_stack(stack, new_thread_handler); | ||||
| 	os_usr1_process(os_getpid()); | ||||
| 	change_sig(SIGUSR1, 1); | ||||
| 	return(0); | ||||
| } | ||||
| 
 | ||||
| /* Signal masking - signals are blocked at the start of fork_tramp.  They
 | ||||
|  * are re-enabled when finish_fork_handler is entered by fork_tramp hitting | ||||
|  * itself with a SIGUSR1.  set_user_mode has to be run with SIGUSR1 off, | ||||
|  * so it is blocked before it's called.  They are re-enabled on sigreturn | ||||
|  * despite the fact that they were blocked when the SIGUSR1 was issued because | ||||
|  * copy_thread copies the parent's sigcontext, including the signal mask | ||||
|  * onto the signal frame. | ||||
|  */ | ||||
| 
 | ||||
| void finish_fork_handler(int sig) | ||||
| { | ||||
|  	UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1); | ||||
| 	suspend_new_thread(current->thread.mode.tt.switch_pipe[0]); | ||||
| 
 | ||||
| 	force_flush_all(); | ||||
| 	if(current->thread.prev_sched != NULL) | ||||
| 		schedule_tail(current->thread.prev_sched); | ||||
| 	current->thread.prev_sched = NULL; | ||||
| 
 | ||||
| 	enable_timer(); | ||||
| 	change_sig(SIGVTALRM, 1); | ||||
| 	local_irq_enable(); | ||||
| 	if(current->mm != current->parent->mm) | ||||
| 		protect_memory(uml_reserved, high_physmem - uml_reserved, 1,  | ||||
| 			       1, 0, 1); | ||||
| 	stack_protections((unsigned long) current_thread); | ||||
| 
 | ||||
| 	free_page(current->thread.temp_stack); | ||||
| 	local_irq_disable(); | ||||
| 	change_sig(SIGUSR1, 0); | ||||
| 	set_user_mode(current); | ||||
| } | ||||
| 
 | ||||
| int fork_tramp(void *stack) | ||||
| { | ||||
| 	local_irq_disable(); | ||||
| 	arch_init_thread(); | ||||
| 	init_new_thread_stack(stack, finish_fork_handler); | ||||
| 
 | ||||
| 	os_usr1_process(os_getpid()); | ||||
| 	change_sig(SIGUSR1, 1); | ||||
| 	return(0); | ||||
| } | ||||
| 
 | ||||
| int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, | ||||
| 		   unsigned long stack_top, struct task_struct * p,  | ||||
| 		   struct pt_regs *regs) | ||||
| { | ||||
| 	int (*tramp)(void *); | ||||
| 	int new_pid, err; | ||||
| 	unsigned long stack; | ||||
| 	 | ||||
| 	if(current->thread.forking) | ||||
| 		tramp = fork_tramp; | ||||
| 	else { | ||||
| 		tramp = new_thread_proc; | ||||
| 		p->thread.request.u.thread = current->thread.request.u.thread; | ||||
| 	} | ||||
| 
 | ||||
| 	err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1); | ||||
| 	if(err < 0){ | ||||
| 		printk("copy_thread : pipe failed, err = %d\n", -err); | ||||
| 		return(err); | ||||
| 	} | ||||
| 
 | ||||
| 	stack = alloc_stack(0, 0); | ||||
| 	if(stack == 0){ | ||||
| 		printk(KERN_ERR "copy_thread : failed to allocate " | ||||
| 		       "temporary stack\n"); | ||||
| 		return(-ENOMEM); | ||||
| 	} | ||||
| 
 | ||||
| 	clone_flags &= CLONE_VM; | ||||
| 	p->thread.temp_stack = stack; | ||||
| 	new_pid = start_fork_tramp(task_stack_page(p), stack, clone_flags, tramp); | ||||
| 	if(new_pid < 0){ | ||||
| 		printk(KERN_ERR "copy_thread : clone failed - errno = %d\n",  | ||||
| 		       -new_pid); | ||||
| 		return(new_pid); | ||||
| 	} | ||||
| 
 | ||||
| 	if(current->thread.forking){ | ||||
| 		sc_to_sc(UPT_SC(&p->thread.regs.regs), UPT_SC(®s->regs)); | ||||
| 		SC_SET_SYSCALL_RETURN(UPT_SC(&p->thread.regs.regs), 0); | ||||
| 		if(sp != 0) | ||||
| 			SC_SP(UPT_SC(&p->thread.regs.regs)) = sp; | ||||
| 	} | ||||
| 	p->thread.mode.tt.extern_pid = new_pid; | ||||
| 
 | ||||
| 	current->thread.request.op = OP_FORK; | ||||
| 	current->thread.request.u.fork.pid = new_pid; | ||||
| 	os_usr1_process(os_getpid()); | ||||
| 
 | ||||
| 	/* Enable the signal and then disable it to ensure that it is handled
 | ||||
| 	 * here, and nowhere else. | ||||
| 	 */ | ||||
| 	change_sig(SIGUSR1, 1); | ||||
| 
 | ||||
| 	change_sig(SIGUSR1, 0); | ||||
| 	err = 0; | ||||
| 	return(err); | ||||
| } | ||||
| 
 | ||||
| void reboot_tt(void) | ||||
| { | ||||
| 	current->thread.request.op = OP_REBOOT; | ||||
| 	os_usr1_process(os_getpid()); | ||||
| 	change_sig(SIGUSR1, 1); | ||||
| } | ||||
| 
 | ||||
| void halt_tt(void) | ||||
| { | ||||
| 	current->thread.request.op = OP_HALT; | ||||
| 	os_usr1_process(os_getpid()); | ||||
| 	change_sig(SIGUSR1, 1); | ||||
| } | ||||
| 
 | ||||
| void kill_off_processes_tt(void) | ||||
| { | ||||
| 	struct task_struct *p; | ||||
| 	int me; | ||||
| 
 | ||||
| 	me = os_getpid(); | ||||
|         for_each_process(p){ | ||||
| 		if(p->thread.mode.tt.extern_pid != me)  | ||||
| 			os_kill_process(p->thread.mode.tt.extern_pid, 0); | ||||
| 	} | ||||
| 	if(init_task.thread.mode.tt.extern_pid != me)  | ||||
| 		os_kill_process(init_task.thread.mode.tt.extern_pid, 0); | ||||
| } | ||||
| 
 | ||||
| void initial_thread_cb_tt(void (*proc)(void *), void *arg) | ||||
| { | ||||
| 	if(os_getpid() == tracing_pid){ | ||||
| 		(*proc)(arg); | ||||
| 	} | ||||
| 	else { | ||||
| 		current->thread.request.op = OP_CB; | ||||
| 		current->thread.request.u.cb.proc = proc; | ||||
| 		current->thread.request.u.cb.arg = arg; | ||||
| 		os_usr1_process(os_getpid()); | ||||
| 		change_sig(SIGUSR1, 1); | ||||
| 
 | ||||
| 		change_sig(SIGUSR1, 0); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int do_proc_op(void *t, int proc_id) | ||||
| { | ||||
| 	struct task_struct *task; | ||||
| 	struct thread_struct *thread; | ||||
| 	int op, pid; | ||||
| 
 | ||||
| 	task = t; | ||||
| 	thread = &task->thread; | ||||
| 	op = thread->request.op; | ||||
| 	switch(op){ | ||||
| 	case OP_NONE: | ||||
| 	case OP_TRACE_ON: | ||||
| 		break; | ||||
| 	case OP_EXEC: | ||||
| 		pid = thread->request.u.exec.pid; | ||||
| 		do_exec(thread->mode.tt.extern_pid, pid); | ||||
| 		thread->mode.tt.extern_pid = pid; | ||||
| 		cpu_tasks[task_thread_info(task)->cpu].pid = pid; | ||||
| 		break; | ||||
| 	case OP_FORK: | ||||
| 		attach_process(thread->request.u.fork.pid); | ||||
| 		break; | ||||
| 	case OP_CB: | ||||
| 		(*thread->request.u.cb.proc)(thread->request.u.cb.arg); | ||||
| 		break; | ||||
| 	case OP_REBOOT: | ||||
| 	case OP_HALT: | ||||
| 		break; | ||||
| 	default: | ||||
| 		tracer_panic("Bad op in do_proc_op"); | ||||
| 		break; | ||||
| 	} | ||||
| 	thread->request.op = OP_NONE; | ||||
| 	return(op); | ||||
| } | ||||
| 
 | ||||
| void init_idle_tt(void) | ||||
| { | ||||
| 	default_idle(); | ||||
| } | ||||
| 
 | ||||
| extern void start_kernel(void); | ||||
| 
 | ||||
| static int start_kernel_proc(void *unused) | ||||
| { | ||||
| 	int pid; | ||||
| 
 | ||||
| 	block_signals(); | ||||
| 	pid = os_getpid(); | ||||
| 
 | ||||
| 	cpu_tasks[0].pid = pid; | ||||
| 	cpu_tasks[0].task = current; | ||||
| #ifdef CONFIG_SMP | ||||
|  	cpu_online_map = cpumask_of_cpu(0); | ||||
| #endif | ||||
| 	if(debug) os_stop_process(pid); | ||||
| 	start_kernel(); | ||||
| 	return(0); | ||||
| } | ||||
| 
 | ||||
| void set_tracing(void *task, int tracing) | ||||
| { | ||||
| 	((struct task_struct *) task)->thread.mode.tt.tracing = tracing; | ||||
| } | ||||
| 
 | ||||
| int is_tracing(void *t) | ||||
| { | ||||
| 	return (((struct task_struct *) t)->thread.mode.tt.tracing); | ||||
| } | ||||
| 
 | ||||
| int set_user_mode(void *t) | ||||
| { | ||||
| 	struct task_struct *task; | ||||
| 
 | ||||
| 	task = t ? t : current; | ||||
| 	if(task->thread.mode.tt.tracing)  | ||||
| 		return(1); | ||||
| 	task->thread.request.op = OP_TRACE_ON; | ||||
| 	os_usr1_process(os_getpid()); | ||||
| 	return(0); | ||||
| } | ||||
| 
 | ||||
| void set_init_pid(int pid) | ||||
| { | ||||
| 	int err; | ||||
| 
 | ||||
| 	init_task.thread.mode.tt.extern_pid = pid; | ||||
| 	err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1); | ||||
| 	if(err) | ||||
| 		panic("Can't create switch pipe for init_task, errno = %d", | ||||
| 		      -err); | ||||
| } | ||||
| 
 | ||||
| int start_uml_tt(void) | ||||
| { | ||||
| 	void *sp; | ||||
| 	int pages; | ||||
| 
 | ||||
| 	pages = (1 << CONFIG_KERNEL_STACK_ORDER); | ||||
| 	sp = task_stack_page(&init_task) + | ||||
| 		pages * PAGE_SIZE - sizeof(unsigned long); | ||||
| 	return(tracer(start_kernel_proc, sp)); | ||||
| } | ||||
| 
 | ||||
| int external_pid_tt(struct task_struct *task) | ||||
| { | ||||
| 	return(task->thread.mode.tt.extern_pid); | ||||
| } | ||||
| 
 | ||||
| int thread_pid_tt(struct task_struct *task) | ||||
| { | ||||
| 	return(task->thread.mode.tt.extern_pid); | ||||
| } | ||||
| 
 | ||||
| int is_valid_pid(int pid) | ||||
| { | ||||
| 	struct task_struct *task; | ||||
| 
 | ||||
|         read_lock(&tasklist_lock); | ||||
|         for_each_process(task){ | ||||
|                 if(task->thread.mode.tt.extern_pid == pid){ | ||||
| 			read_unlock(&tasklist_lock); | ||||
| 			return(1); | ||||
|                 } | ||||
|         } | ||||
| 	read_unlock(&tasklist_lock); | ||||
| 	return(0); | ||||
| } | ||||
|  | @ -1,10 +0,0 @@ | |||
| # 
 | ||||
| # Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
 | ||||
| # Licensed under the GPL
 | ||||
| #
 | ||||
| 
 | ||||
| obj-y = proxy.o ptrace.o sysdep.o wait.o | ||||
| 
 | ||||
| USER_OBJS := $(obj-y) | ||||
| 
 | ||||
| include arch/um/scripts/Makefile.rules | ||||
|  | @ -1,377 +0,0 @@ | |||
| /**********************************************************************
 | ||||
| proxy.c | ||||
| 
 | ||||
| Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing | ||||
| terms and conditions. | ||||
| 
 | ||||
| Jeff Dike (jdike@karaya.com) : Modified for integration into uml | ||||
| **********************************************************************/ | ||||
| 
 | ||||
| /* XXX This file shouldn't refer to CONFIG_* */ | ||||
| 
 | ||||
| #include <errno.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
| #include <signal.h> | ||||
| #include <string.h> | ||||
| #include <termios.h> | ||||
| #include <sys/wait.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <asm/unistd.h> | ||||
| #include "ptrace_user.h" | ||||
| 
 | ||||
| #include "ptproxy.h" | ||||
| #include "sysdep.h" | ||||
| #include "wait.h" | ||||
| 
 | ||||
| #include "user.h" | ||||
| #include "os.h" | ||||
| #include "tempfile.h" | ||||
| 
 | ||||
| static int debugger_wait(debugger_state *debugger, int *status, int options, | ||||
| 			 int (*syscall)(debugger_state *debugger, pid_t child), | ||||
| 			 int (*normal_return)(debugger_state *debugger,  | ||||
| 					      pid_t unused), | ||||
| 			 int (*wait_return)(debugger_state *debugger,  | ||||
| 					    pid_t unused)) | ||||
| { | ||||
| 	if(debugger->real_wait){ | ||||
| 		debugger->handle_trace = normal_return; | ||||
| 		syscall_continue(debugger->pid); | ||||
| 		debugger->real_wait = 0; | ||||
| 		return(1); | ||||
| 	} | ||||
| 	debugger->wait_status_ptr = status; | ||||
| 	debugger->wait_options = options; | ||||
| 	if((debugger->debugee != NULL) && debugger->debugee->event){ | ||||
| 		syscall_continue(debugger->pid); | ||||
| 		wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL, | ||||
| 			      NULL); | ||||
| 		(*wait_return)(debugger, -1); | ||||
| 		return(0); | ||||
| 	} | ||||
| 	else if(debugger->wait_options & WNOHANG){ | ||||
| 		syscall_cancel(debugger->pid, 0); | ||||
| 		debugger->handle_trace = syscall; | ||||
| 		return(0); | ||||
| 	} | ||||
| 	else { | ||||
| 		syscall_pause(debugger->pid); | ||||
| 		debugger->handle_trace = wait_return; | ||||
| 		debugger->waiting = 1; | ||||
| 	} | ||||
| 	return(1); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Handle debugger trap, i.e. syscall. | ||||
|  */ | ||||
| 
 | ||||
| int debugger_syscall(debugger_state *debugger, pid_t child) | ||||
| { | ||||
| 	long arg1, arg2, arg3, arg4, arg5, result; | ||||
| 	int syscall, ret = 0; | ||||
| 
 | ||||
| 	syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4,  | ||||
| 			      &arg5); | ||||
| 
 | ||||
| 	switch(syscall){ | ||||
| 	case __NR_execve: | ||||
| 		/* execve never returns */ | ||||
| 		debugger->handle_trace = debugger_syscall;  | ||||
| 		break; | ||||
| 
 | ||||
| 	case __NR_ptrace: | ||||
| 		if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid; | ||||
| 		if(!debugger->debugee->in_context)  | ||||
| 			child = debugger->debugee->pid; | ||||
| 		result = proxy_ptrace(debugger, arg1, arg2, arg3, arg4, child, | ||||
| 				      &ret); | ||||
| 		syscall_cancel(debugger->pid, result); | ||||
| 		debugger->handle_trace = debugger_syscall; | ||||
| 		return(ret); | ||||
| 
 | ||||
| #ifdef __NR_waitpid | ||||
| 	case __NR_waitpid: | ||||
| #endif | ||||
| 	case __NR_wait4: | ||||
| 		if(!debugger_wait(debugger, (int *) arg2, arg3,  | ||||
| 				  debugger_syscall, debugger_normal_return,  | ||||
| 				  proxy_wait_return)) | ||||
| 			return(0); | ||||
| 		break; | ||||
| 
 | ||||
| 	case __NR_kill: | ||||
| 		if(!debugger->debugee->in_context)  | ||||
| 			child = debugger->debugee->pid; | ||||
| 		if(arg1 == debugger->debugee->pid){ | ||||
| 			result = kill(child, arg2); | ||||
| 			syscall_cancel(debugger->pid, result); | ||||
| 			debugger->handle_trace = debugger_syscall; | ||||
| 			return(0); | ||||
| 		} | ||||
| 		else debugger->handle_trace = debugger_normal_return; | ||||
| 		break; | ||||
| 
 | ||||
| 	default: | ||||
| 		debugger->handle_trace = debugger_normal_return; | ||||
| 	} | ||||
| 
 | ||||
| 	syscall_continue(debugger->pid); | ||||
| 	return(0); | ||||
| } | ||||
| 
 | ||||
| /* Used by the tracing thread */ | ||||
| static debugger_state parent; | ||||
| static int parent_syscall(debugger_state *debugger, int pid); | ||||
| 
 | ||||
| int init_parent_proxy(int pid) | ||||
| { | ||||
| 	parent = ((debugger_state) { .pid 		= pid, | ||||
| 				     .wait_options 	= 0, | ||||
| 				     .wait_status_ptr 	= NULL, | ||||
| 				     .waiting 		= 0, | ||||
| 				     .real_wait 	= 0, | ||||
| 				     .expecting_child 	= 0, | ||||
| 				     .handle_trace  	= parent_syscall, | ||||
| 				     .debugee 		= NULL } ); | ||||
| 	return(0); | ||||
| } | ||||
| 
 | ||||
| int parent_normal_return(debugger_state *debugger, pid_t unused) | ||||
| { | ||||
| 	debugger->handle_trace = parent_syscall; | ||||
| 	syscall_continue(debugger->pid); | ||||
| 	return(0); | ||||
| } | ||||
| 
 | ||||
| static int parent_syscall(debugger_state *debugger, int pid) | ||||
| { | ||||
| 	long arg1, arg2, arg3, arg4, arg5; | ||||
| 	int syscall; | ||||
| 
 | ||||
| 	syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5); | ||||
| 		 | ||||
| 	if((syscall == __NR_wait4) | ||||
| #ifdef __NR_waitpid | ||||
| 	   || (syscall == __NR_waitpid) | ||||
| #endif | ||||
| 	){ | ||||
| 		debugger_wait(&parent, (int *) arg2, arg3, parent_syscall, | ||||
| 			      parent_normal_return, parent_wait_return); | ||||
| 	} | ||||
| 	else ptrace(PTRACE_SYSCALL, pid, 0, 0); | ||||
| 	return(0); | ||||
| } | ||||
| 
 | ||||
| int debugger_normal_return(debugger_state *debugger, pid_t unused) | ||||
| { | ||||
| 	debugger->handle_trace = debugger_syscall; | ||||
| 	syscall_continue(debugger->pid); | ||||
| 	return(0); | ||||
| } | ||||
| 
 | ||||
| void debugger_cancelled_return(debugger_state *debugger, int result) | ||||
| { | ||||
| 	debugger->handle_trace = debugger_syscall; | ||||
| 	syscall_set_result(debugger->pid, result); | ||||
| 	syscall_continue(debugger->pid); | ||||
| } | ||||
| 
 | ||||
| /* Used by the tracing thread */ | ||||
| static debugger_state debugger; | ||||
| static debugee_state debugee; | ||||
| 
 | ||||
| void init_proxy (pid_t debugger_pid, int stopped, int status) | ||||
| { | ||||
| 	debugger.pid = debugger_pid; | ||||
| 	debugger.handle_trace = debugger_syscall; | ||||
| 	debugger.debugee = &debugee; | ||||
| 	debugger.waiting = 0; | ||||
| 	debugger.real_wait = 0; | ||||
| 	debugger.expecting_child = 0; | ||||
| 
 | ||||
| 	debugee.pid = 0; | ||||
| 	debugee.traced = 0; | ||||
| 	debugee.stopped = stopped; | ||||
| 	debugee.event = 0; | ||||
| 	debugee.zombie = 0; | ||||
| 	debugee.died = 0; | ||||
| 	debugee.wait_status = status; | ||||
| 	debugee.in_context = 1; | ||||
| } | ||||
| 
 | ||||
| int debugger_proxy(int status, int pid) | ||||
| { | ||||
| 	int ret = 0, sig; | ||||
| 
 | ||||
| 	if(WIFSTOPPED(status)){ | ||||
| 		sig = WSTOPSIG(status); | ||||
| 		if (sig == SIGTRAP) | ||||
| 			ret = (*debugger.handle_trace)(&debugger, pid); | ||||
| 						        | ||||
| 		else if(sig == SIGCHLD){ | ||||
| 			if(debugger.expecting_child){ | ||||
| 				ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig); | ||||
| 				debugger.expecting_child = 0; | ||||
| 			} | ||||
| 			else if(debugger.waiting) | ||||
| 				real_wait_return(&debugger); | ||||
| 			else { | ||||
| 				ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig); | ||||
| 				debugger.real_wait = 1; | ||||
| 			} | ||||
| 		} | ||||
| 		else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig); | ||||
| 	} | ||||
| 	else if(WIFEXITED(status)){ | ||||
| 		tracer_panic("debugger (pid %d) exited with status %d",  | ||||
| 			     debugger.pid, WEXITSTATUS(status)); | ||||
| 	} | ||||
| 	else if(WIFSIGNALED(status)){ | ||||
| 		tracer_panic("debugger (pid %d) exited with signal %d",  | ||||
| 			     debugger.pid, WTERMSIG(status)); | ||||
| 	} | ||||
| 	else { | ||||
| 		tracer_panic("proxy got unknown status (0x%x) on debugger " | ||||
| 			     "(pid %d)", status, debugger.pid); | ||||
| 	} | ||||
| 	return(ret); | ||||
| } | ||||
| 
 | ||||
| void child_proxy(pid_t pid, int status) | ||||
| { | ||||
| 	debugee.event = 1; | ||||
| 	debugee.wait_status = status; | ||||
| 
 | ||||
| 	if(WIFSTOPPED(status)){ | ||||
| 		debugee.stopped = 1; | ||||
| 		debugger.expecting_child = 1; | ||||
| 		kill(debugger.pid, SIGCHLD); | ||||
| 	} | ||||
| 	else if(WIFEXITED(status) || WIFSIGNALED(status)){ | ||||
| 		debugee.zombie = 1; | ||||
| 		debugger.expecting_child = 1; | ||||
| 		kill(debugger.pid, SIGCHLD); | ||||
| 	} | ||||
| 	else panic("proxy got unknown status (0x%x) on child (pid %d)",  | ||||
| 		   status, pid); | ||||
| } | ||||
| 
 | ||||
| void debugger_parent_signal(int status, int pid) | ||||
| { | ||||
| 	int sig; | ||||
| 
 | ||||
| 	if(WIFSTOPPED(status)){ | ||||
| 		sig = WSTOPSIG(status); | ||||
| 		if(sig == SIGTRAP) (*parent.handle_trace)(&parent, pid); | ||||
| 		else ptrace(PTRACE_SYSCALL, pid, 0, sig); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void fake_child_exit(void) | ||||
| { | ||||
| 	int status, pid; | ||||
| 
 | ||||
| 	child_proxy(1, W_EXITCODE(0, 0)); | ||||
| 	while(debugger.waiting == 1){ | ||||
| 		CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED)); | ||||
| 		if(pid != debugger.pid){ | ||||
| 			printk("fake_child_exit - waitpid failed, " | ||||
| 			       "errno = %d\n", errno); | ||||
| 			return; | ||||
| 		} | ||||
| 		debugger_proxy(status, debugger.pid); | ||||
| 	} | ||||
| 	CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED)); | ||||
| 	if(pid != debugger.pid){ | ||||
| 		printk("fake_child_exit - waitpid failed, " | ||||
| 		       "errno = %d\n", errno); | ||||
| 		return; | ||||
| 	} | ||||
| 	if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0) | ||||
| 		printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n", | ||||
| 		       errno); | ||||
| } | ||||
| 
 | ||||
| char gdb_init_string[] =  | ||||
| "att 1 \n\
 | ||||
| b panic \n\ | ||||
| b stop \n\ | ||||
| handle SIGWINCH nostop noprint pass \n\ | ||||
| "; | ||||
| 
 | ||||
| int start_debugger(char *prog, int startup, int stop, int *fd_out) | ||||
| { | ||||
| 	int slave, child; | ||||
| 
 | ||||
| 	slave = open_gdb_chan(); | ||||
| 	child = fork(); | ||||
| 	if(child == 0){ | ||||
| 		char *tempname = NULL; | ||||
| 		int fd; | ||||
| 
 | ||||
| 	        if(setsid() < 0) perror("setsid"); | ||||
| 		if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) ||  | ||||
| 		   (dup2(slave, 2) < 0)){ | ||||
| 			printk("start_debugger : dup2 failed, errno = %d\n", | ||||
| 			       errno); | ||||
| 			exit(1); | ||||
| 		} | ||||
| 		if(ioctl(0, TIOCSCTTY, 0) < 0){ | ||||
| 			printk("start_debugger : TIOCSCTTY failed, " | ||||
| 			       "errno = %d\n", errno); | ||||
| 			exit(1); | ||||
| 		} | ||||
| 		if(tcsetpgrp (1, os_getpid()) < 0){ | ||||
| 			printk("start_debugger : tcsetpgrp failed, " | ||||
| 			       "errno = %d\n", errno); | ||||
| #ifdef notdef | ||||
| 			exit(1); | ||||
| #endif | ||||
| 		} | ||||
| 		fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0); | ||||
| 		if(fd < 0){ | ||||
| 			printk("start_debugger : make_tempfile failed," | ||||
| 			       "err = %d\n", -fd); | ||||
| 			exit(1); | ||||
| 		} | ||||
| 		os_write_file(fd, gdb_init_string, | ||||
| 			      sizeof(gdb_init_string) - 1); | ||||
| 		if(startup){ | ||||
| 			if(stop){ | ||||
| 				os_write_file(fd, "b start_kernel\n", | ||||
| 						strlen("b start_kernel\n")); | ||||
| 			} | ||||
| 			os_write_file(fd, "c\n", strlen("c\n")); | ||||
| 		} | ||||
| 		if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ | ||||
| 			printk("start_debugger :  PTRACE_TRACEME failed, " | ||||
| 			       "errno = %d\n", errno); | ||||
| 			exit(1); | ||||
| 		} | ||||
| 		execlp("gdb", "gdb", "--command", tempname, prog, NULL); | ||||
| 		printk("start_debugger : exec of gdb failed, errno = %d\n", | ||||
| 		       errno); | ||||
| 	} | ||||
| 	if(child < 0){ | ||||
| 		printk("start_debugger : fork for gdb failed, errno = %d\n", | ||||
| 		       errno); | ||||
| 		return(-1); | ||||
| 	} | ||||
| 	*fd_out = slave; | ||||
| 	return(child); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * 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: | ||||
|  */ | ||||
|  | @ -1,61 +0,0 @@ | |||
| /**********************************************************************
 | ||||
| ptproxy.h | ||||
| 
 | ||||
| Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing | ||||
| terms and conditions. | ||||
| **********************************************************************/ | ||||
| 
 | ||||
| #ifndef __PTPROXY_H | ||||
| #define __PTPROXY_H | ||||
| 
 | ||||
| #include <sys/types.h> | ||||
| 
 | ||||
| typedef struct debugger debugger_state; | ||||
| typedef struct debugee debugee_state; | ||||
| 
 | ||||
| struct debugger | ||||
| { | ||||
| 	pid_t pid; | ||||
| 	int wait_options; | ||||
| 	int *wait_status_ptr; | ||||
| 	unsigned int waiting : 1; | ||||
| 	unsigned int real_wait : 1; | ||||
| 	unsigned int expecting_child : 1; | ||||
| 	int (*handle_trace) (debugger_state *, pid_t); | ||||
| 
 | ||||
| 	debugee_state *debugee; | ||||
| }; | ||||
| 
 | ||||
| struct debugee | ||||
| { | ||||
| 	pid_t pid; | ||||
| 	int wait_status; | ||||
| 	unsigned int died : 1; | ||||
| 	unsigned int event : 1; | ||||
| 	unsigned int stopped : 1; | ||||
| 	unsigned int trace_singlestep : 1; | ||||
| 	unsigned int trace_syscall : 1; | ||||
| 	unsigned int traced : 1; | ||||
| 	unsigned int zombie : 1; | ||||
| 	unsigned int in_context : 1; | ||||
| }; | ||||
| 
 | ||||
| extern int debugger_syscall(debugger_state *debugger, pid_t pid); | ||||
| extern int debugger_normal_return (debugger_state *debugger, pid_t unused); | ||||
| 
 | ||||
| extern long proxy_ptrace (struct debugger *, int, pid_t, long, long, pid_t, | ||||
| 			  int *strace_out); | ||||
| extern void debugger_cancelled_return(debugger_state *debugger, int result); | ||||
| 
 | ||||
| #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: | ||||
|  */ | ||||
|  | @ -1,237 +0,0 @@ | |||
| /**********************************************************************
 | ||||
| ptrace.c | ||||
| 
 | ||||
| Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing | ||||
| terms and conditions. | ||||
| 
 | ||||
| Jeff Dike (jdike@karaya.com) : Modified for integration into uml | ||||
| **********************************************************************/ | ||||
| 
 | ||||
| #include <errno.h> | ||||
| #include <unistd.h> | ||||
| #include <signal.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/wait.h> | ||||
| 
 | ||||
| #include "ptproxy.h" | ||||
| #include "debug.h" | ||||
| #include "kern_util.h" | ||||
| #include "ptrace_user.h" | ||||
| #include "tt.h" | ||||
| #include "os.h" | ||||
| 
 | ||||
| long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2, | ||||
| 		  long arg3, long arg4, pid_t child, int *ret) | ||||
| { | ||||
| 	sigset_t relay; | ||||
| 	long result; | ||||
| 	int status; | ||||
| 
 | ||||
| 	*ret = 0; | ||||
| 	if(debugger->debugee->died) return(-ESRCH); | ||||
| 
 | ||||
| 	switch(arg1){ | ||||
| 	case PTRACE_ATTACH: | ||||
| 		if(debugger->debugee->traced) return(-EPERM); | ||||
| 
 | ||||
| 		debugger->debugee->pid = arg2; | ||||
| 		debugger->debugee->traced = 1; | ||||
| 
 | ||||
| 		if(is_valid_pid(arg2) && (arg2 != child)){ | ||||
| 			debugger->debugee->in_context = 0; | ||||
| 			kill(arg2, SIGSTOP); | ||||
| 			debugger->debugee->event = 1; | ||||
| 			debugger->debugee->wait_status = W_STOPCODE(SIGSTOP); | ||||
| 		} | ||||
| 		else { | ||||
| 			debugger->debugee->in_context = 1; | ||||
| 			if(debugger->debugee->stopped)  | ||||
| 				child_proxy(child, W_STOPCODE(SIGSTOP)); | ||||
| 			else kill(child, SIGSTOP); | ||||
| 		} | ||||
| 
 | ||||
| 		return(0); | ||||
| 
 | ||||
| 	case PTRACE_DETACH: | ||||
| 		if(!debugger->debugee->traced) return(-EPERM); | ||||
| 		 | ||||
| 		debugger->debugee->traced = 0; | ||||
| 		debugger->debugee->pid = 0; | ||||
| 		if(!debugger->debugee->in_context) | ||||
| 			kill(child, SIGCONT); | ||||
| 
 | ||||
| 		return(0); | ||||
| 
 | ||||
| 	case PTRACE_CONT: | ||||
| 		if(!debugger->debugee->in_context) return(-EPERM); | ||||
| 		*ret = PTRACE_CONT; | ||||
| 		return(ptrace(PTRACE_CONT, child, arg3, arg4)); | ||||
| 
 | ||||
| #ifdef UM_HAVE_GETFPREGS | ||||
| 	case PTRACE_GETFPREGS: | ||||
| 	{ | ||||
| 		long regs[FP_FRAME_SIZE]; | ||||
| 		int i, result; | ||||
| 
 | ||||
| 		result = ptrace(PTRACE_GETFPREGS, child, 0, regs); | ||||
| 		if(result == -1) return(-errno); | ||||
| 		 | ||||
| 		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) | ||||
| 			ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i, | ||||
| 			       regs[i]); | ||||
| 		return(result); | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| #ifdef UM_HAVE_GETFPXREGS | ||||
| 	case PTRACE_GETFPXREGS: | ||||
| 	{ | ||||
| 		long regs[FPX_FRAME_SIZE]; | ||||
| 		int i, result; | ||||
| 
 | ||||
| 		result = ptrace(PTRACE_GETFPXREGS, child, 0, regs); | ||||
| 		if(result == -1) return(-errno); | ||||
| 		 | ||||
| 		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) | ||||
| 			ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i, | ||||
| 			       regs[i]); | ||||
| 		return(result); | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| #ifdef UM_HAVE_GETREGS | ||||
| 	case PTRACE_GETREGS: | ||||
| 	{ | ||||
| 		long regs[FRAME_SIZE]; | ||||
| 		int i, result; | ||||
| 
 | ||||
| 		result = ptrace(PTRACE_GETREGS, child, 0, regs); | ||||
| 		if(result == -1) return(-errno); | ||||
| 
 | ||||
| 		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) | ||||
| 			ptrace (PTRACE_POKEDATA, debugger->pid, | ||||
| 				arg4 + 4 * i, regs[i]); | ||||
| 		return(result); | ||||
| 	} | ||||
| 	break; | ||||
| #endif | ||||
| 
 | ||||
| 	case PTRACE_KILL: | ||||
| 		result = ptrace(PTRACE_KILL, child, arg3, arg4); | ||||
| 		if(result == -1) return(-errno); | ||||
| 
 | ||||
| 		return(result); | ||||
| 
 | ||||
| 	case PTRACE_PEEKDATA: | ||||
| 	case PTRACE_PEEKTEXT: | ||||
| 	case PTRACE_PEEKUSR: | ||||
| 		/* The value being read out could be -1, so we have to 
 | ||||
| 		 * check errno to see if there's an error, and zero it | ||||
| 		 * beforehand so we're not faked out by an old error | ||||
| 		 */ | ||||
| 
 | ||||
| 		errno = 0; | ||||
| 		result = ptrace(arg1, child, arg3, 0); | ||||
| 		if((result == -1) && (errno != 0)) return(-errno); | ||||
| 
 | ||||
| 		result = ptrace(PTRACE_POKEDATA, debugger->pid, arg4, result); | ||||
| 		if(result == -1) return(-errno); | ||||
| 			 | ||||
| 		return(result); | ||||
| 
 | ||||
| 	case PTRACE_POKEDATA: | ||||
| 	case PTRACE_POKETEXT: | ||||
| 	case PTRACE_POKEUSR: | ||||
| 		result = ptrace(arg1, child, arg3, arg4); | ||||
| 		if(result == -1) return(-errno); | ||||
| 
 | ||||
| 		if(arg1 == PTRACE_POKEUSR) ptrace_pokeuser(arg3, arg4); | ||||
| 		return(result); | ||||
| 
 | ||||
| #ifdef UM_HAVE_SETFPREGS | ||||
| 	case PTRACE_SETFPREGS: | ||||
| 	{ | ||||
| 		long regs[FP_FRAME_SIZE]; | ||||
| 		int i; | ||||
| 
 | ||||
| 		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) | ||||
| 			regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid, | ||||
| 					  arg4 + 4 * i, 0); | ||||
| 		result = ptrace(PTRACE_SETFPREGS, child, 0, regs); | ||||
| 		if(result == -1) return(-errno); | ||||
| 
 | ||||
| 		return(result); | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| #ifdef UM_HAVE_SETFPXREGS | ||||
| 	case PTRACE_SETFPXREGS: | ||||
| 	{ | ||||
| 		long regs[FPX_FRAME_SIZE]; | ||||
| 		int i; | ||||
| 
 | ||||
| 		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) | ||||
| 			regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid, | ||||
| 					  arg4 + 4 * i, 0); | ||||
| 		result = ptrace(PTRACE_SETFPXREGS, child, 0, regs); | ||||
| 		if(result == -1) return(-errno); | ||||
| 
 | ||||
| 		return(result); | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| #ifdef UM_HAVE_SETREGS | ||||
| 	case PTRACE_SETREGS: | ||||
| 	{ | ||||
| 		long regs[FRAME_SIZE]; | ||||
| 		int i; | ||||
| 
 | ||||
| 		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) | ||||
| 			regs[i] = ptrace(PTRACE_PEEKDATA, debugger->pid, | ||||
| 					 arg4 + 4 * i, 0); | ||||
| 		result = ptrace(PTRACE_SETREGS, child, 0, regs); | ||||
| 		if(result == -1) return(-errno); | ||||
| 
 | ||||
| 		return(result); | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	case PTRACE_SINGLESTEP: | ||||
| 		if(!debugger->debugee->in_context) return(-EPERM); | ||||
| 		sigemptyset(&relay); | ||||
| 		sigaddset(&relay, SIGSEGV); | ||||
| 		sigaddset(&relay, SIGILL); | ||||
| 		sigaddset(&relay, SIGBUS); | ||||
| 		result = ptrace(PTRACE_SINGLESTEP, child, arg3, arg4); | ||||
| 		if(result == -1) return(-errno); | ||||
| 		 | ||||
| 		status = wait_for_stop(child, SIGTRAP, PTRACE_SINGLESTEP, | ||||
| 				       &relay); | ||||
| 		child_proxy(child, status); | ||||
| 		return(result); | ||||
| 
 | ||||
| 	case PTRACE_SYSCALL: | ||||
| 		if(!debugger->debugee->in_context) return(-EPERM); | ||||
| 		result = ptrace(PTRACE_SYSCALL, child, arg3, arg4); | ||||
| 		if(result == -1) return(-errno); | ||||
| 
 | ||||
| 		*ret = PTRACE_SYSCALL; | ||||
| 		return(result); | ||||
| 
 | ||||
| 	case PTRACE_TRACEME: | ||||
| 	default: | ||||
| 		return(-EINVAL); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * 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: | ||||
|  */ | ||||
|  | @ -1,70 +0,0 @@ | |||
| /**********************************************************************
 | ||||
| sysdep.c | ||||
| 
 | ||||
| Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing | ||||
| terms and conditions. | ||||
| **********************************************************************/ | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| #include <signal.h> | ||||
| #include <errno.h> | ||||
| #include <sys/types.h> | ||||
| #include <linux/unistd.h> | ||||
| #include "ptrace_user.h" | ||||
| #include "user.h" | ||||
| #include "os.h" | ||||
| 
 | ||||
| int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4,  | ||||
| 		long *arg5) | ||||
| { | ||||
| 	*arg1 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG1_OFFSET, 0); | ||||
| 	*arg2 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG2_OFFSET, 0); | ||||
| 	*arg3 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG3_OFFSET, 0); | ||||
| 	*arg4 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG4_OFFSET, 0); | ||||
| 	*arg5 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG5_OFFSET, 0); | ||||
| 	return(ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, 0)); | ||||
| } | ||||
| 
 | ||||
| void syscall_cancel(pid_t pid, int result) | ||||
| { | ||||
| 	if((ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, | ||||
| 		   __NR_getpid) < 0) || | ||||
| 	   (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) || | ||||
| 	   (wait_for_stop(pid, SIGTRAP, PTRACE_SYSCALL, NULL) < 0) || | ||||
| 	   (ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result) < 0) || | ||||
| 	   (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)) | ||||
| 		printk("ptproxy: couldn't cancel syscall: errno = %d\n",  | ||||
| 		       errno); | ||||
| } | ||||
| 
 | ||||
| void syscall_set_result(pid_t pid, long result) | ||||
| { | ||||
| 	ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result); | ||||
| } | ||||
| 
 | ||||
| void syscall_continue(pid_t pid) | ||||
| { | ||||
| 	ptrace(PTRACE_SYSCALL, pid, 0, 0); | ||||
| } | ||||
| 
 | ||||
| int syscall_pause(pid_t pid)  | ||||
| { | ||||
| 	if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_pause) < 0){ | ||||
| 		printk("syscall_change - ptrace failed, errno = %d\n", errno); | ||||
| 		return(-1); | ||||
| 	} | ||||
| 	return(0); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * 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: | ||||
|  */ | ||||
|  | @ -1,25 +0,0 @@ | |||
| /**********************************************************************
 | ||||
| sysdep.h | ||||
| 
 | ||||
| Copyright (C) 1999 Lars Brinkhoff. | ||||
| Copyright (C) 2001 Jeff Dike (jdike@karaya.com) | ||||
| See the file COPYING for licensing terms and conditions. | ||||
| **********************************************************************/ | ||||
| 
 | ||||
| extern int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3,  | ||||
| 		       long *arg4, long *arg5); | ||||
| extern void syscall_cancel (pid_t pid, long result); | ||||
| extern void syscall_set_result (pid_t pid, long result); | ||||
| extern void syscall_continue (pid_t pid); | ||||
| extern int syscall_pause(pid_t pid); | ||||
| 
 | ||||
| /*
 | ||||
|  * 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: | ||||
|  */ | ||||
|  | @ -1,85 +0,0 @@ | |||
| /**********************************************************************
 | ||||
| wait.c | ||||
| 
 | ||||
| Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing | ||||
| terms and conditions. | ||||
| 
 | ||||
| **********************************************************************/ | ||||
| 
 | ||||
| #include <errno.h> | ||||
| #include <signal.h> | ||||
| #include <sys/wait.h> | ||||
| 
 | ||||
| #include "ptproxy.h" | ||||
| #include "sysdep.h" | ||||
| #include "wait.h" | ||||
| #include "ptrace_user.h" | ||||
| #include "sysdep/ptrace.h" | ||||
| #include "sysdep/sigcontext.h" | ||||
| 
 | ||||
| int proxy_wait_return(struct debugger *debugger, pid_t unused) | ||||
| { | ||||
| 	debugger->waiting = 0; | ||||
| 
 | ||||
| 	if(debugger->debugee->died || (debugger->wait_options & __WCLONE)){ | ||||
| 		debugger_cancelled_return(debugger, -ECHILD); | ||||
| 		return(0); | ||||
| 	} | ||||
| 
 | ||||
| 	if(debugger->debugee->zombie && debugger->debugee->event) | ||||
| 		debugger->debugee->died = 1; | ||||
| 
 | ||||
| 	if(debugger->debugee->event){ | ||||
| 		debugger->debugee->event = 0; | ||||
| 		ptrace(PTRACE_POKEDATA, debugger->pid, | ||||
| 		       debugger->wait_status_ptr,  | ||||
| 		       debugger->debugee->wait_status); | ||||
| 		/* if (wait4)
 | ||||
| 		   ptrace (PTRACE_POKEDATA, pid, rusage_ptr, ...); */ | ||||
| 		debugger_cancelled_return(debugger, debugger->debugee->pid); | ||||
| 		return(0); | ||||
| 	} | ||||
| 
 | ||||
| 	/* pause will return -EINTR, which happens to be right for wait */ | ||||
| 	debugger_normal_return(debugger, -1); | ||||
| 	return(0); | ||||
| } | ||||
| 
 | ||||
| int parent_wait_return(struct debugger *debugger, pid_t unused) | ||||
| { | ||||
| 	return(debugger_normal_return(debugger, -1)); | ||||
| } | ||||
| 
 | ||||
| int real_wait_return(struct debugger *debugger) | ||||
| { | ||||
| 	unsigned long ip; | ||||
| 	int pid; | ||||
| 
 | ||||
| 	pid = debugger->pid; | ||||
| 
 | ||||
| 	ip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0); | ||||
| 	IP_RESTART_SYSCALL(ip); | ||||
| 
 | ||||
| 	if(ptrace(PTRACE_POKEUSR, pid, PT_IP_OFFSET, ip) < 0) | ||||
| 		tracer_panic("real_wait_return : Failed to restart system " | ||||
| 			     "call, errno = %d\n", errno); | ||||
| 
 | ||||
| 	if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) || | ||||
| 	   (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) || | ||||
| 	   (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) || | ||||
| 	   debugger_normal_return(debugger, -1)) | ||||
| 		tracer_panic("real_wait_return : gdb failed to wait, " | ||||
| 			     "errno = %d\n", errno); | ||||
| 	return(0); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * 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: | ||||
|  */ | ||||
|  | @ -1,15 +0,0 @@ | |||
| /**********************************************************************
 | ||||
| wait.h | ||||
| 
 | ||||
| Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing | ||||
| terms and conditions. | ||||
| **********************************************************************/ | ||||
| 
 | ||||
| #ifndef __PTPROXY_WAIT_H | ||||
| #define __PTPROXY_WAIT_H | ||||
| 
 | ||||
| extern int proxy_wait_return(struct debugger *debugger, pid_t unused); | ||||
| extern int real_wait_return(struct debugger *debugger); | ||||
| extern int parent_wait_return(struct debugger *debugger, pid_t unused); | ||||
| 
 | ||||
| #endif | ||||
|  | @ -1,46 +0,0 @@ | |||
| /* 
 | ||||
|  * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include "linux/types.h" | ||||
| #include "linux/utime.h" | ||||
| #include "linux/sys.h" | ||||
| #include "linux/ptrace.h" | ||||
| #include "asm/unistd.h" | ||||
| #include "asm/ptrace.h" | ||||
| #include "asm/uaccess.h" | ||||
| #include "asm/stat.h" | ||||
| #include "sysdep/syscalls.h" | ||||
| #include "sysdep/sigcontext.h" | ||||
| #include "kern_util.h" | ||||
| #include "syscall.h" | ||||
| 
 | ||||
| void syscall_handler_tt(int sig, struct pt_regs *regs) | ||||
| { | ||||
| 	void *sc; | ||||
| 	long result; | ||||
| 	int syscall; | ||||
| 
 | ||||
| 	sc = UPT_SC(®s->regs); | ||||
| 	SC_START_SYSCALL(sc); | ||||
| 
 | ||||
| 	syscall = UPT_SYSCALL_NR(®s->regs); | ||||
| 	syscall_trace(®s->regs, 0); | ||||
| 
 | ||||
| 	current->thread.nsyscalls++; | ||||
| 	nsyscalls++; | ||||
| 
 | ||||
| 	if((syscall >= NR_syscalls) || (syscall < 0)) | ||||
| 		result = -ENOSYS; | ||||
| 	else result = EXECUTE_SYSCALL(syscall, regs); | ||||
| 
 | ||||
| 	/* regs->sc may have changed while the system call ran (there may
 | ||||
| 	 * have been an interrupt or segfault), so it needs to be refreshed. | ||||
| 	 */ | ||||
| 	UPT_SC(®s->regs) = sc; | ||||
| 
 | ||||
| 	SC_SET_SYSCALL_RETURN(sc, result); | ||||
| 
 | ||||
| 	syscall_trace(®s->regs, 1); | ||||
| } | ||||
|  | @ -1,60 +0,0 @@ | |||
| /* 
 | ||||
|  * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include <unistd.h> | ||||
| #include <signal.h> | ||||
| #include <errno.h> | ||||
| #include <asm/unistd.h> | ||||
| #include "sysdep/ptrace.h" | ||||
| #include "sigcontext.h" | ||||
| #include "ptrace_user.h" | ||||
| #include "task.h" | ||||
| #include "kern_util.h" | ||||
| #include "syscall.h" | ||||
| #include "tt.h" | ||||
| 
 | ||||
| void do_sigtrap(void *task) | ||||
| { | ||||
| 	UPT_SYSCALL_NR(TASK_REGS(task)) = -1; | ||||
| } | ||||
| 
 | ||||
| void do_syscall(void *task, int pid, int local_using_sysemu) | ||||
| { | ||||
| 	unsigned long proc_regs[FRAME_SIZE]; | ||||
| 
 | ||||
| 	if(ptrace_getregs(pid, proc_regs) < 0) | ||||
| 		tracer_panic("Couldn't read registers"); | ||||
| 
 | ||||
| 	UPT_SYSCALL_NR(TASK_REGS(task)) = PT_SYSCALL_NR(proc_regs); | ||||
| 
 | ||||
| #ifdef UPT_ORIGGPR2 | ||||
|         UPT_ORIGGPR2(TASK_REGS(task)) = REGS_ORIGGPR2(proc_regs); | ||||
| #endif | ||||
| 
 | ||||
| 	if(((unsigned long *) PT_IP(proc_regs) >= &_stext) && | ||||
| 	   ((unsigned long *) PT_IP(proc_regs) <= &_etext)) | ||||
| 		tracer_panic("I'm tracing myself and I can't get out"); | ||||
| 
 | ||||
| 	/* advanced sysemu mode set syscall number to -1 automatically */ | ||||
| 	if (local_using_sysemu==2) | ||||
| 		return; | ||||
| 
 | ||||
| 	/* syscall number -1 in sysemu skips syscall restarting in host */ | ||||
| 	if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, | ||||
| 		  local_using_sysemu ? -1 : __NR_getpid) < 0) | ||||
| 		tracer_panic("do_syscall : Nullifying syscall failed, " | ||||
| 			     "errno = %d", errno); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * 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: | ||||
|  */ | ||||
|  | @ -1,120 +0,0 @@ | |||
| /* 
 | ||||
|  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||||
|  * Copyright 2003 PathScale, Inc. | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include "linux/stddef.h" | ||||
| #include "linux/kernel.h" | ||||
| #include "linux/sched.h" | ||||
| #include "linux/mm.h" | ||||
| #include "asm/page.h" | ||||
| #include "asm/pgtable.h" | ||||
| #include "asm/uaccess.h" | ||||
| #include "asm/tlbflush.h" | ||||
| #include "mem_user.h" | ||||
| #include "os.h" | ||||
| #include "tlb.h" | ||||
| 
 | ||||
| static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last, | ||||
| 		    int finished, void **flush) | ||||
| { | ||||
| 	struct host_vm_op *op; | ||||
|         int i, ret=0; | ||||
| 
 | ||||
|         for(i = 0; i <= last && !ret; i++){ | ||||
| 		op = &ops[i]; | ||||
| 		switch(op->type){ | ||||
| 		case MMAP: | ||||
|                         ret = os_map_memory((void *) op->u.mmap.addr, | ||||
|                                             op->u.mmap.fd, op->u.mmap.offset, | ||||
|                                             op->u.mmap.len, op->u.mmap.r, | ||||
|                                             op->u.mmap.w, op->u.mmap.x); | ||||
| 			break; | ||||
| 		case MUNMAP: | ||||
|                         ret = os_unmap_memory((void *) op->u.munmap.addr, | ||||
|                                               op->u.munmap.len); | ||||
| 			break; | ||||
| 		case MPROTECT: | ||||
|                         ret = protect_memory(op->u.mprotect.addr, | ||||
|                                              op->u.munmap.len, | ||||
|                                              op->u.mprotect.r, | ||||
|                                              op->u.mprotect.w, | ||||
|                                              op->u.mprotect.x, 1); | ||||
| 			protect_memory(op->u.mprotect.addr, op->u.munmap.len, | ||||
| 				       op->u.mprotect.r, op->u.mprotect.w, | ||||
| 				       op->u.mprotect.x, 1); | ||||
| 			break; | ||||
| 		default: | ||||
| 			printk("Unknown op type %d in do_ops\n", op->type); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static void fix_range(struct mm_struct *mm, unsigned long start_addr,  | ||||
| 		      unsigned long end_addr, int force) | ||||
| { | ||||
|         if((current->thread.mode.tt.extern_pid != -1) && | ||||
|            (current->thread.mode.tt.extern_pid != os_getpid())) | ||||
|                 panic("fix_range fixing wrong address space, current = 0x%p", | ||||
|                       current); | ||||
| 
 | ||||
|         fix_range_common(mm, start_addr, end_addr, force, do_ops); | ||||
| } | ||||
| 
 | ||||
| atomic_t vmchange_seq = ATOMIC_INIT(1); | ||||
| 
 | ||||
| void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end) | ||||
| { | ||||
|         if(flush_tlb_kernel_range_common(start, end)) | ||||
|                 atomic_inc(&vmchange_seq); | ||||
| } | ||||
| 
 | ||||
| void flush_tlb_kernel_vm_tt(void) | ||||
| { | ||||
|         flush_tlb_kernel_range(start_vm, end_vm); | ||||
| } | ||||
| 
 | ||||
| void __flush_tlb_one_tt(unsigned long addr) | ||||
| { | ||||
|         flush_tlb_kernel_range(addr, addr + PAGE_SIZE); | ||||
| } | ||||
|    | ||||
| void flush_tlb_range_tt(struct vm_area_struct *vma, unsigned long start,  | ||||
| 		     unsigned long end) | ||||
| { | ||||
| 	if(vma->vm_mm != current->mm) return; | ||||
| 
 | ||||
| 	/* Assumes that the range start ... end is entirely within
 | ||||
| 	 * either process memory or kernel vm | ||||
| 	 */ | ||||
| 	if((start >= start_vm) && (start < end_vm)){ | ||||
| 		if(flush_tlb_kernel_range_common(start, end)) | ||||
| 			atomic_inc(&vmchange_seq); | ||||
| 	} | ||||
| 	else fix_range(vma->vm_mm, start, end, 0); | ||||
| } | ||||
| 
 | ||||
| void flush_tlb_mm_tt(struct mm_struct *mm) | ||||
| { | ||||
| 	unsigned long seq; | ||||
| 
 | ||||
| 	if(mm != current->mm) return; | ||||
| 
 | ||||
| 	fix_range(mm, 0, STACK_TOP, 0); | ||||
| 
 | ||||
| 	seq = atomic_read(&vmchange_seq); | ||||
| 	if(current->thread.mode.tt.vm_seq == seq) | ||||
| 		return; | ||||
| 	current->thread.mode.tt.vm_seq = seq; | ||||
| 	flush_tlb_kernel_range_common(start_vm, end_vm); | ||||
| } | ||||
| 
 | ||||
| void force_flush_all_tt(void) | ||||
| { | ||||
| 	fix_range(current->mm, 0, STACK_TOP, 1); | ||||
| 	flush_tlb_kernel_range_common(start_vm, end_vm); | ||||
| } | ||||
|  | @ -1,461 +0,0 @@ | |||
| /* 
 | ||||
|  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdarg.h> | ||||
| #include <unistd.h> | ||||
| #include <signal.h> | ||||
| #include <errno.h> | ||||
| #include <sched.h> | ||||
| #include <string.h> | ||||
| #include <sys/mman.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/wait.h> | ||||
| #include "user.h" | ||||
| #include "sysdep/ptrace.h" | ||||
| #include "sigcontext.h" | ||||
| #include "sysdep/sigcontext.h" | ||||
| #include "os.h" | ||||
| #include "mem_user.h" | ||||
| #include "process.h" | ||||
| #include "kern_util.h" | ||||
| #include "chan_user.h" | ||||
| #include "ptrace_user.h" | ||||
| #include "irq_user.h" | ||||
| #include "mode.h" | ||||
| #include "tt.h" | ||||
| 
 | ||||
| static int tracer_winch[2]; | ||||
| 
 | ||||
| int is_tracer_winch(int pid, int fd, void *data) | ||||
| { | ||||
| 	if(pid != os_getpgrp()) | ||||
| 		return(0); | ||||
| 
 | ||||
| 	register_winch_irq(tracer_winch[0], fd, -1, data); | ||||
| 	return(1); | ||||
| } | ||||
| 
 | ||||
| static void tracer_winch_handler(int sig) | ||||
| { | ||||
| 	int n; | ||||
| 	char c = 1; | ||||
| 
 | ||||
| 	n = os_write_file(tracer_winch[1], &c, sizeof(c)); | ||||
| 	if(n != sizeof(c)) | ||||
| 		printk("tracer_winch_handler - write failed, err = %d\n", -n); | ||||
| } | ||||
| 
 | ||||
| /* Called only by the tracing thread during initialization */ | ||||
| 
 | ||||
| static void setup_tracer_winch(void) | ||||
| { | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = os_pipe(tracer_winch, 1, 1); | ||||
| 	if(err < 0){ | ||||
| 		printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err); | ||||
| 		return; | ||||
| 	} | ||||
| 	signal(SIGWINCH, tracer_winch_handler); | ||||
| } | ||||
| 
 | ||||
| void attach_process(int pid) | ||||
| { | ||||
| 	if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) || | ||||
| 	   (ptrace(PTRACE_CONT, pid, 0, 0) < 0)) | ||||
| 		tracer_panic("OP_FORK failed to attach pid"); | ||||
| 	wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL); | ||||
| 	if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) | ||||
| 		tracer_panic("OP_FORK: PTRACE_SETOPTIONS failed, errno = %d", errno); | ||||
| 	if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) | ||||
| 		tracer_panic("OP_FORK failed to continue process"); | ||||
| } | ||||
| 
 | ||||
| void tracer_panic(char *format, ...) | ||||
| { | ||||
| 	va_list ap; | ||||
| 
 | ||||
| 	va_start(ap, format); | ||||
| 	vprintf(format, ap); | ||||
| 	va_end(ap); | ||||
| 	printf("\n"); | ||||
| 	while(1) pause(); | ||||
| } | ||||
| 
 | ||||
| static void tracer_segv(int sig, struct sigcontext sc) | ||||
| { | ||||
|         struct faultinfo fi; | ||||
|         GET_FAULTINFO_FROM_SC(fi, &sc); | ||||
| 	printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n", | ||||
|                FAULT_ADDRESS(fi), SC_IP(&sc)); | ||||
| 	while(1) | ||||
| 		pause(); | ||||
| } | ||||
| 
 | ||||
| /* Changed early in boot, and then only read */ | ||||
| int debug = 0; | ||||
| int debug_stop = 1; | ||||
| int debug_parent = 0; | ||||
| int honeypot = 0; | ||||
| 
 | ||||
| static int signal_tramp(void *arg) | ||||
| { | ||||
| 	int (*proc)(void *); | ||||
| 
 | ||||
| 	if(honeypot && munmap((void *) (host_task_size - 0x10000000), | ||||
| 			      0x10000000))  | ||||
| 		panic("Unmapping stack failed"); | ||||
| 	if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) | ||||
| 		panic("ptrace PTRACE_TRACEME failed"); | ||||
| 	os_stop_process(os_getpid()); | ||||
| 	change_sig(SIGWINCH, 0); | ||||
| 	signal(SIGUSR1, SIG_IGN); | ||||
| 	change_sig(SIGCHLD, 0); | ||||
| 	signal(SIGSEGV, (__sighandler_t) sig_handler); | ||||
| 	set_cmdline("(idle thread)"); | ||||
| 	set_init_pid(os_getpid()); | ||||
| 	init_irq_signals(0); | ||||
| 	proc = arg; | ||||
| 	return((*proc)(NULL)); | ||||
| } | ||||
| 
 | ||||
| static void sleeping_process_signal(int pid, int sig) | ||||
| { | ||||
| 	switch(sig){ | ||||
| 	/* These two result from UML being ^Z-ed and bg-ed.  PTRACE_CONT is
 | ||||
| 	 * right because the process must be in the kernel already. | ||||
| 	 */ | ||||
| 	case SIGCONT: | ||||
| 	case SIGTSTP: | ||||
| 		if(ptrace(PTRACE_CONT, pid, 0, sig) < 0) | ||||
| 			tracer_panic("sleeping_process_signal : Failed to " | ||||
| 				     "continue pid %d, signal = %d, " | ||||
| 				     "errno = %d\n", pid, sig, errno); | ||||
| 		break; | ||||
| 
 | ||||
| 	/* This happens when the debugger (e.g. strace) is doing system call 
 | ||||
| 	 * tracing on the kernel.  During a context switch, the current task | ||||
| 	 * will be set to the incoming process and the outgoing process will | ||||
| 	 * hop into write and then read.  Since it's not the current process | ||||
| 	 * any more, the trace of those will land here.  So, we need to just  | ||||
| 	 * PTRACE_SYSCALL it. | ||||
| 	 */ | ||||
| 	case (SIGTRAP + 0x80): | ||||
| 		if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) | ||||
| 			tracer_panic("sleeping_process_signal : Failed to " | ||||
| 				     "PTRACE_SYSCALL pid %d, errno = %d\n", | ||||
| 				     pid, errno); | ||||
| 		break; | ||||
| 	case SIGSTOP: | ||||
| 		break; | ||||
| 	default: | ||||
| 		tracer_panic("sleeping process %d got unexpected " | ||||
| 			     "signal : %d\n", pid, sig); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Accessed only by the tracing thread */ | ||||
| int debugger_pid = -1; | ||||
| int debugger_parent = -1; | ||||
| int debugger_fd = -1; | ||||
| int gdb_pid = -1; | ||||
| 
 | ||||
| struct { | ||||
| 	int pid; | ||||
| 	int signal; | ||||
| 	unsigned long addr; | ||||
| 	struct timeval time; | ||||
| } signal_record[1024][32]; | ||||
| 
 | ||||
| int signal_index[32]; | ||||
| int nsignals = 0; | ||||
| int debug_trace = 0; | ||||
| 
 | ||||
| extern void signal_usr1(int sig); | ||||
| 
 | ||||
| int tracing_pid = -1; | ||||
| 
 | ||||
| int tracer(int (*init_proc)(void *), void *sp) | ||||
| { | ||||
| 	void *task = NULL; | ||||
| 	int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0; | ||||
| 	int proc_id = 0, n, err, old_tracing = 0, strace = 0; | ||||
| 	int local_using_sysemu = 0; | ||||
| 
 | ||||
| 	signal(SIGPIPE, SIG_IGN); | ||||
| 	setup_tracer_winch(); | ||||
| 	tracing_pid = os_getpid(); | ||||
| 	printf("tracing thread pid = %d\n", tracing_pid); | ||||
| 
 | ||||
| 	pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc); | ||||
| 	CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); | ||||
| 	if(n < 0){ | ||||
| 		printf("waitpid on idle thread failed, errno = %d\n", errno); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) { | ||||
| 		printf("Failed to PTRACE_SETOPTIONS for idle thread, errno = %d\n", errno); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){ | ||||
| 		printf("Failed to continue idle thread, errno = %d\n", errno); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 
 | ||||
| 	signal(SIGSEGV, (sighandler_t) tracer_segv); | ||||
| 	signal(SIGUSR1, signal_usr1); | ||||
| 	if(debug_trace){ | ||||
| 		printf("Tracing thread pausing to be attached\n"); | ||||
| 		stop(); | ||||
| 	} | ||||
| 	if(debug){ | ||||
| 		if(gdb_pid != -1)  | ||||
| 			debugger_pid = attach_debugger(pid, gdb_pid, 1); | ||||
| 		else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop); | ||||
| 		if(debug_parent){ | ||||
| 			debugger_parent = os_process_parent(debugger_pid); | ||||
| 			init_parent_proxy(debugger_parent); | ||||
| 			err = attach(debugger_parent); | ||||
| 			if(err){ | ||||
| 				printf("Failed to attach debugger parent %d, " | ||||
| 				       "errno = %d\n", debugger_parent, -err); | ||||
| 				debugger_parent = -1; | ||||
| 			} | ||||
| 			else { | ||||
| 				if(ptrace(PTRACE_SYSCALL, debugger_parent,  | ||||
| 					  0, 0) < 0){ | ||||
| 					printf("Failed to continue debugger " | ||||
| 					       "parent, errno = %d\n", errno); | ||||
| 					debugger_parent = -1; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	set_cmdline("(tracing thread)"); | ||||
| 	while(1){ | ||||
| 		CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED)); | ||||
| 		if(pid <= 0){ | ||||
| 			if(errno != ECHILD){ | ||||
| 				printf("wait failed - errno = %d\n", errno); | ||||
| 			} | ||||
| 			continue; | ||||
| 		} | ||||
| 		if(pid == debugger_pid){ | ||||
| 			int cont = 0; | ||||
| 
 | ||||
| 			if(WIFEXITED(status) || WIFSIGNALED(status)) | ||||
| 				debugger_pid = -1; | ||||
| 			/* XXX Figure out how to deal with gdb and SMP */ | ||||
| 			else cont = debugger_signal(status, cpu_tasks[0].pid); | ||||
| 			if(cont == PTRACE_SYSCALL) strace = 1; | ||||
| 			continue; | ||||
| 		} | ||||
| 		else if(pid == debugger_parent){ | ||||
| 			debugger_parent_signal(status, pid); | ||||
| 			continue; | ||||
| 		} | ||||
| 		nsignals++; | ||||
| 		if(WIFEXITED(status)) ; | ||||
| #ifdef notdef | ||||
| 		{ | ||||
| 			printf("Child %d exited with status %d\n", pid,  | ||||
| 			       WEXITSTATUS(status)); | ||||
| 		} | ||||
| #endif | ||||
| 		else if(WIFSIGNALED(status)){ | ||||
| 			sig = WTERMSIG(status); | ||||
| 			if(sig != 9){ | ||||
| 				printf("Child %d exited with signal %d\n", pid, | ||||
| 				       sig); | ||||
| 			} | ||||
| 		} | ||||
| 		else if(WIFSTOPPED(status)){ | ||||
| 			proc_id = pid_to_processor_id(pid); | ||||
| 			sig = WSTOPSIG(status); | ||||
| 			if(proc_id == -1){ | ||||
| 				sleeping_process_signal(pid, sig); | ||||
| 				continue; | ||||
| 			} | ||||
| 
 | ||||
| 			task = cpu_tasks[proc_id].task; | ||||
| 			tracing = is_tracing(task); | ||||
| 			old_tracing = tracing; | ||||
| 
 | ||||
| 			/* Assume: no syscall, when coming from user */ | ||||
| 			if ( tracing ) | ||||
| 				do_sigtrap(task); | ||||
| 
 | ||||
| 			switch(sig){ | ||||
| 			case SIGUSR1: | ||||
| 				sig = 0; | ||||
| 				op = do_proc_op(task, proc_id); | ||||
| 				switch(op){ | ||||
| 				/*
 | ||||
| 				 * This is called when entering user mode; after | ||||
| 				 * this, we start intercepting syscalls. | ||||
| 				 * | ||||
| 				 * In fact, a process is started in kernel mode, | ||||
| 				 * so with is_tracing() == 0 (and that is reset | ||||
| 				 * when executing syscalls, since UML kernel has | ||||
| 				 * the right to do syscalls); | ||||
| 				 */ | ||||
| 				case OP_TRACE_ON: | ||||
| 					arch_leave_kernel(task, pid); | ||||
| 					tracing = 1; | ||||
| 					break; | ||||
| 				case OP_REBOOT: | ||||
| 				case OP_HALT: | ||||
| 					unmap_physmem(); | ||||
| 					kmalloc_ok = 0; | ||||
| 					os_kill_ptraced_process(pid, 0); | ||||
| 					/* Now let's reap remaining zombies */ | ||||
| 					errno = 0; | ||||
| 					do { | ||||
| 						waitpid(-1, &status, | ||||
| 							WUNTRACED); | ||||
| 					} while (errno != ECHILD); | ||||
| 					return(op == OP_REBOOT); | ||||
| 				case OP_NONE: | ||||
| 					printf("Detaching pid %d\n", pid); | ||||
| 					detach(pid, SIGSTOP); | ||||
| 					continue; | ||||
| 				default: | ||||
| 					break; | ||||
| 				} | ||||
| 				/* OP_EXEC switches host processes on us,
 | ||||
| 				 * we want to continue the new one. | ||||
| 				 */ | ||||
| 				pid = cpu_tasks[proc_id].pid; | ||||
| 				break; | ||||
| 			case (SIGTRAP + 0x80): | ||||
| 				if(!tracing && (debugger_pid != -1)){ | ||||
| 					child_signal(pid, status & 0x7fff); | ||||
| 					continue; | ||||
| 				} | ||||
| 				tracing = 0; | ||||
| 				/* local_using_sysemu has been already set
 | ||||
| 				 * below, since if we are here, is_tracing() on | ||||
| 				 * the traced task was 1, i.e. the process had | ||||
| 				 * already run through one iteration of the | ||||
| 				 * loop which executed a OP_TRACE_ON request.*/ | ||||
| 				do_syscall(task, pid, local_using_sysemu); | ||||
| 				sig = SIGUSR2; | ||||
| 				break; | ||||
| 			case SIGTRAP: | ||||
| 				if(!tracing && (debugger_pid != -1)){ | ||||
| 					child_signal(pid, status); | ||||
| 					continue; | ||||
| 				} | ||||
| 				tracing = 0; | ||||
| 				break; | ||||
| 			case SIGPROF: | ||||
| 				if(tracing) sig = 0; | ||||
| 				break; | ||||
| 			case SIGCHLD: | ||||
| 			case SIGHUP: | ||||
| 				sig = 0; | ||||
| 				break; | ||||
| 			case SIGSEGV: | ||||
| 			case SIGIO: | ||||
| 			case SIGALRM: | ||||
| 			case SIGVTALRM: | ||||
| 			case SIGFPE: | ||||
| 			case SIGBUS: | ||||
| 			case SIGILL: | ||||
| 			case SIGWINCH: | ||||
| 
 | ||||
| 			default: | ||||
| 				tracing = 0; | ||||
| 				break; | ||||
| 			} | ||||
| 			set_tracing(task, tracing); | ||||
| 
 | ||||
| 			if(!tracing && old_tracing) | ||||
| 				arch_enter_kernel(task, pid); | ||||
| 
 | ||||
| 			if(!tracing && (debugger_pid != -1) && (sig != 0) && | ||||
| 				(sig != SIGALRM) && (sig != SIGVTALRM) && | ||||
| 				(sig != SIGSEGV) && (sig != SIGTRAP) && | ||||
| 				(sig != SIGUSR2) && (sig != SIGIO) && | ||||
| 				(sig != SIGFPE)){ | ||||
| 				child_signal(pid, status); | ||||
| 				continue; | ||||
| 			} | ||||
| 
 | ||||
| 			local_using_sysemu = get_using_sysemu(); | ||||
| 
 | ||||
| 			if(tracing) | ||||
| 				cont_type = SELECT_PTRACE_OPERATION(local_using_sysemu, | ||||
| 				                                    singlestepping(task)); | ||||
| 			else if((debugger_pid != -1) && strace) | ||||
| 				cont_type = PTRACE_SYSCALL; | ||||
| 			else | ||||
| 				cont_type = PTRACE_CONT; | ||||
| 
 | ||||
| 			if(ptrace(cont_type, pid, 0, sig) != 0){ | ||||
| 				tracer_panic("ptrace failed to continue " | ||||
| 					     "process - errno = %d\n",  | ||||
| 					     errno); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return(0); | ||||
| } | ||||
| 
 | ||||
| static int __init uml_debug_setup(char *line, int *add) | ||||
| { | ||||
| 	char *next; | ||||
| 
 | ||||
| 	debug = 1; | ||||
| 	*add = 0; | ||||
| 	if(*line != '=') return(0); | ||||
| 	line++; | ||||
| 
 | ||||
| 	while(line != NULL){ | ||||
| 		next = strchr(line, ','); | ||||
| 		if(next) *next++ = '\0'; | ||||
| 		 | ||||
| 		if(!strcmp(line, "go"))	debug_stop = 0; | ||||
| 		else if(!strcmp(line, "parent")) debug_parent = 1; | ||||
| 		else printf("Unknown debug option : '%s'\n", line); | ||||
| 
 | ||||
| 		line = next; | ||||
| 	} | ||||
| 	return(0); | ||||
| } | ||||
| 
 | ||||
| __uml_setup("debug", uml_debug_setup, | ||||
| "debug\n" | ||||
| "    Starts up the kernel under the control of gdb. See the \n" | ||||
| "    kernel debugging tutorial and the debugging session pages\n" | ||||
| "    at http://user-mode-linux.sourceforge.net/ for more information.\n\n" | ||||
| ); | ||||
| 
 | ||||
| static int __init uml_debugtrace_setup(char *line, int *add) | ||||
| { | ||||
| 	debug_trace = 1; | ||||
| 	return 0; | ||||
| } | ||||
| __uml_setup("debugtrace", uml_debugtrace_setup, | ||||
| "debugtrace\n" | ||||
| "    Causes the tracing thread to pause until it is attached by a\n" | ||||
| "    debugger and continued.  This is mostly for debugging crashes\n" | ||||
| "    early during boot, and should be pretty much obsoleted by\n" | ||||
| "    the debug switch.\n\n" | ||||
| ); | ||||
| 
 | ||||
| /*
 | ||||
|  * 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: | ||||
|  */ | ||||
|  | @ -1,70 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <errno.h> | ||||
| #include <signal.h> | ||||
| #include "sysdep/ptrace.h" | ||||
| #include "sysdep/sigcontext.h" | ||||
| #include "kern_util.h" | ||||
| #include "task.h" | ||||
| #include "tt.h" | ||||
| #include "os.h" | ||||
| 
 | ||||
| void sig_handler_common_tt(int sig, void *sc_ptr) | ||||
| { | ||||
| 	struct sigcontext *sc = sc_ptr; | ||||
| 	struct tt_regs save_regs, *r; | ||||
| 	int save_errno = errno, is_user = 0; | ||||
| 	void (*handler)(int, union uml_pt_regs *); | ||||
| 
 | ||||
| 	/* This is done because to allow SIGSEGV to be delivered inside a SEGV
 | ||||
| 	 * handler.  This can happen in copy_user, and if SEGV is disabled, | ||||
| 	 * the process will die. | ||||
| 	 */ | ||||
| 	if(sig == SIGSEGV) | ||||
| 		change_sig(SIGSEGV, 1); | ||||
| 
 | ||||
| 	r = &TASK_REGS(get_current())->tt; | ||||
|         if ( sig == SIGFPE || sig == SIGSEGV || | ||||
|              sig == SIGBUS || sig == SIGILL || | ||||
|              sig == SIGTRAP ) { | ||||
|                 GET_FAULTINFO_FROM_SC(r->faultinfo, sc); | ||||
|         } | ||||
| 	save_regs = *r; | ||||
| 	if (sc) | ||||
| 		is_user = user_context(SC_SP(sc)); | ||||
| 	r->sc = sc; | ||||
| 	if(sig != SIGUSR2)  | ||||
| 		r->syscall = -1; | ||||
| 
 | ||||
| 	handler = sig_info[sig]; | ||||
| 
 | ||||
| 	/* unblock SIGALRM, SIGVTALRM, SIGIO if sig isn't IRQ signal */ | ||||
| 	if (sig != SIGIO && sig != SIGWINCH && | ||||
| 	    sig != SIGVTALRM && sig != SIGALRM) | ||||
| 		unblock_signals(); | ||||
| 
 | ||||
| 	handler(sig, (union uml_pt_regs *) r); | ||||
| 
 | ||||
| 	if(is_user){ | ||||
| 		interrupt_end(); | ||||
| 		block_signals(); | ||||
| 		set_user_mode(NULL); | ||||
| 	} | ||||
| 	*r = save_regs; | ||||
| 	errno = save_errno; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * 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: | ||||
|  */ | ||||
|  | @ -1,73 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include "linux/sched.h" | ||||
| #include "asm/uaccess.h" | ||||
| 
 | ||||
| int copy_from_user_tt(void *to, const void __user *from, int n) | ||||
| { | ||||
| 	if(!access_ok(VERIFY_READ, from, n)) | ||||
| 		return(n); | ||||
| 
 | ||||
| 	return(__do_copy_from_user(to, from, n, ¤t->thread.fault_addr, | ||||
| 				   ¤t->thread.fault_catcher)); | ||||
| } | ||||
| 
 | ||||
| int copy_to_user_tt(void __user *to, const void *from, int n) | ||||
| { | ||||
| 	if(!access_ok(VERIFY_WRITE, to, n)) | ||||
| 		return(n); | ||||
| 
 | ||||
| 	return(__do_copy_to_user(to, from, n, ¤t->thread.fault_addr, | ||||
| 				 ¤t->thread.fault_catcher)); | ||||
| } | ||||
| 
 | ||||
| int strncpy_from_user_tt(char *dst, const char __user *src, int count) | ||||
| { | ||||
| 	int n; | ||||
| 
 | ||||
| 	if(!access_ok(VERIFY_READ, src, 1)) | ||||
| 		return(-EFAULT); | ||||
| 
 | ||||
| 	n = __do_strncpy_from_user(dst, src, count, | ||||
| 				   ¤t->thread.fault_addr, | ||||
| 				   ¤t->thread.fault_catcher); | ||||
| 	if(n < 0) return(-EFAULT); | ||||
| 	return(n); | ||||
| } | ||||
| 
 | ||||
| int __clear_user_tt(void __user *mem, int len) | ||||
| { | ||||
| 	return(__do_clear_user(mem, len, | ||||
| 			       ¤t->thread.fault_addr, | ||||
| 			       ¤t->thread.fault_catcher)); | ||||
| } | ||||
| 
 | ||||
| int clear_user_tt(void __user *mem, int len) | ||||
| { | ||||
| 	if(!access_ok(VERIFY_WRITE, mem, len)) | ||||
| 		return(len); | ||||
| 
 | ||||
| 	return(__do_clear_user(mem, len, ¤t->thread.fault_addr, | ||||
| 			       ¤t->thread.fault_catcher)); | ||||
| } | ||||
| 
 | ||||
| int strnlen_user_tt(const void __user *str, int len) | ||||
| { | ||||
| 	return(__do_strnlen_user(str, len, | ||||
| 				 ¤t->thread.fault_addr, | ||||
| 				 ¤t->thread.fault_catcher)); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * 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: | ||||
|  */ | ||||
|  | @ -1,105 +0,0 @@ | |||
| /* 
 | ||||
|  * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) | ||||
|  * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include <string.h> | ||||
| #include "uml_uaccess.h" | ||||
| #include "task.h" | ||||
| #include "kern_util.h" | ||||
| #include "os.h" | ||||
| #include "longjmp.h" | ||||
| 
 | ||||
| int __do_copy_from_user(void *to, const void *from, int n, | ||||
| 			void **fault_addr, void **fault_catcher) | ||||
| { | ||||
| 	struct tt_regs save = TASK_REGS(get_current())->tt; | ||||
| 	unsigned long fault; | ||||
| 	int faulted; | ||||
| 
 | ||||
| 	fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, | ||||
| 			       __do_copy, &faulted); | ||||
| 	TASK_REGS(get_current())->tt = save; | ||||
| 
 | ||||
| 	if(!faulted) | ||||
| 		return 0; | ||||
| 	else if (fault) | ||||
| 		return n - (fault - (unsigned long) from); | ||||
| 	else | ||||
| 		/* In case of a general protection fault, we don't have the
 | ||||
| 		 * fault address, so NULL is used instead. Pretend we didn't | ||||
| 		 * copy anything. */ | ||||
| 		return n; | ||||
| } | ||||
| 
 | ||||
| static void __do_strncpy(void *dst, const void *src, int count) | ||||
| { | ||||
| 	strncpy(dst, src, count); | ||||
| }	 | ||||
| 
 | ||||
| int __do_strncpy_from_user(char *dst, const char *src, unsigned long count, | ||||
| 			   void **fault_addr, void **fault_catcher) | ||||
| { | ||||
| 	struct tt_regs save = TASK_REGS(get_current())->tt; | ||||
| 	unsigned long fault; | ||||
| 	int faulted; | ||||
| 
 | ||||
| 	fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher, | ||||
| 			       __do_strncpy, &faulted); | ||||
| 	TASK_REGS(get_current())->tt = save; | ||||
| 
 | ||||
| 	if(!faulted) return(strlen(dst)); | ||||
| 	else return(-1); | ||||
| } | ||||
| 
 | ||||
| static void __do_clear(void *to, const void *from, int n) | ||||
| { | ||||
| 	memset(to, 0, n); | ||||
| }	 | ||||
| 
 | ||||
| int __do_clear_user(void *mem, unsigned long len, | ||||
| 		    void **fault_addr, void **fault_catcher) | ||||
| { | ||||
| 	struct tt_regs save = TASK_REGS(get_current())->tt; | ||||
| 	unsigned long fault; | ||||
| 	int faulted; | ||||
| 
 | ||||
| 	fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher, | ||||
| 			       __do_clear, &faulted); | ||||
| 	TASK_REGS(get_current())->tt = save; | ||||
| 
 | ||||
| 	if(!faulted) return(0); | ||||
| 	else return(len - (fault - (unsigned long) mem)); | ||||
| } | ||||
| 
 | ||||
| int __do_strnlen_user(const char *str, unsigned long n, | ||||
| 		      void **fault_addr, void **fault_catcher) | ||||
| { | ||||
| 	struct tt_regs save = TASK_REGS(get_current())->tt; | ||||
| 	int ret; | ||||
| 	unsigned long *faddrp = (unsigned long *)fault_addr; | ||||
| 	jmp_buf jbuf; | ||||
| 
 | ||||
| 	*fault_catcher = &jbuf; | ||||
| 	if(UML_SETJMP(&jbuf) == 0) | ||||
| 		ret = strlen(str) + 1; | ||||
| 	else ret = *faddrp - (unsigned long) str; | ||||
| 
 | ||||
| 	*fault_addr = NULL; | ||||
| 	*fault_catcher = NULL; | ||||
| 
 | ||||
| 	TASK_REGS(get_current())->tt = save; | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * 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: | ||||
|  */ | ||||
|  | @ -38,9 +38,7 @@ | |||
| #include "choose-mode.h" | ||||
| #include "mode_kern.h" | ||||
| #include "mode.h" | ||||
| #ifdef UML_CONFIG_MODE_SKAS | ||||
| #include "skas.h" | ||||
| #endif | ||||
| 
 | ||||
| #define DEFAULT_COMMAND_LINE "root=98:0" | ||||
| 
 | ||||
|  | @ -132,43 +130,12 @@ unsigned long end_vm; | |||
| /* Set in uml_ncpus_setup */ | ||||
| int ncpus = 1; | ||||
| 
 | ||||
| #ifdef CONFIG_CMDLINE_ON_HOST | ||||
| /* Pointer set in linux_main, the array itself is private to each thread,
 | ||||
|  * and changed at address space creation time so this poses no concurrency | ||||
|  * problems. | ||||
|  */ | ||||
| static char *argv1_begin = NULL; | ||||
| static char *argv1_end = NULL; | ||||
| #endif | ||||
| 
 | ||||
| /* Set in early boot */ | ||||
| static int have_root __initdata = 0; | ||||
| 
 | ||||
| /* Set in uml_mem_setup and modified in linux_main */ | ||||
| long long physmem_size = 32 * 1024 * 1024; | ||||
| 
 | ||||
| void set_cmdline(char *cmd) | ||||
| { | ||||
| #ifdef CONFIG_CMDLINE_ON_HOST | ||||
| 	char *umid, *ptr; | ||||
| 
 | ||||
| 	if(CHOOSE_MODE(honeypot, 0)) return; | ||||
| 
 | ||||
| 	umid = get_umid(); | ||||
| 	if(*umid != '\0'){ | ||||
| 		snprintf(argv1_begin,  | ||||
| 			 (argv1_end - argv1_begin) * sizeof(*ptr),  | ||||
| 			 "(%s) ", umid); | ||||
| 		ptr = &argv1_begin[strlen(argv1_begin)]; | ||||
| 	} | ||||
| 	else ptr = argv1_begin; | ||||
| 
 | ||||
| 	snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd); | ||||
| 	memset(argv1_begin + strlen(argv1_begin), '\0',  | ||||
| 	       argv1_end - argv1_begin - strlen(argv1_begin)); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static char *usage_string =  | ||||
| "User Mode Linux v%s\n" | ||||
| "	available at http://user-mode-linux.sourceforge.net/\n\n"; | ||||
|  | @ -201,13 +168,10 @@ __uml_setup("root=", uml_root_setup, | |||
| "        root=/dev/ubd5\n\n" | ||||
| ); | ||||
| 
 | ||||
| #ifndef CONFIG_MODE_TT | ||||
| 
 | ||||
| static int __init no_skas_debug_setup(char *line, int *add) | ||||
| { | ||||
| 	printf("'debug' is not necessary to gdb UML in skas mode - run \n"); | ||||
| 	printf("'gdb linux' and disable CONFIG_CMDLINE_ON_HOST if gdb \n"); | ||||
| 	printf("doesn't work as expected\n"); | ||||
| 	printf("'gdb linux'"); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | @ -217,8 +181,6 @@ __uml_setup("debug", no_skas_debug_setup, | |||
| "    this flag is not needed to run gdb on UML in skas mode\n\n" | ||||
| ); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_SMP | ||||
| static int __init uml_ncpus_setup(char *line, int *add) | ||||
| { | ||||
|  | @ -236,52 +198,6 @@ __uml_setup("ncpus=", uml_ncpus_setup, | |||
| ); | ||||
| #endif | ||||
| 
 | ||||
| static int force_tt = 0; | ||||
| 
 | ||||
| #if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS) | ||||
| #define DEFAULT_TT 0 | ||||
| 
 | ||||
| static int __init mode_tt_setup(char *line, int *add) | ||||
| { | ||||
| 	force_tt = 1; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #else | ||||
| #ifdef CONFIG_MODE_SKAS | ||||
| 
 | ||||
| #define DEFAULT_TT 0 | ||||
| 
 | ||||
| static int __init mode_tt_setup(char *line, int *add) | ||||
| { | ||||
| 	printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n"); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #else | ||||
| #ifdef CONFIG_MODE_TT | ||||
| 
 | ||||
| #define DEFAULT_TT 1 | ||||
| 
 | ||||
| static int __init mode_tt_setup(char *line, int *add) | ||||
| { | ||||
| 	printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n"); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| __uml_setup("mode=tt", mode_tt_setup, | ||||
| "mode=tt\n" | ||||
| "    When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n" | ||||
| "    forces UML to run in tt (tracing thread) mode.  It is not the default\n" | ||||
| "    because it's slower and less secure than skas mode.\n\n" | ||||
| ); | ||||
| 
 | ||||
| int mode_tt = DEFAULT_TT; | ||||
| 
 | ||||
| static int __init Usage(char *line, int *add) | ||||
| { | ||||
| 	const char **p; | ||||
|  | @ -357,29 +273,13 @@ int __init linux_main(int argc, char **argv) | |||
| 		add_arg(DEFAULT_COMMAND_LINE); | ||||
| 
 | ||||
| 	os_early_checks(); | ||||
| 	if (force_tt) | ||||
| 		clear_can_do_skas(); | ||||
| 	mode_tt = force_tt ? 1 : !can_do_skas(); | ||||
| #ifndef CONFIG_MODE_TT | ||||
| 	if (mode_tt) { | ||||
| 		/*Since CONFIG_MODE_TT is #undef'ed, force_tt cannot be 1. So,
 | ||||
| 		 * can_do_skas() returned 0, and the message is correct. */ | ||||
| 		printf("Support for TT mode is disabled, and no SKAS support is present on the host.\n"); | ||||
| 		exit(1); | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| #ifndef CONFIG_MODE_SKAS | ||||
| 	mode = "TT"; | ||||
| #else | ||||
| 	/* Show to the user the result of selection */ | ||||
| 	if (mode_tt) | ||||
| 		mode = "TT"; | ||||
| 	else if (proc_mm && ptrace_faultinfo) | ||||
| 	can_do_skas(); | ||||
| 
 | ||||
| 	if (proc_mm && ptrace_faultinfo) | ||||
| 		mode = "SKAS3"; | ||||
| 	else | ||||
| 		mode = "SKAS0"; | ||||
| #endif | ||||
| 
 | ||||
| 	printf("UML running in %s mode\n", mode); | ||||
| 
 | ||||
|  | @ -411,11 +311,6 @@ int __init linux_main(int argc, char **argv) | |||
| 
 | ||||
| 	setup_machinename(init_utsname()->machine); | ||||
| 
 | ||||
| #ifdef CONFIG_CMDLINE_ON_HOST | ||||
| 	argv1_begin = argv[1]; | ||||
| 	argv1_end = &argv[1][strlen(argv[1])]; | ||||
| #endif | ||||
| 
 | ||||
| 	highmem = 0; | ||||
| 	iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK; | ||||
| 	max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC; | ||||
|  |  | |||
|  | @ -18,13 +18,6 @@ SECTIONS | |||
| 
 | ||||
|   . = START + SIZEOF_HEADERS;
 | ||||
| 
 | ||||
| #ifdef MODE_TT | ||||
|   .remap_data : { UNMAP_PATH (.data .bss) } | ||||
|   .remap : { UNMAP_PATH (.text) } | ||||
| 
 | ||||
|   . = ALIGN(4096);		/* Init code and data */
 | ||||
| #endif | ||||
| 
 | ||||
|   _text = .;
 | ||||
|   _stext = .;
 | ||||
|   __init_begin = .;
 | ||||
|  |  | |||
|  | @ -5,12 +5,7 @@ | |||
| 
 | ||||
| obj-y = aio.o elf_aux.o execvp.o file.o helper.o irq.o main.o mem.o process.o \
 | ||||
| 	registers.o sigio.o signal.o start_up.o time.o trap.o tty.o uaccess.o \
 | ||||
| 	umid.o tls.o user_syms.o util.o drivers/ sys-$(SUBARCH)/ | ||||
| 
 | ||||
| obj-$(CONFIG_MODE_SKAS) += skas/ | ||||
| 
 | ||||
| obj-$(CONFIG_MODE_TT) += tt.o | ||||
| user-objs-$(CONFIG_MODE_TT) += tt.o | ||||
| 	umid.o tls.o user_syms.o util.o drivers/ sys-$(SUBARCH)/ skas/ | ||||
| 
 | ||||
| obj-$(CONFIG_TTY_LOG) += tty_log.o | ||||
| user-objs-$(CONFIG_TTY_LOG) += tty_log.o | ||||
|  |  | |||
|  | @ -25,9 +25,6 @@ | |||
| #include "um_malloc.h" | ||||
| #include "kern_constants.h" | ||||
| 
 | ||||
| /* Set in main, unchanged thereafter */ | ||||
| char *linux_prog; | ||||
| 
 | ||||
| #define PGD_BOUND (4 * 1024 * 1024) | ||||
| #define STACKSIZE (8 * 1024 * 1024) | ||||
| #define THREAD_NAME_LEN (256) | ||||
|  | @ -125,35 +122,6 @@ int __init main(int argc, char **argv, char **envp) | |||
| 	char **new_argv; | ||||
| 	int ret, i, err; | ||||
| 
 | ||||
| #ifdef UML_CONFIG_CMDLINE_ON_HOST | ||||
| 	/* Allocate memory for thread command lines */ | ||||
| 	if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){ | ||||
| 
 | ||||
| 		char padding[THREAD_NAME_LEN] = { | ||||
| 			[ 0 ...  THREAD_NAME_LEN - 2] = ' ', '\0' | ||||
| 		}; | ||||
| 
 | ||||
| 		new_argv = malloc((argc + 2) * sizeof(char*)); | ||||
| 		if(!new_argv) { | ||||
| 			perror("Allocating extended argv"); | ||||
| 			exit(1); | ||||
| 		} | ||||
| 
 | ||||
| 		new_argv[0] = argv[0]; | ||||
| 		new_argv[1] = padding; | ||||
| 
 | ||||
| 		for(i = 2; i <= argc; i++) | ||||
| 			new_argv[i] = argv[i - 1]; | ||||
| 		new_argv[argc + 1] = NULL; | ||||
| 
 | ||||
| 		execvp(new_argv[0], new_argv); | ||||
| 		perror("execing with extended args"); | ||||
| 		exit(1); | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	linux_prog = argv[0]; | ||||
| 
 | ||||
| 	set_stklim(); | ||||
| 
 | ||||
| 	setup_env_path(); | ||||
|  |  | |||
|  | @ -133,13 +133,6 @@ void os_kill_ptraced_process(int pid, int reap_child) | |||
| 		CATCH_EINTR(waitpid(pid, NULL, 0)); | ||||
| } | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| void os_usr1_process(int pid) | ||||
| { | ||||
| 	kill(pid, SIGUSR1); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /* Don't use the glibc version, which caches the result in TLS. It misses some
 | ||||
|  * syscalls, and also breaks with clone(), which does not unshare the TLS. | ||||
|  */ | ||||
|  | @ -239,30 +232,6 @@ int __init can_drop_memory(void) | |||
| 	return ok; | ||||
| } | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) | ||||
| { | ||||
| 	int flags = 0, pages; | ||||
| 
 | ||||
| 	if(sig_stack != NULL){ | ||||
| 		pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER); | ||||
| 		set_sigstack(sig_stack, pages * UM_KERN_PAGE_SIZE); | ||||
| 		flags = SA_ONSTACK; | ||||
| 	} | ||||
| 	if(usr1_handler){ | ||||
| 		struct sigaction sa; | ||||
| 
 | ||||
| 		sa.sa_handler = usr1_handler; | ||||
| 		sigemptyset(&sa.sa_mask); | ||||
| 		sa.sa_flags = flags; | ||||
| 		sa.sa_restorer = NULL; | ||||
| 		if(sigaction(SIGUSR1, &sa, NULL) < 0) | ||||
| 			panic("init_new_thread_stack - sigaction failed - " | ||||
| 			      "errno = %d\n", errno); | ||||
| 	} | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| void init_new_thread_signals(void) | ||||
| { | ||||
| 	set_handler(SIGSEGV, (__sighandler_t) sig_handler, SA_ONSTACK, | ||||
|  |  | |||
|  | @ -35,12 +35,9 @@ | |||
| #include "mode.h" | ||||
| #include "tempfile.h" | ||||
| #include "kern_constants.h" | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_SKAS | ||||
| #include "skas.h" | ||||
| #include "skas_ptrace.h" | ||||
| #include "registers.h" | ||||
| #endif | ||||
| 
 | ||||
| static int ptrace_child(void *arg) | ||||
| { | ||||
|  | @ -407,7 +404,6 @@ __uml_setup("noptraceldt", noptraceldt_cmd_param, | |||
| "    To support PTRACE_LDT, the host needs to be patched using\n" | ||||
| "    the current skas3 patch.\n\n"); | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_SKAS | ||||
| static inline void check_skas3_ptrace_faultinfo(void) | ||||
| { | ||||
| 	struct ptrace_faultinfo fi; | ||||
|  | @ -504,12 +500,6 @@ int can_do_skas(void) | |||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| #else | ||||
| int can_do_skas(void) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| int __init parse_iomem(char *str, int *add) | ||||
| { | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
| # Licensed under the GPL
 | ||||
| #
 | ||||
| 
 | ||||
| obj-$(CONFIG_MODE_SKAS) = registers.o signal.o tls.o | ||||
| obj-y = registers.o signal.o tls.o | ||||
| 
 | ||||
| USER_OBJS := $(obj-y) | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
| # Licensed under the GPL
 | ||||
| #
 | ||||
| 
 | ||||
| obj-$(CONFIG_MODE_SKAS) = registers.o prctl.o signal.o | ||||
| obj-y = registers.o prctl.o signal.o | ||||
| 
 | ||||
| USER_OBJS := $(obj-y) | ||||
| 
 | ||||
|  |  | |||
|  | @ -30,13 +30,6 @@ int set_interval(int is_virtual) | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| void enable_timer(void) | ||||
| { | ||||
| 	set_interval(1); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| void disable_timer(void) | ||||
| { | ||||
| 	struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); | ||||
|  | @ -71,18 +64,6 @@ void switch_timers(int to_real) | |||
| 		       errno); | ||||
| } | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| void uml_idle_timer(void) | ||||
| { | ||||
| 	if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR) | ||||
| 		panic("Couldn't unset SIGVTALRM handler"); | ||||
| 
 | ||||
| 	set_handler(SIGALRM, (__sighandler_t) alarm_handler, | ||||
| 		    SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); | ||||
| 	set_interval(0); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| unsigned long long os_nsecs(void) | ||||
| { | ||||
| 	struct timeval tv; | ||||
|  |  | |||
|  | @ -8,11 +8,6 @@ | |||
| 
 | ||||
| /* 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 | ||||
|  | @ -32,8 +27,6 @@ int os_set_thread_area(user_desc_t *info, int pid) | |||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_SKAS | ||||
| 
 | ||||
| int os_get_thread_area(user_desc_t *info, int pid) | ||||
| { | ||||
| 	int ret; | ||||
|  | @ -44,32 +37,3 @@ int os_get_thread_area(user_desc_t *info, int pid) | |||
| 		ret = -errno; | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| #include "linux/unistd.h" | ||||
| 
 | ||||
| int do_set_thread_area_tt(user_desc_t *info) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = syscall(__NR_set_thread_area,info); | ||||
| 	if (ret < 0) { | ||||
| 		ret = -errno; | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| int do_get_thread_area_tt(user_desc_t *info) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = syscall(__NR_get_thread_area,info); | ||||
| 	if (ret < 0) { | ||||
| 		ret = -errno; | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| #endif /* UML_CONFIG_MODE_TT */ | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ $(UNPROFILE_OBJS:.o=.%): \ | |||
| $(UNPROFILE_OBJS) : CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ \ | ||||
| 	-Dunix -D__unix__ -D__$(SUBARCH)__ $(CF) | ||||
| 
 | ||||
| # The stubs and unmap.o can't try to call mcount or update basic block data | ||||
| # The stubs can't try to call mcount or update basic block data | ||||
| define unprofile | ||||
| 	$(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1))) | ||||
| endef | ||||
|  |  | |||
|  | @ -1,8 +1,6 @@ | |||
| obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
 | ||||
| 	ptrace_user.o setjmp.o signal.o sigcontext.o syscalls.o sysrq.o \
 | ||||
| 	sys_call_table.o tls.o | ||||
| 
 | ||||
| obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o | ||||
| 	ptrace_user.o setjmp.o signal.o sigcontext.o stub.o stub_segv.o \
 | ||||
| 	syscalls.o sysrq.o sys_call_table.o tls.o | ||||
| 
 | ||||
| subarch-obj-y = lib/bitops_32.o lib/semaphore_32.o lib/string_32.o | ||||
| subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o | ||||
|  | @ -13,11 +11,7 @@ USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o | |||
| USER_OBJS += user-offsets.s | ||||
| extra-y += user-offsets.s | ||||
| 
 | ||||
| extra-$(CONFIG_MODE_TT) += unmap.o | ||||
| 
 | ||||
| UNPROFILE_OBJS := stub_segv.o | ||||
| CFLAGS_stub_segv.o := $(CFLAGS_NO_HARDENING) | ||||
| 
 | ||||
| include arch/um/scripts/Makefile.rules | ||||
| 
 | ||||
| $(obj)/unmap.%: _c_flags = $(call unprofile,$(CFLAGS)) | ||||
|  |  | |||
|  | @ -19,72 +19,6 @@ | |||
| 
 | ||||
| extern int modify_ldt(int func, void *ptr, unsigned long bytecount); | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_TT | ||||
| 
 | ||||
| static long do_modify_ldt_tt(int func, void __user *ptr, | ||||
| 			      unsigned long bytecount) | ||||
| { | ||||
| 	struct user_desc info; | ||||
| 	int res = 0; | ||||
| 	void *buf = NULL; | ||||
| 	void *p = NULL; /* What we pass to host. */ | ||||
| 
 | ||||
| 	switch(func){ | ||||
| 	case 1: | ||||
| 	case 0x11: /* write_ldt */ | ||||
| 		/* Do this check now to avoid overflows. */ | ||||
| 		if (bytecount != sizeof(struct user_desc)) { | ||||
| 			res = -EINVAL; | ||||
| 			goto out; | ||||
| 		} | ||||
| 
 | ||||
| 		if(copy_from_user(&info, ptr, sizeof(info))) { | ||||
| 			res = -EFAULT; | ||||
| 			goto out; | ||||
| 		} | ||||
| 
 | ||||
| 		p = &info; | ||||
| 		break; | ||||
| 	case 0: | ||||
| 	case 2: /* read_ldt */ | ||||
| 
 | ||||
| 		/* The use of info avoids kmalloc on the write case, not on the
 | ||||
| 		 * read one. */ | ||||
| 		buf = kmalloc(bytecount, GFP_KERNEL); | ||||
| 		if (!buf) { | ||||
| 			res = -ENOMEM; | ||||
| 			goto out; | ||||
| 		} | ||||
| 		p = buf; | ||||
| 		break; | ||||
| 	default: | ||||
| 		res = -ENOSYS; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	res = modify_ldt(func, p, bytecount); | ||||
| 	if(res < 0) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	switch(func){ | ||||
| 	case 0: | ||||
| 	case 2: | ||||
| 		/* Modify_ldt was for reading and returned the number of read
 | ||||
| 		 * bytes.*/ | ||||
| 		if(copy_to_user(ptr, p, res)) | ||||
| 			res = -EFAULT; | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| out: | ||||
| 	kfree(buf); | ||||
| 	return res; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_SKAS | ||||
| 
 | ||||
| #include "skas.h" | ||||
| #include "skas_ptrace.h" | ||||
| #include "asm/mmu_context.h" | ||||
|  | @ -569,7 +503,6 @@ void free_ldt(struct mmu_context_skas * mm) | |||
| 	} | ||||
| 	mm->ldt.entry_count = 0; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) | ||||
| { | ||||
|  |  | |||
|  | @ -14,12 +14,6 @@ | |||
| #include "sysdep/sigcontext.h" | ||||
| #include "sysdep/sc.h" | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
| 	int err = arch_switch_tls_skas(from, to); | ||||
|  | @ -233,79 +227,12 @@ static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave | |||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * FXSR floating point environment conversions. | ||||
|  */ | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_TT | ||||
| static inline int convert_fxsr_to_user_tt(struct _fpstate __user *buf, | ||||
| 					  struct pt_regs *regs) | ||||
| { | ||||
| 	struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); | ||||
| 	unsigned long env[7]; | ||||
| 	struct _fpreg __user *to; | ||||
| 	struct _fpxreg *from; | ||||
| 	int i; | ||||
| 
 | ||||
| 	env[0] = (unsigned long)fxsave->cwd | 0xffff0000; | ||||
| 	env[1] = (unsigned long)fxsave->swd | 0xffff0000; | ||||
| 	env[2] = twd_fxsr_to_i387(fxsave); | ||||
| 	env[3] = fxsave->fip; | ||||
| 	env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16); | ||||
| 	env[5] = fxsave->foo; | ||||
| 	env[6] = fxsave->fos; | ||||
| 
 | ||||
| 	if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) ) | ||||
| 		return 1; | ||||
| 
 | ||||
| 	to = &buf->_st[0]; | ||||
| 	from = (struct _fpxreg *) &fxsave->st_space[0]; | ||||
| 	for ( i = 0 ; i < 8 ; i++, to++, from++ ) { | ||||
| 		if ( __copy_to_user( to, from, sizeof(*to) ) ) | ||||
| 			return 1; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static inline int convert_fxsr_to_user(struct _fpstate __user *buf, | ||||
| 				       struct pt_regs *regs) | ||||
| { | ||||
| 	return(CHOOSE_MODE(convert_fxsr_to_user_tt(buf, regs), 0)); | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_TT | ||||
| static inline int convert_fxsr_from_user_tt(struct pt_regs *regs, | ||||
| 					    struct _fpstate __user *buf) | ||||
| { | ||||
| 	struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); | ||||
| 	unsigned long env[7]; | ||||
| 	struct _fpxreg *to; | ||||
| 	struct _fpreg __user *from; | ||||
| 	int i; | ||||
| 
 | ||||
| 	if ( __copy_from_user( env, buf, 7 * sizeof(long) ) ) | ||||
| 		return 1; | ||||
| 
 | ||||
| 	fxsave->cwd = (unsigned short)(env[0] & 0xffff); | ||||
| 	fxsave->swd = (unsigned short)(env[1] & 0xffff); | ||||
| 	fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff)); | ||||
| 	fxsave->fip = env[3]; | ||||
| 	fxsave->fop = (unsigned short)((env[4] & 0xffff0000) >> 16); | ||||
| 	fxsave->fcs = (env[4] & 0xffff); | ||||
| 	fxsave->foo = env[5]; | ||||
| 	fxsave->fos = env[6]; | ||||
| 
 | ||||
| 	to = (struct _fpxreg *) &fxsave->st_space[0]; | ||||
| 	from = &buf->_st[0]; | ||||
| 	for ( i = 0 ; i < 8 ; i++, to++, from++ ) { | ||||
| 		if ( __copy_from_user( to, from, sizeof(*from) ) ) | ||||
| 			return 1; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static inline int convert_fxsr_from_user(struct pt_regs *regs,  | ||||
| 					 struct _fpstate __user *buf) | ||||
| { | ||||
|  | @ -332,39 +259,11 @@ int set_fpregs(unsigned long buf, struct task_struct *child) | |||
| 	else return(0); | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_TT | ||||
| int get_fpxregs_tt(unsigned long buf, struct task_struct *tsk) | ||||
| { | ||||
| 	struct pt_regs *regs = &tsk->thread.regs; | ||||
| 	struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = __copy_to_user((void __user *) buf, fxsave, | ||||
| 			     sizeof(struct user_fxsr_struct)); | ||||
| 	if(err) return -EFAULT; | ||||
| 	else return 0; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| int get_fpxregs(unsigned long buf, struct task_struct *tsk) | ||||
| { | ||||
| 	return(CHOOSE_MODE(get_fpxregs_tt(buf, tsk), 0)); | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_TT | ||||
| int set_fpxregs_tt(unsigned long buf, struct task_struct *tsk) | ||||
| { | ||||
| 	struct pt_regs *regs = &tsk->thread.regs; | ||||
| 	struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = __copy_from_user(fxsave, (void __user *) buf, | ||||
| 			       sizeof(struct user_fxsr_struct) ); | ||||
| 	if(err) return -EFAULT; | ||||
| 	else return 0; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| int set_fpxregs(unsigned long buf, struct task_struct *tsk) | ||||
| { | ||||
| 	return(CHOOSE_MODE(set_fpxregs_tt(buf, tsk), 0)); | ||||
|  | @ -387,25 +286,6 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) | |||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_TT | ||||
| static inline void copy_fpu_fxsave_tt(struct pt_regs *regs, | ||||
| 				      struct user_i387_struct *buf) | ||||
| { | ||||
| 	struct i387_fxsave_struct *fpu = SC_FXSR_ENV(PT_REGS_SC(regs)); | ||||
| 	unsigned short *to; | ||||
| 	unsigned short *from; | ||||
| 	int i; | ||||
| 
 | ||||
| 	memcpy( buf, fpu, 7 * sizeof(long) ); | ||||
| 
 | ||||
| 	to = (unsigned short *) &buf->st_space[0]; | ||||
| 	from = (unsigned short *) &fpu->st_space[0]; | ||||
| 	for ( i = 0 ; i < 8 ; i++, to += 5, from += 8 ) { | ||||
| 		memcpy( to, from, 5 * sizeof(unsigned short) ); | ||||
| 	} | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static inline void copy_fpu_fxsave(struct pt_regs *regs, | ||||
| 				   struct user_i387_struct *buf) | ||||
| { | ||||
|  |  | |||
|  | @ -43,89 +43,3 @@ int ptrace_setfpregs(long pid, unsigned long *regs) | |||
| 		return -errno; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef UML_CONFIG_MODE_TT | ||||
| 
 | ||||
| static void write_debugregs(int pid, unsigned long *regs) | ||||
| { | ||||
| 	struct user *dummy; | ||||
| 	int nregs, i; | ||||
| 
 | ||||
| 	dummy = NULL; | ||||
| 	nregs = ARRAY_SIZE(dummy->u_debugreg); | ||||
| 	for(i = 0; i < nregs; i++){ | ||||
| 		if((i == 4) || (i == 5)) continue; | ||||
| 		if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i], | ||||
| 			  regs[i]) < 0) | ||||
| 			printk("write_debugregs - ptrace failed on " | ||||
| 			       "register %d, value = 0x%lx, errno = %d\n", i, | ||||
| 			       regs[i], errno); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void read_debugregs(int pid, unsigned long *regs) | ||||
| { | ||||
| 	struct user *dummy; | ||||
| 	int nregs, i; | ||||
| 
 | ||||
| 	dummy = NULL; | ||||
| 	nregs = ARRAY_SIZE(dummy->u_debugreg); | ||||
| 	for(i = 0; i < nregs; i++){ | ||||
| 		regs[i] = ptrace(PTRACE_PEEKUSR, pid, | ||||
| 				 &dummy->u_debugreg[i], 0); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Accessed only by the tracing thread */ | ||||
| static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 }; | ||||
| 
 | ||||
| void arch_enter_kernel(void *task, int pid) | ||||
| { | ||||
| 	read_debugregs(pid, TASK_DEBUGREGS(task)); | ||||
| 	write_debugregs(pid, kernel_debugregs); | ||||
| } | ||||
| 
 | ||||
| void arch_leave_kernel(void *task, int pid) | ||||
| { | ||||
| 	read_debugregs(pid, kernel_debugregs); | ||||
| 	write_debugregs(pid, TASK_DEBUGREGS(task)); | ||||
| } | ||||
| 
 | ||||
| #ifdef UML_CONFIG_PT_PROXY | ||||
| /* Accessed only by the tracing thread */ | ||||
| static int debugregs_seq; | ||||
| 
 | ||||
| /* Only called by the ptrace proxy */ | ||||
| void ptrace_pokeuser(unsigned long addr, unsigned long data) | ||||
| { | ||||
| 	if((addr < offsetof(struct user, u_debugreg[0])) || | ||||
| 	   (addr > offsetof(struct user, u_debugreg[7]))) | ||||
| 		return; | ||||
| 	addr -= offsetof(struct user, u_debugreg[0]); | ||||
| 	addr = addr >> 2; | ||||
| 	if(kernel_debugregs[addr] == data) return; | ||||
| 
 | ||||
| 	kernel_debugregs[addr] = data; | ||||
| 	debugregs_seq++; | ||||
| } | ||||
| 
 | ||||
| static void update_debugregs_cb(void *arg) | ||||
| { | ||||
| 	int pid = *((int *) arg); | ||||
| 
 | ||||
| 	write_debugregs(pid, kernel_debugregs); | ||||
| } | ||||
| 
 | ||||
| /* Optimized out in its header when not defined */ | ||||
| void update_debugregs(int seq) | ||||
| { | ||||
| 	int me; | ||||
| 
 | ||||
| 	if(seq == debugregs_seq) return; | ||||
| 
 | ||||
| 	me = os_getpid(); | ||||
| 	initial_thread_cb(update_debugregs_cb, &me); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -13,9 +13,6 @@ | |||
| #include "sigcontext.h" | ||||
| #include "registers.h" | ||||
| #include "mode.h" | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_SKAS | ||||
| 
 | ||||
| #include "skas.h" | ||||
| 
 | ||||
| void copy_sc(union uml_pt_regs *regs, void *from) | ||||
|  | @ -108,61 +105,6 @@ int copy_sc_to_user_skas(struct sigcontext __user *to, struct _fpstate __user *t | |||
| 	return copy_to_user(to, &sc, sizeof(sc)) || | ||||
| 	       copy_to_user(to_fp, fpregs, sizeof(fpregs)); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_TT | ||||
| 
 | ||||
| /* These copy a sigcontext to/from userspace.  They copy the fpstate pointer,
 | ||||
|  * blowing away the old, good one.  So, that value is saved, and then restored | ||||
|  * after the sigcontext copy.  In copy_from, the variable holding the saved | ||||
|  * fpstate pointer, and the sigcontext that it should be restored to are both | ||||
|  * in the kernel, so we can just restore using an assignment.  In copy_to, the | ||||
|  * saved pointer is in the kernel, but the sigcontext is in userspace, so we | ||||
|  * copy_to_user it. | ||||
|  */ | ||||
| int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext __user *from, | ||||
| 			 int fpsize) | ||||
| { | ||||
| 	struct _fpstate *to_fp; | ||||
| 	struct _fpstate __user *from_fp; | ||||
| 	unsigned long sigs; | ||||
| 	int err; | ||||
| 
 | ||||
| 	to_fp = to->fpstate; | ||||
| 	sigs = to->oldmask; | ||||
| 	err = copy_from_user(to, from, sizeof(*to)); | ||||
| 	from_fp = to->fpstate; | ||||
| 	to->oldmask = sigs; | ||||
| 	to->fpstate = to_fp; | ||||
| 	if(to_fp != NULL) | ||||
| 		err |= copy_from_user(to_fp, from_fp, fpsize); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| int copy_sc_to_user_tt(struct sigcontext __user *to, struct _fpstate __user *fp, | ||||
| 		       struct sigcontext *from, int fpsize, unsigned long sp) | ||||
| { | ||||
| 	struct _fpstate __user *to_fp; | ||||
| 	struct _fpstate *from_fp; | ||||
| 	int err; | ||||
| 
 | ||||
| 	to_fp =	(fp ? fp : (struct _fpstate __user *) (to + 1)); | ||||
| 	from_fp = from->fpstate; | ||||
| 	err = copy_to_user(to, from, sizeof(*to)); | ||||
| 
 | ||||
| 	/* The SP in the sigcontext is the updated one for the signal
 | ||||
| 	 * delivery.  The sp passed in is the original, and this needs | ||||
| 	 * to be restored, so we stick it in separately. | ||||
| 	 */ | ||||
| 	err |= copy_to_user(&SC_SP(to), &sp, sizeof(sp)); | ||||
| 
 | ||||
| 	if(from_fp != NULL){ | ||||
| 		err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); | ||||
| 		err |= copy_to_user(to_fp, from_fp, fpsize); | ||||
| 	} | ||||
| 	return err; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static int copy_sc_from_user(struct pt_regs *to, void __user *from) | ||||
| { | ||||
|  |  | |||
|  | @ -18,10 +18,7 @@ | |||
| #include "mode_kern.h" | ||||
| #include "os.h" | ||||
| #include "mode.h" | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_SKAS | ||||
| #include "skas.h" | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * If needed we can detect when it's uninitialized. | ||||
|  | @ -31,7 +28,6 @@ | |||
| static int host_supports_tls = -1; | ||||
| int host_gdt_entry_tls_min; | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_SKAS | ||||
| int do_set_thread_area_skas(struct user_desc *info) | ||||
| { | ||||
| 	int ret; | ||||
|  | @ -53,7 +49,6 @@ int do_get_thread_area_skas(struct user_desc *info) | |||
| 	put_cpu(); | ||||
| 	return ret; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * sys_get_thread_area: get a yet unused TLS descriptor index. | ||||
|  | @ -187,17 +182,6 @@ int arch_switch_tls_skas(struct task_struct *from, struct task_struct *to) | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int arch_switch_tls_tt(struct task_struct *from, struct task_struct *to) | ||||
| { | ||||
| 	if (!host_supports_tls) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (needs_TLS_update(to)) | ||||
| 		return load_TLS(0, to); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int set_tls_entry(struct task_struct* task, struct user_desc *info, | ||||
| 			 int idx, int flushed) | ||||
| { | ||||
|  |  | |||
|  | @ -1,25 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/mman.h> | ||||
| #include <asm/unistd.h> | ||||
| 
 | ||||
| static int errno; | ||||
| 
 | ||||
| static inline _syscall2(int,munmap,void *,start,size_t,len) | ||||
| static inline _syscall6(void *,mmap2,void *,addr,size_t,len,int,prot,int,flags,int,fd,off_t,offset) | ||||
| int switcheroo(int fd, int prot, void *from, void *to, int size) | ||||
| { | ||||
| 	if(munmap(to, size) < 0){ | ||||
| 		return(-1); | ||||
| 	} | ||||
| 	if(mmap2(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) == (void*) -1 ){ | ||||
| 		return(-1); | ||||
| 	} | ||||
| 	if(munmap(from, size) < 0){ | ||||
| 		return(-1); | ||||
| 	} | ||||
| 	return(0); | ||||
| } | ||||
|  | @ -5,10 +5,9 @@ | |||
| #
 | ||||
| 
 | ||||
| obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \
 | ||||
| 	setjmp.o sigcontext.o signal.o syscalls.o syscall_table.o sysrq.o \
 | ||||
| 	ksyms.o tls.o | ||||
| 	setjmp.o sigcontext.o signal.o stub.o stub_segv.o syscalls.o \
 | ||||
| 	syscall_table.o sysrq.o ksyms.o tls.o | ||||
| 
 | ||||
| obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o | ||||
| obj-$(CONFIG_MODULES) += um_module.o | ||||
| 
 | ||||
| subarch-obj-y = lib/bitops_64.o lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o | ||||
|  | @ -21,11 +20,7 @@ USER_OBJS := ptrace_user.o sigcontext.o | |||
| USER_OBJS += user-offsets.s | ||||
| extra-y += user-offsets.s | ||||
| 
 | ||||
| extra-$(CONFIG_MODE_TT) += unmap.o | ||||
| 
 | ||||
| UNPROFILE_OBJS := stub_segv.o | ||||
| CFLAGS_stub_segv.o := $(CFLAGS_NO_HARDENING) | ||||
| 
 | ||||
| include arch/um/scripts/Makefile.rules | ||||
| 
 | ||||
| $(obj)/unmap.%: _c_flags = $(call unprofile,$(CFLAGS)) | ||||
|  |  | |||
|  | @ -15,9 +15,6 @@ | |||
| #include "choose-mode.h" | ||||
| #include "sysdep/ptrace.h" | ||||
| #include "frame_kern.h" | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_SKAS | ||||
| 
 | ||||
| #include "skas.h" | ||||
| 
 | ||||
| void copy_sc(union uml_pt_regs *regs, void *from) | ||||
|  | @ -134,53 +131,6 @@ int copy_sc_to_user_skas(struct sigcontext __user *to, | |||
| 	return(err); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_TT | ||||
| int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext __user *from, | ||||
| 			 int fpsize) | ||||
| { | ||||
| 	struct _fpstate *to_fp; | ||||
| 	struct _fpstate __user *from_fp; | ||||
| 	unsigned long sigs; | ||||
| 	int err; | ||||
| 
 | ||||
| 	to_fp = to->fpstate; | ||||
| 	sigs = to->oldmask; | ||||
| 	err = copy_from_user(to, from, sizeof(*to)); | ||||
| 	from_fp = to->fpstate; | ||||
| 	to->fpstate = to_fp; | ||||
| 	to->oldmask = sigs; | ||||
| 	if(to_fp != NULL) | ||||
| 		err |= copy_from_user(to_fp, from_fp, fpsize); | ||||
| 	return(err); | ||||
| } | ||||
| 
 | ||||
| int copy_sc_to_user_tt(struct sigcontext __user *to, struct _fpstate __user *fp, | ||||
| 		       struct sigcontext *from, int fpsize, unsigned long sp) | ||||
| { | ||||
| 	struct _fpstate __user *to_fp; | ||||
| 	struct _fpstate *from_fp; | ||||
| 	int err; | ||||
| 
 | ||||
| 	to_fp = (fp ? fp : (struct _fpstate __user *) (to + 1)); | ||||
| 	from_fp = from->fpstate; | ||||
| 	err = copy_to_user(to, from, sizeof(*to)); | ||||
| 	/* The SP in the sigcontext is the updated one for the signal
 | ||||
| 	 * delivery.  The sp passed in is the original, and this needs | ||||
| 	 * to be restored, so we stick it in separately. | ||||
| 	 */ | ||||
| 	err |= copy_to_user(&SC_SP(to), &sp, sizeof(sp)); | ||||
| 
 | ||||
| 	if(from_fp != NULL){ | ||||
| 		err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); | ||||
| 		err |= copy_to_user(to_fp, from_fp, fpsize); | ||||
| 	} | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| static int copy_sc_from_user(struct pt_regs *to, void __user *from) | ||||
| { | ||||
|        int ret; | ||||
|  |  | |||
|  | @ -29,36 +29,6 @@ asmlinkage long sys_uname64(struct new_utsname __user * name) | |||
| 	return err ? -EFAULT : 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_TT | ||||
| extern long arch_prctl(int code, unsigned long addr); | ||||
| 
 | ||||
| static long arch_prctl_tt(int code, unsigned long addr) | ||||
| { | ||||
| 	unsigned long tmp; | ||||
| 	long ret; | ||||
| 
 | ||||
| 	switch(code){ | ||||
| 	case ARCH_SET_GS: | ||||
| 	case ARCH_SET_FS: | ||||
| 		ret = arch_prctl(code, addr); | ||||
| 		break; | ||||
| 	case ARCH_GET_FS: | ||||
| 	case ARCH_GET_GS: | ||||
| 		ret = arch_prctl(code, (unsigned long) &tmp); | ||||
| 		if(!ret) | ||||
| 			ret = put_user(tmp, (long __user *)addr); | ||||
| 		break; | ||||
| 	default: | ||||
| 		ret = -EINVAL; | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	return(ret); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_SKAS | ||||
| 
 | ||||
| long arch_prctl_skas(struct task_struct *task, int code, | ||||
|                      unsigned long __user *addr) | ||||
| { | ||||
|  | @ -119,7 +89,6 @@ long arch_prctl_skas(struct task_struct *task, int code, | |||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| long sys_arch_prctl(int code, unsigned long addr) | ||||
| { | ||||
|  |  | |||
|  | @ -1,25 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/mman.h> | ||||
| #include <asm/unistd.h> | ||||
| 
 | ||||
| static int errno; | ||||
| 
 | ||||
| static inline _syscall2(int,munmap,void *,start,size_t,len) | ||||
| static inline _syscall6(void *,mmap,void *,addr,size_t,len,int,prot,int,flags,int,fd,off_t,offset) | ||||
| int switcheroo(int fd, int prot, void *from, void *to, int size) | ||||
| { | ||||
| 	if(munmap(to, size) < 0){ | ||||
| 		return(-1); | ||||
| 	} | ||||
| 	if(mmap(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) == (void*) -1){ | ||||
| 		return(-1); | ||||
| 	} | ||||
| 	if(munmap(from, size) < 0){ | ||||
| 		return(-1); | ||||
| 	} | ||||
| 	return(0); | ||||
| } | ||||
|  | @ -56,12 +56,6 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, | |||
| extern int init_new_context_skas(struct task_struct *task,  | ||||
| 				 struct mm_struct *mm); | ||||
| 
 | ||||
| static inline int init_new_context_tt(struct task_struct *task,  | ||||
| 				      struct mm_struct *mm) | ||||
| { | ||||
| 	return(0); | ||||
| } | ||||
| 
 | ||||
| static inline int init_new_context(struct task_struct *task,  | ||||
| 				   struct mm_struct *mm) | ||||
| { | ||||
|  |  | |||
|  | @ -34,20 +34,10 @@ struct thread_struct { | |||
| 	void *exec_buf; | ||||
| 	struct arch_thread arch; | ||||
| 	union { | ||||
| #ifdef CONFIG_MODE_TT | ||||
| 		struct { | ||||
| 			int extern_pid; | ||||
| 			int tracing; | ||||
| 			int switch_pipe[2]; | ||||
| 			int vm_seq; | ||||
| 		} tt; | ||||
| #endif | ||||
| #ifdef CONFIG_MODE_SKAS | ||||
| 		struct { | ||||
| 			jmp_buf switch_buf; | ||||
| 			int mm_count; | ||||
| 		} skas; | ||||
| #endif | ||||
| 	} mode; | ||||
| 	struct { | ||||
| 		int op; | ||||
|  | @ -136,12 +126,8 @@ extern struct cpuinfo_um cpu_data[]; | |||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| #ifdef CONFIG_MODE_SKAS | ||||
| #define KSTK_REG(tsk, reg) \ | ||||
| 	get_thread_reg(reg, &tsk->thread.mode.skas.switch_buf) | ||||
| #else | ||||
| #define KSTK_REG(tsk, reg) (0xbadbabe) | ||||
| #endif | ||||
| #define get_wchan(p) (0) | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Jeff Dike
						Jeff Dike