summaryrefslogtreecommitdiff
path: root/arch/alpha/kernel
diff options
context:
space:
mode:
authorRichard Henderson <rth@fidel.sfbay.redhat.com>2002-02-10 13:42:53 -0800
committerRichard Henderson <rth@fidel.sfbay.redhat.com>2002-02-10 13:42:53 -0800
commit374eeee8a8a50e12278dfa37021df7b6efe506c3 (patch)
tree2388fbed3bb98ad9f8f342c1353c2bbfb40e07c8 /arch/alpha/kernel
parent74c0102446bb3160f186555bd133062003acf194 (diff)
Update Alpha UP for thread_info and scheduler changes.
Diffstat (limited to 'arch/alpha/kernel')
-rw-r--r--arch/alpha/kernel/Makefile20
-rw-r--r--arch/alpha/kernel/check_asm.c42
-rw-r--r--arch/alpha/kernel/entry.S266
-rw-r--r--arch/alpha/kernel/head.S4
-rw-r--r--arch/alpha/kernel/init_task.c17
-rw-r--r--arch/alpha/kernel/osf_sys.c22
-rw-r--r--arch/alpha/kernel/pci_iommu.c9
-rw-r--r--arch/alpha/kernel/process.c79
-rw-r--r--arch/alpha/kernel/ptrace.c52
-rw-r--r--arch/alpha/kernel/signal.c15
-rw-r--r--arch/alpha/kernel/traps.c33
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(&current_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(&current->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"),
&regs, 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(&current->thread);
+ current_thead_info()->pcb.flags |= 1;
+ __reload_thread(&current_thread_info()->pcb);
return;
case 5: /* illoc */
@@ -605,12 +611,11 @@ got_exception:
dik_show_code((unsigned int *)pc);
dik_show_trace((unsigned long *)(&regs+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