iPXE
xferbuf.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2012 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 (at your option) 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
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27#include <stdlib.h>
28#include <string.h>
29#include <errno.h>
30#include <ipxe/xfer.h>
31#include <ipxe/iobuf.h>
32#include <ipxe/umalloc.h>
33#include <ipxe/profile.h>
34#include <ipxe/image.h>
35#include <ipxe/xferbuf.h>
36
37/** @file
38 *
39 * Data transfer buffers
40 *
41 * @anchor xferbuf
42 *
43 * Data transfer buffers provide an abstraction of an underlying
44 * storage buffer, with strictly bounds-checking accessors for reading
45 * and writing data and optional automatic resizing. They are
46 * designed primarily to act as the ultimate sink for receiving I/O
47 * buffers containing downloaded data, after all protocol-level
48 * framing has been stripped.
49 *
50 * The underlying storage buffer may be backed by a malloc()
51 * allocation, a umalloc() allocation, a fixed-size buffer, a
52 * downloadable image's data, or a /dev/null-style void buffer.
53 *
54 * Consumers of data buffers pass an offset and length when reading
55 * from or writing to the buffer. Any integer overflow will be
56 * reported as a failure (and no data will be read or written).
57 *
58 * Attempting to read beyond the end of a buffer will always fail.
59 * Attempting to write beyond the end of a buffer will automatically
60 * attempt to resize the buffer to accommodate the write (and will
61 * fail if this cannot be done).
62 *
63 * An object interface may choose to implement the xfer_buffer()
64 * interface method to provide another object with direct access to
65 * its own data buffer. This is something of a layering violation,
66 * but is required to support the badly designed PeerDist protocol
67 * which fails to provide the AES initialisation vector until after
68 * the encrypted data has all been received.
69 */
70
71/** Data delivery profiler */
72static struct profiler xferbuf_deliver_profiler __profiler =
73 { .name = "xferbuf.deliver" };
74
75/** Data write profiler */
76static struct profiler xferbuf_write_profiler __profiler =
77 { .name = "xferbuf.write" };
78
79/** Data read profiler */
80static struct profiler xferbuf_read_profiler __profiler =
81 { .name = "xferbuf.read" };
82
83/**
84 * Free data transfer buffer
85 *
86 * @v xferbuf Data transfer buffer
87 */
88void xferbuf_free ( struct xfer_buffer *xferbuf ) {
89
90 xferbuf->op->realloc ( xferbuf, 0 );
91 xferbuf->len = 0;
92 xferbuf->max = 0;
93 xferbuf->pos = 0;
94}
95
96/**
97 * Ensure that data transfer buffer is large enough for the specified size
98 *
99 * @v xferbuf Data transfer buffer
100 * @v len Required minimum size
101 * @ret rc Return status code
102 */
103static int xferbuf_ensure_size ( struct xfer_buffer *xferbuf, size_t len ) {
104 int rc;
105
106 /* Record maximum required size */
107 if ( len > xferbuf->max )
108 xferbuf->max = len;
109
110 /* If buffer is already large enough, do nothing */
112 return 0;
113
114 /* Extend buffer */
115 if ( ( rc = xferbuf->op->realloc ( xferbuf, len ) ) != 0 ) {
116 DBGC ( xferbuf, "XFERBUF %p could not extend buffer to "
117 "%zd bytes: %s\n", xferbuf, len, strerror ( rc ) );
118 return rc;
119 }
120 xferbuf->len = len;
121
122 return 0;
123}
124
125/**
126 * Write to data transfer buffer
127 *
128 * @v xferbuf Data transfer buffer
129 * @v offset Starting offset
130 * @v data Data to write
131 * @v len Length of data
132 */
133int xferbuf_write ( struct xfer_buffer *xferbuf, size_t offset,
134 const void *data, size_t len ) {
135 size_t max_len;
136 void *raw;
137 int rc;
138
139 /* Check for overflow */
140 max_len = ( offset + len );
141 if ( max_len < offset )
142 return -EOVERFLOW;
143
144 /* Ensure buffer is large enough to contain this write */
145 if ( ( rc = xferbuf_ensure_size ( xferbuf, max_len ) ) != 0 )
146 return rc;
147
148 /* Copy data to buffer (if non-void) */
149 raw = xferbuf->op->access ( xferbuf );
150 profile_start ( &xferbuf_write_profiler );
151 if ( raw )
152 memcpy ( ( raw + offset ), data, len );
153 profile_stop ( &xferbuf_write_profiler );
154
155 return 0;
156}
157
158/**
159 * Read from data transfer buffer
160 *
161 * @v xferbuf Data transfer buffer
162 * @v offset Starting offset
163 * @v data Data to write
164 * @v len Length of data
165 */
166int xferbuf_read ( struct xfer_buffer *xferbuf, size_t offset,
167 void *data, size_t len ) {
168 const void *raw;
169
170 /* Check that read is within buffer range */
171 if ( ( offset > xferbuf->len ) ||
172 ( len > ( xferbuf->len - offset ) ) )
173 return -ENOENT;
174
175 /* Access raw data buffer */
176 raw = xferbuf->op->access ( xferbuf );
177
178 /* Check that buffer is non-void */
179 if ( len && ( ! raw ) )
180 return -ENOTTY;
181
182 /* Copy data from buffer */
183 profile_start ( &xferbuf_read_profiler );
184 memcpy ( data, ( raw + offset ), len );
185 profile_stop ( &xferbuf_read_profiler );
186
187 return 0;
188}
189
190/**
191 * Add received data to data transfer buffer
192 *
193 * @v xferbuf Data transfer buffer
194 * @v iobuf I/O buffer
195 * @v meta Data transfer metadata
196 * @ret rc Return status code
197 */
198int xferbuf_deliver ( struct xfer_buffer *xferbuf, struct io_buffer *iobuf,
199 struct xfer_metadata *meta ) {
200 size_t len = iob_len ( iobuf );
201 size_t pos;
202 int rc;
203
204 /* Start profiling */
205 profile_start ( &xferbuf_deliver_profiler );
206
207 /* Calculate new buffer position */
208 pos = xferbuf->pos;
209 if ( meta->flags & XFER_FL_ABS_OFFSET )
210 pos = 0;
211 pos += meta->offset;
212
213 /* Write data to buffer */
214 if ( ( rc = xferbuf_write ( xferbuf, pos, iobuf->data, len ) ) != 0 )
215 goto done;
216
217 /* Update current buffer position */
218 xferbuf->pos = ( pos + len );
219
220 done:
221 free_iob ( iobuf );
222 profile_stop ( &xferbuf_deliver_profiler );
223 return rc;
224}
225
226/**
227 * Access raw pointer based data buffer
228 *
229 * @v xferbuf Data transfer buffer
230 * @ret raw Raw data pointer
231 */
232static void * xferbuf_raw_access ( struct xfer_buffer *xferbuf ) {
233
234 return xferbuf->data;
235}
236
237/**
238 * Reallocate malloc()-based data transfer buffer
239 *
240 * @v xferbuf Data transfer buffer
241 * @v len New length (or zero to free buffer)
242 * @ret rc Return status code
243 */
244static int xferbuf_malloc_realloc ( struct xfer_buffer *xferbuf, size_t len ) {
245 void *new_data;
246
247 new_data = realloc ( xferbuf->data, len );
248 if ( ! new_data )
249 return -ENOSPC;
250 xferbuf->data = new_data;
251 return 0;
252}
253
254/** malloc()-based data buffer operations */
259
260/**
261 * Reallocate umalloc()-based data transfer buffer
262 *
263 * @v xferbuf Data transfer buffer
264 * @v len New length (or zero to free buffer)
265 * @ret rc Return status code
266 */
267static int xferbuf_umalloc_realloc ( struct xfer_buffer *xferbuf, size_t len ) {
268 void *new_udata;
269
270 new_udata = urealloc ( xferbuf->data, len );
271 if ( ! new_udata )
272 return -ENOSPC;
273 xferbuf->data = new_udata;
274 return 0;
275}
276
277/** umalloc()-based data buffer operations */
282
283/**
284 * Reallocate fixed-size data transfer buffer
285 *
286 * @v xferbuf Data transfer buffer
287 * @v len New length (or zero to free buffer)
288 * @ret rc Return status code
289 */
290static int xferbuf_fixed_realloc ( struct xfer_buffer *xferbuf, size_t len ) {
291
292 /* Refuse to allocate extra space */
293 if ( len > xferbuf->len ) {
294 /* Note that EFI relies upon this error mapping to
295 * EFI_BUFFER_TOO_SMALL.
296 */
297 return -ERANGE;
298 }
299
300 return 0;
301}
302
303/** Fixed-size data buffer operations */
308
309/**
310 * Reallocate void data transfer buffer
311 *
312 * @v xferbuf Data transfer buffer
313 * @v len New length (or zero to free buffer)
314 * @ret rc Return status code
315 */
316static int xferbuf_void_realloc ( struct xfer_buffer *xferbuf,
317 size_t len __unused ) {
318
319 /* Succeed without ever allocating data */
320 assert ( xferbuf->data == NULL );
321 return 0;
322}
323
324/** Void data buffer operations */
329
330/**
331 * Reallocate image-based data transfer buffer
332 *
333 * @v xferbuf Data transfer buffer
334 * @v len New length (or zero to free buffer)
335 * @ret rc Return status code
336 */
337static int xferbuf_image_realloc ( struct xfer_buffer *xferbuf, size_t len ) {
338 struct image *image = xferbuf->data;
339 int rc;
340
341 /* Resize image */
342 if ( ( rc = image_set_len ( image, len ) ) != 0 )
343 return rc;
344
345 return 0;
346}
347
348/**
349 * Access image-based data transfer buffer
350 *
351 * @v xferbuf Data transfer buffer
352 * @ret raw Raw data pointer
353 */
354static void * xferbuf_image_access ( struct xfer_buffer *xferbuf ) {
355 struct image *image = xferbuf->data;
356
357 return image->rwdata;
358}
359
360/** Image-based data buffer operations */
365
366/**
367 * Get underlying data transfer buffer
368 *
369 * @v interface Data transfer interface
370 * @ret xferbuf Data transfer buffer, or NULL on error
371 *
372 * This call will check that the xfer_buffer() handler belongs to the
373 * destination interface which also provides xfer_deliver() for this
374 * interface.
375 *
376 * This is done to prevent accidental accesses to a data transfer
377 * buffer which may be located behind a non-transparent datapath via a
378 * series of pass-through interfaces.
379 */
380struct xfer_buffer * xfer_buffer ( struct interface *intf ) {
381 struct interface *dest;
382 xfer_buffer_TYPE ( void * ) *op =
384 void *object = intf_object ( dest );
385 struct interface *xfer_deliver_dest;
386 struct xfer_buffer *xferbuf;
387
388 /* Check that this operation is provided by the same interface
389 * which handles xfer_deliver().
390 */
391 ( void ) intf_get_dest_op ( intf, xfer_deliver, &xfer_deliver_dest );
392
393 if ( op && ( dest == xfer_deliver_dest ) ) {
394 xferbuf = op ( object );
395 } else {
396 /* Default is to not have a data transfer buffer */
397 xferbuf = NULL;
398 }
399
400 intf_put ( xfer_deliver_dest );
401 intf_put ( dest );
402 return xferbuf;
403}
#define NULL
NULL pointer (VOID *).
Definition Base.h:321
__be32 raw[7]
Definition CIB_PRM.h:0
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
if(len >=6 *4) __asm__ __volatile__("movsl" if(len >=5 *4) __asm__ __volatile__("movsl" if(len >=4 *4) __asm__ __volatile__("movsl" if(len >=3 *4) __asm__ __volatile__("movsl" if(len >=2 *4) __asm__ __volatile__("movsl" if(len >=1 *4) __asm__ __volatile__("movsl" if((len % 4) >=2) __asm__ __volatile__("movsw" if((len % 2) >=1) __asm__ __volatile__("movsb" retur dest)
Definition string.h:151
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:61
struct bofm_section_header done
Definition bofm_test.c:46
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 meta
Metadata flags.
Definition ena.h:3
Error codes.
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:598
#define DBGC(...)
Definition compiler.h:530
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:921
#define ENOENT
No such file or directory.
Definition errno.h:558
#define ENOSPC
No space left on device.
Definition errno.h:593
#define EOVERFLOW
Value too large to be stored in data type.
Definition errno.h:653
#define ERANGE
Result too large.
Definition errno.h:683
#define ENOTTY
Inappropriate I/O control operation.
Definition errno.h:638
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:951
int image_set_len(struct image *image, size_t len)
Set image length.
Definition image.c:249
Executable images.
Profiling.
#define __profiler
Declare a profiler.
Definition profile.h:61
static void profile_stop(struct profiler *profiler)
Stop profiling.
Definition profile.h:174
static void profile_start(struct profiler *profiler)
Start profiling.
Definition profile.h:161
User memory allocation.
void * urealloc(void *ptr, size_t new_size)
Reallocate external memory.
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * intf_object(struct interface *intf)
Get pointer to object containing object interface.
Definition interface.c:160
void intf_put(struct interface *intf)
Decrement reference count on an object interface.
Definition interface.c:150
#define intf_get_dest_op(intf, type, dest)
Get object interface destination and operation method.
Definition interface.h:270
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
I/O buffers.
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:220
void * realloc(void *old_ptr, size_t new_size)
Reallocate memory.
Definition malloc.c:663
static uint16_t struct vmbus_xfer_pages_operations * op
Definition netvsc.h:327
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
An executable image.
Definition image.h:24
void * rwdata
Writable data.
Definition image.h:53
An object interface.
Definition interface.h:125
struct interface * intf
Original interface.
Definition interface.h:159
A persistent I/O buffer.
Definition iobuf.h:98
void * data
Start of data.
Definition iobuf.h:113
A data structure for storing profiling information.
Definition profile.h:27
Data transfer buffer operations.
Definition xferbuf.h:35
int(* realloc)(struct xfer_buffer *xferbuf, size_t len)
Reallocate data buffer.
Definition xferbuf.h:42
void *(* access)(struct xfer_buffer *xferbuf)
Access data buffer.
Definition xferbuf.h:49
A data transfer buffer.
Definition xferbuf.h:21
size_t len
Size of data.
Definition xferbuf.h:25
size_t max
Maximum required size of data.
Definition xferbuf.h:27
size_t pos
Current offset within data.
Definition xferbuf.h:29
struct xfer_buffer_operations * op
Data transfer buffer operations.
Definition xferbuf.h:31
void * data
Data.
Definition xferbuf.h:23
Data transfer metadata.
Definition xfer.h:23
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition xfer.c:195
Data transfer interfaces.
#define XFER_FL_ABS_OFFSET
Offset is absolute.
Definition xfer.h:48
struct xfer_buffer_operations xferbuf_malloc_operations
malloc()-based data buffer operations
Definition xferbuf.c:255
struct xfer_buffer * xfer_buffer(struct interface *intf)
Get underlying data transfer buffer.
Definition xferbuf.c:380
static int xferbuf_void_realloc(struct xfer_buffer *xferbuf, size_t len __unused)
Reallocate void data transfer buffer.
Definition xferbuf.c:316
struct xfer_buffer_operations xferbuf_image_operations
Image-based data buffer operations.
Definition xferbuf.c:361
int xferbuf_read(struct xfer_buffer *xferbuf, size_t offset, void *data, size_t len)
Read from data transfer buffer.
Definition xferbuf.c:166
static int xferbuf_umalloc_realloc(struct xfer_buffer *xferbuf, size_t len)
Reallocate umalloc()-based data transfer buffer.
Definition xferbuf.c:267
static int xferbuf_malloc_realloc(struct xfer_buffer *xferbuf, size_t len)
Reallocate malloc()-based data transfer buffer.
Definition xferbuf.c:244
static int xferbuf_ensure_size(struct xfer_buffer *xferbuf, size_t len)
Ensure that data transfer buffer is large enough for the specified size.
Definition xferbuf.c:103
int xferbuf_write(struct xfer_buffer *xferbuf, size_t offset, const void *data, size_t len)
Write to data transfer buffer.
Definition xferbuf.c:133
struct xfer_buffer_operations xferbuf_void_operations
Void data buffer operations.
Definition xferbuf.c:325
static void * xferbuf_raw_access(struct xfer_buffer *xferbuf)
Access raw pointer based data buffer.
Definition xferbuf.c:232
void xferbuf_free(struct xfer_buffer *xferbuf)
Free data transfer buffer.
Definition xferbuf.c:88
static void * xferbuf_image_access(struct xfer_buffer *xferbuf)
Access image-based data transfer buffer.
Definition xferbuf.c:354
struct xfer_buffer_operations xferbuf_fixed_operations
Fixed-size data buffer operations.
Definition xferbuf.c:304
struct xfer_buffer_operations xferbuf_umalloc_operations
umalloc()-based data buffer operations
Definition xferbuf.c:278
int xferbuf_deliver(struct xfer_buffer *xferbuf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Add received data to data transfer buffer.
Definition xferbuf.c:198
static int xferbuf_fixed_realloc(struct xfer_buffer *xferbuf, size_t len)
Reallocate fixed-size data transfer buffer.
Definition xferbuf.c:290
static int xferbuf_image_realloc(struct xfer_buffer *xferbuf, size_t len)
Reallocate image-based data transfer buffer.
Definition xferbuf.c:337
Data transfer buffers.
#define xfer_buffer_TYPE(object_type)
Definition xferbuf.h:138