Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a3f99858 authored by David S. Miller's avatar David S. Miller
Browse files

[SPARC64]: Move kernel unaligned trap handlers into assembler file.



GCC 4.x really dislikes the games we are playing in
unaligned.c, and the cleanest way to fix this is to
move things into assembler.

Noted by Al Viro.

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8d529014
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+3 −0
Original line number Diff line number Diff line
@@ -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();
+153 −0
Original line number Diff line number Diff line
/* 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
+59 −202
Original line number Diff line number Diff line
@@ -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)
{
	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);
				     decode_asi(insn, regs));
			break;
#if 0 /* unsupported */
		case both:
			do_atomic(fetch_reg_addr(((insn>>25)&0x1f), regs),
				  (unsigned long *) addr,
				  kernel_unaligned_trap_fault);
			break;
#endif

		default:
			panic("Impossible kernel unaligned trap.");
			/* Not reached... */
+5 −0
Original line number Diff line number Diff line
@@ -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 */