]>
Commit | Line | Data |
---|---|---|
afa3a931 | 1 | /* |
79461d20 | 2 | * Copyright (c) 2010, 2011, 2014 Nicira, Inc. |
afa3a931 BP |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at: | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | */ | |
16 | ||
17 | #ifndef UNALIGNED_H | |
18 | #define UNALIGNED_H 1 | |
19 | ||
20 | #include <stdint.h> | |
10a24935 | 21 | #include "byte-order.h" |
9ea5d2d5 | 22 | #include "openvswitch/types.h" |
ae06a561 | 23 | #include "openvswitch/type-props.h" |
320232ec | 24 | #include "util.h" |
afa3a931 BP |
25 | |
26 | /* Public API. */ | |
27 | static inline uint16_t get_unaligned_u16(const uint16_t *); | |
28 | static inline uint32_t get_unaligned_u32(const uint32_t *); | |
afa3a931 BP |
29 | static inline void put_unaligned_u16(uint16_t *, uint16_t); |
30 | static inline void put_unaligned_u32(uint32_t *, uint32_t); | |
31 | static inline void put_unaligned_u64(uint64_t *, uint64_t); | |
32 | ||
9ea5d2d5 BP |
33 | static inline ovs_be16 get_unaligned_be16(const ovs_be16 *); |
34 | static inline ovs_be32 get_unaligned_be32(const ovs_be32 *); | |
35 | static inline ovs_be64 get_unaligned_be64(const ovs_be64 *); | |
36 | static inline void put_unaligned_be16(ovs_be16 *, ovs_be16); | |
37 | static inline void put_unaligned_be32(ovs_be32 *, ovs_be32); | |
38 | static inline void put_unaligned_be64(ovs_be64 *, ovs_be64); | |
39 | ||
79461d20 BP |
40 | /* uint64_t get_unaligned_u64(uint64_t *p); |
41 | * | |
42 | * Returns the value of the possibly misaligned uint64_t at 'p'. 'p' may | |
43 | * actually be any type that points to a 64-bit integer. That is, on Unix-like | |
44 | * 32-bit ABIs, it may point to an "unsigned long long int", and on Unix-like | |
45 | * 64-bit ABIs, it may point to an "unsigned long int" or an "unsigned long | |
46 | * long int". | |
47 | * | |
48 | * This is special-cased because on some Linux targets, the kernel __u64 is | |
49 | * unsigned long long int and the userspace uint64_t is unsigned long int, so | |
50 | * that any single function prototype would fail to accept one or the other. | |
51 | * | |
52 | * Below, "sizeof (*(P) % 1)" verifies that *P has an integer type, since | |
53 | * operands to % must be integers. | |
54 | */ | |
55 | #define get_unaligned_u64(P) \ | |
56 | (BUILD_ASSERT(sizeof *(P) == 8), \ | |
57 | BUILD_ASSERT_GCCONLY(!TYPE_IS_SIGNED(typeof(*(P)))), \ | |
58 | (void) sizeof (*(P) % 1), \ | |
59 | get_unaligned_u64__((const uint64_t *) (P))) | |
60 | ||
afa3a931 BP |
61 | #ifdef __GNUC__ |
62 | /* GCC implementations. */ | |
9ea5d2d5 BP |
63 | #define GCC_UNALIGNED_ACCESSORS(TYPE, ABBREV) \ |
64 | struct unaligned_##ABBREV { \ | |
65 | TYPE x __attribute__((__packed__)); \ | |
66 | }; \ | |
67 | static inline struct unaligned_##ABBREV * \ | |
68 | unaligned_##ABBREV(const TYPE *p) \ | |
69 | { \ | |
70 | return (struct unaligned_##ABBREV *) p; \ | |
71 | } \ | |
72 | \ | |
73 | static inline TYPE \ | |
74 | get_unaligned_##ABBREV(const TYPE *p) \ | |
75 | { \ | |
76 | return unaligned_##ABBREV(p)->x; \ | |
77 | } \ | |
78 | \ | |
79 | static inline void \ | |
80 | put_unaligned_##ABBREV(TYPE *p, TYPE x) \ | |
81 | { \ | |
82 | unaligned_##ABBREV(p)->x = x; \ | |
afa3a931 BP |
83 | } |
84 | ||
9ea5d2d5 BP |
85 | GCC_UNALIGNED_ACCESSORS(uint16_t, u16); |
86 | GCC_UNALIGNED_ACCESSORS(uint32_t, u32); | |
320232ec | 87 | GCC_UNALIGNED_ACCESSORS(uint64_t, u64__); /* Special case: see below. */ |
9ea5d2d5 BP |
88 | |
89 | GCC_UNALIGNED_ACCESSORS(ovs_be16, be16); | |
90 | GCC_UNALIGNED_ACCESSORS(ovs_be32, be32); | |
91 | GCC_UNALIGNED_ACCESSORS(ovs_be64, be64); | |
afa3a931 BP |
92 | #else |
93 | /* Generic implementations. */ | |
94 | ||
95 | static inline uint16_t get_unaligned_u16(const uint16_t *p_) | |
96 | { | |
97 | const uint8_t *p = (const uint8_t *) p_; | |
98 | return ntohs((p[0] << 8) | p[1]); | |
99 | } | |
100 | ||
101 | static inline void put_unaligned_u16(uint16_t *p_, uint16_t x_) | |
102 | { | |
103 | uint8_t *p = (uint8_t *) p_; | |
104 | uint16_t x = ntohs(x_); | |
105 | ||
106 | p[0] = x >> 8; | |
107 | p[1] = x; | |
108 | } | |
109 | ||
110 | static inline uint32_t get_unaligned_u32(const uint32_t *p_) | |
111 | { | |
112 | const uint8_t *p = (const uint8_t *) p_; | |
113 | return ntohl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); | |
114 | } | |
115 | ||
116 | static inline void put_unaligned_u32(uint32_t *p_, uint32_t x_) | |
117 | { | |
118 | uint8_t *p = (uint8_t *) p_; | |
119 | uint32_t x = ntohl(x_); | |
120 | ||
121 | p[0] = x >> 24; | |
122 | p[1] = x >> 16; | |
123 | p[2] = x >> 8; | |
124 | p[3] = x; | |
125 | } | |
126 | ||
320232ec | 127 | static inline uint64_t get_unaligned_u64__(const uint64_t *p_) |
afa3a931 BP |
128 | { |
129 | const uint8_t *p = (const uint8_t *) p_; | |
130 | return ntohll(((uint64_t) p[0] << 56) | |
131 | | ((uint64_t) p[1] << 48) | |
132 | | ((uint64_t) p[2] << 40) | |
133 | | ((uint64_t) p[3] << 32) | |
134 | | (p[4] << 24) | |
135 | | (p[5] << 16) | |
136 | | (p[6] << 8) | |
137 | | p[7]); | |
138 | } | |
139 | ||
320232ec | 140 | static inline void put_unaligned_u64__(uint64_t *p_, uint64_t x_) |
afa3a931 BP |
141 | { |
142 | uint8_t *p = (uint8_t *) p_; | |
143 | uint64_t x = ntohll(x_); | |
144 | ||
145 | p[0] = x >> 56; | |
146 | p[1] = x >> 48; | |
147 | p[2] = x >> 40; | |
148 | p[3] = x >> 32; | |
149 | p[4] = x >> 24; | |
150 | p[5] = x >> 16; | |
151 | p[6] = x >> 8; | |
152 | p[7] = x; | |
153 | } | |
9ea5d2d5 BP |
154 | |
155 | /* Only sparse cares about the difference between uint<N>_t and ovs_be<N>, and | |
156 | * that takes the GCC branch, so there's no point in working too hard on these | |
157 | * accessors. */ | |
158 | #define get_unaligned_be16 get_unaligned_u16 | |
159 | #define get_unaligned_be32 get_unaligned_u32 | |
9ea5d2d5 BP |
160 | #define put_unaligned_be16 put_unaligned_u16 |
161 | #define put_unaligned_be32 put_unaligned_u32 | |
162 | #define put_unaligned_be64 put_unaligned_u64 | |
320232ec | 163 | |
79461d20 BP |
164 | /* We do not #define get_unaligned_be64 as for the other be<N> functions above, |
165 | * because such a definition would mean that get_unaligned_be64() would have a | |
166 | * different interface in each branch of the #if: with GCC it would take a | |
167 | * "ovs_be64 *", with other compilers any pointer-to-64-bit-type (but not void | |
168 | * *). The latter means code like "get_unaligned_be64(ofpbuf_data(b))" would | |
169 | * work with GCC but not with other compilers, which is surprising and | |
170 | * undesirable. Hence this wrapper function. */ | |
171 | static inline ovs_be64 | |
172 | get_unaligned_be64(const ovs_be64 *p) | |
173 | { | |
174 | return get_unaligned_u64(p); | |
175 | } | |
176 | #endif | |
320232ec BP |
177 | |
178 | /* Stores 'x' at possibly misaligned address 'p'. | |
179 | * | |
180 | * put_unaligned_u64() could be overloaded in the same way as | |
181 | * get_unaligned_u64(), but so far it has not proven necessary. | |
182 | */ | |
183 | static inline void | |
184 | put_unaligned_u64(uint64_t *p, uint64_t x) | |
185 | { | |
186 | put_unaligned_u64__(p, x); | |
187 | } | |
7bef2c91 | 188 | \f |
7c457c33 BP |
189 | /* Returns the value in 'x'. */ |
190 | static inline uint32_t | |
191 | get_16aligned_u32(const ovs_16aligned_u32 *x) | |
192 | { | |
193 | return ((uint32_t) x->hi << 16) | x->lo; | |
194 | } | |
195 | ||
196 | /* Stores 'value' in 'x'. */ | |
197 | static inline void | |
198 | put_16aligned_u32(ovs_16aligned_u32 *x, uint32_t value) | |
199 | { | |
200 | x->hi = value >> 16; | |
201 | x->lo = value; | |
202 | } | |
203 | ||
7bef2c91 BP |
204 | /* Returns the value in 'x'. */ |
205 | static inline uint64_t | |
206 | get_32aligned_u64(const ovs_32aligned_u64 *x) | |
207 | { | |
05fe1764 | 208 | return ((uint64_t) x->hi << 32) | x->lo; |
7bef2c91 BP |
209 | } |
210 | ||
211 | /* Stores 'value' in 'x'. */ | |
212 | static inline void | |
213 | put_32aligned_u64(ovs_32aligned_u64 *x, uint64_t value) | |
214 | { | |
05fe1764 BP |
215 | x->hi = value >> 32; |
216 | x->lo = value; | |
7bef2c91 BP |
217 | } |
218 | ||
6506f45c | 219 | #ifndef __CHECKER__ |
7c457c33 BP |
220 | /* Returns the value of 'x'. */ |
221 | static inline ovs_be32 | |
222 | get_16aligned_be32(const ovs_16aligned_be32 *x) | |
223 | { | |
224 | #ifdef WORDS_BIGENDIAN | |
225 | return ((ovs_be32) x->hi << 16) | x->lo; | |
226 | #else | |
227 | return ((ovs_be32) x->lo << 16) | x->hi; | |
228 | #endif | |
229 | } | |
230 | ||
231 | /* Stores network byte order 'value' into 'x'. */ | |
232 | static inline void | |
233 | put_16aligned_be32(ovs_16aligned_be32 *x, ovs_be32 value) | |
234 | { | |
235 | #if WORDS_BIGENDIAN | |
236 | x->hi = value >> 16; | |
237 | x->lo = value; | |
238 | #else | |
239 | x->hi = value; | |
240 | x->lo = value >> 16; | |
241 | #endif | |
242 | } | |
243 | ||
7bef2c91 BP |
244 | /* Returns the value of 'x'. */ |
245 | static inline ovs_be64 | |
246 | get_32aligned_be64(const ovs_32aligned_be64 *x) | |
247 | { | |
248 | #ifdef WORDS_BIGENDIAN | |
05fe1764 | 249 | return ((ovs_be64) x->hi << 32) | x->lo; |
7bef2c91 | 250 | #else |
05fe1764 | 251 | return ((ovs_be64) x->lo << 32) | x->hi; |
7bef2c91 BP |
252 | #endif |
253 | } | |
254 | ||
255 | /* Stores network byte order 'value' into 'x'. */ | |
256 | static inline void | |
257 | put_32aligned_be64(ovs_32aligned_be64 *x, ovs_be64 value) | |
258 | { | |
259 | #if WORDS_BIGENDIAN | |
05fe1764 BP |
260 | x->hi = value >> 32; |
261 | x->lo = value; | |
7bef2c91 BP |
262 | #else |
263 | x->hi = value; | |
264 | x->lo = value >> 32; | |
265 | #endif | |
266 | } | |
6506f45c BP |
267 | #else /* __CHECKER__ */ |
268 | /* Making sparse happy with these functions also makes them unreadable, so | |
269 | * don't bother to show it their implementations. */ | |
7c457c33 BP |
270 | ovs_be32 get_16aligned_be32(const ovs_16aligned_be32 *); |
271 | void put_16aligned_be32(ovs_16aligned_be32 *, ovs_be32); | |
6506f45c BP |
272 | ovs_be64 get_32aligned_be64(const ovs_32aligned_be64 *); |
273 | void put_32aligned_be64(ovs_32aligned_be64 *, ovs_be64); | |
274 | #endif | |
afa3a931 BP |
275 | |
276 | #endif /* unaligned.h */ |