[Linux-ia64] kernel update (relative to 2.4.0)

David Mosberger
2001-01-26T04:53:44Z

The latest IA-64 patch is now available at:

ftp://ftp.kernel.org/pub/linux/kernel/ports/ia64/

in file linux-2.4.0-ia64-010125.diff*

What changed since last time:

o Alex Williamson: Fix "implemented VA bits" calculation so it
doesn't fail when all virtual address bits are implemented.
o Erich Focht/YT: Fix llseek() in /proc/mem to make it work when
offset >=2^63.
o William Taber/YT: fix mm/memory.c so handle_mm_fault() gets called
with the right arguments.
o BJ Nima: Update qla1280 driver to version 3.23 beta.
o Keith Owens: Fix unw_access_gr() so it accesses stacked regs correctly.
o Don Dugger: Fix munmap, mprotect, & msync to do the right thing
when 4KB pages are in use. Various other IA-32 fixes.
o Asit Mallick:
+ Fix TLB handlers (this was fix was posted to the list earlier on).
+ Add missing restore of ar.lc in copy_user()
o YT:
+ Make IA-64 timer data structure (itm) part of CPU-local data
+ "Randomize" the timer tick on different CPUs so it's less likely
for multiple CPUs to hit the timer interrupt simultaneous (shouldn't
really make much of a difference on today's machines, but it seemed
like the right thing to do and was easy to add)
+ Make unaligned handler work inside the kernel and fix
a nasty bug that would let a user program crash the system.
+ Turn on "alignment check" (psr.ac) inside the kernel so we can
reliably detect unaligned accesses
+ Clean up syscall path and improve code scheduling.
+ Make MAX_DMA_ADDRESS a variable so platform-specific code can
override the default value
+ Various IA-32 subsystem cleanups
- added ia32_execve() to get the right register frame when
execv'ing an IA-64 program
- drop IA-32 syscall register frame in the IA-32 specific
code, so we don't have to check and slow down the normal
kernel exit path
- added sys32_signal since Intel's cross compiler wants it

Below is a diff that shows the changes since the last IA-64 patch. As
usual, this is for your enjoyment only. If you want to get the real
sources, start with 2.4.0 and apply the above patch on top of it.

This patch has been tested on BigSur, Lion, and the HP Ski simulator
and found to be generally good to public health. As always, if you
should encounter some unexpected problems, please let us all know.

Enjoy,

--david

diff -urN linux-davidm/Documentation/Configure.help linux-2.4.0-lia/Documentation/Configure.help
--- linux-davidm/Documentation/Configure.help Thu Jan 25 19:17:24 2001
+++ linux-2.4.0-lia/Documentation/Configure.help Thu Jan 25 15:00:58 2001
@@ -17030,11 +17030,6 @@
Say Y here to enable hacks to make the kernel work on the Intel
SoftSDV simulator. Select N here if you're unsure.

-Enable AzusA hacks
-CONFIG_IA64_AZUSA_HACKS
- Say Y here to enable hacks to make the kernel work on the NEC
- AzusA platform. Select N here if you're unsure.
-
Force socket buffers below 4GB?
CONFIG_SKB_BELOW_4GB
Most of today's network interface cards (NICs) support DMA to
diff -urN linux-davidm/arch/ia64/config.in linux-2.4.0-lia/arch/ia64/config.in
--- linux-davidm/arch/ia64/config.in Thu Jan 25 19:17:24 2001
+++ linux-2.4.0-lia/arch/ia64/config.in Thu Jan 25 18:44:45 2001
@@ -54,7 +54,6 @@
bool ' Force interrupt redirection' CONFIG_IA64_HAVE_IRQREDIR
bool ' Enable use of global TLB purge instruction (ptc.g)' CONFIG_ITANIUM_PTCG
bool ' Enable SoftSDV hacks' CONFIG_IA64_SOFTSDV_HACKS
- bool ' Enable AzusA hacks' CONFIG_IA64_AZUSA_HACKS
bool ' Enable IA-64 Machine Check Abort' CONFIG_IA64_MCA
bool ' Enable ACPI 2.0 with errata 1.3' CONFIG_ACPI20
bool ' ACPI kernel configuration manager (EXPERIMENTAL)' CONFIG_ACPI_KERNEL_CONFIG
diff -urN linux-davidm/arch/ia64/ia32/binfmt_elf32.c linux-2.4.0-lia/arch/ia64/ia32/binfmt_elf32.c
--- linux-davidm/arch/ia64/ia32/binfmt_elf32.c Thu Jan 25 19:17:24 2001
+++ linux-2.4.0-lia/arch/ia64/ia32/binfmt_elf32.c Thu Jan 25 15:06:16 2001
@@ -93,8 +93,8 @@

/* Do all the IA-32 setup here */

- current->thread.map_base = 0x40000000;
- current->thread.task_size = 0xc0000000; /* use what Linux/x86 uses... */
+ current->thread.map_base = 0x40000000;
+ current->thread.task_size = 0xc0000000; /* use what Linux/x86 uses... */
set_fs(USER_DS); /* set addr limit for new TASK_SIZE */

/* setup ia32 state for ia32_load_state */
diff -urN linux-davidm/arch/ia64/ia32/ia32_entry.S linux-2.4.0-lia/arch/ia64/ia32/ia32_entry.S
--- linux-davidm/arch/ia64/ia32/ia32_entry.S Thu Jan 4 22:40:10 2001
+++ linux-2.4.0-lia/arch/ia64/ia32/ia32_entry.S Thu Jan 25 15:06:29 2001
@@ -4,11 +4,36 @@

#include "../kernel/entry.h"

+ .text
+
+ /*
+ * execve() is special because in case of success, we need to
+ * setup a null register window frame (in case an IA-32 process
+ * is exec'ing an IA-64 program).
+ */
+ENTRY(ia32_execve)
+ UNW(.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(3))
+ alloc loc1=ar.pfs,3,2,4,0
+ mov loc0=rp
+ UNW(.body)
+ mov out0=in0 // filename
+ ;; // stop bit between alloc and call
+ mov out1=in1 // argv
+ mov out2=in2 // envp
+ add out3\x16,sp // regs
+ br.call.sptk.few rp=sys32_execve
+1: cmp4.ge p6,p0=r8,r0
+ mov ar.pfs=loc1 // restore ar.pfs
+ ;;
+(p6) mov ar.pfs=r0 // clear ar.pfs in case of success
+ sxt4 r8=r8 // return 64-bit result
+ mov rp=loc0
+ br.ret.sptk.few rp
+END(ia32_execve)
+
//
// Get possibly unaligned sigmask argument into an aligned
// kernel buffer
- .text
-
GLOBAL_ENTRY(ia32_rt_sigsuspend)
// We'll cheat and not do an alloc here since we are ultimately
// going to do a simple branch to the IA64 sys_rt_sigsuspend.
@@ -46,8 +71,9 @@
cmp.ge p6,p7=r8,r0 // syscall executed successfully?
adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8
;;
+ alloc r3=ar.pfs,0,0,0,0 // drop the syscall argument frame
st8 [r2]=r8 // store return value in slot for r8
- br.cond.sptk.few ia64_leave_kernel
+ br.cond.sptk.many ia64_leave_kernel
END(ia32_ret_from_syscall)

//
@@ -69,7 +95,8 @@
;;
st8.spill [r2]=r8 // store return value in slot for r8
br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value
-.ret2: br.cond.sptk.many ia64_leave_kernel // rp MUST be != ia64_leave_kernel!
+.ret2: alloc r2=ar.pfs,0,0,0,0 // drop the syscall argument frame
+ br.cond.sptk.many ia64_leave_kernel // rp MUST be != ia64_leave_kernel!
END(ia32_trace_syscall)

GLOBAL_ENTRY(sys32_vfork)
@@ -116,7 +143,7 @@
data8 sys_creat
data8 sys_link
data8 sys_unlink /* 10 */
- data8 sys32_execve
+ data8 ia32_execve
data8 sys_chdir
data8 sys32_time
data8 sys_mknod
@@ -153,7 +180,7 @@
data8 sys_brk /* 45 */
data8 sys_setgid
data8 sys_getgid
- data8 sys32_ni_syscall
+ data8 sys32_signal
data8 sys_geteuid
data8 sys_getegid /* 50 */
data8 sys_acct
diff -urN linux-davidm/arch/ia64/ia32/sys_ia32.c linux-2.4.0-lia/arch/ia64/ia32/sys_ia32.c
--- linux-davidm/arch/ia64/ia32/sys_ia32.c Thu Jan 25 19:17:24 2001
+++ linux-2.4.0-lia/arch/ia64/ia32/sys_ia32.c Thu Jan 25 17:17:36 2001
@@ -64,7 +64,6 @@
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))

extern asmlinkage long sys_execve (char *, char **, char **, struct pt_regs *);
-extern asmlinkage long sys_munmap (unsigned long, size_t len);
extern asmlinkage long sys_mprotect (unsigned long, size_t, unsigned long);

static int
@@ -134,10 +133,10 @@
/* oops, execve failed, switch back to old map base & task-size: */
current->thread.map_base = old_map_base;
current->thread.task_size = old_task_size;
+ set_fs(USER_DS); /* establish new task-size as the address-limit */
out:
kfree(av);
}
- set_fs(USER_DS); /* establish new task-size as the address-limit */
return r;
}

@@ -213,7 +212,6 @@
return ret;
}

-#define ALIGN4K(a) (((a) + 0xfff) & ~0xfff)
#define OFFSET4K(a) ((a) & 0xfff)

unsigned long
@@ -320,18 +318,46 @@
if (copy_from_user(&a, arg, sizeof(a)))
return -EFAULT;

+ if (PAGE_ALIGN(a.len) = 0)
+ return a.addr;
+
if (!(a.flags & MAP_ANONYMOUS)) {
file = fget(a.fd);
if (!file)
return -EBADF;
}
+#ifdef CONFIG_IA64_PAGE_SIZE_4KB
+ if ((a.offset & ~PAGE_MASK) != 0)
+ return -EINVAL;
+
+ down(&current->mm->mmap_sem);
+ retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset >> PAGE_SHIFT);
+ up(&current->mm->mmap_sem);
+#else // CONFIG_IA64_PAGE_SIZE_4KB
retval = ia32_do_mmap(file, a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
+#endif // CONFIG_IA64_PAGE_SIZE_4KB
if (file)
fput(file);
return retval;
}

asmlinkage long
+sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
+{
+
+#ifdef CONFIG_IA64_PAGE_SIZE_4KB
+ return(sys_mprotect(start, len, prot));
+#else // CONFIG_IA64_PAGE_SIZE_4KB
+ if (prot = 0)
+ return(0);
+ len += start & ~PAGE_MASK;
+ if ((start & ~PAGE_MASK) && (prot & PROT_WRITE))
+ prot |= PROT_EXEC;
+ return(sys_mprotect(start & PAGE_MASK, len & PAGE_MASK, prot));
+#endif // CONFIG_IA64_PAGE_SIZE_4KB
+}
+
+asmlinkage long
sys32_pipe(int *fd)
{
int retval;
@@ -347,15 +373,17 @@
}

asmlinkage long
-sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
+sys32_signal (int sig, unsigned int handler)
{
+ struct k_sigaction new_sa, old_sa;
+ int ret;

- if (prot = 0)
- return(0);
- len += start & ~PAGE_MASK;
- if ((start & ~PAGE_MASK) && (prot & PROT_WRITE))
- prot |= PROT_EXEC;
- return(sys_mprotect(start & PAGE_MASK, len & PAGE_MASK, prot));
+ new_sa.sa.sa_handler = (__sighandler_t) A(handler);
+ new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK;
+
+ ret = do_sigaction(sig, &new_sa, &old_sa);
+
+ return ret ? ret : (unsigned long)old_sa.sa.sa_handler;
}

asmlinkage long
@@ -526,7 +554,6 @@
return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
(__get_user(o->tv_sec, &i->tv_sec) |
__get_user(o->tv_usec, &i->tv_usec)));
- return ENOSYS;
}

static inline long
@@ -545,18 +572,16 @@
__get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
__get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
__get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
- return ENOSYS;
}

static inline long
put_it32(struct itimerval32 *o, struct itimerval *i)
{
- return (!access_ok(VERIFY_WRITE, i, sizeof(*i)) ||
+ return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
(__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
__put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
__put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
__put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
- return ENOSYS;
}

extern int do_getitimer(int which, struct itimerval *value);
@@ -2644,6 +2669,8 @@
}
return(ret);
}
+
+asmlinkage long sys_msync(unsigned long start, size_t len, int flags);

asmlinkage int
sys_pause (void)
diff -urN linux-davidm/arch/ia64/kernel/entry.S linux-2.4.0-lia/arch/ia64/kernel/entry.S
--- linux-davidm/arch/ia64/kernel/entry.S Thu Jan 25 19:17:25 2001
+++ linux-2.4.0-lia/arch/ia64/kernel/entry.S Thu Jan 25 15:08:06 2001
@@ -40,7 +40,7 @@
#include <asm/asmmacro.h>
#include <asm/pgtable.h>

-#include "entry.h"
+#include "minstate.h"

.text
.psr abi64
@@ -147,7 +147,7 @@
mov r13=in0 // set "current" pointer
;;
(p6) ssm psr.i // renable psr.i AFTER the ic bit is serialized
- DO_LOAD_SWITCH_STACK( )
+ DO_LOAD_SWITCH_STACK

#ifdef CONFIG_SMP
sync.i // ensure "fc"s done by this CPU are visible on other CPUs
@@ -492,22 +492,6 @@
br.cond.sptk.few strace_save_retval
END(ia64_trace_syscall)

-/*
- * A couple of convenience macros to help implement/understand the state
- * restoration that happens at the end of ia64_ret_from_syscall.
- */
-#define rARPR r31
-#define rCRIFS r30
-#define rCRIPSR r29
-#define rCRIIP r28
-#define rARRSC r27
-#define rARPFS r26
-#define rARUNAT r25
-#define rARRNAT r24
-#define rARBSPSTORE r23
-#define rKRBS r22
-#define rB6 r21
-
GLOBAL_ENTRY(ia64_ret_from_clone)
PT_REGS_UNWIND_INFO(0)
#ifdef CONFIG_SMP
@@ -554,10 +538,11 @@
;;
add r3=r2,r3
#else
+ adds r16=IA64_PT_REGS_R8_OFFSET+16,r12
movl r3=irq_stat // softirq_active
#endif
;;
- ld8 r2=[r3] // r3 (softirq_active+softirq_mask) is guaranteed to be 8-byte aligned!
+ ld8 r2=[r3] // r3 (softirq_active+softirq_mask) is guaranteed to be 8-byte aligned!
;;
shr r3=r2,32
;;
@@ -692,12 +677,13 @@
;;
ld8 rCRIFS=[r16],16 // load cr.ifs
ld8 rARUNAT=[r17],16 // load ar.unat
+ cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs
;;
ld8 rARPFS=[r16],16 // load ar.pfs
ld8 rARRSC=[r17],16 // load ar.rsc
;;
ld8 rARRNAT=[r16],16 // load ar.rnat (may be garbage)
- ld8 rARBSPSTORE=[r17],16 // load ar.bspstore (may be garbage)
+ ld8 rARBSPSTORE=[r17],16 // load ar.bspstore (may be garbage)
;;
ld8 rARPR=[r16],16 // load predicates
ld8 rB6=[r17],16 // load b6
@@ -707,15 +693,17 @@
;;
ld8.fill r2=[r16],16
ld8.fill r3=[r17],16
+ extr.u r19=rCRIPSR,32,2 // extract ps.cpl
;;
ld8.fill r12=[r16],16
ld8.fill r13=[r17],16
- extr.u r19=rCRIPSR,32,2 // extract ps.cpl
+(pSys) shr.u r18=r18,16 // get size of existing "dirty" partition
;;
- ld8.fill r14=[r16],16
- ld8.fill r15=[r17],16
+ ld8.fill r14=[r16]
+ ld8.fill r15=[r17]
cmp.eq p6,p7=r0,r19 // are we returning to kernel mode? (psr.cpl=0)
;;
+ mov r16=ar.bsp // get existing backing store pointer
mov b6=rB6
mov ar.pfs=rARPFS
(p6) br.cond.dpnt.few skip_rbs_switch
@@ -724,47 +712,34 @@
* Restore user backing store.
*
* NOTE: alloc, loadrs, and cover can't be predicated.
- *
- * XXX This needs some scheduling/tuning once we believe it
- * really does work as intended.
*/
- mov r16=ar.bsp // get existing backing store pointer
(pNonSys) br.cond.dpnt.few dont_preserve_current_frame
cover // add current frame into dirty partition
;;
- mov rCRIFS=cr.ifs // fetch the cr.ifs value that "cover" produced
mov r17=ar.bsp // get new backing store pointer
+ sub r18=r16,r18 // krbs = old bsp - size of dirty partition
+ cmp.ne p9,p0=r0,r0 // clear p9 to skip restore of cr.ifs
;;
- sub r16=r17,r16 // calculate number of bytes that were added to rbs
- ;;
- shl r16=r16,16 // shift additional frame size into position for loadrs
+ sub r18=r17,r18 // calculate number of bytes that were added to rbs
;;
- add r18=r16,r18 // adjust the loadrs value
+ shl r18=r18,16 // shift size of dirty partition into loadrs position
;;
dont_preserve_current_frame:
- alloc r16=ar.pfs,0,0,0,0 // drop the current call frame (noop for syscalls)
- ;;
+ alloc r17=ar.pfs,0,0,0,0 // drop the current call frame (noop for syscalls)
mov ar.rsc=r18 // load ar.rsc to be used for "loadrs"
-#ifdef CONFIG_IA32_SUPPORT
- tbit.nz p6,p0=rCRIPSR,IA64_PSR_IS_BIT
- ;;
-(p6) mov ar.rsc=r0 // returning to IA32 mode
-#endif
;;
loadrs
;;
- mov ar.bspstore=rARBSPSTORE
- ;;
- mov ar.rnat=rARRNAT // must happen with RSE in lazy mode
-
skip_rbs_switch:
+(p7) mov ar.bspstore=rARBSPSTORE
+(p9) mov cr.ifs=rCRIFS
+ mov cr.ipsr=rCRIPSR
+ mov cr.iip=rCRIIP
+ ;;
+(p7) mov ar.rnat=rARRNAT // must happen with RSE in lazy mode
mov ar.rsc=rARRSC
mov ar.unat=rARUNAT
- mov cr.ifs=rCRIFS // restore cr.ifs only if not a (synchronous) syscall
mov pr=rARPR,-1
- mov cr.iip=rCRIIP
- mov cr.ipsr=rCRIPSR
- ;;
rfi;; // must be last instruction in an insn group
END(ia64_leave_kernel)

@@ -904,7 +879,7 @@
(pNonSys) mov out2=0 // out2=0 => not a syscall
br.call.sptk.few rp=ia64_do_signal
.ret16: // restore the switch stack (ptrace may have modified it)
- DO_LOAD_SWITCH_STACK( )
+ DO_LOAD_SWITCH_STACK
br.ret.sptk.many rp
#endif /* !CONFIG_IA64_NEW_UNWIND */
END(handle_signal_delivery)
@@ -944,7 +919,7 @@
adds out2\x16,sp // out1=&sigscratch
br.call.sptk.many rp=ia64_rt_sigsuspend
.ret18: // restore the switch stack (ptrace may have modified it)
- DO_LOAD_SWITCH_STACK( )
+ DO_LOAD_SWITCH_STACK
br.ret.sptk.many rp
#endif /* !CONFIG_IA64_NEW_UNWIND */
END(sys_rt_sigsuspend)
@@ -957,7 +932,7 @@
PT_REGS_SAVES(16)
adds sp=-16,sp
.body
- cmp.eq pNonSys,p0=r0,r0 // sigreturn isn't a normal syscall...
+ cmp.eq pNonSys,pSys=r0,r0 // sigreturn isn't a normal syscall...
;;
adds out0\x16,sp // out0 = &sigscratch
br.call.sptk.few rp=ia64_rt_sigreturn
@@ -979,7 +954,7 @@
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
- cmp.eq pNonSys,p0=r0,r0 // sigreturn isn't a normal syscall...
+ cmp.eq pNonSys,pSys=r0,r0 // sigreturn isn't a normal syscall...
;;
UNW(.body)

@@ -1002,13 +977,12 @@
// r16 = fake ar.pfs, we simply need to make sure
// privilege is still 0
//
- PT_REGS_UNWIND_INFO(0)
mov r16=r0
UNW(.prologue)
DO_SAVE_SWITCH_STACK
br.call.sptk.few rp=ia64_handle_unaligned // stack frame setup in ivt
.ret21: .body
- DO_LOAD_SWITCH_STACK(PT_REGS_UNWIND_INFO(0))
+ DO_LOAD_SWITCH_STACK
br.cond.sptk.many rp // goes to ia64_leave_kernel
END(ia64_prepare_handle_unaligned)

diff -urN linux-davidm/arch/ia64/kernel/entry.h linux-2.4.0-lia/arch/ia64/kernel/entry.h
--- linux-davidm/arch/ia64/kernel/entry.h Thu Jun 22 07:09:44 2000
+++ linux-2.4.0-lia/arch/ia64/kernel/entry.h Thu Jan 25 15:08:35 2001
@@ -55,11 +55,10 @@
br.cond.sptk.many save_switch_stack; \
1:

-#define DO_LOAD_SWITCH_STACK(extra) \
+#define DO_LOAD_SWITCH_STACK \
movl r28\x1f; \
;; \
mov b7=r28; \
br.cond.sptk.many load_switch_stack; \
1: UNW(.restore sp); \
- extra; \
adds sp=IA64_SWITCH_STACK_SIZE,sp
diff -urN linux-davidm/arch/ia64/kernel/iosapic.c linux-2.4.0-lia/arch/ia64/kernel/iosapic.c
--- linux-davidm/arch/ia64/kernel/iosapic.c Thu Jan 4 22:40:10 2001
+++ linux-2.4.0-lia/arch/ia64/kernel/iosapic.c Thu Jan 25 15:40:04 2001
@@ -137,12 +137,6 @@
(dmode << IOSAPIC_DELIVERY_SHIFT) |
vector);

-#ifdef CONFIG_IA64_AZUSA_HACKS
- /* set Flush Disable bit */
- if (addr != (char *) 0xc0000000fec00000)
- low32 |= (1 << 17);
-#endif
-
/* dest contains both id and eid */
high32 = (dest << IOSAPIC_DEST_SHIFT);

diff -urN linux-davidm/arch/ia64/kernel/ivt.S linux-2.4.0-lia/arch/ia64/kernel/ivt.S
--- linux-davidm/arch/ia64/kernel/ivt.S Thu Jan 25 19:17:25 2001
+++ linux-2.4.0-lia/arch/ia64/kernel/ivt.S Thu Jan 25 15:41:48 2001
@@ -45,6 +45,12 @@
#include <asm/system.h>
#include <asm/unistd.h>

+#if 1
+# define PSR_DEFAULT_BITS psr.ac
+#else
+# define PSR_DEFAULT_BITS 0
+#endif
+
#define MINSTATE_VIRT /* needed by minstate.h */
#include "minstate.h"

@@ -184,15 +190,16 @@
* mode, walk the page table, and then re-execute the L3 PTE read
* and go on normally after that.
*/
-itlb_fault:
mov r16=cr.ifa // get virtual address
mov r29° // save b0
mov r31=pr // save predicates
+itlb_fault:
mov r17=cr.iha // get virtual address of L3 PTE
movl r30\x1f // load nested fault continuation point
;;
1: ld8 r18=[r17] // read L3 PTE
;;
+ mov b0=r29
tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared?
(p6) br.cond.spnt.many page_fault
;;
@@ -219,15 +226,16 @@
* mode, walk the page table, and then re-execute the L3 PTE read
* and go on normally after that.
*/
-dtlb_fault:
mov r16=cr.ifa // get virtual address
mov r29° // save b0
mov r31=pr // save predicates
+dtlb_fault:
mov r17=cr.iha // get virtual address of L3 PTE
movl r30\x1f // load nested fault continuation point
;;
1: ld8 r18=[r17] // read L3 PTE
;;
+ mov b0=r29
tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared?
(p6) br.cond.spnt.many page_fault
;;
@@ -261,6 +269,7 @@
(p8) thash r17=r16
;;
(p8) mov cr.iha=r17
+(p8) mov r29° // save b0
(p8) br.cond.dptk.many itlb_fault
#endif
extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl
@@ -296,6 +305,7 @@
(p8) thash r17=r16
;;
(p8) mov cr.iha=r17
+(p8) mov r29° // save b0
(p8) br.cond.dptk.many dtlb_fault
#endif
extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl
@@ -336,7 +346,7 @@
mov r9=cr.isr
adds r3=8,r2 // set up second base pointer
;;
- ssm psr.ic
+ ssm psr.ic | PSR_DEFAULT_BITS
;;
srlz.i // guarantee that interrupt collection is enabled
;;
@@ -399,7 +409,6 @@
shr.u r18=r16,PMD_SHIFT // shift L2 index into position
;;
ld8 r17=[r17] // fetch the L1 entry (may be 0)
- mov b0=r30
;;
(p7) cmp.eq p6,p7=r17,r0 // was L1 entry NULL?
dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry
@@ -409,8 +418,8 @@
;;
(p7) cmp.eq.or.andcm p6,p7=r17,r0 // was L2 entry NULL?
dep r17=r19,r17,3,(PAGE_SHIFT-3) // compute address of L3 page table entry
- ;;
(p6) br.cond.spnt.many page_fault
+ mov b0=r30
br.sptk.many b0 // return to continuation point
;;

@@ -613,8 +622,7 @@

SAVE_MIN // uses r31; defines r2:

- // turn interrupt collection back on:
- ssm psr.ic
+ ssm psr.ic | PSR_DEFAULT_BITS
;;
srlz.i // guarantee that interrupt collection is enabled
cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0
@@ -701,11 +709,12 @@
.align 1024
/////////////////////////////////////////////////////////////////////////////////////////
// 0x3000 Entry 12 (size 64 bundles) External Interrupt (4)
+interrupt:
mov r31=pr // prepare to save predicates
;;

SAVE_MIN_WITH_COVER // uses r31; defines r2 and r3
- ssm psr.ic // turn interrupt collection
+ ssm psr.ic | PSR_DEFAULT_BITS
;;
adds r3=8,r2 // set up second base pointer for SAVE_REST
srlz.i // ensure everybody knows psr.ic is back on
@@ -755,7 +764,7 @@
// The "alloc" can cause a mandatory store which could lead to
// an "Alt DTLB" fault which we can handle only if psr.ic is on.
//
- ssm psr.ic
+ ssm psr.ic | PSR_DEFAULT_BITS
;;
srlz.i // guarantee that interrupt collection is enabled
;;
@@ -801,7 +810,7 @@
SAVE_MIN
;;
mov r14=cr.isr
- ssm psr.ic
+ ssm psr.ic | PSR_DEFAULT_BITS
;;
srlz.i // guarantee that interrupt collection is enabled
;;
@@ -887,8 +896,7 @@
mov r8=cr.iim // get break immediate (must be done while psr.ic is off)
adds r3=8,r2 // set up second base pointer for SAVE_REST

- // turn interrupt collection back on:
- ssm psr.ic
+ ssm psr.ic | PSR_DEFAULT_BITS
;;
srlz.i // guarantee that interrupt collection is enabled
;;
@@ -926,7 +934,7 @@
// wouldn't get the state to recover.
//
mov r15=cr.ifa
- ssm psr.ic
+ ssm psr.ic | PSR_DEFAULT_BITS
;;
srlz.i // guarantee that interrupt collection is enabled
;;
@@ -974,7 +982,7 @@
mov r10=cr.iim
mov r11=cr.itir
;;
- ssm psr.ic
+ ssm psr.ic | PSR_DEFAULT_BITS
;;
srlz.i // guarantee that interrupt collection is enabled
;;
diff -urN linux-davidm/arch/ia64/kernel/mca_asm.S linux-2.4.0-lia/arch/ia64/kernel/mca_asm.S
--- linux-davidm/arch/ia64/kernel/mca_asm.S Thu Jan 4 22:40:10 2001
+++ linux-2.4.0-lia/arch/ia64/kernel/mca_asm.S Thu Jan 25 15:42:26 2001
@@ -8,6 +8,7 @@
// kstack, switch modes, jump to C INIT handler
//
#include <linux/config.h>
+
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/mca_asm.h>
diff -urN linux-davidm/arch/ia64/kernel/minstate.h linux-2.4.0-lia/arch/ia64/kernel/minstate.h
--- linux-davidm/arch/ia64/kernel/minstate.h Thu Jan 4 22:40:10 2001
+++ linux-2.4.0-lia/arch/ia64/kernel/minstate.h Thu Jan 25 15:42:35 2001
@@ -107,7 +107,7 @@
* Note that psr.ic is NOT turned on by this macro. This is so that
* we can pass interruption state as arguments to a handler.
*/
-#define DO_SAVE_MIN(COVER,EXTRA) \
+#define DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA) \
mov rARRSC=ar.rsc; \
mov rARPFS=ar.pfs; \
mov rR1=r1; \
@@ -116,14 +116,15 @@
mov rB6¶; /* rB6 = branch reg 6 */ \
mov rCRIIP=cr.iip; \
mov r1=ar.k6; /* r1 = current (physical) */ \
+ COVER; \
;; \
invala; \
extr.u r16=rCRIPSR,32,2; /* extract psr.cpl */ \
;; \
cmp.eq pKern,p7=r0,r16; /* are we in kernel mode already? (psr.cpl=0) */ \
/* switch from user to kernel RBS: */ \
- COVER; \
;; \
+ SAVE_IFS; \
MINSTATE_START_SAVE_MIN \
;; \
mov r16=r1; /* initialize first base pointer */ \
@@ -240,6 +241,6 @@
# define STOPS
#endif

-#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs,) STOPS
-#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs, mov r15=r19) STOPS
-#define SAVE_MIN DO_SAVE_MIN(mov rCRIFS=r0,) STOPS
+#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs,) STOPS
+#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs, mov r15=r19) STOPS
+#define SAVE_MIN DO_SAVE_MIN( , mov rCRIFS=r0, ) STOPS
diff -urN linux-davidm/arch/ia64/kernel/smp.c linux-2.4.0-lia/arch/ia64/kernel/smp.c
--- linux-davidm/arch/ia64/kernel/smp.c Thu Jan 25 19:17:25 2001
+++ linux-2.4.0-lia/arch/ia64/kernel/smp.c Thu Jan 25 17:19:30 2001
@@ -64,7 +64,6 @@
volatile int __cpu_physical_id[NR_CPUS] = { -1, }; /* Logical ID -> SAPIC ID */
int smp_num_cpus = 1;
volatile int smp_threads_ready; /* Set when the idlers are all forked */
-cycles_t cacheflush_time;
unsigned long ap_wakeup_vector = -1; /* External Int to use to wakeup AP's */

static volatile unsigned long cpu_callin_map;
diff -urN linux-davidm/arch/ia64/kernel/time.c linux-2.4.0-lia/arch/ia64/kernel/time.c
--- linux-davidm/arch/ia64/kernel/time.c Thu Jan 25 19:17:25 2001
+++ linux-2.4.0-lia/arch/ia64/kernel/time.c Thu Jan 25 17:21:22 2001
@@ -1,9 +1,9 @@
/*
* linux/arch/ia64/kernel/time.c
*
- * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
* Copyright (C) 1998-2000 Stephane Eranian <eranian@hpl.hp.com>
- * Copyright (C) 1999-2000 David Mosberger <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2001 David Mosberger <davidm@hpl.hp.com>
* Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
* Copyright (C) 1999-2000 VA Linux Systems
* Copyright (C) 1999-2000 Walt Drummond <drummond@valinux.com>
@@ -32,14 +32,6 @@

#endif

-static struct {
- unsigned long delta;
- union {
- unsigned long count;
- unsigned char pad[SMP_CACHE_BYTES];
- } next[NR_CPUS];
-} itm;
-
static void
do_profile (unsigned long ip)
{
@@ -82,7 +74,7 @@
unsigned long now = ia64_get_itc(), last_tick;
unsigned long elapsed_cycles, lost = jiffies - wall_jiffies;

- last_tick = (itm.next[smp_processor_id()].count - (lost+1)*itm.delta);
+ last_tick = (my_cpu_data.itm_next - (lost+1)*my_cpu_data.itm_delta);
# if 1
if ((long) (now - last_tick) < 0) {
printk("Yikes: now < last_tick (now=0x%lx,last_tick=%lx)! No can do.\n",
@@ -153,7 +145,7 @@
int cpu = smp_processor_id();
unsigned long new_itm;

- new_itm = itm.next[cpu].count;
+ new_itm = cpu_data[cpu].itm_next;

if (!time_after(ia64_get_itc(), new_itm))
printk("Oops: timer tick before it's due (itc=%lx,itm=%lx)\n",
@@ -183,8 +175,8 @@
write_unlock(&xtime_lock);
}

- new_itm += itm.delta;
- itm.next[cpu].count = new_itm;
+ new_itm += cpu_data[cpu].itm_delta;
+ cpu_data[cpu].itm_next = new_itm;
if (time_after(new_itm, ia64_get_itc()))
break;
}
@@ -197,8 +189,8 @@
* turn would let our clock run too fast (with the potentially
* devastating effect of losing monotony of time).
*/
- while (!time_after(new_itm, ia64_get_itc() + itm.delta/2))
- new_itm += itm.delta;
+ while (!time_after(new_itm, ia64_get_itc() + cpu_data[cpu].itm_delta/2))
+ new_itm += cpu_data[cpu].itm_delta;
ia64_set_itm(new_itm);
}

@@ -219,16 +211,29 @@
* Encapsulate access to the itm structure for SMP.
*/
void __init
-ia64_cpu_local_tick(void)
+ia64_cpu_local_tick (void)
{
+ int cpu = smp_processor_id();
+ unsigned long shift = 0, delta;
+
#ifdef CONFIG_IA64_SOFTSDV_HACKS
ia64_set_itc(0);
#endif

/* arrange for the cycle counter to generate a timer interrupt: */
ia64_set_itv(TIMER_IRQ);
- itm.next[smp_processor_id()].count = ia64_get_itc() + itm.delta;
- ia64_set_itm(itm.next[smp_processor_id()].count);
+
+ delta = cpu_data[cpu].itm_delta;
+ /*
+ * Stagger the timer tick for each CPU so they don't occur all at (almost) the
+ * same time:
+ */
+ if (cpu) {
+ unsigned long hi = 1UL << ia64_fls(cpu);
+ shift = (2*(cpu - hi) + 1) * delta/hi/2;
+ }
+ cpu_data[cpu].itm_next = ia64_get_itc() + delta + shift;
+ ia64_set_itm(cpu_data[cpu].itm_next);
}

void __init
@@ -236,6 +241,7 @@
{
unsigned long platform_base_freq, itc_freq, drift;
struct pal_freq_ratio itc_ratio, proc_ratio;
+ int cpu = smp_processor_id();
long status;

/*
@@ -275,16 +281,16 @@
itc_ratio.num = 1; /* avoid division by zero */

itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den;
- itm.delta = itc_freq / HZ;
+ cpu_data[cpu].itm_delta = (itc_freq + HZ/2) / HZ;
printk("CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, ITC freq=%lu.%03luMHz\n",
smp_processor_id(),
platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000,
itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000);

- my_cpu_data.proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den;
- my_cpu_data.itc_freq = itc_freq;
- my_cpu_data.cyc_per_usec = itc_freq / 1000000;
- my_cpu_data.usec_per_cyc = (1000000UL << IA64_USEC_PER_CYC_SHIFT) / itc_freq;
+ cpu_data[cpu].proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den;
+ cpu_data[cpu].itc_freq = itc_freq;
+ cpu_data[cpu].cyc_per_usec = (itc_freq + 500000) / 1000000;
+ cpu_data[cpu].usec_per_cyc = ((1000000UL<<IA64_USEC_PER_CYC_SHIFT) + itc_freq/2)/itc_freq;

/* Setup the CPU local timer tick */
ia64_cpu_local_tick();
diff -urN linux-davidm/arch/ia64/kernel/unaligned.c linux-2.4.0-lia/arch/ia64/kernel/unaligned.c
--- linux-davidm/arch/ia64/kernel/unaligned.c Thu Jan 4 22:40:10 2001
+++ linux-2.4.0-lia/arch/ia64/kernel/unaligned.c Thu Jan 25 17:21:49 2001
@@ -1,8 +1,11 @@
/*
* Architecture-specific unaligned trap handling.
*
- * Copyright (C) 1999-2000 Hewlett-Packard Co
+ * Copyright (C) 1999-2001 Hewlett-Packard Co
* Copyright (C) 1999-2000 Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * 2001/01/17 Add support emulation of unaligned kernel accesses.
*/
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -17,14 +20,28 @@
#undef DEBUG_UNALIGNED_TRAP

#ifdef DEBUG_UNALIGNED_TRAP
-#define DPRINT(a) { printk("%s, line %d: ", __FUNCTION__, __LINE__); printk a;}
+# define DPRINT(a...) do { printk("%s.%u: ", __FUNCTION__, __LINE__); printk (a); } while (0)
+# define DDUMP(str,vp,len) dump(str, vp, len)
+
+static void
+dump (const char *str, void *vp, size_t len)
+{
+ unsigned char *cp = vp;
+ int i;
+
+ printk("%s", str);
+ for (i = 0; i < len; ++i)
+ printk (" %02x", *cp++);
+ printk("\n");
+}
#else
-#define DPRINT(a)
+# define DPRINT(a...)
+# define DDUMP(str,vp,len)
#endif

#define IA64_FIRST_STACKED_GR 32
#define IA64_FIRST_ROTATING_FR 32
-#define SIGN_EXT9 __IA64_UL(0xffffffffffffff00)
+#define SIGN_EXT9 0xffffffffffffff00ul

/*
* For M-unit:
@@ -40,7 +57,8 @@
* mask ([40:32]) using 9 bits. The 'e' comes from the fact that we defer
* checking the m-bit until later in the load/store emulation.
*/
-#define IA64_OPCODE_MASK 0x1ef00000000
+#define IA64_OPCODE_MASK 0x1ef
+#define IA64_OPCODE_SHIFT 32

/*
* Table C-28 Integer Load/Store
@@ -50,18 +68,18 @@
* ld8.fill, st8.fill MUST be aligned because the RNATs are based on
* the address (bits [8:3]), so we must failed.
*/
-#define LD_OP 0x08000000000
-#define LDS_OP 0x08100000000
-#define LDA_OP 0x08200000000
-#define LDSA_OP 0x08300000000
-#define LDBIAS_OP 0x08400000000
-#define LDACQ_OP 0x08500000000
+#define LD_OP 0x080
+#define LDS_OP 0x081
+#define LDA_OP 0x082
+#define LDSA_OP 0x083
+#define LDBIAS_OP 0x084
+#define LDACQ_OP 0x085
/* 0x086, 0x087 are not relevant */
-#define LDCCLR_OP 0x08800000000
-#define LDCNC_OP 0x08900000000
-#define LDCCLRACQ_OP 0x08a00000000
-#define ST_OP 0x08c00000000
-#define STREL_OP 0x08d00000000
+#define LDCCLR_OP 0x088
+#define LDCNC_OP 0x089
+#define LDCCLRACQ_OP 0x08a
+#define ST_OP 0x08c
+#define STREL_OP 0x08d
/* 0x08e,0x8f are not relevant */

/*
@@ -79,32 +97,32 @@
* ld8.fill, st8.fill must be aligned because the Nat register are based on
* the address, so we must fail and the program must be fixed.
*/
-#define LD_IMM_OP 0x0a000000000
-#define LDS_IMM_OP 0x0a100000000
-#define LDA_IMM_OP 0x0a200000000
-#define LDSA_IMM_OP 0x0a300000000
-#define LDBIAS_IMM_OP 0x0a400000000
-#define LDACQ_IMM_OP 0x0a500000000
+#define LD_IMM_OP 0x0a0
+#define LDS_IMM_OP 0x0a1
+#define LDA_IMM_OP 0x0a2
+#define LDSA_IMM_OP 0x0a3
+#define LDBIAS_IMM_OP 0x0a4
+#define LDACQ_IMM_OP 0x0a5
/* 0x0a6, 0xa7 are not relevant */
-#define LDCCLR_IMM_OP 0x0a800000000
-#define LDCNC_IMM_OP 0x0a900000000
-#define LDCCLRACQ_IMM_OP 0x0aa00000000
-#define ST_IMM_OP 0x0ac00000000
-#define STREL_IMM_OP 0x0ad00000000
+#define LDCCLR_IMM_OP 0x0a8
+#define LDCNC_IMM_OP 0x0a9
+#define LDCCLRACQ_IMM_OP 0x0aa
+#define ST_IMM_OP 0x0ac
+#define STREL_IMM_OP 0x0ad
/* 0x0ae,0xaf are not relevant */

/*
* Table C-32 Floating-point Load/Store
*/
-#define LDF_OP 0x0c000000000
-#define LDFS_OP 0x0c100000000
-#define LDFA_OP 0x0c200000000
-#define LDFSA_OP 0x0c300000000
+#define LDF_OP 0x0c0
+#define LDFS_OP 0x0c1
+#define LDFA_OP 0x0c2
+#define LDFSA_OP 0x0c3
/* 0x0c6 is irrelevant */
-#define LDFCCLR_OP 0x0c800000000
-#define LDFCNC_OP 0x0c900000000
+#define LDFCCLR_OP 0x0c8
+#define LDFCNC_OP 0x0c9
/* 0x0cb is irrelevant */
-#define STF_OP 0x0cc00000000
+#define STF_OP 0x0cc

/*
* Table C-33 Floating-point Load +Reg
@@ -116,14 +134,14 @@
/*
* Table C-34 Floating-point Load/Store +Imm
*/
-#define LDF_IMM_OP 0x0e000000000
-#define LDFS_IMM_OP 0x0e100000000
-#define LDFA_IMM_OP 0x0e200000000
-#define LDFSA_IMM_OP 0x0e300000000
+#define LDF_IMM_OP 0x0e0
+#define LDFS_IMM_OP 0x0e1
+#define LDFA_IMM_OP 0x0e2
+#define LDFSA_IMM_OP 0x0e3
/* 0x0e6 is irrelevant */
-#define LDFCCLR_IMM_OP 0x0e800000000
-#define LDFCNC_IMM_OP 0x0e900000000
-#define STF_IMM_OP 0x0ec00000000
+#define LDFCCLR_IMM_OP 0x0e8
+#define LDFCNC_IMM_OP 0x0e9
+#define STF_IMM_OP 0x0ec

typedef struct {
unsigned long qp:6; /* [0:5] */
@@ -255,150 +273,148 @@
}

static void
-set_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long val, int nat)
+set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, int nat)
{
- struct switch_stack *sw = (struct switch_stack *)regs - 1;
- unsigned long *kbs = ((unsigned long *)current) + IA64_RBS_OFFSET/8;
+ struct switch_stack *sw = (struct switch_stack *) regs - 1;
+ unsigned long *bsp, *bspstore, *addr, *rnat_addr, *ubs_end;
+ unsigned long *kbs = (void *) current + IA64_RBS_OFFSET;
+ unsigned long rnats, nat_mask;
unsigned long on_kbs;
- unsigned long *bsp, *bspstore, *addr, *ubs_end, *slot;
- unsigned long rnats;
- long nlocals;
+ long sof = (regs->cr_ifs) & 0x7f;

- /*
- * cr_ifs=[rv:ifm], ifm=[....:sof(6)]
- * nlocal=number of locals (in+loc) register of the faulting function
- */
- nlocals = (regs->cr_ifs) & 0x7f;
+ DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld\n",
+ r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f);

- DPRINT(("sw.bsptore=%lx pt.bspstore=%lx\n", sw->ar_bspstore, regs->ar_bspstore));
- DPRINT(("cr.ifs=%lx sof=%ld sol=%ld\n",
- regs->cr_ifs, regs->cr_ifs &0x7f, (regs->cr_ifs>>7)&0x7f));
+ if ((r1 - 32) >= sof) {
+ /* this should never happen, as the "rsvd register fault" has higher priority */
+ DPRINT("ignoring write to r%lu; only %lu registers are allocated!\n", r1, sof);
+ return;
+ }

- on_kbs = ia64_rse_num_regs(kbs, (unsigned long *)sw->ar_bspstore);
- bspstore = (unsigned long *)regs->ar_bspstore;
+ on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore);
+ addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + (r1 - 32));
+ if (addr >= kbs) {
+ /* the register is on the kernel backing store: easy... */
+ rnat_addr = ia64_rse_rnat_addr(addr);
+ if ((unsigned long) rnat_addr >= sw->ar_bspstore)
+ rnat_addr = &sw->ar_rnat;
+ nat_mask = 1UL << ia64_rse_slot_num(addr);

- DPRINT(("rse_slot_num=0x%lx\n",ia64_rse_slot_num((unsigned long *)sw->ar_bspstore)));
- DPRINT(("kbs=%p nlocals=%ld\n", (void *) kbs, nlocals));
- DPRINT(("bspstore next rnat slot %p\n",
- (void *) ia64_rse_rnat_addr((unsigned long *)sw->ar_bspstore)));
- DPRINT(("on_kbs=%ld rnats=%ld\n",
- on_kbs, ((sw->ar_bspstore-(unsigned long)kbs)>>3) - on_kbs));
+ *addr = val;
+ if (nat)
+ *rnat_addr |= nat_mask;
+ else
+ *rnat_addr &= ~nat_mask;
+ return;
+ }

/*
- * See get_rse_reg() for an explanation on the following instructions
+ * Avoid using user_mode() here: with "epc", we cannot use the privilege level to
+ * infer whether the interrupt task was running on the kernel backing store.
*/
+ if (regs->r12 >= TASK_SIZE) {
+ DPRINT("ignoring kernel write to r%lu; register isn't on the RBS!", r1);
+ return;
+ }
+
+ bspstore = (unsigned long *) regs->ar_bspstore;
ubs_end = ia64_rse_skip_regs(bspstore, on_kbs);
- bsp = ia64_rse_skip_regs(ubs_end, -nlocals);
- addr = slot = ia64_rse_skip_regs(bsp, r1 - 32);
+ bsp = ia64_rse_skip_regs(ubs_end, -sof);
+ addr = ia64_rse_skip_regs(bsp, r1 - 32);

- DPRINT(("ubs_end=%p bsp=%p addr=%p slot=0x%lx\n",
- (void *) ubs_end, (void *) bsp, (void *) addr, ia64_rse_slot_num(addr)));
+ DPRINT("ubs_end=%p bsp=%p addr=%px\n", (void *) ubs_end, (void *) bsp, (void *) addr);

- ia64_poke(regs, current, (unsigned long)addr, val);
+ ia64_poke(regs, current, (unsigned long) addr, val);

- /*
- * addr will now contain the address of the RNAT for the register
- */
- addr = ia64_rse_rnat_addr(addr);
+ rnat_addr = ia64_rse_rnat_addr(addr);

- ia64_peek(regs, current, (unsigned long)addr, &rnats);
- DPRINT(("rnat @%p = 0x%lx nat=%d rnatval=%lx\n",
- (void *) addr, rnats, nat, rnats &ia64_rse_slot_num(slot)));
-
- if (nat) {
- rnats |= __IA64_UL(1) << ia64_rse_slot_num(slot);
- } else {
- rnats &= ~(__IA64_UL(1) << ia64_rse_slot_num(slot));
- }
- ia64_poke(regs, current, (unsigned long)addr, rnats);
+ ia64_peek(regs, current, (unsigned long) rnat_addr, &rnats);
+ DPRINT("rnat @%p = 0x%lx nat=%d old nat=%ld\n",
+ (void *) rnat_addr, rnats, nat, (rnats >> ia64_rse_slot_num(addr)) & 1);
+
+ nat_mask = 1UL << ia64_rse_slot_num(addr);
+ if (nat)
+ rnats |= nat_mask;
+ else
+ rnats &= ~nat_mask;
+ ia64_poke(regs, current, (unsigned long) rnat_addr, rnats);

- DPRINT(("rnat changed to @%p = 0x%lx\n", (void *) addr, rnats));
+ DPRINT("rnat changed to @%p = 0x%lx\n", (void *) rnat_addr, rnats);
}

static void
-get_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long *val, int *nat)
+get_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long *val, int *nat)
{
- struct switch_stack *sw = (struct switch_stack *)regs - 1;
- unsigned long *kbs = (unsigned long *)current + IA64_RBS_OFFSET/8;
+ struct switch_stack *sw = (struct switch_stack *) regs - 1;
+ unsigned long *bsp, *addr, *rnat_addr, *ubs_end, *bspstore;
+ unsigned long *kbs = (void *) current + IA64_RBS_OFFSET;
+ unsigned long rnats, nat_mask;
unsigned long on_kbs;
- long nlocals;
- unsigned long *bsp, *addr, *ubs_end, *slot, *bspstore;
- unsigned long rnats;
+ long sof = (regs->cr_ifs) & 0x7f;

- /*
- * cr_ifs=[rv:ifm], ifm=[....:sof(6)]
- * nlocals=number of local registers in the faulting function
- */
- nlocals = (regs->cr_ifs) & 0x7f;
+ DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld\n",
+ r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f);

- /*
- * save_switch_stack does a flushrs and saves bspstore.
- * on_kbs = actual number of registers saved on kernel backing store
- * (taking into accound potential RNATs)
- *
- * Note that this number can be greater than nlocals if the dirty
- * parititions included more than one stack frame at the time we
- * switched to KBS
- */
- on_kbs = ia64_rse_num_regs(kbs, (unsigned long *)sw->ar_bspstore);
- bspstore = (unsigned long *)regs->ar_bspstore;
+ if ((r1 - 32) >= sof) {
+ /* this should never happen, as the "rsvd register fault" has higher priority */
+ DPRINT("ignoring read from r%lu; only %lu registers are allocated!\n", r1, sof);
+ return;
+ }
+
+ on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore);
+ addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + (r1 - 32));
+ if (addr >= kbs) {
+ /* the register is on the kernel backing store: easy... */
+ *val = *addr;
+ if (nat) {
+ rnat_addr = ia64_rse_rnat_addr(addr);
+ if ((unsigned long) rnat_addr >= sw->ar_bspstore)
+ rnat_addr = &sw->ar_rnat;
+ nat_mask = 1UL << ia64_rse_slot_num(addr);
+ *nat = (*rnat_addr & nat_mask) != 0;
+ }
+ return;
+ }

/*
- * To simplify the logic, we calculate everything as if there was only
- * one backing store i.e., the user one (UBS). We let it to peek/poke
- * to figure out whether the register we're looking for really is
- * on the UBS or on KBS.
- *
- * regs->ar_bsptore = address of last register saved on UBS (before switch)
- *
- * ubs_end = virtual end of the UBS (if everything had been spilled there)
- *
- * We know that ubs_end is the point where the last register on the
- * stack frame we're interested in as been saved. So we need to walk
- * our way backward to figure out what the BSP "was" for that frame,
- * this will give us the location of r32.
- *
- * bsp = "virtual UBS" address of r32 for our frame
- *
- * Finally, get compute the address of the register we're looking for
- * using bsp as our base (move up again).
- *
- * Please note that in our case, we know that the register is necessarily
- * on the KBS because we are only interested in the current frame at the moment
- * we got the exception i.e., bsp is not changed until we switch to KBS.
+ * Avoid using user_mode() here: with "epc", we cannot use the privilege level to
+ * infer whether the interrupt task was running on the kernel backing store.
*/
+ if (regs->r12 >= TASK_SIZE) {
+ DPRINT("ignoring kernel read of r%lu; register isn't on the RBS!", r1);
+ return;
+ }
+
+ bspstore = (unsigned long *)regs->ar_bspstore;
ubs_end = ia64_rse_skip_regs(bspstore, on_kbs);
- bsp = ia64_rse_skip_regs(ubs_end, -nlocals);
- addr = slot = ia64_rse_skip_regs(bsp, r1 - 32);
+ bsp = ia64_rse_skip_regs(ubs_end, -sof);
+ addr = ia64_rse_skip_regs(bsp, r1 - 32);

- DPRINT(("ubs_end=%p bsp=%p addr=%p slot=0x%lx\n",
- (void *) ubs_end, (void *) bsp, (void *) addr, ia64_rse_slot_num(addr)));
+ DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr);

- ia64_peek(regs, current, (unsigned long)addr, val);
+ ia64_peek(regs, current, (unsigned long) addr, val);

- /*
- * addr will now contain the address of the RNAT for the register
- */
- addr = ia64_rse_rnat_addr(addr);
+ if (nat) {
+ rnat_addr = ia64_rse_rnat_addr(addr);
+ nat_mask = 1UL << ia64_rse_slot_num(addr);

- ia64_peek(regs, current, (unsigned long)addr, &rnats);
- DPRINT(("rnat @%p = 0x%lx\n", (void *) addr, rnats));
-
- if (nat)
- *nat = rnats >> ia64_rse_slot_num(slot) & 0x1;
+ DPRINT("rnat @%p = 0x%lx\n", (void *) rnat_addr, rnats);
+
+ ia64_peek(regs, current, (unsigned long) rnat_addr, &rnats);
+ *nat = (rnats & nat_mask) != 0;
+ }
}

static void
-setreg(unsigned long regnum, unsigned long val, int nat, struct pt_regs *regs)
+setreg (unsigned long regnum, unsigned long val, int nat, struct pt_regs *regs)
{
- struct switch_stack *sw = (struct switch_stack *)regs -1;
+ struct switch_stack *sw = (struct switch_stack *) regs - 1;
unsigned long addr;
unsigned long bitmask;
unsigned long *unat;

-
/*
* First takes care of stacked registers
*/
@@ -422,8 +438,8 @@
addr = (unsigned long)regs;
unat = &sw->caller_unat;
}
- DPRINT(("tmp_base=%lx switch_stack=%s offset=%d\n",
- addr, unat=&sw->ar_unat ? "yes":"no", GR_OFFS(regnum)));
+ DPRINT("tmp_base=%lx switch_stack=%s offset=%d\n",
+ addr, unat=&sw->ar_unat ? "yes":"no", GR_OFFS(regnum));
/*
* add offset from base of struct
* and do it !
@@ -436,20 +452,20 @@
* We need to clear the corresponding UNAT bit to fully emulate the load
* UNAT bit_pos = GR[r3]{8:3} form EAS-2.4
*/
- bitmask = __IA64_UL(1) << (addr >> 3 & 0x3f);
- DPRINT(("*0x%lx=0x%lx NaT=%d prev_unat @%p=%lx\n", addr, val, nat, (void *) unat, *unat));
+ bitmask = 1UL << (addr >> 3 & 0x3f);
+ DPRINT("*0x%lx=0x%lx NaT=%d prev_unat @%p=%lx\n", addr, val, nat, (void *) unat, *unat);
if (nat) {
*unat |= bitmask;
} else {
*unat &= ~bitmask;
}
- DPRINT(("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, (void *) unat,*unat));
+ DPRINT("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, (void *) unat,*unat);
}

#define IA64_FPH_OFFS(r) (r - IA64_FIRST_ROTATING_FR)

static void
-setfpreg(unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
+setfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
{
struct switch_stack *sw = (struct switch_stack *)regs - 1;
unsigned long addr;
@@ -478,7 +494,7 @@
addr = (unsigned long)regs;
}

- DPRINT(("tmp_base=%lx offset=%d\n", addr, FR_OFFS(regnum)));
+ DPRINT("tmp_base=%lx offset=%d\n", addr, FR_OFFS(regnum));

addr += FR_OFFS(regnum);
*(struct ia64_fpreg *)addr = *fpval;
@@ -498,21 +514,21 @@
* registers which can be used with stfX
*/
static inline void
-float_spill_f0(struct ia64_fpreg *final)
+float_spill_f0 (struct ia64_fpreg *final)
{
__asm__ __volatile__ ("stf.spill [%0]ð" :: "r"(final) : "memory");
}

static inline void
-float_spill_f1(struct ia64_fpreg *final)
+float_spill_f1 (struct ia64_fpreg *final)
{
__asm__ __volatile__ ("stf.spill [%0]ñ" :: "r"(final) : "memory");
}

static void
-getfpreg(unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
+getfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
{
- struct switch_stack *sw = (struct switch_stack *)regs -1;
+ struct switch_stack *sw = (struct switch_stack *) regs - 1;
unsigned long addr;

/*
@@ -546,8 +562,8 @@
addr = FR_IN_SW(regnum) ? (unsigned long)sw
: (unsigned long)regs;

- DPRINT(("is_sw=%d tmp_base=%lx offset=0x%x\n",
- FR_IN_SW(regnum), addr, FR_OFFS(regnum)));
+ DPRINT("is_sw=%d tmp_base=%lx offset=0x%x\n",
+ FR_IN_SW(regnum), addr, FR_OFFS(regnum));

addr += FR_OFFS(regnum);
*fpval = *(struct ia64_fpreg *)addr;
@@ -557,9 +573,9 @@

static void
-getreg(unsigned long regnum, unsigned long *val, int *nat, struct pt_regs *regs)
+getreg (unsigned long regnum, unsigned long *val, int *nat, struct pt_regs *regs)
{
- struct switch_stack *sw = (struct switch_stack *)regs -1;
+ struct switch_stack *sw = (struct switch_stack *) regs - 1;
unsigned long addr, *unat;

if (regnum >= IA64_FIRST_STACKED_GR) {
@@ -588,7 +604,7 @@
unat = &sw->caller_unat;
}

- DPRINT(("addr_base=%lx offset=0x%x\n", addr, GR_OFFS(regnum)));
+ DPRINT("addr_base=%lx offset=0x%x\n", addr, GR_OFFS(regnum));

addr += GR_OFFS(regnum);

@@ -602,7 +618,7 @@
}

static void
-emulate_load_updates(update_t type, load_store_t *ld, struct pt_regs *regs, unsigned long ifa)
+emulate_load_updates (update_t type, load_store_t ld, struct pt_regs *regs, unsigned long ifa)
{
/*
* IMPORTANT:
@@ -610,7 +626,7 @@
* not get to this point in the code but we keep this sanity check,
* just in case.
*/
- if (ld->x6_op = 1 || ld->x6_op = 3) {
+ if (ld.x6_op = 1 || ld.x6_op = 3) {
printk(KERN_ERR __FUNCTION__": register update on speculative load, error\n");
die_if_kernel("unaligned reference on specualtive load with register update\n",
regs, 30);
@@ -630,12 +646,12 @@
*
* form imm9: [13:19] contain the first 7 bits
*/
- imm = ld->x << 7 | ld->imm;
+ imm = ld.x << 7 | ld.imm;

/*
* sign extend (1+8bits) if m set
*/
- if (ld->m) imm |= SIGN_EXT9;
+ if (ld.m) imm |= SIGN_EXT9;

/*
* ifa = r3 and we know that the NaT bit on r3 was clear so
@@ -643,11 +659,11 @@
*/
ifa += imm;

- setreg(ld->r3, ifa, 0, regs);
+ setreg(ld.r3, ifa, 0, regs);

- DPRINT(("ld.x=%d ld.m=%d imm=%ld r3=0x%lx\n", ld->x, ld->m, imm, ifa));
+ DPRINT("ld.x=%d ld.m=%d imm=%ld r3=0x%lx\n", ld.x, ld.m, imm, ifa);

- } else if (ld->m) {
+ } else if (ld.m) {
unsigned long r2;
int nat_r2;

@@ -667,39 +683,24 @@
* never reach this code when trying to do a ldX.s.
* If we ever make it to here on an ldfX.s then
*/
- getreg(ld->imm, &r2, &nat_r2, regs);
+ getreg(ld.imm, &r2, &nat_r2, regs);

ifa += r2;

/*
* propagate Nat r2 -> r3
*/
- setreg(ld->r3, ifa, nat_r2, regs);
+ setreg(ld.r3, ifa, nat_r2, regs);

- DPRINT(("imm=%d r2=%ld r3=0x%lx nat_r2=%d\n",ld->imm, r2, ifa, nat_r2));
+ DPRINT("imm=%d r2=%ld r3=0x%lx nat_r2=%d\n",ld.imm, r2, ifa, nat_r2);
}
}

static int
-emulate_load_int(unsigned long ifa, load_store_t *ld, struct pt_regs *regs)
+emulate_load_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs)
{
- unsigned long val;
- unsigned int len = 1<< ld->x6_sz;
-
- /*
- * the macro supposes sequential access (which is the case)
- * if the first byte is an invalid address we return here. Otherwise
- * there is a guard page at the top of the user's address page and
- * the first access would generate a NaT consumption fault and return
- * with a SIGSEGV, which is what we want.
- *
- * Note: the first argument is ignored
- */
- if (access_ok(VERIFY_READ, (void *)ifa, len) < 0) {
- DPRINT(("verify area failed on %lx\n", ifa));
- return -1;
- }
+ unsigned int len = 1 << ld.x6_sz;

/*
* r0, as target, doesn't need to be checked because Illegal Instruction
@@ -710,42 +711,27 @@
*/

/*
- * ldX.a we don't try to emulate anything but we must
- * invalidate the ALAT entry.
+ * ldX.a we don't try to emulate anything but we must invalidate the ALAT entry.
* See comment below for explanation on how we handle ldX.a
*/
- if (ld->x6_op != 0x2) {
- /*
- * we rely on the macros in unaligned.h for now i.e.,
- * we let the compiler figure out how to read memory gracefully.
- *
- * We need this switch/case because the way the inline function
- * works. The code is optimized by the compiler and looks like
- * a single switch/case.
- */
- switch(len) {
- case 2:
- val = ia64_get_unaligned((void *)ifa, 2);
- break;
- case 4:
- val = ia64_get_unaligned((void *)ifa, 4);
- break;
- case 8:
- val = ia64_get_unaligned((void *)ifa, 8);
- break;
- default:
- DPRINT(("unknown size: x6=%d\n", ld->x6_sz));
- return -1;
- }
+ if (ld.x6_op != 0x2) {
+ unsigned long val = 0;

- setreg(ld->r1, val, 0, regs);
+ if (len != 2 && len != 4 && len != 8) {
+ DPRINT("unknown size: x6=%d\n", ld.x6_sz);
+ return -1;
+ }
+ /* this assumes little-endian byte-order: */
+ if (copy_from_user(&val, (void *) ifa, len))
+ return -1;
+ setreg(ld.r1, val, 0, regs);
}

/*
* check for updates on any kind of loads
*/
- if (ld->op = 0x5 || ld->m)
- emulate_load_updates(ld->op = 0x5 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa);
+ if (ld.op = 0x5 || ld.m)
+ emulate_load_updates(ld.op = 0x5 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa);

/*
* handling of various loads (based on EAS2.4):
@@ -753,7 +739,6 @@
* ldX.acq (ordered load):
* - acquire semantics would have been used, so force fence instead.
*
- *
* ldX.c.clr (check load and clear):
* - if we get to this handler, it's because the entry was not in the ALAT.
* Therefore the operation reverts to a normal load
@@ -831,45 +816,31 @@
* when the load has the .acq completer then
* use ordering fence.
*/
- if (ld->x6_op = 0x5 || ld->x6_op = 0xa)
+ if (ld.x6_op = 0x5 || ld.x6_op = 0xa)
mb();

/*
* invalidate ALAT entry in case of advanced load
*/
- if (ld->x6_op = 0x2)
- invala_gr(ld->r1);
+ if (ld.x6_op = 0x2)
+ invala_gr(ld.r1);

return 0;
}

static int
-emulate_store_int(unsigned long ifa, load_store_t *ld, struct pt_regs *regs)
+emulate_store_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs)
{
unsigned long r2;
- unsigned int len = 1<< ld->x6_sz;
+ unsigned int len = 1 << ld.x6_sz;

/*
- * the macro supposes sequential access (which is the case)
- * if the first byte is an invalid address we return here. Otherwise
- * there is a guard page at the top of the user's address page and
- * the first access would generate a NaT consumption fault and return
- * with a SIGSEGV, which is what we want.
- *
- * Note: the first argument is ignored
- */
- if (access_ok(VERIFY_WRITE, (void *)ifa, len) < 0) {
- DPRINT(("verify area failed on %lx\n",ifa));
- return -1;
- }
-
- /*
* if we get to this handler, Nat bits on both r3 and r2 have already
* been checked. so we don't need to do it
*
* extract the value to be stored
*/
- getreg(ld->imm, &r2, 0, regs);
+ getreg(ld.imm, &r2, 0, regs);

/*
* we rely on the macros in unaligned.h for now i.e.,
@@ -879,48 +850,43 @@
* works. The code is optimized by the compiler and looks like
* a single switch/case.
*/
- DPRINT(("st%d [%lx]=%lx\n", len, ifa, r2));
+ DPRINT("st%d [%lx]=%lx\n", len, ifa, r2);

- switch(len) {
- case 2:
- ia64_put_unaligned(r2, (void *)ifa, 2);
- break;
- case 4:
- ia64_put_unaligned(r2, (void *)ifa, 4);
- break;
- case 8:
- ia64_put_unaligned(r2, (void *)ifa, 8);
- break;
- default:
- DPRINT(("unknown size: x6=%d\n", ld->x6_sz));
- return -1;
+ if (len != 2 && len != 4 && len != 8) {
+ DPRINT("unknown size: x6=%d\n", ld.x6_sz);
+ return -1;
}
+
+ /* this assumes little-endian byte-order: */
+ if (copy_to_user((void *) ifa, &r2, len))
+ return -1;
+
/*
* stX [r3]=r2,imm(9)
*
* NOTE:
- * ld->r3 can never be r0, because r0 would not generate an
+ * ld.r3 can never be r0, because r0 would not generate an
* unaligned access.
*/
- if (ld->op = 0x5) {
+ if (ld.op = 0x5) {
unsigned long imm;

/*
* form imm9: [12:6] contain first 7bits
*/
- imm = ld->x << 7 | ld->r1;
+ imm = ld.x << 7 | ld.r1;
/*
* sign extend (8bits) if m set
*/
- if (ld->m) imm |= SIGN_EXT9;
+ if (ld.m) imm |= SIGN_EXT9;
/*
* ifa = r3 (NaT is necessarily cleared)
*/
ifa += imm;

- DPRINT(("imm=%lx r3=%lx\n", imm, ifa));
+ DPRINT("imm=%lx r3=%lx\n", imm, ifa);

- setreg(ld->r3, ifa, 0, regs);
+ setreg(ld.r3, ifa, 0, regs);
}
/*
* we don't have alat_invalidate_multiple() so we need
@@ -931,7 +897,7 @@
/*
* stX.rel: use fence instead of release
*/
- if (ld->x6_op = 0xd)
+ if (ld.x6_op = 0xd)
mb();

return 0;
@@ -940,7 +906,7 @@
/*
* floating point operations sizes in bytes
*/
-static const unsigned short float_fsz[4]={
+static const unsigned char float_fsz[4]={
16, /* extended precision (e) */
8, /* integer (8) */
4, /* single precision (s) */
@@ -948,72 +914,68 @@
};

static inline void
-mem2float_extended(struct ia64_fpreg *init, struct ia64_fpreg *final)
+mem2float_extended (struct ia64_fpreg *init, struct ia64_fpreg *final)
{
__asm__ __volatile__ ("ldfe f6=[%0];; stf.spill [%1]ö"
:: "r"(init), "r"(final) : "f6","memory");
}

static inline void
-mem2float_integer(struct ia64_fpreg *init, struct ia64_fpreg *final)
+mem2float_integer (struct ia64_fpreg *init, struct ia64_fpreg *final)
{
__asm__ __volatile__ ("ldf8 f6=[%0];; stf.spill [%1]ö"
:: "r"(init), "r"(final) : "f6","memory");
}

static inline void
-mem2float_single(struct ia64_fpreg *init, struct ia64_fpreg *final)
+mem2float_single (struct ia64_fpreg *init, struct ia64_fpreg *final)
{
__asm__ __volatile__ ("ldfs f6=[%0];; stf.spill [%1]ö"
:: "r"(init), "r"(final) : "f6","memory");
}

static inline void
-mem2float_double(struct ia64_fpreg *init, struct ia64_fpreg *final)
+mem2float_double (struct ia64_fpreg *init, struct ia64_fpreg *final)
{
__asm__ __volatile__ ("ldfd f6=[%0];; stf.spill [%1]ö"
:: "r"(init), "r"(final) : "f6","memory");
}

static inline void
-float2mem_extended(struct ia64_fpreg *init, struct ia64_fpreg *final)
+float2mem_extended (struct ia64_fpreg *init, struct ia64_fpreg *final)
{
__asm__ __volatile__ ("ldf.fill f6=[%0];; stfe [%1]ö"
:: "r"(init), "r"(final) : "f6","memory");
}

static inline void
-float2mem_integer(struct ia64_fpreg *init, struct ia64_fpreg *final)
+float2mem_integer (struct ia64_fpreg *init, struct ia64_fpreg *final)
{
__asm__ __volatile__ ("ldf.fill f6=[%0];; stf8 [%1]ö"
:: "r"(init), "r"(final) : "f6","memory");
}

static inline void
-float2mem_single(struct ia64_fpreg *init, struct ia64_fpreg *final)
+float2mem_single (struct ia64_fpreg *init, struct ia64_fpreg *final)
{
__asm__ __volatile__ ("ldf.fill f6=[%0];; stfs [%1]ö"
:: "r"(init), "r"(final) : "f6","memory");
}

static inline void
-float2mem_double(struct ia64_fpreg *init, struct ia64_fpreg *final)
+float2mem_double (struct ia64_fpreg *init, struct ia64_fpreg *final)
{
__asm__ __volatile__ ("ldf.fill f6=[%0];; stfd [%1]ö"
:: "r"(init), "r"(final) : "f6","memory");
}

static int
-emulate_load_floatpair(unsigned long ifa, load_store_t *ld, struct pt_regs *regs)
+emulate_load_floatpair (unsigned long ifa, load_store_t ld, struct pt_regs *regs)
{
struct ia64_fpreg fpr_init[2];
struct ia64_fpreg fpr_final[2];
- unsigned long len = float_fsz[ld->x6_sz];
+ unsigned long len = float_fsz[ld.x6_sz];

- if (access_ok(VERIFY_READ, (void *)ifa, len<<1) < 0) {
- DPRINT(("verify area failed on %lx\n", ifa));
- return -1;
- }
/*
* fr0 & fr1 don't need to be checked because Illegal Instruction
* faults have higher priority than unaligned faults.
@@ -1025,35 +987,27 @@
/*
* make sure we get clean buffers
*/
- memset(&fpr_init,0, sizeof(fpr_init));
- memset(&fpr_final,0, sizeof(fpr_final));
+ memset(&fpr_init, 0, sizeof(fpr_init));
+ memset(&fpr_final, 0, sizeof(fpr_final));

/*
* ldfpX.a: we don't try to emulate anything but we must
* invalidate the ALAT entry and execute updates, if any.
*/
- if (ld->x6_op != 0x2) {
- /*
- * does the unaligned access
- */
- memcpy(&fpr_init[0], (void *)ifa, len);
- memcpy(&fpr_init[1], (void *)(ifa+len), len);
+ if (ld.x6_op != 0x2) {
+ /* this assumes little-endian byte-order: */

- DPRINT(("ld.r1=%d ld.imm=%d x6_sz=%d\n", ld->r1, ld->imm, ld->x6_sz));
-#ifdef DEBUG_UNALIGNED_TRAP
- { int i; char *c = (char *)&fpr_init;
- printk("fpr_init= ");
- for(i=0; i < len<<1; i++ ) {
- printk("%02x ", c[i]&0xff);
- }
- printk("\n");
- }
-#endif
+ if (copy_from_user(&fpr_init[0], (void *) ifa, len)
+ || copy_from_user(&fpr_init[1], (void *) (ifa + len), len))
+ return -1;
+
+ DPRINT("ld.r1=%d ld.imm=%d x6_sz=%d\n", ld.r1, ld.imm, ld.x6_sz);
+ DDUMP("frp_init =", &fpr_init, 2*len);
/*
* XXX fixme
* Could optimize inlines by using ldfpX & 2 spills
*/
- switch( ld->x6_sz ) {
+ switch( ld.x6_sz ) {
case 0:
mem2float_extended(&fpr_init[0], &fpr_final[0]);
mem2float_extended(&fpr_init[1], &fpr_final[1]);
@@ -1071,15 +1025,7 @@
mem2float_double(&fpr_init[1], &fpr_final[1]);
break;
}
-#ifdef DEBUG_UNALIGNED_TRAP
- { int i; char *c = (char *)&fpr_final;
- printk("fpr_final= ");
- for(i=0; i < len<<1; i++ ) {
- printk("%02x ", c[i]&0xff);
- }
- printk("\n");
- }
-#endif
+ DDUMP("fpr_final =", &fpr_final, 2*len);
/*
* XXX fixme
*
@@ -1087,16 +1033,15 @@
* use the storage from the saved context i.e., the actual final
* destination (pt_regs, switch_stack or thread structure).
*/
- setfpreg(ld->r1, &fpr_final[0], regs);
- setfpreg(ld->imm, &fpr_final[1], regs);
+ setfpreg(ld.r1, &fpr_final[0], regs);
+ setfpreg(ld.imm, &fpr_final[1], regs);
}

/*
* Check for updates: only immediate updates are available for this
* instruction.
*/
- if (ld->m) {
-
+ if (ld.m) {
/*
* the immediate is implicit given the ldsz of the operation:
* single: 8 (2x4) and for all others it's 16 (2x8)
@@ -1109,43 +1054,32 @@
* as long as we don't come here with a ldfpX.s.
* For this reason we keep this sanity check
*/
- if (ld->x6_op = 1 || ld->x6_op = 3) {
- printk(KERN_ERR "%s: register update on speculative load pair, error\n",
- __FUNCTION__);
- }
-
+ if (ld.x6_op = 1 || ld.x6_op = 3)
+ printk(KERN_ERR __FUNCTION__": register update on speculative load pair, "
+ "error\n");

- setreg(ld->r3, ifa, 0, regs);
+ setreg(ld.r3, ifa, 0, regs);
}

/*
* Invalidate ALAT entries, if any, for both registers.
*/
- if (ld->x6_op = 0x2) {
- invala_fr(ld->r1);
- invala_fr(ld->imm);
+ if (ld.x6_op = 0x2) {
+ invala_fr(ld.r1);
+ invala_fr(ld.imm);
}
return 0;
}

static int
-emulate_load_float(unsigned long ifa, load_store_t *ld, struct pt_regs *regs)
+emulate_load_float (unsigned long ifa, load_store_t ld, struct pt_regs *regs)
{
struct ia64_fpreg fpr_init;
struct ia64_fpreg fpr_final;
- unsigned long len = float_fsz[ld->x6_sz];
+ unsigned long len = float_fsz[ld.x6_sz];

/*
- * check for load pair because our masking scheme is not fine grain enough
- if (ld->x = 1) return emulate_load_floatpair(ifa,ld,regs);
- */
-
- if (access_ok(VERIFY_READ, (void *)ifa, len) < 0) {
- DPRINT(("verify area failed on %lx\n", ifa));
- return -1;
- }
- /*
* fr0 & fr1 don't need to be checked because Illegal Instruction
* faults have higher priority than unaligned faults.
*
@@ -1153,7 +1087,6 @@
* unaligned reference.
*/

-
/*
* make sure we get clean buffers
*/
@@ -1165,27 +1098,16 @@
* invalidate the ALAT entry.
* See comments in ldX for descriptions on how the various loads are handled.
*/
- if (ld->x6_op != 0x2) {
-
- /*
- * does the unaligned access
- */
- memcpy(&fpr_init, (void *)ifa, len);
+ if (ld.x6_op != 0x2) {
+ if (copy_from_user(&fpr_init, (void *) ifa, len))
+ return -1;

- DPRINT(("ld.r1=%d x6_sz=%d\n", ld->r1, ld->x6_sz));
-#ifdef DEBUG_UNALIGNED_TRAP
- { int i; char *c = (char *)&fpr_init;
- printk("fpr_init= ");
- for(i=0; i < len; i++ ) {
- printk("%02x ", c[i]&0xff);
- }
- printk("\n");
- }
-#endif
+ DPRINT("ld.r1=%d x6_sz=%d\n", ld.r1, ld.x6_sz);
+ DDUMP("fpr_init =", &fpr_init, len);
/*
* we only do something for x6_op={0,8,9}
*/
- switch( ld->x6_sz ) {
+ switch( ld.x6_sz ) {
case 0:
mem2float_extended(&fpr_init, &fpr_final);
break;
@@ -1199,15 +1121,7 @@
mem2float_double(&fpr_init, &fpr_final);
break;
}
-#ifdef DEBUG_UNALIGNED_TRAP
- { int i; char *c = (char *)&fpr_final;
- printk("fpr_final= ");
- for(i=0; i < len; i++ ) {
- printk("%02x ", c[i]&0xff);
- }
- printk("\n");
- }
-#endif
+ DDUMP("fpr_final =", &fpr_final, len);
/*
* XXX fixme
*
@@ -1215,66 +1129,51 @@
* use the storage from the saved context i.e., the actual final
* destination (pt_regs, switch_stack or thread structure).
*/
- setfpreg(ld->r1, &fpr_final, regs);
+ setfpreg(ld.r1, &fpr_final, regs);
}

/*
* check for updates on any loads
*/
- if (ld->op = 0x7 || ld->m)
- emulate_load_updates(ld->op = 0x7 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa);
+ if (ld.op = 0x7 || ld.m)
+ emulate_load_updates(ld.op = 0x7 ? UPD_IMMEDIATE: UPD_REG, ld, regs, ifa);

/*
* invalidate ALAT entry in case of advanced floating point loads
*/
- if (ld->x6_op = 0x2)
- invala_fr(ld->r1);
+ if (ld.x6_op = 0x2)
+ invala_fr(ld.r1);

return 0;
}

static int
-emulate_store_float(unsigned long ifa, load_store_t *ld, struct pt_regs *regs)
+emulate_store_float (unsigned long ifa, load_store_t ld, struct pt_regs *regs)
{
struct ia64_fpreg fpr_init;
struct ia64_fpreg fpr_final;
- unsigned long len = float_fsz[ld->x6_sz];
+ unsigned long len = float_fsz[ld.x6_sz];

- /*
- * the macro supposes sequential access (which is the case)
- * if the first byte is an invalid address we return here. Otherwise
- * there is a guard page at the top of the user's address page and
- * the first access would generate a NaT consumption fault and return
- * with a SIGSEGV, which is what we want.
- *
- * Note: the first argument is ignored
- */
- if (access_ok(VERIFY_WRITE, (void *)ifa, len) < 0) {
- DPRINT(("verify area failed on %lx\n",ifa));
- return -1;
- }
-
/*
* make sure we get clean buffers
*/
memset(&fpr_init,0, sizeof(fpr_init));
memset(&fpr_final,0, sizeof(fpr_final));

-
/*
* if we get to this handler, Nat bits on both r3 and r2 have already
* been checked. so we don't need to do it
*
* extract the value to be stored
*/
- getfpreg(ld->imm, &fpr_init, regs);
+ getfpreg(ld.imm, &fpr_init, regs);
/*
* during this step, we extract the spilled registers from the saved
* context i.e., we refill. Then we store (no spill) to temporary
* aligned location
*/
- switch( ld->x6_sz ) {
+ switch( ld.x6_sz ) {
case 0:
float2mem_extended(&fpr_init, &fpr_final);
break;
@@ -1288,56 +1187,40 @@
float2mem_double(&fpr_init, &fpr_final);
break;
}
- DPRINT(("ld.r1=%d x6_sz=%d\n", ld->r1, ld->x6_sz));
-#ifdef DEBUG_UNALIGNED_TRAP
- { int i; char *c = (char *)&fpr_init;
- printk("fpr_init= ");
- for(i=0; i < len; i++ ) {
- printk("%02x ", c[i]&0xff);
- }
- printk("\n");
- }
- { int i; char *c = (char *)&fpr_final;
- printk("fpr_final= ");
- for(i=0; i < len; i++ ) {
- printk("%02x ", c[i]&0xff);
- }
- printk("\n");
- }
-#endif
+ DPRINT("ld.r1=%d x6_sz=%d\n", ld.r1, ld.x6_sz);
+ DDUMP("fpr_init =", &fpr_init, len);
+ DDUMP("fpr_final =", &fpr_final, len);

- /*
- * does the unaligned store
- */
- memcpy((void *)ifa, &fpr_final, len);
+ if (copy_to_user((void *) ifa, &fpr_final, len))
+ return -1;

/*
* stfX [r3]=r2,imm(9)
*
* NOTE:
- * ld->r3 can never be r0, because r0 would not generate an
+ * ld.r3 can never be r0, because r0 would not generate an
* unaligned access.
*/
- if (ld->op = 0x7) {
+ if (ld.op = 0x7) {
unsigned long imm;

/*
* form imm9: [12:6] contain first 7bits
*/
- imm = ld->x << 7 | ld->r1;
+ imm = ld.x << 7 | ld.r1;
/*
* sign extend (8bits) if m set
*/
- if (ld->m)
+ if (ld.m)
imm |= SIGN_EXT9;
/*
* ifa = r3 (NaT is necessarily cleared)
*/
ifa += imm;

- DPRINT(("imm=%lx r3=%lx\n", imm, ifa));
+ DPRINT("imm=%lx r3=%lx\n", imm, ifa);

- setreg(ld->r3, ifa, 0, regs);
+ setreg(ld.r3, ifa, 0, regs);
}
/*
* we don't have alat_invalidate_multiple() so we need
@@ -1348,129 +1231,96 @@
return 0;
}

-void
-ia64_handle_unaligned(unsigned long ifa, struct pt_regs *regs)
+/*
+ * Make sure we log the unaligned access, so that user/sysadmin can notice it and
+ * eventually fix the program. However, we don't want to do that for every access so we
+ * pace it with jiffies. This isn't really MP-safe, but it doesn't really have to be
+ * either...
+ */
+static int
+within_logging_rate_limit (void)
{
- static unsigned long unalign_count;
- static long last_time;
+ static unsigned long count, last_time;
+
+ if (count > 5 && jiffies - last_time > 5*HZ)
+ count = 0;
+ if (++count < 5) {
+ last_time = jiffies;
+ return 1;
+ }
+ return 0;

+}
+
+void
+ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs)
+{
+ const struct exception_table_entry *fix = NULL;
struct ia64_psr *ipsr = ia64_psr(regs);
- unsigned long *bundle_addr;
+ mm_segment_t old_fs = get_fs();
+ unsigned long bundle[2];
unsigned long opcode;
- unsigned long op;
- load_store_t *insn;
+ struct siginfo si;
+ union {
+ unsigned long l;
+ load_store_t insn;
+ } u;
int ret = -1;

- /*
- * Unaligned references in the kernel could come from unaligned
- * arguments to system calls. We fault the user process in
- * these cases and panic the kernel otherwise (the kernel should
- * be fixed to not make unaligned accesses).
- */
- if (!user_mode(regs)) {
- const struct exception_table_entry *fix;
-
- fix = search_exception_table(regs->cr_iip);
- if (fix) {
- regs->r8 = -EFAULT;
- if (fix->skip & 1) {
- regs->r9 = 0;
- }
- regs->cr_iip += ((long) fix->skip) & ~15;
- regs->cr_ipsr &= ~IA64_PSR_RI; /* clear exception slot number */
- return;
- }
- die_if_kernel("Unaligned reference while in kernel\n", regs, 30);
- /* NOT_REACHED */
- }
- /*
- * For now, we don't support user processes running big-endian
- * which do unaligned accesses
- */
if (ia64_psr(regs)->be) {
- struct siginfo si;
-
- printk(KERN_ERR "%s(%d): big-endian unaligned access %016lx (ip=%016lx) not "
- "yet supported\n",
- current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri);
-
- si.si_signo = SIGBUS;
- si.si_errno = 0;
- si.si_code = BUS_ADRALN;
- si.si_addr = (void *) ifa;
- force_sig_info(SIGBUS, &si, current);
- return;
+ /* we don't support big-endian accesses */
+ die_if_kernel("big-endian unaligned accesses are not supported", regs, 0);
+ goto force_sigbus;
}

- if (current->thread.flags & IA64_THREAD_UAC_SIGBUS) {
- struct siginfo si;
-
- si.si_signo = SIGBUS;
- si.si_errno = 0;
- si.si_code = BUS_ADRALN;
- si.si_addr = (void *) ifa;
- force_sig_info(SIGBUS, &si, current);
- return;
- }
+ /*
+ * Treat kernel accesses for which there is an exception handler entry the same as
+ * user-level unaligned accesses. Otherwise, a clever program could user could
+ * trick this handler into reading an arbitrary kernel addresses...
+ */
+ if (user_mode(regs) || (fix = search_exception_table(regs->cr_iip))) {
+ if ((current->thread.flags & IA64_THREAD_UAC_SIGBUS) != 0)
+ goto force_sigbus;

- if (!(current->thread.flags & IA64_THREAD_UAC_NOPRINT)) {
- /*
- * Make sure we log the unaligned access, so that
- * user/sysadmin can notice it and eventually fix the
- * program.
- *
- * We don't want to do that for every access so we
- * pace it with jiffies.
- */
- if (unalign_count > 5 && jiffies - last_time > 5*HZ)
- unalign_count = 0;
- if (++unalign_count < 5) {
+ if (!(current->thread.flags & IA64_THREAD_UAC_NOPRINT)
+ && within_logging_rate_limit())
+ {
char buf[200]; /* comm[] is at most 16 bytes... */
size_t len;

- last_time = jiffies;
- len = sprintf(buf, "%s(%d): unaligned access to 0x%016lx, ip=0x%016lx\n\r",
- current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri);
+ len = sprintf(buf, "%s(%d): unaligned access to 0x%016lx, "
+ "ip=0x%016lx\n\r", current->comm, current->pid,
+ ifa, regs->cr_iip + ipsr->ri);
tty_write_message(current->tty, buf);
buf[len-1] = '\0'; /* drop '\r' */
- printk("%s", buf); /* guard against command names containing %s!! */
+ printk("%s", buf); /* watch for command names containing %s */
}
+ } else {
+ if (within_logging_rate_limit())
+ printk("kernel unaligned access to 0x%016lx, ip=0x%016lx\n",
+ ifa, regs->cr_iip + ipsr->ri);
+ set_fs(KERNEL_DS);
}

- DPRINT(("iip=%lx ifa=%lx isr=%lx\n", regs->cr_iip, ifa, regs->cr_ipsr));
- DPRINT(("ISR.ei=%d ISR.sp=%d\n", ipsr->ri, ipsr->it));
+ DPRINT("iip=%lx ifa=%lx isr=%lx (ei=%d, sp=%d)\n",
+ regs->cr_iip, ifa, regs->cr_ipsr, ipsr->ri, ipsr->it);

- bundle_addr = (unsigned long *)(regs->cr_iip);
+ if (__copy_from_user(bundle, (void *) regs->cr_iip, 16))
+ goto failure;

/*
* extract the instruction from the bundle given the slot number
*/
- switch ( ipsr->ri ) {
- case 0: op = *bundle_addr >> 5;
- break;
-
- case 1: op = *bundle_addr >> 46 | (*(bundle_addr+1) & 0x7fffff)<<18;
- break;
-
- case 2: op = *(bundle_addr+1) >> 23;
- break;
- }
-
- insn = (load_store_t *)&op;
- opcode = op & IA64_OPCODE_MASK;
-
- DPRINT(("opcode=%lx ld.qp=%d ld.r1=%d ld.imm=%d ld.r3=%d ld.x=%d ld.hint=%d "
- "ld.x6=0x%x ld.m=%d ld.op=%d\n",
- opcode,
- insn->qp,
- insn->r1,
- insn->imm,
- insn->r3,
- insn->x,
- insn->hint,
- insn->x6_sz,
- insn->m,
- insn->op));
+ switch (ipsr->ri) {
+ case 0: u.l = (bundle[0] >> 5); break;
+ case 1: u.l = (bundle[0] >> 46) | (bundle[1] << 18); break;
+ case 2: u.l = (bundle[1] >> 23); break;
+ }
+ opcode = (u.l >> IA64_OPCODE_SHIFT) & IA64_OPCODE_MASK;
+
+ DPRINT("opcode=%lx ld.qp=%d ld.r1=%d ld.imm=%d ld.r3=%d ld.x=%d ld.hint=%d "
+ "ld.x6=0x%x ld.m=%d ld.op=%d\n", opcode, u.insn.qp, u.insn.r1, u.insn.imm,
+ u.insn.r3, u.insn.x, u.insn.hint, u.insn.x6_sz, u.insn.m, u.insn.op);

/*
* IMPORTANT:
@@ -1502,85 +1352,109 @@
* I would like to get rid of this switch case and do something
* more elegant.
*/
- switch(opcode) {
- case LDS_OP:
- case LDSA_OP:
- case LDS_IMM_OP:
- case LDSA_IMM_OP:
- case LDFS_OP:
- case LDFSA_OP:
- case LDFS_IMM_OP:
- /*
- * The instruction will be retried with defered exceptions
- * turned on, and we should get Nat bit installed
- *
- * IMPORTANT:
- * When PSR_ED is set, the register & immediate update
- * forms are actually executed even though the operation
- * failed. So we don't need to take care of this.
- */
- DPRINT(("forcing PSR_ED\n"));
- regs->cr_ipsr |= IA64_PSR_ED;
- return;
-
- case LD_OP:
- case LDA_OP:
- case LDBIAS_OP:
- case LDACQ_OP:
- case LDCCLR_OP:
- case LDCNC_OP:
- case LDCCLRACQ_OP:
- case LD_IMM_OP:
- case LDA_IMM_OP:
- case LDBIAS_IMM_OP:
- case LDACQ_IMM_OP:
- case LDCCLR_IMM_OP:
- case LDCNC_IMM_OP:
- case LDCCLRACQ_IMM_OP:
- ret = emulate_load_int(ifa, insn, regs);
- break;
- case ST_OP:
- case STREL_OP:
- case ST_IMM_OP:
- case STREL_IMM_OP:
- ret = emulate_store_int(ifa, insn, regs);
- break;
- case LDF_OP:
- case LDFA_OP:
- case LDFCCLR_OP:
- case LDFCNC_OP:
- case LDF_IMM_OP:
- case LDFA_IMM_OP:
- case LDFCCLR_IMM_OP:
- case LDFCNC_IMM_OP:
- ret = insn->x ?
- emulate_load_floatpair(ifa, insn, regs):
- emulate_load_float(ifa, insn, regs);
- break;
- case STF_OP:
- case STF_IMM_OP:
- ret = emulate_store_float(ifa, insn, regs);
- }
-
- DPRINT(("ret=%d\n", ret));
- if (ret) {
- struct siginfo si;
-
- si.si_signo = SIGBUS;
- si.si_errno = 0;
- si.si_code = BUS_ADRALN;
- si.si_addr = (void *) ifa;
- force_sig_info(SIGBUS, &si, current);
- } else {
+ switch (opcode) {
+ case LDS_OP:
+ case LDSA_OP:
+ case LDS_IMM_OP:
+ case LDSA_IMM_OP:
+ case LDFS_OP:
+ case LDFSA_OP:
+ case LDFS_IMM_OP:
/*
- * given today's architecture this case is not likely to happen
- * because a memory access instruction (M) can never be in the
- * last slot of a bundle. But let's keep it for now.
- */
- if (ipsr->ri = 2)
- regs->cr_iip += 16;
- ipsr->ri = ++ipsr->ri & 3;
- }
+ * The instruction will be retried with deferred exceptions turned on, and
+ * we should get Nat bit installed
+ *
+ * IMPORTANT: When PSR_ED is set, the register & immediate update forms
+ * are actually executed even though the operation failed. So we don't
+ * need to take care of this.
+ */
+ DPRINT("forcing PSR_ED\n");
+ regs->cr_ipsr |= IA64_PSR_ED;
+ goto done;
+
+ case LD_OP:
+ case LDA_OP:
+ case LDBIAS_OP:
+ case LDACQ_OP:
+ case LDCCLR_OP:
+ case LDCNC_OP:
+ case LDCCLRACQ_OP:
+ case LD_IMM_OP:
+ case LDA_IMM_OP:
+ case LDBIAS_IMM_OP:
+ case LDACQ_IMM_OP:
+ case LDCCLR_IMM_OP:
+ case LDCNC_IMM_OP:
+ case LDCCLRACQ_IMM_OP:
+ ret = emulate_load_int(ifa, u.insn, regs);
+ break;
+
+ case ST_OP:
+ case STREL_OP:
+ case ST_IMM_OP:
+ case STREL_IMM_OP:
+ ret = emulate_store_int(ifa, u.insn, regs);
+ break;
+
+ case LDF_OP:
+ case LDFA_OP:
+ case LDFCCLR_OP:
+ case LDFCNC_OP:
+ case LDF_IMM_OP:
+ case LDFA_IMM_OP:
+ case LDFCCLR_IMM_OP:
+ case LDFCNC_IMM_OP:
+ if (u.insn.x)
+ ret = emulate_load_floatpair(ifa, u.insn, regs);
+ else
+ ret = emulate_load_float(ifa, u.insn, regs);
+ break;
+
+ case STF_OP:
+ case STF_IMM_OP:
+ ret = emulate_store_float(ifa, u.insn, regs);
+ break;
+
+ default:
+ goto failure;
+ }
+ DPRINT("ret=%d\n", ret);
+ if (ret)
+ goto failure;
+
+ if (ipsr->ri = 2)
+ /*
+ * given today's architecture this case is not likely to happen because a
+ * memory access instruction (M) can never be in the last slot of a
+ * bundle. But let's keep it for now.
+ */
+ regs->cr_iip += 16;
+ ipsr->ri = (ipsr->ri + 1) & 0x3;
+
+ DPRINT("ipsr->ri=%d iip=%lx\n", ipsr->ri, regs->cr_iip);
+ done:
+ set_fs(old_fs); /* restore original address limit */
+ return;

- DPRINT(("ipsr->ri=%d iip=%lx\n", ipsr->ri, regs->cr_iip));
+ failure:
+ /* something went wrong... */
+ if (!user_mode(regs)) {
+ if (fix) {
+ regs->r8 = -EFAULT;
+ if (fix->skip & 1)
+ regs->r9 = 0;
+ regs->cr_iip += ((long) fix->skip) & ~15;
+ regs->cr_ipsr &= ~IA64_PSR_RI; /* clear exception slot number */
+ goto done;
+ }
+ die_if_kernel("error during unaligned kernel access\n", regs, ret);
+ /* NOT_REACHED */
+ }
+ force_sigbus:
+ si.si_signo = SIGBUS;
+ si.si_errno = 0;
+ si.si_code = BUS_ADRALN;
+ si.si_addr = (void *) ifa;
+ force_sig_info(SIGBUS, &si, current);
+ goto done;
}
diff -urN linux-davidm/arch/ia64/kernel/unwind.c linux-2.4.0-lia/arch/ia64/kernel/unwind.c
--- linux-davidm/arch/ia64/kernel/unwind.c Thu Jan 4 22:40:10 2001
+++ linux-2.4.0-lia/arch/ia64/kernel/unwind.c Thu Jan 25 17:22:06 2001
@@ -306,7 +306,7 @@
}
} else {
/* access a stacked register */
- addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum);
+ addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum - 32);
nat_addr = ia64_rse_rnat_addr(addr);
if ((unsigned long) addr < info->regstk.limit
|| (unsigned long) addr >= info->regstk.top)
diff -urN linux-davidm/arch/ia64/lib/copy_user.S linux-2.4.0-lia/arch/ia64/lib/copy_user.S
--- linux-davidm/arch/ia64/lib/copy_user.S Thu Jan 4 22:40:10 2001
+++ linux-2.4.0-lia/arch/ia64/lib/copy_user.S Thu Jan 25 17:22:15 2001
@@ -319,6 +319,7 @@
EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1)
br.ctop.dptk.few 5b
;;
+ mov ar.lc=saved_lc
mov pr=saved_pr,0xffffffffffff0000
mov ar.pfs=saved_pfs
br.ret.dptk.few rp
diff -urN linux-davidm/arch/ia64/lib/swiotlb.c linux-2.4.0-lia/arch/ia64/lib/swiotlb.c
--- linux-davidm/arch/ia64/lib/swiotlb.c Thu Jan 25 19:17:25 2001
+++ linux-2.4.0-lia/arch/ia64/lib/swiotlb.c Thu Jan 25 17:22:25 2001
@@ -10,8 +10,6 @@
* unnecessary i-cache flushing.
*/

-#include <linux/config.h>
-
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/pci.h>
diff -urN linux-davidm/arch/ia64/mm/init.c linux-2.4.0-lia/arch/ia64/mm/init.c
--- linux-davidm/arch/ia64/mm/init.c Thu Jan 4 22:40:10 2001
+++ linux-2.4.0-lia/arch/ia64/mm/init.c Thu Jan 25 17:22:35 2001
@@ -23,6 +23,7 @@
#include <asm/pgalloc.h>
#include <asm/sal.h>
#include <asm/system.h>
+#include <asm/uaccess.h>

/* References to section boundaries: */
extern char _stext, _etext, _edata, __init_begin, __init_end;
@@ -37,6 +38,8 @@

extern void ia64_tlb_init (void);

+unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL;
+
static unsigned long totalram_pages;

/*
@@ -356,7 +359,7 @@
# define vmlpt_bits (impl_va_bits - PAGE_SHIFT + pte_bits)
# define POW2(n) (1ULL << (n))

- impl_va_bits = ffz(~my_cpu_data.unimpl_va_mask);
+ impl_va_bits = ffz(~(my_cpu_data.unimpl_va_mask | (7UL << 61)));

if (impl_va_bits < 51 || impl_va_bits > 61)
panic("CPU has bogus IMPL_VA_MSB value of %lu!\n", impl_va_bits - 1);
@@ -390,7 +393,7 @@

memset(zones_size, 0, sizeof(zones_size));

- max_dma = (PAGE_ALIGN(MAX_DMA_ADDRESS) >> PAGE_SHIFT);
+ max_dma = virt_to_phys(MAX_DMA_ADDRESS) >> PAGE_SHIFT;
if (max_low_pfn < max_dma)
zones_size[ZONE_DMA] = max_low_pfn;
else {
diff -urN linux-davidm/arch/ia64/sn/fprom/fw-emu.c linux-2.4.0-lia/arch/ia64/sn/fprom/fw-emu.c
--- linux-davidm/arch/ia64/sn/fprom/fw-emu.c Thu Jan 4 22:40:10 2001
+++ linux-2.4.0-lia/arch/ia64/sn/fprom/fw-emu.c Wed Dec 13 18:59:33 2000
@@ -8,6 +8,8 @@
* Copyright (C) 2000 Silicon Graphics, Inc.
* Copyright (C) 2000 by Jack Steiner (steiner@sgi.com)
*/
+#include <linux/config.h>
+
#include <asm/efi.h>
#include <asm/pal.h>
#include <asm/sal.h>
diff -urN linux-davidm/drivers/char/mem.c linux-2.4.0-lia/drivers/char/mem.c
--- linux-davidm/drivers/char/mem.c Thu Jan 25 19:17:25 2001
+++ linux-2.4.0-lia/drivers/char/mem.c Thu Jan 25 17:43:34 2001
@@ -484,13 +484,13 @@
switch (orig) {
case 0:
file->f_pos = offset;
- return file->f_pos;
case 1:
file->f_pos += offset;
- return file->f_pos;
default:
return -EINVAL;
}
+ force_successful_syscall_return();
+ return file->f_pos;
}

static int open_port(struct inode * inode, struct file * filp)
diff -urN linux-davidm/drivers/scsi/qla1280.c linux-2.4.0-lia/drivers/scsi/qla1280.c
--- linux-davidm/drivers/scsi/qla1280.c Thu Jan 25 19:17:26 2001
+++ linux-2.4.0-lia/drivers/scsi/qla1280.c Thu Jan 25 17:43:56 2001
@@ -16,9 +16,23 @@
* General Public License for more details.
**
******************************************************************************/
-#define QLA1280_VERSION "3.21 Beta"
+#define QLA1280_VERSION "3.23 Beta"
/****************************************************************************
Revision History:
+ Rev 3.23 Beta January 11, 2001 BN Qlogic
+ - Added check of device_id when handling non
+ QLA12160s during detect().
+ Rev 3.22 Beta January 5, 2001 BN Qlogic
+ - Changed queue_task() to schedule_task()
+ for kernels 2.4.0 and higher.
+ Note: 2.4.0-testxx kernels released prior to
+ the actual 2.4.0 kernel release on January 2001
+ will get compile/link errors with schedule_task().
+ Please update your kernel to released 2.4.0 level,
+ or comment lines in this file flagged with 3.22
+ to resolve compile/link error of schedule_task().
+ - Added -DCONFIG_SMP in addition to -D__SMP__
+ in Makefile for 2.4.0 builds of driver as module.
Rev 3.21 Beta January 4, 2001 BN Qlogic
- Changed criteria of 64/32 Bit mode of HBA
operation according to BITS_PER_LONG rather
@@ -521,10 +535,10 @@
scsi_qla_host_t *ha;
int size = 0;
scsi_lu_t *up;
- int len = 0;
- qla_boards_t *bdp;
- uint32_t b, t, l;
-
+ int len = 0;
+ qla_boards_t *bdp;
+ uint32_t b, t, l;
+ uint8_t *temp;
host = NULL;

/* Find the host that was specified */
@@ -570,6 +584,10 @@
/* save the size of our buffer */
qla1280_buffer_size = size;

+ /* 3.20 clear the buffer we use for proc display */
+ temp = qla1280_buffer;
+ for (b=0 ; b < size; b++) *(temp+b) = 0;
+
/* start building the print buffer */
bdp = &QL1280BoardTbl[ha->devnum];
size = sprintf(PROC_BUF,
@@ -580,7 +598,7 @@

size = sprintf(PROC_BUF, "SCSI Host Adapter Information: %s\n", bdp->bdName);
len += size;
- size = sprintf(PROC_BUF, "Request Queue = 0x%lx, Response Queue = 0x%lx\n",
+ size = sprintf(PROC_BUF, "Request Queue = 0x%x, Response Queue = 0x%x\n",
ha->request_dma,
ha->response_dma);
len += size;
@@ -754,21 +772,19 @@
#endif

/* 3.20 */
- /* present the on-board ISP12160 for IA-64 Lion systems
- first to the OS; to preserve boot drive access in case another
- QLA12160 is inserted in the PCI slots */
+ /* First Initialize QLA12160 on PCI Bus 1 Dev 2 */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,18)
while ((pdev = pci_find_subsys(QLA1280_VENDOR_ID,
bdp->device_id, /* QLA12160 first in list */
PCI_ANY_ID,
PCI_ANY_ID,pdev))) {

- /* only interested here on devices on PCI bus=1 slot=2 */
+ /* find QLA12160 device on PCI bus=1 slot=2 */
if ((pdev->bus->number != 1) ||
(PCI_SLOT(pdev->devfn) != 2)) continue;

if (pci_enable_device(pdev)) goto find_devices;
- printk("qla1x160: Initializing IA-64 ISP12160\n");
+ printk("qla1x160: Initializing ISP12160 on PCI Bus 1, Dev 2\n");
host = scsi_register(template, sizeof(scsi_qla_host_t));
ha = (scsi_qla_host_t *) host->hostdata;
/* Clear our data area */
@@ -801,7 +817,7 @@
ha->instance = num_hosts;
if (qla1280_initialize_adapter(ha))
{
- printk(KERN_INFO "qla1x160: Failed to initialize onboard ISP12160 on IA-64 \n");
+ printk(KERN_INFO "qla1x160: Failed to initialize QLA12160 on PCI Bus 1 Dev 2 \n");
qla1280_mem_free(ha);
scsi_unregister(host);
goto find_devices;
@@ -809,7 +825,7 @@
host->max_channel = bdp->numPorts-1;
/* Register our resources with Linux */
if( qla1280_register_with_Linux(ha, bdp->numPorts-1) ) {
- printk(KERN_INFO "qla1x160: Failed to register resources for onboard ISP12160 on IA-64\n");
+ printk(KERN_INFO "qla1x160: Failed to register resources for QLA12160 on PCI Bus 1 Dev 2\n");
qla1280_mem_free(ha);
scsi_unregister(host);
goto find_devices;
@@ -863,9 +879,11 @@
continue;
}

- /* 3.20 skip IA-64 Lion on-board ISP12160 */
+ /* 3.20 and 3.23 */
+ /* skip QLA12160 already initialized on PCI Bus 1 Dev 2 */
/* since we already initialized and presented it */
- if ((pdev->bus->number = 1) &&
+ if ((bdp->device_id = QLA12160_DEVICE_ID) &&
+ (pdev->bus->number = 1) &&
(PCI_SLOT(pdev->devfn) = 2)) continue;

printk("qla1x160: Supported Device Found VID=%x DID=%x SSVID=%x SSDID=%x\n",
@@ -1165,7 +1183,12 @@
{
CMD_RESULT(cmd) = (int) (DID_BUS_BUSY << 16);
qla1280_done_q_put(sp, &ha->done_q_first, &ha->done_q_last);
- schedule_task(&ha->run_qla_bh);
+/* 3.22 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) /* 3.22 */
+ queue_task(&ha->run_qla_bh,&tq_scheduler);
+#else /* 3.22 */
+ schedule_task(&ha->run_qla_bh); /* 3.22 */
+#endif /* 3.22 */
ha->flags.dpc_sched = TRUE;
DRIVER_UNLOCK
return(0);
@@ -1663,7 +1686,7 @@
ha->run_qla_bh.routine = qla1280_do_dpc;

COMTRACE('P')
- schedule_task(&ha->run_qla_bh);
+ queue_task_irq(&ha->run_qla_bh,&tq_scheduler);
ha->flags.dpc_sched = TRUE;
}
clear_bit(QLA1280_IN_ISR_BIT, (int *)&ha->flags);
diff -urN linux-davidm/fs/proc/base.c linux-2.4.0-lia/fs/proc/base.c
--- linux-davidm/fs/proc/base.c Thu Nov 16 13:18:26 2000
+++ linux-2.4.0-lia/fs/proc/base.c Thu Jan 25 17:45:12 2001
@@ -395,7 +395,22 @@
}
#endif

+static loff_t mem_lseek(struct file * file, loff_t offset, int orig)
+{
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ case 1:
+ file->f_pos += offset;
+ default:
+ return -EINVAL;
+ }
+ force_successful_syscall_return();
+ return file->f_pos;
+}
+
static struct file_operations proc_mem_operations = {
+ llseek: mem_lseek,
read: mem_read,
write: mem_write,
};
diff -urN linux-davidm/include/asm-ia64/acpikcfg.h linux-2.4.0-lia/include/asm-ia64/acpikcfg.h
--- linux-davidm/include/asm-ia64/acpikcfg.h Thu Jan 4 22:40:20 2001
+++ linux-2.4.0-lia/include/asm-ia64/acpikcfg.h Thu Jan 25 17:47:22 2001
@@ -1,4 +1,5 @@
#include <linux/config.h>
+
#ifdef CONFIG_ACPI_KERNEL_CONFIG
/*
* acpikcfg.h - ACPI based Kernel Configuration Manager External Interfaces
diff -urN linux-davidm/include/asm-ia64/bitops.h linux-2.4.0-lia/include/asm-ia64/bitops.h
--- linux-davidm/include/asm-ia64/bitops.h Mon Oct 9 17:54:57 2000
+++ linux-2.4.0-lia/include/asm-ia64/bitops.h Thu Jan 25 17:51:43 2001
@@ -158,6 +158,7 @@
__asm__ ("getf.exp %0=%1" : "=r"(exp) : "f"(d));
return exp - 0xffff;
}
+
/*
* ffs: find first bit set. This is defined the same way as
* the libc and compiler builtin ffs routines, therefore
diff -urN linux-davidm/include/asm-ia64/dma.h linux-2.4.0-lia/include/asm-ia64/dma.h
--- linux-davidm/include/asm-ia64/dma.h Thu Jun 22 07:09:45 2000
+++ linux-2.4.0-lia/include/asm-ia64/dma.h Thu Jan 25 17:51:51 2001
@@ -2,35 +2,20 @@
#define _ASM_IA64_DMA_H

/*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
*/

#include <linux/config.h>
-#include <linux/spinlock.h> /* And spinlocks */
-#include <linux/delay.h>

#include <asm/io.h> /* need byte IO */

-#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
-#define dma_outb outb_p
-#else
-#define dma_outb outb
-#endif
-
-#define dma_inb inb
-
-#define MAX_DMA_CHANNELS 8
-#define MAX_DMA_ADDRESS 0xffffffffUL
-
-extern spinlock_t dma_spin_lock;
-
-/* From PCI */
+extern unsigned long MAX_DMA_ADDRESS;

#ifdef CONFIG_PCI
-extern int isa_dma_bridge_buggy;
+ extern int isa_dma_bridge_buggy;
#else
-#define isa_dma_bridge_buggy (0)
+# define isa_dma_bridge_buggy (0)
#endif

#endif /* _ASM_IA64_DMA_H */
diff -urN linux-davidm/include/asm-ia64/ia32.h linux-2.4.0-lia/include/asm-ia64/ia32.h
--- linux-davidm/include/asm-ia64/ia32.h Thu Jan 4 22:40:20 2001
+++ linux-2.4.0-lia/include/asm-ia64/ia32.h Thu Jan 25 17:52:10 2001
@@ -378,9 +378,10 @@
ia64_psr(regs)->ri = 0; /* clear return slot number */ \
ia64_psr(regs)->is = 1; /* IA-32 instruction set */ \
regs->cr_iip = new_ip; \
- regs->r12 = new_sp; \
+ regs->ar_rsc = 0xc; /* enforced lazy mode, priv. level 3 */ \
regs->ar_rnat = 0; \
regs->loadrs = 0; \
+ regs->r12 = new_sp; \
} while (0)

extern void ia32_gdt_init (void);
diff -urN linux-davidm/include/asm-ia64/mmu_context.h linux-2.4.0-lia/include/asm-ia64/mmu_context.h
--- linux-davidm/include/asm-ia64/mmu_context.h Thu Jan 4 22:40:20 2001
+++ linux-2.4.0-lia/include/asm-ia64/mmu_context.h Thu Jan 25 17:59:55 2001
@@ -12,21 +12,14 @@
#include <asm/processor.h>

/*
- * Routines to manage the allocation of task context numbers. Task
- * context numbers are used to reduce or eliminate the need to perform
- * TLB flushes due to context switches. Context numbers are
- * implemented using ia-64 region ids. Since ia-64 TLBs do not
- * guarantee that the region number is checked when performing a TLB
- * lookup, we need to assign a unique region id to each region in a
- * process. We use the least significant three bits in a region id
- * for this purpose. On processors where the region number is checked
- * in TLB lookups, we can get back those two bits by defining
- * CONFIG_IA64_TLB_CHECKS_REGION_NUMBER. The macro
- * IA64_REGION_ID_BITS gives the number of bits in a region id. The
- * architecture manual guarantees this number to be in the range
- * 18-24.
+ * Routines to manage the allocation of task context numbers. Task context numbers are
+ * used to reduce or eliminate the need to perform TLB flushes due to context switches.
+ * Context numbers are implemented using ia-64 region ids. Since the IA-64 TLB does not
+ * consider the region number when performing a TLB lookup, we need to assign a unique
+ * region id to each region in a process. We use the least significant three bits in a
+ * region id for this purpose.
*
- * Copyright (C) 1998 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
*/

#define IA64_REGION_ID_KERNEL 0 /* the kernel's region id (tlb.c depends on this being 0) */
diff -urN linux-davidm/include/asm-ia64/offsets.h linux-2.4.0-lia/include/asm-ia64/offsets.h
--- linux-davidm/include/asm-ia64/offsets.h Thu Jan 25 19:17:27 2001
+++ linux-2.4.0-lia/include/asm-ia64/offsets.h Thu Jan 25 18:00:03 2001
@@ -1,14 +1,17 @@
#ifndef _ASM_IA64_OFFSETS_H
#define _ASM_IA64_OFFSETS_H
+
/*
* DO NOT MODIFY
*
- * This file was generated by arch/ia64/tools/print_offsets.awk.
+ * This file was generated by arch/ia64/tools/print_offsets.
*
*/
-#define PT_PTRACED_BIT 0
-#define PT_TRACESYS_BIT 1
-#define IA64_TASK_SIZE 3408 /* 0xd50 */
+
+#define PT_PTRACED_BIT 0
+#define PT_TRACESYS_BIT 1
+
+#define IA64_TASK_SIZE 3376 /* 0xd30 */
#define IA64_PT_REGS_SIZE 400 /* 0x190 */
#define IA64_SWITCH_STACK_SIZE 560 /* 0x230 */
#define IA64_SIGINFO_SIZE 128 /* 0x80 */
@@ -18,10 +21,9 @@
#define IA64_TASK_SIGPENDING_OFFSET 16 /* 0x10 */
#define IA64_TASK_NEED_RESCHED_OFFSET 40 /* 0x28 */
#define IA64_TASK_PROCESSOR_OFFSET 100 /* 0x64 */
-#define IA64_TASK_THREAD_OFFSET 960 /* 0x3c0 */
-#define IA64_TASK_THREAD_KSP_OFFSET 960 /* 0x3c0 */
-#define IA64_TASK_THREAD_SIGMASK_OFFSET 3256 /* 0xcb8 */
-#define IA64_TASK_PFM_NOTIFY 3152 /* 0xc50 */
+#define IA64_TASK_THREAD_OFFSET 1456 /* 0x5b0 */
+#define IA64_TASK_THREAD_KSP_OFFSET 1456 /* 0x5b0 */
+#define IA64_TASK_THREAD_SIGMASK_OFFSET 3224 /* 0xc98 */
#define IA64_TASK_PID_OFFSET 196 /* 0xc4 */
#define IA64_TASK_MM_OFFSET 88 /* 0x58 */
#define IA64_PT_REGS_CR_IPSR_OFFSET 0 /* 0x0 */
@@ -71,7 +73,7 @@
#define IA64_PT_REGS_F8_OFFSET 368 /* 0x170 */
#define IA64_PT_REGS_F9_OFFSET 384 /* 0x180 */
#define IA64_SWITCH_STACK_CALLER_UNAT_OFFSET 0 /* 0x0 */
-#define IA64_SWITCH_STACK_AR_FPSR_OFFSET 8 /* 0x8 */
+#define IA64_SWITCH_STACK_AR_FPSR_OFFSET 8 /* 0x8 */
#define IA64_SWITCH_STACK_F2_OFFSET 16 /* 0x10 */
#define IA64_SWITCH_STACK_F3_OFFSET 32 /* 0x20 */
#define IA64_SWITCH_STACK_F4_OFFSET 48 /* 0x30 */
@@ -110,8 +112,8 @@
#define IA64_SWITCH_STACK_B5_OFFSET 504 /* 0x1f8 */
#define IA64_SWITCH_STACK_AR_PFS_OFFSET 512 /* 0x200 */
#define IA64_SWITCH_STACK_AR_LC_OFFSET 520 /* 0x208 */
-#define IA64_SWITCH_STACK_AR_UNAT_OFFSET 528 /* 0x210 */
-#define IA64_SWITCH_STACK_AR_RNAT_OFFSET 536 /* 0x218 */
+#define IA64_SWITCH_STACK_AR_UNAT_OFFSET 528 /* 0x210 */
+#define IA64_SWITCH_STACK_AR_RNAT_OFFSET 536 /* 0x218 */
#define IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET 544 /* 0x220 */
#define IA64_SWITCH_STACK_PR_OFFSET 552 /* 0x228 */
#define IA64_SIGCONTEXT_AR_BSP_OFFSET 72 /* 0x48 */
@@ -119,7 +121,7 @@
#define IA64_SIGCONTEXT_FLAGS_OFFSET 0 /* 0x0 */
#define IA64_SIGCONTEXT_CFM_OFFSET 48 /* 0x30 */
#define IA64_SIGCONTEXT_FR6_OFFSET 560 /* 0x230 */
-#define IA64_CLONE_VFORK 16384 /* 0x4000 */
+#define IA64_CLONE_VFORK 16384 /* 0x4000 */
#define IA64_CLONE_VM 256 /* 0x100 */

#endif /* _ASM_IA64_OFFSETS_H */
diff -urN linux-davidm/include/asm-ia64/pgtable.h linux-2.4.0-lia/include/asm-ia64/pgtable.h
--- linux-davidm/include/asm-ia64/pgtable.h Thu Jan 25 19:17:27 2001
+++ linux-2.4.0-lia/include/asm-ia64/pgtable.h Thu Jan 25 18:00:19 2001
@@ -8,11 +8,12 @@
* This hopefully works with any (fixed) IA-64 page-size, as defined
* in <asm/page.h> (currently 8192).
*
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
*/

#include <linux/config.h>
+
#include <asm/mman.h>
#include <asm/page.h>
#include <asm/processor.h>
diff -urN linux-davidm/include/asm-ia64/processor.h linux-2.4.0-lia/include/asm-ia64/processor.h
--- linux-davidm/include/asm-ia64/processor.h Thu Jan 25 19:17:27 2001
+++ linux-2.4.0-lia/include/asm-ia64/processor.h Thu Jan 25 18:00:30 2001
@@ -230,9 +230,12 @@
#define IA64_USEC_PER_CYC_SHIFT 41

/*
- * CPU type, hardware bug flags, and per-CPU state.
+ * CPU type, hardware bug flags, and per-CPU state. Frequently used
+ * state comes earlier:
*/
struct cpuinfo_ia64 {
+ __u64 itm_delta; /* # of clock cycles between clock ticks */
+ __u64 itm_next; /* interval timer mask value to use for next clock tick */
__u64 *pgd_quick;
__u64 *pmd_quick;
__u64 *pte_quick;
@@ -353,10 +356,10 @@
ia64_psr(regs)->is = 0; /* IA-64 instruction set */ \
regs->cr_iip = new_ip; \
regs->ar_rsc = 0xf; /* eager mode, privilege level 3 */ \
- regs->r12 = new_sp - 16; /* allocate 16 byte scratch area */ \
- regs->ar_bspstore = IA64_RBS_BOT; \
regs->ar_rnat = 0; \
+ regs->ar_bspstore = IA64_RBS_BOT; \
regs->loadrs = 0; \
+ regs->r12 = new_sp - 16; /* allocate 16 byte scratch area */ \
} while (0)

/* Forward declarations, a strange C thing... */
diff -urN linux-davidm/include/asm-ia64/segment.h linux-2.4.0-lia/include/asm-ia64/segment.h
--- linux-davidm/include/asm-ia64/segment.h Sun Feb 6 18:42:40 2000
+++ linux-2.4.0-lia/include/asm-ia64/segment.h Thu Jan 25 18:00:39 2001
@@ -3,4 +3,4 @@

/* Only here because we have some old header files that expect it.. */

-#endif /* __ALPHA_SEGMENT_H */
+#endif /* _ASM_IA64_SEGMENT_H */
diff -urN linux-davidm/include/asm-ia64/sn/addrs.h linux-2.4.0-lia/include/asm-ia64/sn/addrs.h
--- linux-davidm/include/asm-ia64/sn/addrs.h Thu Jan 4 22:40:20 2001
+++ linux-2.4.0-lia/include/asm-ia64/sn/addrs.h Thu Jan 25 18:00:55 2001
@@ -11,6 +11,7 @@
#define _ASM_SN_ADDRS_H

#include <linux/config.h>
+
#if _LANGUAGE_C
#include <linux/types.h>
#endif /* _LANGUAGE_C */
diff -urN linux-davidm/include/asm-ia64/sn/agent.h linux-2.4.0-lia/include/asm-ia64/sn/agent.h
--- linux-davidm/include/asm-ia64/sn/agent.h Thu Jan 4 22:40:20 2001
+++ linux-2.4.0-lia/include/asm-ia64/sn/agent.h Thu Jan 25 18:01:03 2001
@@ -13,6 +13,7 @@
#define _ASM_SGI_SN_AGENT_H

#include <linux/config.h>
+
#include <asm/sn/addrs.h>
#include <asm/sn/arch.h>
//#include <asm/sn/io.h>
diff -urN linux-davidm/include/asm-ia64/sn/mmzone_sn1.h linux-2.4.0-lia/include/asm-ia64/sn/mmzone_sn1.h
--- linux-davidm/include/asm-ia64/sn/mmzone_sn1.h Thu Jan 4 22:40:20 2001
+++ linux-2.4.0-lia/include/asm-ia64/sn/mmzone_sn1.h Thu Jan 25 18:19:46 2001
@@ -1,11 +1,11 @@
#ifndef _ASM_IA64_MMZONE_SN1_H
#define _ASM_IA64_MMZONE_SN1_H

+#include <linux/config.h>
+
/*
* Copyright, 2000, Silicon Graphics, sprasad@engr.sgi.com
*/
-
-#include <linux/config.h>

/* Maximum configuration supported by SNIA hardware. There are other
* restrictions that may limit us to a smaller max configuration.
diff -urN linux-davidm/include/asm-ia64/timex.h linux-2.4.0-lia/include/asm-ia64/timex.h
--- linux-davidm/include/asm-ia64/timex.h Sun Feb 6 18:42:40 2000
+++ linux-2.4.0-lia/include/asm-ia64/timex.h Thu Jan 25 18:21:38 2001
@@ -2,14 +2,15 @@
#define _ASM_IA64_TIMEX_H

/*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ */
+/*
+ * 2001/01/18 davidm Removed CLOCK_TICK_RATE. It makes no sense on IA-64.
+ * Also removed cacheflush_time as it's entirely unused.
*/
-
-#define CLOCK_TICK_RATE 1193180 /* Underlying HZ XXX fix me! */

typedef unsigned long cycles_t;
-extern cycles_t cacheflush_time;

static inline cycles_t
get_cycles (void)
diff -urN linux-davidm/kernel/sched.c linux-2.4.0-lia/kernel/sched.c
--- linux-davidm/kernel/sched.c Thu Jan 4 22:40:21 2001
+++ linux-2.4.0-lia/kernel/sched.c Thu Jan 25 18:23:04 2001
@@ -260,7 +260,7 @@
target_tsk = tsk;
}
} else {
- if (oldest_idle = -1ULL) {
+ if (oldest_idle = (cycles_t) -1) {
int prio = preemption_goodness(tsk, p, cpu);

if (prio > max_prio) {
@@ -272,7 +272,7 @@
}
tsk = target_tsk;
if (tsk) {
- if (oldest_idle != -1ULL) {
+ if (oldest_idle != (cycles_t) -1) {
best_cpu = tsk->processor;
goto send_now_idle;
}
diff -urN linux-davidm/mm/memory.c linux-2.4.0-lia/mm/memory.c
--- linux-davidm/mm/memory.c Thu Jan 25 19:17:27 2001
+++ linux-2.4.0-lia/mm/memory.c Thu Jan 25 18:23:11 2001
@@ -473,7 +473,7 @@
goto out_unlock;
}
}
- if (handle_mm_fault(current->mm, vma, ptr, datain) <= 0)
+ if (handle_mm_fault(current->mm, vma, ptr, datain ? VM_READ : VM_WRITE) <= 0)
goto out_unlock;
spin_lock(&mm->page_table_lock);
map = follow_page(ptr);
@@ -1223,7 +1223,7 @@
if (addr >= end)
BUG();
do {
- if (handle_mm_fault(mm, vma, addr, write) < 0)
+ if (handle_mm_fault(mm, vma, addr, write ? VM_WRITE : VM_READ) < 0)
return -1;
addr += PAGE_SIZE;
} while (addr < end);