AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
io.h
Go to the documentation of this file.
1#ifndef _X86_IO_H
2#define _X86_IO_H
3
4#include <stdint.h>
5
6/*
7 * x86: devices' registers, as I/O ports or memory. Drivers use the
8 * io_in*() and io_out*() functions below with a struct ioaddr, which says
9 * which of the two a device's registers are, and how far apart they are.
10 * The __in* and __out* macros are the port instructions themselves.
11 */
12
13/* read a port */
14#define __inb(port) \
15({ \
16 uint8_t ret; \
17 asm volatile ("inb %%dx, %%al":"=a"(ret):"d"(port)); \
18 ret; \
19})
20
21#define __inw(port) \
22({ \
23 uint16_t ret; \
24 asm volatile ("inw %%dx, %%ax":"=a"(ret):"dN"(port)); \
25 ret; \
26})
27
28#define __inl(port) \
29({ \
30 uint32_t ret; \
31 asm volatile ("inl %%dx, %%eax":"=a"(ret):"d"(port)); \
32 ret; \
33})
34
35/* Read or write `count` 16-bit words through a port. rep insw and rep
36 * outsw change EDI (ESI) and ECX, so those are outputs for the
37 * compiler. */
38#define __insw(port, count, buf) \
39({ \
40 void *__buf = (buf); \
41 uint32_t __count = (count); \
42 asm volatile ("rep insw":"+D"(__buf), "+c"(__count):"d"(port):"memory"); \
43})
44
45#define __outsw(port, count, buf) \
46({ \
47 const void *__buf = (buf); \
48 uint32_t __count = (count); \
49 asm volatile ("rep outsw":"+S"(__buf), "+c"(__count):"d"(port):"memory"); \
50})
51
52/* write a port */
53#define __outb(port, value) \
54({ \
55 asm volatile ("outb %%al, %%dx"::"d"((port)),"a"((value))); \
56})
57
58#define __outw(port, value) \
59({ \
60 asm volatile ("outw %%ax, %%dx"::"d"(port),"a"(value)); \
61})
62
63#define __outl(port, value) \
64({ \
65 asm volatile ("outl %%eax, %%dx"::"d"(port),"a"(value)); \
66})
67
68/* a short delay, for old devices that need time between accesses */
69#define __io_wait() \
70({ \
71 asm volatile ( "jmp 1f\n\t" \
72 "1:jmp 2f\n\t" \
73 "2:" ); \
74})
75
76/* read or write a memory-mapped register */
77#define __mmio_inb(addr) (*((volatile uint8_t *)(addr)))
78#define __mmio_inw(addr) (*((volatile uint16_t *)(addr)))
79#define __mmio_inl(addr) (*((volatile uint32_t *)(addr)))
80#define __mmio_inq(addr) (*((volatile uint64_t *)(addr)))
81
82#define __mmio_outb(addr, v) (*((volatile uint8_t *)(addr)) = v)
83#define __mmio_outw(addr, v) (*((volatile uint16_t *)(addr)) = v)
84#define __mmio_outl(addr, v) (*((volatile uint32_t *)(addr)) = v)
85#define __mmio_outq(addr, v) (*((volatile uint64_t *)(addr)) = v)
86
87/* What a device's registers are: I/O ports, or memory with registers 1,
88 * 2 or 4 bytes apart. */
89#define IOADDR_PORT 1
90#define IOADDR_MMIO8 2
91#define IOADDR_MMIO16 3
92#define IOADDR_MMIO32 4
93
95struct ioaddr {
96 char type; /* IOADDR_* */
97 uintptr_t addr; /* the first port, or the kernel address of the first register */
98};
99
100/* Returns the name of an ioaddr's type, for messages. */
101static inline char *ioaddr_type_str(struct ioaddr *io)
102{
103 switch (io->type) {
104 case IOADDR_PORT:
105 return "pio";
106 case IOADDR_MMIO8:
107 return "mmio8";
108 case IOADDR_MMIO16:
109 return "mmio16";
110 case IOADDR_MMIO32:
111 return "mmio32";
112 }
113
114 return NULL;
115}
116
117/* Read or write register number `off` of a device, 8, 16 or 32 bits at
118 * a time. */
119static inline uint8_t io_in8(struct ioaddr *io, uintptr_t off)
120{
121 switch (io->type) {
122 case IOADDR_PORT:
123 return __inb(io->addr + off);
124 case IOADDR_MMIO8:
125 return __mmio_inb(io->addr + off);
126 case IOADDR_MMIO16:
127 return __mmio_inb(io->addr + (off << 1));
128 case IOADDR_MMIO32:
129 return __mmio_inb(io->addr + (off << 2));
130 }
131
132 return 0;
133}
134
135static inline uint16_t io_in16(struct ioaddr *io, uintptr_t off)
136{
137 switch (io->type) {
138 case IOADDR_PORT:
139 return __inw(io->addr + off);
140 case IOADDR_MMIO8:
141 return __mmio_inw(io->addr + off);
142 case IOADDR_MMIO16:
143 return __mmio_inw(io->addr + (off << 1));
144 case IOADDR_MMIO32:
145 return __mmio_inw(io->addr + (off << 2));
146 }
147
148 return 0;
149}
150
151static inline uint32_t io_in32(struct ioaddr *io, uintptr_t off)
152{
153 switch (io->type) {
154 case IOADDR_PORT:
155 return __inl(io->addr + off);
156 case IOADDR_MMIO8:
157 return __mmio_inl(io->addr + off);
158 case IOADDR_MMIO16:
159 return __mmio_inl(io->addr + (off << 1));
160 case IOADDR_MMIO32:
161 return __mmio_inl(io->addr + (off << 2));
162 }
163
164 return 0;
165}
166
167static inline void io_out8(struct ioaddr *io, uintptr_t off, uint8_t val)
168{
169 switch (io->type) {
170 case IOADDR_PORT:
171 __outb(io->addr + off, val); return;
172 case IOADDR_MMIO8:
173 __mmio_outb(io->addr + off, val); return;
174 case IOADDR_MMIO16:
175 __mmio_outb(io->addr + (off << 1), val); return;
176 case IOADDR_MMIO32:
177 __mmio_outb(io->addr + (off << 2), val); return;
178 }
179}
180
181static inline void io_out16(struct ioaddr *io, uintptr_t off, uint16_t val)
182{
183 switch (io->type) {
184 case IOADDR_PORT:
185 __outw(io->addr + off, val); return;
186 case IOADDR_MMIO8:
187 __mmio_outw(io->addr + off, val); return;
188 case IOADDR_MMIO16:
189 __mmio_outw(io->addr + (off << 1), val); return;
190 case IOADDR_MMIO32:
191 __mmio_outw(io->addr + (off << 2), val); return;
192 }
193}
194
195static inline void io_out32(struct ioaddr *io, uintptr_t off, uint32_t val)
196{
197 switch (io->type) {
198 case IOADDR_PORT:
199 __outl(io->addr + off, val); return;
200 case IOADDR_MMIO8:
201 __mmio_outl(io->addr + off, val); return;
202 case IOADDR_MMIO16:
203 __mmio_outl(io->addr + (off << 1), val); return;
204 case IOADDR_MMIO32:
205 __mmio_outl(io->addr + (off << 2), val); return;
206 }
207}
208
209#endif /* ! _X86_IO_H */
static void io_out16(struct ioaddr *io, uintptr_t off, uint16_t val)
Definition io.h:49
static uint32_t io_in32(struct ioaddr *io, uintptr_t off)
Definition io.h:38
static uint16_t io_in16(struct ioaddr *io, uintptr_t off)
Definition io.h:33
static void io_out32(struct ioaddr *io, uintptr_t off, uint32_t val)
Definition io.h:54
static uint8_t io_in8(struct ioaddr *io, uintptr_t off)
Reads an 8-, 16- or 32-bit register.
Definition io.h:28
static void io_out8(struct ioaddr *io, uintptr_t off, uint8_t val)
Writes an 8-, 16- or 32-bit register.
Definition io.h:44
#define __outw(port, value)
Definition io.h:58
#define __mmio_inl(addr)
Definition io.h:79
static char * ioaddr_type_str(struct ioaddr *io)
Definition io.h:101
#define __outb(port, value)
Definition io.h:53
#define __mmio_outl(addr, v)
Definition io.h:84
#define __mmio_inb(addr)
Definition io.h:77
#define IOADDR_PORT
Definition io.h:89
#define __mmio_outb(addr, v)
Definition io.h:82
#define __inb(port)
Definition io.h:14
#define __mmio_inw(addr)
Definition io.h:78
#define __inw(port)
Definition io.h:21
#define __outl(port, value)
Definition io.h:63
#define IOADDR_MMIO16
Definition io.h:91
#define __mmio_outw(addr, v)
Definition io.h:83
#define IOADDR_MMIO8
Definition io.h:90
#define __inl(port)
Definition io.h:28
#define IOADDR_MMIO32
Definition io.h:92
#define NULL
Definition stddef.h:27
__SIZE_TYPE__ uintptr_t
Definition stddef.h:12
unsigned int uint32_t
Definition stddef.h:22
unsigned char uint8_t
Definition stddef.h:20
unsigned short int uint16_t
Definition stddef.h:21
Where a device's registers are.
Definition io.h:95
uintptr_t addr
Definition io.h:97
char type
Definition io.h:96