archclean:
@$(MAKE) -C arch/alpha/kernel clean
@$(MAKEBOOT) clean
- rm -f arch/alpha/vmlinux.lds
archmrproper:
+ rm -f arch/alpha/vmlinux.lds
+ rm -f include/asm-alpha/asm_offsets.h
archdep:
+ $(MAKE) -C arch/alpha/kernel asm_offsets
@$(MAKEBOOT) dep
vmlinux: arch/alpha/vmlinux.lds
# 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
#
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
#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__ */");
}
#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.
*/
#define SAVE_ALL \
- subq $30,184,$30; \
+ subq $30,SP_OFF,$30; \
stq $0,0($30); \
stq $1,8($30); \
stq $2,16($30); \
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:; \
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
.end 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
/*
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.
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
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)
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
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
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:
.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. */
--- /dev/null
+#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) };
/* 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;
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;
/* 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();
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:
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)
#include "proto.h"
#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..
*/
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();
}
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. */
{
/* 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));
}
*
* 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().
*/
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;
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;
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;
}
return error;
}
+/*
+ * 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..
*/
* 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;
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;
/* 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;
}
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;
* 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;
}
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);
}
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);
}
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. */
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. */
goto out;
}
out:
- free_task_struct(child);
+ put_task_struct(child);
out_notsk:
unlock_kernel();
return ret;
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;
#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)
* 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)
{
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);
+}
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];
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);
}
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);
}
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 */
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);
}
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;
}
}
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
mode = (insn >> 11) & 0x3;
fpcr = rdfpcr();
- swcr = swcr_update_status(current->thread.flags, fpcr);
+ swcr = swcr_update_status(current_thread_info()->ieee_state, fpcr);
if (mode == 3) {
/* Dynamic -- get rounding mode from fpcr. */
if (_fex) {
/* Record exceptions in software control word. */
swcr |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT);
- current->thread.flags |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT);
+ current_thread_info()->ieee_state
+ |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT);
/* Update hardware control register. */
fpcr &= (~FPCR_MASK | FPCR_DYN_MASK);
__load_new_mm_context(struct mm_struct *next_mm)
{
unsigned long mmc;
+ struct pcb_struct *pcb;
mmc = __get_new_mm_context(next_mm, smp_processor_id());
next_mm->context[smp_processor_id()] = mmc;
- current->thread.asn = mmc & HARDWARE_ASN_MASK;
- current->thread.ptbr
- = ((unsigned long) next_mm->pgd - IDENT_ADDR) >> PAGE_SHIFT;
- __reload_thread(¤t->thread);
+ pcb = ¤t_thread_info()->pcb;
+ pcb->asn = mmc & HARDWARE_ASN_MASK;
+ pcb->ptbr = ((unsigned long) next_mm->pgd - IDENT_ADDR) >> PAGE_SHIFT;
+
+ __reload_thread(pcb);
}
extern void die_if_kernel(char *,struct pt_regs *,long);
-struct thread_struct original_pcb;
+static struct pcb_struct original_pcb;
#ifndef CONFIG_SMP
struct pgtable_cache_struct quicklists;
#endif
static inline unsigned long
-load_PCB(struct thread_struct * pcb)
+load_PCB(struct pcb_struct *pcb)
{
register unsigned long sp __asm__("$30");
pcb->ksp = sp;
}
/* Also set up the real kernel PCB while we're at it. */
- init_task.thread.ptbr = newptbr;
- init_task.thread.pal_flags = 1; /* set FEN, clear everything else */
- init_task.thread.flags = 0;
- original_pcb_ptr = load_PCB(&init_task.thread);
+ init_thread_info.pcb.ptbr = newptbr;
+ init_thread_info.pcb.flags = 1; /* set FEN, clear everything else */
+ original_pcb_ptr = load_PCB(&init_thread_info.pcb);
tbia();
/* Save off the contents of the original PCB so that we can
original_pcb_ptr = (unsigned long)
phys_to_virt(original_pcb_ptr);
}
- original_pcb = *(struct thread_struct *) original_pcb_ptr;
+ original_pcb = *(struct pcb_struct *) original_pcb_ptr;
}
int callback_init_done;
. = 0xfffffc0000810000;
#endif
- _text = .;
- .text : { *(.text) } :kernel
- _etext = .;
+ .text : {
+ _text = .;
+ *(.text)
+ _etext = .;
+ } :kernel
/* Exception table */
- . = ALIGN(16);
- __start___ex_table = .;
- __ex_table : { *(__ex_table) }
- __stop___ex_table = .;
+ __ex_table ALIGN(16) : {
+ __start___ex_table = .;
+ *(__ex_table)
+ __stop___ex_table = .;
+ }
/* Kernel symbol table */
- . = ALIGN(8);
- __start___ksymtab = .;
- __ksymtab : { *(__ksymtab) }
- __stop___ksymtab = .;
+ __ksymtab ALIGN(8) : {
+ __start___ksymtab = .;
+ *(__ksymtab)
+ __stop___ksymtab = .;
+ }
.kstrtab : { *(.kstrtab) }
/* Startup code */
- . = ALIGN(8192);
- __init_begin = .;
- .text.init : { *(.text.init) }
+ .text.init ALIGN(8192) : {
+ __init_begin = .;
+ *(.text.init)
+ }
.data.init : { *(.data.init) }
- . = ALIGN(16);
- __setup_start = .;
- .setup.init : { *(.setup.init) }
- __setup_end = .;
+ .setup.init ALIGN(16): {
+ __setup_start = .;
+ *(.setup.init)
+ __setup_end = .;
+ }
- . = ALIGN(8);
- __initcall_start = .;
- .initcall.init : {
+ .initcall.init ALIGN(8): {
+ __initcall_start = .;
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
+ __initcall_end = .;
}
- __initcall_end = .;
-
- . = ALIGN(2*8192); /* Align double page for init_task_union */
- __init_end = .;
/* The initial task and kernel stack */
- init_task : { *(init_task) }
+ .data.init_thread ALIGN(2*8192) : {
+ __init_end = .;
+ *(.data.init_thread)
+ }
/* Global data */
- _data = .;
- .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+ .data.cacheline_aligned : {
+ _data = .;
+ *(.data.cacheline_aligned)
+ }
.rodata : { *(.rodata) *(.rodata.*) }
.data : { *(.data) CONSTRUCTORS }
.got : { *(.got) }
- .sdata : { *(.sdata) }
- _edata = .;
+ .sdata : {
+ *(.sdata)
+ _edata = .;
+ }
- __bss_start = .;
- .sbss : { *(.sbss) *(.scommon) }
- .bss : { *(.bss) *(COMMON) }
- __bss_stop = .;
- _end = .;
+ .sbss : {
+ __bss_start = .;
+ *(.sbss) *(.scommon)
+ }
+ .bss : {
+ *(.bss) *(COMMON)
+ __bss_stop = .;
+ _end = .;
+ }
.mdebug 0 : { *(.mdebug) }
.note 0 : { *(.note) }
* WARNING: non atomic version.
*/
static __inline__ void
-__change_bit(unsigned long nr, volatile void * addr)
+__clear_bit(unsigned long nr, volatile void * addr)
{
int *m = ((int *) addr) + (nr >> 5);
- *m ^= 1 << (nr & 31);
+ *m &= ~(1 << (nr & 31));
}
static inline void
:"Ir" (1UL << (nr & 31)), "m" (*m));
}
+/*
+ * WARNING: non atomic version.
+ */
+static __inline__ void
+__change_bit(unsigned long nr, volatile void * addr)
+{
+ int *m = ((int *) addr) + (nr >> 5);
+
+ *m ^= 1 << (nr & 31);
+}
+
static inline int
test_and_set_bit(unsigned long nr, volatile void *addr)
{
return (old & mask) != 0;
}
-/*
- * WARNING: non atomic version.
- */
-static __inline__ int
-__test_and_change_bit(unsigned long nr, volatile void * addr)
-{
- unsigned long mask = 1 << (nr & 0x1f);
- int *m = ((int *) addr) + (nr >> 5);
- int old = *m;
-
- *m = old ^ mask;
- return (old & mask) != 0;
-}
-
static inline int
test_and_change_bit(unsigned long nr, volatile void * addr)
{
return oldbit != 0;
}
+/*
+ * WARNING: non atomic version.
+ */
+static __inline__ int
+__test_and_change_bit(unsigned long nr, volatile void * addr)
+{
+ unsigned long mask = 1 << (nr & 0x1f);
+ int *m = ((int *) addr) + (nr >> 5);
+ int old = *m;
+
+ *m = old ^ mask;
+ return (old & mask) != 0;
+}
+
static inline int
test_bit(int nr, volatile void * addr)
{
#endif
}
+/*
+ * __ffs = Find First set bit in word. Undefined if no set bit exists.
+ */
+static inline unsigned long __ffs(unsigned long word)
+{
+#if defined(__alpha_cix__) && defined(__alpha_fix__)
+ /* Whee. EV67 can calculate it directly. */
+ unsigned long result;
+ __asm__("cttz %1,%0" : "=r"(result) : "r"(word));
+ return result;
+#else
+ unsigned long bits, qofs, bofs;
+
+ __asm__("cmpbge $31,%1,%0" : "=r"(bits) : "r"(word));
+ qofs = ffz_b(bits);
+ __asm__("extbl %1,%2,%0" : "=r"(bits) : "r"(word), "r"(qofs));
+ bofs = ffz_b(~bits);
+
+ return qofs*8 + bofs;
+#endif
+}
+
#ifdef __KERNEL__
/*
* ffs: find first bit set. This is defined the same way as
* the libc and compiler builtin ffs routines, therefore
- * differs in spirit from the above ffz (man ffs).
+ * differs in spirit from the above __ffs.
*/
static inline int ffs(int word)
{
- int result = ffz(~word);
+ int result = __ffs(word);
return word ? result+1 : 0;
}
}
/*
- * The optimizer actually does good code for this case..
+ * Find next one bit in a bitmap reasonably efficiently.
+ */
+static inline unsigned long
+find_next_bit(void * addr, unsigned long size, unsigned long offset)
+{
+ unsigned long * p = ((unsigned long *) addr) + (offset >> 6);
+ unsigned long result = offset & ~63UL;
+ unsigned long tmp;
+
+ if (offset >= size)
+ return size;
+ size -= result;
+ offset &= 63UL;
+ if (offset) {
+ tmp = *(p++);
+ tmp &= ~0UL << offset;
+ if (size < 64)
+ goto found_first;
+ if (tmp)
+ goto found_middle;
+ size -= 64;
+ result += 64;
+ }
+ while (size & ~63UL) {
+ if ((tmp = *(p++)))
+ goto found_middle;
+ result += 64;
+ size -= 64;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+found_first:
+ tmp &= ~0UL >> (64 - size);
+ if (!tmp)
+ return result + size;
+found_middle:
+ return result + __ffs(tmp);
+}
+
+/*
+ * The optimizer actually does good code for this case.
*/
#define find_first_zero_bit(addr, size) \
find_next_zero_bit((addr), (size), 0)
+#define find_first_bit(addr, size) \
+ find_next_bit((addr), (size), 0)
#ifdef __KERNEL__
#ifndef _ALPHA_CURRENT_H
#define _ALPHA_CURRENT_H
-register struct task_struct *current __asm__("$8");
+#include <asm/thread_info.h>
-#endif /* !(_ALPHA_CURRENT_H) */
+#define get_current() (current_thread_info()->task + 0)
+#define current get_current()
+
+#endif /* _ALPHA_CURRENT_H */
/*
* IEEE trap enables are implemented in software. These per-thread
- * bits are stored in the "flags" field of "struct thread_struct".
+ * bits are stored in the "ieee_state" field of "struct thread_info".
* Thus, the bits are defined so as not to conflict with the
* floating-point enable bit (which is architected). On top of that,
* we want to make these bits compatible with OSF/1 so
#include <linux/config.h>
#include <linux/kernel.h>
#include <asm/system.h>
+#include <asm/pgtable.h>
#include <asm/machvec.h>
/*
return (void *) (address + IDENT_ADDR);
}
-#define page_to_phys(page) (((page) - (page)->zone->zone_mem_map) << PAGE_SHIFT)
+#define page_to_phys(page) PAGE_TO_PA(page)
+
+/* This depends on working iommu. */
+#define BIO_VMERGE_BOUNDARY (alpha_mv.mv_pci_tbi ? PAGE_SIZE : 0)
/*
* Change addresses as seen by the kernel (virtual) to addresses as
#include <asm/io.h>
#endif
+/* ??? This does not belong here. */
+/*
+ * Every architecture must define this function. It's the fastest
+ * way of searching a 168-bit bitmap where the first 128 bits are
+ * unlikely to be set. It's guaranteed that at least one of the 168
+ * bits is set.
+ */
+#if MAX_RT_PRIO != 128 || MAX_PRIO > 192
+# error update this function.
+#endif
+
+static inline int
+sched_find_first_bit(unsigned long *b)
+{
+ unsigned long b0 = b[0], b1 = b[1], b2 = b[2];
+ unsigned long offset = 128;
+
+ if (unlikely(b0 | b1)) {
+ b2 = (b0 ? b0 : b1);
+ offset = (b0 ? 0 : 64);
+ }
+
+ return __ffs(b2) + offset;
+}
+
+
extern inline unsigned long
-__reload_thread(struct thread_struct *pcb)
+__reload_thread(struct pcb_struct *pcb)
{
register unsigned long a0 __asm__("$16");
register unsigned long v0 __asm__("$0");
/* Always update the PCB ASN. Another thread may have allocated
a new mm->context (via flush_tlb_mm) without the ASN serial
number wrapping. We have no way to detect when this is needed. */
- next->thread.asn = mmc & HARDWARE_ASN_MASK;
+ next->thread_info->pcb.asn = mmc & HARDWARE_ASN_MASK;
}
__EXTERN_INLINE void
for (i = 0; i < smp_num_cpus; i++)
mm->context[cpu_logical_map(i)] = 0;
- tsk->thread.ptbr = ((unsigned long)mm->pgd - IDENT_ADDR) >> PAGE_SHIFT;
+ tsk->thread_info->pcb.ptbr
+ = ((unsigned long)mm->pgd - IDENT_ADDR) >> PAGE_SHIFT;
return 0;
}
static inline void
enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
{
- tsk->thread.ptbr = ((unsigned long)mm->pgd - IDENT_ADDR) >> PAGE_SHIFT;
+ tsk->thread_info->pcb.ptbr
+ = ((unsigned long)mm->pgd - IDENT_ADDR) >> PAGE_SHIFT;
}
#ifdef __MMU_EXTERN_INLINE
#endif /* STRICT_MM_TYPECHECKS */
-#define BUG() \
-do { \
- printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
- __asm__ __volatile__("call_pal %0 # bugchk" : : "i" (PAL_bugchk)); \
-} while (0)
+/* ??? Would be nice to use .gprel32 here, but we can't be sure that the
+ function loaded the GP, so this could fail in modules. */
+#define BUG() \
+ __asm__ __volatile__("call_pal %0 # bugchk\n\t"".long %1\n\t.8byte %2" \
+ : : "i" (PAL_bugchk), "i"(__LINE__), "i"(__FILE__))
#define PAGE_BUG(page) BUG()
unsigned long seg;
} mm_segment_t;
-struct thread_struct {
- /* the fields below are used by PALcode and must match struct pcb: */
- unsigned long ksp;
- unsigned long usp;
- unsigned long ptbr;
- unsigned int pcc;
- unsigned int asn;
- unsigned long unique;
- /*
- * bit 0: floating point enable
- * bit 62: performance monitor enable
- */
- unsigned long pal_flags;
- unsigned long res1, res2;
-
- /*
- * The fields below are Linux-specific:
- *
- * bit 1..5: IEEE_TRAP_ENABLE bits (see fpu.h)
- * bit 6..8: UAC bits (see sysinfo.h)
- * bit 17..21: IEEE_STATUS_MASK bits (see fpu.h)
- * bit 63: die_if_kernel recursion lock
- */
- unsigned long flags;
-
- /* Perform syscall argument validation (get/set_fs). */
- mm_segment_t fs;
-
- /* Breakpoint handling for ptrace. */
- unsigned long bpt_addr[2];
- unsigned int bpt_insn[2];
- int bpt_nsaved;
-};
-
-#define INIT_THREAD { \
- 0, 0, 0, \
- 0, 0, 0, \
- 0, 0, 0, \
- 0, \
- KERNEL_DS \
-}
-
-#define THREAD_SIZE (2*PAGE_SIZE)
+/* This is dead. Everything has been moved to thread_info. */
+struct thread_struct { };
+#define INIT_THREAD { }
-#include <asm/ptrace.h>
-
-/*
- * 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~
- */
-extern inline unsigned long thread_saved_pc(struct thread_struct *t)
-{
- unsigned long fp, sp = t->ksp, base = (unsigned long)t;
-
- 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;
-}
+/* Return saved PC of a blocked thread. */
+struct task_struct;
+extern unsigned long thread_saved_pc(struct task_struct *);
/* Do necessary setup to start up a newly executed thread. */
extern void start_thread(struct pt_regs *, unsigned long, unsigned long);
-struct task_struct;
-
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
unsigned long get_wchan(struct task_struct *p);
/* See arch/alpha/kernel/ptrace.c for details. */
-#define PT_REG(reg) (PAGE_SIZE*2 - sizeof(struct pt_regs) \
- + (long)&((struct pt_regs *)0)->reg)
+#define PT_REG(reg) \
+ (PAGE_SIZE*2 - sizeof(struct pt_regs) + offsetof(struct pt_regs, reg))
-#define SW_REG(reg) (PAGE_SIZE*2 - sizeof(struct pt_regs) \
- - sizeof(struct switch_stack) \
- + (long)&((struct switch_stack *)0)->reg)
+#define SW_REG(reg) \
+ (PAGE_SIZE*2 - sizeof(struct pt_regs) - sizeof(struct switch_stack) \
+ + offsetof(struct switch_stack, reg))
#define KSTK_EIP(tsk) \
- (*(unsigned long *)(PT_REG(pc) + (unsigned long)(tsk)))
-
-#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp)
-
-/* NOTE: The task struct and the stack go together! */
-#define alloc_task_struct() \
- ((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
-#define free_task_struct(p) free_pages((unsigned long)(p),1)
-#define get_task_struct(tsk) atomic_inc(&virt_to_page(tsk)->count)
+ (*(unsigned long *)(PT_REG(pc) + (unsigned long) ((tsk)->thread_info)))
-#define init_task (init_task_union.task)
-#define init_stack (init_task_union.stack)
+#define KSTK_ESP(tsk) \
+ ((tsk) == current ? rdusp() : (tsk)->thread_info->pcb.usp)
#define cpu_relax() do { } while (0)
#define ARCH_HAS_PREFETCHW
#define ARCH_HAS_SPINLOCK_PREFETCH
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
extern inline void prefetch(const void *ptr)
{
- __asm__ ("ldl $31,%0" : : "m"(*(char *)ptr));
+ __builtin_prefetch(ptr, 0, 3);
}
extern inline void prefetchw(const void *ptr)
{
- __asm__ ("ldl $31,%0" : : "m"(*(char *)ptr));
+ __builtin_prefetch(ptr, 1, 3);
}
extern inline void spin_lock_prefetch(const void *ptr)
{
+ __builtin_prefetch(ptr, 1, 3);
+}
+#else
+extern inline void prefetch(const void *ptr)
+{
__asm__ ("ldl $31,%0" : : "m"(*(char *)ptr));
}
-
+extern inline void prefetchw(const void *ptr)
+{
+ __asm__ ("ldq $31,%0" : : "m"(*(char *)ptr));
+}
+
+extern inline void spin_lock_prefetch(const void *ptr)
+{
+ __asm__ ("ldq $31,%0" : : "m"(*(char *)ptr));
+}
+#endif /* GCC 3.1 */
#endif /* __ASM_ALPHA_PROCESSOR_H */
#define __ASM_SMP_H
#include <linux/config.h>
+#include <linux/threads.h>
#include <asm/pal.h>
/* HACK: Cabrio WHAMI return value is bogus if more than 8 bits used.. :-( */
#define cpu_logical_map(cpu) __cpu_logical_map[cpu]
#define hard_smp_processor_id() __hard_smp_processor_id()
-#define smp_processor_id() (current->processor)
+#define smp_processor_id() (current_thread_info()->cpu)
extern unsigned long cpu_present_mask;
#define cpu_online_map cpu_present_mask
#ifdef __KERNEL__
-/* This is the shift that is applied to the UAC bits as stored in the
- per-thread flags. */
+/* This is the shift that is applied to the UAC bits as stored in the
+ per-thread flags. See thread_info.h. */
#define UAC_SHIFT 6
#endif
#define switch_to(prev,next,last) \
do { \
unsigned long pcbb; \
- current = (next); \
- pcbb = virt_to_phys(¤t->thread); \
+ pcbb = virt_to_phys(&(next)->thread_info->pcb); \
(last) = alpha_switch_to(pcbb, (prev)); \
check_mmu_context(); \
} while (0)
--- /dev/null
+#ifndef _ALPHA_THREAD_INFO_H
+#define _ALPHA_THREAD_INFO_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+#include <asm/processor.h>
+#include <asm/types.h>
+#include <asm/hwrpb.h>
+#endif
+
+#ifndef __ASSEMBLY__
+struct thread_info {
+ struct pcb_struct pcb; /* palcode state */
+
+ struct task_struct *task; /* main task structure */
+ unsigned int flags; /* low level flags */
+ unsigned int ieee_state; /* see fpu.h */
+
+ struct exec_domain *exec_domain; /* execution domain */
+ mm_segment_t addr_limit; /* thread address space */
+ int cpu; /* current CPU */
+
+ int bpt_nsaved;
+ unsigned long bpt_addr[2]; /* breakpoint handling */
+ unsigned int bpt_insn[2];
+};
+
+/*
+ * Macros/functions for gaining access to the thread information structure.
+ */
+#define INIT_THREAD_INFO(tsk) \
+{ \
+ task: &tsk, \
+ exec_domain: &default_exec_domain, \
+ addr_limit: KERNEL_DS, \
+}
+
+#define init_thread_info (init_thread_union.thread_info)
+#define init_stack (init_thread_union.stack)
+
+/* How to get the thread information struct from C. */
+register struct thread_info *__current_thread_info __asm__("$8");
+#define current_thread_info() __current_thread_info
+
+/* Thread information allocation. */
+#define THREAD_SIZE (2*PAGE_SIZE)
+#define alloc_thread_info() \
+ ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
+#define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
+#define get_thread_info(ti) get_task_struct((ti)->task)
+#define put_thread_info(ti) put_task_struct((ti)->task)
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * Thread information flags:
+ * - these are process state flags and used from assembly
+ * - pending work-to-be-done flags come first to fit in and immediate operand.
+ *
+ * TIF_SYSCALL_TRACE is known to be 0 via blbs.
+ */
+#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
+#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */
+#define TIF_SIGPENDING 2 /* signal pending */
+#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
+#define TIF_POLLING_NRFLAG 4 /* poll_idle is polling NEED_RESCHED */
+#define TIF_DIE_IF_KERNEL 5 /* dik recursion lock */
+#define TIF_UAC_NOPRINT 6 /* see sysinfo.h */
+#define TIF_UAC_NOFIX 7
+#define TIF_UAC_SIGBUS 8
+
+#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
+#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
+#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
+#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
+
+/* Work to do on interrupt/exception return. */
+#define _TIF_WORK_MASK (_TIF_NOTIFY_RESUME \
+ | _TIF_SIGPENDING \
+ | _TIF_NEED_RESCHED)
+
+/* Work to do on any return to userspace. */
+#define _TIF_ALLWORK_MASK (_TIF_WORK_MASK \
+ | _TIF_SYSCALL_TRACE)
+
+#endif /* __KERNEL__ */
+#endif /* _ALPHA_THREAD_INFO_H */
#define VERIFY_READ 0
#define VERIFY_WRITE 1
-#define get_fs() (current->thread.fs)
+#define get_fs() (current_thread_info()->addr_limit)
#define get_ds() (KERNEL_DS)
-#define set_fs(x) (current->thread.fs = (x))
+#define set_fs(x) (current_thread_info()->addr_limit = (x))
#define segment_eq(a,b) ((a).seg == (b).seg)
#include <linux/string.h>
#include <linux/signal.h>
+#include <asm/ptrace.h>
extern void sys_idle(void);
static inline void idle(void)
return sys_sync();
}
+struct rusage;
+extern asmlinkage long sys_wait4(pid_t, unsigned int *, int, struct rusage *);
static inline pid_t waitpid(int pid, int * wait_stat, int flags)
{
return sys_wait4(pid, wait_stat, flags, NULL);