mirror of
https://github.com/torvalds/linux.git
synced 2024-11-12 15:11:50 +00:00
62c4f0a2d5
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
203 lines
5.5 KiB
C
203 lines
5.5 KiB
C
/* 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
|