unaligned.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. #ifndef _ASM_GENERIC_UNALIGNED_H_
  2. #define _ASM_GENERIC_UNALIGNED_H_
  3. /*
  4. * For the benefit of those who are trying to port Linux to another
  5. * architecture, here are some C-language equivalents.
  6. *
  7. * This is based almost entirely upon Richard Henderson's
  8. * asm-alpha/unaligned.h implementation. Some comments were
  9. * taken from David Mosberger's asm-ia64/unaligned.h header.
  10. */
  11. #include <linux/types.h>
  12. /*
  13. * The main single-value unaligned transfer routines.
  14. */
  15. #define get_unaligned(ptr) \
  16. __get_unaligned((ptr), sizeof(*(ptr)))
  17. #define put_unaligned(x,ptr) \
  18. ((void)sizeof(*(ptr)=(x)),\
  19. __put_unaligned((__force __u64)(x), (ptr), sizeof(*(ptr))))
  20. /*
  21. * This function doesn't actually exist. The idea is that when
  22. * someone uses the macros below with an unsupported size (datatype),
  23. * the linker will alert us to the problem via an unresolved reference
  24. * error.
  25. */
  26. extern void bad_unaligned_access_length(void) __attribute__((noreturn));
  27. struct __una_u64 { __u64 x __attribute__((packed)); };
  28. struct __una_u32 { __u32 x __attribute__((packed)); };
  29. struct __una_u16 { __u16 x __attribute__((packed)); };
  30. /*
  31. * Elemental unaligned loads
  32. */
  33. static inline __u64 __uldq(const __u64 *addr)
  34. {
  35. const struct __una_u64 *ptr = (const struct __una_u64 *) addr;
  36. return ptr->x;
  37. }
  38. static inline __u32 __uldl(const __u32 *addr)
  39. {
  40. const struct __una_u32 *ptr = (const struct __una_u32 *) addr;
  41. return ptr->x;
  42. }
  43. static inline __u16 __uldw(const __u16 *addr)
  44. {
  45. const struct __una_u16 *ptr = (const struct __una_u16 *) addr;
  46. return ptr->x;
  47. }
  48. /*
  49. * Elemental unaligned stores
  50. */
  51. static inline void __ustq(__u64 val, __u64 *addr)
  52. {
  53. struct __una_u64 *ptr = (struct __una_u64 *) addr;
  54. ptr->x = val;
  55. }
  56. static inline void __ustl(__u32 val, __u32 *addr)
  57. {
  58. struct __una_u32 *ptr = (struct __una_u32 *) addr;
  59. ptr->x = val;
  60. }
  61. static inline void __ustw(__u16 val, __u16 *addr)
  62. {
  63. struct __una_u16 *ptr = (struct __una_u16 *) addr;
  64. ptr->x = val;
  65. }
  66. #define __get_unaligned(ptr, size) ({ \
  67. const void *__gu_p = ptr; \
  68. __u64 __val; \
  69. switch (size) { \
  70. case 1: \
  71. __val = *(const __u8 *)__gu_p; \
  72. break; \
  73. case 2: \
  74. __val = __uldw(__gu_p); \
  75. break; \
  76. case 4: \
  77. __val = __uldl(__gu_p); \
  78. break; \
  79. case 8: \
  80. __val = __uldq(__gu_p); \
  81. break; \
  82. default: \
  83. bad_unaligned_access_length(); \
  84. }; \
  85. (__force __typeof__(*(ptr)))__val; \
  86. })
  87. #define __put_unaligned(val, ptr, size) \
  88. ({ \
  89. void *__gu_p = ptr; \
  90. switch (size) { \
  91. case 1: \
  92. *(__u8 *)__gu_p = (__force __u8)val; \
  93. break; \
  94. case 2: \
  95. __ustw((__force __u16)val, __gu_p); \
  96. break; \
  97. case 4: \
  98. __ustl((__force __u32)val, __gu_p); \
  99. break; \
  100. case 8: \
  101. __ustq(val, __gu_p); \
  102. break; \
  103. default: \
  104. bad_unaligned_access_length(); \
  105. }; \
  106. (void)0; \
  107. })
  108. #endif /* _ASM_GENERIC_UNALIGNED_H */