You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

xferbuf.c 8.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <errno.h>
  27. #include <ipxe/xfer.h>
  28. #include <ipxe/iobuf.h>
  29. #include <ipxe/umalloc.h>
  30. #include <ipxe/profile.h>
  31. #include <ipxe/xferbuf.h>
  32. /** @file
  33. *
  34. * Data transfer buffer
  35. *
  36. */
  37. /** Data delivery profiler */
  38. static struct profiler xferbuf_deliver_profiler __profiler =
  39. { .name = "xferbuf.deliver" };
  40. /** Data write profiler */
  41. static struct profiler xferbuf_write_profiler __profiler =
  42. { .name = "xferbuf.write" };
  43. /** Data read profiler */
  44. static struct profiler xferbuf_read_profiler __profiler =
  45. { .name = "xferbuf.read" };
  46. /**
  47. * Free data transfer buffer
  48. *
  49. * @v xferbuf Data transfer buffer
  50. */
  51. void xferbuf_free ( struct xfer_buffer *xferbuf ) {
  52. xferbuf->op->realloc ( xferbuf, 0 );
  53. xferbuf->len = 0;
  54. xferbuf->pos = 0;
  55. }
  56. /**
  57. * Ensure that data transfer buffer is large enough for the specified size
  58. *
  59. * @v xferbuf Data transfer buffer
  60. * @v len Required minimum size
  61. * @ret rc Return status code
  62. */
  63. static int xferbuf_ensure_size ( struct xfer_buffer *xferbuf, size_t len ) {
  64. int rc;
  65. /* If buffer is already large enough, do nothing */
  66. if ( len <= xferbuf->len )
  67. return 0;
  68. /* Extend buffer */
  69. if ( ( rc = xferbuf->op->realloc ( xferbuf, len ) ) != 0 ) {
  70. DBGC ( xferbuf, "XFERBUF %p could not extend buffer to "
  71. "%zd bytes: %s\n", xferbuf, len, strerror ( rc ) );
  72. return rc;
  73. }
  74. xferbuf->len = len;
  75. return 0;
  76. }
  77. /**
  78. * Write to data transfer buffer
  79. *
  80. * @v xferbuf Data transfer buffer
  81. * @v offset Starting offset
  82. * @v data Data to write
  83. * @v len Length of data
  84. */
  85. int xferbuf_write ( struct xfer_buffer *xferbuf, size_t offset,
  86. const void *data, size_t len ) {
  87. size_t max_len;
  88. int rc;
  89. /* Check for overflow */
  90. max_len = ( offset + len );
  91. if ( max_len < offset )
  92. return -EOVERFLOW;
  93. /* Ensure buffer is large enough to contain this write */
  94. if ( ( rc = xferbuf_ensure_size ( xferbuf, max_len ) ) != 0 )
  95. return rc;
  96. /* Copy data to buffer */
  97. profile_start ( &xferbuf_write_profiler );
  98. xferbuf->op->write ( xferbuf, offset, data, len );
  99. profile_stop ( &xferbuf_write_profiler );
  100. return 0;
  101. }
  102. /**
  103. * Read from data transfer buffer
  104. *
  105. * @v xferbuf Data transfer buffer
  106. * @v offset Starting offset
  107. * @v data Data to write
  108. * @v len Length of data
  109. */
  110. int xferbuf_read ( struct xfer_buffer *xferbuf, size_t offset,
  111. void *data, size_t len ) {
  112. /* Check that read is within buffer range */
  113. if ( ( offset > xferbuf->len ) ||
  114. ( len > ( xferbuf->len - offset ) ) )
  115. return -ENOENT;
  116. /* Copy data from buffer */
  117. profile_start ( &xferbuf_read_profiler );
  118. xferbuf->op->read ( xferbuf, offset, data, len );
  119. profile_stop ( &xferbuf_read_profiler );
  120. return 0;
  121. }
  122. /**
  123. * Add received data to data transfer buffer
  124. *
  125. * @v xferbuf Data transfer buffer
  126. * @v iobuf I/O buffer
  127. * @v meta Data transfer metadata
  128. * @ret rc Return status code
  129. */
  130. int xferbuf_deliver ( struct xfer_buffer *xferbuf, struct io_buffer *iobuf,
  131. struct xfer_metadata *meta ) {
  132. size_t len = iob_len ( iobuf );
  133. size_t pos;
  134. int rc;
  135. /* Start profiling */
  136. profile_start ( &xferbuf_deliver_profiler );
  137. /* Calculate new buffer position */
  138. pos = xferbuf->pos;
  139. if ( meta->flags & XFER_FL_ABS_OFFSET )
  140. pos = 0;
  141. pos += meta->offset;
  142. /* Write data to buffer */
  143. if ( ( rc = xferbuf_write ( xferbuf, pos, iobuf->data, len ) ) != 0 )
  144. goto done;
  145. /* Update current buffer position */
  146. xferbuf->pos = ( pos + len );
  147. done:
  148. free_iob ( iobuf );
  149. profile_stop ( &xferbuf_deliver_profiler );
  150. return rc;
  151. }
  152. /**
  153. * Reallocate malloc()-based data buffer
  154. *
  155. * @v xferbuf Data transfer buffer
  156. * @v len New length (or zero to free buffer)
  157. * @ret rc Return status code
  158. */
  159. static int xferbuf_malloc_realloc ( struct xfer_buffer *xferbuf, size_t len ) {
  160. void *new_data;
  161. new_data = realloc ( xferbuf->data, len );
  162. if ( ! new_data )
  163. return -ENOSPC;
  164. xferbuf->data = new_data;
  165. return 0;
  166. }
  167. /**
  168. * Write data to malloc()-based data buffer
  169. *
  170. * @v xferbuf Data transfer buffer
  171. * @v offset Starting offset
  172. * @v data Data to copy
  173. * @v len Length of data
  174. */
  175. static void xferbuf_malloc_write ( struct xfer_buffer *xferbuf, size_t offset,
  176. const void *data, size_t len ) {
  177. memcpy ( ( xferbuf->data + offset ), data, len );
  178. }
  179. /**
  180. * Read data from malloc()-based data buffer
  181. *
  182. * @v xferbuf Data transfer buffer
  183. * @v offset Starting offset
  184. * @v data Data to read
  185. * @v len Length of data
  186. */
  187. static void xferbuf_malloc_read ( struct xfer_buffer *xferbuf, size_t offset,
  188. void *data, size_t len ) {
  189. memcpy ( data, ( xferbuf->data + offset ), len );
  190. }
  191. /** malloc()-based data buffer operations */
  192. struct xfer_buffer_operations xferbuf_malloc_operations = {
  193. .realloc = xferbuf_malloc_realloc,
  194. .write = xferbuf_malloc_write,
  195. .read = xferbuf_malloc_read,
  196. };
  197. /**
  198. * Reallocate umalloc()-based data buffer
  199. *
  200. * @v xferbuf Data transfer buffer
  201. * @v len New length (or zero to free buffer)
  202. * @ret rc Return status code
  203. */
  204. static int xferbuf_umalloc_realloc ( struct xfer_buffer *xferbuf, size_t len ) {
  205. userptr_t *udata = xferbuf->data;
  206. userptr_t new_udata;
  207. new_udata = urealloc ( *udata, len );
  208. if ( ! new_udata )
  209. return -ENOSPC;
  210. *udata = new_udata;
  211. return 0;
  212. }
  213. /**
  214. * Write data to umalloc()-based data buffer
  215. *
  216. * @v xferbuf Data transfer buffer
  217. * @v offset Starting offset
  218. * @v data Data to copy
  219. * @v len Length of data
  220. */
  221. static void xferbuf_umalloc_write ( struct xfer_buffer *xferbuf, size_t offset,
  222. const void *data, size_t len ) {
  223. userptr_t *udata = xferbuf->data;
  224. copy_to_user ( *udata, offset, data, len );
  225. }
  226. /**
  227. * Read data from umalloc()-based data buffer
  228. *
  229. * @v xferbuf Data transfer buffer
  230. * @v offset Starting offset
  231. * @v data Data to read
  232. * @v len Length of data
  233. */
  234. static void xferbuf_umalloc_read ( struct xfer_buffer *xferbuf, size_t offset,
  235. void *data, size_t len ) {
  236. userptr_t *udata = xferbuf->data;
  237. copy_from_user ( data, *udata, offset, len );
  238. }
  239. /** umalloc()-based data buffer operations */
  240. struct xfer_buffer_operations xferbuf_umalloc_operations = {
  241. .realloc = xferbuf_umalloc_realloc,
  242. .write = xferbuf_umalloc_write,
  243. .read = xferbuf_umalloc_read,
  244. };
  245. /**
  246. * Get underlying data transfer buffer
  247. *
  248. * @v interface Data transfer interface
  249. * @ret xferbuf Data transfer buffer, or NULL on error
  250. *
  251. * This call will check that the xfer_buffer() handler belongs to the
  252. * destination interface which also provides xfer_deliver() for this
  253. * interface.
  254. *
  255. * This is done to prevent accidental accesses to a data transfer
  256. * buffer which may be located behind a non-transparent datapath via a
  257. * series of pass-through interfaces.
  258. */
  259. struct xfer_buffer * xfer_buffer ( struct interface *intf ) {
  260. struct interface *dest;
  261. xfer_buffer_TYPE ( void * ) *op =
  262. intf_get_dest_op ( intf, xfer_buffer, &dest );
  263. void *object = intf_object ( dest );
  264. struct interface *xfer_deliver_dest;
  265. struct xfer_buffer *xferbuf;
  266. /* Check that this operation is provided by the same interface
  267. * which handles xfer_deliver().
  268. */
  269. ( void ) intf_get_dest_op ( intf, xfer_deliver, &xfer_deliver_dest );
  270. if ( op && ( dest == xfer_deliver_dest ) ) {
  271. xferbuf = op ( object );
  272. } else {
  273. /* Default is to not have a data transfer buffer */
  274. xferbuf = NULL;
  275. }
  276. intf_put ( xfer_deliver_dest );
  277. intf_put ( dest );
  278. return xferbuf;
  279. }