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 x64,
4 // they require IOPL 3).
9 #include <lowlevel/types.h>
11 // Unconditional byte-swap
13 static inline uint16_t ll_swap16(uint16_t val)
15 asm("xchgb %b0, %h0" : "+abcd" (val));
19 static inline uint32_t ll_swap32(uint32_t val)
21 asm("bswap %0" : "+r" (val));
25 static inline uint64_t ll_swap64(uint64_t val)
27 asm("bswap %0" : "+r" (val));
31 // Conditional byte-swap to/from a specific endianness
33 static inline uint64_t ll_swap_le64(uint64_t val)
38 static inline uint32_t ll_swap_le32(uint32_t val)
43 static inline uint16_t ll_swap_le16(uint16_t val)
48 static inline uint64_t ll_swap_be64(uint64_t val)
50 return ll_swap64(val);
53 static inline uint32_t ll_swap_be32(uint32_t val)
55 return ll_swap32(val);
58 static inline uint16_t ll_swap_be16(uint16_t val)
60 return ll_swap16(val);
63 // Unaligned, host-endian
65 static inline uint64_t ll_load_unaligned_64(void *addr)
67 return *(uint64_t *)addr;
70 static inline uint32_t ll_load_unaligned_32(void *addr)
72 return *(uint32_t *)addr;
75 static inline uint16_t ll_load_unaligned_16(void *addr)
77 return *(uint16_t *)addr;
80 static inline void ll_store_unaligned_64(void *addr, uint64_t val)
82 *(uint64_t *)addr = val;
85 static inline void ll_store_unaligned_32(void *addr, uint32_t val)
87 *(uint32_t *)addr = val;
90 static inline void ll_store_unaligned_16(void *addr, uint16_t val)
92 *(uint16_t *)addr = val;
95 // Unaligned, big-endian
97 static inline uint16_t ll_load_unaligned_be16(void *addr)
99 return ll_swap16(ll_load_unaligned_16(addr));
102 static inline uint32_t ll_load_unaligned_be32(void *addr)
104 return ll_swap32(ll_load_unaligned_32(addr));
107 static inline uint64_t ll_load_unaligned_be64(void *addr)
109 return ll_swap64(ll_load_unaligned_64(addr));
112 static inline void ll_store_unaligned_be16(void *addr, uint16_t val)
114 ll_store_unaligned_16(addr, ll_swap16(val));
117 static inline void ll_store_unaligned_be32(void *addr, uint32_t val)
119 ll_store_unaligned_32(addr, ll_swap32(val));
122 static inline void ll_store_unaligned_be64(void *addr, uint64_t val)
124 ll_store_unaligned_64(addr, ll_swap64(val));
127 // Aligned, big-endian
129 static inline uint64_t ll_load_be64(uint64_t *addr)
131 return ll_load_unaligned_be64(addr);
134 static inline uint32_t ll_load_be32(uint32_t *addr)
136 return ll_load_unaligned_be32(addr);
139 static inline uint16_t ll_load_be16(uint16_t *addr)
141 return ll_load_unaligned_be16(addr);
144 static inline void ll_store_be64(uint64_t *addr, uint64_t val)
146 ll_store_unaligned_be64(addr, val);
149 static inline void ll_store_be32(uint32_t *addr, uint32_t val)
151 ll_store_unaligned_be32(addr, val);
154 static inline void ll_store_be16(uint16_t *addr, uint16_t val)
156 ll_store_unaligned_be16(addr, val);
159 // Unaligned, little-endian
161 static inline uint64_t ll_load_unaligned_le64(void *addr)
163 return ll_load_unaligned_64(addr);
166 static inline uint32_t ll_load_unaligned_le32(void *addr)
168 return ll_load_unaligned_32(addr);
171 static inline uint16_t ll_load_unaligned_le16(void *addr)
173 return ll_load_unaligned_16(addr);
176 static inline void ll_store_unaligned_le32(void *addr, uint32_t val)
178 ll_store_unaligned_32(addr, val);
181 static inline void ll_store_unaligned_le16(void *addr, uint16_t val)
183 ll_store_unaligned_16(addr, val);
186 // Aligned, little-endian
188 static inline uint32_t ll_load_le32(uint32_t *addr)
190 return ll_load_unaligned_le32(addr);
193 static inline uint16_t ll_load_le16(uint16_t *addr)
195 return ll_load_unaligned_le16(addr);
198 static inline void ll_store_le32(uint32_t *addr, uint32_t val)
200 ll_store_unaligned_le32(addr, val);
203 static inline void ll_store_le16(uint16_t *addr, uint16_t val)
205 ll_store_unaligned_le16(addr, val);
208 // PCI/ISA/similar I/O-space; if memory-mapped, addr must include
209 // the base of the I/O window.
211 static inline uint8_t ll_in_8(uintptr_t addr)
214 asm volatile("inb %w1, %b0" : "=a" (val) : "d" (addr) : "memory");
218 static inline uint16_t ll_in_le16(uintptr_t addr)
221 asm volatile("inw %w1, %w0" : "=a" (val) : "d" (addr) : "memory");
225 static inline uint32_t ll_in_le32(uintptr_t addr)
228 asm volatile("inl %w1, %0" : "=a" (val) : "d" (addr) : "memory");
232 static inline uint16_t ll_in_be16(uintptr_t addr)
234 return ll_swap16(ll_in_le16(addr));
237 static inline uint32_t ll_in_be32(uintptr_t addr)
239 return ll_swap32(ll_in_le32(addr));
242 static inline void ll_out_8(uintptr_t addr, uint8_t val)
244 asm volatile("outb %b0, %w1" : : "a" (val), "d" (addr) : "memory");
247 static inline void ll_out_le16(uintptr_t addr, uint16_t val)
249 asm volatile("outw %w0, %w1" : : "a" (val), "d" (addr) : "memory");
252 static inline void ll_out_le32(uintptr_t addr, uint32_t val)
254 asm volatile("outl %0, %w1" : : "a" (val), "d" (addr) : "memory");
257 static inline void ll_out_be16(uintptr_t addr, uint16_t val)
259 ll_out_le16(addr, ll_swap16(val));
262 static inline void ll_out_be32(uintptr_t addr, uint32_t val)
264 ll_out_le32(addr, ll_swap32(val));