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