1 // Byte-swapping, unaligned memory, and I/O port access functions. These
2 // functions are all unprivileged, except the ll_in_* and ll_out_*
3 // functions, whose privilege is architecture-dependent (on PPC and most
4 // other non-x86 architectures, they require the address specified to be
5 // mapped appropriately).
10 #include <lowlevel/types.h>
12 // Unconditional byte-swap
14 static inline uint16_t ll_swap16(uint16_t val)
16 return (uint16_t)val | ((uint16_t)val >> 8) << 8);
19 static inline uint32_t ll_swap32(uint32_t val)
21 return ((val & 0x000000ff) << 24) |
22 ((val & 0x0000ff00) << 8) |
23 ((val & 0x00ff0000) >> 8) |
24 ((val & 0xff000000) >> 24);
27 static inline uint64_t ll_swap64(uint64_t val)
29 return (uint64_t)ll_swap32(val) | ((uint64_t)ll_swap32(val >> 32) << 32);
32 // Conditional byte-swap to/from a specific endianness
34 static inline uint64_t ll_swap_be64(uint64_t val)
39 static inline uint32_t ll_swap_be32(uint32_t val)
44 static inline uint16_t ll_swap_be16(uint16_t val)
49 static inline uint64_t ll_swap_le64(uint64_t val)
51 return ll_swap64(val);
54 static inline uint32_t ll_swap_le32(uint32_t val)
56 return ll_swap32(val);
59 static inline uint16_t ll_swap_le16(uint16_t val)
61 return ll_swap16(val);
64 // Unaligned, host-endian
66 static inline uint16_t ll_load_unaligned_16(void *addr)
68 return *(uint16_t *)addr;
71 static inline uint64_t ll_load_unaligned_64(void *addr)
73 // FIXME: atomic using FP?
74 return *(uint64_t *)addr;
77 static inline uint32_t ll_load_unaligned_32(void *addr)
79 return *(uint32_t *)addr;
82 static inline void ll_store_unaligned_16(void *addr, uint16_t val)
84 *(uint16_t *)addr = val;
87 static inline void ll_store_unaligned_64(void *addr, uint64_t val)
89 // FIXME: atomic using FP?
90 *(uint64_t *)addr = val;
93 static inline void ll_store_unaligned_32(void *addr, uint32_t val)
95 *(uint32_t *)addr = val;
98 // Unaligned, little-endian
100 static inline uint16_t ll_load_unaligned_le16(void *addr)
103 asm("lhbrx %0, 0, %1" : "=r" (val) : "r" (addr), "m" (*(uint16_t *)addr));
107 static inline uint32_t ll_load_unaligned_le32(void *addr)
110 asm("lwbrx %0, 0, %1" : "=r" (val) : "r" (addr), "m" (*(uint32_t *)addr));
114 static inline uint64_t ll_load_unaligned_le64(void *addr)
116 // FIXME: atomic using FP?
117 return (uint64_t)ll_load_unaligned_le32(addr) |
118 ((uint64_t)ll_load_unaligned_le32((void *)((char *)addr + 4)) << 32);
121 static inline void ll_store_unaligned_le16(void *addr, uint16_t val)
123 asm("sthbrx %1, 0, %2" : "=m" (*(uint16_t *)addr) : "r" (val), "r" (addr));
126 static inline void ll_store_unaligned_le32(void *addr, uint32_t val)
128 asm("stwbrx %1, 0, %2" : "=m" (*(uint32_t *)addr) : "r" (val), "r" (addr));
131 static inline void ll_store_unaligned_le64(void *addr, uint64_t val)
133 // FIXME: atomic using FP?
134 ll_store_unaligned_le32(addr, (uint32_t)val);
135 ll_store_unaligned_le32((void *)((char *)addr + 4), (uint32_t)(val >> 32));
138 // Aligned, little-endian
140 static inline uint64_t ll_load_le64(uint64_t *addr)
142 return ll_load_unaligned_le64(addr);
145 static inline uint32_t ll_load_le32(uint32_t *addr)
147 return ll_load_unaligned_le32(addr);
150 static inline uint16_t ll_load_le16(uint16_t *addr)
152 return ll_load_unaligned_le16(addr);
155 static inline void ll_store_le64(uint64_t *addr, uint64_t val)
157 ll_store_unaligned_le64(addr, val);
160 static inline void ll_store_le32(uint32_t *addr, uint32_t val)
162 ll_store_unaligned_le32(addr, val);
165 static inline void ll_store_le16(uint16_t *addr, uint16_t val)
167 ll_store_unaligned_le16(addr, val);
170 // Unaligned, big-endian
172 static inline uint64_t ll_load_unaligned_be64(void *addr)
174 return ll_load_unaligned_64(addr);
177 static inline uint32_t ll_load_unaligned_be32(void *addr)
179 return ll_load_unaligned_32(addr);
182 static inline uint16_t ll_load_unaligned_be16(void *addr)
184 return ll_load_unaligned_16(addr);
187 static inline void ll_store_unaligned_be32(void *addr, uint32_t val)
189 ll_store_unaligned_32(addr, val);
192 static inline void ll_store_unaligned_be16(void *addr, uint16_t val)
194 ll_store_unaligned_16(addr, val);
197 // Aligned, big-endian
199 static inline uint32_t ll_load_be32(uint32_t *addr)
201 return ll_load_unaligned_be32(addr);
204 static inline uint16_t ll_load_be16(uint16_t *addr)
206 return ll_load_unaligned_be16(addr);
209 static inline void ll_store_be32(uint32_t *addr, uint32_t val)
211 ll_store_unaligned_be32(addr, val);
214 static inline void ll_store_be16(uint16_t *addr, uint16_t val)
216 ll_store_unaligned_be16(addr, val);
219 // PCI/ISA/similar I/O-space; if memory-mapped, addr must include
220 // the base of the I/O window.
222 static inline uint8_t ll_in_8(ulong addr)
224 return *(uint8_t *)addr;
227 static inline uint16_t ll_in_be16(ulong addr)
229 return ll_load_be16(addr);
232 static inline uint32_t ll_in_be32(ulong addr)
234 return ll_load_be32(addr);
237 static inline uint16_t ll_in_le16(ulong addr)
239 return ll_load_le16(addr);
242 static inline uint32_t ll_in_le32(ulong addr)
244 return ll_load_le32(addr);
247 static inline void ll_out_8(ulong addr, uint8_t val)
249 *(uint8_t *)addr = val;
252 static inline void ll_out_be16(ulong addr, uint16_t val)
254 ll_store_be16(addr, val);
257 static inline void ll_out_be32(ulong addr, uint32_t val)
259 ll_store_be32(addr, val);
262 static inline void ll_out_le16(ulong addr, uint16_t val)
264 ll_store_le16(addr, val);
267 static inline void ll_out_le32(ulong addr, uint32_t val)
269 ll_store_le32(addr, val);