Commit b8d9598c authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6

parents 01c314a0 83c4e437
......@@ -98,8 +98,9 @@ extern void ___rw_write_enter(void);
* The module references will be fixed up by module_frob_arch_sections.
*/
#define DOT_ALIAS2(__ret, __x, __arg1, __arg2) \
extern __ret __x(__arg1, __arg2) \
__attribute__((weak, alias("." # __x)));
extern __ret __x(__arg1, __arg2); \
asm(".weak " #__x);\
asm(#__x "=." #__x);
DOT_ALIAS2(int, div, int, int)
DOT_ALIAS2(int, mul, int, int)
......
......@@ -8,7 +8,7 @@ EXTRA_CFLAGS := -Werror
extra-y := head.o init_task.o vmlinux.lds
obj-y := process.o setup.o cpu.o idprom.o \
traps.o devices.o auxio.o \
traps.o devices.o auxio.o una_asm.o \
irq.o ptrace.o time.o sys_sparc.o signal.o \
unaligned.o central.o pci.o starfire.o semaphore.o \
power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o
......
......@@ -2127,6 +2127,9 @@ void __init trap_init(void)
TI_PRE_COUNT != offsetof(struct thread_info, preempt_count) ||
TI_NEW_CHILD != offsetof(struct thread_info, new_child) ||
TI_SYS_NOERROR != offsetof(struct thread_info, syscall_noerror) ||
TI_RESTART_BLOCK != offsetof(struct thread_info, restart_block) ||
TI_KUNA_REGS != offsetof(struct thread_info, kern_una_regs) ||
TI_KUNA_INSN != offsetof(struct thread_info, kern_una_insn) ||
TI_FPREGS != offsetof(struct thread_info, fpregs) ||
(TI_FPREGS & (64 - 1)))
thread_info_offsets_are_bolixed_dave();
......
/* una_asm.S: Kernel unaligned trap assembler helpers.
*
* Copyright (C) 1996,2005 David S. Miller (davem@davemloft.net)
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
.text
kernel_unaligned_trap_fault:
call kernel_mna_trap_fault
nop
retl
nop
.size kern_unaligned_trap_fault, .-kern_unaligned_trap_fault
.globl __do_int_store
__do_int_store:
rd %asi, %o4
wr %o3, 0, %asi
ldx [%o2], %g3
cmp %o1, 2
be,pn %icc, 2f
cmp %o1, 4
be,pt %icc, 1f
srlx %g3, 24, %g2
srlx %g3, 56, %g1
srlx %g3, 48, %g7
4: stba %g1, [%o0] %asi
srlx %g3, 40, %g1
5: stba %g7, [%o0 + 1] %asi
srlx %g3, 32, %g7
6: stba %g1, [%o0 + 2] %asi
7: stba %g7, [%o0 + 3] %asi
srlx %g3, 16, %g1
8: stba %g2, [%o0 + 4] %asi
srlx %g3, 8, %g7
9: stba %g1, [%o0 + 5] %asi
10: stba %g7, [%o0 + 6] %asi
ba,pt %xcc, 0f
11: stba %g3, [%o0 + 7] %asi
1: srl %g3, 16, %g7
12: stba %g2, [%o0] %asi
srl %g3, 8, %g2
13: stba %g7, [%o0 + 1] %asi
14: stba %g2, [%o0 + 2] %asi
ba,pt %xcc, 0f
15: stba %g3, [%o0 + 3] %asi
2: srl %g3, 8, %g2
16: stba %g2, [%o0] %asi
17: stba %g3, [%o0 + 1] %asi
0:
wr %o4, 0x0, %asi
retl
nop
.size __do_int_store, .-__do_int_store
.section __ex_table
.word 4b, kernel_unaligned_trap_fault
.word 5b, kernel_unaligned_trap_fault
.word 6b, kernel_unaligned_trap_fault
.word 7b, kernel_unaligned_trap_fault
.word 8b, kernel_unaligned_trap_fault
.word 9b, kernel_unaligned_trap_fault
.word 10b, kernel_unaligned_trap_fault
.word 11b, kernel_unaligned_trap_fault
.word 12b, kernel_unaligned_trap_fault
.word 13b, kernel_unaligned_trap_fault
.word 14b, kernel_unaligned_trap_fault
.word 15b, kernel_unaligned_trap_fault
.word 16b, kernel_unaligned_trap_fault
.word 17b, kernel_unaligned_trap_fault
.previous
.globl do_int_load
do_int_load:
rd %asi, %o5
wr %o4, 0, %asi
cmp %o1, 8
bge,pn %icc, 9f
cmp %o1, 4
be,pt %icc, 6f
4: lduba [%o2] %asi, %g2
5: lduba [%o2 + 1] %asi, %g3
sll %g2, 8, %g2
brz,pt %o3, 3f
add %g2, %g3, %g2
sllx %g2, 48, %g2
srax %g2, 48, %g2
3: ba,pt %xcc, 0f
stx %g2, [%o0]
6: lduba [%o2 + 1] %asi, %g3
sll %g2, 24, %g2
7: lduba [%o2 + 2] %asi, %g7
sll %g3, 16, %g3
8: lduba [%o2 + 3] %asi, %g1
sll %g7, 8, %g7
or %g2, %g3, %g2
or %g7, %g1, %g7
or %g2, %g7, %g2
brnz,a,pt %o3, 3f
sra %g2, 0, %g2
3: ba,pt %xcc, 0f
stx %g2, [%o0]
9: lduba [%o2] %asi, %g2
10: lduba [%o2 + 1] %asi, %g3
sllx %g2, 56, %g2
11: lduba [%o2 + 2] %asi, %g7
sllx %g3, 48, %g3
12: lduba [%o2 + 3] %asi, %g1
sllx %g7, 40, %g7
sllx %g1, 32, %g1
or %g2, %g3, %g2
or %g7, %g1, %g7
13: lduba [%o2 + 4] %asi, %g3
or %g2, %g7, %g7
14: lduba [%o2 + 5] %asi, %g1
sllx %g3, 24, %g3
15: lduba [%o2 + 6] %asi, %g2
sllx %g1, 16, %g1
or %g7, %g3, %g7
16: lduba [%o2 + 7] %asi, %g3
sllx %g2, 8, %g2
or %g7, %g1, %g7
or %g2, %g3, %g2
or %g7, %g2, %g7
cmp %o1, 8
be,a,pt %icc, 0f
stx %g7, [%o0]
srlx %g7, 32, %g2
sra %g7, 0, %g7
stx %g2, [%o0]
stx %g7, [%o0 + 8]
0:
wr %o5, 0x0, %asi
retl
nop
.size __do_int_load, .-__do_int_load
.section __ex_table
.word 4b, kernel_unaligned_trap_fault
.word 5b, kernel_unaligned_trap_fault
.word 6b, kernel_unaligned_trap_fault
.word 7b, kernel_unaligned_trap_fault
.word 8b, kernel_unaligned_trap_fault
.word 9b, kernel_unaligned_trap_fault
.word 10b, kernel_unaligned_trap_fault
.word 11b, kernel_unaligned_trap_fault
.word 12b, kernel_unaligned_trap_fault
.word 13b, kernel_unaligned_trap_fault
.word 14b, kernel_unaligned_trap_fault
.word 15b, kernel_unaligned_trap_fault
.word 16b, kernel_unaligned_trap_fault
.previous
......@@ -180,169 +180,28 @@ static void __attribute_used__ unaligned_panic(char *str, struct pt_regs *regs)
die_if_kernel(str, regs);
}
#define do_integer_load(dest_reg, size, saddr, is_signed, asi, errh) ({ \
__asm__ __volatile__ ( \
"wr %4, 0, %%asi\n\t" \
"cmp %1, 8\n\t" \
"bge,pn %%icc, 9f\n\t" \
" cmp %1, 4\n\t" \
"be,pt %%icc, 6f\n" \
"4:\t" " lduba [%2] %%asi, %%l1\n" \
"5:\t" "lduba [%2 + 1] %%asi, %%l2\n\t" \
"sll %%l1, 8, %%l1\n\t" \
"brz,pt %3, 3f\n\t" \
" add %%l1, %%l2, %%l1\n\t" \
"sllx %%l1, 48, %%l1\n\t" \
"srax %%l1, 48, %%l1\n" \
"3:\t" "ba,pt %%xcc, 0f\n\t" \
" stx %%l1, [%0]\n" \
"6:\t" "lduba [%2 + 1] %%asi, %%l2\n\t" \
"sll %%l1, 24, %%l1\n" \
"7:\t" "lduba [%2 + 2] %%asi, %%g7\n\t" \
"sll %%l2, 16, %%l2\n" \
"8:\t" "lduba [%2 + 3] %%asi, %%g1\n\t" \
"sll %%g7, 8, %%g7\n\t" \
"or %%l1, %%l2, %%l1\n\t" \
"or %%g7, %%g1, %%g7\n\t" \
"or %%l1, %%g7, %%l1\n\t" \
"brnz,a,pt %3, 3f\n\t" \
" sra %%l1, 0, %%l1\n" \
"3:\t" "ba,pt %%xcc, 0f\n\t" \
" stx %%l1, [%0]\n" \
"9:\t" "lduba [%2] %%asi, %%l1\n" \
"10:\t" "lduba [%2 + 1] %%asi, %%l2\n\t" \
"sllx %%l1, 56, %%l1\n" \
"11:\t" "lduba [%2 + 2] %%asi, %%g7\n\t" \
"sllx %%l2, 48, %%l2\n" \
"12:\t" "lduba [%2 + 3] %%asi, %%g1\n\t" \
"sllx %%g7, 40, %%g7\n\t" \
"sllx %%g1, 32, %%g1\n\t" \
"or %%l1, %%l2, %%l1\n\t" \
"or %%g7, %%g1, %%g7\n" \
"13:\t" "lduba [%2 + 4] %%asi, %%l2\n\t" \
"or %%l1, %%g7, %%g7\n" \
"14:\t" "lduba [%2 + 5] %%asi, %%g1\n\t" \
"sllx %%l2, 24, %%l2\n" \
"15:\t" "lduba [%2 + 6] %%asi, %%l1\n\t" \
"sllx %%g1, 16, %%g1\n\t" \
"or %%g7, %%l2, %%g7\n" \
"16:\t" "lduba [%2 + 7] %%asi, %%l2\n\t" \
"sllx %%l1, 8, %%l1\n\t" \
"or %%g7, %%g1, %%g7\n\t" \
"or %%l1, %%l2, %%l1\n\t" \
"or %%g7, %%l1, %%g7\n\t" \
"cmp %1, 8\n\t" \
"be,a,pt %%icc, 0f\n\t" \
" stx %%g7, [%0]\n\t" \
"srlx %%g7, 32, %%l1\n\t" \
"sra %%g7, 0, %%g7\n\t" \
"stx %%l1, [%0]\n\t" \
"stx %%g7, [%0 + 8]\n" \
"0:\n\t" \
"wr %%g0, %5, %%asi\n\n\t" \
".section __ex_table\n\t" \
".word 4b, " #errh "\n\t" \
".word 5b, " #errh "\n\t" \
".word 6b, " #errh "\n\t" \
".word 7b, " #errh "\n\t" \
".word 8b, " #errh "\n\t" \
".word 9b, " #errh "\n\t" \
".word 10b, " #errh "\n\t" \
".word 11b, " #errh "\n\t" \
".word 12b, " #errh "\n\t" \
".word 13b, " #errh "\n\t" \
".word 14b, " #errh "\n\t" \
".word 15b, " #errh "\n\t" \
".word 16b, " #errh "\n\n\t" \
".previous\n\t" \
: : "r" (dest_reg), "r" (size), "r" (saddr), "r" (is_signed), \
"r" (asi), "i" (ASI_AIUS) \
: "l1", "l2", "g7", "g1", "cc"); \
})
#define store_common(dst_addr, size, src_val, asi, errh) ({ \
__asm__ __volatile__ ( \
"wr %3, 0, %%asi\n\t" \
"ldx [%2], %%l1\n" \
"cmp %1, 2\n\t" \
"be,pn %%icc, 2f\n\t" \
" cmp %1, 4\n\t" \
"be,pt %%icc, 1f\n\t" \
" srlx %%l1, 24, %%l2\n\t" \
"srlx %%l1, 56, %%g1\n\t" \
"srlx %%l1, 48, %%g7\n" \
"4:\t" "stba %%g1, [%0] %%asi\n\t" \
"srlx %%l1, 40, %%g1\n" \
"5:\t" "stba %%g7, [%0 + 1] %%asi\n\t" \
"srlx %%l1, 32, %%g7\n" \
"6:\t" "stba %%g1, [%0 + 2] %%asi\n" \
"7:\t" "stba %%g7, [%0 + 3] %%asi\n\t" \
"srlx %%l1, 16, %%g1\n" \
"8:\t" "stba %%l2, [%0 + 4] %%asi\n\t" \
"srlx %%l1, 8, %%g7\n" \
"9:\t" "stba %%g1, [%0 + 5] %%asi\n" \
"10:\t" "stba %%g7, [%0 + 6] %%asi\n\t" \
"ba,pt %%xcc, 0f\n" \
"11:\t" " stba %%l1, [%0 + 7] %%asi\n" \
"1:\t" "srl %%l1, 16, %%g7\n" \
"12:\t" "stba %%l2, [%0] %%asi\n\t" \
"srl %%l1, 8, %%l2\n" \
"13:\t" "stba %%g7, [%0 + 1] %%asi\n" \
"14:\t" "stba %%l2, [%0 + 2] %%asi\n\t" \
"ba,pt %%xcc, 0f\n" \
"15:\t" " stba %%l1, [%0 + 3] %%asi\n" \
"2:\t" "srl %%l1, 8, %%l2\n" \
"16:\t" "stba %%l2, [%0] %%asi\n" \
"17:\t" "stba %%l1, [%0 + 1] %%asi\n" \
"0:\n\t" \
"wr %%g0, %4, %%asi\n\n\t" \
".section __ex_table\n\t" \
".word 4b, " #errh "\n\t" \
".word 5b, " #errh "\n\t" \
".word 6b, " #errh "\n\t" \
".word 7b, " #errh "\n\t" \
".word 8b, " #errh "\n\t" \
".word 9b, " #errh "\n\t" \
".word 10b, " #errh "\n\t" \
".word 11b, " #errh "\n\t" \
".word 12b, " #errh "\n\t" \
".word 13b, " #errh "\n\t" \
".word 14b, " #errh "\n\t" \
".word 15b, " #errh "\n\t" \
".word 16b, " #errh "\n\t" \
".word 17b, " #errh "\n\n\t" \
".previous\n\t" \
: : "r" (dst_addr), "r" (size), "r" (src_val), "r" (asi), "i" (ASI_AIUS)\
: "l1", "l2", "g7", "g1", "cc"); \
})
#define do_integer_store(reg_num, size, dst_addr, regs, asi, errh) ({ \
unsigned long zero = 0; \
unsigned long *src_val = &zero; \
\
if (size == 16) { \
size = 8; \
zero = (((long)(reg_num ? \
(unsigned)fetch_reg(reg_num, regs) : 0)) << 32) | \
(unsigned)fetch_reg(reg_num + 1, regs); \
} else if (reg_num) src_val = fetch_reg_addr(reg_num, regs); \
store_common(dst_addr, size, src_val, asi, errh); \
})
extern void smp_capture(void);
extern void smp_release(void);
#define do_atomic(srcdest_reg, mem, errh) ({ \
unsigned long flags, tmp; \
\
smp_capture(); \
local_irq_save(flags); \
tmp = *srcdest_reg; \
do_integer_load(srcdest_reg, 4, mem, 0, errh); \
store_common(mem, 4, &tmp, errh); \
local_irq_restore(flags); \
smp_release(); \
})
extern void do_int_load(unsigned long *dest_reg, int size,
unsigned long *saddr, int is_signed, int asi);
extern void __do_int_store(unsigned long *dst_addr, int size,
unsigned long *src_val, int asi);
static inline void do_int_store(int reg_num, int size, unsigned long *dst_addr,
struct pt_regs *regs, int asi)
{
unsigned long zero = 0;
unsigned long *src_val = &zero;
if (size == 16) {
size = 8;
zero = (((long)(reg_num ?
(unsigned)fetch_reg(reg_num, regs) : 0)) << 32) |
(unsigned)fetch_reg(reg_num + 1, regs);
} else if (reg_num) {
src_val = fetch_reg_addr(reg_num, regs);
}
__do_int_store(dst_addr, size, src_val, asi);
}
static inline void advance(struct pt_regs *regs)
{
......@@ -364,24 +223,29 @@ static inline int ok_for_kernel(unsigned int insn)
return !floating_point_load_or_store_p(insn);
}
void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn) __asm__ ("kernel_mna_trap_fault");
void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
void kernel_mna_trap_fault(void)
{
unsigned long g2 = regs->u_regs [UREG_G2];
struct pt_regs *regs = current_thread_info()->kern_una_regs;
unsigned int insn = current_thread_info()->kern_una_insn;
unsigned long g2 = regs->u_regs[UREG_G2];
unsigned long fixup = search_extables_range(regs->tpc, &g2);
if (!fixup) {
unsigned long address = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f));
unsigned long address;
address = compute_effective_address(regs, insn,
((insn >> 25) & 0x1f));
if (address < PAGE_SIZE) {
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference in mna handler");
printk(KERN_ALERT "Unable to handle kernel NULL "
"pointer dereference in mna handler");
} else
printk(KERN_ALERT "Unable to handle kernel paging request in mna handler");
printk(KERN_ALERT "Unable to handle kernel paging "
"request in mna handler");
printk(KERN_ALERT " at virtual address %016lx\n",address);
printk(KERN_ALERT "current->{mm,active_mm}->context = %016lx\n",
printk(KERN_ALERT "current->{active_,}mm->context = %016lx\n",
(current->mm ? CTX_HWBITS(current->mm->context) :
CTX_HWBITS(current->active_mm->context)));
printk(KERN_ALERT "current->{mm,active_mm}->pgd = %016lx\n",
printk(KERN_ALERT "current->{active_,}mm->pgd = %016lx\n",
(current->mm ? (unsigned long) current->mm->pgd :
(unsigned long) current->active_mm->pgd));
die_if_kernel("Oops", regs);
......@@ -400,48 +264,41 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u
enum direction dir = decode_direction(insn);
int size = decode_access_size(insn);
current_thread_info()->kern_una_regs = regs;
current_thread_info()->kern_una_insn = insn;
if (!ok_for_kernel(insn) || dir == both) {
printk("Unsupported unaligned load/store trap for kernel at <%016lx>.\n",
regs->tpc);
unaligned_panic("Kernel does fpu/atomic unaligned load/store.", regs);
__asm__ __volatile__ ("\n"
"kernel_unaligned_trap_fault:\n\t"
"mov %0, %%o0\n\t"
"call kernel_mna_trap_fault\n\t"
" mov %1, %%o1\n\t"
:
: "r" (regs), "r" (insn)
: "o0", "o1", "o2", "o3", "o4", "o5", "o7",
"g1", "g2", "g3", "g4", "g7", "cc");
printk("Unsupported unaligned load/store trap for kernel "
"at <%016lx>.\n", regs->tpc);
unaligned_panic("Kernel does fpu/atomic "
"unaligned load/store.", regs);
kernel_mna_trap_fault();
} else {
unsigned long addr = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f));
unsigned long addr;
addr = compute_effective_address(regs, insn,
((insn >> 25) & 0x1f));
#ifdef DEBUG_MNA
printk("KMNA: pc=%016lx [dir=%s addr=%016lx size=%d] retpc[%016lx]\n",
regs->tpc, dirstrings[dir], addr, size, regs->u_regs[UREG_RETPC]);
printk("KMNA: pc=%016lx [dir=%s addr=%016lx size=%d] "
"retpc[%016lx]\n",
regs->tpc, dirstrings[dir], addr, size,
regs->u_regs[UREG_RETPC]);
#endif
switch (dir) {
case load:
do_integer_load(fetch_reg_addr(((insn>>25)&0x1f), regs),
do_int_load(fetch_reg_addr(((insn>>25)&0x1f), regs),
size, (unsigned long *) addr,
decode_signedness(insn), decode_asi(insn, regs),
kernel_unaligned_trap_fault);
decode_signedness(insn),
decode_asi(insn, regs));
break;
case store:
do_integer_store(((insn>>25)&0x1f), size,
do_int_store(((insn>>25)&0x1f), size,
(unsigned long *) addr, regs,
decode_asi(insn, regs),
kernel_unaligned_trap_fault);
break;
#if 0 /* unsupported */
case both:
do_atomic(fetch_reg_addr(((insn>>25)&0x1f), regs),
(unsigned long *) addr,
kernel_unaligned_trap_fault);
decode_asi(insn, regs));
break;
#endif
default:
panic("Impossible kernel unaligned trap.");
/* Not reached... */
......
......@@ -68,6 +68,9 @@ struct thread_info {
struct restart_block restart_block;
struct pt_regs *kern_una_regs;
unsigned int kern_una_insn;
unsigned long fpregs[0] __attribute__ ((aligned(64)));
};
......@@ -103,6 +106,8 @@ struct thread_info {
#define TI_PCR 0x00000490
#define TI_CEE_STUFF 0x00000498
#define TI_RESTART_BLOCK 0x000004a0
#define TI_KUNA_REGS 0x000004c8
#define TI_KUNA_INSN 0x000004d0
#define TI_FPREGS 0x00000500
/* We embed this in the uppermost byte of thread_info->flags */
......
......@@ -359,11 +359,16 @@ handle_modversions(struct module *mod, struct elf_info *info,
/* ignore __this_module, it will be resolved shortly */
if (strcmp(symname, MODULE_SYMBOL_PREFIX "__this_module") == 0)
break;
#ifdef STT_REGISTER
/* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */
#if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER)
/* add compatibility with older glibc */
#ifndef STT_SPARC_REGISTER
#define STT_SPARC_REGISTER STT_REGISTER
#endif
if (info->hdr->e_machine == EM_SPARC ||
info->hdr->e_machine == EM_SPARCV9) {
/* Ignore register directives. */
if (ELF_ST_TYPE(sym->st_info) == STT_REGISTER)
if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER)
break;
}
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment