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 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_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/xferbuf.h>
35 
36 /** @file
37  *
38  * Data transfer buffer
39  *
40  */
41 
42 /** Data delivery profiler */
43 static struct profiler xferbuf_deliver_profiler __profiler =
44  { .name = "xferbuf.deliver" };
45 
46 /** Data write profiler */
47 static struct profiler xferbuf_write_profiler __profiler =
48  { .name = "xferbuf.write" };
49 
50 /** Data read profiler */
51 static struct profiler xferbuf_read_profiler __profiler =
52  { .name = "xferbuf.read" };
53 
54 /**
55  * Detach data from data transfer buffer
56  *
57  * @v xferbuf Data transfer buffer
58  *
59  * The caller assumes responsibility for eventually freeing the data
60  * previously owned by the data transfer buffer.
61  */
62 void xferbuf_detach ( struct xfer_buffer *xferbuf ) {
63 
64  xferbuf->data = NULL;
65  xferbuf->len = 0;
66  xferbuf->pos = 0;
67 }
68 
69 /**
70  * Free data transfer buffer
71  *
72  * @v xferbuf Data transfer buffer
73  */
74 void xferbuf_free ( struct xfer_buffer *xferbuf ) {
75 
76  xferbuf->op->realloc ( xferbuf, 0 );
77  xferbuf_detach ( xferbuf );
78 }
79 
80 /**
81  * Ensure that data transfer buffer is large enough for the specified size
82  *
83  * @v xferbuf Data transfer buffer
84  * @v len Required minimum size
85  * @ret rc Return status code
86  */
87 static int xferbuf_ensure_size ( struct xfer_buffer *xferbuf, size_t len ) {
88  int rc;
89 
90  /* If buffer is already large enough, do nothing */
91  if ( len <= xferbuf->len )
92  return 0;
93 
94  /* Extend buffer */
95  if ( ( rc = xferbuf->op->realloc ( xferbuf, len ) ) != 0 ) {
96  DBGC ( xferbuf, "XFERBUF %p could not extend buffer to "
97  "%zd bytes: %s\n", xferbuf, len, strerror ( rc ) );
98  return rc;
99  }
100  xferbuf->len = len;
101 
102  return 0;
103 }
104 
105 /**
106  * Write to data transfer buffer
107  *
108  * @v xferbuf Data transfer buffer
109  * @v offset Starting offset
110  * @v data Data to write
111  * @v len Length of data
112  */
113 int xferbuf_write ( struct xfer_buffer *xferbuf, size_t offset,
114  const void *data, size_t len ) {
115  size_t max_len;
116  int rc;
117 
118  /* Check for overflow */
119  max_len = ( offset + len );
120  if ( max_len < offset )
121  return -EOVERFLOW;
122 
123  /* Ensure buffer is large enough to contain this write */
124  if ( ( rc = xferbuf_ensure_size ( xferbuf, max_len ) ) != 0 )
125  return rc;
126 
127  /* Check that buffer is non-void */
128  if ( len && ( ! xferbuf->data ) )
129  return -ENOTTY;
130 
131  /* Copy data to buffer */
132  profile_start ( &xferbuf_write_profiler );
133  memcpy ( ( xferbuf->data + offset ), data, len );
134  profile_stop ( &xferbuf_write_profiler );
135 
136  return 0;
137 }
138 
139 /**
140  * Read from data transfer buffer
141  *
142  * @v xferbuf Data transfer buffer
143  * @v offset Starting offset
144  * @v data Data to write
145  * @v len Length of data
146  */
147 int xferbuf_read ( struct xfer_buffer *xferbuf, size_t offset,
148  void *data, size_t len ) {
149 
150  /* Check that read is within buffer range */
151  if ( ( offset > xferbuf->len ) ||
152  ( len > ( xferbuf->len - offset ) ) )
153  return -ENOENT;
154 
155  /* Check that buffer is non-void */
156  if ( len && ( ! xferbuf->data ) )
157  return -ENOTTY;
158 
159  /* Copy data from buffer */
160  profile_start ( &xferbuf_read_profiler );
161  memcpy ( data, ( xferbuf->data + offset ), len );
162  profile_stop ( &xferbuf_read_profiler );
163 
164  return 0;
165 }
166 
167 /**
168  * Add received data to data transfer buffer
169  *
170  * @v xferbuf Data transfer buffer
171  * @v iobuf I/O buffer
172  * @v meta Data transfer metadata
173  * @ret rc Return status code
174  */
175 int xferbuf_deliver ( struct xfer_buffer *xferbuf, struct io_buffer *iobuf,
176  struct xfer_metadata *meta ) {
177  size_t len = iob_len ( iobuf );
178  size_t pos;
179  int rc;
180 
181  /* Start profiling */
182  profile_start ( &xferbuf_deliver_profiler );
183 
184  /* Calculate new buffer position */
185  pos = xferbuf->pos;
186  if ( meta->flags & XFER_FL_ABS_OFFSET )
187  pos = 0;
188  pos += meta->offset;
189 
190  /* Write data to buffer */
191  if ( ( rc = xferbuf_write ( xferbuf, pos, iobuf->data, len ) ) != 0 )
192  goto done;
193 
194  /* Update current buffer position */
195  xferbuf->pos = ( pos + len );
196 
197  done:
198  free_iob ( iobuf );
199  profile_stop ( &xferbuf_deliver_profiler );
200  return rc;
201 }
202 
203 /**
204  * Reallocate malloc()-based data transfer buffer
205  *
206  * @v xferbuf Data transfer buffer
207  * @v len New length (or zero to free buffer)
208  * @ret rc Return status code
209  */
210 static int xferbuf_malloc_realloc ( struct xfer_buffer *xferbuf, size_t len ) {
211  void *new_data;
212 
213  new_data = realloc ( xferbuf->data, len );
214  if ( ! new_data )
215  return -ENOSPC;
216  xferbuf->data = new_data;
217  return 0;
218 }
219 
220 /** malloc()-based data buffer operations */
223 };
224 
225 /**
226  * Reallocate umalloc()-based data transfer buffer
227  *
228  * @v xferbuf Data transfer buffer
229  * @v len New length (or zero to free buffer)
230  * @ret rc Return status code
231  */
232 static int xferbuf_umalloc_realloc ( struct xfer_buffer *xferbuf, size_t len ) {
233  void *new_udata;
234 
235  new_udata = urealloc ( xferbuf->data, len );
236  if ( ! new_udata )
237  return -ENOSPC;
238  xferbuf->data = new_udata;
239  return 0;
240 }
241 
242 /** umalloc()-based data buffer operations */
245 };
246 
247 /**
248  * Reallocate fixed-size data transfer buffer
249  *
250  * @v xferbuf Data transfer buffer
251  * @v len New length (or zero to free buffer)
252  * @ret rc Return status code
253  */
254 static int xferbuf_fixed_realloc ( struct xfer_buffer *xferbuf, size_t len ) {
255 
256  /* Refuse to allocate extra space */
257  if ( len > xferbuf->len ) {
258  /* Note that EFI relies upon this error mapping to
259  * EFI_BUFFER_TOO_SMALL.
260  */
261  return -ERANGE;
262  }
263 
264  return 0;
265 }
266 
267 /** Fixed-size data buffer operations */
270 };
271 
272 /**
273  * Reallocate void data transfer buffer
274  *
275  * @v xferbuf Data transfer buffer
276  * @v len New length (or zero to free buffer)
277  * @ret rc Return status code
278  */
279 static int xferbuf_void_realloc ( struct xfer_buffer *xferbuf,
280  size_t len __unused ) {
281 
282  /* Succeed without ever allocating data */
283  assert ( xferbuf->data == NULL );
284  return 0;
285 }
286 
287 /** Void data buffer operations */
290 };
291 
292 /**
293  * Get underlying data transfer buffer
294  *
295  * @v interface Data transfer interface
296  * @ret xferbuf Data transfer buffer, or NULL on error
297  *
298  * This call will check that the xfer_buffer() handler belongs to the
299  * destination interface which also provides xfer_deliver() for this
300  * interface.
301  *
302  * This is done to prevent accidental accesses to a data transfer
303  * buffer which may be located behind a non-transparent datapath via a
304  * series of pass-through interfaces.
305  */
306 struct xfer_buffer * xfer_buffer ( struct interface *intf ) {
307  struct interface *dest;
308  xfer_buffer_TYPE ( void * ) *op =
310  void *object = intf_object ( dest );
311  struct interface *xfer_deliver_dest;
312  struct xfer_buffer *xferbuf;
313 
314  /* Check that this operation is provided by the same interface
315  * which handles xfer_deliver().
316  */
317  ( void ) intf_get_dest_op ( intf, xfer_deliver, &xfer_deliver_dest );
318 
319  if ( op && ( dest == xfer_deliver_dest ) ) {
320  xferbuf = op ( object );
321  } else {
322  /* Default is to not have a data transfer buffer */
323  xferbuf = NULL;
324  }
325 
326  intf_put ( xfer_deliver_dest );
327  intf_put ( dest );
328  return xferbuf;
329 }
void * data
Data.
Definition: xferbuf.h:21
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
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:175
Data transfer metadata.
Definition: xfer.h:23
#define XFER_FL_ABS_OFFSET
Offset is absolute.
Definition: xfer.h:48
Error codes.
A data transfer buffer.
Definition: xferbuf.h:19
I/O buffers.
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:153
#define DBGC(...)
Definition: compiler.h:505
#define ENOENT
No such file or directory.
Definition: errno.h:515
size_t pos
Current offset within data.
Definition: xferbuf.h:25
static int xferbuf_void_realloc(struct xfer_buffer *xferbuf, size_t len __unused)
Reallocate void data transfer buffer.
Definition: xferbuf.c:279
A data structure for storing profiling information.
Definition: profile.h:27
void xferbuf_free(struct xfer_buffer *xferbuf)
Free data transfer buffer.
Definition: xferbuf.c:74
static void profile_stop(struct profiler *profiler)
Stop profiling.
Definition: profile.h:174
int xferbuf_write(struct xfer_buffer *xferbuf, size_t offset, const void *data, size_t len)
Write to data transfer buffer.
Definition: xferbuf.c:113
static int xferbuf_malloc_realloc(struct xfer_buffer *xferbuf, size_t len)
Reallocate malloc()-based data transfer buffer.
Definition: xferbuf.c:210
void * intf_object(struct interface *intf)
Get pointer to object containing object interface.
Definition: interface.c:160
Data transfer interfaces.
struct interface * intf
Original interface.
Definition: interface.h:159
Data transfer buffer operations.
Definition: xferbuf.h:31
size_t len
Size of data.
Definition: xferbuf.h:23
void * memcpy(void *dest, const void *src, size_t len) __nonnull
const char * name
Name.
Definition: profile.h:29
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
An object interface.
Definition: interface.h:125
struct xfer_buffer_operations xferbuf_void_operations
Void data buffer operations.
Definition: xferbuf.c:288
#define xfer_buffer_TYPE(object_type)
Definition: xferbuf.h:111
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
ring len
Length.
Definition: dwmac.h:231
struct xfer_buffer_operations xferbuf_fixed_operations
Fixed-size data buffer operations.
Definition: xferbuf.c:268
static void profile_start(struct profiler *profiler)
Start profiling.
Definition: profile.h:161
Profiling.
struct xfer_buffer_operations * op
Data transfer buffer operations.
Definition: xferbuf.h:27
#define ERANGE
Result too large.
Definition: errno.h:640
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:160
User memory allocation.
#define EOVERFLOW
Value too large to be stored in data type.
Definition: errno.h:610
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition: xfer.c:195
struct xfer_buffer * xfer_buffer(struct interface *intf)
Get underlying data transfer buffer.
Definition: xferbuf.c:306
void xferbuf_detach(struct xfer_buffer *xferbuf)
Detach data from data transfer buffer.
Definition: xferbuf.c:62
static int xferbuf_fixed_realloc(struct xfer_buffer *xferbuf, size_t len)
Reallocate fixed-size data transfer buffer.
Definition: xferbuf.c:254
int xferbuf_read(struct xfer_buffer *xferbuf, size_t offset, void *data, size_t len)
Read from data transfer buffer.
Definition: xferbuf.c:147
static int xferbuf_umalloc_realloc(struct xfer_buffer *xferbuf, size_t len)
Reallocate umalloc()-based data transfer buffer.
Definition: xferbuf.c:232
static uint16_t struct vmbus_xfer_pages_operations * op
Definition: netvsc.h:327
#define ENOSPC
No space left on device.
Definition: errno.h:550
struct xfer_buffer_operations xferbuf_umalloc_operations
umalloc()-based data buffer operations
Definition: xferbuf.c:243
static struct profiler xferbuf_deliver_profiler __profiler
Data delivery profiler.
Definition: xferbuf.c:43
#define ENOTTY
Inappropriate I/O control operation.
Definition: errno.h:595
void * data
Start of data.
Definition: iobuf.h:53
int(* realloc)(struct xfer_buffer *xferbuf, size_t len)
Reallocate data buffer.
Definition: xferbuf.h:38
void intf_put(struct interface *intf)
Decrement reference count on an object interface.
Definition: interface.c:150
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:87
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" return dest
Definition: string.h:151
uint8_t data[48]
Additional event data.
Definition: ena.h:22
void * realloc(void *old_ptr, size_t new_size)
Reallocate memory.
Definition: malloc.c:607
void * urealloc(void *ptr, size_t new_size)
Reallocate external memory.
uint16_t offset
Offset to command line.
Definition: bzimage.h:8
uint8_t meta
Metadata flags.
Definition: ena.h:14
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
FILE_SECBOOT(PERMITTED)
String functions.
#define intf_get_dest_op(intf, type, dest)
Get object interface destination and operation method.
Definition: interface.h:270
struct bofm_section_header done
Definition: bofm_test.c:46
Data transfer buffer.
struct xfer_buffer_operations xferbuf_malloc_operations
malloc()-based data buffer operations
Definition: xferbuf.c:221
A persistent I/O buffer.
Definition: iobuf.h:38