1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1996, 1999, 2000, 2001, 2003 by Ralf Baechle
* Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc.
*/
#ifndef _ASM_UNALIGNED_H
#define _ASM_UNALIGNED_H
#include <linux/types.h>
/*
* get_unaligned - get value from possibly mis-aligned location
* @ptr: pointer to value
*
* This macro should be used for accessing values larger in size than
* single bytes at locations that are expected to be improperly aligned,
* e.g. retrieving a u16 value from a location not u16-aligned.
*
* Note that unaligned accesses can be very expensive on some architectures.
*/
#define get_unaligned(ptr) \
((__typeof__(*(ptr)))__get_unaligned((ptr), sizeof(*(ptr))))
/*
* put_unaligned - put value to a possibly mis-aligned location
* @val: value to place
* @ptr: pointer to location
*
* This macro should be used for placing values larger in size than
* single bytes at locations that are expected to be improperly aligned,
* e.g. writing a u16 value to a location not u16-aligned.
*
* Note that unaligned accesses can be very expensive on some architectures.
*/
#define put_unaligned(x,ptr) \
__put_unaligned((__u64)(x), (ptr), sizeof(*(ptr)))
/*
* This is a silly but good way to make sure that
* the get/put functions are indeed always optimized,
* and that we use the correct sizes.
*/
extern void bad_unaligned_access_length(void);
/*
* EGCS 1.1 knows about arbitrary unaligned loads. Define some
* packed structures to talk about such things with.
*/
struct __una_u64 { __u64 x __attribute__((packed)); };
struct __una_u32 { __u32 x __attribute__((packed)); };
struct __una_u16 { __u16 x __attribute__((packed)); };
/*
* Elemental unaligned loads
*/
extern inline __u64 __uldq(const __u64 * r11)
{
const struct __una_u64 *ptr = (const struct __una_u64 *) r11;
return ptr->x;
}
extern inline __u32 __uldl(const __u32 * r11)
{
const struct __una_u32 *ptr = (const struct __una_u32 *) r11;
return ptr->x;
}
extern inline __u16 __uldw(const __u16 * r11)
{
const struct __una_u16 *ptr = (const struct __una_u16 *) r11;
return ptr->x;
}
/*
* Elemental unaligned stores
*/
extern inline void __ustq(__u64 r5, __u64 * r11)
{
struct __una_u64 *ptr = (struct __una_u64 *) r11;
ptr->x = r5;
}
extern inline void __ustl(__u32 r5, __u32 * r11)
{
struct __una_u32 *ptr = (struct __una_u32 *) r11;
ptr->x = r5;
}
extern inline void __ustw(__u16 r5, __u16 * r11)
{
struct __una_u16 *ptr = (struct __una_u16 *) r11;
ptr->x = r5;
}
extern inline __u64 __get_unaligned(const void *ptr, size_t size)
{
__u64 val;
switch (size) {
case 1:
val = *(const __u8 *)ptr;
break;
case 2:
val = __uldw((const __u16 *)ptr);
break;
case 4:
val = __uldl((const __u32 *)ptr);
break;
case 8:
val = __uldq((const __u64 *)ptr);
break;
default:
bad_unaligned_access_length();
}
return val;
}
extern inline void __put_unaligned(__u64 val, void *ptr, size_t size)
{
switch (size) {
case 1:
*(__u8 *)ptr = (val);
break;
case 2:
__ustw(val, (__u16 *)ptr);
break;
case 4:
__ustl(val, (__u32 *)ptr);
break;
case 8:
__ustq(val, (__u64 *)ptr);
break;
default:
bad_unaligned_access_length();
}
}
#endif /* _ASM_UNALIGNED_H */
|