]> git.buserror.net Git - polintos/scott/priv.git/blob - include/c/lowlevel/arch-x64/io.h
Initial checkin from Perforce.
[polintos/scott/priv.git] / include / c / lowlevel / arch-x64 / io.h
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).
5
6 #ifndef _LL_ARCH_IO_H
7 #define _LL_ARCH_IO_H
8
9 #include <lowlevel/types.h>
10
11 // Unconditional byte-swap
12
13 static inline uint16_t ll_swap16(uint16_t val)
14 {
15         asm("xchgb %b0, %h0" : "+abcd" (val));
16         return val;
17 }
18
19 static inline uint32_t ll_swap32(uint32_t val)
20 {
21         asm("bswap %0" : "+r" (val));
22         return val;
23 }
24
25 static inline uint64_t ll_swap64(uint64_t val)
26 {
27         asm("bswap %0" : "+r" (val));
28         return val;
29 }
30
31 // Conditional byte-swap to/from a specific endianness
32
33 static inline uint64_t ll_swap_le64(uint64_t val)
34 {
35         return val;
36 }
37
38 static inline uint32_t ll_swap_le32(uint32_t val)
39 {
40         return val;
41 }
42
43 static inline uint16_t ll_swap_le16(uint16_t val)
44 {
45         return val;
46 }
47
48 static inline uint64_t ll_swap_be64(uint64_t val)
49 {
50         return ll_swap64(val);
51 }
52
53 static inline uint32_t ll_swap_be32(uint32_t val)
54 {
55         return ll_swap32(val);
56 }
57
58 static inline uint16_t ll_swap_be16(uint16_t val)
59 {
60         return ll_swap16(val);
61 }
62
63 // Unaligned, host-endian
64
65 static inline uint64_t ll_load_unaligned_64(void *addr)
66 {
67         return *(uint64_t *)addr;
68 }
69
70 static inline uint32_t ll_load_unaligned_32(void *addr)
71 {
72         return *(uint32_t *)addr;
73 }
74
75 static inline uint16_t ll_load_unaligned_16(void *addr)
76 {
77         return *(uint16_t *)addr;
78 }
79
80 static inline void ll_store_unaligned_64(void *addr, uint64_t val)
81 {
82         *(uint64_t *)addr = val;
83 }
84
85 static inline void ll_store_unaligned_32(void *addr, uint32_t val)
86 {
87         *(uint32_t *)addr = val;
88 }
89
90 static inline void ll_store_unaligned_16(void *addr, uint16_t val)
91 {
92         *(uint16_t *)addr = val;
93 }
94
95 // Unaligned, big-endian
96
97 static inline uint16_t ll_load_unaligned_be16(void *addr)
98 {
99         return ll_swap16(ll_load_unaligned_16(addr));
100 }
101
102 static inline uint32_t ll_load_unaligned_be32(void *addr)
103 {
104         return ll_swap32(ll_load_unaligned_32(addr));
105 }
106
107 static inline uint64_t ll_load_unaligned_be64(void *addr)
108 {
109         return ll_swap64(ll_load_unaligned_64(addr));
110 }
111
112 static inline void ll_store_unaligned_be16(void *addr, uint16_t val)
113 {
114         ll_store_unaligned_16(addr, ll_swap16(val));
115 }
116
117 static inline void ll_store_unaligned_be32(void *addr, uint32_t val)
118 {
119         ll_store_unaligned_32(addr, ll_swap32(val));
120 }
121
122 static inline void ll_store_unaligned_be64(void *addr, uint64_t val)
123 {
124         ll_store_unaligned_64(addr, ll_swap64(val));
125 }
126
127 // Aligned, big-endian
128
129 static inline uint64_t ll_load_be64(uint64_t *addr)
130 {
131         return ll_load_unaligned_be64(addr);
132 }
133
134 static inline uint32_t ll_load_be32(uint32_t *addr)
135 {
136         return ll_load_unaligned_be32(addr);
137 }
138
139 static inline uint16_t ll_load_be16(uint16_t *addr)
140 {
141         return ll_load_unaligned_be16(addr);
142 }
143
144 static inline void ll_store_be64(uint64_t *addr, uint64_t val)
145 {
146         ll_store_unaligned_be64(addr, val);
147 }
148
149 static inline void ll_store_be32(uint32_t *addr, uint32_t val)
150 {
151         ll_store_unaligned_be32(addr, val);
152 }
153
154 static inline void ll_store_be16(uint16_t *addr, uint16_t val)
155 {
156         ll_store_unaligned_be16(addr, val);
157 }
158
159 // Unaligned, little-endian
160
161 static inline uint64_t ll_load_unaligned_le64(void *addr)
162 {
163         return ll_load_unaligned_64(addr);
164 }
165
166 static inline uint32_t ll_load_unaligned_le32(void *addr)
167 {
168         return ll_load_unaligned_32(addr);
169 }
170
171 static inline uint16_t ll_load_unaligned_le16(void *addr)
172 {
173         return ll_load_unaligned_16(addr);
174 }
175
176 static inline void ll_store_unaligned_le32(void *addr, uint32_t val)
177 {
178         ll_store_unaligned_32(addr, val);
179 }
180
181 static inline void ll_store_unaligned_le16(void *addr, uint16_t val)
182 {
183         ll_store_unaligned_16(addr, val);
184 }
185
186 // Aligned, little-endian
187
188 static inline uint32_t ll_load_le32(uint32_t *addr)
189 {
190         return ll_load_unaligned_le32(addr);
191 }
192
193 static inline uint16_t ll_load_le16(uint16_t *addr)
194 {
195         return ll_load_unaligned_le16(addr);
196 }
197
198 static inline void ll_store_le32(uint32_t *addr, uint32_t val)
199 {
200         ll_store_unaligned_le32(addr, val);
201 }
202
203 static inline void ll_store_le16(uint16_t *addr, uint16_t val)
204 {
205         ll_store_unaligned_le16(addr, val);
206 }
207
208 // PCI/ISA/similar I/O-space; if memory-mapped, addr must include
209 // the base of the I/O window.
210
211 static inline uint8_t ll_in_8(uintptr_t addr)
212 {
213         uint8_t val;
214         asm volatile("inb %w1, %b0" : "=a" (val) : "d" (addr) : "memory");
215         return val;
216 }
217
218 static inline uint16_t ll_in_le16(uintptr_t addr)
219 {
220         uint16_t val;
221         asm volatile("inw %w1, %w0" : "=a" (val) : "d" (addr) : "memory");
222         return val;
223 }
224
225 static inline uint32_t ll_in_le32(uintptr_t addr)
226 {
227         uint32_t val;
228         asm volatile("inl %w1, %0" : "=a" (val) : "d" (addr) : "memory");
229         return val;
230 }
231
232 static inline uint16_t ll_in_be16(uintptr_t addr)
233 {
234         return ll_swap16(ll_in_le16(addr));
235 }
236
237 static inline uint32_t ll_in_be32(uintptr_t addr)
238 {
239         return ll_swap32(ll_in_le32(addr));
240 }
241
242 static inline void ll_out_8(uintptr_t addr, uint8_t val)
243 {
244         asm volatile("outb %b0, %w1" : : "a" (val), "d" (addr) : "memory");
245 }
246
247 static inline void ll_out_le16(uintptr_t addr, uint16_t val)
248 {
249         asm volatile("outw %w0, %w1" : : "a" (val), "d" (addr) : "memory");
250 }
251
252 static inline void ll_out_le32(uintptr_t addr, uint32_t val)
253 {
254         asm volatile("outl %0, %w1" : : "a" (val), "d" (addr) : "memory");
255 }
256
257 static inline void ll_out_be16(uintptr_t addr, uint16_t val)
258 {
259         ll_out_le16(addr, ll_swap16(val));
260 }
261
262 static inline void ll_out_be32(uintptr_t addr, uint32_t val)
263 {
264         ll_out_le32(addr, ll_swap32(val));
265 }
266
267 #endif