diff options
| author | Richard Henderson <rth@fidel.sfbay.redhat.com> | 2002-02-10 13:42:53 -0800 |
|---|---|---|
| committer | Richard Henderson <rth@fidel.sfbay.redhat.com> | 2002-02-10 13:42:53 -0800 |
| commit | 374eeee8a8a50e12278dfa37021df7b6efe506c3 (patch) | |
| tree | 2388fbed3bb98ad9f8f342c1353c2bbfb40e07c8 /arch/alpha/kernel | |
| parent | 74c0102446bb3160f186555bd133062003acf194 (diff) | |
Update Alpha UP for thread_info and scheduler changes.
Diffstat (limited to 'arch/alpha/kernel')
| -rw-r--r-- | arch/alpha/kernel/Makefile | 20 | ||||
| -rw-r--r-- | arch/alpha/kernel/check_asm.c | 42 | ||||
| -rw-r--r-- | arch/alpha/kernel/entry.S | 266 | ||||
| -rw-r--r-- | arch/alpha/kernel/head.S | 4 | ||||
| -rw-r--r-- | arch/alpha/kernel/init_task.c | 17 | ||||
| -rw-r--r-- | arch/alpha/kernel/osf_sys.c | 22 | ||||
| -rw-r--r-- | arch/alpha/kernel/pci_iommu.c | 9 | ||||
| -rw-r--r-- | arch/alpha/kernel/process.c | 79 | ||||
| -rw-r--r-- | arch/alpha/kernel/ptrace.c | 52 | ||||
| -rw-r--r-- | arch/alpha/kernel/signal.c | 15 | ||||
| -rw-r--r-- | arch/alpha/kernel/traps.c | 33 |
11 files changed, 284 insertions, 275 deletions
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index 7db812cdac68..51a5d4da1344 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile @@ -8,15 +8,15 @@ # Note 2! The CFLAGS definitions are now in the main makefile... .S.s: - $(CPP) $(AFLAGS) -o $*.s $< + $(CPP) $(CFLAGS) $(AFLAGS) -o $*.s $< .S.o: - $(CC) $(AFLAGS) -c -o $*.o $< + $(CC) $(CFLAGS) $(AFLAGS) -c -o $*.o $< O_TARGET := kernel.o export-objs := alpha_ksyms.o -obj-y := entry.o traps.o process.o osf_sys.o irq.o irq_alpha.o \ +obj-y := entry.o traps.o process.o init_task.o osf_sys.o irq.o irq_alpha.o \ signal.o setup.o ptrace.o time.o semaphore.o alpha_ksyms.o # @@ -102,11 +102,15 @@ endif # GENERIC all: kernel.o head.o -asm_offsets: check_asm - ./check_asm > $(TOPDIR)/include/asm-alpha/asm_offsets.h - -check_asm: check_asm.c - $(HOSTCC) -o $@ $< $(CPPFLAGS) -ffixed-8 +ASM_OFFSETS_H = $(TOPDIR)/include/asm-alpha/asm_offsets.h +asm_offsets: + $(CC) $(CFLAGS) -S -o - check_asm.c | \ + sed -e '/xyzzy/ { s/xyzzy //; p; }; d;' > asm_offsets.tmp + @if cmp -s asm_offsets.tmp $(ASM_OFFSETS_H); then \ + set -x; rm asm_offsets.tmp; \ + else \ + set -x; mv asm_offsets.tmp $(ASM_OFFSETS_H); \ + fi clean:: rm -f check_asm diff --git a/arch/alpha/kernel/check_asm.c b/arch/alpha/kernel/check_asm.c index 9685fa6cdf12..3c0a15416a27 100644 --- a/arch/alpha/kernel/check_asm.c +++ b/arch/alpha/kernel/check_asm.c @@ -3,30 +3,28 @@ #include <linux/sched.h> #include <asm/io.h> -int main() +#define OUT(x) \ + asm ("\nxyzzy " x) +#define DEF(name, val) \ + asm volatile ("\nxyzzy #define " name " %0" : : "i"(val)) + +void foo(void) { - printf("#ifndef __ASM_OFFSETS_H__\n#define __ASM_OFFSETS_H__\n"); + OUT("#ifndef __ASM_OFFSETS_H__"); + OUT("#define __ASM_OFFSETS_H__"); + OUT(""); + + DEF("TI_TASK", offsetof(struct thread_struct, task)); + DEF("TI_FLAGS", offsetof(struct thread_struct, flags)); + DEF("TI_CPU", offsetof(struct thread_struct, cpu)); - printf("#define TASK_STATE %ld\n", - (long)offsetof(struct task_struct, state)); - printf("#define TASK_FLAGS %ld\n", - (long)offsetof(struct task_struct, flags)); - printf("#define TASK_SIGPENDING %ld\n", -#error (long)offsetof(struct task_struct, sigpending)); - printf("#define TASK_ADDR_LIMIT %ld\n", - (long)offsetof(struct task_struct, addr_limit)); - printf("#define TASK_EXEC_DOMAIN %ld\n", - (long)offsetof(struct task_struct, exec_domain)); - printf("#define TASK_NEED_RESCHED %ld\n", -#error (long)offsetof(struct task_struct, work.need_resched)); - printf("#define TASK_SIZE %ld\n", sizeof(struct task_struct)); - printf("#define STACK_SIZE %ld\n", sizeof(union task_union)); + DEF("PT_PTRACED", PT_PTRACED); + DEF("CLONE_VM", CLONE_VM); + DEF("SIGCHLD", SIGCHLD); - printf("#define HAE_CACHE %ld\n", - (long)offsetof(struct alpha_machine_vector, hae_cache)); - printf("#define HAE_REG %ld\n", - (long)offsetof(struct alpha_machine_vector, hae_register)); + DEF("HAE_CACHE", offsetof(struct alpha_machine_vector, hae_cache)); + DEF("HAE_REG", offsetof(struct alpha_machine_vector, hae_register)); - printf("#endif /* __ASM_OFFSETS_H__ */\n"); - return 0; + OUT(""); + OUT("#endif /* __ASM_OFFSETS_H__ */"); } diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index 4c1bd59cc94f..7b0e4f9a847e 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -7,42 +7,16 @@ #include <linux/config.h> #include <asm/system.h> #include <asm/cache.h> +#include <asm/asm_offsets.h> +#include <asm/thread_info.h> -#define SIGCHLD 20 - -#define NR_SYSCALLS 378 - -/* - * These offsets must match with alpha_mv in <asm/machvec.h>. - */ -#define HAE_CACHE 0 -#define HAE_REG 8 +#define NR_SYSCALLS 381 /* * stack offsets */ -#define SP_OFF 184 - -#define SWITCH_STACK_SIZE 320 - -/* - * task structure offsets - */ -#define TASK_STATE 0 -#define TASK_FLAGS 8 -#error #define TASK_SIGPENDING 16 -#define TASK_ADDR_LIMIT 24 -#define TASK_EXEC_DOMAIN 32 -#error #define TASK_NEED_RESCHED 40 -#error #define TASK_PTRACE 48 -#define TASK_PROCESSOR 100 - -/* - * task flags (must match include/linux/sched.h): - */ -#define PT_PTRACED 0x00000001 - -#define CLONE_VM 0x00000100 +#define SP_OFF 184 +#define SWITCH_STACK_SIZE 320 /* * This defines the normal kernel pt-regs layout. @@ -55,7 +29,7 @@ */ #define SAVE_ALL \ - subq $30,184,$30; \ + subq $30,SP_OFF,$30; \ stq $0,0($30); \ stq $1,8($30); \ stq $2,16($30); \ @@ -98,12 +72,8 @@ ldq $8,64($30); \ beq $20,99f; \ ldq $20,HAE_REG($19); \ - addq $31,7,$16; \ - call_pal PAL_swpipl; \ stq $21,HAE_CACHE($19); \ stq $21,0($20); \ - mov $0,$16; \ - call_pal PAL_swpipl; \ ldq $0,0($30); \ ldq $1,8($30); \ 99:; \ @@ -117,13 +87,10 @@ ldq $26,128($30); \ ldq $27,136($30); \ ldq $28,144($30); \ - addq $30,184,$30 + addq $30,SP_OFF,$30 .text .set noat -#if defined(__linux__) && !defined(__ELF__) - .set singlegp -#endif .align 3 .globl entInt @@ -203,68 +170,58 @@ entDbg: /* - * Fork() is one of the special system calls: it needs to - * save the callee-saved regs so that the regs can be found - * for the new process.. We save them in the "context switch" - * stack format (see arch/alpha/kernel/process.c). - * - * Also, for the kernel fork, we need to fake the system call - * stack buildup, as we can't do system calls from kernel space. - */ -.align 3 -.ent kernel_clone -kernel_clone: - .frame $30, 0, $26 - .prologue 0 - subq $30,6*8,$30 - stq $31,0($30) - stq $26,8($30) - stq $29,16($30) - stq $16,24($30) - stq $17,32($30) - stq $18,40($30) - bis $31,2,$0 /* Register v0: syscall nr for fork() */ - SAVE_ALL - bsr $26,sys_clone - stq $0,0($30) - br ret_from_sys_call -.end kernel_clone - -/* * kernel_thread(fn, arg, clone_flags) */ -.align 3 -.globl kernel_thread -.ent kernel_thread + .align 4 + .globl kernel_thread + .ent kernel_thread kernel_thread: ldgp $29,0($27) /* we can be called from a module */ - .frame $30, 4*8, $26 - subq $30,4*8,$30 - stq $10,16($30) - stq $9,8($30) - lda $0,CLONE_VM - stq $26,0($30) .prologue 1 - mov $16,$9 /* save fn */ - mov $17,$10 /* save arg */ - or $18,$0,$16 /* shuffle flags to front; add CLONE_VM. */ - bsr $26,kernel_clone - bne $20,1f /* $20 is non-zero in child */ - ldq $26,0($30) - ldq $9,8($30) - ldq $10,16($30) - addq $30,4*8,$30 - ret $31,($26),1 -/* this is in child: look out as we don't have any stack here.. */ -1: mov $9,$27 /* get fn */ - lda $8,0x3fff - mov $10,$16 /* get arg */ - bic $30,$8,$8 /* get current */ - jsr $26,($27) - ldgp $29,0($26) - mov $0,$16 - mov $31,$26 - jsr $31,sys_exit + subq $30,SP_OFF+6*8,$30 + br $1, 2f /* load start address */ + + /* We've now "returned" from a fake system call. */ + unop + blt $0, 1f /* error? */ + ldi $1, 0x3fff + beq $20, 1f /* parent or child? */ + + bic $30, $1, $8 /* in child. */ + jsr $26, ($27) + ldgp $29, 0($26) + mov $0, $16 + mov $31, $26 + jmp $31, sys_exit + +1: ret /* in parent. */ + + .align 4 +2: /* Fake a system call stack frame, as we can't do system calls + from kernel space. Note that we store FN and ARG as they + need to be set up in the child for the call. Also store $8 + and $26 for use in the parent. */ + stq $31, SP_OFF($30) /* ps */ + stq $1, SP_OFF+8($30) /* pc */ + stq $29, SP_OFF+16($30) /* gp */ + stq $16, 136($30) /* $27; FN for child */ + stq $17, 160($30) /* $16; ARG for child */ + stq $8, 64($30) /* $8 */ + stq $26, 128($30) /* $26 */ + /* Avoid the HAE being gratuitously wrong, which would cause us + to go off to restore it. */ + ldq $2, alpha_mv+HAE_CACHE + stq $2, 152($30) /* HAE */ + + /* Shuffle FLAGS to the front; add CLONE_VM. */ + ldi $1, CLONE_VM + or $18, $1, $16 + bsr $26, sys_clone + + /* We don't actually care for a3 success widgetry in the kernel. + Not for positive errno values. */ + stq $0, 0($30) /* $0 */ + br restore_all .end kernel_thread /* @@ -535,10 +492,21 @@ alpha_switch_to: call_pal PAL_swpctx unop bsr $1,undo_switch_stack + lda $8,0x3fff mov $17,$0 + bic $30,$8,$8 ret $31,($26),1 .end alpha_switch_to +.globl ret_from_fork +.align 3 +.ent ret_from_fork +ret_from_fork: + lda $26,ret_from_sys_call + mov $0,$16 + jmp $31,schedule_tail +.end ret_from_fork + /* * Oh, well.. Disassembling OSF/1 binaries to find out how the * system calls work isn't much fun. @@ -559,12 +527,11 @@ entSys: lda $5,sys_call_table lda $27,sys_ni_syscall cmpult $0,$4,$4 - ldq $3,TASK_PTRACE($8) + ldl $3,TI_FLAGS($8) stq $17,SP_OFF+32($30) s8addq $0,$5,$5 - and $3,PT_PTRACED,$3 stq $18,SP_OFF+40($30) - bne $3,strace + blbs $3,strace beq $4,1f ldq $27,0($5) 1: jsr $26,($27),alpha_ni_syscall @@ -580,34 +547,65 @@ ret_from_sys_call: and $0,8,$0 beq $0,restore_all ret_from_reschedule: -#error ldq $2,TASK_NEED_RESCHED($8) - lda $4,init_task_union - bne $2,reschedule - xor $4,$8,$4 -#error ldl $5,TASK_SIGPENDING($8) - beq $4,restore_all - bne $5,signal_return + /* Make sure need_resched and sigpending don't change between + sampling and the rti. */ + lda $16,7 + call_pal PAL_swpipl + ldl $5,TI_FLAGS($8) + and $5,_TIF_WORK_MASK,$2 + bne $5,work_pending restore_all: RESTORE_ALL call_pal PAL_rti +work_pending: + and $5,_TIF_NEED_RESCHED,$2 + beq $2,work_notifysig + +work_resched: + subq $30,16,$30 + stq $19,0($30) /* save syscall nr */ + stq $20,8($30) /* and error indication (a3) */ + jsr $26,schedule + ldq $19,0($30) + ldq $20,8($30) + addq $30,16,$30 + /* Make sure need_resched and sigpending don't change between + sampling and the rti. */ + lda $16,7 + call_pal PAL_swpipl + ldl $5,TI_FLAGS($8) + and $5,_TIF_WORK_MASK,$2 + beq $2,restore_all + and $5,_TIF_NEED_RESCHED,$2 + bne $2,work_resched + +work_notifysig: + mov $30,$17 + br $1,do_switch_stack + mov $5,$21 + mov $30,$18 + mov $31,$16 + jsr $26,do_notify_resume + bsr $1,undo_switch_stack + br restore_all /* PTRACE syscall handler */ .align 3 strace: /* set up signal stack, call syscall_trace */ bsr $1,do_switch_stack - jsr $26,syscall_trace + jsr $26,syscall_trace bsr $1,undo_switch_stack /* get the system call number and the arguments back.. */ - ldq $0,0($30) - ldq $16,SP_OFF+24($30) - ldq $17,SP_OFF+32($30) - ldq $18,SP_OFF+40($30) - ldq $19,72($30) - ldq $20,80($30) - ldq $21,88($30) + ldq $0,0($30) + ldq $16,SP_OFF+24($30) + ldq $17,SP_OFF+32($30) + ldq $18,SP_OFF+40($30) + ldq $19,72($30) + ldq $20,80($30) + ldq $21,88($30) /* get the system call pointer.. */ lda $1,NR_SYSCALLS($31) @@ -627,11 +625,11 @@ strace_success: stq $0,0($30) /* save return value */ bsr $1,do_switch_stack - jsr $26,syscall_trace + jsr $26,syscall_trace bsr $1,undo_switch_stack br $31,ret_from_sys_call - .align 3 + .align 3 strace_error: ldq $19,0($30) /* old syscall nr (zero if success) */ beq $19,strace_success @@ -645,7 +643,7 @@ strace_error: bsr $1,do_switch_stack mov $19,$9 /* save old syscall number */ mov $20,$10 /* save old a3 */ - jsr $26,syscall_trace + jsr $26,syscall_trace mov $9,$19 mov $10,$20 bsr $1,undo_switch_stack @@ -677,40 +675,8 @@ ret_success: stq $0,0($30) stq $31,72($30) /* a3=0 => no error */ br ret_from_sys_call - -.align 3 -signal_return: - mov $30,$17 - br $1,do_switch_stack - mov $30,$18 - mov $31,$16 - jsr $26,do_signal - bsr $1,undo_switch_stack - br restore_all .end entSys - .globl ret_from_fork -.align 3 -.ent ret_from_fork -ret_from_fork: - lda $26,ret_from_sys_call - mov $17,$16 - jsr $31,schedule_tail -.end ret_from_fork - -.align 3 -.ent reschedule -reschedule: - subq $30,16,$30 - stq $19,0($30) /* save syscall nr */ - stq $20,8($30) /* and error indication (a3) */ - jsr $26,schedule - ldq $19,0($30) - ldq $20,8($30) - addq $30,16,$30 - br ret_from_reschedule -.end reschedule - .align 3 .ent sys_sigreturn sys_sigreturn: diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S index 4c87ee3a7b07..fe03ed241fa3 100644 --- a/arch/alpha/kernel/head.S +++ b/arch/alpha/kernel/head.S @@ -22,8 +22,8 @@ __start: .prologue 0 br $27,1f 1: ldgp $29,0($27) - /* We need to get current loaded up with our first task... */ - lda $8,init_task_union + /* We need to get current_task_info loaded up... */ + lda $8,init_thread_union /* ... and find our stack ... */ lda $30,0x4000($8) /* ... and then we can start the kernel. */ diff --git a/arch/alpha/kernel/init_task.c b/arch/alpha/kernel/init_task.c new file mode 100644 index 000000000000..c52bef4d6fa2 --- /dev/null +++ b/arch/alpha/kernel/init_task.c @@ -0,0 +1,17 @@ +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/init_task.h> +#include <linux/fs.h> +#include <asm/uaccess.h> + + +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; +struct mm_struct init_mm = INIT_MM(init_mm); +struct task_struct init_task = INIT_TASK(init_task); + +union thread_union init_thread_union + __attribute__((section(".data.init_thread"))) + = { INIT_THREAD_INFO(init_task) }; diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 9d82bf9f7f99..6150a3b4cc78 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -776,7 +776,7 @@ asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer, /* Return current software fp control & status bits. */ /* Note that DU doesn't verify available space here. */ - w = current->thread.flags & IEEE_SW_MASK; + w = current_thread_info->ieee_state & IEEE_SW_MASK; w = swcr_update_status(w, rdfpcr()); if (put_user(w, (unsigned long *) buffer)) return -EFAULT; @@ -793,7 +793,7 @@ asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer, case GSI_UACPROC: if (nbytes < sizeof(unsigned int)) return -EINVAL; - w = (current->thread.flags >> UAC_SHIFT) & UAC_BITMASK; + w = (current_thread_info()->flags >> UAC_SHIFT) & UAC_BITMASK; if (put_user(w, (unsigned int *)buffer)) return -EFAULT; return 1; @@ -840,8 +840,9 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer, /* Update softare trap enable bits. */ if (get_user(swcr, (unsigned long *)buffer)) return -EFAULT; - current->thread.flags &= ~IEEE_SW_MASK; - current->thread.flags |= swcr & IEEE_SW_MASK; + current_thread_info()->ieee_state + = ((current_thread_info()->ieee_state & ~IEEE_SW_MASK) + | (swcr & IEEE_SW_MASK)); /* Update the real fpcr. */ fpcr = rdfpcr(); @@ -869,18 +870,23 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer, case SSI_NVPAIRS: { unsigned long v, w, i; + unsigned int old, new; for (i = 0; i < nbytes; ++i) { + if (get_user(v, 2*i + (unsigned int *)buffer)) return -EFAULT; if (get_user(w, 2*i + 1 + (unsigned int *)buffer)) return -EFAULT; switch (v) { case SSIN_UACPROC: - current->thread.flags &= - ~(UAC_BITMASK << UAC_SHIFT); - current->thread.flags |= - (w & UAC_BITMASK) << UAC_SHIFT; + again: + old = current_thread_info()->flags; + new = old & ~(UAC_BITMASK << UAC_SHIFT); + new = new | (w & UAC_BITMASK) << UAC_SHIFT; + if (cmpxchg(¤t_thread_info()->flags, + old, new) != old) + goto again; break; default: diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c index eb2bf74d8b1c..f85e4bfb5f52 100644 --- a/arch/alpha/kernel/pci_iommu.c +++ b/arch/alpha/kernel/pci_iommu.c @@ -411,13 +411,8 @@ pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu_addr, Write dma_length of each leader with the combined lengths of the mergable followers. */ -#define SG_ENT_VIRT_ADDRESS(SG) \ - ((SG)->address \ - ? (SG)->address \ - : page_address((SG)->page) + (SG)->offset) - -#define SG_ENT_PHYS_ADDRESS(SG) \ - __pa(SG_ENT_VIRT_ADDRESS(SG)) +#define SG_ENT_VIRT_ADDRESS(SG) (page_address((SG)->page) + (SG)->offset) +#define SG_ENT_PHYS_ADDRESS(SG) __pa(SG_ENT_VIRT_ADDRESS(SG)) static void sg_classify(struct scatterlist *sg, struct scatterlist *end, int virt_ok) diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 68fc72ecdd0a..015eaa828cf7 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -43,22 +43,6 @@ #include "pci_impl.h" /* - * Initial task structure. Make this a per-architecture thing, - * because different architectures tend to have different - * alignment requirements and potentially different initial - * setup. - */ - -unsigned long init_user_stack[1024] = { STACK_MAGIC, }; -static struct fs_struct init_fs = INIT_FS; -static struct files_struct init_files = INIT_FILES; -static struct signal_struct init_signals = INIT_SIGNALS; -struct mm_struct init_mm = INIT_MM(init_mm); - -union task_union init_task_union __attribute__((section("init_task"))) - = { task: INIT_TASK(init_task_union.task) }; - -/* * No need to acquire the kernel lock, we're entirely local.. */ asmlinkage int @@ -73,18 +57,12 @@ sys_sethae(unsigned long hae, unsigned long a1, unsigned long a2, void cpu_idle(void) { - /* An endless idle loop with no priority at all. */ - current->nice = 20; - while (1) { /* FIXME -- EV6 and LCA45 know how to power down the CPU. */ - /* Although we are an idle CPU, we do not want to - get into the scheduler unnecessarily. */ - long oldval = xchg(¤t->work.need_resched, -1UL); - if (!oldval) - while (current->work.need_resched < 0); + while (!need_resched()) + barrier(); schedule(); check_pgt_cache(); } @@ -152,7 +130,7 @@ common_shutdown_1(void *generic_ptr) barrier(); #endif - /* If booted from SRM, reset some of the original environment. */ + /* If booted from SRM, reset some of the original environment. */ if (alpha_using_srm) { #ifdef CONFIG_DUMMY_CONSOLE /* This has the effect of resetting the VGA video origin. */ @@ -255,7 +233,7 @@ flush_thread(void) { /* Arrange for each exec'ed process to start off with a clean slate with respect to the FPU. This is all exceptions disabled. */ - current->thread.flags &= ~IEEE_SW_MASK; + current_thread_info()->ieee_state = 0; wrfpcr(FPCR_DYN_NORMAL | ieee_swcr_to_fpcr(0)); } @@ -294,8 +272,8 @@ alpha_vfork(struct switch_stack * swstack) * * Note the "stack_offset" stuff: when returning to kernel mode, we need * to have some extra stack-space for the kernel stack that still exists - * after the "ret_from_sys_call". When returning to user mode, we only - * want the space needed by the syscall stack frame (ie "struct pt_regs"). + * after the "ret_from_fork". When returning to user mode, we only want + * the space needed by the syscall stack frame (ie "struct pt_regs"). * Use the passed "regs" pointer to determine how much space we need * for a kernel fork(). */ @@ -305,9 +283,9 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, unsigned long unused, struct task_struct * p, struct pt_regs * regs) { - extern void ret_from_sys_call(void); extern void ret_from_fork(void); + struct thread_info *childti = p->thread_info; struct pt_regs * childregs; struct switch_stack * childstack, *stack; unsigned long stack_offset; @@ -315,7 +293,8 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, stack_offset = PAGE_SIZE - sizeof(struct pt_regs); if (!(regs->ps & 8)) stack_offset = (PAGE_SIZE-1) & (unsigned long) regs; - childregs = (struct pt_regs *) (stack_offset + PAGE_SIZE + (long)p); + childregs = (struct pt_regs *) + (stack_offset + PAGE_SIZE + (long) childti); *childregs = *regs; childregs->r0 = 0; @@ -326,10 +305,9 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, childstack = ((struct switch_stack *) childregs) - 1; *childstack = *stack; childstack->r26 = (unsigned long) ret_from_fork; - p->thread.usp = usp; - p->thread.ksp = (unsigned long) childstack; - p->thread.pal_flags = 1; /* set FEN, clear everything else */ - p->thread.flags = current->thread.flags; + childti->pcb.usp = usp; + childti->pcb.ksp = (unsigned long) childstack; + childti->pcb.flags = 1; /* set FEN, clear everything else */ return 0; } @@ -433,6 +411,35 @@ out: } /* + * Return saved PC of a blocked thread. This assumes the frame + * pointer is the 6th saved long on the kernel stack and that the + * saved return address is the first long in the frame. This all + * holds provided the thread blocked through a call to schedule() ($15 + * is the frame pointer in schedule() and $15 is saved at offset 48 by + * entry.S:do_switch_stack). + * + * Under heavy swap load I've seen this lose in an ugly way. So do + * some extra sanity checking on the ranges we expect these pointers + * to be in so that we can fail gracefully. This is just for ps after + * all. -- r~ + */ + +unsigned long +thread_saved_pc(task_t *t) +{ + unsigned long base = (unsigned long)t->thread_info; + unsigned long fp, sp = t->thread_info->pcb.ksp; + + if (sp > base && sp+6*8 < base + 16*1024) { + fp = ((unsigned long*)sp)[6]; + if (fp > sp && fp < base + 16*1024) + return *(unsigned long *)fp; + } + + return 0; +} + +/* * These bracket the sleeping functions.. */ extern void scheduling_functions_start_here(void); @@ -457,9 +464,9 @@ get_wchan(struct task_struct *p) * after all... */ - pc = thread_saved_pc(&p->thread); + pc = thread_saved_pc(p); if (pc >= first_sched && pc < last_sched) { - schedule_frame = ((unsigned long *)p->thread.ksp)[6]; + schedule_frame = ((unsigned long *)p->thread_info->pcb.ksp)[6]; return ((unsigned long *)schedule_frame)[12]; } return pc; diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index 103c2abe0bee..4b22cbbf29fd 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c @@ -101,7 +101,7 @@ get_reg_addr(struct task_struct * task, unsigned long regno) long *addr; if (regno == 30) { - addr = &task->thread.usp; + addr = &task->thread_info->pcb.usp; } else if (regno == 31 || regno > 64) { zero = 0; addr = &zero; @@ -120,7 +120,8 @@ get_reg(struct task_struct * task, unsigned long regno) /* Special hack for fpcr -- combine hardware and software bits. */ if (regno == 63) { unsigned long fpcr = *get_reg_addr(task, regno); - unsigned long swcr = task->thread.flags & IEEE_SW_MASK; + unsigned long swcr + = task->thread_info->ieee_state & IEEE_SW_MASK; swcr = swcr_update_status(swcr, fpcr); return fpcr | swcr; } @@ -134,8 +135,9 @@ static int put_reg(struct task_struct *task, unsigned long regno, long data) { if (regno == 63) { - task->thread.flags = ((task->thread.flags & ~IEEE_SW_MASK) - | (data & IEEE_SW_MASK)); + task->thread_info->ieee_state + = ((task->thread_info->ieee_state & ~IEEE_SW_MASK) + | (data & IEEE_SW_MASK)); data = (data & FPCR_DYN_MASK) | ieee_swcr_to_fpcr(data); } *get_reg_addr(task, regno) = data; @@ -182,31 +184,33 @@ ptrace_set_bpt(struct task_struct * child) * branch (emulation can be tricky for fp branches). */ displ = ((s32)(insn << 11)) >> 9; - child->thread.bpt_addr[nsaved++] = pc + 4; + child->thread_info->bpt_addr[nsaved++] = pc + 4; if (displ) /* guard against unoptimized code */ child->thread.bpt_addr[nsaved++] = pc + 4 + displ; DBG(DBG_BPT, ("execing branch\n")); } else if (op_code == 0x1a) { reg_b = (insn >> 16) & 0x1f; - child->thread.bpt_addr[nsaved++] = get_reg(child, reg_b); + child->thread_info->bpt_addr[nsaved++] = get_reg(child, reg_b); DBG(DBG_BPT, ("execing jump\n")); } else { - child->thread.bpt_addr[nsaved++] = pc + 4; + child->thread_info->bpt_addr[nsaved++] = pc + 4; DBG(DBG_BPT, ("execing normal insn\n")); } /* install breakpoints: */ for (i = 0; i < nsaved; ++i) { - res = read_int(child, child->thread.bpt_addr[i], &insn); + res = read_int(child, child->thread_info->bpt_addr[i], &insn); if (res < 0) return res; - child->thread.bpt_insn[i] = insn; - DBG(DBG_BPT, (" -> next_pc=%lx\n", child->thread.bpt_addr[i])); - res = write_int(child, child->thread.bpt_addr[i], BREAKINST); + child->thread_info->bpt_insn[i] = insn; + DBG(DBG_BPT, (" -> next_pc=%lx\n", + child->thread_info->bpt_addr[i])); + res = write_int(child, child->thread_info->bpt_addr[i], + BREAKINST); if (res < 0) return res; } - child->thread.bpt_nsaved = nsaved; + child->thread_info->bpt_nsaved = nsaved; return 0; } @@ -217,9 +221,9 @@ ptrace_set_bpt(struct task_struct * child) int ptrace_cancel_bpt(struct task_struct * child) { - int i, nsaved = child->thread.bpt_nsaved; + int i, nsaved = child->thread_info->bpt_nsaved; - child->thread.bpt_nsaved = 0; + child->thread_info->bpt_nsaved = 0; if (nsaved > 2) { printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); @@ -227,8 +231,8 @@ ptrace_cancel_bpt(struct task_struct * child) } for (i = 0; i < nsaved; ++i) { - write_int(child, child->thread.bpt_addr[i], - child->thread.bpt_insn[i]); + write_int(child, child->thread_info->bpt_addr[i], + child->thread_info->bpt_insn[i]); } return (nsaved != 0); } @@ -335,9 +339,9 @@ sys_ptrace(long request, long pid, long addr, long data, if ((unsigned long) data > _NSIG) goto out; if (request == PTRACE_SYSCALL) - child->ptrace |= PT_TRACESYS; + set_thread_flag(TIF_SYSCALL_TRACE); else - child->ptrace &= ~PT_TRACESYS; + clear_thread_flag(TIF_SYSCALL_TRACE); child->exit_code = data; wake_up_process(child); /* make sure single-step breakpoint is gone. */ @@ -364,8 +368,9 @@ sys_ptrace(long request, long pid, long addr, long data, ret = -EIO; if ((unsigned long) data > _NSIG) goto out; - child->thread.bpt_nsaved = -1; /* mark single-stepping */ - child->ptrace &= ~PT_TRACESYS; + /* Mark single stepping. */ + child->thread_info->bpt_nsaved = -1; + clear_thread_flag(TIF_SYSCALL_TRACE); wake_up_process(child); child->exit_code = data; /* give it a chance to run. */ @@ -381,7 +386,7 @@ sys_ptrace(long request, long pid, long addr, long data, goto out; } out: - free_task_struct(child); + put_task_struct(child); out_notsk: unlock_kernel(); return ret; @@ -390,8 +395,9 @@ sys_ptrace(long request, long pid, long addr, long data, asmlinkage void syscall_trace(void) { - if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) - != (PT_PTRACED|PT_TRACESYS)) + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + if (!(current->ptrace & PT_PTRACED)) return; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index de6e44e8ad47..972a41d9f7fc 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -32,8 +32,8 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) asmlinkage void ret_from_sys_call(void); -asmlinkage int do_signal(sigset_t *, struct pt_regs *, - struct switch_stack *, unsigned long, unsigned long); +static int do_signal(sigset_t *, struct pt_regs *, struct switch_stack *, + unsigned long, unsigned long); int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) @@ -618,7 +618,7 @@ syscall_restart(unsigned long r0, unsigned long r19, * restart. "r0" is also used as an indicator whether we can restart at * all (if we get here from anything but a syscall return, it will be 0) */ -asmlinkage int +static int do_signal(sigset_t *oldset, struct pt_regs * regs, struct switch_stack * sw, unsigned long r0, unsigned long r19) { @@ -744,3 +744,12 @@ do_signal(sigset_t *oldset, struct pt_regs * regs, struct switch_stack * sw, return 0; } + +void +do_notify_resume(sigset_t *oldset, struct pt_regs *regs, + struct switch_stack *sw, unsigned long r0, + unsigned long r19, unsigned long thread_info_flags) +{ + if (thread_info_flags & _TIF_SIGPENDING) + do_signal(oldset, regs, sw, r0, r19); +} diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index 46db9ffe645d..10a4e78aec5c 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -131,8 +131,8 @@ dik_show_trace(unsigned long *sp) void show_trace_task(struct task_struct * tsk) { - struct thread_struct * thread = &tsk->thread; - unsigned long fp, sp = thread->ksp, base = (unsigned long) thread; + struct thread_info *ti = &tsk->thread_info; + unsigned long fp, sp = ti->pcb.ksp, base = (unsigned long) ti; if (sp > base && sp+6*8 < base + 16*1024) { fp = ((unsigned long*)sp)[6]; @@ -180,12 +180,11 @@ die_if_kernel(char * str, struct pt_regs *regs, long err, unsigned long *r9_15) dik_show_trace((unsigned long *)(regs+1)); dik_show_code((unsigned int *)regs->pc); - if (current->thread.flags & (1UL << 63)) { + if (test_and_set_thread_flag (TIF_DIE_IF_KERNEL)) { printk("die_if_kernel recursion detected.\n"); sti(); while (1); } - current->thread.flags |= (1UL << 63); do_exit(SIGSEGV); } @@ -232,6 +231,13 @@ do_entIF(unsigned long type, unsigned long a1, unsigned long a5, struct pt_regs regs) { if (!opDEC_testing || type != 4) { + if (type == 1) { + const unsigned int *data + = (const unsigned int *) regs.pc; + printk("Kernel bug at %s:%d\n", + (const char *)(data[1] | (long)data[2] << 32), + data[0]); + } die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"), ®s, type, 0); } @@ -324,8 +330,8 @@ do_entIF(unsigned long type, unsigned long a1, FP registers, PAL_clrfen is not useful except for DoS attacks. So turn the bleeding FPU back on and be done with it. */ - current->thread.pal_flags |= 1; - __reload_thread(¤t->thread); + current_thead_info()->pcb.flags |= 1; + __reload_thread(¤t_thread_info()->pcb); return; case 5: /* illoc */ @@ -605,12 +611,11 @@ got_exception: dik_show_code((unsigned int *)pc); dik_show_trace((unsigned long *)(®s+1)); - if (current->thread.flags & (1UL << 63)) { + if (test_and_set_thread_flag (TIF_DIE_IF_KERNEL)) { printk("die_if_kernel recursion detected.\n"); sti(); while (1); } - current->thread.flags |= (1UL << 63); do_exit(SIGSEGV); } @@ -706,14 +711,12 @@ do_entUnaUser(void * va, unsigned long opcode, unsigned long tmp1, tmp2, tmp3, tmp4; unsigned long fake_reg, *reg_addr = &fake_reg; - unsigned long uac_bits; long error; /* Check the UAC bits to decide what the user wants us to do with the unaliged access. */ - uac_bits = (current->thread.flags >> UAC_SHIFT) & UAC_BITMASK; - if (!(uac_bits & UAC_NOPRINT)) { + if (!test_thread_flag (TIF_UAC_NOPRINT)) { if (cnt >= 5 && jiffies - last_time > 5*HZ) { cnt = 0; } @@ -724,13 +727,11 @@ do_entUnaUser(void * va, unsigned long opcode, } last_time = jiffies; } - if (uac_bits & UAC_SIGBUS) { + if (test_thread_flag (TIF_UAC_SIGBUS)) goto give_sigbus; - } - if (uac_bits & UAC_NOFIX) { - /* Not sure why you'd want to use this, but... */ + /* Not sure why you'd want to use this, but... */ + if (test_thread_flag (TIF_UAC_NOFIX)) return; - } /* Don't bother reading ds in the access check since we already know that this came from the user. Also rely on the fact that |
