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 x86,
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 return (uint64_t)ll_swap32(val) | ((uint64_t)ll_swap32(val >> 32) << 32);
30 // Conditional byte-swap to/from a specific endianness
32 static inline uint64_t ll_swap_le64(uint64_t val)
37 static inline uint32_t ll_swap_le32(uint32_t val)
42 static inline uint16_t ll_swap_le16(uint16_t val)
47 static inline uint64_t ll_swap_be64(uint64_t val)
49 return ll_swap64(val);
52 static inline uint32_t ll_swap_be32(uint32_t val)
54 return ll_swap32(val);
57 static inline uint16_t ll_swap_be16(uint16_t val)
59 return ll_swap16(val);
62 // Unaligned, host-endian
64 static inline uint64_t ll_load_unaligned_64(void *addr)
66 // FIXME: atomic using FP/MMX?
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 // FIXME: atomic using FP/MMX?
83 *(uint64_t *)addr = val;
86 static inline void ll_store_unaligned_32(void *addr, uint32_t val)
88 *(uint32_t *)addr = val;
91 static inline void ll_store_unaligned_16(void *addr, uint16_t val)
93 *(uint16_t *)addr = val;
96 // Unaligned, big-endian
98 static inline uint16_t ll_load_unaligned_be16(void *addr)
100 return ll_swap16(ll_load_unaligned_16(addr));
103 static inline uint32_t ll_load_unaligned_be32(void *addr)
105 return ll_swap32(ll_load_unaligned_32(addr));
108 static inline uint64_t ll_load_unaligned_be64(void *addr)
110 // FIXME: atomic using FP/MMX?
111 return ((uint64_t)ll_load_unaligned_be32(addr) << 32) |
112 (uint64_t)ll_load_unaligned_be32((void *)((char *)addr + 4));
115 static inline void ll_store_unaligned_be16(void *addr, uint16_t val)
117 ll_store_unaligned_16(addr, ll_swap16(val));
120 static inline void ll_store_unaligned_be32(void *addr, uint32_t val)
122 ll_store_unaligned_32(addr, ll_swap32(val));
125 static inline void ll_store_unaligned_be64(void *addr, uint64_t val)
127 // FIXME: atomic using FP/MMX?
128 ll_store_unaligned_be32(addr, (uint32_t)(val >> 32));
129 ll_store_unaligned_be32((void *)((char *)addr + 4), (uint32_t)val);
132 // Aligned, big-endian
134 static inline uint64_t ll_load_be64(uint64_t *addr)
136 return ll_load_unaligned_be64(addr);
139 static inline uint32_t ll_load_be32(uint32_t *addr)
141 return ll_load_unaligned_be32(addr);
144 static inline uint16_t ll_load_be16(uint16_t *addr)
146 return ll_load_unaligned_be16(addr);
149 static inline void ll_store_be64(uint64_t *addr, uint64_t val)
151 ll_store_unaligned_be64(addr, val);
154 static inline void ll_store_be32(uint32_t *addr, uint32_t val)
156 ll_store_unaligned_be32(addr, val);
159 static inline void ll_store_be16(uint16_t *addr, uint16_t val)
161 ll_store_unaligned_be16(addr, val);
164 // Unaligned, little-endian
166 static inline uint64_t ll_load_unaligned_le64(void *addr)
168 return ll_load_unaligned_64(addr);
171 static inline uint32_t ll_load_unaligned_le32(void *addr)
173 return ll_load_unaligned_32(addr);
176 static inline uint16_t ll_load_unaligned_le16(void *addr)
178 return ll_load_unaligned_16(addr);
181 static inline void ll_store_unaligned_le32(void *addr, uint32_t val)
183 ll_store_unaligned_32(addr, val);
186 static inline void ll_store_unaligned_le16(void *addr, uint16_t val)
188 ll_store_unaligned_16(addr, val);
191 // Aligned, little-endian
193 static inline uint32_t ll_load_le32(uint32_t *addr)
195 return ll_load_unaligned_le32(addr);
198 static inline uint16_t ll_load_le16(uint16_t *addr)
200 return ll_load_unaligned_le16(addr);
203 static inline void ll_store_le32(uint32_t *addr, uint32_t val)
205 ll_store_unaligned_le32(addr, val);
208 static inline void ll_store_le16(uint16_t *addr, uint16_t val)
210 ll_store_unaligned_le16(addr, val);
213 // PCI/ISA/similar I/O-space; if memory-mapped, addr must include
214 // the base of the I/O window.
216 static inline uint8_t ll_in_8(uintptr_t addr)
219 asm volatile("inb %w1, %b0" : "=a" (val) : "d" (addr) : "memory");
223 static inline uint16_t ll_in_le16(uintptr_t addr)
226 asm volatile("inw %w1, %w0" : "=a" (val) : "d" (addr) : "memory");
230 static inline uint32_t ll_in_le32(uintptr_t addr)
233 asm volatile("inl %w1, %0" : "=a" (val) : "d" (addr) : "memory");
237 static inline uint16_t ll_in_be16(uintptr_t addr)
239 return ll_swap16(ll_in_le16(addr));
242 static inline uint32_t ll_in_be32(uintptr_t addr)
244 return ll_swap32(ll_in_le32(addr));
247 static inline void ll_out_8(uintptr_t addr, uint8_t val)
249 asm volatile("outb %b0, %w1" : : "a" (val), "d" (addr) : "memory");
252 static inline void ll_out_le16(uintptr_t addr, uint16_t val)
254 asm volatile("outw %w0, %w1" : : "a" (val), "d" (addr) : "memory");
257 static inline void ll_out_le32(uintptr_t addr, uint32_t val)
259 asm volatile("outl %0, %w1" : : "a" (val), "d" (addr) : "memory");
262 static inline void ll_out_be16(uintptr_t addr, uint16_t val)
264 ll_out_le16(addr, ll_swap16(val));
267 static inline void ll_out_be32(uintptr_t addr, uint32_t val)
269 ll_out_le32(addr, ll_swap32(val));