iPXE
iobuf.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 #include <stdint.h>
27 #include <strings.h>
28 #include <errno.h>
29 #include <ipxe/malloc.h>
30 #include <ipxe/iobuf.h>
31 
32 /** @file
33  *
34  * I/O buffers
35  *
36  */
37 
38 /**
39  * Allocate I/O buffer with specified alignment and offset
40  *
41  * @v len Required length of buffer
42  * @v align Physical alignment
43  * @v offset Offset from physical alignment
44  * @ret iobuf I/O buffer, or NULL if none available
45  *
46  * @c align will be rounded up to the nearest power of two.
47  */
48 struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) {
49  struct io_buffer *iobuf;
50  size_t padding;
51  size_t threshold;
52  unsigned int align_log2;
53  void *data;
54 
55  /* Calculate padding required below alignment boundary to
56  * ensure that a correctly aligned inline struct io_buffer
57  * could fit (regardless of the requested offset).
58  */
59  padding = ( sizeof ( *iobuf ) + __alignof__ ( *iobuf ) - 1 );
60 
61  /* Round up requested alignment to at least the size of the
62  * padding, to simplify subsequent calculations.
63  */
64  if ( align < padding )
65  align = padding;
66 
67  /* Round up alignment to the nearest power of two, avoiding
68  * a potentially undefined shift operation.
69  */
70  align_log2 = fls ( align - 1 );
71  if ( align_log2 >= ( 8 * sizeof ( align ) ) )
72  return NULL;
73  align = ( 1UL << align_log2 );
74 
75  /* Calculate length threshold */
76  assert ( align >= padding );
77  threshold = ( align - padding );
78 
79  /* Allocate buffer plus an inline descriptor as a single unit,
80  * unless doing so would push the total size over the
81  * alignment boundary.
82  */
83  if ( len <= threshold ) {
84 
85  /* Round up buffer length to ensure that struct
86  * io_buffer is aligned.
87  */
88  len += ( ( - len - offset ) & ( __alignof__ ( *iobuf ) - 1 ) );
89 
90  /* Allocate memory for buffer plus descriptor */
91  data = malloc_dma_offset ( len + sizeof ( *iobuf ), align,
92  offset );
93  if ( ! data )
94  return NULL;
95  iobuf = ( data + len );
96 
97  } else {
98 
99  /* Allocate memory for buffer */
100  data = malloc_dma_offset ( len, align, offset );
101  if ( ! data )
102  return NULL;
103 
104  /* Allocate memory for descriptor */
105  iobuf = malloc ( sizeof ( *iobuf ) );
106  if ( ! iobuf ) {
107  free_dma ( data, len );
108  return NULL;
109  }
110  }
111 
112  /* Populate descriptor */
113  iobuf->head = iobuf->data = iobuf->tail = data;
114  iobuf->end = ( data + len );
115 
116  return iobuf;
117 }
118 
119 /**
120  * Allocate I/O buffer
121  *
122  * @v len Required length of buffer
123  * @ret iobuf I/O buffer, or NULL if none available
124  *
125  * The I/O buffer will be physically aligned on its own size (rounded
126  * up to the nearest power of two).
127  */
128 struct io_buffer * alloc_iob ( size_t len ) {
129 
130  /* Pad to minimum length */
131  if ( len < IOB_ZLEN )
132  len = IOB_ZLEN;
133 
134  /* Align buffer on its own size to avoid potential problems
135  * with boundary-crossing DMA.
136  */
137  return alloc_iob_raw ( len, len, 0 );
138 }
139 
140 /**
141  * Free I/O buffer
142  *
143  * @v iobuf I/O buffer
144  */
145 void free_iob ( struct io_buffer *iobuf ) {
146  size_t len;
147 
148  /* Allow free_iob(NULL) to be valid */
149  if ( ! iobuf )
150  return;
151 
152  /* Sanity checks */
153  assert ( iobuf->head <= iobuf->data );
154  assert ( iobuf->data <= iobuf->tail );
155  assert ( iobuf->tail <= iobuf->end );
156 
157  /* Free buffer */
158  len = ( iobuf->end - iobuf->head );
159  if ( iobuf->end == iobuf ) {
160 
161  /* Descriptor is inline */
162  free_dma ( iobuf->head, ( len + sizeof ( *iobuf ) ) );
163 
164  } else {
165 
166  /* Descriptor is detached */
167  free_dma ( iobuf->head, len );
168  free ( iobuf );
169  }
170 }
171 
172 /**
173  * Ensure I/O buffer has sufficient headroom
174  *
175  * @v iobuf I/O buffer
176  * @v len Required headroom
177  *
178  * This function currently only checks for the required headroom; it
179  * does not reallocate the I/O buffer if required. If we ever have a
180  * code path that requires this functionality, it's a fairly trivial
181  * change to make.
182  */
183 int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len ) {
184 
185  if ( iob_headroom ( iobuf ) >= len )
186  return 0;
187  return -ENOBUFS;
188 }
189 
190 /**
191  * Concatenate I/O buffers into a single buffer
192  *
193  * @v list List of I/O buffers
194  * @ret iobuf Concatenated I/O buffer, or NULL on allocation failure
195  *
196  * After a successful concatenation, the list will be empty.
197  */
198 struct io_buffer * iob_concatenate ( struct list_head *list ) {
199  struct io_buffer *iobuf;
200  struct io_buffer *tmp;
201  struct io_buffer *concatenated;
202  size_t len = 0;
203 
204  /* If the list contains only a single entry, avoid an
205  * unnecessary additional allocation.
206  */
207  if ( list_is_singular ( list ) ) {
208  iobuf = list_first_entry ( list, struct io_buffer, list );
209  INIT_LIST_HEAD ( list );
210  return iobuf;
211  }
212 
213  /* Calculate total length */
214  list_for_each_entry ( iobuf, list, list )
215  len += iob_len ( iobuf );
216 
217  /* Allocate new I/O buffer */
218  concatenated = alloc_iob_raw ( len, __alignof__ ( *iobuf ), 0 );
219  if ( ! concatenated )
220  return NULL;
221 
222  /* Move data to new I/O buffer */
223  list_for_each_entry_safe ( iobuf, tmp, list, list ) {
224  list_del ( &iobuf->list );
225  memcpy ( iob_put ( concatenated, iob_len ( iobuf ) ),
226  iobuf->data, iob_len ( iobuf ) );
227  free_iob ( iobuf );
228  }
229 
230  return concatenated;
231 }
232 
233 /**
234  * Split I/O buffer
235  *
236  * @v iobuf I/O buffer
237  * @v len Length to split into a new I/O buffer
238  * @ret split New I/O buffer, or NULL on allocation failure
239  *
240  * Split the first @c len bytes of the existing I/O buffer into a
241  * separate I/O buffer. The resulting buffers are likely to have no
242  * headroom or tailroom.
243  *
244  * If this call fails, then the original buffer will be unmodified.
245  */
246 struct io_buffer * iob_split ( struct io_buffer *iobuf, size_t len ) {
247  struct io_buffer *split;
248 
249  /* Sanity checks */
250  assert ( len <= iob_len ( iobuf ) );
251 
252  /* Allocate new I/O buffer */
253  split = alloc_iob ( len );
254  if ( ! split )
255  return NULL;
256 
257  /* Copy in data */
258  memcpy ( iob_put ( split, len ), iobuf->data, len );
259  iob_pull ( iobuf, len );
260  return split;
261 }
#define iob_pull(iobuf, len)
Definition: iobuf.h:98
static void *__malloc malloc_dma_offset(size_t size, size_t phys_align, size_t offset)
Allocate memory for DMA.
Definition: malloc.h:46
#define iob_put(iobuf, len)
Definition: iobuf.h:116
Error codes.
I/O buffers.
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:145
struct io_buffer * alloc_iob_raw(size_t len, size_t align, size_t offset)
Allocate I/O buffer with specified alignment and offset.
Definition: iobuf.c:48
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition: iobuf.c:128
A doubly-linked list entry (or list head)
Definition: list.h:18
Dynamic memory allocation.
#define list_first_entry(list, type, member)
Get the container of the first entry in a list.
Definition: list.h:333
#define list_del(list)
Delete an entry from a list.
Definition: list.h:119
void * tail
End of data.
Definition: iobuf.h:46
void * memcpy(void *dest, const void *src, size_t len) __nonnull
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
#define list_for_each_entry(pos, head, member)
Iterate over entries in a list.
Definition: list.h:420
static userptr_t size_t offset
Offset of the first segment within the content.
Definition: deflate.h:259
#define list_for_each_entry_safe(pos, tmp, head, member)
Iterate over entries in a list, safe against deletion of the current entry.
Definition: list.h:447
struct io_buffer * iob_concatenate(struct list_head *list)
Concatenate I/O buffers into a single buffer.
Definition: iobuf.c:198
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:151
uint8_t * tmp
Definition: entropy.h:156
void * end
End of the buffer.
Definition: iobuf.h:48
void * malloc(size_t size)
Allocate memory.
Definition: malloc.c:583
#define INIT_LIST_HEAD(list)
Initialise a list head.
Definition: list.h:45
static size_t iob_headroom(struct io_buffer *iobuf)
Calculate available space at start of an I/O buffer.
Definition: iobuf.h:161
#define list_is_singular(list)
Test whether a list has just one entry.
Definition: list.h:149
struct list_head list
List of which this buffer is a member.
Definition: iobuf.h:39
uint32_t len
Length.
Definition: ena.h:14
#define ENOBUFS
No buffer space available.
Definition: errno.h:498
void * head
Start of the buffer.
Definition: iobuf.h:42
struct io_buffer * iob_split(struct io_buffer *iobuf, size_t len)
Split I/O buffer.
Definition: iobuf.c:246
#define IOB_ZLEN
Minimum I/O buffer length.
Definition: iobuf.h:23
void * data
Start of data.
Definition: iobuf.h:44
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
struct arbelprm_port_state_change_st data
Message.
Definition: arbel.h:12
#define fls(x)
Find last (i.e.
Definition: strings.h:166
int iob_ensure_headroom(struct io_buffer *iobuf, size_t len)
Ensure I/O buffer has sufficient headroom.
Definition: iobuf.c:183
static void free_dma(void *ptr, size_t size)
Free memory allocated with malloc_dma()
Definition: malloc.h:81
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
String functions.
A persistent I/O buffer.
Definition: iobuf.h:32