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