iPXE
iobuf.h
Go to the documentation of this file.
1#ifndef _IPXE_IOBUF_H
2#define _IPXE_IOBUF_H
3
4/** @file
5 *
6 * I/O buffers
7 *
8 */
9
10FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11FILE_SECBOOT ( PERMITTED );
12
13#include <stdint.h>
14#include <assert.h>
15#include <ipxe/list.h>
16#include <ipxe/dma.h>
17
18/**
19 * Minimum I/O buffer length and alignment
20 *
21 * alloc_iob() will round up the allocated length to this size if
22 * necessary. This is used on behalf of hardware that is not capable
23 * of auto-padding.
24 *
25 * This length must be at least as large as the largest cacheline size
26 * that we expect to encounter, to allow for platforms where DMA
27 * devices are not in the same coherency domain as the CPU cache.
28 */
29#define IOB_ZLEN 128
30
31/**
32 * A persistent I/O buffer
33 *
34 * This data structure encapsulates a long-lived I/O buffer. The
35 * buffer may be passed between multiple owners, queued for possible
36 * retransmission, etc.
37 *
38 * The datapath model uses a zero-copy fast path for both transmit and
39 * receive directions. Headers and footers are appended/prepended and
40 * stripped in situ as the buffer is passed between layers of the
41 * network stack. Adding or stripping a header or footer is merely a
42 * pointer update: no existing data is ever moved.
43 *
44 * The buffer content is delineated by four pointers, which satisfy
45 * the invariant:
46 *
47 * head <= data <= tail <= end
48 *
49 * The head and end pointers are set when the buffer is first
50 * allocated and are never changed. The data and tail pointers
51 * represent the current data region within the buffer, and are
52 * modified by the accessor functions iob_push(), iob_pull(),
53 * iob_put(), iob_unput() etc.
54 *
55 * The current length of the data region may be obtained using
56 * iob_len(). The space currently between the head and data pointers
57 * is the available headroom and its length may be obtained using
58 * iob_headroom(). Similarly, the space currently between the tail
59 * and end pointers is the available tailroom and its length may be
60 * obtained using iob_tailroom().
61 *
62 * It is the responsibility of the allocator of the I/O buffer to
63 * ensure that sufficient headroom and tailroom exists for all
64 * subsequent users of the I/O buffer. For example: a transmit buffer
65 * allocated by the TCP layer must ensure that there is sufficient
66 * headroom for the TCP headers, the network-layer (IPv4/IPv6)
67 * headers, and the longest possible link-layer header. The lower
68 * layers are permitted to assume that sufficient headroom exists and
69 * may call iob_push() to prepend their headers without performing any
70 * further checks.
71 *
72 * On the receive datapath, I/O buffers are typically allocated by the
73 * device driver. Some care must be taken to ensure that received
74 * buffers that end up being reflected and transmitted (e.g. responses
75 * to ARP requests) contain sufficient headroom. For most devices,
76 * transmit and receive buffers are symmetric and so any receive
77 * buffer will always have sufficient headroom for this purpose.
78 * Devices that require additional transmit headers (such as the Asix
79 * USB NICs) must ensure that additional headroom is allocated in
80 * receive buffers to allow for this reflection.
81 *
82 * Received I/O buffers should always be treated as containing
83 * untrusted data. Device drivers may assume that DMA-capable
84 * hardware will not report erroneous lengths (e.g. a received length
85 * greater than the original allocation length), but all other
86 * consumers must validate the buffer length before accessing its
87 * contents or stripping headers or footers.
88 *
89 * The accessor functions iob_push(), iob_pull(), iob_unput() etc
90 * include assertion checks but do not perform any runtime checks that
91 * the pointer invariant is maintained. In particular, using
92 * iob_pull() or iob_unput() to strip a header without first using
93 * iob_len() to check the available length will result in an invariant
94 * violation that causes the iob_len() calculation to underflow and
95 * report an extremely large buffer length (which is then likely to
96 * cause a false positive for any subsequent buffer length checks).
97 */
98struct io_buffer {
99 /** List of which this buffer is a member
100 *
101 * The list must belong to the current owner of the buffer.
102 * Different owners may maintain different lists (e.g. a
103 * retransmission list for TCP).
104 */
106
107 /** DMA mapping */
109
110 /** Start of the buffer */
111 void *head;
112 /** Start of data */
113 void *data;
114 /** End of data */
115 void *tail;
116 /** End of the buffer */
117 void *end;
118};
119
120/**
121 * Reserve space at start of I/O buffer
122 *
123 * @v iobuf I/O buffer
124 * @v len Length to reserve
125 * @ret data Pointer to new start of buffer
126 */
127static inline void * iob_reserve ( struct io_buffer *iobuf, size_t len ) {
128 iobuf->data += len;
129 iobuf->tail += len;
130 return iobuf->data;
131}
132#define iob_reserve( iobuf, len ) ( { \
133 void *__result; \
134 __result = iob_reserve ( (iobuf), (len) ); \
135 assert ( (iobuf)->tail <= (iobuf)->end ); \
136 __result; } )
137
138/**
139 * Add data to start of I/O buffer
140 *
141 * @v iobuf I/O buffer
142 * @v len Length to add
143 * @ret data Pointer to new start of buffer
144 */
145static inline void * iob_push ( struct io_buffer *iobuf, size_t len ) {
146 iobuf->data -= len;
147 return iobuf->data;
148}
149#define iob_push( iobuf, len ) ( { \
150 void *__result; \
151 __result = iob_push ( (iobuf), (len) ); \
152 assert ( (iobuf)->data >= (iobuf)->head ); \
153 __result; } )
154
155/**
156 * Remove data from start of I/O buffer
157 *
158 * @v iobuf I/O buffer
159 * @v len Length to remove
160 * @ret data Pointer to new start of buffer
161 */
162static inline void * iob_pull ( struct io_buffer *iobuf, size_t len ) {
163 iobuf->data += len;
164 assert ( iobuf->data <= iobuf->tail );
165 return iobuf->data;
166}
167#define iob_pull( iobuf, len ) ( { \
168 void *__result; \
169 __result = iob_pull ( (iobuf), (len) ); \
170 assert ( (iobuf)->data <= (iobuf)->tail ); \
171 __result; } )
172
173/**
174 * Add data to end of I/O buffer
175 *
176 * @v iobuf I/O buffer
177 * @v len Length to add
178 * @ret data Pointer to newly added space
179 */
180static inline void * iob_put ( struct io_buffer *iobuf, size_t len ) {
181 void *old_tail = iobuf->tail;
182 iobuf->tail += len;
183 return old_tail;
184}
185#define iob_put( iobuf, len ) ( { \
186 void *__result; \
187 __result = iob_put ( (iobuf), (len) ); \
188 assert ( (iobuf)->tail <= (iobuf)->end ); \
189 __result; } )
190
191/**
192 * Remove data from end of I/O buffer
193 *
194 * @v iobuf I/O buffer
195 * @v len Length to remove
196 */
197static inline void iob_unput ( struct io_buffer *iobuf, size_t len ) {
198 iobuf->tail -= len;
199}
200#define iob_unput( iobuf, len ) do { \
201 iob_unput ( (iobuf), (len) ); \
202 assert ( (iobuf)->tail >= (iobuf)->data ); \
203 } while ( 0 )
204
205/**
206 * Empty an I/O buffer
207 *
208 * @v iobuf I/O buffer
209 */
210static inline void iob_empty ( struct io_buffer *iobuf ) {
211 iobuf->tail = iobuf->data;
212}
213
214/**
215 * Calculate length of data in an I/O buffer
216 *
217 * @v iobuf I/O buffer
218 * @ret len Length of data in buffer
219 */
220static inline size_t iob_len ( struct io_buffer *iobuf ) {
221 return ( iobuf->tail - iobuf->data );
222}
223
224/**
225 * Calculate available space at start of an I/O buffer
226 *
227 * @v iobuf I/O buffer
228 * @ret len Length of data available at start of buffer
229 */
230static inline size_t iob_headroom ( struct io_buffer *iobuf ) {
231 return ( iobuf->data - iobuf->head );
232}
233
234/**
235 * Calculate available space at end of an I/O buffer
236 *
237 * @v iobuf I/O buffer
238 * @ret len Length of data available at end of buffer
239 */
240static inline size_t iob_tailroom ( struct io_buffer *iobuf ) {
241 return ( iobuf->end - iobuf->tail );
242}
243
244/**
245 * Create a temporary I/O buffer
246 *
247 * @v iobuf I/O buffer
248 * @v data Data buffer
249 * @v len Length of data
250 * @v max_len Length of buffer
251 *
252 * It is sometimes useful to use the iob_xxx() methods on temporary
253 * data buffers.
254 */
255static inline void iob_populate ( struct io_buffer *iobuf,
256 void *data, size_t len, size_t max_len ) {
257 iobuf->head = iobuf->data = data;
258 iobuf->tail = ( data + len );
259 iobuf->end = ( data + max_len );
260}
261
262/**
263 * Disown an I/O buffer
264 *
265 * @v iobuf I/O buffer
266 *
267 * There are many functions that take ownership of the I/O buffer they
268 * are passed as a parameter. The caller should not retain a pointer
269 * to the I/O buffer. Use iob_disown() to automatically nullify the
270 * caller's pointer, e.g.:
271 *
272 * xfer_deliver_iob ( xfer, iob_disown ( iobuf ) );
273 *
274 * This will ensure that iobuf is set to NULL for any code after the
275 * call to xfer_deliver_iob().
276 */
277#define iob_disown( iobuf ) ( { \
278 struct io_buffer *__iobuf = (iobuf); \
279 (iobuf) = NULL; \
280 __iobuf; } )
281
282/**
283 * Map I/O buffer for DMA
284 *
285 * @v iobuf I/O buffer
286 * @v dma DMA device
287 * @v len Length to map
288 * @v flags Mapping flags
289 * @ret rc Return status code
290 */
291static inline __always_inline int iob_map ( struct io_buffer *iobuf,
292 struct dma_device *dma,
293 size_t len, int flags ) {
294 return dma_map ( dma, &iobuf->map, iobuf->data, len, flags );
295}
296
297/**
298 * Map I/O buffer for transmit DMA
299 *
300 * @v iobuf I/O buffer
301 * @v dma DMA device
302 * @ret rc Return status code
303 */
304static inline __always_inline int iob_map_tx ( struct io_buffer *iobuf,
305 struct dma_device *dma ) {
306 return iob_map ( iobuf, dma, iob_len ( iobuf ), DMA_TX );
307}
308
309/**
310 * Map empty I/O buffer for receive DMA
311 *
312 * @v iobuf I/O buffer
313 * @v dma DMA device
314 * @ret rc Return status code
315 */
316static inline __always_inline int iob_map_rx ( struct io_buffer *iobuf,
317 struct dma_device *dma ) {
318 assert ( iob_len ( iobuf ) == 0 );
319 return iob_map ( iobuf, dma, iob_tailroom ( iobuf ), DMA_RX );
320}
321
322/**
323 * Get I/O buffer DMA address
324 *
325 * @v iobuf I/O buffer
326 * @ret addr DMA address
327 */
328static inline __always_inline physaddr_t iob_dma ( struct io_buffer *iobuf ) {
329 return dma ( &iobuf->map, iobuf->data );
330}
331
332/**
333 * Unmap I/O buffer for DMA
334 *
335 * @v iobuf I/O buffer
336 * @v dma DMA device
337 * @ret rc Return status code
338 */
339static inline __always_inline void iob_unmap ( struct io_buffer *iobuf ) {
340 dma_unmap ( &iobuf->map, iob_len ( iobuf ) );
341}
342
343extern struct io_buffer * __malloc alloc_iob_raw ( size_t len, size_t align,
344 size_t offset );
345extern struct io_buffer * __malloc alloc_iob ( size_t len );
346extern void free_iob ( struct io_buffer *iobuf );
347extern struct io_buffer * __malloc alloc_rx_iob ( size_t len,
348 struct dma_device *dma );
349extern void free_rx_iob ( struct io_buffer *iobuf );
350extern void iob_pad ( struct io_buffer *iobuf, size_t min_len );
351extern int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len );
352extern struct io_buffer * iob_concatenate ( struct list_head *list );
353extern struct io_buffer * iob_split ( struct io_buffer *iobuf, size_t len );
354
355#endif /* _IPXE_IOBUF_H */
unsigned long physaddr_t
Definition stdint.h:20
Assertions.
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:61
uint16_t offset
Offset to command line.
Definition bzimage.h:3
ring len
Length.
Definition dwmac.h:226
uint8_t data[48]
Additional event data.
Definition ena.h:11
uint8_t flags
Flags.
Definition ena.h:7
#define __malloc
Declare a pointer returned by a function as a unique memory address as returned by malloc-type functi...
Definition compiler.h:623
#define __always_inline
Declare a function to be always inline.
Definition compiler.h:636
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:921
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:951
static size_t iob_headroom(struct io_buffer *iobuf)
Calculate available space at start of an I/O buffer.
Definition iobuf.h:230
static void iob_empty(struct io_buffer *iobuf)
Empty an I/O buffer.
Definition iobuf.h:210
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
#define iob_push(iobuf, len)
Definition iobuf.h:149
static void iob_populate(struct io_buffer *iobuf, void *data, size_t len, size_t max_len)
Create a temporary I/O buffer.
Definition iobuf.h:255
int iob_ensure_headroom(struct io_buffer *iobuf, size_t len)
Ensure I/O buffer has sufficient headroom.
Definition iobuf.c:235
static __always_inline void iob_unmap(struct io_buffer *iobuf)
Unmap I/O buffer for DMA.
Definition iobuf.h:339
#define iob_put(iobuf, len)
Definition iobuf.h:185
static __always_inline int iob_map_rx(struct io_buffer *iobuf, struct dma_device *dma)
Map empty I/O buffer for receive DMA.
Definition iobuf.h:316
struct io_buffer *__malloc alloc_iob(size_t len)
Allocate I/O buffer.
Definition iobuf.c:131
static __always_inline int iob_map_tx(struct io_buffer *iobuf, struct dma_device *dma)
Map I/O buffer for transmit DMA.
Definition iobuf.h:304
struct io_buffer *__malloc alloc_iob_raw(size_t len, size_t align, size_t offset)
Allocate I/O buffer with specified alignment and offset.
Definition iobuf.c:49
static __always_inline physaddr_t iob_dma(struct io_buffer *iobuf)
Get I/O buffer DMA address.
Definition iobuf.h:328
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:220
void iob_pad(struct io_buffer *iobuf, size_t min_len)
Pad I/O buffer.
Definition iobpad.c:50
#define iob_reserve(iobuf, len)
Definition iobuf.h:132
void free_rx_iob(struct io_buffer *iobuf)
Unmap and free I/O buffer for receive DMA.
Definition iobuf.c:215
#define iob_pull(iobuf, len)
Definition iobuf.h:167
struct io_buffer *__malloc alloc_rx_iob(size_t len, struct dma_device *dma)
Allocate and map I/O buffer for receive DMA.
Definition iobuf.c:188
struct io_buffer * iob_concatenate(struct list_head *list)
Concatenate I/O buffers into a single buffer.
Definition iobuf.c:250
#define iob_unput(iobuf, len)
Definition iobuf.h:200
static size_t iob_tailroom(struct io_buffer *iobuf)
Calculate available space at end of an I/O buffer.
Definition iobuf.h:240
struct io_buffer * iob_split(struct io_buffer *iobuf, size_t len)
Split I/O buffer.
Definition iobuf.c:298
static __always_inline int iob_map(struct io_buffer *iobuf, struct dma_device *dma, size_t len, int flags)
Map I/O buffer for DMA.
Definition iobuf.h:291
DMA mappings.
#define DMA_TX
Device will read data from host memory.
Definition dma.h:135
#define DMA_RX
Device will write data to host memory.
Definition dma.h:138
void dma_unmap(struct dma_mapping *map, size_t len)
Unmap buffer.
physaddr_t dma(struct dma_mapping *map, void *addr)
Get DMA address from virtual address.
Linked lists.
A DMA-capable device.
Definition dma.h:48
A DMA mapping.
Definition dma.h:33
A persistent I/O buffer.
Definition iobuf.h:98
void * data
Start of data.
Definition iobuf.h:113
void * tail
End of data.
Definition iobuf.h:115
struct list_head list
List of which this buffer is a member.
Definition iobuf.h:105
void * end
End of the buffer.
Definition iobuf.h:117
void * head
Start of the buffer.
Definition iobuf.h:111
struct dma_mapping map
DMA mapping.
Definition iobuf.h:108
A doubly-linked list entry (or list head).
Definition list.h:19