PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
ioring.h
Go to the documentation of this file.
1#ifndef _SYS_IORING_H
2#define _SYS_IORING_H 1
3
4#include <stdatomic.h>
5#include <stddef.h>
6#include <stdint.h>
7#include <sys/defs.h>
8#include <sys/list.h>
9
10#if defined(__cplusplus)
11extern "C"
12{
13#endif
14
15#include "_libstd/MAX_NAME.h"
16#include "_libstd/MAX_PATH.h"
17#include "_libstd/clock_t.h"
18#include "_libstd/errno_t.h"
19#include "_libstd/fd_t.h"
20#include "_libstd/ssize_t.h"
21
22/**
23 * @addtogroup kernel_io
24 * @{
25 */
26
27#define IO_OFF_CUR ((ssize_t) - 1) ///< Use the current file offset.
28
29typedef uint64_t io_whence_t; ///< Seek origin type.
30#define IO_SEEK_SET (1) ///< Use the start of the file.
31#define IO_SEEK_END (2) ///< Use the end of the file.
32#define IO_SEEK_CUR (3) ///< Use the current file offset.
33
34typedef uint64_t io_events_t; ///< Poll events type.
35#define IO_POLL_READ (1 << 0) ///< File descriptor is ready to read.
36#define IO_POLL_WRITE (1 << 1) ///< File descriptor is ready to write
37#define IO_POLL_ERROR (1 << 2) ///< File descriptor caused an error.
38#define IO_POLL_HUP (1 << 3) ///< File descriptor is closed.
39#define IO_POLL_NVAL (1 << 4) ///< Invalid file descriptor.
40
41typedef uint32_t io_op_t; ///< I/O operation code type.
42#define IO_OP_NOP 0 ///< No-op operation.
43#define IO_OP_READ 1 ///< Read operation.
44#define IO_OP_WRITE 2 ///< Write operation.
45#define IO_OP_POLL 3 ///< Poll operation.
46#define IO_OP_MAX 4 ///< The maximum number of operation.
47
48typedef uint32_t sqe_flags_t; ///< Submission queue entry (SQE) flags.
49#define SQE_REG0 (0) ///< The first register.
50#define SQE_REG1 (1) ///< The second register.
51#define SQE_REG2 (2) ///< The third register.
52#define SQE_REG3 (3) ///< The fourth register.
53#define SQE_REG4 (4) ///< The fifth register.
54#define SQE_REG5 (5) ///< The sixth register.
55#define SQE_REG6 (6) ///< The seventh register.
56#define SQE_REG_NONE (7) ///< No register.
57#define SQE_REGS_MAX (7) ///< The maximum number of registers.
58#define SQE_REG_SHIFT (3) ///< The bitshift for each register specifier in a `sqe_flags_t`.
59#define SQE_REG_MASK (0b111) ///< The bitmask for a register specifier in a `sqe_flags_t`.
60
61#define SQE_LOAD0 (0) ///< The offset to specify the register to load into the first argument.
62#define SQE_LOAD1 (SQE_LOAD0 + SQE_REG_SHIFT) ///< The offset to specify the register to load into the second argument.
63#define SQE_LOAD2 (SQE_LOAD1 + SQE_REG_SHIFT) ///< The offset to specify the register to load into the third argument.
64#define SQE_LOAD3 (SQE_LOAD2 + SQE_REG_SHIFT) ///< The offset to specify the register to load into the fourth argument.
65#define SQE_LOAD4 (SQE_LOAD3 + SQE_REG_SHIFT) ///< The offset to specify the register to load into the fifth argument.
66#define SQE_SAVE (SQE_LOAD4 + SQE_REG_SHIFT) ///< The offset to specify the register to save the result into.
67
68#define _SQE_FLAGS (SQE_SAVE + SQE_REG_SHIFT) ///< The bitshift for where bit flags start in a `sqe_flags_t`.
69
70/**
71 * Only process the next SQE when this one completes successfully) only applies within one `enter()` call.
72 */
73#define SQE_LINK (1 << (_SQE_FLAGS))
74/**
75 * Like `SQE_LINK` but will process the next SQE even if this one fails.
76 */
77#define SQE_HARDLINK (1 << (_SQE_FLAGS + 1))
78
79/**
80 * @brief Asynchronous submission queue entry (SQE).
81 * @struct sqe_t
82 *
83 * @warning It is the responsibility of userspace to ensure that any pointers
84 * passed to the kernel remain valid until the operation is complete.
85 *
86 * @see kernel_io for more information for each possible operation.
87 */
88typedef struct sqe
89{
90 clock_t timeout; ///< Timeout for the operation, `CLOCKS_NEVER` for no timeout.
91 void* data; ///< Private data for the operation, will be returned in the completion entry.
92 io_op_t op; ///< The operation to perform.
93 sqe_flags_t flags; ///< Submission flags.
94 union {
97 };
98 union {
100 void* buffer;
102 };
103 union {
105 size_t count;
106 };
107 union {
110 };
111 union {
113 };
114} sqe_t;
115
116#ifdef static_assert
117static_assert(sizeof(sqe_t) == 64, "sqe_t is not 64 bytes");
118#endif
119
120/**
121 * @brief Macro to create an asynchronous submission queue entry (SQE).
122 *
123 * @param _op The operation to perform.
124 * @param _flags Submission flags.
125 * @param _timeout Timeout for the operation, `CLOCKS_NEVER` for no timeout.
126 * @param _data Private data for the operation.
127 */
128#define SQE_CREATE(_op, _flags, _timeout, _data) \
129 { \
130 .op = (_op), \
131 .flags = (_flags), \
132 .timeout = (_timeout), \
133 .data = (void*)(_data), \
134 }
135
136/**
137 * @brief Asynchronous completion queue entry (CQE).
138 * @struct cqe_t
139 *
140 * @see kernel_io for more information on the possible operations.
141 */
142typedef struct cqe
143{
144 io_op_t op; ///< The operation that was performed.
145 errno_t error; ///< Error code, if not equal to `EOK` an error occurred.
146 void* data; ///< Private data from the submission entry.
147 union {
149 size_t count;
150 void* ptr;
153 };
154 uint64_t _padding[1];
155} cqe_t;
156
157#ifdef static_assert
158static_assert(sizeof(cqe_t) == 32, "cqe_t is not 32 bytes");
159#endif
160
161/**
162 * @brief Shared ring control structure.
163 * @struct ioring_ctrl_t
164 *
165 * Used as the intermediate between userspace and the kernel.
166 *
167 * @note The structure is aligned in such a way to reduce false sharing.
168 *
169 */
170typedef struct ALIGNED(64) ioring_ctrl
171{
172 atomic_uint32_t shead; ///< Submission head index, updated by the kernel.
173 atomic_uint32_t ctail; ///< Completion tail index, updated by the kernel.
174 uint8_t _padding0[64 - sizeof(atomic_uint32_t) * 2];
175 atomic_uint32_t stail; ///< Submission tail index, updated by userspace.
176 atomic_uint32_t chead; ///< Completion head index, updated by userspace.
177 uint8_t _padding1[64 - sizeof(atomic_uint32_t) * 2];
178 atomic_uint64_t regs[SQE_REGS_MAX] ALIGNED(64); ///< General purpose registers.
179 uint8_t _reserved[8];
181
182/**
183 * @}
184 * @brief Programmable submission/completion interface.
185 * @defgroup libstd_sys_ioring User-side I/O Ring Interface
186 * @ingroup libstd
187 *
188 * The ring interface acts as the interface for all asynchronous operations in the kernel.
189 *
190 * @see kernel_io for more information about the I/O ring system.
191 *
192 * @{
193 */
194
195typedef uint64_t ioring_id_t; ///< I/O ring ID type.
196
197/**
198 * @brief User I/O ring structure.
199 * @struct ioring_t
200 *
201 * The kernel and userspace will have their own instances of this structure.
202 */
203typedef struct ioring
204{
205 ioring_ctrl_t* ctrl; ///< Pointer to the shared control structure.
206 ioring_id_t id; ///< The ID of the ring.
207 sqe_t* squeue; ///< Pointer to the submission queue.
208 size_t sentries; ///< Number of entries in the submission queue.
209 size_t smask; ///< Bitmask for submission queue (sentries - 1).
210 cqe_t* cqueue; ///< Pointer to the completion queue.
211 size_t centries; ///< Number of entries in the completion queue.
212 size_t cmask; ///< Bitmask for completion queue (centries - 1).
213} ioring_t;
214
215/**
216 * @brief System call to initialize the I/O ring.
217 *
218 * This system call will populate the given structure with the necessary pointers and metadata for the submission and
219 * completion ring.
220 *
221 * @param ring Pointer to the ring structure to populate.
222 * @param address Desired address to allocate the ring, or `NULL` to let the kernel choose.
223 * @param sentries Number of entires to allocate for the submission queue, must be a power of two.
224 * @param centries Number of entries to allocate for the completion queue, must be a power of two.
225 * @return On success, the ID of the new I/O ring. On failure, `ERR` and `errno` is set.
226 */
227ioring_id_t ioring_setup(ioring_t* ring, void* address, size_t sentries, size_t centries);
228
229/**
230 * @brief System call to deinitialize the I/O ring.
231 *
232 * @param id The ID of the I/O ring to teardown.
233 * @return On success, `0`. On failure, `ERR` and `errno` is set.
234 */
236
237/**
238 * @brief System call to notify the kernel of new submission queue entries (SQEs).
239 *
240 * @param id The ID of the I/O ring to notify.
241 * @param amount The number of SQEs that the kernel should process.
242 * @param wait The minimum number of completion queue entries (CQEs) to wait for.
243 * @return On success, the number of SQEs successfully processed. On failure, `ERR` and `errno` is set.
244 */
245uint64_t ioring_enter(ioring_id_t id, size_t amount, size_t wait);
246
247/**
248 * @brief Pushes a submission queue entry (SQE) to the submission queue.
249 *
250 * After pushing SQEs, `enter()` must be called to notify the kernel of the new entries.
251 *
252 * @param ring Pointer to the I/O ring structure.
253 * @param sqe Pointer to the SQE to push.
254 * @return `true` if the SQE was pushed, `false` if the submission queue is full.
255 */
256static inline bool sqe_push(ioring_t* ring, sqe_t* sqe)
257{
260
261 if ((tail - head) >= ring->sentries)
262 {
263 return false;
264 }
265
266 ring->squeue[tail & ring->smask] = *sqe;
267 atomic_store_explicit(&ring->ctrl->stail, tail + 1, memory_order_release);
268
269 return true;
270}
271
272/**
273 * @brief Pops a completion queue entry (CQE) from the completion queue.
274 *
275 * @param ring Pointer to the I/O ring structure.
276 * @param cqe Pointer to the CQE to pop.
277 * @return `true` if a CQE was popped, `false` if the completion queue is empty.
278 */
279static inline bool cqe_pop(ioring_t* ring, cqe_t* cqe)
280{
283
284 if (head == tail)
285 {
286 return false;
287 }
288
289 *cqe = ring->cqueue[head & ring->cmask];
290 atomic_store_explicit(&ring->ctrl->chead, head + 1, memory_order_release);
291
292 return true;
293}
294
295/** @} */
296
297#if defined(__cplusplus)
298}
299#endif
300
301#endif
int errno_t
Definition errno_t.h:4
static uintptr_t address
Mapped virtual address of the HPET registers.
Definition hpet.c:96
ioring_ctrl_t
Definition ioring.h:180
uint32_t io_op_t
I/O operation code type.
Definition ioring.h:41
#define SQE_REGS_MAX
The maximum number of registers.
Definition ioring.h:57
uint64_t io_whence_t
Seek origin type.
Definition ioring.h:29
uint64_t io_events_t
Poll events type.
Definition ioring.h:34
uint32_t sqe_flags_t
Submission queue entry (SQE) flags.
Definition ioring.h:48
#define ALIGNED(alignment)
GCC aligned attribute.
Definition defs.h:23
uint64_t ioring_enter(ioring_id_t id, size_t amount, size_t wait)
System call to notify the kernel of new submission queue entries (SQEs).
Definition ioring_enter.c:5
uint64_t ioring_teardown(ioring_id_t id)
System call to deinitialize the I/O ring.
uint64_t ioring_id_t
I/O ring ID type.
Definition ioring.h:195
static bool sqe_push(ioring_t *ring, sqe_t *sqe)
Pushes a submission queue entry (SQE) to the submission queue.
Definition ioring.h:256
static bool cqe_pop(ioring_t *ring, cqe_t *cqe)
Pops a completion queue entry (CQE) from the completion queue.
Definition ioring.h:279
ioring_id_t ioring_setup(ioring_t *ring, void *address, size_t sentries, size_t centries)
System call to initialize the I/O ring.
Definition ioring_setup.c:5
__INT64_TYPE__ ssize_t
Signed size type.
Definition ssize_t.h:11
__UINT64_TYPE__ fd_t
File descriptor type.
Definition fd_t.h:10
__UINT64_TYPE__ clock_t
A nanosecond time.
Definition clock_t.h:13
@ memory_order_release
Definition stdatomic.h:119
@ memory_order_relaxed
Definition stdatomic.h:116
@ memory_order_acquire
Definition stdatomic.h:118
#define atomic_load_explicit(object, order)
Definition stdatomic.h:264
#define atomic_store_explicit(object, desired, order)
Definition stdatomic.h:265
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
Asynchronous completion queue entry (CQE).
Definition ioring.h:143
errno_t error
Error code, if not equal to EOK an error occurred.
Definition ioring.h:145
io_op_t op
The operation that was performed.
Definition ioring.h:144
fd_t fd
Definition ioring.h:148
uint64_t _result
Definition ioring.h:152
size_t count
Definition ioring.h:149
void * ptr
Definition ioring.h:150
void * data
Private data from the submission entry.
Definition ioring.h:146
io_events_t events
Definition ioring.h:151
Shared ring control structure.
User I/O ring structure.
Definition ioring.h:204
ioring_ctrl_t * ctrl
Pointer to the shared control structure.
Definition ioring.h:205
sqe_t * squeue
Pointer to the submission queue.
Definition ioring.h:207
size_t smask
Bitmask for submission queue (sentries - 1).
Definition ioring.h:209
cqe_t * cqueue
Pointer to the completion queue.
Definition ioring.h:210
size_t cmask
Bitmask for completion queue (centries - 1).
Definition ioring.h:212
size_t sentries
Number of entries in the submission queue.
Definition ioring.h:208
size_t centries
Number of entries in the completion queue.
Definition ioring.h:211
ioring_id_t id
The ID of the ring.
Definition ioring.h:206
Asynchronous submission queue entry (SQE).
Definition ioring.h:89
uint64_t arg1
Definition ioring.h:99
void * data
Private data for the operation, will be returned in the completion entry.
Definition ioring.h:91
uint64_t arg2
Definition ioring.h:104
uint64_t arg0
Definition ioring.h:95
void * buffer
Definition ioring.h:100
ssize_t offset
Definition ioring.h:109
fd_t fd
Definition ioring.h:96
uint64_t arg4
Definition ioring.h:112
size_t count
Definition ioring.h:105
io_events_t events
Definition ioring.h:101
io_op_t op
The operation to perform.
Definition ioring.h:92
clock_t timeout
Timeout for the operation, CLOCKS_NEVER for no timeout.
Definition ioring.h:90
sqe_flags_t flags
Submission flags.
Definition ioring.h:93
uint64_t arg3
Definition ioring.h:108