* Happy New Year PARISC
@ 2012-01-01 0:02 John David Anglin
2012-01-02 6:23 ` Grant Grundler
0 siblings, 1 reply; 18+ messages in thread
From: John David Anglin @ 2012-01-01 0:02 UTC (permalink / raw)
To: linux-parisc List
Hi all,
After a lot of trial and error, I believe that I have resolved the
random segmentation faults
on SMP PA8800 and PA8900 systems. This includes the libgomp hpmc's
which turned
out to be caused by a non-equivalent alias mapping in libattr (I
hadn't rebuilt the attr
package because there is a build issue with the current version in
unstable). This was
hard to find!
I have started working on setting up magnum for buildd.
Happy New Year,
Dave
--
John David Anglin dave.anglin@bell.net
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Happy New Year PARISC
2012-01-01 0:02 Happy New Year PARISC John David Anglin
@ 2012-01-02 6:23 ` Grant Grundler
2012-01-02 15:12 ` John David Anglin
0 siblings, 1 reply; 18+ messages in thread
From: Grant Grundler @ 2012-01-02 6:23 UTC (permalink / raw)
To: John David Anglin; +Cc: linux-parisc List
On Sat, Dec 31, 2011 at 4:02 PM, John David Anglin <dave.anglin@bell.ne=
t> wrote:
> Hi all,
>
> After a lot of trial and error, I believe that I have resolved the ra=
ndom
> segmentation faults
> on SMP PA8800 and PA8900 systems. =C2=A0This includes the libgomp hpm=
c's which
> turned
> out to be caused by a non-equivalent alias mapping in libattr (I hadn=
't
> rebuilt the attr
> package because there is a build issue with the current version in
> unstable). =C2=A0This was
> hard to find!
Wow! Happy New Year!
Well Done!
That must have been incredibly hard to find. It's a bummer the only
way we can find those sorts of things is by unraveling crash dumps. :(
> I have started working on setting up magnum for buildd.
If I can download a bunch of .debs, I'd be happy to install and run
some tests on my j6k.
cheers,
grant
--
To unsubscribe from this list: send the line "unsubscribe linux-parisc"=
in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Happy New Year PARISC
2012-01-02 6:23 ` Grant Grundler
@ 2012-01-02 15:12 ` John David Anglin
2012-01-02 23:12 ` John David Anglin
0 siblings, 1 reply; 18+ messages in thread
From: John David Anglin @ 2012-01-02 15:12 UTC (permalink / raw)
To: Grant Grundler; +Cc: linux-parisc List
On 2-Jan-12, at 1:23 AM, Grant Grundler wrote:
> Well Done!
> That must have been incredibly hard to find. It's a bummer the only
> way we can find those sorts of things is by unraveling crash dumps. :(
>
Sadly, the crash dumps were never very helpful. The hpmc's arising
from cache corruption were usually significantly deferred. Often, the
crashes would occur with the processors in the idle loop! Probably,
HP had a JTAG box or something similar to analyze cache problems.
We have known for some time that non-equivalent aliases are not
supported on PA8800 and PA8900 processors. I patched binutils
several months ago to fix this problem. However, the entire runtime
needs to be recompiled to eliminate the problem.
The kernel routine that causes the hpmc's is flush_cache_range.
I wrote a modified version that can check the page mapping, but it
is very slow. This is a very performance critical function.
Another source of instability was TLB purges. We put lock/unlock
sequences around all the purges in the C code, but somehow we forgot
to do the same in the assembly code in pacache.S.
I believe that I fixed the COW/minifail bug yesterday. I now have
copy_user_page doing copies via the temp-alias region. We also
forgot to purge the TLB entries when we write protected the page
table for COW. As a result, multithreaded applications could continue
to dirty a page after it was nominally write protected.
There is more to do on this. I know that clear_user_page and
copy_user_page no longer need the dcache flushes in
kunmap_parisc. What I'm really hoping is that we will now be
able to change the define for flush_cache_dup_mm to:
#define flush_cache_dup_mm(mm) do { } while (0)
>> I have started working on setting up magnum for buildd.
>
> If I can download a bunch of .debs, I'd be happy to install and run
> some tests on my j6k.
The .debs can be found in my home directory on dogma. binutils,
gcc-4.4 and gcc-4.6 can be updated without kernel issues. I believe
that glibc needs 2.6.26 or later. Watch out for udev. Don't update
it until glibc is updated. It's definitely tricky to do the updates
by hand.
I'm going to work on the kernel patch some more today. Hopefully,
it will then be ready for testing on other machines.
Dave
Happy New Year
--
John David Anglin dave.anglin@bell.net
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Happy New Year PARISC
2012-01-02 15:12 ` John David Anglin
@ 2012-01-02 23:12 ` John David Anglin
2012-01-03 11:50 ` Carlos O'Donell
0 siblings, 1 reply; 18+ messages in thread
From: John David Anglin @ 2012-01-02 23:12 UTC (permalink / raw)
To: Grant Grundler; +Cc: linux-parisc List
[-- Attachment #1: Type: text/plain, Size: 324 bytes --]
On 2-Jan-12, at 10:12 AM, John David Anglin wrote:
> I'm going to work on the kernel patch some more today. Hopefully,
> it will then be ready for testing on other machines.
None of this worked. Attached patch as it stands. Comments and
testing appreciated.
Regards,
Dave
--
John David Anglin dave.anglin@bell.net
[-- Attachment #2: linux-stable-20120102.d.txt --]
[-- Type: text/plain, Size: 29200 bytes --]
diff --git a/arch/parisc/hpux/wrappers.S b/arch/parisc/hpux/wrappers.S
index 58c53c8..bdcea33 100644
--- a/arch/parisc/hpux/wrappers.S
+++ b/arch/parisc/hpux/wrappers.S
@@ -88,7 +88,7 @@ ENTRY(hpux_fork_wrapper)
STREG %r2,-20(%r30)
ldo 64(%r30),%r30
- STREG %r2,PT_GR19(%r1) ;! save for child
+ STREG %r2,PT_SYSCALL_RP(%r1) ;! save for child
STREG %r30,PT_GR21(%r1) ;! save for child
LDREG PT_GR30(%r1),%r25
@@ -132,7 +132,7 @@ ENTRY(hpux_child_return)
bl,n schedule_tail, %r2
#endif
- LDREG TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2
+ LDREG TASK_PT_SYSCALL_RP-TASK_SZ_ALGN-128(%r30),%r2
b fork_return
copy %r0,%r28
ENDPROC(hpux_child_return)
diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h
index 2388bdb..7839285 100644
--- a/arch/parisc/include/asm/futex.h
+++ b/arch/parisc/include/asm/futex.h
@@ -8,6 +8,29 @@
#include <asm/atomic.h>
#include <asm/errno.h>
+/* The following has to match the LWS code in syscall.S. We have
+ sixteen four-word locks. */
+
+static inline void
+_futex_spin_lock_irqsave (u32 __user *uaddr, unsigned long int *flags)
+{
+ extern u32 lws_lock_start[];
+ long index = ((long)uaddr & 0xf0) >> 2;
+ arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
+ local_irq_save(*flags);
+ arch_spin_lock(s);
+}
+
+static inline void
+_futex_spin_unlock_irqrestore (u32 __user *uaddr, unsigned long int *flags)
+{
+ extern u32 lws_lock_start[];
+ long index = ((long)uaddr & 0xf0) >> 2;
+ arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
+ arch_spin_unlock(s);
+ local_irq_restore(*flags);
+}
+
static inline int
futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
@@ -26,7 +49,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
pagefault_disable();
- _atomic_spin_lock_irqsave(uaddr, flags);
+ _futex_spin_lock_irqsave(uaddr, &flags);
switch (op) {
case FUTEX_OP_SET:
@@ -71,7 +94,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
ret = -ENOSYS;
}
- _atomic_spin_unlock_irqrestore(uaddr, flags);
+ _futex_spin_unlock_irqrestore(uaddr, &flags);
pagefault_enable();
@@ -113,7 +136,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
* address. This should scale to a couple of CPUs.
*/
- _atomic_spin_lock_irqsave(uaddr, flags);
+ _futex_spin_lock_irqsave(uaddr, &flags);
ret = get_user(val, uaddr);
@@ -122,7 +145,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
*uval = val;
- _atomic_spin_unlock_irqrestore(uaddr, flags);
+ _futex_spin_unlock_irqrestore(uaddr, &flags);
return ret;
}
diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h
index a84cc1f..ea63524 100644
--- a/arch/parisc/include/asm/page.h
+++ b/arch/parisc/include/asm/page.h
@@ -22,14 +22,14 @@
#include <asm/cache.h>
#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
-#define copy_page(to,from) copy_user_page_asm((void *)(to), (void *)(from))
+#define copy_page(to,from) copy_page_asm((void *)(to), (void *)(from))
struct page;
-void copy_user_page_asm(void *to, void *from);
+void copy_page_asm(void *to, void *from);
void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
struct page *pg);
-void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
+void clear_user_page(void *vto, unsigned long vaddr, struct page *pg);
/*
* These are used to make use of C type-checking..
diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
index 22dadeb..ab667f8 100644
--- a/arch/parisc/include/asm/pgtable.h
+++ b/arch/parisc/include/asm/pgtable.h
@@ -40,7 +40,14 @@ struct vm_area_struct;
do{ \
*(pteptr) = (pteval); \
} while(0)
-#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+
+extern void purge_tlb_entries(struct mm_struct *, unsigned long);
+
+#define set_pte_at(mm,addr,ptep, pteval) \
+ do{ \
+ set_pte(ptep,pteval); \
+ purge_tlb_entries(mm,addr); \
+ } while(0)
#endif /* !__ASSEMBLY__ */
@@ -464,6 +471,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
old = pte_val(*ptep);
new = pte_val(pte_wrprotect(__pte (old)));
} while (cmpxchg((unsigned long *) ptep, old, new) != old);
+ purge_tlb_entries(mm, addr);
#else
pte_t old_pte = *ptep;
set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
diff --git a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c
index dcd5510..5df1597 100644
--- a/arch/parisc/kernel/asm-offsets.c
+++ b/arch/parisc/kernel/asm-offsets.c
@@ -141,6 +141,7 @@ int main(void)
DEFINE(TASK_PT_IAOQ0, offsetof(struct task_struct, thread.regs.iaoq[0]));
DEFINE(TASK_PT_IAOQ1, offsetof(struct task_struct, thread.regs.iaoq[1]));
DEFINE(TASK_PT_CR27, offsetof(struct task_struct, thread.regs.cr27));
+ DEFINE(TASK_PT_SYSCALL_RP, offsetof(struct task_struct, thread.regs.pad0));
DEFINE(TASK_PT_ORIG_R28, offsetof(struct task_struct, thread.regs.orig_r28));
DEFINE(TASK_PT_KSP, offsetof(struct task_struct, thread.regs.ksp));
DEFINE(TASK_PT_KPC, offsetof(struct task_struct, thread.regs.kpc));
@@ -230,6 +231,7 @@ int main(void)
DEFINE(PT_IAOQ0, offsetof(struct pt_regs, iaoq[0]));
DEFINE(PT_IAOQ1, offsetof(struct pt_regs, iaoq[1]));
DEFINE(PT_CR27, offsetof(struct pt_regs, cr27));
+ DEFINE(PT_SYSCALL_RP, offsetof(struct pt_regs, pad0));
DEFINE(PT_ORIG_R28, offsetof(struct pt_regs, orig_r28));
DEFINE(PT_KSP, offsetof(struct pt_regs, ksp));
DEFINE(PT_KPC, offsetof(struct pt_regs, kpc));
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index 83335f3..a6e90cf 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -134,7 +134,7 @@ parisc_cache_init(void)
if (pdc_cache_info(&cache_info) < 0)
panic("parisc_cache_init: pdc_cache_info failed");
-#if 0
+#if 1
printk("ic_size %lx dc_size %lx it_size %lx\n",
cache_info.ic_size,
cache_info.dc_size,
@@ -315,9 +315,13 @@ void flush_dcache_page(struct page *page)
flush_tlb_page(mpnt, addr);
if (old_addr == 0 || (old_addr & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) {
- __flush_cache_page(mpnt, addr, page_to_phys(page));
- if (old_addr)
+ if (old_addr == 0)
+ __flush_cache_page(mpnt, addr, page_to_phys(page));
+ else if (parisc_requires_coherency()) {
+ /* Big trouble -- we have a bad mapping */
+ flush_cache_all();
printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? (char *)mpnt->vm_file->f_path.dentry->d_name.name : "(null)");
+ }
old_addr = addr;
}
}
@@ -331,17 +335,6 @@ EXPORT_SYMBOL(flush_kernel_dcache_page_asm);
EXPORT_SYMBOL(flush_data_cache_local);
EXPORT_SYMBOL(flush_kernel_icache_range_asm);
-void clear_user_page_asm(void *page, unsigned long vaddr)
-{
- unsigned long flags;
- /* This function is implemented in assembly in pacache.S */
- extern void __clear_user_page_asm(void *page, unsigned long vaddr);
-
- purge_tlb_start(flags);
- __clear_user_page_asm(page, vaddr);
- purge_tlb_end(flags);
-}
-
#define FLUSH_THRESHOLD 0x80000 /* 0.5MB */
int parisc_cache_flush_threshold __read_mostly = FLUSH_THRESHOLD;
@@ -375,18 +368,25 @@ void __init parisc_setup_cache_timing(void)
printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus());
}
-extern void purge_kernel_dcache_page(unsigned long);
-extern void clear_user_page_asm(void *page, unsigned long vaddr);
+extern void purge_kernel_dcache_page_asm(unsigned long);
+extern void clear_user_page_asm(void *, unsigned long);
+extern void copy_user_page_asm(void *, void *, unsigned long);
-void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
+void clear_user_page(void *vto, unsigned long vaddr, struct page *page)
{
unsigned long flags;
- purge_kernel_dcache_page((unsigned long)page);
+ /* The PA-RISC 2.0 Architecture book states on page F-6:
+ "Before a write-capable translation is enabled, *all*
+ non-equivalently-aliased translations must be removed
+ from the page table and purged from the TLB. (Note
+ that the caches are not required to be flushed at this
+ time.)" */
+
purge_tlb_start(flags);
- pdtlb_kernel(page);
+ pdtlb_kernel(vto);
purge_tlb_end(flags);
- clear_user_page_asm(page, vaddr);
+ clear_user_page_asm(vto, vaddr);
}
EXPORT_SYMBOL(clear_user_page);
@@ -401,13 +401,33 @@ void flush_kernel_dcache_page_addr(void *addr)
}
EXPORT_SYMBOL(flush_kernel_dcache_page_addr);
+#define COPY_USER_PAGE_VIA_KMAP 1
+
void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
- struct page *pg)
+ struct page *pg)
{
- /* no coherency needed (all in kmap/kunmap) */
- copy_user_page_asm(vto, vfrom);
+#if COPY_USER_PAGE_VIA_KMAP
+ /* Copy using kernel mapping. This has the advantage
+ that no coherency is needed in copy_page_asm (all in
+ kmap/kunmap). However, the `from' page may be dirty
+ in threaded applications and it needs to be flushed
+ before it can be accessed through the kernel mapping. */
+ copy_page_asm(vto, vfrom);
if (!parisc_requires_coherency())
flush_kernel_dcache_page_asm(vto);
+#else
+ unsigned long flags;
+
+ /* Copy through temp-alias region. This has the advantage
+ that the `from' page doesn't need to be flushed. However,
+ the `to' page must be flushed in copy_user_page_asm since
+ it can be used to bring in code. */
+ purge_tlb_start(flags);
+ pdtlb_kernel(vto);
+ pdtlb_kernel(vfrom);
+ purge_tlb_end(flags);
+ copy_user_page_asm(vto, vfrom, vaddr);
+#endif
}
EXPORT_SYMBOL(copy_user_page);
@@ -487,18 +507,90 @@ flush_user_icache_range(unsigned long start, unsigned long end)
flush_instruction_cache();
}
+/* While useful for testing, this check has too much overhead for
+ general use. Thus, it is better to fix inequivalent mappings
+ than whack the cache. */
+#define DEBUG_PAGE_MAPPING 0
+
+static inline void check_page_mapping(struct page *page)
+{
+#if DEBUG_PAGE_MAPPING
+ struct address_space *mapping = page_mapping(page);
+ struct vm_area_struct *mpnt;
+ struct prio_tree_iter iter;
+ unsigned long offset;
+ unsigned long addr, old_addr = 0;
+ pgoff_t pgoff;
+
+ if (!mapping || !mapping_mapped(mapping))
+ return;
+
+ pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
+
+ /* Check that all mappings of a file are congruently mapped */
+
+ flush_dcache_mmap_lock(mapping);
+ vma_prio_tree_foreach(mpnt, &iter, &mapping->i_mmap, pgoff, pgoff) {
+ offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
+ addr = mpnt->vm_start + offset;
+ if (old_addr == 0 || (old_addr & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) {
+ if (old_addr) {
+ printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? (char *)mpnt->vm_file->f_path.dentry->d_name.name : "(null)");
+ }
+ old_addr = addr;
+ }
+ }
+ flush_dcache_mmap_unlock(mapping);
+#endif
+}
+
+static inline pte_t *get_ptep(pgd_t *pgd, unsigned long addr)
+{
+ pte_t *ptep = NULL;
+
+ if (!pgd_none(*pgd)) {
+ pud_t *pud = pud_offset(pgd, addr);
+ if (!pud_none(*pud)) {
+ pmd_t *pmd = pmd_offset(pud, addr);
+ if (!pmd_none(*pmd)) {
+ ptep = pte_offset_map(pmd, addr);
+ }
+ }
+ }
+ return ptep;
+}
+
+/* While flushing by page is slightly less efficient, it allows detection
+ of pages without pte's and mappings with inequivalent aliases. */
+
+#define FLUSH_CACHE_RANGE_BY_PAGE 0
void flush_cache_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
- int sr3;
-
BUG_ON(!vma->vm_mm->context);
- sr3 = mfsp(3);
- if (vma->vm_mm->context == sr3) {
- flush_user_dcache_range(start,end);
- flush_user_icache_range(start,end);
+ if ((end - start) < parisc_cache_flush_threshold
+ && vma->vm_mm->context == mfsp(3)) {
+#if FLUSH_CACHE_RANGE_BY_PAGE
+ unsigned long addr;
+ pte_t *ptep;
+ pgd_t *pgd = vma->vm_mm->pgd;
+
+ for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) {
+ ptep = get_ptep(pgd, addr);
+ if (!ptep) {
+ /* ??? Why don't we have a pte? */
+ flush_cache_all();
+ return;
+ }
+ check_page_mapping(pte_page(*ptep));
+ flush_cache_page(vma, addr, pte_pfn(*ptep));
+ }
+#else
+ flush_user_dcache_range_asm(start,end);
+ flush_user_icache_range_asm(start,end);
+#endif
} else {
flush_cache_all();
}
@@ -513,3 +605,23 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
__flush_cache_page(vma, vmaddr, page_to_phys(pfn_to_page(pfn)));
}
+
+void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
+{
+ unsigned long flags;
+
+ /* The PA-RISC 2.0 Architecture book states on page F-7:
+ "Before any non-equivalent aliased translation is re-enabled,
+ the virtual address range for the writeable page (the entire
+ page) must be flushed from the cache, and the write-capable
+ translation removed from the page table and purged from the
+ TLB." set_pte_at is used to setup COW pages, so the TLB
+ must be purged. Note: purge_tlb_entries can be called at
+ startup with no context. */
+
+ mtsp(mm->context,1);
+ purge_tlb_start(flags);
+ pdtlb(addr);
+ pitlb(addr);
+ purge_tlb_end(flags);
+}
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index 6f05944..3caa199 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -483,7 +483,7 @@
* B <-> _PAGE_DMB (memory break)
*
* Then incredible subtlety: The access rights are
- * _PAGE_GATEWAY _PAGE_EXEC _PAGE_READ
+ * _PAGE_GATEWAY, _PAGE_EXEC and _PAGE_WRITE
* See 3-14 of the parisc 2.0 manual
*
* Finally, _PAGE_READ goes in the top bit of PL1 (so we
@@ -493,7 +493,7 @@
/* PAGE_USER indicates the page can be read with user privileges,
* so deposit X1|11 to PL1|PL2 (remember the upper bit of PL1
- * contains _PAGE_READ */
+ * contains _PAGE_READ) */
extrd,u,*= \pte,_PAGE_USER_BIT+32,1,%r0
depdi 7,11,3,\prot
/* If we're a gateway page, drop PL2 back to zero for promotion
@@ -1777,9 +1777,9 @@ ENTRY(sys_fork_wrapper)
ldo -16(%r30),%r29 /* Reference param save area */
#endif
- /* These are call-clobbered registers and therefore
- also syscall-clobbered (we hope). */
- STREG %r2,PT_GR19(%r1) /* save for child */
+ STREG %r2,PT_SYSCALL_RP(%r1) /* save for child */
+
+ /* WARNING - Clobbers r21, userspace must save! */
STREG %r30,PT_GR21(%r1)
LDREG PT_GR30(%r1),%r25
@@ -1809,7 +1809,7 @@ ENTRY(child_return)
nop
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE-FRAME_SIZE(%r30), %r1
- LDREG TASK_PT_GR19(%r1),%r2
+ LDREG TASK_PT_SYSCALL_RP(%r1),%r2
b wrapper_exit
copy %r0,%r28
ENDPROC(child_return)
@@ -1828,8 +1828,9 @@ ENTRY(sys_clone_wrapper)
ldo -16(%r30),%r29 /* Reference param save area */
#endif
- /* WARNING - Clobbers r19 and r21, userspace must save these! */
- STREG %r2,PT_GR19(%r1) /* save for child */
+ STREG %r2,PT_SYSCALL_RP(%r1) /* save for child */
+
+ /* WARNING - Clobbers r21, userspace must save! */
STREG %r30,PT_GR21(%r1)
BL sys_clone,%r2
copy %r1,%r24
@@ -1852,7 +1853,7 @@ ENTRY(sys_vfork_wrapper)
ldo -16(%r30),%r29 /* Reference param save area */
#endif
- STREG %r2,PT_GR19(%r1) /* save for child */
+ STREG %r2,PT_SYSCALL_RP(%r1) /* save for child */
STREG %r30,PT_GR21(%r1)
BL sys_vfork,%r2
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
index c0b1aff..0299d63 100644
--- a/arch/parisc/kernel/irq.c
+++ b/arch/parisc/kernel/irq.c
@@ -410,11 +410,13 @@ void __init init_IRQ(void)
{
local_irq_disable(); /* PARANOID - should already be disabled */
mtctl(~0UL, 23); /* EIRR : clear all pending external intr */
- claim_cpu_irqs();
#ifdef CONFIG_SMP
- if (!cpu_eiem)
+ if (!cpu_eiem) {
+ claim_cpu_irqs();
cpu_eiem = EIEM_MASK(IPI_IRQ) | EIEM_MASK(TIMER_IRQ);
+ }
#else
+ claim_cpu_irqs();
cpu_eiem = EIEM_MASK(TIMER_IRQ);
#endif
set_eiem(cpu_eiem); /* EIEM : enable all external intr */
diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S
index 93ff3d9..5188abd 100644
--- a/arch/parisc/kernel/pacache.S
+++ b/arch/parisc/kernel/pacache.S
@@ -199,7 +199,6 @@ ENTRY(flush_instruction_cache_local)
.callinfo NO_CALLS
.entry
- mtsp %r0, %sr1
load32 cache_info, %r1
/* Flush Instruction Cache */
@@ -208,20 +207,46 @@ ENTRY(flush_instruction_cache_local)
LDREG ICACHE_STRIDE(%r1), %arg1
LDREG ICACHE_COUNT(%r1), %arg2
LDREG ICACHE_LOOP(%r1), %arg3
- rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/
+ rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/
addib,COND(=) -1, %arg3, fioneloop /* Preadjust and test */
movb,<,n %arg3, %r31, fisync /* If loop < 0, do sync */
fimanyloop: /* Loop if LOOP >= 2 */
addib,COND(>) -1, %r31, fimanyloop /* Adjusted inner loop decr */
- fice %r0(%sr1, %arg0)
- fice,m %arg1(%sr1, %arg0) /* Last fice and addr adjust */
+ fice %r0(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0) /* Last fice and addr adjust */
movb,tr %arg3, %r31, fimanyloop /* Re-init inner loop count */
addib,COND(<=),n -1, %arg2, fisync /* Outer loop decr */
fioneloop: /* Loop if LOOP = 1 */
- addib,COND(>) -1, %arg2, fioneloop /* Outer loop count decr */
- fice,m %arg1(%sr1, %arg0) /* Fice for one loop */
+ /* Some implementations may flush with a single fice instruction */
+ cmpib,COND(>>=),n 15, %arg2, fioneloop2
+
+fioneloop1:
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ addib,COND(>) -16, %arg2, fioneloop1
+ fice,m %arg1(%sr2, %arg0)
+
+ /* Check if done */
+ cmpb,COND(=),n %arg2, %r0, fisync /* Predict branch taken */
+
+fioneloop2:
+ addib,COND(>) -1, %arg2, fioneloop2 /* Outer loop count decr */
+ fice,m %arg1(%sr2, %arg0) /* Fice for one loop */
fisync:
sync
@@ -240,8 +265,7 @@ ENTRY(flush_data_cache_local)
.callinfo NO_CALLS
.entry
- mtsp %r0, %sr1
- load32 cache_info, %r1
+ load32 cache_info, %r1
/* Flush Data Cache */
@@ -249,20 +273,46 @@ ENTRY(flush_data_cache_local)
LDREG DCACHE_STRIDE(%r1), %arg1
LDREG DCACHE_COUNT(%r1), %arg2
LDREG DCACHE_LOOP(%r1), %arg3
- rsm PSW_SM_I, %r22
+ rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/
addib,COND(=) -1, %arg3, fdoneloop /* Preadjust and test */
movb,<,n %arg3, %r31, fdsync /* If loop < 0, do sync */
fdmanyloop: /* Loop if LOOP >= 2 */
addib,COND(>) -1, %r31, fdmanyloop /* Adjusted inner loop decr */
- fdce %r0(%sr1, %arg0)
- fdce,m %arg1(%sr1, %arg0) /* Last fdce and addr adjust */
+ fdce %r0(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0) /* Last fdce and addr adjust */
movb,tr %arg3, %r31, fdmanyloop /* Re-init inner loop count */
addib,COND(<=),n -1, %arg2, fdsync /* Outer loop decr */
fdoneloop: /* Loop if LOOP = 1 */
- addib,COND(>) -1, %arg2, fdoneloop /* Outer loop count decr */
- fdce,m %arg1(%sr1, %arg0) /* Fdce for one loop */
+ /* Some implementations may flush with a single fdce instruction */
+ cmpib,COND(>>=),n 15, %arg2, fdoneloop2
+
+fdoneloop1:
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ addib,COND(>) -16, %arg2, fdoneloop1
+ fdce,m %arg1(%sr2, %arg0)
+
+ /* Check if done */
+ cmpb,COND(=),n %arg2, %r0, fdsync /* Predict branch taken */
+
+fdoneloop2:
+ addib,COND(>) -1, %arg2, fdoneloop2 /* Outer loop count decr */
+ fdce,m %arg1(%sr2, %arg0) /* Fdce for one loop */
fdsync:
syncdma
@@ -277,7 +327,34 @@ ENDPROC(flush_data_cache_local)
.align 16
-ENTRY(copy_user_page_asm)
+/* Macros to serialize TLB purge operations on SMP. */
+
+ .macro tlb_lock la,flags,tmp
+#ifdef CONFIG_SMP
+ ldil L%pa_tlb_lock,%r1
+ ldo R%pa_tlb_lock(%r1),\la
+ rsm PSW_SM_I,\flags
+1: LDCW 0(\la),\tmp
+ cmpib,<>,n 0,\tmp,3f
+2: ldw 0(\la),\tmp
+ cmpb,<> %r0,\tmp,1b
+ nop
+ b,n 2b
+3:
+#endif
+ .endm
+
+ .macro tlb_unlock la,flags,tmp
+#ifdef CONFIG_SMP
+ ldi 1,\tmp
+ stw \tmp,0(\la)
+ mtsm \flags
+#endif
+ .endm
+
+/* Copy page using kernel mapping. */
+
+ENTRY(copy_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -399,7 +476,7 @@ ENTRY(copy_user_page_asm)
.exit
.procend
-ENDPROC(copy_user_page_asm)
+ENDPROC(copy_page_asm)
/*
* NOTE: Code in clear_user_page has a hard coded dependency on the
@@ -422,8 +499,6 @@ ENDPROC(copy_user_page_asm)
* %r23 physical page (shifted for tlb insert) of "from" translation
*/
-#if 0
-
/*
* We can't do this since copy_user_page is used to bring in
* file data that might have instructions. Since the data would
@@ -435,6 +510,11 @@ ENDPROC(copy_user_page_asm)
* use it if more information is passed into copy_user_page().
* Have to do some measurements to see if it is worthwhile to
* lobby for such a change.
+ *
+ * JDA: Added code to flush the data cache, so this function
+ * now works. Even with this additional overhead, it may make
+ * sense to use this function because it should handle dirty
+ * `from' pages.
*/
ENTRY(copy_user_page_asm)
@@ -466,9 +546,83 @@ ENTRY(copy_user_page_asm)
/* Purge any old translations */
+ tlb_lock %r20,%r21,%r22
pdtlb 0(%r28)
pdtlb 0(%r29)
+ tlb_unlock %r20,%r21,%r22
+
+ ldil L%dcache_stride, %r23
+ ldw R%dcache_stride(%r23), %r23
+
+#ifdef CONFIG_64BIT
+ /* PA8x00 CPUs can consume 2 loads or 1 store per cycle.
+ * Unroll the loop by hand and arrange insn appropriately.
+ * GCC probably can do this just as well.
+ */
+
+ ldd 0(%r29), %r19
+ ldi (PAGE_SIZE / 128), %r1
+
+ ldw 64(%r29), %r0 /* prefetch 1 cacheline ahead */
+ ldw 128(%r29), %r0 /* prefetch 2 */
+
+1: ldd 8(%r29), %r20
+ ldw 192(%r29), %r0 /* prefetch 3 */
+ ldw 256(%r29), %r0 /* prefetch 4 */
+
+ ldd 16(%r29), %r21
+ ldd 24(%r29), %r22
+ std %r19, 0(%r28)
+ std %r20, 8(%r28)
+
+ ldd 32(%r29), %r19
+ ldd 40(%r29), %r20
+ std %r21, 16(%r28)
+ std %r22, 24(%r28)
+
+ ldd 48(%r29), %r21
+ ldd 56(%r29), %r22
+ std %r19, 32(%r28)
+ std %r20, 40(%r28)
+
+ ldd 64(%r29), %r19
+ ldd 72(%r29), %r20
+ std %r21, 48(%r28)
+ std %r22, 56(%r28)
+
+ ldd 80(%r29), %r21
+ ldd 88(%r29), %r22
+ std %r19, 64(%r28)
+ std %r20, 72(%r28)
+
+ ldd 96(%r29), %r19
+ ldd 104(%r29), %r20
+ std %r21, 80(%r28)
+ std %r22, 88(%r28)
+
+ ldd 112(%r29), %r21
+ ldd 120(%r29), %r22
+ std %r19, 96(%r28)
+ std %r20, 104(%r28)
+
+ ldo 128(%r29), %r29
+ std %r21, 112(%r28)
+ std %r22, 120(%r28)
+
+ /* Flush lines. */
+ ldo 128(%r28), %r24
+ fdc,m %r23(%r28)
+2: cmpb,COND(<<),n %r28,%r24,2b
+ fdc,m %r23(%r28)
+ /* conditional branches nullify on forward taken branch, and on
+ * non-taken backward branch. Note that .+4 is a backwards branch.
+ * The ldd should only get executed if the branch is taken.
+ */
+ addib,COND(>),n -1, %r1, 1b /* bundle 10 */
+ ldd 0(%r29), %r19 /* start next loads */
+
+#else
ldi 64, %r1
/*
@@ -480,9 +634,7 @@ ENTRY(copy_user_page_asm)
* use ldd/std on a 32 bit kernel.
*/
-
-1:
- ldw 0(%r29), %r19
+1: ldw 0(%r29), %r19
ldw 4(%r29), %r20
ldw 8(%r29), %r21
ldw 12(%r29), %r22
@@ -514,19 +666,26 @@ ENTRY(copy_user_page_asm)
stw %r20, 52(%r28)
stw %r21, 56(%r28)
stw %r22, 60(%r28)
- ldo 64(%r28), %r28
+
+ /* Flush lines. */
+ ldo 64(%r28), %r24
+ fdc,m %r23(%r28)
+2: cmpb,COND(<<),n %r28,%r24,2b
+ fdc,m %r23(%r28)
+
addib,COND(>) -1, %r1,1b
ldo 64(%r29), %r29
+#endif
+ sync
bv %r0(%r2)
nop
.exit
.procend
ENDPROC(copy_user_page_asm)
-#endif
-ENTRY(__clear_user_page_asm)
+ENTRY(clear_user_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -550,7 +709,9 @@ ENTRY(__clear_user_page_asm)
/* Purge any old translation */
+ tlb_lock %r20,%r21,%r22
pdtlb 0(%r28)
+ tlb_unlock %r20,%r21,%r22
#ifdef CONFIG_64BIT
ldi (PAGE_SIZE / 128), %r1
@@ -580,8 +741,7 @@ ENTRY(__clear_user_page_asm)
#else /* ! CONFIG_64BIT */
ldi (PAGE_SIZE / 64), %r1
-1:
- stw %r0, 0(%r28)
+1: stw %r0, 0(%r28)
stw %r0, 4(%r28)
stw %r0, 8(%r28)
stw %r0, 12(%r28)
@@ -606,7 +766,7 @@ ENTRY(__clear_user_page_asm)
.exit
.procend
-ENDPROC(__clear_user_page_asm)
+ENDPROC(clear_user_page_asm)
ENTRY(flush_dcache_page_asm)
.proc
@@ -630,7 +790,9 @@ ENTRY(flush_dcache_page_asm)
/* Purge any old translation */
+ tlb_lock %r20,%r21,%r22
pdtlb 0(%r28)
+ tlb_unlock %r20,%r21,%r22
ldil L%dcache_stride, %r1
ldw R%dcache_stride(%r1), %r1
@@ -663,8 +825,11 @@ ENTRY(flush_dcache_page_asm)
fdc,m %r1(%r28)
sync
+ tlb_lock %r20,%r21,%r22
+ pdtlb 0(%r25)
+ tlb_unlock %r20,%r21,%r22
bv %r0(%r2)
- pdtlb (%r25)
+ nop
.exit
.procend
@@ -692,7 +857,9 @@ ENTRY(flush_icache_page_asm)
/* Purge any old translation */
+ tlb_lock %r20,%r21,%r22
pitlb (%sr0,%r28)
+ tlb_unlock %r20,%r21,%r22
ldil L%icache_stride, %r1
ldw R%icache_stride(%r1), %r1
@@ -725,8 +892,11 @@ ENTRY(flush_icache_page_asm)
fic,m %r1(%r28)
sync
- bv %r0(%r2)
+ tlb_lock %r20,%r21,%r22
pitlb (%sr0,%r25)
+ tlb_unlock %r20,%r21,%r22
+ bv %r0(%r2)
+ nop
.exit
.procend
@@ -775,7 +945,7 @@ ENTRY(flush_kernel_dcache_page_asm)
.procend
ENDPROC(flush_kernel_dcache_page_asm)
-ENTRY(purge_kernel_dcache_page)
+ENTRY(purge_kernel_dcache_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -815,7 +985,7 @@ ENTRY(purge_kernel_dcache_page)
.exit
.procend
-ENDPROC(purge_kernel_dcache_page)
+ENDPROC(purge_kernel_dcache_page_asm)
ENTRY(flush_user_dcache_range_asm)
.proc
diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c
index a7bb757..546c51d 100644
--- a/arch/parisc/kernel/parisc_ksyms.c
+++ b/arch/parisc/kernel/parisc_ksyms.c
@@ -159,4 +159,4 @@ EXPORT_SYMBOL(_mcount);
#endif
/* from pacache.S -- needed for copy_page */
-EXPORT_SYMBOL(copy_user_page_asm);
+EXPORT_SYMBOL(copy_page_asm);
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 12c1ed3..5dd1059 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -314,7 +314,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
#if DEBUG_SIG
/* Assert that we're flushing in the correct space... */
{
- int sid;
+ unsigned long sid;
asm ("mfsp %%sr3,%0" : "=r" (sid));
DBG(1,"setup_rt_frame: Flushing 64 bytes at space %#x offset %p\n",
sid, frame->tramp);
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
index c9b9322..f0cb56e 100644
--- a/arch/parisc/kernel/sys_parisc.c
+++ b/arch/parisc/kernel/sys_parisc.c
@@ -92,11 +92,12 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
{
if (len > TASK_SIZE)
return -ENOMEM;
- /* Might want to check for cache aliasing issues for MAP_FIXED case
- * like ARM or MIPS ??? --BenH.
- */
- if (flags & MAP_FIXED)
+ if (flags & MAP_FIXED) {
+ if ((flags & MAP_SHARED) &&
+ (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
+ return -EINVAL;
return addr;
+ }
if (!addr)
addr = TASK_UNMAPPED_BASE;
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c
index 45b7389..53a1c69 100644
--- a/arch/parisc/kernel/time.c
+++ b/arch/parisc/kernel/time.c
@@ -76,7 +76,7 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
cycles_elapsed = now - next_tick;
- if ((cycles_elapsed >> 6) < cpt) {
+ if ((cycles_elapsed >> 7) < cpt) {
/* use "cheap" math (add/subtract) instead
* of the more expensive div/mul method
*/
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index dc5114b..1d6d390 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -531,6 +531,7 @@ out_eoi:
void
handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
{
+ struct irqaction *action;
struct irq_chip *chip = irq_desc_get_chip(desc);
kstat_incr_irqs_this_cpu(irq, desc);
@@ -538,7 +539,9 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
if (chip->irq_ack)
chip->irq_ack(&desc->irq_data);
- handle_irq_event_percpu(desc, desc->action);
+ action = desc->action;
+ if (action)
+ handle_irq_event_percpu(desc, action);
if (chip->irq_eoi)
chip->irq_eoi(&desc->irq_data);
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: Happy New Year PARISC
2012-01-02 23:12 ` John David Anglin
@ 2012-01-03 11:50 ` Carlos O'Donell
2012-01-03 15:13 ` John David Anglin
0 siblings, 1 reply; 18+ messages in thread
From: Carlos O'Donell @ 2012-01-03 11:50 UTC (permalink / raw)
To: John David Anglin; +Cc: Grant Grundler, linux-parisc List
On Mon, Jan 2, 2012 at 6:12 PM, John David Anglin <dave.anglin@bell.net=
> wrote:
> None of this worked. =A0Attached patch as it stands. =A0Comments and =
testing
> appreciated.
Could you clarify what you mean by "none of this worked?"
Cheers,
Carlos.
--
To unsubscribe from this list: send the line "unsubscribe linux-parisc"=
in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Happy New Year PARISC
2012-01-03 11:50 ` Carlos O'Donell
@ 2012-01-03 15:13 ` John David Anglin
2012-01-03 15:32 ` James Bottomley
2012-01-03 15:32 ` James Bottomley
0 siblings, 2 replies; 18+ messages in thread
From: John David Anglin @ 2012-01-03 15:13 UTC (permalink / raw)
To: Carlos O'Donell; +Cc: Grant Grundler, linux-parisc List
On 1/3/2012 6:50 AM, Carlos O'Donell wrote:
> On Mon, Jan 2, 2012 at 6:12 PM, John David Anglin<dave.anglin@bell.net> wrote:
>> None of this worked. Attached patch as it stands. Comments and testing
>> appreciated.
> Could you clarify what you mean by "none of this worked?"
>
I tried eliminating the flushes that occur in kunmap_atomic on PA8800
and PA8900
after the calls to clear_user_page and copy_user_page by defining
clear_user_highpage
and copy_user_highpage. I had thought the flushes weren't necessary.
There's something
about this that I don't understand. Why do we need to flush
non-equivalent page mappings
that aren't used?
Also tried:
#define flush_cache_dup_mm(mm) do { } while (0)
In both cases, init died causing a panic at boot. Maybe there's
something missing at
startup.
Most arch's have the above define for flush_cache_dup_mm. Our define
really hurts
fork performance. The GCC testsuite takes almost twice as long to run
on linux as hpux.
On the other hand, build times are fairly comparable.
Dave
--
John David Anglin dave.anglin@bell.net
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Happy New Year PARISC
2012-01-03 15:13 ` John David Anglin
@ 2012-01-03 15:32 ` James Bottomley
2012-01-03 15:32 ` James Bottomley
1 sibling, 0 replies; 18+ messages in thread
From: James Bottomley @ 2012-01-03 15:32 UTC (permalink / raw)
To: John David Anglin; +Cc: Carlos O'Donell, Grant Grundler, linux-parisc List
On Tue, 2012-01-03 at 10:13 -0500, John David Anglin wrote:
> On 1/3/2012 6:50 AM, Carlos O'Donell wrote:
> > On Mon, Jan 2, 2012 at 6:12 PM, John David Anglin<dave.anglin@bell.net> wrote:
> >> None of this worked. Attached patch as it stands. Comments and testing
> >> appreciated.
> > Could you clarify what you mean by "none of this worked?"
> >
>
> I tried eliminating the flushes that occur in kunmap_atomic on PA8800
> and PA8900
> after the calls to clear_user_page and copy_user_page by defining
> clear_user_highpage
> and copy_user_highpage. I had thought the flushes weren't necessary.
> There's something
> about this that I don't understand. Why do we need to flush
> non-equivalent page mappings
> that aren't used?
But they are used: Your work makes sure that all user space mappings
are equivalent. However, because of the way Linux sets up kernel
mappings (from the pfn array and offsets) the user virtual address and
kernel virtual address almost never are. kmap is exclusively used so
the kernel can access a user page, and at that point, we need to flush
because we've set up an inequivalent alias (even if it's only done for
read)
kmap/kmap_atomic is used in more than just copy/flush ... or did you
mean that you removed the kmap calls in copy/flush and the whole thing
doesn't work (rather than as you imply you removed the flush in kunmap?)
> Also tried:
> #define flush_cache_dup_mm(mm) do { } while (0)
>
> In both cases, init died causing a panic at boot. Maybe there's
> something missing at
> startup.
>
> Most arch's have the above define for flush_cache_dup_mm. Our define
> really hurts
> fork performance. The GCC testsuite takes almost twice as long to run
> on linux as hpux.
> On the other hand, build times are fairly comparable.
I'll look into this, but I fear, because of the way the pa cache is
tagged, we'll have to keep the flush (same goes for flush_cache_mm).
James
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Happy New Year PARISC
2012-01-03 15:13 ` John David Anglin
2012-01-03 15:32 ` James Bottomley
@ 2012-01-03 15:32 ` James Bottomley
2012-01-03 16:26 ` John David Anglin
1 sibling, 1 reply; 18+ messages in thread
From: James Bottomley @ 2012-01-03 15:32 UTC (permalink / raw)
To: John David Anglin; +Cc: Carlos O'Donell, Grant Grundler, linux-parisc List
On Tue, 2012-01-03 at 10:13 -0500, John David Anglin wrote:
> On 1/3/2012 6:50 AM, Carlos O'Donell wrote:
> > On Mon, Jan 2, 2012 at 6:12 PM, John David Anglin<dave.anglin@bell.net> wrote:
> >> None of this worked. Attached patch as it stands. Comments and testing
> >> appreciated.
> > Could you clarify what you mean by "none of this worked?"
> >
>
> I tried eliminating the flushes that occur in kunmap_atomic on PA8800
> and PA8900
> after the calls to clear_user_page and copy_user_page by defining
> clear_user_highpage
> and copy_user_highpage. I had thought the flushes weren't necessary.
> There's something
> about this that I don't understand. Why do we need to flush
> non-equivalent page mappings
> that aren't used?
But they are used: Your work makes sure that all user space mappings
are equivalent. However, because of the way Linux sets up kernel
mappings (from the pfn array and offsets) the user virtual address and
kernel virtual address almost never are. kmap is exclusively used so
the kernel can access a user page, and at that point, we need to flush
because we've set up an inequivalent alias (even if it's only done for
read)
kmap/kmap_atomic is used in more than just copy/flush ... or did you
mean that you removed the kmap calls in copy/flush and the whole thing
doesn't work (rather than as you imply you removed the flush in kunmap?)
> Also tried:
> #define flush_cache_dup_mm(mm) do { } while (0)
>
> In both cases, init died causing a panic at boot. Maybe there's
> something missing at
> startup.
>
> Most arch's have the above define for flush_cache_dup_mm. Our define
> really hurts
> fork performance. The GCC testsuite takes almost twice as long to run
> on linux as hpux.
> On the other hand, build times are fairly comparable.
I'll look into this, but I fear, because of the way the pa cache is
tagged, we'll have to keep the flush (same goes for flush_cache_mm).
James
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Happy New Year PARISC
2012-01-03 15:32 ` James Bottomley
@ 2012-01-03 16:26 ` John David Anglin
2012-01-03 16:42 ` John David Anglin
2012-01-03 16:42 ` James Bottomley
0 siblings, 2 replies; 18+ messages in thread
From: John David Anglin @ 2012-01-03 16:26 UTC (permalink / raw)
To: James Bottomley; +Cc: Carlos O'Donell, Grant Grundler, linux-parisc List
On 1/3/2012 10:32 AM, James Bottomley wrote:
> On Tue, 2012-01-03 at 10:13 -0500, John David Anglin wrote:
>> On 1/3/2012 6:50 AM, Carlos O'Donell wrote:
>>> On Mon, Jan 2, 2012 at 6:12 PM, John David Anglin<dave.anglin@bell.net> wrote:
>>>> None of this worked. Attached patch as it stands. Comments and testing
>>>> appreciated.
>>> Could you clarify what you mean by "none of this worked?"
>>>
>> I tried eliminating the flushes that occur in kunmap_atomic on PA8800
>> and PA8900
>> after the calls to clear_user_page and copy_user_page by defining
>> clear_user_highpage
>> and copy_user_highpage. I had thought the flushes weren't necessary.
>> There's something
>> about this that I don't understand. Why do we need to flush
>> non-equivalent page mappings
>> that aren't used?
> But they are used: Your work makes sure that all user space mappings
> are equivalent. However, because of the way Linux sets up kernel
> mappings (from the pfn array and offsets) the user virtual address and
> kernel virtual address almost never are. kmap is exclusively used so
> the kernel can access a user page, and at that point, we need to flush
> because we've set up an inequivalent alias (even if it's only done for
> read)
>
> kmap/kmap_atomic is used in more than just copy/flush ... or did you
> mean that you removed the kmap calls in copy/flush and the whole thing
> doesn't work (rather than as you imply you removed the flush in kunmap?)
>
I didn't modify kmap/kunmap_atomic. I wrote versions of
clear_user_highpage and
copy_user_highpage to replace the default versions in linux/highmem.h.
I replaced
the kunmap_atomic calls with pagefault_enable to avoid the flush in the
returns from
clear/copy_user_page (actually, I only used one call to
pagefault_enable, so maybe
that was the issue). As far as I could tell, clear/copy_user_page are
only called via
clear/copy_user_highpage. The behavior of kmap/kunmap_atomic in other
situations
shouldn't have changed.
Chapter F makes it clear that *all* inequivalent aliases to a page have
to be removed
when a write capable translation is enabled (no flush needed). When a
write-capable
translation needs to be read through an inequivalent alias, the page is
supposed to
be flushed, the write-capable translation is supposed to be removed from
the page
directory and then purged.
That's why I added the purge_tlb_entries calls to set_pte_at and
ptep_set_wrprotect.
We avoid the flush by doing the `from' read through an equivalent
mapping. However,
the inequivalent mapping is still there. It seems to be necessary to
purge the TLB
entries prior to clearing/copying. However, from what I read in Chapter
F, the purge
is probably insufficient to speculative prevent move in. If I recall
correctly, the
kunmap_atomic also generates another TLB purge as well as a flush.
There is a special access type (7) that can be used to prevent read and
write move in.
Dave
--
John David Anglin dave.anglin@bell.net
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Happy New Year PARISC
2012-01-03 16:26 ` John David Anglin
@ 2012-01-03 16:42 ` John David Anglin
2012-01-03 16:42 ` James Bottomley
1 sibling, 0 replies; 18+ messages in thread
From: John David Anglin @ 2012-01-03 16:42 UTC (permalink / raw)
To: James Bottomley; +Cc: Carlos O'Donell, Grant Grundler, linux-parisc List
On 1/3/2012 11:26 AM, John David Anglin wrote:
> I replaced
> the kunmap_atomic calls with pagefault_enable to avoid the flush in
> the returns from
> clear/copy_user_page (actually, I only used one call to
> pagefault_enable, so maybe
> that was the issue).
It looks like I messed up the enable. Will retry.
Dave
--
John David Anglin dave.anglin@bell.net
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Happy New Year PARISC
2012-01-03 16:26 ` John David Anglin
2012-01-03 16:42 ` John David Anglin
@ 2012-01-03 16:42 ` James Bottomley
2012-01-03 18:39 ` John David Anglin
1 sibling, 1 reply; 18+ messages in thread
From: James Bottomley @ 2012-01-03 16:42 UTC (permalink / raw)
To: John David Anglin; +Cc: Carlos O'Donell, Grant Grundler, linux-parisc List
On Tue, 2012-01-03 at 11:26 -0500, John David Anglin wrote:
> On 1/3/2012 10:32 AM, James Bottomley wrote:
> > On Tue, 2012-01-03 at 10:13 -0500, John David Anglin wrote:
> >> On 1/3/2012 6:50 AM, Carlos O'Donell wrote:
> >>> On Mon, Jan 2, 2012 at 6:12 PM, John David Anglin<dave.anglin@bell.net> wrote:
> >>>> None of this worked. Attached patch as it stands. Comments and testing
> >>>> appreciated.
> >>> Could you clarify what you mean by "none of this worked?"
> >>>
> >> I tried eliminating the flushes that occur in kunmap_atomic on PA8800
> >> and PA8900
> >> after the calls to clear_user_page and copy_user_page by defining
> >> clear_user_highpage
> >> and copy_user_highpage. I had thought the flushes weren't necessary.
> >> There's something
> >> about this that I don't understand. Why do we need to flush
> >> non-equivalent page mappings
> >> that aren't used?
> > But they are used: Your work makes sure that all user space mappings
> > are equivalent. However, because of the way Linux sets up kernel
> > mappings (from the pfn array and offsets) the user virtual address and
> > kernel virtual address almost never are. kmap is exclusively used so
> > the kernel can access a user page, and at that point, we need to flush
> > because we've set up an inequivalent alias (even if it's only done for
> > read)
> >
> > kmap/kmap_atomic is used in more than just copy/flush ... or did you
> > mean that you removed the kmap calls in copy/flush and the whole thing
> > doesn't work (rather than as you imply you removed the flush in kunmap?)
> >
> I didn't modify kmap/kunmap_atomic. I wrote versions of
> clear_user_highpage and
> copy_user_highpage to replace the default versions in linux/highmem.h.
> I replaced
> the kunmap_atomic calls with pagefault_enable to avoid the flush in the
> returns from
> clear/copy_user_page (actually, I only used one call to
> pagefault_enable, so maybe
> that was the issue). As far as I could tell, clear/copy_user_page are
> only called via
> clear/copy_user_highpage. The behavior of kmap/kunmap_atomic in other
> situations
> shouldn't have changed.
>
> Chapter F makes it clear that *all* inequivalent aliases to a page have
> to be removed
> when a write capable translation is enabled (no flush needed). When a
> write-capable
> translation needs to be read through an inequivalent alias, the page is
> supposed to
> be flushed, the write-capable translation is supposed to be removed from
> the page
> directory and then purged.
>
> That's why I added the purge_tlb_entries calls to set_pte_at and
> ptep_set_wrprotect.
> We avoid the flush by doing the `from' read through an equivalent
> mapping. However,
> the inequivalent mapping is still there. It seems to be necessary to
> purge the TLB
> entries prior to clearing/copying. However, from what I read in Chapter
> F, the purge
> is probably insufficient to speculative prevent move in. If I recall
> correctly, the
> kunmap_atomic also generates another TLB purge as well as a flush.
>
> There is a special access type (7) that can be used to prevent read and
> write move in.
Actually, now I recall why copy_user_highpage never got implemented
through the tmpalias space: it does cache hot copies (so we effectively
copy straight from the cache of the source address into the cache of the
destination). This is all fine and dandy and very fast until we have to
copy executable pages: in this case, we set up an I/D cache
inconsistency in userspace (which userspace apparently doesn't expect).
It can be resolved by flushing the userspace cache, so the page becomes
up to date an I movein sees the correct data, which is probably what the
flush you still need is doing.
James
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Happy New Year PARISC
2012-01-03 16:42 ` James Bottomley
@ 2012-01-03 18:39 ` John David Anglin
2012-01-29 21:45 ` Happy New Year PARISC (take 2) John David Anglin
0 siblings, 1 reply; 18+ messages in thread
From: John David Anglin @ 2012-01-03 18:39 UTC (permalink / raw)
To: James Bottomley; +Cc: Carlos O'Donell, Grant Grundler, linux-parisc List
On 1/3/2012 11:42 AM, James Bottomley wrote:
> On Tue, 2012-01-03 at 11:26 -0500, John David Anglin wrote:
>> On 1/3/2012 10:32 AM, James Bottomley wrote:
>>> On Tue, 2012-01-03 at 10:13 -0500, John David Anglin wrote:
>>>> On 1/3/2012 6:50 AM, Carlos O'Donell wrote:
>>>>> On Mon, Jan 2, 2012 at 6:12 PM, John David Anglin<dave.anglin@bell.net> wrote:
>>>>>> None of this worked. Attached patch as it stands. Comments and testing
>>>>>> appreciated.
>>>>> Could you clarify what you mean by "none of this worked?"
>>>>>
>>>> I tried eliminating the flushes that occur in kunmap_atomic on PA8800
>>>> and PA8900
>>>> after the calls to clear_user_page and copy_user_page by defining
>>>> clear_user_highpage
>>>> and copy_user_highpage. I had thought the flushes weren't necessary.
>>>> There's something
>>>> about this that I don't understand. Why do we need to flush
>>>> non-equivalent page mappings
>>>> that aren't used?
>>> But they are used: Your work makes sure that all user space mappings
>>> are equivalent. However, because of the way Linux sets up kernel
>>> mappings (from the pfn array and offsets) the user virtual address and
>>> kernel virtual address almost never are. kmap is exclusively used so
>>> the kernel can access a user page, and at that point, we need to flush
>>> because we've set up an inequivalent alias (even if it's only done for
>>> read)
>>>
>>> kmap/kmap_atomic is used in more than just copy/flush ... or did you
>>> mean that you removed the kmap calls in copy/flush and the whole thing
>>> doesn't work (rather than as you imply you removed the flush in kunmap?)
>>>
>> I didn't modify kmap/kunmap_atomic. I wrote versions of
>> clear_user_highpage and
>> copy_user_highpage to replace the default versions in linux/highmem.h.
>> I replaced
>> the kunmap_atomic calls with pagefault_enable to avoid the flush in the
>> returns from
>> clear/copy_user_page (actually, I only used one call to
>> pagefault_enable, so maybe
>> that was the issue). As far as I could tell, clear/copy_user_page are
>> only called via
>> clear/copy_user_highpage. The behavior of kmap/kunmap_atomic in other
>> situations
>> shouldn't have changed.
>>
>> Chapter F makes it clear that *all* inequivalent aliases to a page have
>> to be removed
>> when a write capable translation is enabled (no flush needed). When a
>> write-capable
>> translation needs to be read through an inequivalent alias, the page is
>> supposed to
>> be flushed, the write-capable translation is supposed to be removed from
>> the page
>> directory and then purged.
>>
>> That's why I added the purge_tlb_entries calls to set_pte_at and
>> ptep_set_wrprotect.
>> We avoid the flush by doing the `from' read through an equivalent
>> mapping. However,
>> the inequivalent mapping is still there. It seems to be necessary to
>> purge the TLB
>> entries prior to clearing/copying. However, from what I read in Chapter
>> F, the purge
>> is probably insufficient to speculative prevent move in. If I recall
>> correctly, the
>> kunmap_atomic also generates another TLB purge as well as a flush.
>>
>> There is a special access type (7) that can be used to prevent read and
>> write move in.
> Actually, now I recall why copy_user_highpage never got implemented
> through the tmpalias space: it does cache hot copies (so we effectively
> copy straight from the cache of the source address into the cache of the
> destination). This is all fine and dandy and very fast until we have to
> copy executable pages: in this case, we set up an I/D cache
> inconsistency in userspace (which userspace apparently doesn't expect).
> It can be resolved by flushing the userspace cache, so the page becomes
> up to date an I movein sees the correct data, which is probably what the
> flush you still need is doing.
>
Note that I added flush code to "copy_user_page_asm" to handle this. I
guess this
flush could be avoided if we knew the page wasn't executable, but it is
not that easy
to figure out if a page is executable without the vma or mm. I also
added 64-bit
support and renamed the old version to copy_page_asm so both versions
would be
available for use/testing.
I see that copy_user_highpage does have the vma, so maybe there is some hope
of further optimizing copy_user_page_asm.
I came to the conclusion that it was better to do a flush when copying
through the
tmpalias space than try to flush the `from' page in ptep_set_wrprotect
as proposed
by Niibe a couple of years ago. First, a COW page may never be written
to, so
why do a unnecessary flush (my assumption based on the documentation is
that
clear/copy_user_page are primarily for COW support)?
At the time the minifail bug was being discussed, I hadn't realized that
the TLB
needed purging in set_pte_at and ptep_set_wrprotect. This became clear when
I looked at arm. Without the TLB purge, the flush proposed by Niibe was
still
racy.
Dave
--
John David Anglin dave.anglin@bell.net
^ permalink raw reply [flat|nested] 18+ messages in thread
* Happy New Year PARISC (take 2)
2012-01-03 18:39 ` John David Anglin
@ 2012-01-29 21:45 ` John David Anglin
[not found] ` <CA+DQjFiTwKC76Hn-x-s2C9Nc_qkqrRFXv3ji22KGtgMzGOfx0Q@mail.gmail.com>
2012-02-28 15:28 ` John David Anglin
0 siblings, 2 replies; 18+ messages in thread
From: John David Anglin @ 2012-01-29 21:45 UTC (permalink / raw)
To: John David Anglin
Cc: James Bottomley, Carlos O'Donell, Grant Grundler,
linux-parisc List
[-- Attachment #1: Type: text/plain, Size: 1694 bytes --]
Here is take take 2. It's against linux-stable v3.2.2. I also have a
very similar
version against v3.1.10.
This one implements clear_user_highpage and copy_user_highpage. I
revamped the patch to make it trivial to test the tmpalias and kmap
versions.
At the moment, it is setup for kmap.
I tested the tmpalias version for a couple of weeks. I now have more
than
a week of testing with the latest kmap version. The general stability
of the
kmap version is good (i.e., no random segmentation faults). Of
course, I
have rebuilt most of userspace with binutils 2.22 and GCC 4.6 to avoid
the non equivalent alias bug present in earlier versions of binutils.
My current impression is the kmap version is better. With the tmpalias
version, I saw the occasional hpmc in the GCC libgomp testsuite. I
haven't had one with the kmap version so far.
I believe both versions fix the minifail bug and some thread related
bugs
seen in the perl, python and git testsuites. However, there are still
more
thread related bugs to fix.
The minifail bug is fixed by the TLB purge added to ptep_set_wrprotect,
and flushing the `from' page in copy_user_page (kmap version). The
tmpalias version doesn't need this flush, but the `to' page needs to be
flushed. So, both versions have about the same flush requirements.
This version fixes the math emulation bug that I reported, but I have
another one that I haven't tracked down.
It would be great if someone else could test the change on something
other
than a rp3440. The cache issues are very subtle. If the results are
positive,
I will break up the patch and formally submit it.
Dave
--
John David Anglin dave.anglin@bell.net
[-- Attachment #2: linux-stable-3.2.2-20120129.d.txt --]
[-- Type: text/plain, Size: 33418 bytes --]
diff --git a/arch/parisc/hpux/wrappers.S b/arch/parisc/hpux/wrappers.S
index 58c53c8..bdcea33 100644
--- a/arch/parisc/hpux/wrappers.S
+++ b/arch/parisc/hpux/wrappers.S
@@ -88,7 +88,7 @@ ENTRY(hpux_fork_wrapper)
STREG %r2,-20(%r30)
ldo 64(%r30),%r30
- STREG %r2,PT_GR19(%r1) ;! save for child
+ STREG %r2,PT_SYSCALL_RP(%r1) ;! save for child
STREG %r30,PT_GR21(%r1) ;! save for child
LDREG PT_GR30(%r1),%r25
@@ -132,7 +132,7 @@ ENTRY(hpux_child_return)
bl,n schedule_tail, %r2
#endif
- LDREG TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2
+ LDREG TASK_PT_SYSCALL_RP-TASK_SZ_ALGN-128(%r30),%r2
b fork_return
copy %r0,%r28
ENDPROC(hpux_child_return)
diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h
index 2388bdb..7839285 100644
--- a/arch/parisc/include/asm/futex.h
+++ b/arch/parisc/include/asm/futex.h
@@ -8,6 +8,29 @@
#include <asm/atomic.h>
#include <asm/errno.h>
+/* The following has to match the LWS code in syscall.S. We have
+ sixteen four-word locks. */
+
+static inline void
+_futex_spin_lock_irqsave (u32 __user *uaddr, unsigned long int *flags)
+{
+ extern u32 lws_lock_start[];
+ long index = ((long)uaddr & 0xf0) >> 2;
+ arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
+ local_irq_save(*flags);
+ arch_spin_lock(s);
+}
+
+static inline void
+_futex_spin_unlock_irqrestore (u32 __user *uaddr, unsigned long int *flags)
+{
+ extern u32 lws_lock_start[];
+ long index = ((long)uaddr & 0xf0) >> 2;
+ arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
+ arch_spin_unlock(s);
+ local_irq_restore(*flags);
+}
+
static inline int
futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
@@ -26,7 +49,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
pagefault_disable();
- _atomic_spin_lock_irqsave(uaddr, flags);
+ _futex_spin_lock_irqsave(uaddr, &flags);
switch (op) {
case FUTEX_OP_SET:
@@ -71,7 +94,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
ret = -ENOSYS;
}
- _atomic_spin_unlock_irqrestore(uaddr, flags);
+ _futex_spin_unlock_irqrestore(uaddr, &flags);
pagefault_enable();
@@ -113,7 +136,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
* address. This should scale to a couple of CPUs.
*/
- _atomic_spin_lock_irqsave(uaddr, flags);
+ _futex_spin_lock_irqsave(uaddr, &flags);
ret = get_user(val, uaddr);
@@ -122,7 +145,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
*uval = val;
- _atomic_spin_unlock_irqrestore(uaddr, flags);
+ _futex_spin_unlock_irqrestore(uaddr, &flags);
return ret;
}
diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h
index a84cc1f..14b2a96 100644
--- a/arch/parisc/include/asm/page.h
+++ b/arch/parisc/include/asm/page.h
@@ -22,14 +22,25 @@
#include <asm/cache.h>
#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
-#define copy_page(to,from) copy_user_page_asm((void *)(to), (void *)(from))
+#define copy_page(to,from) copy_page_asm((void *)(to), (void *)(from))
struct page;
-void copy_user_page_asm(void *to, void *from);
+void copy_page_asm(void *to, void *from);
+void clear_user_page(void *vto, unsigned long vaddr, struct page *pg);
void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
struct page *pg);
-void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
+
+// #define CONFIG_PARISC_TMPALIAS
+
+#ifdef CONFIG_PARISC_TMPALIAS
+void clear_user_highpage(struct page *page, unsigned long vaddr);
+#define clear_user_highpage clear_user_highpage
+struct vm_area_struct;
+void copy_user_highpage(struct page *to, struct page *from,
+ unsigned long vaddr, struct vm_area_struct *vma);
+#define __HAVE_ARCH_COPY_USER_HIGHPAGE
+#endif
/*
* These are used to make use of C type-checking..
diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
index 22dadeb..891b369 100644
--- a/arch/parisc/include/asm/pgtable.h
+++ b/arch/parisc/include/asm/pgtable.h
@@ -40,7 +40,14 @@ struct vm_area_struct;
do{ \
*(pteptr) = (pteval); \
} while(0)
-#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+
+extern void purge_tlb_entries(struct mm_struct *, unsigned long);
+
+#define set_pte_at(mm,addr,ptep, pteval) \
+ do{ \
+ set_pte(ptep,pteval); \
+ purge_tlb_entries(mm,addr); \
+ } while(0)
#endif /* !__ASSEMBLY__ */
@@ -460,10 +467,13 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
#ifdef CONFIG_SMP
unsigned long new, old;
+ /* ??? This might be racy because the page table updates in
+ entry.S don't use the same lock. */
do {
old = pte_val(*ptep);
new = pte_val(pte_wrprotect(__pte (old)));
} while (cmpxchg((unsigned long *) ptep, old, new) != old);
+ purge_tlb_entries(mm, addr);
#else
pte_t old_pte = *ptep;
set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
diff --git a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c
index dcd5510..5df1597 100644
--- a/arch/parisc/kernel/asm-offsets.c
+++ b/arch/parisc/kernel/asm-offsets.c
@@ -141,6 +141,7 @@ int main(void)
DEFINE(TASK_PT_IAOQ0, offsetof(struct task_struct, thread.regs.iaoq[0]));
DEFINE(TASK_PT_IAOQ1, offsetof(struct task_struct, thread.regs.iaoq[1]));
DEFINE(TASK_PT_CR27, offsetof(struct task_struct, thread.regs.cr27));
+ DEFINE(TASK_PT_SYSCALL_RP, offsetof(struct task_struct, thread.regs.pad0));
DEFINE(TASK_PT_ORIG_R28, offsetof(struct task_struct, thread.regs.orig_r28));
DEFINE(TASK_PT_KSP, offsetof(struct task_struct, thread.regs.ksp));
DEFINE(TASK_PT_KPC, offsetof(struct task_struct, thread.regs.kpc));
@@ -230,6 +231,7 @@ int main(void)
DEFINE(PT_IAOQ0, offsetof(struct pt_regs, iaoq[0]));
DEFINE(PT_IAOQ1, offsetof(struct pt_regs, iaoq[1]));
DEFINE(PT_CR27, offsetof(struct pt_regs, cr27));
+ DEFINE(PT_SYSCALL_RP, offsetof(struct pt_regs, pad0));
DEFINE(PT_ORIG_R28, offsetof(struct pt_regs, orig_r28));
DEFINE(PT_KSP, offsetof(struct pt_regs, ksp));
DEFINE(PT_KPC, offsetof(struct pt_regs, kpc));
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index 83335f3..fb752dc 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -134,7 +134,7 @@ parisc_cache_init(void)
if (pdc_cache_info(&cache_info) < 0)
panic("parisc_cache_init: pdc_cache_info failed");
-#if 0
+#if 1
printk("ic_size %lx dc_size %lx it_size %lx\n",
cache_info.ic_size,
cache_info.dc_size,
@@ -316,7 +316,7 @@ void flush_dcache_page(struct page *page)
flush_tlb_page(mpnt, addr);
if (old_addr == 0 || (old_addr & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) {
__flush_cache_page(mpnt, addr, page_to_phys(page));
- if (old_addr)
+ if (old_addr && parisc_requires_coherency())
printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? (char *)mpnt->vm_file->f_path.dentry->d_name.name : "(null)");
old_addr = addr;
}
@@ -331,17 +331,6 @@ EXPORT_SYMBOL(flush_kernel_dcache_page_asm);
EXPORT_SYMBOL(flush_data_cache_local);
EXPORT_SYMBOL(flush_kernel_icache_range_asm);
-void clear_user_page_asm(void *page, unsigned long vaddr)
-{
- unsigned long flags;
- /* This function is implemented in assembly in pacache.S */
- extern void __clear_user_page_asm(void *page, unsigned long vaddr);
-
- purge_tlb_start(flags);
- __clear_user_page_asm(page, vaddr);
- purge_tlb_end(flags);
-}
-
#define FLUSH_THRESHOLD 0x80000 /* 0.5MB */
int parisc_cache_flush_threshold __read_mostly = FLUSH_THRESHOLD;
@@ -375,20 +364,9 @@ void __init parisc_setup_cache_timing(void)
printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus());
}
-extern void purge_kernel_dcache_page(unsigned long);
-extern void clear_user_page_asm(void *page, unsigned long vaddr);
-
-void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
-{
- unsigned long flags;
-
- purge_kernel_dcache_page((unsigned long)page);
- purge_tlb_start(flags);
- pdtlb_kernel(page);
- purge_tlb_end(flags);
- clear_user_page_asm(page, vaddr);
-}
-EXPORT_SYMBOL(clear_user_page);
+extern void purge_kernel_dcache_page_asm(unsigned long);
+extern void clear_user_page_asm(void *, unsigned long);
+extern void copy_user_page_asm(void *, void *, unsigned long);
void flush_kernel_dcache_page_addr(void *addr)
{
@@ -401,11 +379,24 @@ void flush_kernel_dcache_page_addr(void *addr)
}
EXPORT_SYMBOL(flush_kernel_dcache_page_addr);
+void clear_user_page(void *vto, unsigned long vaddr, struct page *page)
+{
+ memset(vto, 0, PAGE_SIZE);
+ if (!parisc_requires_coherency())
+ flush_kernel_dcache_page_asm(vto);
+}
+EXPORT_SYMBOL(clear_user_page);
+
void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
- struct page *pg)
+ struct page *pg)
{
- /* no coherency needed (all in kmap/kunmap) */
- copy_user_page_asm(vto, vfrom);
+ /* Copy using kernel mapping. No coherency is needed
+ (all in kmap/kunmap) on machines that don't support
+ non-equivalent aliasing. However, the `from' page
+ needs to be flushed before it can be accessed through
+ the kernel mapping. */
+ flush_dcache_page_asm(__pa(vfrom), vaddr);
+ copy_page_asm(vto, vfrom);
if (!parisc_requires_coherency())
flush_kernel_dcache_page_asm(vto);
}
@@ -487,18 +478,90 @@ flush_user_icache_range(unsigned long start, unsigned long end)
flush_instruction_cache();
}
+/* While useful for testing, this check has too much overhead for
+ general use. Thus, it is better to fix inequivalent mappings
+ than whack the cache. */
+#define DEBUG_PAGE_MAPPING 0
+
+static inline void check_page_mapping(struct page *page)
+{
+#if DEBUG_PAGE_MAPPING
+ struct address_space *mapping = page_mapping(page);
+ struct vm_area_struct *mpnt;
+ struct prio_tree_iter iter;
+ unsigned long offset;
+ unsigned long addr, old_addr = 0;
+ pgoff_t pgoff;
+
+ if (!mapping || !mapping_mapped(mapping))
+ return;
+
+ pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
+
+ /* Check that all mappings of a file are congruently mapped */
+
+ flush_dcache_mmap_lock(mapping);
+ vma_prio_tree_foreach(mpnt, &iter, &mapping->i_mmap, pgoff, pgoff) {
+ offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
+ addr = mpnt->vm_start + offset;
+ if (old_addr == 0 || (old_addr & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) {
+ if (old_addr) {
+ printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? (char *)mpnt->vm_file->f_path.dentry->d_name.name : "(null)");
+ }
+ old_addr = addr;
+ }
+ }
+ flush_dcache_mmap_unlock(mapping);
+#endif
+}
+
+static inline pte_t *get_ptep(pgd_t *pgd, unsigned long addr)
+{
+ pte_t *ptep = NULL;
+
+ if (!pgd_none(*pgd)) {
+ pud_t *pud = pud_offset(pgd, addr);
+ if (!pud_none(*pud)) {
+ pmd_t *pmd = pmd_offset(pud, addr);
+ if (!pmd_none(*pmd)) {
+ ptep = pte_offset_map(pmd, addr);
+ }
+ }
+ }
+ return ptep;
+}
+
+/* While flushing by page is slightly less efficient, it allows detection
+ of pages without pte's and mappings with inequivalent aliases. */
+
+#define FLUSH_CACHE_RANGE_BY_PAGE 0
void flush_cache_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
- int sr3;
-
BUG_ON(!vma->vm_mm->context);
- sr3 = mfsp(3);
- if (vma->vm_mm->context == sr3) {
- flush_user_dcache_range(start,end);
- flush_user_icache_range(start,end);
+ if ((end - start) < parisc_cache_flush_threshold
+ && vma->vm_mm->context == mfsp(3)) {
+#if FLUSH_CACHE_RANGE_BY_PAGE
+ unsigned long addr;
+ pte_t *ptep;
+ pgd_t *pgd = vma->vm_mm->pgd;
+
+ for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) {
+ ptep = get_ptep(pgd, addr);
+ if (!ptep) {
+ /* ??? Why don't we have a pte? */
+ flush_cache_all();
+ return;
+ }
+ check_page_mapping(pte_page(*ptep));
+ flush_cache_page(vma, addr, pte_pfn(*ptep));
+ }
+#else
+ flush_user_dcache_range_asm(start,end);
+ flush_user_icache_range_asm(start,end);
+#endif
} else {
flush_cache_all();
}
@@ -513,3 +576,77 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
__flush_cache_page(vma, vmaddr, page_to_phys(pfn_to_page(pfn)));
}
+
+void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
+{
+ unsigned long flags;
+
+ /* Note: purge_tlb_entries can be called at startup with
+ no context. */
+
+ mtsp(mm->context,1);
+ purge_tlb_start(flags);
+ pdtlb(addr);
+ pitlb(addr);
+ purge_tlb_end(flags);
+}
+
+#ifdef CONFIG_PARISC_TMPALIAS
+
+void clear_user_highpage(struct page *page, unsigned long vaddr)
+{
+ void *vto;
+ unsigned long flags;
+
+ /* Clear using TMPALIAS region. The page doesn't need to
+ be flushed but the kernel mapping needs to be purged. */
+
+ vto = kmap_atomic(page, KM_USER0);
+
+ /* The PA-RISC 2.0 Architecture book states on page F-6:
+ "Before a write-capable translation is enabled, *all*
+ non-equivalently-aliased translations must be removed
+ from the page table and purged from the TLB. (Note
+ that the caches are not required to be flushed at this
+ time.) Before any non-equivalent aliased translation
+ is re-enabled, the virtual address range for the writeable
+ page (the entire page) must be flushed from the cache,
+ and the write-capable translation removed from the page
+ table and purged from the TLB." */
+
+ purge_kernel_dcache_page_asm((unsigned long)vto);
+ purge_tlb_start(flags);
+ pdtlb_kernel(vto);
+ purge_tlb_end(flags);
+ clear_user_page_asm(vto, vaddr);
+
+ pagefault_enable(); /* kunmap_atomic(addr, KM_USER0); */
+}
+
+void copy_user_highpage(struct page *to, struct page *from,
+ unsigned long vaddr, struct vm_area_struct *vma)
+{
+ void *vfrom, *vto;
+ unsigned long flags;
+
+ /* Copy using TMPALIAS region. This has the advantage
+ that the `from' page doesn't need to be flushed. However,
+ the `to' page must be flushed in copy_user_page_asm since
+ it can be used to bring in executable code. */
+
+ vfrom = kmap_atomic(from, KM_USER0);
+ vto = kmap_atomic(to, KM_USER1);
+
+ purge_kernel_dcache_page_asm((unsigned long)vto);
+ purge_tlb_start(flags);
+ pdtlb_kernel(vto);
+ pdtlb_kernel(vfrom);
+ purge_tlb_end(flags);
+ copy_user_page_asm(vto, vfrom, vaddr);
+ flush_dcache_page_asm(__pa(vto), vaddr);
+
+ pagefault_enable(); /* kunmap_atomic(addr, KM_USER1); */
+ pagefault_enable(); /* kunmap_atomic(addr, KM_USER0); */
+}
+
+#endif /* CONFIG_PARISC_TMPALIAS */
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index 6f05944..3caa199 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -483,7 +483,7 @@
* B <-> _PAGE_DMB (memory break)
*
* Then incredible subtlety: The access rights are
- * _PAGE_GATEWAY _PAGE_EXEC _PAGE_READ
+ * _PAGE_GATEWAY, _PAGE_EXEC and _PAGE_WRITE
* See 3-14 of the parisc 2.0 manual
*
* Finally, _PAGE_READ goes in the top bit of PL1 (so we
@@ -493,7 +493,7 @@
/* PAGE_USER indicates the page can be read with user privileges,
* so deposit X1|11 to PL1|PL2 (remember the upper bit of PL1
- * contains _PAGE_READ */
+ * contains _PAGE_READ) */
extrd,u,*= \pte,_PAGE_USER_BIT+32,1,%r0
depdi 7,11,3,\prot
/* If we're a gateway page, drop PL2 back to zero for promotion
@@ -1777,9 +1777,9 @@ ENTRY(sys_fork_wrapper)
ldo -16(%r30),%r29 /* Reference param save area */
#endif
- /* These are call-clobbered registers and therefore
- also syscall-clobbered (we hope). */
- STREG %r2,PT_GR19(%r1) /* save for child */
+ STREG %r2,PT_SYSCALL_RP(%r1) /* save for child */
+
+ /* WARNING - Clobbers r21, userspace must save! */
STREG %r30,PT_GR21(%r1)
LDREG PT_GR30(%r1),%r25
@@ -1809,7 +1809,7 @@ ENTRY(child_return)
nop
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE-FRAME_SIZE(%r30), %r1
- LDREG TASK_PT_GR19(%r1),%r2
+ LDREG TASK_PT_SYSCALL_RP(%r1),%r2
b wrapper_exit
copy %r0,%r28
ENDPROC(child_return)
@@ -1828,8 +1828,9 @@ ENTRY(sys_clone_wrapper)
ldo -16(%r30),%r29 /* Reference param save area */
#endif
- /* WARNING - Clobbers r19 and r21, userspace must save these! */
- STREG %r2,PT_GR19(%r1) /* save for child */
+ STREG %r2,PT_SYSCALL_RP(%r1) /* save for child */
+
+ /* WARNING - Clobbers r21, userspace must save! */
STREG %r30,PT_GR21(%r1)
BL sys_clone,%r2
copy %r1,%r24
@@ -1852,7 +1853,7 @@ ENTRY(sys_vfork_wrapper)
ldo -16(%r30),%r29 /* Reference param save area */
#endif
- STREG %r2,PT_GR19(%r1) /* save for child */
+ STREG %r2,PT_SYSCALL_RP(%r1) /* save for child */
STREG %r30,PT_GR21(%r1)
BL sys_vfork,%r2
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
index c0b1aff..8094d3e 100644
--- a/arch/parisc/kernel/irq.c
+++ b/arch/parisc/kernel/irq.c
@@ -379,14 +379,14 @@ void do_cpu_irq_mask(struct pt_regs *regs)
static struct irqaction timer_action = {
.handler = timer_interrupt,
.name = "timer",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU | IRQF_IRQPOLL,
+ .flags = IRQF_TIMER | IRQF_PERCPU | IRQF_IRQPOLL,
};
#ifdef CONFIG_SMP
static struct irqaction ipi_action = {
.handler = ipi_interrupt,
.name = "IPI",
- .flags = IRQF_DISABLED | IRQF_PERCPU,
+ .flags = IRQF_PERCPU,
};
#endif
@@ -410,11 +410,13 @@ void __init init_IRQ(void)
{
local_irq_disable(); /* PARANOID - should already be disabled */
mtctl(~0UL, 23); /* EIRR : clear all pending external intr */
- claim_cpu_irqs();
#ifdef CONFIG_SMP
- if (!cpu_eiem)
+ if (!cpu_eiem) {
+ claim_cpu_irqs();
cpu_eiem = EIEM_MASK(IPI_IRQ) | EIEM_MASK(TIMER_IRQ);
+ }
#else
+ claim_cpu_irqs();
cpu_eiem = EIEM_MASK(TIMER_IRQ);
#endif
set_eiem(cpu_eiem); /* EIEM : enable all external intr */
diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S
index 93ff3d9..fb38149 100644
--- a/arch/parisc/kernel/pacache.S
+++ b/arch/parisc/kernel/pacache.S
@@ -199,7 +199,6 @@ ENTRY(flush_instruction_cache_local)
.callinfo NO_CALLS
.entry
- mtsp %r0, %sr1
load32 cache_info, %r1
/* Flush Instruction Cache */
@@ -208,20 +207,46 @@ ENTRY(flush_instruction_cache_local)
LDREG ICACHE_STRIDE(%r1), %arg1
LDREG ICACHE_COUNT(%r1), %arg2
LDREG ICACHE_LOOP(%r1), %arg3
- rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/
+ rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/
addib,COND(=) -1, %arg3, fioneloop /* Preadjust and test */
movb,<,n %arg3, %r31, fisync /* If loop < 0, do sync */
fimanyloop: /* Loop if LOOP >= 2 */
addib,COND(>) -1, %r31, fimanyloop /* Adjusted inner loop decr */
- fice %r0(%sr1, %arg0)
- fice,m %arg1(%sr1, %arg0) /* Last fice and addr adjust */
+ fice %r0(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0) /* Last fice and addr adjust */
movb,tr %arg3, %r31, fimanyloop /* Re-init inner loop count */
addib,COND(<=),n -1, %arg2, fisync /* Outer loop decr */
fioneloop: /* Loop if LOOP = 1 */
- addib,COND(>) -1, %arg2, fioneloop /* Outer loop count decr */
- fice,m %arg1(%sr1, %arg0) /* Fice for one loop */
+ /* Some implementations may flush with a single fice instruction */
+ cmpib,COND(>>=),n 15, %arg2, fioneloop2
+
+fioneloop1:
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ addib,COND(>) -16, %arg2, fioneloop1
+ fice,m %arg1(%sr2, %arg0)
+
+ /* Check if done */
+ cmpb,COND(=),n %arg2, %r0, fisync /* Predict branch taken */
+
+fioneloop2:
+ addib,COND(>) -1, %arg2, fioneloop2 /* Outer loop count decr */
+ fice,m %arg1(%sr2, %arg0) /* Fice for one loop */
fisync:
sync
@@ -240,8 +265,7 @@ ENTRY(flush_data_cache_local)
.callinfo NO_CALLS
.entry
- mtsp %r0, %sr1
- load32 cache_info, %r1
+ load32 cache_info, %r1
/* Flush Data Cache */
@@ -249,20 +273,46 @@ ENTRY(flush_data_cache_local)
LDREG DCACHE_STRIDE(%r1), %arg1
LDREG DCACHE_COUNT(%r1), %arg2
LDREG DCACHE_LOOP(%r1), %arg3
- rsm PSW_SM_I, %r22
+ rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/
addib,COND(=) -1, %arg3, fdoneloop /* Preadjust and test */
movb,<,n %arg3, %r31, fdsync /* If loop < 0, do sync */
fdmanyloop: /* Loop if LOOP >= 2 */
addib,COND(>) -1, %r31, fdmanyloop /* Adjusted inner loop decr */
- fdce %r0(%sr1, %arg0)
- fdce,m %arg1(%sr1, %arg0) /* Last fdce and addr adjust */
+ fdce %r0(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0) /* Last fdce and addr adjust */
movb,tr %arg3, %r31, fdmanyloop /* Re-init inner loop count */
addib,COND(<=),n -1, %arg2, fdsync /* Outer loop decr */
fdoneloop: /* Loop if LOOP = 1 */
- addib,COND(>) -1, %arg2, fdoneloop /* Outer loop count decr */
- fdce,m %arg1(%sr1, %arg0) /* Fdce for one loop */
+ /* Some implementations may flush with a single fdce instruction */
+ cmpib,COND(>>=),n 15, %arg2, fdoneloop2
+
+fdoneloop1:
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ addib,COND(>) -16, %arg2, fdoneloop1
+ fdce,m %arg1(%sr2, %arg0)
+
+ /* Check if done */
+ cmpb,COND(=),n %arg2, %r0, fdsync /* Predict branch taken */
+
+fdoneloop2:
+ addib,COND(>) -1, %arg2, fdoneloop2 /* Outer loop count decr */
+ fdce,m %arg1(%sr2, %arg0) /* Fdce for one loop */
fdsync:
syncdma
@@ -277,7 +327,34 @@ ENDPROC(flush_data_cache_local)
.align 16
-ENTRY(copy_user_page_asm)
+/* Macros to serialize TLB purge operations on SMP. */
+
+ .macro tlb_lock la,flags,tmp
+#ifdef CONFIG_SMP
+ ldil L%pa_tlb_lock,%r1
+ ldo R%pa_tlb_lock(%r1),\la
+ rsm PSW_SM_I,\flags
+1: LDCW 0(\la),\tmp
+ cmpib,<>,n 0,\tmp,3f
+2: ldw 0(\la),\tmp
+ cmpb,<> %r0,\tmp,1b
+ nop
+ b,n 2b
+3:
+#endif
+ .endm
+
+ .macro tlb_unlock la,flags,tmp
+#ifdef CONFIG_SMP
+ ldi 1,\tmp
+ stw \tmp,0(\la)
+ mtsm \flags
+#endif
+ .endm
+
+/* Copy page using kernel mapping. */
+
+ENTRY(copy_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -291,12 +368,14 @@ ENTRY(copy_user_page_asm)
ldd 0(%r25), %r19
ldi (PAGE_SIZE / 128), %r1
- ldw 64(%r25), %r0 /* prefetch 1 cacheline ahead */
- ldw 128(%r25), %r0 /* prefetch 2 */
+ /* ??? JDA: Disabled prefetch because the last two prefetches
+ will pull lines from the next page. */
+ // ldw 64(%r25), %r0 /* prefetch 1 cacheline ahead */
+ // ldw 128(%r25), %r0 /* prefetch 2 */
1: ldd 8(%r25), %r20
- ldw 192(%r25), %r0 /* prefetch 3 */
- ldw 256(%r25), %r0 /* prefetch 4 */
+ // ldw 192(%r25), %r0 /* prefetch 3 */
+ // ldw 256(%r25), %r0 /* prefetch 4 */
ldd 16(%r25), %r21
ldd 24(%r25), %r22
@@ -399,7 +478,7 @@ ENTRY(copy_user_page_asm)
.exit
.procend
-ENDPROC(copy_user_page_asm)
+ENDPROC(copy_page_asm)
/*
* NOTE: Code in clear_user_page has a hard coded dependency on the
@@ -422,8 +501,6 @@ ENDPROC(copy_user_page_asm)
* %r23 physical page (shifted for tlb insert) of "from" translation
*/
-#if 0
-
/*
* We can't do this since copy_user_page is used to bring in
* file data that might have instructions. Since the data would
@@ -435,6 +512,7 @@ ENDPROC(copy_user_page_asm)
* use it if more information is passed into copy_user_page().
* Have to do some measurements to see if it is worthwhile to
* lobby for such a change.
+ *
*/
ENTRY(copy_user_page_asm)
@@ -442,16 +520,21 @@ ENTRY(copy_user_page_asm)
.callinfo NO_CALLS
.entry
+ /* Convert virtual `to' and `from' addresses to physical addresses.
+ Move `from' physical address to non shadowed register. */
ldil L%(__PAGE_OFFSET), %r1
sub %r26, %r1, %r26
- sub %r25, %r1, %r23 /* move physical addr into non shadowed reg */
+ sub %r25, %r1, %r23
ldil L%(TMPALIAS_MAP_START), %r28
/* FIXME for different page sizes != 4k */
#ifdef CONFIG_64BIT
- extrd,u %r26,56,32, %r26 /* convert phys addr to tlb insert format */
- extrd,u %r23,56,32, %r23 /* convert phys addr to tlb insert format */
- depd %r24,63,22, %r28 /* Form aliased virtual address 'to' */
+#if (TMPALIAS_MAP_START >= 0x80000000)
+ depdi 0, 31,32, %r28 /* clear any sign extension */
+#endif
+ extrd,u %r26,56,32, %r26 /* convert phys addr to tlb insert format */
+ extrd,u %r23,56,32, %r23 /* convert phys addr to tlb insert format */
+ depd %r24,63,22, %r28 /* Form aliased virtual address 'to' */
depdi 0, 63,12, %r28 /* Clear any offset bits */
copy %r28, %r29
depdi 1, 41,1, %r29 /* Form aliased virtual address 'from' */
@@ -466,10 +549,76 @@ ENTRY(copy_user_page_asm)
/* Purge any old translations */
+ tlb_lock %r20,%r21,%r22
pdtlb 0(%r28)
pdtlb 0(%r29)
+ tlb_unlock %r20,%r21,%r22
+
+#ifdef CONFIG_64BIT
+ /* PA8x00 CPUs can consume 2 loads or 1 store per cycle.
+ * Unroll the loop by hand and arrange insn appropriately.
+ * GCC probably can do this just as well.
+ */
+
+ ldd 0(%r29), %r19
+ ldi (PAGE_SIZE / 128), %r1
+
+ /* ldw 64(%r29), %r0 /* prefetch 1 cacheline ahead */
+ /* ldw 128(%r29), %r0 /* prefetch 2 */
+
+1: ldd 8(%r29), %r20
+ /* ldw 192(%r29), %r0 /* prefetch 3 */
+ /* ldw 256(%r29), %r0 /* prefetch 4 */
+
+ ldd 16(%r29), %r21
+ ldd 24(%r29), %r22
+ std %r19, 0(%r28)
+ std %r20, 8(%r28)
+
+ ldd 32(%r29), %r19
+ ldd 40(%r29), %r20
+ std %r21, 16(%r28)
+ std %r22, 24(%r28)
+
+ ldd 48(%r29), %r21
+ ldd 56(%r29), %r22
+ std %r19, 32(%r28)
+ std %r20, 40(%r28)
+
+ ldd 64(%r29), %r19
+ ldd 72(%r29), %r20
+ std %r21, 48(%r28)
+ std %r22, 56(%r28)
+
+ ldd 80(%r29), %r21
+ ldd 88(%r29), %r22
+ std %r19, 64(%r28)
+ std %r20, 72(%r28)
+
+ ldd 96(%r29), %r19
+ ldd 104(%r29), %r20
+ std %r21, 80(%r28)
+ std %r22, 88(%r28)
+
+ ldd 112(%r29), %r21
+ ldd 120(%r29), %r22
+ std %r19, 96(%r28)
+ std %r20, 104(%r28)
+
+ ldo 128(%r29), %r29
+ std %r21, 112(%r28)
+ std %r22, 120(%r28)
+ ldo 128(%r28), %r28
- ldi 64, %r1
+ /* conditional branches nullify on forward taken branch, and on
+ * non-taken backward branch. Note that .+4 is a backwards branch.
+ * The ldd should only get executed if the branch is taken.
+ */
+ addib,COND(>),n -1, %r1, 1b /* bundle 10 */
+ ldd 0(%r29), %r19 /* start next loads */
+
+#else
+ ldi (PAGE_SIZE / 64), %r1
/*
* This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw
@@ -480,9 +629,7 @@ ENTRY(copy_user_page_asm)
* use ldd/std on a 32 bit kernel.
*/
-
-1:
- ldw 0(%r29), %r19
+1: ldw 0(%r29), %r19
ldw 4(%r29), %r20
ldw 8(%r29), %r21
ldw 12(%r29), %r22
@@ -515,8 +662,10 @@ ENTRY(copy_user_page_asm)
stw %r21, 56(%r28)
stw %r22, 60(%r28)
ldo 64(%r28), %r28
+
addib,COND(>) -1, %r1,1b
ldo 64(%r29), %r29
+#endif
bv %r0(%r2)
nop
@@ -524,9 +673,8 @@ ENTRY(copy_user_page_asm)
.procend
ENDPROC(copy_user_page_asm)
-#endif
-ENTRY(__clear_user_page_asm)
+ENTRY(clear_user_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -550,7 +698,9 @@ ENTRY(__clear_user_page_asm)
/* Purge any old translation */
+ tlb_lock %r20,%r21,%r22
pdtlb 0(%r28)
+ tlb_unlock %r20,%r21,%r22
#ifdef CONFIG_64BIT
ldi (PAGE_SIZE / 128), %r1
@@ -580,8 +730,7 @@ ENTRY(__clear_user_page_asm)
#else /* ! CONFIG_64BIT */
ldi (PAGE_SIZE / 64), %r1
-1:
- stw %r0, 0(%r28)
+1: stw %r0, 0(%r28)
stw %r0, 4(%r28)
stw %r0, 8(%r28)
stw %r0, 12(%r28)
@@ -606,7 +755,7 @@ ENTRY(__clear_user_page_asm)
.exit
.procend
-ENDPROC(__clear_user_page_asm)
+ENDPROC(clear_user_page_asm)
ENTRY(flush_dcache_page_asm)
.proc
@@ -630,7 +779,9 @@ ENTRY(flush_dcache_page_asm)
/* Purge any old translation */
+ tlb_lock %r20,%r21,%r22
pdtlb 0(%r28)
+ tlb_unlock %r20,%r21,%r22
ldil L%dcache_stride, %r1
ldw R%dcache_stride(%r1), %r1
@@ -663,8 +814,11 @@ ENTRY(flush_dcache_page_asm)
fdc,m %r1(%r28)
sync
+ tlb_lock %r20,%r21,%r22
+ pdtlb 0(%r25)
+ tlb_unlock %r20,%r21,%r22
bv %r0(%r2)
- pdtlb (%r25)
+ nop
.exit
.procend
@@ -692,7 +846,9 @@ ENTRY(flush_icache_page_asm)
/* Purge any old translation */
+ tlb_lock %r20,%r21,%r22
pitlb (%sr0,%r28)
+ tlb_unlock %r20,%r21,%r22
ldil L%icache_stride, %r1
ldw R%icache_stride(%r1), %r1
@@ -725,8 +881,11 @@ ENTRY(flush_icache_page_asm)
fic,m %r1(%r28)
sync
- bv %r0(%r2)
+ tlb_lock %r20,%r21,%r22
pitlb (%sr0,%r25)
+ tlb_unlock %r20,%r21,%r22
+ bv %r0(%r2)
+ nop
.exit
.procend
@@ -775,7 +934,7 @@ ENTRY(flush_kernel_dcache_page_asm)
.procend
ENDPROC(flush_kernel_dcache_page_asm)
-ENTRY(purge_kernel_dcache_page)
+ENTRY(purge_kernel_dcache_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -815,7 +974,7 @@ ENTRY(purge_kernel_dcache_page)
.exit
.procend
-ENDPROC(purge_kernel_dcache_page)
+ENDPROC(purge_kernel_dcache_page_asm)
ENTRY(flush_user_dcache_range_asm)
.proc
diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c
index a7bb757..546c51d 100644
--- a/arch/parisc/kernel/parisc_ksyms.c
+++ b/arch/parisc/kernel/parisc_ksyms.c
@@ -159,4 +159,4 @@ EXPORT_SYMBOL(_mcount);
#endif
/* from pacache.S -- needed for copy_page */
-EXPORT_SYMBOL(copy_user_page_asm);
+EXPORT_SYMBOL(copy_page_asm);
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 12c1ed3..5dd1059 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -314,7 +314,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
#if DEBUG_SIG
/* Assert that we're flushing in the correct space... */
{
- int sid;
+ unsigned long sid;
asm ("mfsp %%sr3,%0" : "=r" (sid));
DBG(1,"setup_rt_frame: Flushing 64 bytes at space %#x offset %p\n",
sid, frame->tramp);
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
index c9b9322..f0cb56e 100644
--- a/arch/parisc/kernel/sys_parisc.c
+++ b/arch/parisc/kernel/sys_parisc.c
@@ -92,11 +92,12 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
{
if (len > TASK_SIZE)
return -ENOMEM;
- /* Might want to check for cache aliasing issues for MAP_FIXED case
- * like ARM or MIPS ??? --BenH.
- */
- if (flags & MAP_FIXED)
+ if (flags & MAP_FIXED) {
+ if ((flags & MAP_SHARED) &&
+ (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
+ return -EINVAL;
return addr;
+ }
if (!addr)
addr = TASK_UNMAPPED_BASE;
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c
index 45b7389..53a1c69 100644
--- a/arch/parisc/kernel/time.c
+++ b/arch/parisc/kernel/time.c
@@ -76,7 +76,7 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
cycles_elapsed = now - next_tick;
- if ((cycles_elapsed >> 6) < cpt) {
+ if ((cycles_elapsed >> 7) < cpt) {
/* use "cheap" math (add/subtract) instead
* of the more expensive div/mul method
*/
diff --git a/arch/parisc/math-emu/cnv_float.h b/arch/parisc/math-emu/cnv_float.h
index 9071e09..37299c7 100644
--- a/arch/parisc/math-emu/cnv_float.h
+++ b/arch/parisc/math-emu/cnv_float.h
@@ -347,16 +347,15 @@
Sgl_isinexact_to_fix(sgl_value,exponent)
#define Duint_from_sgl_mantissa(sgl_value,exponent,dresultA,dresultB) \
- {Sall(sgl_value) <<= SGL_EXP_LENGTH; /* left-justify */ \
+ {unsigned int val = Sall(sgl_value) << SGL_EXP_LENGTH; \
if (exponent <= 31) { \
Dintp1(dresultA) = 0; \
- Dintp2(dresultB) = (unsigned)Sall(sgl_value) >> (31 - exponent); \
+ Dintp2(dresultB) = val >> (31 - exponent); \
} \
else { \
- Dintp1(dresultA) = Sall(sgl_value) >> (63 - exponent); \
- Dintp2(dresultB) = Sall(sgl_value) << (exponent - 31); \
+ Dintp1(dresultA) = val >> (63 - exponent); \
+ Dintp2(dresultB) = exponent <= 62 ? val << (exponent - 31) : 0; \
} \
- Sall(sgl_value) >>= SGL_EXP_LENGTH; /* return to original */ \
}
#define Duint_setzero(dresultA,dresultB) \
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index f7c543a..d69738a 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -549,6 +549,7 @@ out_eoi:
void
handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
{
+ struct irqaction *action;
struct irq_chip *chip = irq_desc_get_chip(desc);
kstat_incr_irqs_this_cpu(irq, desc);
@@ -556,7 +557,9 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
if (chip->irq_ack)
chip->irq_ack(&desc->irq_data);
- handle_irq_event_percpu(desc, desc->action);
+ action = desc->action;
+ if (action)
+ handle_irq_event_percpu(desc, action);
if (chip->irq_eoi)
chip->irq_eoi(&desc->irq_data);
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: Happy New Year PARISC (take 2)
[not found] ` <CA+DQjFiTwKC76Hn-x-s2C9Nc_qkqrRFXv3ji22KGtgMzGOfx0Q@mail.gmail.com>
@ 2012-01-30 1:06 ` Thibaut VARENE
0 siblings, 0 replies; 18+ messages in thread
From: Thibaut VARENE @ 2012-01-30 1:06 UTC (permalink / raw)
To: linux-parisc List
Reposting as vger is anal about mail format...
On Sun, Jan 29, 2012 at 10:45 PM, John David Anglin
<dave.anglin@bell.net> wrote:
>
> I believe both versions fix the minifail bug and some thread related =
bugs
> seen in the perl, python and git testsuites. =C2=A0However, there are=
still more
> thread related bugs to fix.
>
> The minifail bug is fixed by the TLB purge added to ptep_set_wrprotec=
t,
> and flushing the `from' page in copy_user_page (kmap version). =C2=A0=
The
> tmpalias version doesn't need this flush, but the `to' page needs to =
be
> flushed. =C2=A0So, both versions have about the same flush requiremen=
ts.
>
> This version fixes the math emulation bug that I reported, but I have
> another one that I haven't tracked down.
That's awesome news!
If you want write access to the wiki to update e.g. this page
http://wiki.parisc-linux.org/TestCases=C2=A0I'd be more than happy to a=
dd
your account to the ACL.
> It would be great if someone else could test the change on something =
other
> than a rp3440. =C2=A0The cache issues are very subtle. =C2=A0If the r=
esults are positive,
> I will break up the patch and formally submit it.
Well I have an a500-5x (PA8600) that's doing nothing, but I really
don't have time to do any kind of testing now or in the near future.
I'd be happy to provide access to the hardware tho.
HTH
T-Bone
--
Thibaut VARENE
http://www.parisc-linux.org/~varenet/
--
To unsubscribe from this list: send the line "unsubscribe linux-parisc"=
in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Happy New Year PARISC (take 2)
2012-01-29 21:45 ` Happy New Year PARISC (take 2) John David Anglin
[not found] ` <CA+DQjFiTwKC76Hn-x-s2C9Nc_qkqrRFXv3ji22KGtgMzGOfx0Q@mail.gmail.com>
@ 2012-02-28 15:28 ` John David Anglin
2012-02-28 22:56 ` Domenico Andreoli
1 sibling, 1 reply; 18+ messages in thread
From: John David Anglin @ 2012-02-28 15:28 UTC (permalink / raw)
To: John David Anglin
Cc: James Bottomley, Carlos O'Donell, Grant Grundler,
linux-parisc List
[-- Attachment #1: Type: text/plain, Size: 859 bytes --]
On 1/29/2012 4:45 PM, John David Anglin wrote:
> Here is take take 2. It's against linux-stable v3.2.2. I also have a
> very similar
> version against v3.1.10.
>
Here is take 3. Since take 2, I have tried mainly to explore
performance issues.
The big difference is a new implementation of flush_cache_mm where I try to
avoid the brutal flush of the whole cache. This drops the full GCC
build time at
-j4 from about six hours nine minutes to three hours ten minutes on
rp3440 (i.e.,
almost by a factor two). Build and check time is still a bit slower
than HP-UX.
There's probably more to tweak here.
Other changes made little difference (e.g., clear_page_asm). I also
explored
the affect of prefetch operations in clear_page_asm and copy_page_asm, but
the difference if any was in the noise.
Dave
--
John David Anglin dave.anglin@bell.net
[-- Attachment #2: linux-stable-3.2.7-20120226-2.txt --]
[-- Type: text/plain, Size: 38832 bytes --]
diff --git a/arch/parisc/hpux/wrappers.S b/arch/parisc/hpux/wrappers.S
index 58c53c8..bdcea33 100644
--- a/arch/parisc/hpux/wrappers.S
+++ b/arch/parisc/hpux/wrappers.S
@@ -88,7 +88,7 @@ ENTRY(hpux_fork_wrapper)
STREG %r2,-20(%r30)
ldo 64(%r30),%r30
- STREG %r2,PT_GR19(%r1) ;! save for child
+ STREG %r2,PT_SYSCALL_RP(%r1) ;! save for child
STREG %r30,PT_GR21(%r1) ;! save for child
LDREG PT_GR30(%r1),%r25
@@ -132,7 +132,7 @@ ENTRY(hpux_child_return)
bl,n schedule_tail, %r2
#endif
- LDREG TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2
+ LDREG TASK_PT_SYSCALL_RP-TASK_SZ_ALGN-128(%r30),%r2
b fork_return
copy %r0,%r28
ENDPROC(hpux_child_return)
diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h
index da601dd..08f85dc 100644
--- a/arch/parisc/include/asm/cacheflush.h
+++ b/arch/parisc/include/asm/cacheflush.h
@@ -115,7 +115,9 @@ flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vma
{
if (PageAnon(page)) {
flush_tlb_page(vma, vmaddr);
+ preempt_disable();
flush_dcache_page_asm(page_to_phys(page), vmaddr);
+ preempt_enable();
}
}
diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h
index 2388bdb..7839285 100644
--- a/arch/parisc/include/asm/futex.h
+++ b/arch/parisc/include/asm/futex.h
@@ -8,6 +8,29 @@
#include <asm/atomic.h>
#include <asm/errno.h>
+/* The following has to match the LWS code in syscall.S. We have
+ sixteen four-word locks. */
+
+static inline void
+_futex_spin_lock_irqsave (u32 __user *uaddr, unsigned long int *flags)
+{
+ extern u32 lws_lock_start[];
+ long index = ((long)uaddr & 0xf0) >> 2;
+ arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
+ local_irq_save(*flags);
+ arch_spin_lock(s);
+}
+
+static inline void
+_futex_spin_unlock_irqrestore (u32 __user *uaddr, unsigned long int *flags)
+{
+ extern u32 lws_lock_start[];
+ long index = ((long)uaddr & 0xf0) >> 2;
+ arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
+ arch_spin_unlock(s);
+ local_irq_restore(*flags);
+}
+
static inline int
futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
@@ -26,7 +49,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
pagefault_disable();
- _atomic_spin_lock_irqsave(uaddr, flags);
+ _futex_spin_lock_irqsave(uaddr, &flags);
switch (op) {
case FUTEX_OP_SET:
@@ -71,7 +94,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
ret = -ENOSYS;
}
- _atomic_spin_unlock_irqrestore(uaddr, flags);
+ _futex_spin_unlock_irqrestore(uaddr, &flags);
pagefault_enable();
@@ -113,7 +136,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
* address. This should scale to a couple of CPUs.
*/
- _atomic_spin_lock_irqsave(uaddr, flags);
+ _futex_spin_lock_irqsave(uaddr, &flags);
ret = get_user(val, uaddr);
@@ -122,7 +145,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
*uval = val;
- _atomic_spin_unlock_irqrestore(uaddr, flags);
+ _futex_spin_unlock_irqrestore(uaddr, &flags);
return ret;
}
diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h
index a84cc1f..a2a375d 100644
--- a/arch/parisc/include/asm/page.h
+++ b/arch/parisc/include/asm/page.h
@@ -21,15 +21,27 @@
#include <asm/types.h>
#include <asm/cache.h>
-#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
-#define copy_page(to,from) copy_user_page_asm((void *)(to), (void *)(from))
+#define clear_page(page) clear_page_asm((void *)(page))
+#define copy_page(to,from) copy_page_asm((void *)(to), (void *)(from))
struct page;
-void copy_user_page_asm(void *to, void *from);
+void clear_page_asm(void *page);
+void copy_page_asm(void *to, void *from);
+void clear_user_page(void *vto, unsigned long vaddr, struct page *pg);
void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
struct page *pg);
-void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
+
+// #define CONFIG_PARISC_TMPALIAS
+
+#ifdef CONFIG_PARISC_TMPALIAS
+void clear_user_highpage(struct page *page, unsigned long vaddr);
+#define clear_user_highpage clear_user_highpage
+struct vm_area_struct;
+void copy_user_highpage(struct page *to, struct page *from,
+ unsigned long vaddr, struct vm_area_struct *vma);
+#define __HAVE_ARCH_COPY_USER_HIGHPAGE
+#endif
/*
* These are used to make use of C type-checking..
diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
index 22dadeb..891b369 100644
--- a/arch/parisc/include/asm/pgtable.h
+++ b/arch/parisc/include/asm/pgtable.h
@@ -40,7 +40,14 @@ struct vm_area_struct;
do{ \
*(pteptr) = (pteval); \
} while(0)
-#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+
+extern void purge_tlb_entries(struct mm_struct *, unsigned long);
+
+#define set_pte_at(mm,addr,ptep, pteval) \
+ do{ \
+ set_pte(ptep,pteval); \
+ purge_tlb_entries(mm,addr); \
+ } while(0)
#endif /* !__ASSEMBLY__ */
@@ -460,10 +467,13 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
#ifdef CONFIG_SMP
unsigned long new, old;
+ /* ??? This might be racy because the page table updates in
+ entry.S don't use the same lock. */
do {
old = pte_val(*ptep);
new = pte_val(pte_wrprotect(__pte (old)));
} while (cmpxchg((unsigned long *) ptep, old, new) != old);
+ purge_tlb_entries(mm, addr);
#else
pte_t old_pte = *ptep;
set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
diff --git a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c
index dcd5510..5df1597 100644
--- a/arch/parisc/kernel/asm-offsets.c
+++ b/arch/parisc/kernel/asm-offsets.c
@@ -141,6 +141,7 @@ int main(void)
DEFINE(TASK_PT_IAOQ0, offsetof(struct task_struct, thread.regs.iaoq[0]));
DEFINE(TASK_PT_IAOQ1, offsetof(struct task_struct, thread.regs.iaoq[1]));
DEFINE(TASK_PT_CR27, offsetof(struct task_struct, thread.regs.cr27));
+ DEFINE(TASK_PT_SYSCALL_RP, offsetof(struct task_struct, thread.regs.pad0));
DEFINE(TASK_PT_ORIG_R28, offsetof(struct task_struct, thread.regs.orig_r28));
DEFINE(TASK_PT_KSP, offsetof(struct task_struct, thread.regs.ksp));
DEFINE(TASK_PT_KPC, offsetof(struct task_struct, thread.regs.kpc));
@@ -230,6 +231,7 @@ int main(void)
DEFINE(PT_IAOQ0, offsetof(struct pt_regs, iaoq[0]));
DEFINE(PT_IAOQ1, offsetof(struct pt_regs, iaoq[1]));
DEFINE(PT_CR27, offsetof(struct pt_regs, cr27));
+ DEFINE(PT_SYSCALL_RP, offsetof(struct pt_regs, pad0));
DEFINE(PT_ORIG_R28, offsetof(struct pt_regs, orig_r28));
DEFINE(PT_KSP, offsetof(struct pt_regs, ksp));
DEFINE(PT_KPC, offsetof(struct pt_regs, kpc));
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index 83335f3..eddeddb 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -134,7 +134,7 @@ parisc_cache_init(void)
if (pdc_cache_info(&cache_info) < 0)
panic("parisc_cache_init: pdc_cache_info failed");
-#if 0
+#if 1
printk("ic_size %lx dc_size %lx it_size %lx\n",
cache_info.ic_size,
cache_info.dc_size,
@@ -268,9 +268,11 @@ static inline void
__flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr,
unsigned long physaddr)
{
+ preempt_disable();
flush_dcache_page_asm(physaddr, vmaddr);
if (vma->vm_flags & VM_EXEC)
flush_icache_page_asm(physaddr, vmaddr);
+ preempt_enable();
}
void flush_dcache_page(struct page *page)
@@ -316,7 +318,7 @@ void flush_dcache_page(struct page *page)
flush_tlb_page(mpnt, addr);
if (old_addr == 0 || (old_addr & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) {
__flush_cache_page(mpnt, addr, page_to_phys(page));
- if (old_addr)
+ if (old_addr && parisc_requires_coherency())
printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? (char *)mpnt->vm_file->f_path.dentry->d_name.name : "(null)");
old_addr = addr;
}
@@ -331,17 +333,6 @@ EXPORT_SYMBOL(flush_kernel_dcache_page_asm);
EXPORT_SYMBOL(flush_data_cache_local);
EXPORT_SYMBOL(flush_kernel_icache_range_asm);
-void clear_user_page_asm(void *page, unsigned long vaddr)
-{
- unsigned long flags;
- /* This function is implemented in assembly in pacache.S */
- extern void __clear_user_page_asm(void *page, unsigned long vaddr);
-
- purge_tlb_start(flags);
- __clear_user_page_asm(page, vaddr);
- purge_tlb_end(flags);
-}
-
#define FLUSH_THRESHOLD 0x80000 /* 0.5MB */
int parisc_cache_flush_threshold __read_mostly = FLUSH_THRESHOLD;
@@ -375,20 +366,9 @@ void __init parisc_setup_cache_timing(void)
printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus());
}
-extern void purge_kernel_dcache_page(unsigned long);
-extern void clear_user_page_asm(void *page, unsigned long vaddr);
-
-void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
-{
- unsigned long flags;
-
- purge_kernel_dcache_page((unsigned long)page);
- purge_tlb_start(flags);
- pdtlb_kernel(page);
- purge_tlb_end(flags);
- clear_user_page_asm(page, vaddr);
-}
-EXPORT_SYMBOL(clear_user_page);
+extern void purge_kernel_dcache_page_asm(unsigned long);
+extern void clear_user_page_asm(void *, unsigned long);
+extern void copy_user_page_asm(void *, void *, unsigned long);
void flush_kernel_dcache_page_addr(void *addr)
{
@@ -401,11 +381,26 @@ void flush_kernel_dcache_page_addr(void *addr)
}
EXPORT_SYMBOL(flush_kernel_dcache_page_addr);
+void clear_user_page(void *vto, unsigned long vaddr, struct page *page)
+{
+ clear_page_asm(vto);
+ if (!parisc_requires_coherency())
+ flush_kernel_dcache_page_asm(vto);
+}
+EXPORT_SYMBOL(clear_user_page);
+
void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
- struct page *pg)
+ struct page *pg)
{
- /* no coherency needed (all in kmap/kunmap) */
- copy_user_page_asm(vto, vfrom);
+ /* Copy using kernel mapping. No coherency is needed
+ (all in kmap/kunmap) on machines that don't support
+ non-equivalent aliasing. However, the `from' page
+ needs to be flushed before it can be accessed through
+ the kernel mapping. */
+ preempt_disable();
+ flush_dcache_page_asm(__pa(vfrom), vaddr);
+ preempt_enable();
+ copy_page_asm(vto, vfrom);
if (!parisc_requires_coherency())
flush_kernel_dcache_page_asm(vto);
}
@@ -460,8 +455,64 @@ void flush_cache_all(void)
on_each_cpu(cacheflush_h_tmp_function, NULL, 1);
}
+static inline unsigned long mm_total_size(struct mm_struct *mm)
+{
+ struct vm_area_struct *vma;
+ unsigned long usize = 0;
+
+ for (vma = mm->mmap; vma; vma = vma->vm_next)
+ usize += vma->vm_end - vma->vm_start;
+ return usize;
+}
+
+static inline pte_t *get_ptep(pgd_t *pgd, unsigned long addr)
+{
+ pte_t *ptep = NULL;
+
+ if (!pgd_none(*pgd)) {
+ pud_t *pud = pud_offset(pgd, addr);
+ if (!pud_none(*pud)) {
+ pmd_t *pmd = pmd_offset(pud, addr);
+ if (!pmd_none(*pmd)) {
+ ptep = pte_offset_map(pmd, addr);
+ }
+ }
+ }
+ return ptep;
+}
+
void flush_cache_mm(struct mm_struct *mm)
{
+ /* Flushing the whole cache on each cpu takes forever on
+ rp3440, etc. So, avoid it if mm isn't too big. */
+ if (mm_total_size(mm) < parisc_cache_flush_threshold) {
+ struct vm_area_struct *vma;
+
+ if (mm->context == mfsp(3)) {
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ flush_user_dcache_range_asm(vma->vm_start, vma->vm_end);
+ if(vma->vm_flags & VM_EXEC)
+ flush_user_icache_range_asm(vma->vm_start, vma->vm_end);
+ }
+ } else {
+ pgd_t *pgd = mm->pgd;
+
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ unsigned long addr;
+
+ for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE) {
+ pte_t *ptep = get_ptep(pgd, addr);
+ if (ptep != NULL) {
+ pte_t pte = *ptep;
+ if (pte_present(pte))
+ __flush_cache_page(vma, addr, page_to_phys(pte_page(pte)));
+ }
+ }
+ }
+ }
+ return;
+ }
+
#ifdef CONFIG_SMP
flush_cache_all();
#else
@@ -487,20 +538,71 @@ flush_user_icache_range(unsigned long start, unsigned long end)
flush_instruction_cache();
}
+/* While useful for testing, this check has too much overhead for
+ general use. */
+#define DEBUG_PAGE_MAPPING 0
+
+static inline void check_page_mapping(struct page *page)
+{
+#if DEBUG_PAGE_MAPPING
+ struct address_space *mapping = page_mapping(page);
+ struct vm_area_struct *mpnt;
+ struct prio_tree_iter iter;
+ unsigned long offset;
+ unsigned long addr, old_addr = 0;
+ pgoff_t pgoff;
+
+ if (!mapping || !mapping_mapped(mapping))
+ return;
+
+ pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
+
+ /* Check that all mappings are congruently mapped */
+
+ flush_dcache_mmap_lock(mapping);
+ vma_prio_tree_foreach(mpnt, &iter, &mapping->i_mmap, pgoff, pgoff) {
+ offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
+ addr = mpnt->vm_start + offset;
+ if (old_addr == 0 || (old_addr & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) {
+ if (old_addr) {
+ printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? (char *)mpnt->vm_file->f_path.dentry->d_name.name : "(null)");
+ }
+ old_addr = addr;
+ }
+ }
+ flush_dcache_mmap_unlock(mapping);
+#endif
+}
void flush_cache_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
- int sr3;
-
BUG_ON(!vma->vm_mm->context);
- sr3 = mfsp(3);
- if (vma->vm_mm->context == sr3) {
- flush_user_dcache_range(start,end);
- flush_user_icache_range(start,end);
+ if ((end - start) < parisc_cache_flush_threshold) {
+ if (vma->vm_mm->context == mfsp(3)) {
+ flush_user_dcache_range_asm(start,end);
+ if(vma->vm_flags & VM_EXEC)
+ flush_user_icache_range_asm(start,end);
+ } else {
+ unsigned long addr;
+ pgd_t *pgd = vma->vm_mm->pgd;
+
+ for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) {
+ pte_t *ptep = get_ptep(pgd, addr);
+ if (ptep) {
+ pte_t pte = *ptep;
+ check_page_mapping(pte_page(pte));
+ flush_cache_page(vma, addr, pte_pfn(pte));
+ }
+ }
+ }
} else {
+#ifdef CONFIG_SMP
flush_cache_all();
+#else
+ flush_cache_all_local();
+#endif
}
}
@@ -513,3 +615,81 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
__flush_cache_page(vma, vmaddr, page_to_phys(pfn_to_page(pfn)));
}
+
+void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
+{
+ unsigned long flags;
+
+ /* Note: purge_tlb_entries can be called at startup with
+ no context. */
+
+ mtsp(mm->context,1);
+ purge_tlb_start(flags);
+ pdtlb(addr);
+ pitlb(addr);
+ purge_tlb_end(flags);
+}
+
+#ifdef CONFIG_PARISC_TMPALIAS
+
+void clear_user_highpage(struct page *page, unsigned long vaddr)
+{
+ void *vto;
+ unsigned long flags;
+
+ /* Clear using TMPALIAS region. The page doesn't need to
+ be flushed but the kernel mapping needs to be purged. */
+
+ vto = kmap_atomic(page, KM_USER0);
+
+ /* The PA-RISC 2.0 Architecture book states on page F-6:
+ "Before a write-capable translation is enabled, *all*
+ non-equivalently-aliased translations must be removed
+ from the page table and purged from the TLB. (Note
+ that the caches are not required to be flushed at this
+ time.) Before any non-equivalent aliased translation
+ is re-enabled, the virtual address range for the writeable
+ page (the entire page) must be flushed from the cache,
+ and the write-capable translation removed from the page
+ table and purged from the TLB." */
+
+ purge_kernel_dcache_page_asm((unsigned long)vto);
+ purge_tlb_start(flags);
+ pdtlb_kernel(vto);
+ purge_tlb_end(flags);
+ preempt_disable();
+ clear_user_page_asm(vto, vaddr);
+ preempt_enable();
+
+ pagefault_enable(); /* kunmap_atomic(addr, KM_USER0); */
+}
+
+void copy_user_highpage(struct page *to, struct page *from,
+ unsigned long vaddr, struct vm_area_struct *vma)
+{
+ void *vfrom, *vto;
+ unsigned long flags;
+
+ /* Copy using TMPALIAS region. This has the advantage
+ that the `from' page doesn't need to be flushed. However,
+ the `to' page must be flushed in copy_user_page_asm since
+ it can be used to bring in executable code. */
+
+ vfrom = kmap_atomic(from, KM_USER0);
+ vto = kmap_atomic(to, KM_USER1);
+
+ purge_kernel_dcache_page_asm((unsigned long)vto);
+ purge_tlb_start(flags);
+ pdtlb_kernel(vto);
+ pdtlb_kernel(vfrom);
+ purge_tlb_end(flags);
+ preempt_disable();
+ copy_user_page_asm(vto, vfrom, vaddr);
+ flush_dcache_page_asm(__pa(vto), vaddr);
+ preempt_enable();
+
+ pagefault_enable(); /* kunmap_atomic(addr, KM_USER1); */
+ pagefault_enable(); /* kunmap_atomic(addr, KM_USER0); */
+}
+
+#endif /* CONFIG_PARISC_TMPALIAS */
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index 6f05944..3caa199 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -483,7 +483,7 @@
* B <-> _PAGE_DMB (memory break)
*
* Then incredible subtlety: The access rights are
- * _PAGE_GATEWAY _PAGE_EXEC _PAGE_READ
+ * _PAGE_GATEWAY, _PAGE_EXEC and _PAGE_WRITE
* See 3-14 of the parisc 2.0 manual
*
* Finally, _PAGE_READ goes in the top bit of PL1 (so we
@@ -493,7 +493,7 @@
/* PAGE_USER indicates the page can be read with user privileges,
* so deposit X1|11 to PL1|PL2 (remember the upper bit of PL1
- * contains _PAGE_READ */
+ * contains _PAGE_READ) */
extrd,u,*= \pte,_PAGE_USER_BIT+32,1,%r0
depdi 7,11,3,\prot
/* If we're a gateway page, drop PL2 back to zero for promotion
@@ -1777,9 +1777,9 @@ ENTRY(sys_fork_wrapper)
ldo -16(%r30),%r29 /* Reference param save area */
#endif
- /* These are call-clobbered registers and therefore
- also syscall-clobbered (we hope). */
- STREG %r2,PT_GR19(%r1) /* save for child */
+ STREG %r2,PT_SYSCALL_RP(%r1) /* save for child */
+
+ /* WARNING - Clobbers r21, userspace must save! */
STREG %r30,PT_GR21(%r1)
LDREG PT_GR30(%r1),%r25
@@ -1809,7 +1809,7 @@ ENTRY(child_return)
nop
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE-FRAME_SIZE(%r30), %r1
- LDREG TASK_PT_GR19(%r1),%r2
+ LDREG TASK_PT_SYSCALL_RP(%r1),%r2
b wrapper_exit
copy %r0,%r28
ENDPROC(child_return)
@@ -1828,8 +1828,9 @@ ENTRY(sys_clone_wrapper)
ldo -16(%r30),%r29 /* Reference param save area */
#endif
- /* WARNING - Clobbers r19 and r21, userspace must save these! */
- STREG %r2,PT_GR19(%r1) /* save for child */
+ STREG %r2,PT_SYSCALL_RP(%r1) /* save for child */
+
+ /* WARNING - Clobbers r21, userspace must save! */
STREG %r30,PT_GR21(%r1)
BL sys_clone,%r2
copy %r1,%r24
@@ -1852,7 +1853,7 @@ ENTRY(sys_vfork_wrapper)
ldo -16(%r30),%r29 /* Reference param save area */
#endif
- STREG %r2,PT_GR19(%r1) /* save for child */
+ STREG %r2,PT_SYSCALL_RP(%r1) /* save for child */
STREG %r30,PT_GR21(%r1)
BL sys_vfork,%r2
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
index c0b1aff..8094d3e 100644
--- a/arch/parisc/kernel/irq.c
+++ b/arch/parisc/kernel/irq.c
@@ -379,14 +379,14 @@ void do_cpu_irq_mask(struct pt_regs *regs)
static struct irqaction timer_action = {
.handler = timer_interrupt,
.name = "timer",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU | IRQF_IRQPOLL,
+ .flags = IRQF_TIMER | IRQF_PERCPU | IRQF_IRQPOLL,
};
#ifdef CONFIG_SMP
static struct irqaction ipi_action = {
.handler = ipi_interrupt,
.name = "IPI",
- .flags = IRQF_DISABLED | IRQF_PERCPU,
+ .flags = IRQF_PERCPU,
};
#endif
@@ -410,11 +410,13 @@ void __init init_IRQ(void)
{
local_irq_disable(); /* PARANOID - should already be disabled */
mtctl(~0UL, 23); /* EIRR : clear all pending external intr */
- claim_cpu_irqs();
#ifdef CONFIG_SMP
- if (!cpu_eiem)
+ if (!cpu_eiem) {
+ claim_cpu_irqs();
cpu_eiem = EIEM_MASK(IPI_IRQ) | EIEM_MASK(TIMER_IRQ);
+ }
#else
+ claim_cpu_irqs();
cpu_eiem = EIEM_MASK(TIMER_IRQ);
#endif
set_eiem(cpu_eiem); /* EIEM : enable all external intr */
diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S
index 93ff3d9..9a29e34 100644
--- a/arch/parisc/kernel/pacache.S
+++ b/arch/parisc/kernel/pacache.S
@@ -199,7 +199,6 @@ ENTRY(flush_instruction_cache_local)
.callinfo NO_CALLS
.entry
- mtsp %r0, %sr1
load32 cache_info, %r1
/* Flush Instruction Cache */
@@ -208,20 +207,46 @@ ENTRY(flush_instruction_cache_local)
LDREG ICACHE_STRIDE(%r1), %arg1
LDREG ICACHE_COUNT(%r1), %arg2
LDREG ICACHE_LOOP(%r1), %arg3
- rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/
+ rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/
addib,COND(=) -1, %arg3, fioneloop /* Preadjust and test */
movb,<,n %arg3, %r31, fisync /* If loop < 0, do sync */
fimanyloop: /* Loop if LOOP >= 2 */
addib,COND(>) -1, %r31, fimanyloop /* Adjusted inner loop decr */
- fice %r0(%sr1, %arg0)
- fice,m %arg1(%sr1, %arg0) /* Last fice and addr adjust */
+ fice %r0(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0) /* Last fice and addr adjust */
movb,tr %arg3, %r31, fimanyloop /* Re-init inner loop count */
addib,COND(<=),n -1, %arg2, fisync /* Outer loop decr */
fioneloop: /* Loop if LOOP = 1 */
- addib,COND(>) -1, %arg2, fioneloop /* Outer loop count decr */
- fice,m %arg1(%sr1, %arg0) /* Fice for one loop */
+ /* Some implementations may flush with a single fice instruction */
+ cmpib,COND(>>=),n 15, %arg2, fioneloop2
+
+fioneloop1:
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ fice,m %arg1(%sr2, %arg0)
+ addib,COND(>) -16, %arg2, fioneloop1
+ fice,m %arg1(%sr2, %arg0)
+
+ /* Check if done */
+ cmpb,COND(=),n %arg2, %r0, fisync /* Predict branch taken */
+
+fioneloop2:
+ addib,COND(>) -1, %arg2, fioneloop2 /* Outer loop count decr */
+ fice,m %arg1(%sr2, %arg0) /* Fice for one loop */
fisync:
sync
@@ -240,8 +265,7 @@ ENTRY(flush_data_cache_local)
.callinfo NO_CALLS
.entry
- mtsp %r0, %sr1
- load32 cache_info, %r1
+ load32 cache_info, %r1
/* Flush Data Cache */
@@ -249,20 +273,46 @@ ENTRY(flush_data_cache_local)
LDREG DCACHE_STRIDE(%r1), %arg1
LDREG DCACHE_COUNT(%r1), %arg2
LDREG DCACHE_LOOP(%r1), %arg3
- rsm PSW_SM_I, %r22
+ rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/
addib,COND(=) -1, %arg3, fdoneloop /* Preadjust and test */
movb,<,n %arg3, %r31, fdsync /* If loop < 0, do sync */
fdmanyloop: /* Loop if LOOP >= 2 */
addib,COND(>) -1, %r31, fdmanyloop /* Adjusted inner loop decr */
- fdce %r0(%sr1, %arg0)
- fdce,m %arg1(%sr1, %arg0) /* Last fdce and addr adjust */
+ fdce %r0(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0) /* Last fdce and addr adjust */
movb,tr %arg3, %r31, fdmanyloop /* Re-init inner loop count */
addib,COND(<=),n -1, %arg2, fdsync /* Outer loop decr */
fdoneloop: /* Loop if LOOP = 1 */
- addib,COND(>) -1, %arg2, fdoneloop /* Outer loop count decr */
- fdce,m %arg1(%sr1, %arg0) /* Fdce for one loop */
+ /* Some implementations may flush with a single fdce instruction */
+ cmpib,COND(>>=),n 15, %arg2, fdoneloop2
+
+fdoneloop1:
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ fdce,m %arg1(%sr2, %arg0)
+ addib,COND(>) -16, %arg2, fdoneloop1
+ fdce,m %arg1(%sr2, %arg0)
+
+ /* Check if done */
+ cmpb,COND(=),n %arg2, %r0, fdsync /* Predict branch taken */
+
+fdoneloop2:
+ addib,COND(>) -1, %arg2, fdoneloop2 /* Outer loop count decr */
+ fdce,m %arg1(%sr2, %arg0) /* Fdce for one loop */
fdsync:
syncdma
@@ -277,7 +327,104 @@ ENDPROC(flush_data_cache_local)
.align 16
-ENTRY(copy_user_page_asm)
+/* Macros to serialize TLB purge operations on SMP. */
+
+ .macro tlb_lock la,flags,tmp
+#ifdef CONFIG_SMP
+ ldil L%pa_tlb_lock,%r1
+ ldo R%pa_tlb_lock(%r1),\la
+ rsm PSW_SM_I,\flags
+1: LDCW 0(\la),\tmp
+ cmpib,<>,n 0,\tmp,3f
+2: ldw 0(\la),\tmp
+ cmpb,<> %r0,\tmp,1b
+ nop
+ b,n 2b
+3:
+#endif
+ .endm
+
+ .macro tlb_unlock la,flags,tmp
+#ifdef CONFIG_SMP
+ ldi 1,\tmp
+ stw \tmp,0(\la)
+ mtsm \flags
+#endif
+ .endm
+
+/* Clear page using kernel mapping. */
+
+ENTRY(clear_page_asm)
+ .proc
+ .callinfo NO_CALLS
+ .entry
+
+#ifdef CONFIG_64BIT
+
+ /* Unroll the loop. */
+ ldi (PAGE_SIZE / 128), %r1
+
+1:
+ std %r0, 0(%r26)
+ std %r0, 8(%r26)
+ std %r0, 16(%r26)
+ std %r0, 24(%r26)
+ std %r0, 32(%r26)
+ std %r0, 40(%r26)
+ std %r0, 48(%r26)
+ std %r0, 56(%r26)
+ std %r0, 64(%r26)
+ std %r0, 72(%r26)
+ std %r0, 80(%r26)
+ std %r0, 88(%r26)
+ std %r0, 96(%r26)
+ std %r0, 104(%r26)
+ std %r0, 112(%r26)
+ std %r0, 120(%r26)
+
+ /* Note reverse branch hint for addib is taken. */
+ addib,COND(>),n -1, %r1, 1b
+ ldo 128(%r26), %r26
+
+#else
+
+ /*
+ * Note that until (if) we start saving the full 64-bit register
+ * values on interrupt, we can't use std on a 32 bit kernel.
+ */
+ ldi (PAGE_SIZE / 64), %r1
+
+1:
+ stw %r0, 0(%r26)
+ stw %r0, 4(%r26)
+ stw %r0, 8(%r26)
+ stw %r0, 12(%r26)
+ stw %r0, 16(%r26)
+ stw %r0, 20(%r26)
+ stw %r0, 24(%r26)
+ stw %r0, 28(%r26)
+ stw %r0, 32(%r26)
+ stw %r0, 36(%r26)
+ stw %r0, 40(%r26)
+ stw %r0, 44(%r26)
+ stw %r0, 48(%r26)
+ stw %r0, 52(%r26)
+ stw %r0, 56(%r26)
+ stw %r0, 60(%r26)
+
+ addib,COND(>),n -1, %r1, 1b
+ ldo 64(%r26), %r26
+#endif
+ bv %r0(%r2)
+ nop
+ .exit
+
+ .procend
+ENDPROC(clear_page_asm)
+
+/* Copy page using kernel mapping. */
+
+ENTRY(copy_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -285,18 +432,14 @@ ENTRY(copy_user_page_asm)
#ifdef CONFIG_64BIT
/* PA8x00 CPUs can consume 2 loads or 1 store per cycle.
* Unroll the loop by hand and arrange insn appropriately.
- * GCC probably can do this just as well.
+ * Prefetch doesn't improve performance on rp3440.
+ * GCC probably can do this just as well...
*/
- ldd 0(%r25), %r19
ldi (PAGE_SIZE / 128), %r1
- ldw 64(%r25), %r0 /* prefetch 1 cacheline ahead */
- ldw 128(%r25), %r0 /* prefetch 2 */
-
-1: ldd 8(%r25), %r20
- ldw 192(%r25), %r0 /* prefetch 3 */
- ldw 256(%r25), %r0 /* prefetch 4 */
+1: ldd 0(%r25), %r19
+ ldd 8(%r25), %r20
ldd 16(%r25), %r21
ldd 24(%r25), %r22
@@ -330,20 +473,16 @@ ENTRY(copy_user_page_asm)
ldd 112(%r25), %r21
ldd 120(%r25), %r22
+ ldo 128(%r25), %r25
std %r19, 96(%r26)
std %r20, 104(%r26)
- ldo 128(%r25), %r25
std %r21, 112(%r26)
std %r22, 120(%r26)
- ldo 128(%r26), %r26
- /* conditional branches nullify on forward taken branch, and on
- * non-taken backward branch. Note that .+4 is a backwards branch.
- * The ldd should only get executed if the branch is taken.
- */
- addib,COND(>),n -1, %r1, 1b /* bundle 10 */
- ldd 0(%r25), %r19 /* start next loads */
+ /* Note reverse branch hint for addib is taken. */
+ addib,COND(>),n -1, %r1, 1b
+ ldo 128(%r26), %r26
#else
@@ -399,7 +538,7 @@ ENTRY(copy_user_page_asm)
.exit
.procend
-ENDPROC(copy_user_page_asm)
+ENDPROC(copy_page_asm)
/*
* NOTE: Code in clear_user_page has a hard coded dependency on the
@@ -422,8 +561,6 @@ ENDPROC(copy_user_page_asm)
* %r23 physical page (shifted for tlb insert) of "from" translation
*/
-#if 0
-
/*
* We can't do this since copy_user_page is used to bring in
* file data that might have instructions. Since the data would
@@ -435,6 +572,7 @@ ENDPROC(copy_user_page_asm)
* use it if more information is passed into copy_user_page().
* Have to do some measurements to see if it is worthwhile to
* lobby for such a change.
+ *
*/
ENTRY(copy_user_page_asm)
@@ -442,16 +580,21 @@ ENTRY(copy_user_page_asm)
.callinfo NO_CALLS
.entry
+ /* Convert virtual `to' and `from' addresses to physical addresses.
+ Move `from' physical address to non shadowed register. */
ldil L%(__PAGE_OFFSET), %r1
sub %r26, %r1, %r26
- sub %r25, %r1, %r23 /* move physical addr into non shadowed reg */
+ sub %r25, %r1, %r23
ldil L%(TMPALIAS_MAP_START), %r28
/* FIXME for different page sizes != 4k */
#ifdef CONFIG_64BIT
- extrd,u %r26,56,32, %r26 /* convert phys addr to tlb insert format */
- extrd,u %r23,56,32, %r23 /* convert phys addr to tlb insert format */
- depd %r24,63,22, %r28 /* Form aliased virtual address 'to' */
+#if (TMPALIAS_MAP_START >= 0x80000000)
+ depdi 0, 31,32, %r28 /* clear any sign extension */
+#endif
+ extrd,u %r26,56,32, %r26 /* convert phys addr to tlb insert format */
+ extrd,u %r23,56,32, %r23 /* convert phys addr to tlb insert format */
+ depd %r24,63,22, %r28 /* Form aliased virtual address 'to' */
depdi 0, 63,12, %r28 /* Clear any offset bits */
copy %r28, %r29
depdi 1, 41,1, %r29 /* Form aliased virtual address 'from' */
@@ -466,10 +609,76 @@ ENTRY(copy_user_page_asm)
/* Purge any old translations */
+#ifdef CONFIG_PA20
+ pdtlb,l 0(%r28)
+ pdtlb,l 0(%r29)
+#else
+ tlb_lock %r20,%r21,%r22
pdtlb 0(%r28)
pdtlb 0(%r29)
+ tlb_unlock %r20,%r21,%r22
+#endif
- ldi 64, %r1
+#ifdef CONFIG_64BIT
+ /* PA8x00 CPUs can consume 2 loads or 1 store per cycle.
+ * Unroll the loop by hand and arrange insn appropriately.
+ * GCC probably can do this just as well.
+ */
+
+ ldd 0(%r29), %r19
+ ldi (PAGE_SIZE / 128), %r1
+
+1: ldd 8(%r29), %r20
+
+ ldd 16(%r29), %r21
+ ldd 24(%r29), %r22
+ std %r19, 0(%r28)
+ std %r20, 8(%r28)
+
+ ldd 32(%r29), %r19
+ ldd 40(%r29), %r20
+ std %r21, 16(%r28)
+ std %r22, 24(%r28)
+
+ ldd 48(%r29), %r21
+ ldd 56(%r29), %r22
+ std %r19, 32(%r28)
+ std %r20, 40(%r28)
+
+ ldd 64(%r29), %r19
+ ldd 72(%r29), %r20
+ std %r21, 48(%r28)
+ std %r22, 56(%r28)
+
+ ldd 80(%r29), %r21
+ ldd 88(%r29), %r22
+ std %r19, 64(%r28)
+ std %r20, 72(%r28)
+
+ ldd 96(%r29), %r19
+ ldd 104(%r29), %r20
+ std %r21, 80(%r28)
+ std %r22, 88(%r28)
+
+ ldd 112(%r29), %r21
+ ldd 120(%r29), %r22
+ std %r19, 96(%r28)
+ std %r20, 104(%r28)
+
+ ldo 128(%r29), %r29
+ std %r21, 112(%r28)
+ std %r22, 120(%r28)
+ ldo 128(%r28), %r28
+
+ /* conditional branches nullify on forward taken branch, and on
+ * non-taken backward branch. Note that .+4 is a backwards branch.
+ * The ldd should only get executed if the branch is taken.
+ */
+ addib,COND(>),n -1, %r1, 1b /* bundle 10 */
+ ldd 0(%r29), %r19 /* start next loads */
+
+#else
+ ldi (PAGE_SIZE / 64), %r1
/*
* This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw
@@ -480,9 +689,7 @@ ENTRY(copy_user_page_asm)
* use ldd/std on a 32 bit kernel.
*/
-
-1:
- ldw 0(%r29), %r19
+1: ldw 0(%r29), %r19
ldw 4(%r29), %r20
ldw 8(%r29), %r21
ldw 12(%r29), %r22
@@ -515,8 +722,10 @@ ENTRY(copy_user_page_asm)
stw %r21, 56(%r28)
stw %r22, 60(%r28)
ldo 64(%r28), %r28
+
addib,COND(>) -1, %r1,1b
ldo 64(%r29), %r29
+#endif
bv %r0(%r2)
nop
@@ -524,9 +733,8 @@ ENTRY(copy_user_page_asm)
.procend
ENDPROC(copy_user_page_asm)
-#endif
-ENTRY(__clear_user_page_asm)
+ENTRY(clear_user_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -550,7 +758,13 @@ ENTRY(__clear_user_page_asm)
/* Purge any old translation */
+#ifdef CONFIG_PA20
+ pdtlb,l 0(%r28)
+#else
+ tlb_lock %r20,%r21,%r22
pdtlb 0(%r28)
+ tlb_unlock %r20,%r21,%r22
+#endif
#ifdef CONFIG_64BIT
ldi (PAGE_SIZE / 128), %r1
@@ -580,8 +794,7 @@ ENTRY(__clear_user_page_asm)
#else /* ! CONFIG_64BIT */
ldi (PAGE_SIZE / 64), %r1
-1:
- stw %r0, 0(%r28)
+1: stw %r0, 0(%r28)
stw %r0, 4(%r28)
stw %r0, 8(%r28)
stw %r0, 12(%r28)
@@ -606,7 +819,7 @@ ENTRY(__clear_user_page_asm)
.exit
.procend
-ENDPROC(__clear_user_page_asm)
+ENDPROC(clear_user_page_asm)
ENTRY(flush_dcache_page_asm)
.proc
@@ -630,7 +843,13 @@ ENTRY(flush_dcache_page_asm)
/* Purge any old translation */
+#ifdef CONFIG_PA20
+ pdtlb,l 0(%r28)
+#else
+ tlb_lock %r20,%r21,%r22
pdtlb 0(%r28)
+ tlb_unlock %r20,%r21,%r22
+#endif
ldil L%dcache_stride, %r1
ldw R%dcache_stride(%r1), %r1
@@ -663,8 +882,17 @@ ENTRY(flush_dcache_page_asm)
fdc,m %r1(%r28)
sync
+
+#ifdef CONFIG_PA20
+ pdtlb,l 0(%r25)
+#else
+ tlb_lock %r20,%r21,%r22
+ pdtlb 0(%r25)
+ tlb_unlock %r20,%r21,%r22
+#endif
+
bv %r0(%r2)
- pdtlb (%r25)
+ nop
.exit
.procend
@@ -692,7 +920,13 @@ ENTRY(flush_icache_page_asm)
/* Purge any old translation */
+#ifdef CONFIG_PA20
+ pitlb,l %r0(%sr0,%r28)
+#else
+ tlb_lock %r20,%r21,%r22
pitlb (%sr0,%r28)
+ tlb_unlock %r20,%r21,%r22
+#endif
ldil L%icache_stride, %r1
ldw R%icache_stride(%r1), %r1
@@ -725,8 +959,17 @@ ENTRY(flush_icache_page_asm)
fic,m %r1(%r28)
sync
- bv %r0(%r2)
+
+#ifdef CONFIG_PA20
+ pitlb,l %r0(%sr0,%r25)
+#else
+ tlb_lock %r20,%r21,%r22
pitlb (%sr0,%r25)
+ tlb_unlock %r20,%r21,%r22
+#endif
+
+ bv %r0(%r2)
+ nop
.exit
.procend
@@ -775,7 +1018,7 @@ ENTRY(flush_kernel_dcache_page_asm)
.procend
ENDPROC(flush_kernel_dcache_page_asm)
-ENTRY(purge_kernel_dcache_page)
+ENTRY(purge_kernel_dcache_page_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -815,7 +1058,7 @@ ENTRY(purge_kernel_dcache_page)
.exit
.procend
-ENDPROC(purge_kernel_dcache_page)
+ENDPROC(purge_kernel_dcache_page_asm)
ENTRY(flush_user_dcache_range_asm)
.proc
diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c
index a7bb757..25835d8 100644
--- a/arch/parisc/kernel/parisc_ksyms.c
+++ b/arch/parisc/kernel/parisc_ksyms.c
@@ -158,5 +158,6 @@ extern void _mcount(void);
EXPORT_SYMBOL(_mcount);
#endif
-/* from pacache.S -- needed for copy_page */
-EXPORT_SYMBOL(copy_user_page_asm);
+/* from pacache.S -- needed for clear/copy_page */
+EXPORT_SYMBOL(clear_page_asm);
+EXPORT_SYMBOL(copy_page_asm);
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 12c1ed3..5dd1059 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -314,7 +314,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
#if DEBUG_SIG
/* Assert that we're flushing in the correct space... */
{
- int sid;
+ unsigned long sid;
asm ("mfsp %%sr3,%0" : "=r" (sid));
DBG(1,"setup_rt_frame: Flushing 64 bytes at space %#x offset %p\n",
sid, frame->tramp);
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
index c9b9322..f0cb56e 100644
--- a/arch/parisc/kernel/sys_parisc.c
+++ b/arch/parisc/kernel/sys_parisc.c
@@ -92,11 +92,12 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
{
if (len > TASK_SIZE)
return -ENOMEM;
- /* Might want to check for cache aliasing issues for MAP_FIXED case
- * like ARM or MIPS ??? --BenH.
- */
- if (flags & MAP_FIXED)
+ if (flags & MAP_FIXED) {
+ if ((flags & MAP_SHARED) &&
+ (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
+ return -EINVAL;
return addr;
+ }
if (!addr)
addr = TASK_UNMAPPED_BASE;
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c
index 45b7389..53a1c69 100644
--- a/arch/parisc/kernel/time.c
+++ b/arch/parisc/kernel/time.c
@@ -76,7 +76,7 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
cycles_elapsed = now - next_tick;
- if ((cycles_elapsed >> 6) < cpt) {
+ if ((cycles_elapsed >> 7) < cpt) {
/* use "cheap" math (add/subtract) instead
* of the more expensive div/mul method
*/
diff --git a/arch/parisc/lib/iomap.c b/arch/parisc/lib/iomap.c
index 8f470c9..4b22b27 100644
--- a/arch/parisc/lib/iomap.c
+++ b/arch/parisc/lib/iomap.c
@@ -458,12 +458,15 @@ void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
return NULL;
}
+#ifdef CONFIG_PCI
void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
{
if (!INDIRECT_ADDR(addr)) {
iounmap(addr);
}
}
+EXPORT_SYMBOL(pci_iounmap);
+#endif
EXPORT_SYMBOL(ioread8);
EXPORT_SYMBOL(ioread16);
@@ -484,4 +487,3 @@ EXPORT_SYMBOL(iowrite32_rep);
EXPORT_SYMBOL(ioport_map);
EXPORT_SYMBOL(ioport_unmap);
EXPORT_SYMBOL(pci_iomap);
-EXPORT_SYMBOL(pci_iounmap);
diff --git a/arch/parisc/math-emu/cnv_float.h b/arch/parisc/math-emu/cnv_float.h
index 9071e09..37299c7 100644
--- a/arch/parisc/math-emu/cnv_float.h
+++ b/arch/parisc/math-emu/cnv_float.h
@@ -347,16 +347,15 @@
Sgl_isinexact_to_fix(sgl_value,exponent)
#define Duint_from_sgl_mantissa(sgl_value,exponent,dresultA,dresultB) \
- {Sall(sgl_value) <<= SGL_EXP_LENGTH; /* left-justify */ \
+ {unsigned int val = Sall(sgl_value) << SGL_EXP_LENGTH; \
if (exponent <= 31) { \
Dintp1(dresultA) = 0; \
- Dintp2(dresultB) = (unsigned)Sall(sgl_value) >> (31 - exponent); \
+ Dintp2(dresultB) = val >> (31 - exponent); \
} \
else { \
- Dintp1(dresultA) = Sall(sgl_value) >> (63 - exponent); \
- Dintp2(dresultB) = Sall(sgl_value) << (exponent - 31); \
+ Dintp1(dresultA) = val >> (63 - exponent); \
+ Dintp2(dresultB) = exponent <= 62 ? val << (exponent - 31) : 0; \
} \
- Sall(sgl_value) >>= SGL_EXP_LENGTH; /* return to original */ \
}
#define Duint_setzero(dresultA,dresultB) \
diff --git a/drivers/parisc/iommu-helpers.h b/drivers/parisc/iommu-helpers.h
index a9c46cc..8c33491 100644
--- a/drivers/parisc/iommu-helpers.h
+++ b/drivers/parisc/iommu-helpers.h
@@ -1,3 +1,5 @@
+#include <linux/prefetch.h>
+
/**
* iommu_fill_pdir - Insert coalesced scatter/gather chunks into the I/O Pdir.
* @ioc: The I/O Controller.
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index f7c543a..d69738a 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -549,6 +549,7 @@ out_eoi:
void
handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
{
+ struct irqaction *action;
struct irq_chip *chip = irq_desc_get_chip(desc);
kstat_incr_irqs_this_cpu(irq, desc);
@@ -556,7 +557,9 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
if (chip->irq_ack)
chip->irq_ack(&desc->irq_data);
- handle_irq_event_percpu(desc, desc->action);
+ action = desc->action;
+ if (action)
+ handle_irq_event_percpu(desc, action);
if (chip->irq_eoi)
chip->irq_eoi(&desc->irq_data);
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: Happy New Year PARISC (take 2)
2012-02-28 15:28 ` John David Anglin
@ 2012-02-28 22:56 ` Domenico Andreoli
2012-02-29 1:28 ` John David Anglin
2012-03-01 0:48 ` John David Anglin
0 siblings, 2 replies; 18+ messages in thread
From: Domenico Andreoli @ 2012-02-28 22:56 UTC (permalink / raw)
To: John David Anglin
Cc: James Bottomley, Carlos O'Donell, Grant Grundler,
linux-parisc List
Hi,
On Tue, Feb 28, 2012 at 10:28:10AM -0500, John David Anglin wrote:
>
> Here is take 3. Since take 2, I have tried mainly to explore
> performance issues.
>
> The big difference is a new implementation of flush_cache_mm where I try to
> avoid the brutal flush of the whole cache. This drops the full GCC
> build time at
> -j4 from about six hours nine minutes to three hours ten minutes on
> rp3440 (i.e.,
> almost by a factor two). Build and check time is still a bit slower
> than HP-UX.
> There's probably more to tweak here.
>
> Other changes made little difference (e.g., clear_page_asm). I also
> explored
> the affect of prefetch operations in clear_page_asm and copy_page_asm, but
> the difference if any was in the noise.
I applied this patch to v3.3-rc5 and then tried to build eglibc 2.13-27,
unsuccessfully. Do you have any patch for it?
Thanks,
Domenico
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Happy New Year PARISC (take 2)
2012-02-28 22:56 ` Domenico Andreoli
@ 2012-02-29 1:28 ` John David Anglin
2012-03-01 0:48 ` John David Anglin
1 sibling, 0 replies; 18+ messages in thread
From: John David Anglin @ 2012-02-29 1:28 UTC (permalink / raw)
To: Domenico Andreoli
Cc: James Bottomley, Carlos O'Donell, Grant Grundler,
linux-parisc List
[-- Attachment #1: Type: text/plain, Size: 1381 bytes --]
On 28-Feb-12, at 5:56 PM, Domenico Andreoli wrote:
> I applied this patch to v3.3-rc5 and then tried to build eglibc
> 2.13-27,
> unsuccessfully. Do you have any patch for it?
I have 2.13-26 installed on my home system. I plan to build 2.13-27
soon.
Attached are my glibc patch set. You need to remove hppa/local-stack-
grows-up.diff with quilt
and then import the changes below in order. Each patch must be pushed
after import.
However, there are some pre-dependencies. I believe that you should
build the current version
of binutils with the attached two changes. They are in the upstream
sources but I don't believe
they are in the debian source yet. You also may need to update gcc to
the latest unstable version
of 4.4 (build might have switched to 4.6 branch). I now build almost
everything else with 4.6.2.
For installation, I believe that perl and some dependent libraries
need updating. Otherwise, the
install will break perl.
If you get that far, you will resolve many thread related problems.
If you use udev, it should
then be possible to update.
If you get in trouble, there are many .debs in my /dave/home/archives
directory on shirka.esiee.fr.
If you don't have access to this system, possibly Thibaut can provide
an account. These can help
you revert or resolve dependencies.
Dave
--
John David Anglin dave.anglin@bell.net
[-- Attachment #2: core-2011-08-31.diff --]
[-- Type: application/octet-stream, Size: 12278 bytes --]
Index: eglibc-2.13/nptl/allocatestack.c
===================================================================
--- eglibc-2.13.orig/nptl/allocatestack.c 2011-09-04 12:36:29.000000000 -0400
+++ eglibc-2.13/nptl/allocatestack.c 2011-09-04 12:41:22.000000000 -0400
@@ -356,6 +356,15 @@
if (__builtin_expect (attr->flags & ATTR_FLAG_STACKADDR, 0))
{
uintptr_t adj;
+#if _STACK_GROWS_DOWN
+ char * stackaddr = (char *) attr->stackaddr;
+#else
+ /* Assume the same layout as the _STACK_GROWS_DOWN case,
+ with struct pthread at the top of the stack block.
+ Later we adjust the guard location and stack address
+ to match the _STACK_GROWS_UP case. */
+ char * stackaddr = (char *) attr->stackaddr + attr->stacksize;
+#endif
/* If the user also specified the size of the stack make sure it
is large enough. */
@@ -365,11 +374,11 @@
/* Adjust stack size for alignment of the TLS block. */
#if TLS_TCB_AT_TP
- adj = ((uintptr_t) attr->stackaddr - TLS_TCB_SIZE)
+ adj = ((uintptr_t) stackaddr - TLS_TCB_SIZE)
& __static_tls_align_m1;
assert (size > adj + TLS_TCB_SIZE);
#elif TLS_DTV_AT_TP
- adj = ((uintptr_t) attr->stackaddr - __static_tls_size)
+ adj = ((uintptr_t) stackaddr - __static_tls_size)
& __static_tls_align_m1;
assert (size > adj);
#endif
@@ -379,10 +388,10 @@
the stack. It is the user's responsibility to do this if it
is wanted. */
#if TLS_TCB_AT_TP
- pd = (struct pthread *) ((uintptr_t) attr->stackaddr
+ pd = (struct pthread *) ((uintptr_t) stackaddr
- TLS_TCB_SIZE - adj);
#elif TLS_DTV_AT_TP
- pd = (struct pthread *) (((uintptr_t) attr->stackaddr
+ pd = (struct pthread *) (((uintptr_t) stackaddr
- __static_tls_size - adj)
- TLS_PRE_TCB_SIZE);
#endif
@@ -394,7 +403,7 @@
pd->specific[0] = pd->specific_1stblock;
/* Remember the stack-related values. */
- pd->stackblock = (char *) attr->stackaddr - size;
+ pd->stackblock = (char *) stackaddr - size;
pd->stackblock_size = size;
/* This is a user-provided stack. It will not be queued in the
@@ -625,7 +634,7 @@
char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1);
#elif _STACK_GROWS_DOWN
char *guard = mem;
-# elif _STACK_GROWS_UP
+#elif _STACK_GROWS_UP
char *guard = (char *) (((uintptr_t) pd - guardsize) & ~pagesize_m1);
#endif
if (mprotect (guard, guardsize, PROT_NONE) != 0)
@@ -678,9 +687,13 @@
prot) != 0)
goto mprot_error;
#elif _STACK_GROWS_UP
- if (mprotect ((char *) pd - pd->guardsize,
- pd->guardsize - guardsize, prot) != 0)
- goto mprot_error;
+ char *new_guard = (char *) (((uintptr_t) pd - guardsize) & ~pagesize_m1);
+ char *old_guard = (char *) (((uintptr_t) pd - pd->guardsize) & ~pagesize_m1);
+ /* The guard size difference might be > 0, but once rounded
+ to the nearest page the size difference might be zero. */
+ if (old_guard - new_guard > 0)
+ if (mprotect (old_guard, new_guard - old_guard, prot) != 0)
+ goto mprot_error;
#endif
pd->guardsize = guardsize;
@@ -723,8 +736,10 @@
#elif _STACK_GROWS_DOWN
*stack = stacktop;
#elif _STACK_GROWS_UP
+ /* We don't use stacktop. In _STACK_GROWS_UP the start
+ of the stack is simply stackblock (lowest address of
+ the stored block of memory for the stack). */
*stack = pd->stackblock;
- assert (*stack > 0);
#endif
return 0;
Index: eglibc-2.13/nptl/pthread_attr_getstack.c
===================================================================
--- eglibc-2.13.orig/nptl/pthread_attr_getstack.c 2011-09-04 12:37:08.000000000 -0400
+++ eglibc-2.13/nptl/pthread_attr_getstack.c 2011-09-04 12:41:22.000000000 -0400
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2010 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
@@ -33,7 +33,11 @@
iattr = (struct pthread_attr *) attr;
/* Store the result. */
+#ifdef _STACK_GROWS_DOWN
*stackaddr = (char *) iattr->stackaddr - iattr->stacksize;
+#else
+ *stackaddr = (char *) iattr->stackaddr;
+#endif
*stacksize = iattr->stacksize;
return 0;
Index: eglibc-2.13/nptl/pthread_attr_setstack.c
===================================================================
--- eglibc-2.13.orig/nptl/pthread_attr_setstack.c 2011-09-04 12:37:37.000000000 -0400
+++ eglibc-2.13/nptl/pthread_attr_setstack.c 2011-09-04 12:41:22.000000000 -0400
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2006, 2010 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
@@ -48,7 +48,11 @@
#endif
iattr->stacksize = stacksize;
+#if _STACK_GROWS_DOWN
iattr->stackaddr = (char *) stackaddr + stacksize;
+#else
+ iattr->stackaddr = (char *) stackaddr;
+#endif
iattr->flags |= ATTR_FLAG_STACKADDR;
return 0;
@@ -81,7 +85,11 @@
# endif
iattr->stacksize = stacksize;
+#if _STACK_GROWS_DOWN
iattr->stackaddr = (char *) stackaddr + stacksize;
+#else
+ iattr->stackaddr = (char *) stackaddr;
+#endif
iattr->flags |= ATTR_FLAG_STACKADDR;
return 0;
Index: eglibc-2.13/nptl/pthread_create.c
===================================================================
--- eglibc-2.13.orig/nptl/pthread_create.c 2011-09-04 12:38:04.000000000 -0400
+++ eglibc-2.13/nptl/pthread_create.c 2011-09-04 12:41:22.000000000 -0400
@@ -392,12 +392,25 @@
#ifdef _STACK_GROWS_DOWN
char *sp = CURRENT_STACK_FRAME;
size_t freesize = (sp - (char *) pd->stackblock) & ~pagesize_m1;
-#else
-# error "to do"
-#endif
assert (freesize < pd->stackblock_size);
if (freesize > PTHREAD_STACK_MIN)
madvise (pd->stackblock, freesize - PTHREAD_STACK_MIN, MADV_DONTNEED);
+#else
+ /* Page aligned start of memory to free (higher than or equal
+ to current sp plus the minimum stack size). */
+ void *freeblock = (void*)((size_t)(CURRENT_STACK_FRAME
+ + PTHREAD_STACK_MIN
+ + pagesize_m1)
+ & ~pagesize_m1);
+ char *free_end = (char *) (((uintptr_t) pd - pd->guardsize) & ~pagesize_m1);
+ /* Is there any space to free? */
+ if (free_end > (char *)freeblock)
+ {
+ size_t freesize = (size_t)(free_end - (char *)freeblock);
+ assert (freesize < pd->stackblock_size);
+ madvise (freeblock, freesize, MADV_DONTNEED);
+ }
+#endif
/* If the thread is detached free the TCB. */
if (IS_DETACHED (pd))
Index: eglibc-2.13/nptl/pthread_getattr_np.c
===================================================================
--- eglibc-2.13.orig/nptl/pthread_getattr_np.c 2011-09-04 12:38:22.000000000 -0400
+++ eglibc-2.13/nptl/pthread_getattr_np.c 2011-09-04 12:41:22.000000000 -0400
@@ -1,4 +1,5 @@
-/* Copyright (C) 2002, 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2004, 2006, 2007,
+ 2010 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
@@ -61,7 +62,11 @@
if (__builtin_expect (thread->stackblock != NULL, 1))
{
iattr->stacksize = thread->stackblock_size;
+#ifdef _STACK_GROWS_DOWN
iattr->stackaddr = (char *) thread->stackblock + iattr->stacksize;
+#else
+ iattr->stackaddr = (char *) thread->stackblock;
+#endif
}
else
{
@@ -110,13 +115,21 @@
{
/* Found the entry. Now we have the info we need. */
iattr->stacksize = rl.rlim_cur;
+#ifdef _STACK_GROWS_DOWN
iattr->stackaddr = (void *) to;
/* The limit might be too high. */
if ((size_t) iattr->stacksize
> (size_t) iattr->stackaddr - last_to)
iattr->stacksize = (size_t) iattr->stackaddr - last_to;
+#else
+ iattr->stackaddr = (void *) from;
+ /* The limit might be too high. */
+ if ((size_t) iattr->stacksize
+ > to - (size_t) iattr->stackaddr)
+ iattr->stacksize = to - (size_t) iattr->stackaddr;
+#endif
/* We succeed and no need to look further. */
ret = 0;
break;
Index: eglibc-2.13/nptl/pthread_mutex_trylock.c
===================================================================
--- eglibc-2.13.orig/nptl/pthread_mutex_trylock.c 2011-09-04 12:38:45.000000000 -0400
+++ eglibc-2.13/nptl/pthread_mutex_trylock.c 2011-09-04 12:41:22.000000000 -0400
@@ -240,7 +240,8 @@
private), 0, 0);
if (INTERNAL_SYSCALL_ERROR_P (e, __err)
- && INTERNAL_SYSCALL_ERRNO (e, __err) == EWOULDBLOCK)
+ && ((INTERNAL_SYSCALL_ERRNO (e, __err) == EWOULDBLOCK)
+ || (INTERNAL_SYSCALL_ERRNO (e, __err) == EAGAIN)))
{
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
Index: eglibc-2.13/nptl/sysdeps/pthread/aio_misc.h
===================================================================
--- eglibc-2.13.orig/nptl/sysdeps/pthread/aio_misc.h 2011-09-04 12:39:12.000000000 -0400
+++ eglibc-2.13/nptl/sysdeps/pthread/aio_misc.h 2011-09-04 12:41:22.000000000 -0400
@@ -51,7 +51,7 @@
{ \
status = lll_futex_timed_wait (futexaddr, oldval, timeout, \
LLL_PRIVATE); \
- if (status != -EWOULDBLOCK) \
+ if (status != -EWOULDBLOCK && status != -EAGAIN) \
break; \
\
oldval = *futexaddr; \
@@ -66,7 +66,7 @@
else if (status == -ETIMEDOUT) \
result = EAGAIN; \
else \
- assert (status == 0 || status == -EWOULDBLOCK); \
+ assert (status == 0 || status == -EWOULDBLOCK || status == -EAGAIN);\
\
pthread_mutex_lock (&__aio_requests_mutex); \
} \
Index: eglibc-2.13/nptl/sysdeps/pthread/gai_misc.h
===================================================================
--- eglibc-2.13.orig/nptl/sysdeps/pthread/gai_misc.h 2011-09-04 12:39:40.000000000 -0400
+++ eglibc-2.13/nptl/sysdeps/pthread/gai_misc.h 2011-09-04 12:41:22.000000000 -0400
@@ -52,7 +52,7 @@
{ \
status = lll_futex_timed_wait (futexaddr, oldval, timeout, \
LLL_PRIVATE); \
- if (status != -EWOULDBLOCK) \
+ if (status != -EWOULDBLOCK && status != -EAGAIN) \
break; \
\
oldval = *futexaddr; \
@@ -67,7 +67,7 @@
else if (status == -ETIMEDOUT) \
result = EAGAIN; \
else \
- assert (status == 0 || status == -EWOULDBLOCK); \
+ assert (status == 0 || status == -EWOULDBLOCK || status == -EAGAIN);\
\
pthread_mutex_lock (&__gai_requests_mutex); \
} \
Index: eglibc-2.13/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c
===================================================================
--- eglibc-2.13.orig/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c 2011-09-04 12:40:07.000000000 -0400
+++ eglibc-2.13/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c 2011-09-04 12:41:22.000000000 -0400
@@ -90,7 +90,7 @@
/* Disable asynchronous cancellation. */
__pthread_disable_asynccancel (oldtype);
- if (err != 0 && err != -EWOULDBLOCK)
+ if (err != 0 && err != -EWOULDBLOCK && err != -EAGAIN)
{
__set_errno (-err);
err = -1;
Index: eglibc-2.13/nptl/sysdeps/unix/sysv/linux/sem_wait.c
===================================================================
--- eglibc-2.13.orig/nptl/sysdeps/unix/sysv/linux/sem_wait.c 2011-09-04 12:40:30.000000000 -0400
+++ eglibc-2.13/nptl/sysdeps/unix/sysv/linux/sem_wait.c 2011-09-04 12:41:22.000000000 -0400
@@ -62,7 +62,7 @@
/* Disable asynchronous cancellation. */
__pthread_disable_asynccancel (oldtype);
- if (err != 0 && err != -EWOULDBLOCK)
+ if (err != 0 && err != -EWOULDBLOCK && err != -EAGAIN)
{
__set_errno (-err);
err = -1;
@@ -107,7 +107,7 @@
/* Disable asynchronous cancellation. */
__pthread_disable_asynccancel (oldtype);
}
- while (err == 0 || err == -EWOULDBLOCK);
+ while (err == 0 || err == -EWOULDBLOCK || err == -EAGAIN);
__set_errno (-err);
return -1;
[-- Attachment #3: ports-2011-08-31.diff --]
[-- Type: application/octet-stream, Size: 24762 bytes --]
Index: eglibc-2.13/ports/ChangeLog.hppa
===================================================================
--- eglibc-2.13.orig/ports/ChangeLog.hppa 2011-09-04 14:13:02.000000000 -0400
+++ eglibc-2.13/ports/ChangeLog.hppa 2011-09-04 14:20:23.000000000 -0400
@@ -1,3 +1,8 @@
+2010-10-29 Carlos O'Donell <carlos@codesourcery.com>
+
+ * sysdeps/hppa/dl-machine.h: Update copyright year.
+ (ELF_MACHINE_BEFORE_RTLD_RELOC): Call _dl_fptr_init.
+
2010-06-24 Carlos O'Donell <carlos@codesourcery.com>
* sysdeps/unix/sysv/linux/hppa/nptl/pt-vfork.S: Only create stack
Index: eglibc-2.13/ports/sysdeps/hppa/configure
===================================================================
--- eglibc-2.13.orig/ports/sysdeps/hppa/configure 2011-09-04 14:13:32.000000000 -0400
+++ eglibc-2.13/ports/sysdeps/hppa/configure 2011-09-04 14:34:35.000000000 -0400
@@ -1,19 +1,101 @@
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
# This file is generated from configure.in by Autoconf. DO NOT EDIT!
-{ $as_echo "$as_me:$LINENO: checking for assembler line separator" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for assembler line separator" >&5
$as_echo_n "checking for assembler line separator... " >&6; }
-if test "${libc_cv_asm_line_sep+set}" = set; then
+if test "${libc_cv_asm_line_sep+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat > conftest.s <<EOF
nop ; is_old_puffin
EOF
if { ac_try='${CC-cc} -c $ASFLAGS conftest.s 1>&5'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
(eval $ac_try) 2>&5
ac_status=$?
- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
libc_cv_asm_line_sep='!'
else
if test -z "$enable_hacker_mode"; then
@@ -25,7 +107,7 @@
fi
rm -f conftest*
fi
-{ $as_echo "$as_me:$LINENO: result: $libc_cv_asm_line_sep" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_asm_line_sep" >&5
$as_echo "$libc_cv_asm_line_sep" >&6; }
cat >>confdefs.h <<_ACEOF
#define ASM_LINE_SEP $libc_cv_asm_line_sep
Index: eglibc-2.13/ports/sysdeps/hppa/dl-fptr.h
===================================================================
--- eglibc-2.13.orig/ports/sysdeps/hppa/dl-fptr.h 2011-09-04 14:14:04.000000000 -0400
+++ eglibc-2.13/ports/sysdeps/hppa/dl-fptr.h 2011-09-04 14:20:23.000000000 -0400
@@ -22,6 +22,9 @@
#include <sysdeps/generic/dl-fptr.h>
+/* Initialize function pointer code. Call before relocation processing. */
+extern void _dl_fptr_init (void);
+
/* There are currently 33 dynamic symbols in ld.so.
ELF_MACHINE_BOOT_FPTR_TABLE_LEN needs to be at least that big. */
#define ELF_MACHINE_BOOT_FPTR_TABLE_LEN 64
Index: eglibc-2.13/ports/sysdeps/hppa/dl-machine.h
===================================================================
--- eglibc-2.13.orig/ports/sysdeps/hppa/dl-machine.h 2011-09-04 14:14:30.000000000 -0400
+++ eglibc-2.13/ports/sysdeps/hppa/dl-machine.h 2011-09-04 14:20:23.000000000 -0400
@@ -1,6 +1,5 @@
/* Machine-dependent ELF dynamic relocation inline functions. PA-RISC version.
- Copyright (C) 1995-1997,1999-2003
- Free Software Foundation, Inc.
+ Copyright (C) 1995-1997,1999-2003, 2010 Free Software Foundation, Inc.
Contributed by David Huggins-Daines <dhd@debian.org>
This file is part of the GNU C Library.
Index: eglibc-2.13/ports/sysdeps/hppa/dl-tls.h
===================================================================
--- eglibc-2.13.orig/ports/sysdeps/hppa/dl-tls.h 2011-09-04 14:14:57.000000000 -0400
+++ eglibc-2.13/ports/sysdeps/hppa/dl-tls.h 2011-09-04 14:20:23.000000000 -0400
@@ -1,5 +1,5 @@
/* Thread-local storage handling in the ELF dynamic linker. hppa version.
- Copyright (C) 2003 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2011 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -27,3 +27,6 @@
extern void *__tls_get_addr (tls_index *ti);
+
+/* Value used for dtv entries for which the allocation is delayed. */
+#define TLS_DTV_UNALLOCATED ((void *) -1l)
Index: eglibc-2.13/ports/sysdeps/hppa/elf/configure
===================================================================
--- eglibc-2.13.orig/ports/sysdeps/hppa/elf/configure 2011-09-04 14:15:24.000000000 -0400
+++ eglibc-2.13/ports/sysdeps/hppa/elf/configure 2011-09-04 14:45:59.000000000 -0400
@@ -1,12 +1,94 @@
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
# This file is generated from configure.in by Autoconf. DO NOT EDIT!
# Local configure fragment for sysdeps/hppa/elf.
if test "$usetls" != no; then
# Check for support of thread-local storage handling in assembler and
# linker.
-{ $as_echo "$as_me:$LINENO: checking for hppa TLS support" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for hppa TLS support" >&5
$as_echo_n "checking for hppa TLS support... " >&6; }
-if test "${libc_cv_hppa_tls+set}" = set; then
+if test "${libc_cv_hppa_tls+set}" = set; then :
$as_echo_n "(cached) " >&6
else
cat > conftest.s <<\EOF
@@ -41,23 +123,21 @@
; Done all the TLS tests.
EOF
if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5'
- { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
(eval $ac_try) 2>&5
ac_status=$?
- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); }; }; then
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
libc_cv_hppa_tls=yes
else
libc_cv_hppa_tls=no
fi
rm -f conftest*
fi
-{ $as_echo "$as_me:$LINENO: result: $libc_cv_hppa_tls" >&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_hppa_tls" >&5
$as_echo "$libc_cv_hppa_tls" >&6; }
if test $libc_cv_hppa_tls = yes; then
- cat >>confdefs.h <<\_ACEOF
-#define HAVE_TLS_SUPPORT 1
-_ACEOF
+ $as_echo "#define HAVE_TLS_SUPPORT 1" >>confdefs.h
fi
fi
Index: eglibc-2.13/ports/sysdeps/hppa/fpu/fegetenv.c
===================================================================
--- eglibc-2.13.orig/ports/sysdeps/hppa/fpu/fegetenv.c 2011-09-04 14:15:52.000000000 -0400
+++ eglibc-2.13/ports/sysdeps/hppa/fpu/fegetenv.c 2011-09-04 14:20:23.000000000 -0400
@@ -1,5 +1,5 @@
/* Store current floating-point environment.
- Copyright (C) 2000 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2011 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by David Huggins-Daines <dhd@debian.org>, 2000
Index: eglibc-2.13/ports/sysdeps/hppa/fpu/feupdateenv.c
===================================================================
--- eglibc-2.13.orig/ports/sysdeps/hppa/fpu/feupdateenv.c 2011-09-04 14:16:18.000000000 -0400
+++ eglibc-2.13/ports/sysdeps/hppa/fpu/feupdateenv.c 2011-09-04 14:20:23.000000000 -0400
@@ -1,5 +1,5 @@
/* Install given floating-point environment and raise exceptions.
- Copyright (C) 2000 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2011 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by David Huggins-Daines <dhd@debian.org>, 2000
Index: eglibc-2.13/ports/sysdeps/hppa/fpu/ftestexcept.c
===================================================================
--- eglibc-2.13.orig/ports/sysdeps/hppa/fpu/ftestexcept.c 2011-09-04 14:16:49.000000000 -0400
+++ eglibc-2.13/ports/sysdeps/hppa/fpu/ftestexcept.c 2011-09-04 14:20:23.000000000 -0400
@@ -1,5 +1,5 @@
/* Test exception in current environment.
- Copyright (C) 2000 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2011 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by David Huggins-Daines <dhd@debian.org>, 2000
Index: eglibc-2.13/ports/sysdeps/hppa/stackinfo.h
===================================================================
--- eglibc-2.13.orig/ports/sysdeps/hppa/stackinfo.h 2011-09-04 14:17:22.000000000 -0400
+++ eglibc-2.13/ports/sysdeps/hppa/stackinfo.h 2011-09-04 14:20:23.000000000 -0400
@@ -22,6 +22,12 @@
#ifndef _STACKINFO_H
#define _STACKINFO_H 1
+#include <elf.h>
+
+/* Default to an executable stack. PF_X can be overridden if PT_GNU_STACK is
+ * present, but it is presumed absent. */
+#define DEFAULT_STACK_PERMS (PF_R|PF_W|PF_X)
+
/* On PA the stack grows up. */
#define _STACK_GROWS_UP 1
Index: eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/bits/fcntl.h
===================================================================
--- eglibc-2.13.orig/ports/sysdeps/unix/sysv/linux/hppa/bits/fcntl.h 2011-09-04 14:17:42.000000000 -0400
+++ eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/bits/fcntl.h 2011-09-04 14:20:23.000000000 -0400
@@ -1,5 +1,5 @@
-/* O_*, F_*, FD_* bit values for Linux/HPPA.
- Copyright (C) 1995,1996,1997,1998,1999,2000,2002,2004
+/* O_*, F_*, FD_* bit values for Linux.
+ Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2004, 2010
Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -29,7 +29,7 @@
/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
- located on an ext2 file system */
+ located on a few file systems. */
#define O_ACCMODE 0003
#define O_RDONLY 00
#define O_WRONLY 01
Index: eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/nptl/sysdep-cancel.h
===================================================================
--- eglibc-2.13.orig/ports/sysdeps/unix/sysv/linux/hppa/nptl/sysdep-cancel.h 2011-09-04 14:18:10.000000000 -0400
+++ eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/nptl/sysdep-cancel.h 2011-09-04 14:20:23.000000000 -0400
@@ -61,11 +61,53 @@
# undef PSEUDO
# define PSEUDO(name, syscall_name, args) \
+ ENTRY (__##syscall_name##_nocancel) \
+ DOARGS_##args ASM_LINE_SEP \
+ stwm TREG, 64(%sp) ASM_LINE_SEP \
+ .cfi_offset TREG, 0 ASM_LINE_SEP \
+ .cfi_adjust_cfa_offset 64 ASM_LINE_SEP \
+ stw %sp, -4(%sp) ASM_LINE_SEP \
+ .cfi_offset 30, -4 ASM_LINE_SEP \
+ stw %r19, -32(%sp) ASM_LINE_SEP \
+ .cfi_offset 19, -32 ASM_LINE_SEP \
+ /* Save r19 */ ASM_LINE_SEP \
+ SAVE_PIC(TREG) ASM_LINE_SEP \
+ /* Do syscall, delay loads # */ ASM_LINE_SEP \
+ ble 0x100(%sr2,%r0) ASM_LINE_SEP \
+ ldi SYS_ify (syscall_name), %r20 /* delay */ ASM_LINE_SEP \
+ ldi NO_ERROR,%r1 ASM_LINE_SEP \
+ cmpb,>>=,n %r1,%ret0,L(pre_nc_end) ASM_LINE_SEP \
+ /* Restore r19 from TREG */ ASM_LINE_SEP \
+ LOAD_PIC(TREG) /* delay */ ASM_LINE_SEP \
+ SYSCALL_ERROR_HANDLER ASM_LINE_SEP \
+ /* Use TREG for temp storage */ ASM_LINE_SEP \
+ copy %ret0, TREG /* delay */ ASM_LINE_SEP \
+ /* OPTIMIZE: Don't reload r19 */ ASM_LINE_SEP \
+ /* do a -1*syscall_ret0 */ ASM_LINE_SEP \
+ sub %r0, TREG, TREG ASM_LINE_SEP \
+ /* Store into errno location */ ASM_LINE_SEP \
+ stw TREG, 0(%sr0,%ret0) ASM_LINE_SEP \
+ /* return -1 as error */ ASM_LINE_SEP \
+ ldi -1, %ret0 ASM_LINE_SEP \
+L(pre_nc_end): ASM_LINE_SEP \
+ /* No need to LOAD_PIC */ ASM_LINE_SEP \
+ /* Undo frame */ ASM_LINE_SEP \
+ ldwm -64(%sp),TREG ASM_LINE_SEP \
+ .cfi_adjust_cfa_offset -64 ASM_LINE_SEP \
+ /* Restore rp before exit */ ASM_LINE_SEP \
+ ldw -20(%sp), %rp ASM_LINE_SEP \
+ .cfi_restore 2 ASM_LINE_SEP \
+ ret ASM_LINE_SEP \
+ END(__##syscall_name##_nocancel) ASM_LINE_SEP \
+ /**********************************************/ASM_LINE_SEP \
ENTRY (name) \
DOARGS_##args ASM_LINE_SEP \
stwm TREG, 64(%sp) ASM_LINE_SEP \
+ .cfi_adjust_cfa_offset 64 ASM_LINE_SEP \
stw %sp, -4(%sp) ASM_LINE_SEP \
+ .cfi_offset 30, -4 ASM_LINE_SEP \
stw %r19, -32(%sp) ASM_LINE_SEP \
+ .cfi_offset 19, -32 ASM_LINE_SEP \
/* Done setting up frame, continue... */ ASM_LINE_SEP \
SINGLE_THREAD_P ASM_LINE_SEP \
cmpib,<>,n 0,%ret0,L(pseudo_cancel) ASM_LINE_SEP \
@@ -128,26 +170,40 @@
/* No need to LOAD_PIC */ ASM_LINE_SEP \
/* Undo frame */ ASM_LINE_SEP \
ldwm -64(%sp),TREG ASM_LINE_SEP \
+ .cfi_adjust_cfa_offset -64 ASM_LINE_SEP \
/* Restore rp before exit */ ASM_LINE_SEP \
- ldw -20(%sp), %rp ASM_LINE_SEP
+ ldw -20(%sp), %rp ASM_LINE_SEP \
+ .cfi_restore 2 ASM_LINE_SEP
/* Save arguments into our frame */
# define PUSHARGS_0 /* nothing to do */
-# define PUSHARGS_1 PUSHARGS_0 stw %r26, -36(%sr0,%sp) ASM_LINE_SEP
-# define PUSHARGS_2 PUSHARGS_1 stw %r25, -40(%sr0,%sp) ASM_LINE_SEP
-# define PUSHARGS_3 PUSHARGS_2 stw %r24, -44(%sr0,%sp) ASM_LINE_SEP
-# define PUSHARGS_4 PUSHARGS_3 stw %r23, -48(%sr0,%sp) ASM_LINE_SEP
-# define PUSHARGS_5 PUSHARGS_4 stw %r22, -52(%sr0,%sp) ASM_LINE_SEP
-# define PUSHARGS_6 PUSHARGS_5 stw %r21, -56(%sr0,%sp) ASM_LINE_SEP
+# define PUSHARGS_1 PUSHARGS_0 stw %r26, -36(%sr0,%sp) ASM_LINE_SEP \
+ .cfi_offset 26, -36 ASM_LINE_SEP
+# define PUSHARGS_2 PUSHARGS_1 stw %r25, -40(%sr0,%sp) ASM_LINE_SEP \
+ .cfi_offset 25, -40 ASM_LINE_SEP
+# define PUSHARGS_3 PUSHARGS_2 stw %r24, -44(%sr0,%sp) ASM_LINE_SEP \
+ .cfi_offset 24, -44 ASM_LINE_SEP
+# define PUSHARGS_4 PUSHARGS_3 stw %r23, -48(%sr0,%sp) ASM_LINE_SEP \
+ .cfi_offset 23, -48 ASM_LINE_SEP
+# define PUSHARGS_5 PUSHARGS_4 stw %r22, -52(%sr0,%sp) ASM_LINE_SEP \
+ .cfi_offset 22, -52 ASM_LINE_SEP
+# define PUSHARGS_6 PUSHARGS_5 stw %r21, -56(%sr0,%sp) ASM_LINE_SEP \
+ .cfi_offset 21, -56 ASM_LINE_SEP
/* Bring them back from the stack */
# define POPARGS_0 /* nothing to do */
-# define POPARGS_1 POPARGS_0 ldw -36(%sr0,%sp), %r26 ASM_LINE_SEP
-# define POPARGS_2 POPARGS_1 ldw -40(%sr0,%sp), %r25 ASM_LINE_SEP
-# define POPARGS_3 POPARGS_2 ldw -44(%sr0,%sp), %r24 ASM_LINE_SEP
-# define POPARGS_4 POPARGS_3 ldw -48(%sr0,%sp), %r23 ASM_LINE_SEP
-# define POPARGS_5 POPARGS_4 ldw -52(%sr0,%sp), %r22 ASM_LINE_SEP
-# define POPARGS_6 POPARGS_5 ldw -56(%sr0,%sp), %r21 ASM_LINE_SEP
+# define POPARGS_1 POPARGS_0 ldw -36(%sr0,%sp), %r26 ASM_LINE_SEP \
+ .cfi_restore 26 ASM_LINE_SEP
+# define POPARGS_2 POPARGS_1 ldw -40(%sr0,%sp), %r25 ASM_LINE_SEP \
+ .cfi_restore 25 ASM_LINE_SEP
+# define POPARGS_3 POPARGS_2 ldw -44(%sr0,%sp), %r24 ASM_LINE_SEP \
+ .cfi_restore 24 ASM_LINE_SEP
+# define POPARGS_4 POPARGS_3 ldw -48(%sr0,%sp), %r23 ASM_LINE_SEP \
+ .cfi_restore 23 ASM_LINE_SEP
+# define POPARGS_5 POPARGS_4 ldw -52(%sr0,%sp), %r22 ASM_LINE_SEP \
+ .cfi_restore 22 ASM_LINE_SEP
+# define POPARGS_6 POPARGS_5 ldw -56(%sr0,%sp), %r21 ASM_LINE_SEP \
+ .cfi_restore 21 ASM_LINE_SEP
# ifdef IS_IN_libpthread
# ifdef PIC
Index: eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/sys/procfs.h
===================================================================
--- eglibc-2.13.orig/ports/sysdeps/unix/sysv/linux/hppa/sys/procfs.h 2011-09-04 14:18:44.000000000 -0400
+++ eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/sys/procfs.h 2011-09-04 14:20:23.000000000 -0400
@@ -29,10 +29,8 @@
GDB unless you know what you are doing. */
#include <features.h>
-#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
-#include <sys/ucontext.h>
#include <sys/user.h>
__BEGIN_DECLS
Index: eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/sysdep.h
===================================================================
--- eglibc-2.13.orig/ports/sysdeps/unix/sysv/linux/hppa/sysdep.h 2011-09-04 14:19:27.000000000 -0400
+++ eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/sysdep.h 2011-09-04 14:20:23.000000000 -0400
@@ -22,7 +22,6 @@
#include <asm/unistd.h>
#include <sysdeps/generic/sysdep.h>
-#include <sys/syscall.h>
/* In order to get __set_errno() definition in INLINE_SYSCALL. */
#ifndef __ASSEMBLER__
@@ -35,32 +34,28 @@
#undef SYS_ify
#define SYS_ify(syscall_name) (__NR_##syscall_name)
+/* The vfork, fork, and clone syscalls clobber r19
+ * and r21. We list r21 as either clobbered or as an
+ * input to a 6-argument syscall. We must save and
+ * restore r19 in both PIC and non-PIC cases.
+ */
/* WARNING: TREG must be a callee saves register so
that it doesn't have to be restored after a call
to another function */
-#ifdef PIC
-# define TREG %r3
-# define SAVE_PIC(SREG) copy %r19, SREG ASM_LINE_SEP
-# define LOAD_PIC(LREG) copy LREG, %r19 ASM_LINE_SEP
-/* Inline assembly defines */
-# define TREG_ASM "%r4" /* Cant clobber r3, it holds framemarker */
-# define SAVE_ASM_PIC " copy %%r19, %" TREG_ASM "\n"
-# define LOAD_ASM_PIC " copy %" TREG_ASM ", %%r19\n"
-# define CLOB_TREG TREG_ASM ,
-# define PIC_REG_DEF register unsigned long __r19 asm("r19");
-# define PIC_REG_USE , "r" (__r19)
-#else
-# define TREG %r3
-# define SAVE_PIC(SREG) nop ASM_LINE_SEP
-# define LOAD_PIC(LREG) nop ASM_LINE_SEP
+#define TREG 4
+#define SAVE_PIC(SREG) \
+ copy %r19, SREG ASM_LINE_SEP \
+ .cfi_register 19, SREG
+#define LOAD_PIC(LREG) \
+ copy LREG , %r19 ASM_LINE_SEP \
+ .cfi_restore 19
/* Inline assembly defines */
-# define TREG_ASM
-# define SAVE_ASM_PIC "nop \n"
-# define LOAD_ASM_PIC "nop \n"
-# define CLOB_TREG
-# define PIC_REG_DEF
-# define PIC_REG_USE
-#endif
+#define TREG_ASM "%r4" /* Cant clobber r3, it holds framemarker */
+#define SAVE_ASM_PIC " copy %%r19, %" TREG_ASM "\n"
+#define LOAD_ASM_PIC " copy %" TREG_ASM ", %%r19\n"
+#define CLOB_TREG TREG_ASM ,
+#define PIC_REG_DEF register unsigned long __r19 asm("r19");
+#define PIC_REG_USE , "r" (__r19)
#ifdef __ASSEMBLER__
@@ -127,12 +122,14 @@
.align ALIGNARG(4) ASM_LINE_SEP \
.export C_SYMBOL_NAME(name) ASM_LINE_SEP \
.type C_SYMBOL_NAME(name),@function ASM_LINE_SEP \
+ cfi_startproc ASM_LINE_SEP \
C_LABEL(name) ASM_LINE_SEP \
.PROC ASM_LINE_SEP \
.CALLINFO FRAME=64,CALLS,SAVE_RP,ENTRY_GR=3 ASM_LINE_SEP \
.ENTRY ASM_LINE_SEP \
/* SAVE_RP says we do */ ASM_LINE_SEP \
stw %rp, -20(%sr0,%sp) ASM_LINE_SEP \
+ .cfi_offset 2, -20 ASM_LINE_SEP \
/*FIXME: Call mcount? (carefull with stack!) */
/* Some syscall wrappers do not call other functions, and
@@ -142,18 +139,21 @@
.align ALIGNARG(4) ASM_LINE_SEP \
.export C_SYMBOL_NAME(name) ASM_LINE_SEP \
.type C_SYMBOL_NAME(name),@function ASM_LINE_SEP \
+ cfi_startproc ASM_LINE_SEP \
C_LABEL(name) ASM_LINE_SEP \
.PROC ASM_LINE_SEP \
.CALLINFO FRAME=64,NO_CALLS,SAVE_RP,ENTRY_GR=3 ASM_LINE_SEP \
.ENTRY ASM_LINE_SEP \
/* SAVE_RP says we do */ ASM_LINE_SEP \
stw %rp, -20(%sr0,%sp) ASM_LINE_SEP \
+ .cfi_offset 2, -20 ASM_LINE_SEP \
/*FIXME: Call mcount? (carefull with stack!) */
#undef END
#define END(name) \
.EXIT ASM_LINE_SEP \
.PROCEND ASM_LINE_SEP \
+ cfi_endproc ASM_LINE_SEP \
.size C_SYMBOL_NAME(name), .-C_SYMBOL_NAME(name) ASM_LINE_SEP
/* If compiled for profiling, call `mcount' at the start
@@ -170,9 +170,7 @@
which means
ENTRY(name)
DO_CALL(...)
- nop
- bv 0(2)
- nop
+ bv,n 0(2)
*/
#define PSEUDO(name, syscall_name, args) \
@@ -180,8 +178,7 @@
/* If necc. load args from stack */ ASM_LINE_SEP \
DOARGS_##args ASM_LINE_SEP \
DO_CALL (syscall_name, args) ASM_LINE_SEP \
- UNDOARGS_##args ASM_LINE_SEP \
- nop ASM_LINE_SEP
+ UNDOARGS_##args ASM_LINE_SEP
#define ret \
/* Return value set by ERRNO code */ ASM_LINE_SEP \
@@ -196,8 +193,7 @@
ENTRY_LEAF (name) ASM_LINE_SEP \
DOARGS_##args ASM_LINE_SEP \
DO_CALL_NOERRNO (syscall_name, args) ASM_LINE_SEP \
- UNDOARGS_##args ASM_LINE_SEP \
- nop ASM_LINE_SEP
+ UNDOARGS_##args ASM_LINE_SEP
#define ret_NOERRNO ret
@@ -211,8 +207,7 @@
ENTRY_LEAF (name) ASM_LINE_SEP \
DOARGS_##args ASM_LINE_SEP \
DO_CALL_ERRVAL (syscall_name, args) ASM_LINE_SEP \
- UNDOARGS_##args ASM_LINE_SEP \
- nop ASM_LINE_SEP
+ UNDOARGS_##args ASM_LINE_SEP
#define ret_ERRVAL ret
@@ -290,8 +285,12 @@
#define DO_CALL(syscall_name, args) \
/* Create a frame */ ASM_LINE_SEP \
stwm TREG, 64(%sp) ASM_LINE_SEP \
+ .cfi_offset TREG, 0 ASM_LINE_SEP \
+ .cfi_adjust_cfa_offset 64 ASM_LINE_SEP \
stw %sp, -4(%sp) ASM_LINE_SEP \
+ .cfi_offset 30, -4 ASM_LINE_SEP \
stw %r19, -32(%sp) ASM_LINE_SEP \
+ .cfi_offset 19, -32 ASM_LINE_SEP \
/* Save r19 */ ASM_LINE_SEP \
SAVE_PIC(TREG) ASM_LINE_SEP \
/* Do syscall, delay loads # */ ASM_LINE_SEP \
@@ -314,8 +313,10 @@
L(pre_end): ASM_LINE_SEP \
/* Restore our frame, restoring TREG */ ASM_LINE_SEP \
ldwm -64(%sp), TREG ASM_LINE_SEP \
+ .cfi_adjust_cfa_offset -64 ASM_LINE_SEP \
/* Restore return pointer */ ASM_LINE_SEP \
- ldw -20(%sp),%rp ASM_LINE_SEP
+ ldw -20(%sp),%rp ASM_LINE_SEP \
+ .cfi_restore 2 ASM_LINE_SEP
/* We do nothing with the return, except hand it back to someone else */
#undef DO_CALL_NOERRNO
[-- Attachment #4: ports-2011-09-17.diff --]
[-- Type: application/octet-stream, Size: 1517 bytes --]
Index: eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/nptl/lowlevellock.h
===================================================================
--- eglibc-2.13.orig/ports/sysdeps/unix/sysv/linux/hppa/nptl/lowlevellock.h 2011-09-05 00:09:53.000000000 -0400
+++ eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/nptl/lowlevellock.h 2011-09-17 23:07:14.000000000 -0400
@@ -288,18 +288,20 @@
__lll_robust_timedlock (&(futex), abstime, id, private)
#define __lll_unlock(futex, private) \
- (void) \
- ({ int val = atomic_exchange_rel (futex, 0); \
- if (__builtin_expect (val > 1, 0)) \
- lll_futex_wake (futex, 1, private); \
+ (void) \
+ ({ int *__futex = (futex); \
+ int val = atomic_exchange_rel (__futex, 0); \
+ if (__builtin_expect (val > 1, 0)) \
+ lll_futex_wake (__futex, 1, private); \
})
#define lll_unlock(futex, private) __lll_unlock(&(futex), private)
#define __lll_robust_unlock(futex,private) \
- (void) \
- ({ int val = atomic_exchange_rel (futex, 0); \
- if (__builtin_expect (val & FUTEX_WAITERS, 0)) \
- lll_futex_wake (futex, 1, private); \
+ (void) \
+ ({ int *__futex = (futex); \
+ int val = atomic_exchange_rel (__futex, 0); \
+ if (__builtin_expect (val & FUTEX_WAITERS, 0)) \
+ lll_futex_wake (__futex, 1, private); \
})
#define lll_robust_unlock(futex, private) \
__lll_robust_unlock(&(futex), private)
[-- Attachment #5: ports-2011-10-30.diff --]
[-- Type: application/octet-stream, Size: 17124 bytes --]
Index: eglibc-2.13/ports/ChangeLog.hppa
===================================================================
--- eglibc-2.13.orig/ports/ChangeLog.hppa 2011-09-24 18:40:01.000000000 -0400
+++ eglibc-2.13/ports/ChangeLog.hppa 2011-10-30 11:43:20.000000000 -0400
@@ -3,6 +3,19 @@
* sysdeps/hppa/dl-machine.h: Update copyright year.
(ELF_MACHINE_BEFORE_RTLD_RELOC): Call _dl_fptr_init.
+2010-08-06 Guy Martin <gmsoft@tuxicoman.be>
+
+ * ports/sysdeps/unix/sysv/linux/hppa/sys/epoll.h:
+ Fix EPOLL_CLOEXEC and EPOLL_NONBLOCK to match kernel definition.
+ * ports/sysdeps/unix/sysv/linux/hppa/sys/eventfd.h:
+ Fix EFD_CLOEXEC and EFD_NONBLOCK to match kernel definition.
+ * ports/sysdeps/unix/sysv/linux/hppa/sys/inotify.h:
+ Fix IN_CLOEXEC and IN_NONBLOCK to match kernel definition.
+ * ports/sysdeps/unix/sysv/linux/hppa/sys/signalfd.h:
+ Fix SFD_CLOEXEC and SFD_NONBLOCK to match kernel definition.
+ * ports/sysdeps/unix/sysv/linux/hppa/sys/timerfd.h:
+ Fix TFD_CLOEXEC and TFD_NONBLOCK to match kernel definition.
+
2010-06-24 Carlos O'Donell <carlos@codesourcery.com>
* sysdeps/unix/sysv/linux/hppa/nptl/pt-vfork.S: Only create stack
Index: eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/sys/epoll.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/sys/epoll.h 2011-10-30 11:44:30.000000000 -0400
@@ -0,0 +1,144 @@
+/* Copyright (C) 2002-2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _SYS_EPOLL_H
+#define _SYS_EPOLL_H 1
+
+#include <stdint.h>
+#include <sys/types.h>
+
+/* Get __sigset_t. */
+#include <bits/sigset.h>
+
+#ifndef __sigset_t_defined
+# define __sigset_t_defined
+typedef __sigset_t sigset_t;
+#endif
+
+
+/* Flags to be passed to epoll_create1. */
+enum
+ {
+ EPOLL_CLOEXEC = 010000000,
+#define EPOLL_CLOEXEC EPOLL_CLOEXEC
+ EPOLL_NONBLOCK = 00200004 /* HPUX has separate NDELAY & NONBLOCK */
+#define EPOLL_NONBLOCK EPOLL_NONBLOCK
+ };
+
+
+enum EPOLL_EVENTS
+ {
+ EPOLLIN = 0x001,
+#define EPOLLIN EPOLLIN
+ EPOLLPRI = 0x002,
+#define EPOLLPRI EPOLLPRI
+ EPOLLOUT = 0x004,
+#define EPOLLOUT EPOLLOUT
+ EPOLLRDNORM = 0x040,
+#define EPOLLRDNORM EPOLLRDNORM
+ EPOLLRDBAND = 0x080,
+#define EPOLLRDBAND EPOLLRDBAND
+ EPOLLWRNORM = 0x100,
+#define EPOLLWRNORM EPOLLWRNORM
+ EPOLLWRBAND = 0x200,
+#define EPOLLWRBAND EPOLLWRBAND
+ EPOLLMSG = 0x400,
+#define EPOLLMSG EPOLLMSG
+ EPOLLERR = 0x008,
+#define EPOLLERR EPOLLERR
+ EPOLLHUP = 0x010,
+#define EPOLLHUP EPOLLHUP
+ EPOLLRDHUP = 0x2000,
+#define EPOLLRDHUP EPOLLRDHUP
+ EPOLLONESHOT = (1 << 30),
+#define EPOLLONESHOT EPOLLONESHOT
+ EPOLLET = (1 << 31)
+#define EPOLLET EPOLLET
+ };
+
+
+/* Valid opcodes ( "op" parameter ) to issue to epoll_ctl(). */
+#define EPOLL_CTL_ADD 1 /* Add a file descriptor to the interface. */
+#define EPOLL_CTL_DEL 2 /* Remove a file descriptor from the interface. */
+#define EPOLL_CTL_MOD 3 /* Change file descriptor epoll_event structure. */
+
+
+typedef union epoll_data
+{
+ void *ptr;
+ int fd;
+ uint32_t u32;
+ uint64_t u64;
+} epoll_data_t;
+
+struct epoll_event
+{
+ uint32_t events; /* Epoll events */
+ epoll_data_t data; /* User data variable */
+};
+
+
+__BEGIN_DECLS
+
+/* Creates an epoll instance. Returns an fd for the new instance.
+ The "size" parameter is a hint specifying the number of file
+ descriptors to be associated with the new instance. The fd
+ returned by epoll_create() should be closed with close(). */
+extern int epoll_create (int __size) __THROW;
+
+/* Same as epoll_create but with an FLAGS parameter. The unused SIZE
+ parameter has been dropped. */
+extern int epoll_create1 (int __flags) __THROW;
+
+
+/* Manipulate an epoll instance "epfd". Returns 0 in case of success,
+ -1 in case of error ( the "errno" variable will contain the
+ specific error code ) The "op" parameter is one of the EPOLL_CTL_*
+ constants defined above. The "fd" parameter is the target of the
+ operation. The "event" parameter describes which events the caller
+ is interested in and any associated user data. */
+extern int epoll_ctl (int __epfd, int __op, int __fd,
+ struct epoll_event *__event) __THROW;
+
+
+/* Wait for events on an epoll instance "epfd". Returns the number of
+ triggered events returned in "events" buffer. Or -1 in case of
+ error with the "errno" variable set to the specific error code. The
+ "events" parameter is a buffer that will contain triggered
+ events. The "maxevents" is the maximum number of events to be
+ returned ( usually size of "events" ). The "timeout" parameter
+ specifies the maximum wait time in milliseconds (-1 == infinite).
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern int epoll_wait (int __epfd, struct epoll_event *__events,
+ int __maxevents, int __timeout);
+
+
+/* Same as epoll_wait, but the thread's signal mask is temporarily
+ and atomically replaced with the one provided as parameter.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern int epoll_pwait (int __epfd, struct epoll_event *__events,
+ int __maxevents, int __timeout,
+ __const __sigset_t *__ss);
+
+__END_DECLS
+
+#endif /* sys/epoll.h */
Index: eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/sys/eventfd.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/sys/eventfd.h 2011-10-30 11:44:30.000000000 -0400
@@ -0,0 +1,54 @@
+/* Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _SYS_EVENTFD_H
+#define _SYS_EVENTFD_H 1
+
+#include <stdint.h>
+
+
+/* Type for event counter. */
+typedef uint64_t eventfd_t;
+
+/* Flags for signalfd. */
+enum
+ {
+ EFD_SEMAPHORE = 1,
+#define EFD_SEMAPHORE EFD_SEMAPHORE
+ EFD_CLOEXEC = 010000000,
+#define EFD_CLOEXEC EFD_CLOEXEC
+ EFD_NONBLOCK = 00200004 /* HPUX has separate NDELAY & NONBLOCK */
+#define EFD_NONBLOCK EFD_NONBLOCK
+ };
+
+
+__BEGIN_DECLS
+
+/* Return file descriptor for generic event channel. Set initial
+ value to COUNT. */
+extern int eventfd (int __count, int __flags) __THROW;
+
+/* Read event counter and possibly wait for events. */
+extern int eventfd_read (int __fd, eventfd_t *__value);
+
+/* Increment event counter. */
+extern int eventfd_write (int __fd, eventfd_t __value);
+
+__END_DECLS
+
+#endif /* sys/eventfd.h */
Index: eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/sys/inotify.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/sys/inotify.h 2011-10-30 11:44:30.000000000 -0400
@@ -0,0 +1,105 @@
+/* Copyright (C) 2005, 2006, 2008, 2009 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _SYS_INOTIFY_H
+#define _SYS_INOTIFY_H 1
+
+#include <stdint.h>
+
+
+/* Flags for the parameter of inotify_init1. */
+enum
+ {
+ IN_CLOEXEC = 010000000,
+#define IN_CLOEXEC IN_CLOEXEC
+ IN_NONBLOCK = 000200004 /* HPUX has separate NDELAY & NONBLOCK */
+#define IN_NONBLOCK IN_NONBLOCK
+ };
+
+
+/* Structure describing an inotify event. */
+struct inotify_event
+{
+ int wd; /* Watch descriptor. */
+ uint32_t mask; /* Watch mask. */
+ uint32_t cookie; /* Cookie to synchronize two events. */
+ uint32_t len; /* Length (including NULs) of name. */
+ char name __flexarr; /* Name. */
+};
+
+
+/* Supported events suitable for MASK parameter of INOTIFY_ADD_WATCH. */
+#define IN_ACCESS 0x00000001 /* File was accessed. */
+#define IN_MODIFY 0x00000002 /* File was modified. */
+#define IN_ATTRIB 0x00000004 /* Metadata changed. */
+#define IN_CLOSE_WRITE 0x00000008 /* Writtable file was closed. */
+#define IN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed. */
+#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) /* Close. */
+#define IN_OPEN 0x00000020 /* File was opened. */
+#define IN_MOVED_FROM 0x00000040 /* File was moved from X. */
+#define IN_MOVED_TO 0x00000080 /* File was moved to Y. */
+#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) /* Moves. */
+#define IN_CREATE 0x00000100 /* Subfile was created. */
+#define IN_DELETE 0x00000200 /* Subfile was deleted. */
+#define IN_DELETE_SELF 0x00000400 /* Self was deleted. */
+#define IN_MOVE_SELF 0x00000800 /* Self was moved. */
+
+/* Events sent by the kernel. */
+#define IN_UNMOUNT 0x00002000 /* Backing fs was unmounted. */
+#define IN_Q_OVERFLOW 0x00004000 /* Event queued overflowed. */
+#define IN_IGNORED 0x00008000 /* File was ignored. */
+
+/* Helper events. */
+#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) /* Close. */
+#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) /* Moves. */
+
+/* Special flags. */
+#define IN_ONLYDIR 0x01000000 /* Only watch the path if it is a
+ directory. */
+#define IN_DONT_FOLLOW 0x02000000 /* Do not follow a sym link. */
+#define IN_MASK_ADD 0x20000000 /* Add to the mask of an already
+ existing watch. */
+#define IN_ISDIR 0x40000000 /* Event occurred against dir. */
+#define IN_ONESHOT 0x80000000 /* Only send event once. */
+
+/* All events which a program can wait on. */
+#define IN_ALL_EVENTS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE \
+ | IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM \
+ | IN_MOVED_TO | IN_CREATE | IN_DELETE \
+ | IN_DELETE_SELF | IN_MOVE_SELF)
+
+
+__BEGIN_DECLS
+
+/* Create and initialize inotify instance. */
+extern int inotify_init (void) __THROW;
+
+/* Create and initialize inotify instance. */
+extern int inotify_init1 (int __flags) __THROW;
+
+/* Add watch of object NAME to inotify instance FD. Notify about
+ events specified by MASK. */
+extern int inotify_add_watch (int __fd, const char *__name, uint32_t __mask)
+ __THROW;
+
+/* Remove the watch specified by WD from the inotify instance FD. */
+extern int inotify_rm_watch (int __fd, int __wd) __THROW;
+
+__END_DECLS
+
+#endif /* sys/inotify.h */
Index: eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/sys/signalfd.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/sys/signalfd.h 2011-10-30 11:44:30.000000000 -0400
@@ -0,0 +1,66 @@
+/* Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _SYS_SIGNALFD_H
+#define _SYS_SIGNALFD_H 1
+
+#define __need_sigset_t
+#include <signal.h>
+#include <stdint.h>
+
+
+struct signalfd_siginfo
+{
+ uint32_t ssi_signo;
+ int32_t ssi_errno;
+ int32_t ssi_code;
+ uint32_t ssi_pid;
+ uint32_t ssi_uid;
+ int32_t ssi_fd;
+ uint32_t ssi_tid;
+ uint32_t ssi_band;
+ uint32_t ssi_overrun;
+ uint32_t ssi_trapno;
+ int32_t ssi_status;
+ int32_t ssi_int;
+ uint64_t ssi_ptr;
+ uint64_t ssi_utime;
+ uint64_t ssi_stime;
+ uint64_t ssi_addr;
+ uint8_t __pad[48];
+};
+
+/* Flags for signalfd. */
+enum
+ {
+ SFD_CLOEXEC = 010000000,
+#define SFD_CLOEXEC SFD_CLOEXEC
+ SFD_NONBLOCK = 00200004 /* HPUX has separate NDELAY & NONBLOCK */
+#define SFD_NONBLOCK SFD_NONBLOCK
+ };
+
+__BEGIN_DECLS
+
+/* Request notification for delivery of signals in MASK to be
+ performed using descriptor FD.*/
+extern int signalfd (int __fd, const sigset_t *__mask, int __flags)
+ __THROW __nonnull ((2));
+
+__END_DECLS
+
+#endif /* sys/signalfd.h */
Index: eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/sys/timerfd.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ eglibc-2.13/ports/sysdeps/unix/sysv/linux/hppa/sys/timerfd.h 2011-10-30 11:44:30.000000000 -0400
@@ -0,0 +1,60 @@
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _SYS_TIMERFD_H
+#define _SYS_TIMERFD_H 1
+
+#include <time.h>
+
+
+/* Bits to be set in the FLAGS parameter of `timerfd_create'. */
+enum
+ {
+ TFD_CLOEXEC = 010000000,
+#define TFD_CLOEXEC TFD_CLOEXEC
+ TFD_NONBLOCK = 000200004 /* HPUX has separate NDELAY & NONBLOCK */
+#define TFD_NONBLOCK TFD_NONBLOCK
+ };
+
+
+/* Bits to be set in the FLAGS parameter of `timerfd_settime'. */
+enum
+ {
+ TFD_TIMER_ABSTIME = 1 << 0
+#define TFD_TIMER_ABSTIME TFD_TIMER_ABSTIME
+ };
+
+
+__BEGIN_DECLS
+
+/* Return file descriptor for new interval timer source. */
+extern int timerfd_create (clockid_t __clock_id, int __flags) __THROW;
+
+/* Set next expiration time of interval timer source UFD to UTMR. If
+ FLAGS has the TFD_TIMER_ABSTIME flag set the timeout value is
+ absolute. Optionally return the old expiration time in OTMR. */
+extern int timerfd_settime (int __ufd, int __flags,
+ __const struct itimerspec *__utmr,
+ struct itimerspec *__otmr) __THROW;
+
+/* Return the next expiration time of UFD. */
+extern int timerfd_gettime (int __ufd, struct itimerspec *__otmr) __THROW;
+
+__END_DECLS
+
+#endif /* sys/timerfd.h */
[-- Attachment #6: elf32-hppa.c.d.1 --]
[-- Type: application/octet-stream, Size: 4836 bytes --]
Index: elf32-hppa.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-hppa.c,v
retrieving revision 1.182
diff -u -3 -p -r1.182 elf32-hppa.c
--- elf32-hppa.c 6 Nov 2011 20:25:17 -0000 1.182
+++ elf32-hppa.c 8 Dec 2011 11:47:53 -0000
@@ -3349,10 +3349,16 @@ final_link_relocate (asection *input_sec
switch (r_type)
{
case R_PARISC_DLTIND21L:
+ case R_PARISC_TLS_GD21L:
+ case R_PARISC_TLS_LDM21L:
+ case R_PARISC_TLS_IE21L:
r_type = R_PARISC_DPREL21L;
break;
case R_PARISC_DLTIND14R:
+ case R_PARISC_TLS_GD14R:
+ case R_PARISC_TLS_LDM14R:
+ case R_PARISC_TLS_IE14R:
r_type = R_PARISC_DPREL14R;
break;
@@ -3418,53 +3424,48 @@ final_link_relocate (asection *input_sec
case R_PARISC_DPREL21L:
case R_PARISC_DPREL14R:
case R_PARISC_DPREL14F:
- case R_PARISC_TLS_GD21L:
- case R_PARISC_TLS_LDM21L:
- case R_PARISC_TLS_IE21L:
/* Convert instructions that use the linkage table pointer (r19) to
instructions that use the global data pointer (dp). This is the
most efficient way of using PIC code in an incomplete executable,
but the user must follow the standard runtime conventions for
accessing data for this to work. */
- if (orig_r_type == R_PARISC_DLTIND21L
- || (!info->shared
- && (r_type == R_PARISC_TLS_GD21L
- || r_type == R_PARISC_TLS_LDM21L
- || r_type == R_PARISC_TLS_IE21L)))
- {
- /* Convert addil instructions if the original reloc was a
- DLTIND21L. GCC sometimes uses a register other than r19 for
- the operation, so we must convert any addil instruction
- that uses this relocation. */
- if ((insn & 0xfc000000) == ((int) OP_ADDIL << 26))
- insn = ADDIL_DP;
- else
- /* We must have a ldil instruction. It's too hard to find
- and convert the associated add instruction, so issue an
- error. */
- (*_bfd_error_handler)
- (_("%B(%A+0x%lx): %s fixup for insn 0x%x is not supported in a non-shared link"),
- input_bfd,
- input_section,
- (long) offset,
- howto->name,
- insn);
- }
- else if (orig_r_type == R_PARISC_DLTIND14F)
- {
- /* This must be a format 1 load/store. Change the base
- register to dp. */
- insn = (insn & 0xfc1ffff) | (27 << 21);
- }
-
- /* For all the DP relative relocations, we need to examine the symbol's
- section. If it has no section or if it's a code section, then
- "data pointer relative" makes no sense. In that case we don't
- adjust the "value", and for 21 bit addil instructions, we change the
- source addend register from %dp to %r0. This situation commonly
- arises for undefined weak symbols and when a variable's "constness"
- is declared differently from the way the variable is defined. For
- instance: "extern int foo" with foo defined as "const int foo". */
+ if (orig_r_type != r_type)
+ {
+ if (r_type == R_PARISC_DPREL21L)
+ {
+ /* GCC sometimes uses a register other than r19 for the
+ operation, so we must convert any addil instruction
+ that uses this relocation. */
+ if ((insn & 0xfc000000) == ((int) OP_ADDIL << 26))
+ insn = ADDIL_DP;
+ else
+ /* We must have a ldil instruction. It's too hard to find
+ and convert the associated add instruction, so issue an
+ error. */
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): %s fixup for insn 0x%x is not supported in a non-shared link"),
+ input_bfd,
+ input_section,
+ (long) offset,
+ howto->name,
+ insn);
+ }
+ else if (r_type == R_PARISC_DPREL14F)
+ {
+ /* This must be a format 1 load/store. Change the base
+ register to dp. */
+ insn = (insn & 0xfc1ffff) | (27 << 21);
+ }
+ }
+
+ /* For all the DP relative relocations, we need to examine the symbol's
+ section. If it has no section or if it's a code section, then
+ "data pointer relative" makes no sense. In that case we don't
+ adjust the "value", and for 21 bit addil instructions, we change the
+ source addend register from %dp to %r0. This situation commonly
+ arises for undefined weak symbols and when a variable's "constness"
+ is declared differently from the way the variable is defined. For
+ instance: "extern int foo" with foo defined as "const int foo". */
if (sym_sec == NULL || (sym_sec->flags & SEC_CODE) != 0)
{
if ((insn & ((0x3f << 26) | (0x1f << 21)))
@@ -3481,6 +3482,9 @@ final_link_relocate (asection *input_sec
case R_PARISC_DLTIND21L:
case R_PARISC_DLTIND14R:
case R_PARISC_DLTIND14F:
+ case R_PARISC_TLS_GD21L:
+ case R_PARISC_TLS_LDM21L:
+ case R_PARISC_TLS_IE21L:
case R_PARISC_TLS_GD14R:
case R_PARISC_TLS_LDM14R:
case R_PARISC_TLS_IE14R:
[-- Attachment #7: hidden.d.2 --]
[-- Type: application/octet-stream, Size: 1230 bytes --]
Index: elf32-hppa.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-hppa.c,v
retrieving revision 1.181
diff -u -3 -p -r1.181 elf32-hppa.c
--- elf32-hppa.c 26 Oct 2011 09:47:58 -0000 1.181
+++ elf32-hppa.c 6 Nov 2011 18:21:46 -0000
@@ -1789,10 +1789,12 @@ elf32_hppa_hide_symbol (struct bfd_link_
}
}
- if (! hppa_elf_hash_entry (eh)->plabel)
+ /* STT_GNU_IFUNC symbol must go through PLT. */
+ if (! hppa_elf_hash_entry (eh)->plabel
+ && eh->type != STT_GNU_IFUNC)
{
eh->needs_plt = 0;
- eh->plt = elf_hash_table (info)->init_plt_refcount;
+ eh->plt = elf_hash_table (info)->init_plt_offset;
}
}
@@ -1814,6 +1816,13 @@ elf32_hppa_adjust_dynamic_symbol (struct
if (eh->type == STT_FUNC
|| eh->needs_plt)
{
+ /* If the symbol is used by a plabel, we must allocate a PLT slot.
+ The refcounts are not reliable when it has been hidden since
+ hide_symbol can be called before the plabel flag is set. */
+ if (hppa_elf_hash_entry (eh)->plabel
+ && eh->plt.refcount <= 0)
+ eh->plt.refcount = 1;
+
if (eh->plt.refcount <= 0
|| (eh->def_regular
&& eh->root.type != bfd_link_hash_defweak
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Happy New Year PARISC (take 2)
2012-02-28 22:56 ` Domenico Andreoli
2012-02-29 1:28 ` John David Anglin
@ 2012-03-01 0:48 ` John David Anglin
1 sibling, 0 replies; 18+ messages in thread
From: John David Anglin @ 2012-03-01 0:48 UTC (permalink / raw)
To: Domenico Andreoli
Cc: James Bottomley, Carlos O'Donell, Grant Grundler,
linux-parisc List
On 28-Feb-12, at 5:56 PM, Domenico Andreoli wrote:
> I applied this patch to v3.3-rc5 and then tried to build eglibc
> 2.13-27,
> unsuccessfully. Do you have any patch for it?
I should have remembered. You have to remove/move the expected
results file
(expected-results-hppa-linux-gnu-libc) out of the way -- it hasn't
been updated.
Otherwise, the build will fail in the testsuite.
Dave
--
John David Anglin dave.anglin@bell.net
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2012-03-01 0:48 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-01-01 0:02 Happy New Year PARISC John David Anglin
2012-01-02 6:23 ` Grant Grundler
2012-01-02 15:12 ` John David Anglin
2012-01-02 23:12 ` John David Anglin
2012-01-03 11:50 ` Carlos O'Donell
2012-01-03 15:13 ` John David Anglin
2012-01-03 15:32 ` James Bottomley
2012-01-03 15:32 ` James Bottomley
2012-01-03 16:26 ` John David Anglin
2012-01-03 16:42 ` John David Anglin
2012-01-03 16:42 ` James Bottomley
2012-01-03 18:39 ` John David Anglin
2012-01-29 21:45 ` Happy New Year PARISC (take 2) John David Anglin
[not found] ` <CA+DQjFiTwKC76Hn-x-s2C9Nc_qkqrRFXv3ji22KGtgMzGOfx0Q@mail.gmail.com>
2012-01-30 1:06 ` Thibaut VARENE
2012-02-28 15:28 ` John David Anglin
2012-02-28 22:56 ` Domenico Andreoli
2012-02-29 1:28 ` John David Anglin
2012-03-01 0:48 ` John David Anglin
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.