Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

iobuf.c 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <stdint.h>
  25. #include <strings.h>
  26. #include <errno.h>
  27. #include <ipxe/malloc.h>
  28. #include <ipxe/iobuf.h>
  29. /** @file
  30. *
  31. * I/O buffers
  32. *
  33. */
  34. /**
  35. * Allocate I/O buffer with specified alignment and offset
  36. *
  37. * @v len Required length of buffer
  38. * @v align Physical alignment
  39. * @v offset Offset from physical alignment
  40. * @ret iobuf I/O buffer, or NULL if none available
  41. *
  42. * @c align will be rounded up to the nearest power of two.
  43. */
  44. struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) {
  45. struct io_buffer *iobuf;
  46. void *data;
  47. /* Align buffer length to ensure that struct io_buffer is aligned */
  48. len = ( len + __alignof__ ( *iobuf ) - 1 ) &
  49. ~( __alignof__ ( *iobuf ) - 1 );
  50. /* Round up alignment to the nearest power of two */
  51. align = ( 1 << fls ( align - 1 ) );
  52. /* Allocate buffer plus descriptor as a single unit, unless
  53. * doing so will push the total size over the alignment
  54. * boundary.
  55. */
  56. if ( ( len + sizeof ( *iobuf ) ) <= align ) {
  57. /* Allocate memory for buffer plus descriptor */
  58. data = malloc_dma_offset ( len + sizeof ( *iobuf ), align,
  59. offset );
  60. if ( ! data )
  61. return NULL;
  62. iobuf = ( data + len );
  63. } else {
  64. /* Allocate memory for buffer */
  65. data = malloc_dma_offset ( len, align, offset );
  66. if ( ! data )
  67. return NULL;
  68. /* Allocate memory for descriptor */
  69. iobuf = malloc ( sizeof ( *iobuf ) );
  70. if ( ! iobuf ) {
  71. free_dma ( data, len );
  72. return NULL;
  73. }
  74. }
  75. /* Populate descriptor */
  76. iobuf->head = iobuf->data = iobuf->tail = data;
  77. iobuf->end = ( data + len );
  78. return iobuf;
  79. }
  80. /**
  81. * Allocate I/O buffer
  82. *
  83. * @v len Required length of buffer
  84. * @ret iobuf I/O buffer, or NULL if none available
  85. *
  86. * The I/O buffer will be physically aligned on its own size (rounded
  87. * up to the nearest power of two).
  88. */
  89. struct io_buffer * alloc_iob ( size_t len ) {
  90. /* Pad to minimum length */
  91. if ( len < IOB_ZLEN )
  92. len = IOB_ZLEN;
  93. /* Align buffer on its own size to avoid potential problems
  94. * with boundary-crossing DMA.
  95. */
  96. return alloc_iob_raw ( len, len, 0 );
  97. }
  98. /**
  99. * Free I/O buffer
  100. *
  101. * @v iobuf I/O buffer
  102. */
  103. void free_iob ( struct io_buffer *iobuf ) {
  104. size_t len;
  105. /* Allow free_iob(NULL) to be valid */
  106. if ( ! iobuf )
  107. return;
  108. /* Sanity checks */
  109. assert ( iobuf->head <= iobuf->data );
  110. assert ( iobuf->data <= iobuf->tail );
  111. assert ( iobuf->tail <= iobuf->end );
  112. /* Free buffer */
  113. len = ( iobuf->end - iobuf->head );
  114. if ( iobuf->end == iobuf ) {
  115. /* Descriptor is inline */
  116. free_dma ( iobuf->head, ( len + sizeof ( *iobuf ) ) );
  117. } else {
  118. /* Descriptor is detached */
  119. free_dma ( iobuf->head, len );
  120. free ( iobuf );
  121. }
  122. }
  123. /**
  124. * Ensure I/O buffer has sufficient headroom
  125. *
  126. * @v iobuf I/O buffer
  127. * @v len Required headroom
  128. *
  129. * This function currently only checks for the required headroom; it
  130. * does not reallocate the I/O buffer if required. If we ever have a
  131. * code path that requires this functionality, it's a fairly trivial
  132. * change to make.
  133. */
  134. int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len ) {
  135. if ( iob_headroom ( iobuf ) >= len )
  136. return 0;
  137. return -ENOBUFS;
  138. }
  139. /**
  140. * Concatenate I/O buffers into a single buffer
  141. *
  142. * @v list List of I/O buffers
  143. * @ret iobuf Concatenated I/O buffer, or NULL on allocation failure
  144. *
  145. * After a successful concatenation, the list will be empty.
  146. */
  147. struct io_buffer * iob_concatenate ( struct list_head *list ) {
  148. struct io_buffer *iobuf;
  149. struct io_buffer *tmp;
  150. struct io_buffer *concatenated;
  151. size_t len = 0;
  152. /* If the list contains only a single entry, avoid an
  153. * unnecessary additional allocation.
  154. */
  155. if ( list_is_singular ( list ) ) {
  156. iobuf = list_first_entry ( list, struct io_buffer, list );
  157. INIT_LIST_HEAD ( list );
  158. return iobuf;
  159. }
  160. /* Calculate total length */
  161. list_for_each_entry ( iobuf, list, list )
  162. len += iob_len ( iobuf );
  163. /* Allocate new I/O buffer */
  164. concatenated = alloc_iob_raw ( len, __alignof__ ( *iobuf ), 0 );
  165. if ( ! concatenated )
  166. return NULL;
  167. /* Move data to new I/O buffer */
  168. list_for_each_entry_safe ( iobuf, tmp, list, list ) {
  169. list_del ( &iobuf->list );
  170. memcpy ( iob_put ( concatenated, iob_len ( iobuf ) ),
  171. iobuf->data, iob_len ( iobuf ) );
  172. free_iob ( iobuf );
  173. }
  174. return concatenated;
  175. }
  176. /**
  177. * Split I/O buffer
  178. *
  179. * @v iobuf I/O buffer
  180. * @v len Length to split into a new I/O buffer
  181. * @ret split New I/O buffer, or NULL on allocation failure
  182. *
  183. * Split the first @c len bytes of the existing I/O buffer into a
  184. * separate I/O buffer. The resulting buffers are likely to have no
  185. * headroom or tailroom.
  186. *
  187. * If this call fails, then the original buffer will be unmodified.
  188. */
  189. struct io_buffer * iob_split ( struct io_buffer *iobuf, size_t len ) {
  190. struct io_buffer *split;
  191. /* Sanity checks */
  192. assert ( len <= iob_len ( iobuf ) );
  193. /* Allocate new I/O buffer */
  194. split = alloc_iob ( len );
  195. if ( ! split )
  196. return NULL;
  197. /* Copy in data */
  198. memcpy ( iob_put ( split, len ), iobuf->data, len );
  199. iob_pull ( iobuf, len );
  200. return split;
  201. }