|  | /* unaligned.h: unaligned access handler | 
|  | * | 
|  | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 
|  | * Written by David Howells (dhowells@redhat.com) | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU General Public License | 
|  | * as published by the Free Software Foundation; either version | 
|  | * 2 of the License, or (at your option) any later version. | 
|  | */ | 
|  |  | 
|  | #ifndef _ASM_UNALIGNED_H | 
|  | #define _ASM_UNALIGNED_H | 
|  |  | 
|  |  | 
|  | /* | 
|  | * Unaligned accesses on uClinux can't be performed in a fault handler - the | 
|  | * CPU detects them as imprecise exceptions making this impossible. | 
|  | * | 
|  | * With the FR451, however, they are precise, and so we used to fix them up in | 
|  | * the memory access fault handler.  However, instruction bundling make this | 
|  | * impractical.  So, now we fall back to using memcpy. | 
|  | */ | 
|  | #ifdef CONFIG_MMU | 
|  |  | 
|  | /* | 
|  | * The asm statement in the macros below is a way to get GCC to copy a | 
|  | * value from one variable to another without having any clue it's | 
|  | * actually doing so, so that it won't have any idea that the values | 
|  | * in the two variables are related. | 
|  | */ | 
|  |  | 
|  | #define get_unaligned(ptr) ({				\ | 
|  | typeof((*(ptr))) __x;				\ | 
|  | void *__ptrcopy;				\ | 
|  | asm("" : "=r" (__ptrcopy) : "0" (ptr));		\ | 
|  | memcpy(&__x, __ptrcopy, sizeof(*(ptr)));	\ | 
|  | __x;						\ | 
|  | }) | 
|  |  | 
|  | #define put_unaligned(val, ptr) ({			\ | 
|  | typeof((*(ptr))) __x = (val);			\ | 
|  | void *__ptrcopy;				\ | 
|  | asm("" : "=r" (__ptrcopy) : "0" (ptr));		\ | 
|  | memcpy(__ptrcopy, &__x, sizeof(*(ptr)));	\ | 
|  | }) | 
|  |  | 
|  | extern int handle_misalignment(unsigned long esr0, unsigned long ear0, unsigned long epcr0); | 
|  |  | 
|  | #else | 
|  |  | 
|  | #define get_unaligned(ptr)							\ | 
|  | ({										\ | 
|  | typeof(*(ptr)) x;							\ | 
|  | const char *__p = (const char *) (ptr);					\ | 
|  | \ | 
|  | switch (sizeof(x)) {							\ | 
|  | case 1:									\ | 
|  | x = *(ptr);							\ | 
|  | break;								\ | 
|  | case 2:									\ | 
|  | {									\ | 
|  | uint8_t a;							\ | 
|  | asm("	ldub%I2		%M2,%0		\n"			\ | 
|  | "	ldub%I3.p	%M3,%1		\n"			\ | 
|  | "	slli		%0,#8,%0	\n"			\ | 
|  | "	or		%0,%1,%0	\n"			\ | 
|  | : "=&r"(x), "=&r"(a)					\ | 
|  | : "m"(__p[0]),  "m"(__p[1])					\ | 
|  | );								\ | 
|  | break;								\ | 
|  | }									\ | 
|  | \ | 
|  | case 4:									\ | 
|  | {									\ | 
|  | uint8_t a;							\ | 
|  | asm("	ldub%I2		%M2,%0		\n"			\ | 
|  | "	ldub%I3.p	%M3,%1		\n"			\ | 
|  | "	slli		%0,#8,%0	\n"			\ | 
|  | "	or		%0,%1,%0	\n"			\ | 
|  | "	ldub%I4.p	%M4,%1		\n"			\ | 
|  | "	slli		%0,#8,%0	\n"			\ | 
|  | "	or		%0,%1,%0	\n"			\ | 
|  | "	ldub%I5.p	%M5,%1		\n"			\ | 
|  | "	slli		%0,#8,%0	\n"			\ | 
|  | "	or		%0,%1,%0	\n"			\ | 
|  | : "=&r"(x), "=&r"(a)					\ | 
|  | : "m"(__p[0]),  "m"(__p[1]), "m"(__p[2]), "m"(__p[3])	\ | 
|  | );								\ | 
|  | break;								\ | 
|  | }									\ | 
|  | \ | 
|  | case 8:									\ | 
|  | {									\ | 
|  | union { uint64_t x; u32 y[2]; } z;				\ | 
|  | uint8_t a;							\ | 
|  | asm("	ldub%I3		%M3,%0		\n"			\ | 
|  | "	ldub%I4.p	%M4,%2		\n"			\ | 
|  | "	slli		%0,#8,%0	\n"			\ | 
|  | "	or		%0,%2,%0	\n"			\ | 
|  | "	ldub%I5.p	%M5,%2		\n"			\ | 
|  | "	slli		%0,#8,%0	\n"			\ | 
|  | "	or		%0,%2,%0	\n"			\ | 
|  | "	ldub%I6.p	%M6,%2		\n"			\ | 
|  | "	slli		%0,#8,%0	\n"			\ | 
|  | "	or		%0,%2,%0	\n"			\ | 
|  | "	ldub%I7		%M7,%1		\n"			\ | 
|  | "	ldub%I8.p	%M8,%2		\n"			\ | 
|  | "	slli		%1,#8,%1	\n"			\ | 
|  | "	or		%1,%2,%1	\n"			\ | 
|  | "	ldub%I9.p	%M9,%2		\n"			\ | 
|  | "	slli		%1,#8,%1	\n"			\ | 
|  | "	or		%1,%2,%1	\n"			\ | 
|  | "	ldub%I10.p	%M10,%2		\n"			\ | 
|  | "	slli		%1,#8,%1	\n"			\ | 
|  | "	or		%1,%2,%1	\n"			\ | 
|  | : "=&r"(z.y[0]), "=&r"(z.y[1]), "=&r"(a)			\ | 
|  | : "m"(__p[0]), "m"(__p[1]), "m"(__p[2]), "m"(__p[3]),	\ | 
|  | "m"(__p[4]), "m"(__p[5]), "m"(__p[6]), "m"(__p[7])	\ | 
|  | );								\ | 
|  | x = z.x;							\ | 
|  | break;								\ | 
|  | }									\ | 
|  | \ | 
|  | default:								\ | 
|  | x = 0;								\ | 
|  | BUG();								\ | 
|  | break;								\ | 
|  | }									\ | 
|  | \ | 
|  | x;									\ | 
|  | }) | 
|  |  | 
|  | #define put_unaligned(val, ptr)								\ | 
|  | do {											\ | 
|  | char *__p = (char *) (ptr);							\ | 
|  | int x;										\ | 
|  | \ | 
|  | switch (sizeof(*ptr)) {								\ | 
|  | case 2:										\ | 
|  | {										\ | 
|  | asm("	stb%I1.p	%0,%M1		\n"				\ | 
|  | "	srli		%0,#8,%0	\n"				\ | 
|  | "	stb%I2		%0,%M2		\n"				\ | 
|  | : "=r"(x), "=m"(__p[1]),  "=m"(__p[0])				\ | 
|  | : "0"(val)								\ | 
|  | );									\ | 
|  | break;									\ | 
|  | }										\ | 
|  | \ | 
|  | case 4:										\ | 
|  | {										\ | 
|  | asm("	stb%I1.p	%0,%M1		\n"				\ | 
|  | "	srli		%0,#8,%0	\n"				\ | 
|  | "	stb%I2.p	%0,%M2		\n"				\ | 
|  | "	srli		%0,#8,%0	\n"				\ | 
|  | "	stb%I3.p	%0,%M3		\n"				\ | 
|  | "	srli		%0,#8,%0	\n"				\ | 
|  | "	stb%I4		%0,%M4		\n"				\ | 
|  | : "=r"(x), "=m"(__p[3]),  "=m"(__p[2]), "=m"(__p[1]), "=m"(__p[0])	\ | 
|  | : "0"(val)								\ | 
|  | );									\ | 
|  | break;									\ | 
|  | }										\ | 
|  | \ | 
|  | case 8:										\ | 
|  | {										\ | 
|  | uint32_t __high, __low;							\ | 
|  | __high = (uint64_t)val >> 32;						\ | 
|  | __low = val & 0xffffffff;						\ | 
|  | asm("	stb%I2.p	%0,%M2		\n"				\ | 
|  | "	srli		%0,#8,%0	\n"				\ | 
|  | "	stb%I3.p	%0,%M3		\n"				\ | 
|  | "	srli		%0,#8,%0	\n"				\ | 
|  | "	stb%I4.p	%0,%M4		\n"				\ | 
|  | "	srli		%0,#8,%0	\n"				\ | 
|  | "	stb%I5.p	%0,%M5		\n"				\ | 
|  | "	srli		%0,#8,%0	\n"				\ | 
|  | "	stb%I6.p	%1,%M6		\n"				\ | 
|  | "	srli		%1,#8,%1	\n"				\ | 
|  | "	stb%I7.p	%1,%M7		\n"				\ | 
|  | "	srli		%1,#8,%1	\n"				\ | 
|  | "	stb%I8.p	%1,%M8		\n"				\ | 
|  | "	srli		%1,#8,%1	\n"				\ | 
|  | "	stb%I9		%1,%M9		\n"				\ | 
|  | : "=&r"(__low), "=&r"(__high), "=m"(__p[7]), "=m"(__p[6]), 		\ | 
|  | "=m"(__p[5]), "=m"(__p[4]), "=m"(__p[3]), "=m"(__p[2]), 		\ | 
|  | "=m"(__p[1]), "=m"(__p[0])					\ | 
|  | : "0"(__low), "1"(__high)						\ | 
|  | );									\ | 
|  | break;									\ | 
|  | }										\ | 
|  | \ | 
|  | default:									\ | 
|  | *(ptr) = (val);								\ | 
|  | break;									\ | 
|  | }										\ | 
|  | } while(0) | 
|  |  | 
|  | #endif | 
|  |  | 
|  | #endif |