[Linux-ia64] kernel update (relative to v2.4.0-test1)

David Mosberger
2000-06-10T01:07:23Z

An updated kernel diff is available in the usual place:

ftp://ftp.kernel.org/pub/linux/kernel/ports/ia64/linux-2.4.0-test1-ia64-000609*

Summary of changes:

- Stephen Zeisset's module related fixes to ia64_ksyms.c and pci.c.

- Bill Nottingham's initrd additions.

- Takayoshi Kouchi's pointer-lock related SMP fixes.

- Jes Sorensen's mmap bug fix.

- New unwind support now almost works. Warning: don't enable
CONFIG_IA64_NEW_UNWIND unless you have a bleeding edge toolchain
with _all_ the unwind fixes. Even then you may not want to turn
it on as core-dump support hasn't been finished yet.

- Without the new unwind support, the kernel now is conservative
again and generates a switch_stack frame whenever there is a remote
possibility that it might be needed. This slows down several
signal related operations, but it will be fast again once
the new unwind support is complete.

I also added a printk whenever we get a timer tick before it was due.
Since that happens quite frequently, this quickly becomes annoying.
Look at it as an invitation to investigate the problem... ;-)

--david

diff -urN linux-davidm/arch/ia64/kernel/entry.S linux-2.4.0-test1-lia/arch/ia64/kernel/entry.S
--- linux-davidm/arch/ia64/kernel/entry.S Fri Jun 9 17:38:58 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/entry.S Fri Jun 9 17:09:56 2000
@@ -117,14 +117,11 @@
mov psr.l=r17
;;
srlz.d
-
- movl r28\x1f
- br.cond.sptk.many load_switch_stack
-1: UNW(.restore sp)
- adds sp=IA64_SWITCH_STACK_SIZE,sp // pop switch_stack
+ DO_LOAD_SWITCH_STACK( )
br.ret.sptk.few rp
END(ia64_switch_to)

+#ifndef CONFIG_IA64_NEW_UNWIND
/*
* Like save_switch_stack, but also save the stack frame that is active
* at the time this function is called.
@@ -135,6 +132,8 @@
DO_SAVE_SWITCH_STACK
br.ret.sptk.few rp
END(save_switch_stack_with_current_frame)
+#endif /* !CONFIG_IA64_NEW_UNWIND */
+
/*
* Note that interrupts are enabled during save_switch_stack and
* load_switch_stack. This means that we may get an interrupt with
@@ -343,7 +342,6 @@
;;
ld8.fill r4=[r2],16
ld8.fill r5=[r3],16
- mov b7=r28
;;
ld8.fill r6=[r2],16
ld8.fill r7=[r3],16
@@ -371,6 +369,19 @@
// also use it to preserve b6, which contains the syscall entry point.
//
GLOBAL_ENTRY(invoke_syscall_trace)
+#ifdef CONFIG_IA64_NEW_UNWIND
+ UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8))
+ alloc loc1=ar.pfs,8,3,0,0
+ mov loc0=rp
+ UNW(.body)
+ mov loc2¶
+ ;;
+ br.call.sptk.few rp=syscall_trace
+.ret3: mov rp=loc0
+ mov ar.pfs=loc1
+ mov b6=loc2
+ br.ret.sptk.few rp
+#else /* !CONFIG_IA64_NEW_SYSCALL */
UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8))
alloc loc1=ar.pfs,8,3,0,0
;; // WAW on CFM at the br.call
@@ -384,6 +395,7 @@
mov b6=loc2
;;
br.ret.sptk.few rp
+#endif /* !CONFIG_IA64_NEW_SYSCALL */
END(invoke_syscall_trace)

//
@@ -802,112 +814,140 @@
// args get preserved, in case we need to restart a system call.
//
ENTRY(handle_signal_delivery)
- UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8))
+#ifdef CONFIG_IA64_NEW_UNWIND
+ .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart!
mov r9=ar.unat
-
- // If the process is being ptraced, the signal may not actually be delivered to
- // the process. Instead, SIGCHLD will be sent to the parent. We need to
- // setup a switch_stack so ptrace can inspect the processes state if necessary.
- adds r2=IA64_TASK_FLAGS_OFFSET,r13
- ;;
- ld8 r2=[r2]
+ mov loc0=rp // save return address
+ .body
mov out0=0 // there is no "oldset"
- adds out1\x16,sp // out1=&pt_regs
- ;;
+ adds out1=0,sp // out1=&sigscratch
(pSys) mov out2=1 // out2=1 => we're in a syscall
- tbit.nz p16,p17=r2,PF_PTRACED_BIT
-(p16) br.cond.spnt.many setup_switch_stack
;;
-back_from_setup_switch_stack:
(pNonSys) mov out2=0 // out2=0 => not a syscall
- adds r3=-IA64_SWITCH_STACK_SIZE+IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp
-(p17) adds sp=-IA64_SWITCH_STACK_SIZE,sp // make space for (dummy) switch_stack
- ;;
-(p17) st8 [r3]=r9 // save ar.unat in sw->caller_unat
- mov loc0=rp // save return address
- UNW(.body)
+ .fframe 16
+ .spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!)
+ st8 [sp]=r9,-16 // allocate space for ar.unat and save it
br.call.sptk.few rp=ia64_do_signal
.ret11:
- adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp
+ .restore sp
+ adds sp\x16,sp // pop scratch stack space
;;
- ld8 r9=[r3] // load new unat from sw->caller_unat
+ ld8 r9=[sp] // load new unat from sw->caller_unat
mov rp=loc0
;;
-(p17) adds sp=IA64_SWITCH_STACK_SIZE,sp // drop (dummy) switch_stack
-(p17) mov ar.unat=r9
-(p17) mov ar.pfs=loc1
-(p17) br.ret.sptk.many rp
-
- DO_LOAD_SWITCH_STACK( ) // restore the switch stack (ptrace may have modified it)
+ mov ar.unat=r9
+ mov ar.pfs=loc1
br.ret.sptk.many rp
- // NOT REACHED
-
-setup_switch_stack:
- UNW(.prologue)
- mov r16=loc1
+#else /* !CONFIG_IA64_NEW_UNWIND */
+ .prologue
+ alloc r16=ar.pfs,8,0,3,0 // preserve all eight input regs in case of syscall restart!
DO_SAVE_SWITCH_STACK
UNW(.body)
- br.cond.sptk.many back_from_setup_switch_stack

+ mov out0=0 // there is no "oldset"
+ adds out1\x16,sp // out1=&sigscratch
+ .pred.rel.mutex pSys, pNonSys
+(pSys) mov out2=1 // out2=1 => we're in a syscall
+(pNonSys) mov out2=0 // out2=0 => not a syscall
+ br.call.sptk.few rp=ia64_do_signal
+.ret11:
+ // restore the switch stack (ptrace may have modified it)
+ DO_LOAD_SWITCH_STACK( )
+ br.ret.sptk.many rp
+#endif /* !CONFIG_IA64_NEW_UNWIND */
END(handle_signal_delivery)

GLOBAL_ENTRY(sys_rt_sigsuspend)
- UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2))
- alloc loc1=ar.pfs,2,2,3,0
-
- // If the process is being ptraced, the signal may not actually be delivered to
- // the process. Instead, SIGCHLD will be sent to the parent. We need to
- // setup a switch_stack so ptrace can inspect the processes state if necessary.
- // Also, the process might not ptraced until stopped in sigsuspend, so this
- // isn't something that we can do conditionally based upon the value of
- // PF_PTRACED_BIT.
+#ifdef CONFIG_IA64_NEW_UNWIND
+ .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
+ alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart!
+ mov r9=ar.unat
+ mov loc0=rp // save return address
mov out0=in0 // mask
mov out1=in1 // sigsetsize
+ adds out2=0,sp // out2=&sigscratch
;;
- adds out2\x16,sp // out1=&pt_regs
- mov r16=loc1
- DO_SAVE_SWITCH_STACK
- mov loc0=rp // save return address
- UNW(.body)
- br.call.sptk.many rp=ia64_rt_sigsuspend
+ .fframe 16
+ .spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!)
+ st8 [sp]=r9,-16 // allocate space for ar.unat and save it
+ .body
+ br.call.sptk.few rp=ia64_rt_sigsuspend
.ret12:
- adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp
+ .restore sp
+ adds sp\x16,sp // pop scratch stack space
;;
- ld8 r9=[r3] // load new unat from sw->caller_unat
+ ld8 r9=[sp] // load new unat from sw->caller_unat
mov rp=loc0
;;
+ mov ar.unat=r9
+ mov ar.pfs=loc1
+ br.ret.sptk.many rp
+#else /* !CONFIG_IA64_NEW_UNWIND */
+ UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2))
+ alloc r16=ar.pfs,2,0,3,0
+ DO_SAVE_SWITCH_STACK
+ UNW(.body)
+
+ mov out0=in0 // mask
+ mov out1=in1 // sigsetsize
+ adds out2\x16,sp // out1=&sigscratch
+ br.call.sptk.many rp=ia64_rt_sigsuspend
+.ret12:
// restore the switch stack (ptrace may have modified it)
- DO_LOAD_SWITCH_STACK(PT_REGS_UNWIND_INFO)
+ DO_LOAD_SWITCH_STACK( )
br.ret.sptk.many rp
- // NOT REACHED
+#endif /* !CONFIG_IA64_NEW_UNWIND */
END(sys_rt_sigsuspend)

ENTRY(sys_rt_sigreturn)
+#ifdef CONFIG_IA64_NEW_UNWIND
+ .regstk 0,0,3,0 // inherited from gate.s:invoke_sighandler()
+ PT_REGS_UNWIND_INFO
+ .prologue
+ PT_REGS_SAVES(16)
+ adds sp=-16,sp
+ .body
+ cmp.eq pNonSys,p0=r0,r0 // sigreturn isn't a normal syscall...
+ ;;
+ adds out0\x16,sp // out0 = &sigscratch
+ br.call.sptk.few rp=ia64_rt_sigreturn
+.ret13:
+ adds sp\x16,sp // doesn't drop pt_regs, so don't mark it as restoring sp!
+ PT_REGS_UNWIND_INFO // instead, create a new body section with the smaller frame
+ ;;
+ ld8 r9=[sp] // load new ar.unat
+ mov b7=r8
+ ;;
+ mov ar.unat=r9
+ br b7
+#else /* !CONFIG_IA64_NEW_UNWIND */
.regstk 0,0,3,0 // inherited from gate.s:invoke_sighandler()
PT_REGS_UNWIND_INFO
- adds out0\x16,sp // out0 = &pt_regs
UNW(.prologue)
UNW(.fframe IA64_PT_REGS_SIZE+IA64_SWITCH_STACK_SIZE)
UNW(.spillsp rp, PT(CR_IIP)+IA64_SWITCH_STACK_SIZE)
UNW(.spillsp ar.pfs, PT(CR_IFS)+IA64_SWITCH_STACK_SIZE)
UNW(.spillsp ar.unat, PT(AR_UNAT)+IA64_SWITCH_STACK_SIZE)
UNW(.spillsp pr, PT(PR)+IA64_SWITCH_STACK_SIZE)
- adds sp=-IA64_SWITCH_STACK_SIZE,sp // make space for unat and padding
+ adds sp=-IA64_SWITCH_STACK_SIZE,sp
+ cmp.eq pNonSys,p0=r0,r0 // sigreturn isn't a normal syscall...
;;
UNW(.body)
- cmp.eq pNonSys,p0=r0,r0 // sigreturn isn't a normal syscall...
+
+ adds out0\x16,sp // out0 = &sigscratch
br.call.sptk.few rp=ia64_rt_sigreturn
.ret13:
adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp
;;
ld8 r9=[r3] // load new ar.unat
- mov rp=r8
+ mov b7=r8
;;
PT_REGS_UNWIND_INFO
adds sp=IA64_SWITCH_STACK_SIZE,sp // drop (dummy) switch-stack frame
mov ar.unat=r9
- br rp
+ br b7
+#endif /* !CONFIG_IA64_NEW_UNWIND */
END(sys_rt_sigreturn)

GLOBAL_ENTRY(ia64_prepare_handle_unaligned)
diff -urN linux-davidm/arch/ia64/kernel/ia64_ksyms.c linux-2.4.0-test1-lia/arch/ia64/kernel/ia64_ksyms.c
--- linux-davidm/arch/ia64/kernel/ia64_ksyms.c Fri Jun 9 17:38:58 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/ia64_ksyms.c Fri Jun 9 17:10:26 2000
@@ -5,20 +5,15 @@
#include <linux/config.h>
#include <linux/module.h>

-#include <asm/processor.h>
-EXPORT_SYMBOL(cpu_data);
-EXPORT_SYMBOL(kernel_thread);
-
-#include <asm/uaccess.h>
-EXPORT_SYMBOL(__copy_user);
-
#include <linux/string.h>
-EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL_NOVERS(memset);
EXPORT_SYMBOL(memcmp);
-EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL_NOVERS(memcpy);
+EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(strcat);
EXPORT_SYMBOL(strchr);
EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strcpy);
EXPORT_SYMBOL(strlen);
EXPORT_SYMBOL(strncat);
EXPORT_SYMBOL(strncmp);
@@ -29,9 +24,41 @@
EXPORT_SYMBOL(pci_alloc_consistent);
EXPORT_SYMBOL(pci_free_consistent);

+#include <linux/in6.h>
+#include <asm/checksum.h>
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
+
#include <asm/irq.h>
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
+
+#include <asm/current.h>
+#include <asm/hardirq.h>
+EXPORT_SYMBOL(irq_stat);
+
+#include <asm/processor.h>
+EXPORT_SYMBOL(cpu_data);
+EXPORT_SYMBOL(kernel_thread);
+
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(synchronize_irq);
+
+#include <asm/smplock.h>
+EXPORT_SYMBOL(kernel_flag);
+
+#include <asm/system.h>
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
+
+#endif
+
+#include <asm/uaccess.h>
+EXPORT_SYMBOL(__copy_user);
+
+#include <asm/unistd.h>
+EXPORT_SYMBOL(__ia64_syscall);

/* from arch/ia64/lib */
extern void __divdi3(void);
diff -urN linux-davidm/arch/ia64/kernel/mca_asm.S linux-2.4.0-test1-lia/arch/ia64/kernel/mca_asm.S
--- linux-davidm/arch/ia64/kernel/mca_asm.S Fri Apr 21 15:21:24 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/mca_asm.S Fri Jun 9 17:23:02 2000
@@ -6,7 +6,6 @@
// 00/03/29 cfleck Added code to save INIT handoff state in pt_regs format, switch to temp kstack,
// switch modes, jump to C INIT handler
//
-#include <asm/offsets.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/mca_asm.h>
diff -urN linux-davidm/arch/ia64/kernel/pci.c linux-2.4.0-test1-lia/arch/ia64/kernel/pci.c
--- linux-davidm/arch/ia64/kernel/pci.c Fri Jun 9 17:38:58 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/pci.c Fri Jun 9 17:23:13 2000
@@ -197,7 +197,7 @@
ranges->mem_end -= bus->resource[1]->start;
}

-int __init
+int
pcibios_enable_device (struct pci_dev *dev)
{
/* Not needed, since we enable all devices at startup. */
diff -urN linux-davidm/arch/ia64/kernel/process.c linux-2.4.0-test1-lia/arch/ia64/kernel/process.c
--- linux-davidm/arch/ia64/kernel/process.c Fri Jun 9 17:38:58 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/process.c Fri Jun 9 17:23:40 2000
@@ -311,7 +311,12 @@
dst[12] = pt->r12; dst[13] = pt->r13; dst[14] = pt->r14; dst[15] = pt->r15;
memcpy(dst + 16, &pt->r16, 16*8); /* r16-r31 are contiguous */

+#ifdef CONFIG_IA64_NEW_UNWIND
+ printk("ia64_elf_core_copy_regs: fix me, please?");
+ dst[32] = 0;
+#else
dst[32] = ia64_get_nat_bits(pt, sw);
+#endif
dst[33] = pt->pr;

/* branch regs: */
@@ -332,6 +337,10 @@
struct switch_stack *sw = ((struct switch_stack *) pt) - 1;
struct task_struct *fpu_owner = ia64_get_fpu_owner();

+#ifdef CONFIG_IA64_NEW_UNWIND
+ printk("dump_fpu: fix me, please?");
+#endif
+
memset(dst, 0, sizeof (dst)); /* don't leak any "random" bits */

/* f0 is 0.0 */ /* f1 is 1.0 */ dst[2] = sw->f2; dst[3] = sw->f3;
@@ -440,7 +449,7 @@
do {
if (unw_unwind(&info) < 0)
return 0;
- ip = unw_get_ip(&info);
+ unw_get_ip(&info, &ip);
if (ip < first_sched || ip >= last_sched)
return ip;
} while (count++ < 16);
diff -urN linux-davidm/arch/ia64/kernel/ptrace.c linux-2.4.0-test1-lia/arch/ia64/kernel/ptrace.c
--- linux-davidm/arch/ia64/kernel/ptrace.c Fri Jun 9 17:38:58 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/ptrace.c Fri Jun 9 17:15:55 2000
@@ -33,6 +33,89 @@
#define IPSR_WRITE_MASK 0x000006a00100003eUL
#define IPSR_READ_MASK IPSR_WRITE_MASK

+#ifdef CONFIG_IA64_NEW_UNWIND
+
+#define PTRACE_DEBUG 1
+
+#if PTRACE_DEBUG
+# define dprintk(format...) printk(format)
+# define inline
+#else
+# define dprintk(format...)
+#endif
+
+static int
+unwind_to_user (struct unw_frame_info *info, struct task_struct *child)
+{
+ unsigned long ip;
+
+ unw_init_from_blocked_task(info, child);
+ while (unw_unwind(info) >= 0) {
+ if (unw_get_rp(info, &ip) < 0) {
+ unw_get_ip(info, &ip);
+ dprintk("ptrace: failed to read return pointer (ip=0x%lx)\n", ip);
+ return -1;
+ }
+ if (ip < TASK_SIZE)
+ return 0;
+ }
+ unw_get_ip(info, &ip);
+ dprintk("ptrace: failed to unwind to user-level (ip=0x%lx)\n", ip);
+ return -1;
+}
+
+/*
+ * Collect the NaT bits for r1-r31 from scratch_unat and return a NaT
+ * bitset where bit i is set iff the NaT bit of register i is set.
+ */
+unsigned long
+ia64_get_scratch_nat_bits (struct pt_regs *pt, unsigned long scratch_unat)
+{
+# define GET_BITS(first, last, unat) \
+ ({ \
+ unsigned long bit = ia64_unat_pos(&pt->r##first); \
+ unsigned long mask = ((1UL << (last - first + 1)) - 1) << first; \
+ (ia64_rotl(unat, first) >> bit) & mask; \
+ })
+ unsigned long val;
+
+ val = GET_BITS( 1, 3, scratch_unat);
+ val |= GET_BITS(12, 15, scratch_unat);
+ val |= GET_BITS( 8, 11, scratch_unat);
+ val |= GET_BITS(16, 31, scratch_unat);
+ return val;
+
+# undef GET_BITS
+}
+
+/*
+ * Set the NaT bits for the scratch registers according to NAT and
+ * return the resulting unat (assuming the scratch registers are
+ * stored in PT).
+ */
+unsigned long
+ia64_put_scratch_nat_bits (struct pt_regs *pt, unsigned long nat)
+{
+ unsigned long scratch_unat;
+
+# define PUT_BITS(first, last, nat) \
+ ({ \
+ unsigned long bit = ia64_unat_pos(&pt->r##first); \
+ unsigned long mask = ((1UL << (last - first + 1)) - 1) << bit; \
+ (ia64_rotr(nat, first) << bit) & mask; \
+ })
+ scratch_unat = PUT_BITS( 1, 3, nat);
+ scratch_unat |= PUT_BITS(12, 15, nat);
+ scratch_unat |= PUT_BITS( 8, 11, nat);
+ scratch_unat |= PUT_BITS(16, 31, nat);
+
+ return scratch_unat;
+
+# undef PUT_BITS
+}
+
+#else /* !CONFIG_IA64_NEW_UNWIND */
+
/*
* Collect the NaT bits for r1-r31 from sw->caller_unat and
* sw->ar_unat and return a NaT bitset where bit i is set iff the NaT
@@ -80,28 +163,26 @@
# undef PUT_BITS
}

-#define IA64_MLI_TEMPLATE 0x2
+#endif /* !CONFIG_IA64_NEW_UNWIND */
+
+#define IA64_MLX_TEMPLATE 0x2
#define IA64_MOVL_OPCODE 6

void
ia64_increment_ip (struct pt_regs *regs)
{
- unsigned long w0, w1, ri = ia64_psr(regs)->ri + 1;
+ unsigned long w0, ri = ia64_psr(regs)->ri + 1;

if (ri > 2) {
ri = 0;
regs->cr_iip += 16;
} else if (ri = 2) {
get_user(w0, (char *) regs->cr_iip + 0);
- get_user(w1, (char *) regs->cr_iip + 8);
- if (((w0 >> 1) & 0xf) = IA64_MLI_TEMPLATE && (w1 >> 60) = IA64_MOVL_OPCODE) {
+ if (((w0 >> 1) & 0xf) = IA64_MLX_TEMPLATE) {
/*
- * rfi'ing to slot 2 of an MLI bundle causes
+ * rfi'ing to slot 2 of an MLX bundle causes
* an illegal operation fault. We don't want
- * that to happen... Note that we check the
- * opcode only. "movl" has a vc bit of 0, but
- * since a vc bit of 1 is currently reserved,
- * we might just as well treat it like a movl.
+ * that to happen...
*/
ri = 0;
regs->cr_iip += 16;
@@ -113,21 +194,17 @@
void
ia64_decrement_ip (struct pt_regs *regs)
{
- unsigned long w0, w1, ri = ia64_psr(regs)->ri - 1;
+ unsigned long w0, ri = ia64_psr(regs)->ri - 1;

if (ia64_psr(regs)->ri = 0) {
regs->cr_iip -= 16;
ri = 2;
get_user(w0, (char *) regs->cr_iip + 0);
- get_user(w1, (char *) regs->cr_iip + 8);
- if (((w0 >> 1) & 0xf) = IA64_MLI_TEMPLATE && (w1 >> 60) = IA64_MOVL_OPCODE) {
+ if (((w0 >> 1) & 0xf) = IA64_MLX_TEMPLATE) {
/*
- * rfi'ing to slot 2 of an MLI bundle causes
+ * rfi'ing to slot 2 of an MLX bundle causes
* an illegal operation fault. We don't want
- * that to happen... Note that we check the
- * opcode only. "movl" has a vc bit of 0, but
- * since a vc bit of 1 is currently reserved,
- * we might just as well treat it like a movl.
+ * that to happen...
*/
ri = 1;
}
@@ -292,7 +369,11 @@

laddr = (unsigned long *) addr;
child_regs = ia64_task_regs(child);
+#ifdef CONFIG_IA64_NEW_UNWIND
+ child_stack = (struct switch_stack *) (child->thread.ksp + 16);
+#else
child_stack = (struct switch_stack *) child_regs - 1;
+#endif
bspstore = (unsigned long *) child_regs->ar_bspstore;
krbs = (unsigned long *) child + IA64_RBS_OFFSET/8;
krbs_num_regs = ia64_rse_num_regs(krbs, (unsigned long *) child_stack->ar_bspstore);
@@ -336,7 +417,11 @@

laddr = (unsigned long *) addr;
child_regs = ia64_task_regs(child);
+#ifdef CONFIG_IA64_NEW_UNWIND
+ child_stack = (struct switch_stack *) (child->thread.ksp + 16);
+#else
child_stack = (struct switch_stack *) child_regs - 1;
+#endif
bspstore = (unsigned long *) child_regs->ar_bspstore;
krbs = (unsigned long *) child + IA64_RBS_OFFSET/8;
krbs_num_regs = ia64_rse_num_regs(krbs, (unsigned long *) child_stack->ar_bspstore);
@@ -395,21 +480,42 @@
long new_bsp,
int force_loadrs_to_zero)
{
- unsigned long *krbs, bspstore, bsp, krbs_num_regs, rbs_end, addr, val;
- long ndirty, ret;
- struct pt_regs *child_regs;
+ unsigned long *krbs, bspstore, *kbspstore, bsp, rbs_end, addr, val;
+ long ndirty, ret = 0;
+ struct pt_regs *child_regs = ia64_task_regs(child);
+
+#ifdef CONFIG_IA64_NEW_UNWIND
+ struct unw_frame_info info;
+ unsigned long cfm, sof;
+
+ if (unwind_to_user(&info, child) < 0)
+ return -1;
+
+ unw_get_bsp(&info, (unsigned long *) &kbspstore);
+
+ krbs = (unsigned long *) child + IA64_RBS_OFFSET/8;
+ ndirty = ia64_rse_num_regs(krbs, krbs + (child_regs->loadrs >> 19));
+ bspstore = child_regs->ar_bspstore;
+ bsp = (long) ia64_rse_skip_regs((long *)bspstore, ndirty);
+
+ cfm = child_regs->cr_ifs;
+ if (!(cfm & (1UL << 63)))
+ unw_get_cfm(&info, &cfm);
+ sof = (cfm & 0x7f);
+ rbs_end = (long) ia64_rse_skip_regs((long *)bspstore, sof);
+#else
struct switch_stack *child_stack;
+ unsigned long krbs_num_regs;

- ret = 0;
- child_regs = ia64_task_regs(child);
child_stack = (struct switch_stack *) child_regs - 1;
-
+ kbspstore = (unsigned long *) child_stack->ar_bspstore;
krbs = (unsigned long *) child + IA64_RBS_OFFSET/8;
ndirty = ia64_rse_num_regs(krbs, krbs + (child_regs->loadrs >> 19));
bspstore = child_regs->ar_bspstore;
bsp = (long) ia64_rse_skip_regs((long *)bspstore, ndirty);
- krbs_num_regs = ia64_rse_num_regs(krbs, (unsigned long *) child_stack->ar_bspstore);
+ krbs_num_regs = ia64_rse_num_regs(krbs, kbspstore);
rbs_end = (long) ia64_rse_skip_regs((long *)bspstore, krbs_num_regs);
+#endif

/* Return early if nothing to do */
if (bsp = new_bsp)
@@ -438,13 +544,15 @@
}

static void
-sync_thread_rbs (struct task_struct *child, int make_writable)
+sync_thread_rbs (struct task_struct *child, struct mm_struct *mm, int make_writable)
{
struct task_struct *p;
read_lock(&tasklist_lock);
- for_each_task(p) {
- if (p->mm = child->mm && p->state != TASK_RUNNING)
- sync_kernel_register_backing_store(p, 0, make_writable);
+ {
+ for_each_task(p) {
+ if (p->mm = mm && p->state != TASK_RUNNING)
+ sync_kernel_register_backing_store(p, 0, make_writable);
+ }
}
read_unlock(&tasklist_lock);
child->thread.flags |= IA64_THREAD_KRBS_SYNCED;
@@ -466,6 +574,234 @@
}
}

+#ifdef CONFIG_IA64_NEW_UNWIND
+
+#include <asm/unwind.h>
+
+static int
+access_fr (struct unw_frame_info *info, int regnum, int hi, unsigned long *data, int write_access)
+{
+ struct ia64_fpreg fpval;
+ int ret;
+
+ ret = unw_get_fr(info, regnum, &fpval);
+ if (ret < 0)
+ return ret;
+
+ if (write_access) {
+ fpval.u.bits[hi] = *data;
+ ret = unw_set_fr(info, regnum, fpval);
+ } else
+ *data = fpval.u.bits[hi];
+ return ret;
+}
+
+static int
+access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data, int write_access)
+{
+ unsigned long *ptr, *rbs, *bspstore, ndirty, regnum;
+ struct switch_stack *sw;
+ struct unw_frame_info info;
+ struct pt_regs *pt;
+
+ pt = ia64_task_regs(child);
+ sw = (struct switch_stack *) (child->thread.ksp + 16);
+
+ if ((addr & 0x7) != 0) {
+ dprintk("ptrace: unaligned register address 0x%lx\n", addr);
+ return -1;
+ }
+
+ if (addr < PT_F127 + 16) {
+ /* accessing fph */
+ sync_fph(child);
+ ptr = (unsigned long *) ((unsigned long) &child->thread.fph + addr);
+ } else if (addr >= PT_F10 && addr < PT_F15 + 16) {
+ /* scratch registers untouched by kernel (saved in switch_stack) */
+ ptr = (unsigned long *) ((long) sw + addr - PT_NAT_BITS);
+ } else if (addr < PT_AR_LC + 8) {
+ /* preserved state: */
+ unsigned long nat_bits, scratch_unat, dummy = 0;
+ struct unw_frame_info info;
+ char nat = 0;
+ int ret;
+
+ if (unwind_to_user(&info, child) < 0)
+ return -1;
+
+ switch (addr) {
+ case PT_NAT_BITS:
+ if (write_access) {
+ nat_bits = *data;
+ scratch_unat = ia64_put_scratch_nat_bits(pt, nat_bits);
+ if (unw_set_ar(&info, UNW_AR_UNAT, scratch_unat) < 0) {
+ dprintk("ptrace: failed to set ar.unat\n");
+ return -1;
+ }
+ for (regnum = 4; regnum <= 7; ++regnum) {
+ unw_get_gr(&info, regnum, &dummy, &nat);
+ unw_set_gr(&info, regnum, dummy, (nat_bits >> regnum) & 1);
+ }
+ } else {
+ if (unw_get_ar(&info, UNW_AR_UNAT, &scratch_unat) < 0) {
+ dprintk("ptrace: failed to read ar.unat\n");
+ return -1;
+ }
+ nat_bits = ia64_get_scratch_nat_bits(pt, scratch_unat);
+ for (regnum = 4; regnum <= 7; ++regnum) {
+ unw_get_gr(&info, regnum, &dummy, &nat);
+ nat_bits |= (nat != 0) << regnum;
+ }
+ *data = nat_bits;
+ }
+ return 0;
+
+ case PT_R4: case PT_R5: case PT_R6: case PT_R7:
+ if (write_access) {
+ /* read NaT bit first: */
+ ret = unw_get_gr(&info, (addr - PT_R4)/8 + 4, data, &nat);
+ if (ret < 0)
+ return ret;
+ }
+ return unw_access_gr(&info, (addr - PT_R4)/8 + 4, data, &nat,
+ write_access);
+
+ case PT_B1: case PT_B2: case PT_B3: case PT_B4: case PT_B5:
+ return unw_access_br(&info, (addr - PT_B1)/8 + 1, data, write_access);
+
+ case PT_AR_LC:
+ return unw_access_ar(&info, UNW_AR_LC, data, write_access);
+
+ default:
+ if (addr >= PT_F2 && addr < PT_F5 + 16)
+ return access_fr(&info, (addr - PT_F2)/16 + 2, (addr & 8) != 0,
+ data, write_access);
+ else if (addr >= PT_F16 && addr < PT_F31 + 16)
+ return access_fr(&info, (addr - PT_F16)/16 + 16, (addr & 8) != 0,
+ data, write_access);
+ else {
+ dprintk("ptrace: rejecting access to register address 0x%lx\n",
+ addr);
+ return -1;
+ }
+ }
+ } else if (addr < PT_F9+16) {
+ /* scratch state */
+ switch (addr) {
+ case PT_AR_BSP:
+ if (write_access)
+ /* FIXME? Account for lack of ``cover'' in the syscall case */
+ return sync_kernel_register_backing_store(child, *data, 1);
+ else {
+ rbs = (unsigned long *) child + IA64_RBS_OFFSET/8;
+ bspstore = (unsigned long *) pt->ar_bspstore;
+ ndirty = ia64_rse_num_regs(rbs, rbs + (pt->loadrs >> 19));
+
+ /*
+ * If we're in a system call, no ``cover'' was done. So to
+ * make things uniform, we'll add the appropriate displacement
+ * onto bsp if we're in a system call.
+ */
+ if (!(pt->cr_ifs & (1UL << 63))) {
+ struct unw_frame_info info;
+ unsigned long cfm;
+
+ if (unwind_to_user(&info, child) < 0)
+ return -1;
+
+ unw_get_cfm(&info, &cfm);
+ ndirty += cfm & 0x7f;
+ }
+ *data = (unsigned long) ia64_rse_skip_regs(bspstore, ndirty);
+ return 0;
+ }
+
+ case PT_CFM:
+ if (pt->cr_ifs & (1UL << 63)) {
+ if (write_access)
+ pt->cr_ifs = ((pt->cr_ifs & ~0x3fffffffffUL)
+ | (*data & 0x3fffffffffUL));
+ else
+ *data = pt->cr_ifs & 0x3fffffffffUL;
+ } else {
+ /* kernel was entered through a system call */
+ unsigned long cfm;
+
+ if (unwind_to_user(&info, child) < 0)
+ return -1;
+
+ unw_get_cfm(&info, &cfm);
+ if (write_access)
+ unw_set_cfm(&info, ((cfm & ~0x3fffffffffU)
+ | (*data & 0x3fffffffffUL)));
+ else
+ *data = cfm;
+ }
+ return 0;
+
+ case PT_CR_IPSR:
+ if (write_access)
+ pt->cr_ipsr = ((*data & IPSR_WRITE_MASK)
+ | (pt->cr_ipsr & ~IPSR_WRITE_MASK));
+ else
+ *data = (pt->cr_ipsr & IPSR_READ_MASK);
+ return 0;
+
+ case PT_R1: case PT_R2: case PT_R3:
+ case PT_R8: case PT_R9: case PT_R10: case PT_R11:
+ case PT_R12: case PT_R13: case PT_R14: case PT_R15:
+ case PT_R16: case PT_R17: case PT_R18: case PT_R19:
+ case PT_R20: case PT_R21: case PT_R22: case PT_R23:
+ case PT_R24: case PT_R25: case PT_R26: case PT_R27:
+ case PT_R28: case PT_R29: case PT_R30: case PT_R31:
+ case PT_B0: case PT_B6: case PT_B7:
+ case PT_F6: case PT_F6+8: case PT_F7: case PT_F7+8:
+ case PT_F8: case PT_F8+8: case PT_F9: case PT_F9+8:
+ case PT_AR_BSPSTORE:
+ case PT_AR_RSC: case PT_AR_UNAT: case PT_AR_PFS: case PT_AR_RNAT:
+ case PT_AR_CCV: case PT_AR_FPSR: case PT_CR_IIP: case PT_PR:
+ /* scratch register */
+ ptr = (unsigned long *) ((long) pt + addr - PT_CR_IPSR);
+ break;
+
+ default:
+ /* disallow accessing anything else... */
+ dprintk("ptrace: rejecting access to register address 0x%lx\n",
+ addr);
+ return -1;
+ }
+ } else {
+ /* access debug registers */
+
+ if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) {
+ child->thread.flags |= IA64_THREAD_DBG_VALID;
+ memset(child->thread.dbr, 0, sizeof(child->thread.dbr));
+ memset(child->thread.ibr, 0, sizeof( child->thread.ibr));
+ }
+ if (addr >= PT_IBR) {
+ regnum = (addr - PT_IBR) >> 3;
+ ptr = &child->thread.ibr[0];
+ } else {
+ regnum = (addr - PT_DBR) >> 3;
+ ptr = &child->thread.dbr[0];
+ }
+
+ if (regnum >= 8) {
+ dprintk("ptrace: rejecting access to register address 0x%lx\n", addr);
+ return -1;
+ }
+
+ ptr += regnum;
+ }
+ if (write_access)
+ *ptr = *data;
+ else
+ *data = *ptr;
+ return 0;
+}
+
+#else /* !CONFIG_IA64_NEW_UNWIND */
+
static int
access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data, int write_access)
{
@@ -486,6 +822,13 @@
sw = (struct switch_stack *) pt - 1;

switch (addr) {
+ case PT_NAT_BITS:
+ if (write_access)
+ ia64_put_nat_bits(pt, sw, *data);
+ else
+ *data = ia64_get_nat_bits(pt, sw);
+ return 0;
+
case PT_AR_BSP:
if (write_access)
/* FIXME? Account for lack of ``cover'' in the syscall case */
@@ -508,9 +851,6 @@

case PT_CFM:
if (write_access) {
- pt = ia64_task_regs(child);
- sw = (struct switch_stack *) pt - 1;
-
if (pt->cr_ifs & (1UL << 63))
pt->cr_ifs = ((pt->cr_ifs & ~0x3fffffffffUL)
| (*data & 0x3fffffffffUL));
@@ -545,18 +885,26 @@
case PT_R28: case PT_R29: case PT_R30: case PT_R31:
case PT_B0: case PT_B1: case PT_B2: case PT_B3:
case PT_B4: case PT_B5: case PT_B6: case PT_B7:
- case PT_F2: case PT_F3:
- case PT_F4: case PT_F5: case PT_F6: case PT_F7:
- case PT_F8: case PT_F9: case PT_F10: case PT_F11:
- case PT_F12: case PT_F13: case PT_F14: case PT_F15:
- case PT_F16: case PT_F17: case PT_F18: case PT_F19:
- case PT_F20: case PT_F21: case PT_F22: case PT_F23:
- case PT_F24: case PT_F25: case PT_F26: case PT_F27:
- case PT_F28: case PT_F29: case PT_F30: case PT_F31:
- case PT_AR_LC: case PT_AR_UNAT: case PT_AR_PFS: case PT_AR_RNAT:
- case PT_AR_CCV: case PT_AR_FPSR:
- case PT_CR_IIP: case PT_PR:
- ptr = (unsigned long *) ((long) sw + addr - PT_PRI_UNAT);
+ case PT_F2: case PT_F2+8: case PT_F3: case PT_F3+8:
+ case PT_F4: case PT_F4+8: case PT_F5: case PT_F5+8:
+ case PT_F6: case PT_F6+8: case PT_F7: case PT_F7+8:
+ case PT_F8: case PT_F8+8: case PT_F9: case PT_F9+8:
+ case PT_F10: case PT_F10+8: case PT_F11: case PT_F11+8:
+ case PT_F12: case PT_F12+8: case PT_F13: case PT_F13+8:
+ case PT_F14: case PT_F14+8: case PT_F15: case PT_F15+8:
+ case PT_F16: case PT_F16+8: case PT_F17: case PT_F17+8:
+ case PT_F18: case PT_F18+8: case PT_F19: case PT_F19+8:
+ case PT_F20: case PT_F20+8: case PT_F21: case PT_F21+8:
+ case PT_F22: case PT_F22+8: case PT_F23: case PT_F23+8:
+ case PT_F24: case PT_F24+8: case PT_F25: case PT_F25+8:
+ case PT_F26: case PT_F26+8: case PT_F27: case PT_F27+8:
+ case PT_F28: case PT_F28+8: case PT_F29: case PT_F29+8:
+ case PT_F30: case PT_F30+8: case PT_F31: case PT_F31+8:
+ case PT_AR_BSPSTORE:
+ case PT_AR_RSC: case PT_AR_UNAT: case PT_AR_PFS: case PT_AR_RNAT:
+ case PT_AR_CCV: case PT_AR_FPSR: case PT_CR_IIP: case PT_PR:
+ case PT_AR_LC:
+ ptr = (unsigned long *) ((long) sw + addr - PT_NAT_BITS);
break;

default:
@@ -591,6 +939,8 @@
return 0;
}

+#endif /* !CONFIG_IA64_NEW_UNWIND */
+
asmlinkage long
sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data,
long arg4, long arg5, long arg6, long arg7, long stack)
@@ -613,17 +963,21 @@

ret = -ESRCH;
read_lock(&tasklist_lock);
- child = find_task_by_pid(pid);
+ {
+ child = find_task_by_pid(pid);
+ if (child)
+ get_task_struct(child);
+ }
read_unlock(&tasklist_lock);
if (!child)
goto out;
ret = -EPERM;
if (pid = 1) /* no messing around with init! */
- goto out;
+ goto out_tsk;

if (request = PTRACE_ATTACH) {
if (child = current)
- goto out;
+ goto out_tsk;
if ((!child->dumpable ||
(current->uid != child->euid) ||
(current->uid != child->suid) ||
@@ -632,10 +986,10 @@
(current->gid != child->sgid) ||
(!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
(current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
- goto out;
+ goto out_tsk;
/* the same process cannot be attached many times */
if (child->flags & PF_PTRACED)
- goto out;
+ goto out_tsk;
child->flags |= PF_PTRACED;
if (child->p_pptr != current) {
unsigned long flags;
@@ -648,78 +1002,98 @@
}
send_sig(SIGSTOP, child, 1);
ret = 0;
- goto out;
+ goto out_tsk;
}
ret = -ESRCH;
if (!(child->flags & PF_PTRACED))
- goto out;
+ goto out_tsk;
if (child->state != TASK_STOPPED) {
if (request != PTRACE_KILL)
- goto out;
+ goto out_tsk;
}
if (child->p_pptr != current)
- goto out;
+ goto out_tsk;

switch (request) {
case PTRACE_PEEKTEXT:
case PTRACE_PEEKDATA: /* read word at location addr */
- if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)
- && atomic_read(&child->mm->mm_users) > 1)
- sync_thread_rbs(child, 0);
+ if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) {
+ struct mm_struct *mm;
+ long do_sync;
+
+ task_lock(child);
+ {
+ mm = child->mm;
+ do_sync = mm && (atomic_read(&mm->mm_users) > 1);
+ }
+ task_unlock(child);
+ if (do_sync)
+ sync_thread_rbs(child, mm, 0);
+ }
ret = ia64_peek(regs, child, addr, &data);
if (ret = 0) {
ret = data;
regs->r8 = 0; /* ensure "ret" is not mistaken as an error code */
}
- goto out;
+ goto out_tsk;

case PTRACE_POKETEXT:
case PTRACE_POKEDATA: /* write the word at location addr */
- if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)
- && atomic_read(&child->mm->mm_users) > 1)
- sync_thread_rbs(child, 1);
+ if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) {
+ struct mm_struct *mm;
+ long do_sync;
+
+ task_lock(child);
+ {
+ mm = child->mm;
+ do_sync = mm && (atomic_read(&child->mm->mm_users) > 1);
+ }
+ task_unlock(child);
+ if (do_sync)
+ sync_thread_rbs(child, mm, 1);
+ }
ret = ia64_poke(regs, child, addr, data);
- goto out;
+ goto out_tsk;

case PTRACE_PEEKUSR: /* read the word at addr in the USER area */
if (access_uarea(child, addr, &data, 0) < 0) {
ret = -EIO;
- goto out;
+ goto out_tsk;
}
ret = data;
regs->r8 = 0; /* ensure "ret" is not mistaken as an error code */
- goto out;
+ goto out_tsk;

case PTRACE_POKEUSR: /* write the word at addr in the USER area */
if (access_uarea(child, addr, &data, 1) < 0) {
ret = -EIO;
- goto out;
+ goto out_tsk;
}
ret = 0;
- goto out;
+ goto out_tsk;

case PTRACE_GETSIGINFO:
ret = -EIO;
if (!access_ok(VERIFY_WRITE, data, sizeof (siginfo_t))
|| child->thread.siginfo = 0)
- goto out;
+ goto out_tsk;
copy_to_user((siginfo_t *) data, child->thread.siginfo, sizeof (siginfo_t));
ret = 0;
- goto out;
+ goto out_tsk;
break;
case PTRACE_SETSIGINFO:
ret = -EIO;
if (!access_ok(VERIFY_READ, data, sizeof (siginfo_t))
|| child->thread.siginfo = 0)
- goto out;
+ goto out_tsk;
copy_from_user(child->thread.siginfo, (siginfo_t *) data, sizeof (siginfo_t));
ret = 0;
- goto out;
+ goto out_tsk;
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
case PTRACE_CONT: /* restart after signal. */
ret = -EIO;
if (data > _NSIG)
- goto out;
+ goto out_tsk;
if (request = PTRACE_SYSCALL)
child->flags |= PF_TRACESYS;
else
@@ -735,7 +1109,7 @@

wake_up_process(child);
ret = 0;
- goto out;
+ goto out_tsk;

case PTRACE_KILL:
/*
@@ -744,7 +1118,7 @@
* that it wants to exit.
*/
if (child->state = TASK_ZOMBIE) /* already dead */
- goto out;
+ goto out_tsk;
child->exit_code = SIGKILL;

/* make sure the single step/take-branch tra bits are not set: */
@@ -756,13 +1130,13 @@

wake_up_process(child);
ret = 0;
- goto out;
+ goto out_tsk;

case PTRACE_SINGLESTEP: /* let child execute for one instruction */
case PTRACE_SINGLEBLOCK:
ret = -EIO;
if (data > _NSIG)
- goto out;
+ goto out_tsk;

child->flags &= ~PF_TRACESYS;
if (request = PTRACE_SINGLESTEP) {
@@ -778,12 +1152,12 @@
/* give it a chance to run. */
wake_up_process(child);
ret = 0;
- goto out;
+ goto out_tsk;

case PTRACE_DETACH: /* detach a process that was attached. */
ret = -EIO;
if (data > _NSIG)
- goto out;
+ goto out_tsk;

child->flags &= ~(PF_PTRACED|PF_TRACESYS);
child->exit_code = data;
@@ -802,12 +1176,14 @@

wake_up_process(child);
ret = 0;
- goto out;
+ goto out_tsk;

default:
ret = -EIO;
- goto out;
+ goto out_tsk;
}
+ out_tsk:
+ free_task_struct(child);
out:
unlock_kernel();
return ret;
diff -urN linux-davidm/arch/ia64/kernel/setup.c linux-2.4.0-test1-lia/arch/ia64/kernel/setup.c
--- linux-davidm/arch/ia64/kernel/setup.c Fri Jun 9 17:38:58 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/setup.c Fri Jun 9 17:16:12 2000
@@ -36,6 +36,10 @@
#include <asm/efi.h>
#include <asm/mca.h>

+#ifdef CONFIG_BLK_DEV_RAM
+# include <linux/blk.h>
+#endif
+
extern char _end;

/* cpu_data[bootstrap_processor] is data for the bootstrap processor: */
@@ -127,11 +131,22 @@
* change APIs, they'd do things for the better. Grumble...
*/
bootmap_start = PAGE_ALIGN(__pa(&_end));
+ if (ia64_boot_param.initrd_size)
+ bootmap_start = PAGE_ALIGN(bootmap_start + ia64_boot_param.initrd_size);
bootmap_size = init_bootmem(bootmap_start >> PAGE_SHIFT, max_pfn);

efi_memmap_walk(free_available_memory, 0);

reserve_bootmem(bootmap_start, bootmap_size);
+#ifdef CONFIG_BLK_DEV_INITRD
+ initrd_start = ia64_boot_param.initrd_start;
+ if (initrd_start) {
+ initrd_end = initrd_start+ia64_boot_param.initrd_size;
+ printk("Initial ramdisk at: 0x%p (%lu bytes)\n",
+ (void *) initrd_start, ia64_boot_param.initrd_size);
+ reserve_bootmem(virt_to_phys(initrd_start), ia64_boot_param.initrd_size);
+ }
+#endif
#if 0
/* XXX fix me */
init_mm.start_code = (unsigned long) &_stext;
diff -urN linux-davidm/arch/ia64/kernel/signal.c linux-2.4.0-test1-lia/arch/ia64/kernel/signal.c
--- linux-davidm/arch/ia64/kernel/signal.c Fri Jun 9 17:38:58 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/signal.c Fri Jun 9 17:16:43 2000
@@ -37,16 +37,26 @@
# define GET_SIGSET(k,u) __get_user((k)->sig[0], &(u)->sig[0])
#endif

+struct sigscratch {
+#ifdef CONFIG_IA64_NEW_UNWIND
+ unsigned long scratch_unat; /* ar.unat for the general registers saved in pt */
+ unsigned long pad;
+#else
+ struct switch_stack sw;
+#endif
+ struct pt_regs pt;
+};
+
struct sigframe {
struct siginfo info;
struct sigcontext sc;
};

extern long sys_wait4 (int, int *, int, struct rusage *);
-extern long ia64_do_signal (sigset_t *, struct pt_regs *, long); /* forward decl */
+extern long ia64_do_signal (sigset_t *, struct sigscratch *, long); /* forward decl */

long
-ia64_rt_sigsuspend (sigset_t *uset, size_t sigsetsize, struct pt_regs *pt)
+ia64_rt_sigsuspend (sigset_t *uset, size_t sigsetsize, struct sigscratch *scr)
{
sigset_t oldset, set;

@@ -72,18 +82,18 @@
* get saved in sigcontext by ia64_do_signal.
*/
#ifdef CONFIG_IA32_SUPPORT
- if (IS_IA32_PROCESS(pt)) {
- pt->r8 = -EINTR;
+ if (IS_IA32_PROCESS(&scr->pt)) {
+ scr->pt.r8 = -EINTR;
} else
#endif
{
- pt->r8 = EINTR;
- pt->r10 = -1;
+ scr->pt.r8 = EINTR;
+ scr->pt.r10 = -1;
}
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
schedule();
- if (ia64_do_signal(&oldset, pt, 1))
+ if (ia64_do_signal(&oldset, scr, 1))
return -EINTR;
}
}
@@ -98,9 +108,8 @@
}

static long
-restore_sigcontext (struct sigcontext *sc, struct pt_regs *pt)
+restore_sigcontext (struct sigcontext *sc, struct sigscratch *scr)
{
- struct switch_stack *sw = (struct switch_stack *) pt - 1;
unsigned long ip, flags, nat, um, cfm;
long err;

@@ -111,28 +120,32 @@
err |= __get_user(ip, &sc->sc_ip); /* instruction pointer */
err |= __get_user(cfm, &sc->sc_cfm);
err |= __get_user(um, &sc->sc_um); /* user mask */
- err |= __get_user(pt->ar_rsc, &sc->sc_ar_rsc);
- err |= __get_user(pt->ar_ccv, &sc->sc_ar_ccv);
- err |= __get_user(pt->ar_unat, &sc->sc_ar_unat);
- err |= __get_user(pt->ar_fpsr, &sc->sc_ar_fpsr);
- err |= __get_user(pt->ar_pfs, &sc->sc_ar_pfs);
- err |= __get_user(pt->pr, &sc->sc_pr); /* predicates */
- err |= __get_user(pt->b0, &sc->sc_br[0]); /* b0 (rp) */
- err |= __get_user(pt->b6, &sc->sc_br[6]); /* b6 */
- err |= __get_user(pt->b7, &sc->sc_br[7]); /* b7 */
- err |= __copy_from_user(&pt->r1, &sc->sc_gr[1], 3*8); /* r1-r3 */
- err |= __copy_from_user(&pt->r8, &sc->sc_gr[8], 4*8); /* r8-r11 */
- err |= __copy_from_user(&pt->r12, &sc->sc_gr[12], 4*8); /* r12-r15 */
- err |= __copy_from_user(&pt->r16, &sc->sc_gr[16], 16*8); /* r16-r31 */
+ err |= __get_user(scr->pt.ar_rsc, &sc->sc_ar_rsc);
+ err |= __get_user(scr->pt.ar_ccv, &sc->sc_ar_ccv);
+ err |= __get_user(scr->pt.ar_unat, &sc->sc_ar_unat);
+ err |= __get_user(scr->pt.ar_fpsr, &sc->sc_ar_fpsr);
+ err |= __get_user(scr->pt.ar_pfs, &sc->sc_ar_pfs);
+ err |= __get_user(scr->pt.pr, &sc->sc_pr); /* predicates */
+ err |= __get_user(scr->pt.b0, &sc->sc_br[0]); /* b0 (rp) */
+ err |= __get_user(scr->pt.b6, &sc->sc_br[6]); /* b6 */
+ err |= __get_user(scr->pt.b7, &sc->sc_br[7]); /* b7 */
+ err |= __copy_from_user(&scr->pt.r1, &sc->sc_gr[1], 3*8); /* r1-r3 */
+ err |= __copy_from_user(&scr->pt.r8, &sc->sc_gr[8], 4*8); /* r8-r11 */
+ err |= __copy_from_user(&scr->pt.r12, &sc->sc_gr[12], 4*8); /* r12-r15 */
+ err |= __copy_from_user(&scr->pt.r16, &sc->sc_gr[16], 16*8); /* r16-r31 */

- pt->cr_ifs = cfm | (1UL << 63);
+ scr->pt.cr_ifs = cfm | (1UL << 63);

/* establish new instruction pointer: */
- pt->cr_iip = ip & ~0x3UL;
- ia64_psr(pt)->ri = ip & 0x3;
- pt->cr_ipsr = (pt->cr_ipsr & ~IA64_PSR_UM) | (um & IA64_PSR_UM);
-
- ia64_put_nat_bits (pt, sw, nat); /* restore the original scratch NaT bits */
+ scr->pt.cr_iip = ip & ~0x3UL;
+ ia64_psr(&scr->pt)->ri = ip & 0x3;
+ scr->pt.cr_ipsr = (scr->pt.cr_ipsr & ~IA64_PSR_UM) | (um & IA64_PSR_UM);
+
+#ifdef CONFIG_IA64_NEW_UNWIND
+ scr->scratch_unat = ia64_put_scratch_nat_bits(&scr->pt, nat);
+#else
+ ia64_put_nat_bits(&scr->pt, &scr->sw, nat); /* restore the original scratch NaT bits */
+#endif

if (flags & IA64_SC_FLAG_FPH_VALID) {
struct task_struct *fpu_owner = ia64_get_fpu_owner();
@@ -186,15 +199,8 @@
}
}

-/*
- * When we get here, ((struct switch_stack *) pt - 1) is a
- * switch_stack frame that has no defined value. Upon return, we
- * expect sw->caller_unat to contain the new unat value. The reason
- * we use a full switch_stack frame is so everything is symmetric
- * with ia64_do_signal().
- */
long
-ia64_rt_sigreturn (struct pt_regs *pt)
+ia64_rt_sigreturn (struct sigscratch *scr)
{
extern char ia64_strace_leave_kernel, ia64_leave_kernel;
struct sigcontext *sc;
@@ -202,7 +208,7 @@
sigset_t set;
long retval;

- sc = &((struct sigframe *) (pt->r12 + 16))->sc;
+ sc = &((struct sigframe *) (scr->pt.r12 + 16))->sc;

/*
* When we return to the previously executing context, r8 and
@@ -234,18 +240,18 @@
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);

- if (restore_sigcontext(sc, pt))
+ if (restore_sigcontext(sc, scr))
goto give_sigsegv;

#if DEBUG_SIG
printk("SIG return (%s:%d): sp=%lx ip=%lx\n",
- current->comm, current->pid, pt->r12, pt->cr_iip);
+ current->comm, current->pid, scr->pt.r12, scr->pt.cr_iip);
#endif
/*
* It is more difficult to avoid calling this function than to
* call it and ignore errors.
*/
- do_sigaltstack(&sc->sc_stack, 0, pt->r12);
+ do_sigaltstack(&sc->sc_stack, 0, scr->pt.r12);
return retval;

give_sigsegv:
@@ -266,14 +272,13 @@
* trampoline starts. Everything else is done at the user-level.
*/
static long
-setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct pt_regs *pt)
+setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct sigscratch *scr)
{
- struct switch_stack *sw = (struct switch_stack *) pt - 1;
struct task_struct *fpu_owner = ia64_get_fpu_owner();
unsigned long flags = 0, ifs, nat;
long err;

- ifs = pt->cr_ifs;
+ ifs = scr->pt.cr_ifs;

if (on_sig_stack((unsigned long) sc))
flags |= IA64_SC_FLAG_ONSTACK;
@@ -293,46 +298,49 @@
* Note: sw->ar_unat is UNDEFINED unless the process is being
* PTRACED. However, this is OK because the NaT bits of the
* preserved registers (r4-r7) are never being looked at by
- * the signal handler (register r4-r7 are used instead).
+ * the signal handler (registers r4-r7 are used instead).
*/
- nat = ia64_get_nat_bits(pt, sw);
+#ifdef CONFIG_IA64_NEW_UNWIND
+ nat = ia64_get_scratch_nat_bits(&scr->pt, scr->scratch_unat);
+#else
+ nat = ia64_get_nat_bits(&scr->pt, &scr->sw);
+#endif

err = __put_user(flags, &sc->sc_flags);

err |= __put_user(nat, &sc->sc_nat);
err |= PUT_SIGSET(mask, &sc->sc_mask);
- err |= __put_user(pt->cr_ipsr & IA64_PSR_UM, &sc->sc_um);
- err |= __put_user(pt->ar_rsc, &sc->sc_ar_rsc);
- err |= __put_user(pt->ar_ccv, &sc->sc_ar_ccv);
- err |= __put_user(pt->ar_unat, &sc->sc_ar_unat); /* ar.unat */
- err |= __put_user(pt->ar_fpsr, &sc->sc_ar_fpsr); /* ar.fpsr */
- err |= __put_user(pt->ar_pfs, &sc->sc_ar_pfs);
- err |= __put_user(pt->pr, &sc->sc_pr); /* predicates */
- err |= __put_user(pt->b0, &sc->sc_br[0]); /* b0 (rp) */
- err |= __put_user(pt->b6, &sc->sc_br[6]); /* b6 */
- err |= __put_user(pt->b7, &sc->sc_br[7]); /* b7 */
-
- err |= __copy_to_user(&sc->sc_gr[1], &pt->r1, 3*8); /* r1-r3 */
- err |= __copy_to_user(&sc->sc_gr[8], &pt->r8, 4*8); /* r8-r11 */
- err |= __copy_to_user(&sc->sc_gr[12], &pt->r12, 4*8); /* r12-r15 */
- err |= __copy_to_user(&sc->sc_gr[16], &pt->r16, 16*8); /* r16-r31 */
+ err |= __put_user(scr->pt.cr_ipsr & IA64_PSR_UM, &sc->sc_um);
+ err |= __put_user(scr->pt.ar_rsc, &sc->sc_ar_rsc);
+ err |= __put_user(scr->pt.ar_ccv, &sc->sc_ar_ccv);
+ err |= __put_user(scr->pt.ar_unat, &sc->sc_ar_unat); /* ar.unat */
+ err |= __put_user(scr->pt.ar_fpsr, &sc->sc_ar_fpsr); /* ar.fpsr */
+ err |= __put_user(scr->pt.ar_pfs, &sc->sc_ar_pfs);
+ err |= __put_user(scr->pt.pr, &sc->sc_pr); /* predicates */
+ err |= __put_user(scr->pt.b0, &sc->sc_br[0]); /* b0 (rp) */
+ err |= __put_user(scr->pt.b6, &sc->sc_br[6]); /* b6 */
+ err |= __put_user(scr->pt.b7, &sc->sc_br[7]); /* b7 */
+
+ err |= __copy_to_user(&sc->sc_gr[1], &scr->pt.r1, 3*8); /* r1-r3 */
+ err |= __copy_to_user(&sc->sc_gr[8], &scr->pt.r8, 4*8); /* r8-r11 */
+ err |= __copy_to_user(&sc->sc_gr[12], &scr->pt.r12, 4*8); /* r12-r15 */
+ err |= __copy_to_user(&sc->sc_gr[16], &scr->pt.r16, 16*8); /* r16-r31 */

- err |= __put_user(pt->cr_iip + ia64_psr(pt)->ri, &sc->sc_ip);
- err |= __put_user(pt->r12, &sc->sc_gr[12]); /* r12 */
+ err |= __put_user(scr->pt.cr_iip + ia64_psr(&scr->pt)->ri, &sc->sc_ip);
return err;
}

static long
-setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *pt)
+setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set,
+ struct sigscratch *scr)
{
- struct switch_stack *sw = (struct switch_stack *) pt - 1;
extern char ia64_sigtramp[], __start_gate_section[];
unsigned long tramp_addr, new_rbs = 0;
struct sigframe *frame;
struct siginfo si;
long err;

- frame = (void *) pt->r12;
+ frame = (void *) scr->pt.r12;
tramp_addr = GATE_ADDR + (ia64_sigtramp - __start_gate_section);
if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && !on_sig_stack((unsigned long) frame)) {
new_rbs = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1);
@@ -348,31 +356,39 @@

err |= __put_user(current->sas_ss_sp, &frame->sc.sc_stack.ss_sp);
err |= __put_user(current->sas_ss_size, &frame->sc.sc_stack.ss_size);
- err |= __put_user(sas_ss_flags(pt->r12), &frame->sc.sc_stack.ss_flags);
- err |= setup_sigcontext(&frame->sc, set, pt);
+ err |= __put_user(sas_ss_flags(scr->pt.r12), &frame->sc.sc_stack.ss_flags);
+ err |= setup_sigcontext(&frame->sc, set, scr);

if (err)
goto give_sigsegv;

- pt->r12 = (unsigned long) frame - 16; /* new stack pointer */
- pt->r2 = sig; /* signal number */
- pt->r3 = (unsigned long) ka->sa.sa_handler; /* addr. of handler's proc. descriptor */
- pt->r15 = new_rbs;
- pt->ar_fpsr = FPSR_DEFAULT; /* reset fpsr for signal handler */
- pt->cr_iip = tramp_addr;
- ia64_psr(pt)->ri = 0; /* start executing in first slot */
+ scr->pt.r12 = (unsigned long) frame - 16; /* new stack pointer */
+ scr->pt.r2 = sig; /* signal number */
+ scr->pt.r3 = (unsigned long) ka->sa.sa_handler; /* addr. of handler's proc desc */
+ scr->pt.r15 = new_rbs;
+ scr->pt.ar_fpsr = FPSR_DEFAULT; /* reset fpsr for signal handler */
+ scr->pt.cr_iip = tramp_addr;
+ ia64_psr(&scr->pt)->ri = 0; /* start executing in first slot */

+#ifdef CONFIG_IA64_NEW_UNWIND
+ /*
+ * Note: this affects only the NaT bits of the scratch regs
+ * (the ones saved in pt_regs), which is exactly what we want.
+ */
+ scr->scratch_unat = 0; /* ensure NaT bits of at least r2, r3, r12, and r15 are clear */
+#else
/*
* Note: this affects only the NaT bits of the scratch regs
- * (the ones saved in pt_regs, which is exactly what we want.
+ * (the ones saved in pt_regs), which is exactly what we want.
* The NaT bits for the preserved regs (r4-r7) are in
* sw->ar_unat iff this process is being PTRACED.
*/
- sw->caller_unat = 0; /* ensure NaT bits of at least r2, r3, r12, and r15 are clear */
+ scr->sw.caller_unat = 0; /* ensure NaT bits of at least r2, r3, r12, and r15 are clear */
+#endif

#if DEBUG_SIG
printk("SIG deliver (%s:%d): sig=%d sp=%lx ip=%lx handler=%lx\n",
- current->comm, current->pid, sig, pt->r12, pt->cr_iip, pt->r3);
+ current->comm, current->pid, sig, scr->pt.r12, scr->pt.cr_iip, scr->pt.r3);
#endif
return 1;

@@ -391,17 +407,17 @@

static long
handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset,
- struct pt_regs *pt)
+ struct sigscratch *scr)
{
#ifdef CONFIG_IA32_SUPPORT
- if (IS_IA32_PROCESS(pt)) {
+ if (IS_IA32_PROCESS(&scr->pt)) {
/* send signal to IA-32 process */
- if (!ia32_setup_frame1(sig, ka, info, oldset, pt))
+ if (!ia32_setup_frame1(sig, ka, info, oldset, &scr->pt))
return 0;
} else
#endif
/* send signal to IA-64 process */
- if (!setup_frame(sig, ka, info, oldset, pt))
+ if (!setup_frame(sig, ka, info, oldset, scr))
return 0;

if (ka->sa.sa_flags & SA_ONESHOT)
@@ -418,12 +434,6 @@
}

/*
- * When we get here, `pt' points to struct pt_regs and ((struct
- * switch_stack *) pt - 1) points to a switch stack structure.
- * HOWEVER, in the normal case, the ONLY value valid in the
- * switch_stack is the caller_unat field. The entire switch_stack is
- * valid ONLY if current->flags has PF_PTRACED set.
- *
* Note that `init' is a special process: it doesn't get signals it
* doesn't want to handle. Thus you cannot kill init even with a
* SIGKILL even by mistake.
@@ -433,26 +443,26 @@
* user-level signal handling stack-frames in one go after that.
*/
long
-ia64_do_signal (sigset_t *oldset, struct pt_regs *pt, long in_syscall)
+ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
{
struct k_sigaction *ka;
siginfo_t info;
long restart = in_syscall;
- long errno = pt->r8;
+ long errno = scr->pt.r8;

/*
* In the ia64_leave_kernel code path, we want the common case
* to go fast, which is why we may in certain cases get here
* from kernel mode. Just return without doing anything if so.
*/
- if (!user_mode(pt))
+ if (!user_mode(&scr->pt))
return 0;

if (!oldset)
oldset = &current->blocked;

#ifdef CONFIG_IA32_SUPPORT
- if (IS_IA32_PROCESS(pt)) {
+ if (IS_IA32_PROCESS(&scr->pt)) {
if (in_syscall) {
if (errno >= 0)
restart = 0;
@@ -461,7 +471,7 @@
}
} else
#endif
- if (pt->r10 != -1) {
+ if (scr->pt.r10 != -1) {
/*
* A system calls has to be restarted only if one of
* the error codes ERESTARTNOHAND, ERESTARTSYS, or
@@ -555,7 +565,7 @@
case SIGQUIT: case SIGILL: case SIGTRAP:
case SIGABRT: case SIGFPE: case SIGSEGV:
case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
- if (do_coredump(signr, pt))
+ if (do_coredump(signr, &scr->pt))
exit_code |= 0x80;
/* FALLTHRU */

@@ -575,29 +585,29 @@
if ((ka->sa.sa_flags & SA_RESTART) = 0) {
case ERESTARTNOHAND:
#ifdef CONFIG_IA32_SUPPORT
- if (IS_IA32_PROCESS(pt))
- pt->r8 = -EINTR;
+ if (IS_IA32_PROCESS(&scr->pt))
+ scr->pt.r8 = -EINTR;
else
#endif
- pt->r8 = EINTR;
- /* note: pt->r10 is already -1 */
+ scr->pt.r8 = EINTR;
+ /* note: scr->pt.r10 is already -1 */
break;
}
case ERESTARTNOINTR:
-#ifdef CONFIG_IA32_SUPPOT
- if (IS_IA32_PROCESS(pt)) {
- pt->r8 = pt->r1;
- pt->cr_iip -= 2;
+#ifdef CONFIG_IA32_SUPPORT
+ if (IS_IA32_PROCESS(&scr->pt)) {
+ scr->pt.r8 = scr->pt.r1;
+ scr->pt.cr_iip -= 2;
} else
#endif
- ia64_decrement_ip(pt);
+ ia64_decrement_ip(&scr->pt);
}
}

/* Whee! Actually deliver the signal. If the
delivery failed, we need to continue to iterate in
this loop so we can deliver the SIGSEGV... */
- if (handle_signal(signr, ka, &info, oldset, pt))
+ if (handle_signal(signr, ka, &info, oldset, scr))
return 1;
}

@@ -606,9 +616,9 @@
/* Restart the system call - no handlers present */
if (errno = ERESTARTNOHAND || errno = ERESTARTSYS || errno = ERESTARTNOINTR) {
#ifdef CONFIG_IA32_SUPPORT
- if (IS_IA32_PROCESS(pt)) {
- pt->r8 = pt->r1;
- pt->cr_iip -= 2;
+ if (IS_IA32_PROCESS(&scr->pt)) {
+ scr->pt.r8 = scr->pt.r1;
+ scr->pt.cr_iip -= 2;
} else
#endif
/*
@@ -617,7 +627,7 @@
* is adjust ip so that the "break"
* instruction gets re-executed.
*/
- ia64_decrement_ip(pt);
+ ia64_decrement_ip(&scr->pt);
}
}
return 0;
diff -urN linux-davidm/arch/ia64/kernel/smp.c linux-2.4.0-test1-lia/arch/ia64/kernel/smp.c
--- linux-davidm/arch/ia64/kernel/smp.c Fri Jun 9 17:38:58 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/smp.c Fri Jun 9 17:49:36 2000
@@ -81,7 +81,6 @@
#ifndef CONFIG_ITANIUM_PTCG
# define IPI_FLUSH_TLB 3
#endif /*!CONFIG_ITANIUM_PTCG */
-#define IPI_KDB_INTERRUPT 4

/*
* Setup routine for controlling SMP activation
@@ -133,24 +132,17 @@

}

-static inline void
-pointer_unlock(void **lock, void **data)
-{
- *data = *lock;
- *lock = NULL;
-}
-
static inline int
pointer_lock(void *lock, void *data, int retry)
{
again:
- if (cmpxchg_acq(lock, 0, data) = 0)
+ if (cmpxchg_acq((void **) lock, 0, data) = 0)
return 0;

if (!retry)
return -EBUSY;

- while (*(void**) lock)
+ while (*(void **) lock)
;

goto again;
@@ -191,13 +183,13 @@
int wait;

/* release the 'pointer lock' */
- pointer_unlock((void **) &smp_call_function_data, (void **) &data);
+ data = smp_call_function_data;
func = data->func;
info = data->info;
wait = data->wait;

mb();
- atomic_dec (&data->unstarted_count);
+ atomic_dec(&data->unstarted_count);

/* At this point the structure may be gone unless wait is true. */
(*func)(info);
@@ -205,7 +197,7 @@
/* Notify the sending CPU that the task is done. */
mb();
if (wait)
- atomic_dec (&data->unfinished_count);
+ atomic_dec(&data->unfinished_count);
}
break;

@@ -344,41 +336,35 @@
{
struct smp_call_struct data;
long timeout;
- static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+ int cpus = smp_num_cpus - 1;
+
+ if (cpus = 0)
+ return 0;

data.func = func;
data.info = info;
data.wait = wait;
- atomic_set(&data.unstarted_count, smp_num_cpus - 1);
- atomic_set(&data.unfinished_count, smp_num_cpus - 1);
+ atomic_set(&data.unstarted_count, cpus);
+ atomic_set(&data.unfinished_count, cpus);

if (pointer_lock(&smp_call_function_data, &data, retry))
return -EBUSY;

- smp_call_function_data = &data;
- spin_unlock (&lock);
- data.func = func;
- data.info = info;
- atomic_set (&data.unstarted_count, smp_num_cpus - 1);
- data.wait = wait;
- if (wait)
- atomic_set (&data.unfinished_count, smp_num_cpus - 1);
-
/* Send a message to all other CPUs and wait for them to respond */
send_IPI_allbutself(IPI_CALL_FUNC);

/* Wait for response */
timeout = jiffies + HZ;
- while ( (atomic_read (&data.unstarted_count) > 0) &&
- time_before (jiffies, timeout) )
- barrier ();
- if (atomic_read (&data.unstarted_count) > 0) {
+ while ((atomic_read(&data.unstarted_count) > 0) && time_before(jiffies, timeout))
+ barrier();
+ if (atomic_read(&data.unstarted_count) > 0) {
smp_call_function_data = NULL;
return -ETIMEDOUT;
}
if (wait)
- while (atomic_read (&data.unfinished_count) > 0)
- barrier ();
+ while (atomic_read(&data.unfinished_count) > 0)
+ barrier();
+ /* unlock pointer */
smp_call_function_data = NULL;
return 0;
}
diff -urN linux-davidm/arch/ia64/kernel/sys_ia64.c linux-2.4.0-test1-lia/arch/ia64/kernel/sys_ia64.c
--- linux-davidm/arch/ia64/kernel/sys_ia64.c Fri Jun 9 17:38:58 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/sys_ia64.c Fri Jun 9 17:18:00 2000
@@ -156,6 +156,9 @@
{
struct pt_regs *regs = (struct pt_regs *) &stack;

+ if ((off & ~PAGE_MASK) != 0)
+ return -EINVAL;
+
addr = do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
if (!IS_ERR(addr))
regs->r8 = 0; /* ensure large addresses are not mistaken as failures... */
diff -urN linux-davidm/arch/ia64/kernel/time.c linux-2.4.0-test1-lia/arch/ia64/kernel/time.c
--- linux-davidm/arch/ia64/kernel/time.c Fri Jun 9 17:38:58 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/time.c Fri Jun 9 17:18:07 2000
@@ -162,6 +162,11 @@
*/
write_lock(&xtime_lock);
new_itm = itm.next[cpu].count;
+
+ if (!time_after(ia64_get_itc(), new_itm))
+ printk("Oops: timer tick before it's due (itc=%lx,itm=%lx)\n",
+ ia64_get_itc(), new_itm);
+
while (1) {
/*
* Do kernel PC profiling here. We multiply the
@@ -220,7 +225,7 @@
ia64_set_itm(new_itm);
}

-#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
+#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_IA64_SOFTSDV_HACKS)

/*
* Interrupts must be disabled before calling this routine.
diff -urN linux-davidm/arch/ia64/kernel/traps.c linux-2.4.0-test1-lia/arch/ia64/kernel/traps.c
--- linux-davidm/arch/ia64/kernel/traps.c Fri Jun 9 17:38:58 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/traps.c Fri Jun 9 17:49:52 2000
@@ -36,10 +36,6 @@
#include <linux/init.h>
#include <linux/sched.h>

-#ifdef CONFIG_KDB
-#include <linux/kdb.h>
-#endif
-
#include <asm/ia32.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
@@ -92,13 +88,6 @@
}

printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err);
-
-#ifdef CONFIG_KDB
- while (1) {
- kdb(KDB_REASON_PANIC, 0, regs);
- printk("Cant go anywhere from Panic!\n");
- }
-#endif

show_regs(regs);

diff -urN linux-davidm/arch/ia64/kernel/unwind.c linux-2.4.0-test1-lia/arch/ia64/kernel/unwind.c
--- linux-davidm/arch/ia64/kernel/unwind.c Fri Jun 9 17:38:59 2000
+++ linux-2.4.0-test1-lia/arch/ia64/kernel/unwind.c Fri Jun 9 17:18:53 2000
@@ -49,7 +49,7 @@
#define UNW_LOG_HASH_SIZE (UNW_LOG_CACHE_SIZE + 1)
#define UNW_HASH_SIZE (1 << UNW_LOG_HASH_SIZE)

-#define UNW_DEBUG 0
+#define UNW_DEBUG 1
#define UNW_STATS 0 /* WARNING: this disabled interrupts for long time-spans!! */

#if UNW_DEBUG
@@ -191,8 +191,10 @@
struct unw_ireg *ireg;
struct pt_regs *pt;

- if ((unsigned) regnum - 1 >= 127)
+ if ((unsigned) regnum - 1 >= 127) {
+ dprintk("unwind: trying to access non-existent r%u\n", regnum);
return -1;
+ }

if (regnum < 32) {
if (regnum >= 4 && regnum <= 7) {
@@ -238,7 +240,12 @@
nat_addr = ia64_rse_rnat_addr(addr);
if ((unsigned long) addr < info->regstk.limit
|| (unsigned long) addr >= info->regstk.top)
+ {
+ dprintk("unwind: %lx outside of regstk "
+ "[0x%lx-0x%lx)\n", addr,
+ info->regstk.limit, info->regstk.top);
return -1;
+ }
if ((unsigned long) nat_addr >= info->regstk.top)
nat_addr = &info->sw->ar_rnat;
nat_mask = (1UL << ia64_rse_slot_num(addr));
@@ -307,9 +314,12 @@
/* preserved: */
case 1: case 2: case 3: case 4: case 5:
addr = *(&info->b1 + (regnum - 1));
+ if (!addr)
+ addr = &info->sw->b1 + (regnum - 1);
break;

default:
+ dprintk("unwind: trying to access non-existent b%u\n", regnum);
return -1;
}
if (write)
@@ -325,8 +335,10 @@
struct ia64_fpreg *addr = 0;
struct pt_regs *pt;

- if ((unsigned) (regnum - 2) >= 30)
+ if ((unsigned) (regnum - 2) >= 30) {
+ dprintk("unwind: trying to access non-existent f%u\n", regnum);
return -1;
+ }

pt = (struct pt_regs *) info->sp - 1;

@@ -412,6 +424,7 @@
break;

default:
+ dprintk("unwind: trying to access non-existent ar%u\n", regnum);
return -1;
}

@@ -1327,7 +1340,8 @@
}
if (!e) {
/* no info, return default unwinder (leaf proc, no mem stack, no saved regs) */
- dprintk("unwind: no unwind info for ip=0x%lx\n", ip);
+ dprintk("unwind: no unwind info for ip=0x%lx (prev ip=0x%lx)\n", ip,
+ unw.cache[info->prev_script].ip);
sr.curr.reg[UNW_REG_RP].where = UNW_WHERE_BR;
sr.curr.reg[UNW_REG_RP].when = -1;
sr.curr.reg[UNW_REG_RP].val = 0;
@@ -1338,7 +1352,7 @@
return script;
}

- sr.when_target = (3*((ip & ~0xfUL) - (table->segment_base + e->start_offset))
+ sr.when_target = (3*((ip & ~0xfUL) - (table->segment_base + e->start_offset))/16
+ (ip & 0xfUL));
hdr = *(u64 *) (table->segment_base + e->info_offset);
dp = (u8 *) (table->segment_base + e->info_offset + 8);
@@ -1383,7 +1397,7 @@
case UNW_WHERE_FR: printk("f%lu", r->val); break;
case UNW_WHERE_BR: printk("b%lu", r->val); break;
case UNW_WHERE_SPREL: printk("[sp+0x%lx]", r->val); break;
- case UNW_WHERE_PSPREL: printk("[psp+0x%lx]", 0x10 - r->val); break;
+ case UNW_WHERE_PSPREL: printk("[psp+0x%lx]", r->val); break;
case UNW_WHERE_NONE:
printk("%s+0x%lx", unw.preg_name[r - sr.curr.reg], r->val);
break;
@@ -1531,6 +1545,7 @@

if (info->ip & (my_cpu_data.unimpl_va_mask | 0xf)) {
/* don't let obviously bad addresses pollute the cache */
+ dprintk("unwind: rejecting bad ip=0x%lx\n", info->ip);
info->rp = 0;
return -1;
}
@@ -1590,18 +1605,18 @@
STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));
return -1;
}
- info->cfm = *info->pfs;
+ info->cfm = info->pfs;

/* restore the bsp: */
pr = info->pr_val;
num_regs = 0;
if ((info->flags & UNW_FLAG_INTERRUPT_FRAME)) {
if ((pr & (1UL << pNonSys)) != 0)
- num_regs = info->cfm & 0x7f; /* size of frame */
+ num_regs = *info->cfm & 0x7f; /* size of frame */
info->pfs (unsigned long *) (info->sp + 16 + struct_offset(struct pt_regs, ar_pfs));
} else
- num_regs = (info->cfm >> 7) & 0x7f; /* size of locals */
+ num_regs = (*info->cfm >> 7) & 0x7f; /* size of locals */
info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->bsp, -num_regs);
if (info->bsp < info->regstk.limit || info->bsp > info->regstk.top) {
dprintk("unwind: bsp (0x%lx) out of range [0x%lx-0x%lx]\n",
@@ -1669,8 +1684,8 @@
info->memstk.top = stktop;
info->sw = sw;
info->sp = info->psp = (unsigned long) (sw + 1) - 16;
- info->cfm = sw->ar_pfs;
- sol = (info->cfm >> 7) & 0x7f;
+ info->cfm = &sw->ar_pfs;
+ sol = (*info->cfm >> 7) & 0x7f;
info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol);
info->ip = sw->b0;
info->pr_val = sw->pr;
@@ -1704,7 +1719,7 @@
info->regstk.top = top;
info->sw = sw;
info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol);
- info->cfm = sw->ar_pfs;
+ info->cfm = &sw->ar_pfs;
info->ip = sw->b0;
#endif
}
@@ -1741,7 +1756,7 @@
info->regstk.top = top;
info->sw = sw;
info->bsp = (unsigned long) ia64_rse_skip_regs(bsp, -sof);
- info->cfm = regs->cr_ifs;
+ info->cfm = &regs->cr_ifs;
info->ip = regs->cr_iip;
#endif
}
@@ -1777,7 +1792,7 @@
int
unw_unwind (struct unw_frame_info *info)
{
- unsigned long sol, cfm = info->cfm;
+ unsigned long sol, cfm = *info->cfm;
int is_nat;

sol = (cfm >> 7) & 0x7f; /* size of locals */
@@ -1796,16 +1811,16 @@

info->ip = read_reg(info, sol - 2, &is_nat);
if (is_nat || (info->ip & (my_cpu_data.unimpl_va_mask | 0xf)))
- /* don't let obviously bad addresses pollute the cache */
+ /* reject let obviously bad addresses */
return -1;

+ info->cfm = ia64_rse_skip_regs((unsigned long *) info->bsp, sol - 1);
cfm = read_reg(info, sol - 1, &is_nat);
if (is_nat)
return -1;

sol = (cfm >> 7) & 0x7f;

- info->cfm = cfm;
info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->bsp, -sol);
return 0;
}
diff -urN linux-davidm/arch/ia64/mm/init.c linux-2.4.0-test1-lia/arch/ia64/mm/init.c
--- linux-davidm/arch/ia64/mm/init.c Fri Jun 9 17:38:59 2000
+++ linux-2.4.0-test1-lia/arch/ia64/mm/init.c Fri Jun 9 17:19:34 2000
@@ -183,6 +183,19 @@
}

void
+free_initrd_mem(unsigned long start, unsigned long end)
+{
+ if (start < end)
+ printk ("Freeing initrd memory: %ldkB freed\n", (end - start) >> 10);
+ for (; start < end; start += PAGE_SIZE) {
+ clear_bit(PG_reserved, &mem_map[MAP_NR(start)].flags);
+ set_page_count(&mem_map[MAP_NR(start)], 1);
+ free_page(start);
+ ++totalram_pages;
+ }
+}
+
+void
si_meminfo (struct sysinfo *val)
{
val->totalram = totalram_pages;
diff -urN linux-davidm/arch/ia64/vmlinux.lds.S linux-2.4.0-test1-lia/arch/ia64/vmlinux.lds.S
--- linux-davidm/arch/ia64/vmlinux.lds.S Fri Jun 9 17:38:59 2000
+++ linux-2.4.0-test1-lia/arch/ia64/vmlinux.lds.S Fri Jun 9 17:20:07 2000
@@ -46,6 +46,11 @@
{ *(__ex_table) }
__stop___ex_table = .;

+ __start___ksymtab = .; /* Kernel symbol table */
+ __ksymtab : AT(ADDR(__ksymtab) - PAGE_OFFSET)
+ { *(__ksymtab) }
+ __stop___ksymtab = .;
+
/* Unwind table */
ia64_unw_start = .;
.IA_64.unwind : AT(ADDR(.IA_64.unwind) - PAGE_OFFSET)
@@ -56,6 +61,8 @@

.rodata : AT(ADDR(.rodata) - PAGE_OFFSET)
{ *(.rodata) }
+ .kstrtab : AT(ADDR(.kstrtab) - PAGE_OFFSET)
+ { *(.kstrtab) }
.opd : AT(ADDR(.opd) - PAGE_OFFSET)
{ *(.opd) }

diff -urN linux-davidm/fs/proc/generic.c linux-2.4.0-test1-lia/fs/proc/generic.c
--- linux-davidm/fs/proc/generic.c Sun May 21 20:34:37 2000
+++ linux-2.4.0-test1-lia/fs/proc/generic.c Fri Jun 9 17:24:08 2000
@@ -42,7 +42,7 @@
#endif

/* 4K page size but our output routines use some slack for overruns */
-#define PROC_BLOCK_SIZE (3*1024)
+#define PROC_BLOCK_SIZE (PAGE_SIZE - 1024)

static ssize_t
proc_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
diff -urN linux-davidm/include/asm-ia64/processor.h linux-2.4.0-test1-lia/include/asm-ia64/processor.h
--- linux-davidm/include/asm-ia64/processor.h Fri Jun 9 17:39:00 2000
+++ linux-2.4.0-test1-lia/include/asm-ia64/processor.h Fri Jun 9 17:24:33 2000
@@ -658,13 +658,16 @@
thread_saved_pc (struct thread_struct *t)
{
struct unw_frame_info info;
+ unsigned long ip;
+
/* XXX ouch: Linus, please pass the task pointer to thread_saved_pc() instead! */
struct task_struct *p = (void *) ((unsigned long) t - IA64_TASK_THREAD_OFFSET);

unw_init_from_blocked_task(&info, p);
if (unw_unwind(&info) < 0)
return 0;
- return unw_get_ip(&info);
+ unw_get_ip(&info, &ip);
+ return ip;
}

/*
diff -urN linux-davidm/include/asm-ia64/ptrace.h linux-2.4.0-test1-lia/include/asm-ia64/ptrace.h
--- linux-davidm/include/asm-ia64/ptrace.h Fri Apr 21 15:21:24 2000
+++ linux-2.4.0-test1-lia/include/asm-ia64/ptrace.h Fri Jun 9 17:24:41 2000
@@ -220,10 +220,17 @@
extern long ia64_peek (struct pt_regs *, struct task_struct *, unsigned long addr, long *val);
extern long ia64_poke (struct pt_regs *, struct task_struct *, unsigned long addr, long val);

+#ifdef CONFIG_IA64_NEW_UNWIND
+ /* get nat bits for scratch registers such that bit N=1 iff scratch register rN is a NaT */
+ extern unsigned long ia64_get_scratch_nat_bits (struct pt_regs *pt, unsigned long scratch_unat);
+ /* put nat bits for scratch registers such that scratch register rN is a NaT iff bit N=1 */
+ extern unsigned long ia64_put_scratch_nat_bits (struct pt_regs *pt, unsigned long nat);
+#else
/* get nat bits for r1-r31 such that bit N=1 iff rN is a NaT */
extern long ia64_get_nat_bits (struct pt_regs *pt, struct switch_stack *sw);
/* put nat bits for r1-r31 such that rN is a NaT iff bit N=1 */
extern void ia64_put_nat_bits (struct pt_regs *pt, struct switch_stack *sw, unsigned long nat);
+#endif

extern void ia64_increment_ip (struct pt_regs *pt);
extern void ia64_decrement_ip (struct pt_regs *pt);
diff -urN linux-davidm/include/asm-ia64/ptrace_offsets.h linux-2.4.0-test1-lia/include/asm-ia64/ptrace_offsets.h
--- linux-davidm/include/asm-ia64/ptrace_offsets.h Fri Jun 9 17:39:00 2000
+++ linux-2.4.0-test1-lia/include/asm-ia64/ptrace_offsets.h Fri Jun 9 17:25:05 2000
@@ -118,7 +118,7 @@
#define PT_F126 0x05e0
#define PT_F127 0x05f0
/* switch stack: */
-#define PT_PRI_UNAT 0x0600
+#define PT_NAT_BITS 0x0600

#define PT_F2 0x0610
#define PT_F3 0x0620
diff -urN linux-davidm/include/asm-ia64/system.h linux-2.4.0-test1-lia/include/asm-ia64/system.h
--- linux-davidm/include/asm-ia64/system.h Fri Jun 9 17:39:00 2000
+++ linux-2.4.0-test1-lia/include/asm-ia64/system.h Fri Jun 9 17:25:19 2000
@@ -54,6 +54,8 @@
__u16 num_pci_vectors; /* number of ACPI derived PCI IRQ's*/
__u64 pci_vectors; /* physical address of PCI data (pci_vector_struct)*/
__u64 fpswa; /* physical address of the the fpswa interface */
+ __u64 initrd_start;
+ __u64 initrd_size;
} ia64_boot_param;

extern inline void
diff -urN linux-davidm/include/asm-ia64/unwind.h linux-2.4.0-test1-lia/include/asm-ia64/unwind.h
--- linux-davidm/include/asm-ia64/unwind.h Fri Jun 9 17:39:00 2000
+++ linux-2.4.0-test1-lia/include/asm-ia64/unwind.h Fri Jun 9 17:25:28 2000
@@ -54,9 +54,9 @@
unsigned long bsp;
unsigned long sp; /* stack pointer */
unsigned long psp; /* previous sp */
- unsigned long cfm;
unsigned long ip; /* instruction pointer */
unsigned long pr_val; /* current predicates */
+ unsigned long *cfm;

struct switch_stack *sw;

@@ -123,11 +123,21 @@
*/
extern int unw_unwind (struct unw_frame_info *info);

-#define unw_get_ip(info) ((info)->ip)
-#define unw_get_sp(info) ((unsigned long) (info)->sp)
-#define unw_get_psp(info) ((unsigned long) (info)->psp)
-#define unw_get_bsp(info) ((unsigned long) (info)->bsp)
-#define unw_get_cfm(info) ((info)->cfm)
+#define unw_get_ip(info,vp) ({*(vp) = (info)->ip; 0;})
+#define unw_get_sp(info,vp) ({*(vp) = (unsigned long) (info)->sp; 0;})
+#define unw_get_psp(info,vp) ({*(vp) = (unsigned long) (info)->psp; 0;})
+#define unw_get_bsp(info,vp) ({*(vp) = (unsigned long) (info)->bsp; 0;})
+#define unw_get_cfm(info,vp) ({*(vp) = *(info)->cfm; 0;})
+#define unw_set_cfm(info,val) ({*(info)->cfm = (val); 0;})
+
+static inline int
+unw_get_rp (struct unw_frame_info *info, unsigned long *val)
+{
+ if (!info->rp)
+ return -1;
+ *val = *info->rp;
+ return 0;
+}

extern int unw_access_gr (struct unw_frame_info *, int, unsigned long *, char *, int);
extern int unw_access_br (struct unw_frame_info *, int, unsigned long *, int);
@@ -135,11 +145,35 @@
extern int unw_access_ar (struct unw_frame_info *, int, unsigned long *, int);
extern int unw_access_pr (struct unw_frame_info *, unsigned long *, int);

-#define unw_set_gr(i,n,v,nat) unw_access_gr(i,n,v,nat,1)
-#define unw_set_br(i,n,v) unw_access_br(i,n,v,1)
-#define unw_set_fr(i,n,v) unw_access_fr(i,n,v,1)
-#define unw_set_ar(i,n,v) unw_access_ar(i,n,v,1)
-#define unw_set_pr(i,v) unw_access_ar(i,v,1)
+static inline int
+unw_set_gr (struct unw_frame_info *i, int n, unsigned long v, char nat)
+{
+ return unw_access_gr(i, n, &v, &nat, 1);
+}
+
+static inline int
+unw_set_br (struct unw_frame_info *i, int n, unsigned long v)
+{
+ return unw_access_br(i, n, &v, 1);
+}
+
+static inline int
+unw_set_fr (struct unw_frame_info *i, int n, struct ia64_fpreg v)
+{
+ return unw_access_fr(i, n, &v, 1);
+}
+
+static inline int
+unw_set_ar (struct unw_frame_info *i, int n, unsigned long v)
+{
+ return unw_access_ar(i, n, &v, 1);
+}
+
+static inline int
+unw_set_pr (struct unw_frame_info *i, unsigned long v)
+{
+ return unw_access_pr(i, &v, 1);
+}

#define unw_get_gr(i,n,v,nat) unw_access_gr(i,n,v,nat,0)
#define unw_get_br(i,n,v) unw_access_br(i,n,v,0)