iPXE
Functions | Variables
initrd.c File Reference

Initial ramdisk (initrd) reshuffling. More...

#include <string.h>
#include <errno.h>
#include <ipxe/image.h>
#include <ipxe/uaccess.h>
#include <ipxe/init.h>
#include <ipxe/cpio.h>
#include <ipxe/uheap.h>
#include <ipxe/initrd.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
 
static void initrd_squash_high (physaddr_t start, physaddr_t end)
 Squash initrds as high as possible in memory. More...
 
static void initrd_reverse (void *data, size_t len)
 Reverse aligned memory region. More...
 
static void initrd_swap (struct image *low, struct image *high)
 Swap position of two adjacent initrds. More...
 
static int initrd_swap_any (physaddr_t start, physaddr_t end)
 Swap position of any two adjacent initrds not currently in the correct order. More...
 
static void initrd_dump (void)
 Dump initrd locations (for debug) More...
 
void initrd_reshuffle (void)
 Reshuffle initrds into desired order at top of memory. More...
 
static size_t initrd_load (struct image *initrd, void *address)
 Load initrd. More...
 
size_t initrd_load_all (void *address)
 Load all initrds. More...
 
int initrd_region (size_t len, struct memmap_region *region)
 Calculate post-reshuffle initrd load region. More...
 
static void initrd_startup (void)
 initrd startup function More...
 
struct startup_fn startup_initrd __startup_fn (STARTUP_LATE)
 initrd startup function More...
 

Variables

static physaddr_t initrd_end
 End of reshuffle region. More...
 

Detailed Description

Initial ramdisk (initrd) reshuffling.

Definition in file initrd.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )

◆ initrd_squash_high()

static void initrd_squash_high ( physaddr_t  start,
physaddr_t  end 
)
static

Squash initrds as high as possible in memory.

Parameters
startStart of reshuffle region
endEnd of reshuffle region

Definition at line 50 of file initrd.c.

50  {
51  physaddr_t current = end;
52  struct image *initrd;
53  struct image *highest;
54  void *data;
55 
56  /* Squash up any initrds already within the region */
57  while ( 1 ) {
58 
59  /* Find the highest image not yet in its final position */
60  highest = NULL;
61  for_each_image ( initrd ) {
62  if ( ( virt_to_phys ( initrd->data ) >= start ) &&
63  ( virt_to_phys ( initrd->data ) < current ) &&
64  ( ( highest == NULL ) ||
65  ( virt_to_phys ( initrd->data ) >
66  virt_to_phys ( highest->data ) ) ) ) {
67  highest = initrd;
68  }
69  }
70  if ( ! highest )
71  break;
72 
73  /* Calculate final position */
74  current -= initrd_align ( highest->len );
75  if ( current <= virt_to_phys ( highest->data ) ) {
76  /* Already at (or crossing) end of region */
77  current = virt_to_phys ( highest->data );
78  continue;
79  }
80 
81  /* Move this image to its final position */
82  DBGC ( &images, "INITRD squashing %s [%#08lx,%#08lx)->"
83  "[%#08lx,%#08lx)\n", highest->name,
84  virt_to_phys ( highest->data ),
85  ( virt_to_phys ( highest->data ) + highest->len ),
86  current, ( current + highest->len ) );
87  data = phys_to_virt ( current );
88  memmove ( data, highest->data, highest->len );
89  highest->data = data;
90  }
91 }
const void * data
Read-only data.
Definition: image.h:50
#define DBGC(...)
Definition: compiler.h:505
An executable image.
Definition: image.h:23
static size_t initrd_align(size_t len)
Align initrd length.
Definition: initrd.h:29
uint32_t start
Starting offset.
Definition: netvsc.h:12
#define for_each_image(image)
Iterate over all registered images.
Definition: image.h:190
size_t len
Length of raw file image.
Definition: image.h:55
struct list_head images
List of registered images.
Definition: image.c:58
void * memmove(void *dest, const void *src, size_t len) __nonnull
unsigned long physaddr_t
Definition: stdint.h:20
uint32_t end
Ending offset.
Definition: netvsc.h:18
uint8_t data[48]
Additional event data.
Definition: ena.h:22
char * name
Name.
Definition: image.h:37
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321

References data, image::data, DBGC, end, for_each_image, images, initrd_align(), image::len, memmove(), image::name, NULL, and start.

Referenced by initrd_reshuffle().

◆ initrd_reverse()

static void initrd_reverse ( void *  data,
size_t  len 
)
static

Reverse aligned memory region.

Parameters
dataMemory region
lenLength of region

Definition at line 99 of file initrd.c.

99  {
100  unsigned long *low = data;
101  unsigned long *high = ( data + len );
102  unsigned long tmp;
103 
104  /* Reverse region */
105  for ( high-- ; low < high ; low++, high-- ) {
106  tmp = *low;
107  *low = *high;
108  *high = tmp;
109  }
110 }
uint32_t low
Low 16 bits of address.
Definition: myson.h:19
unsigned long tmp
Definition: linux_pci.h:64
ring len
Length.
Definition: dwmac.h:231
uint32_t high
High 32 bits of address.
Definition: myson.h:20
uint8_t data[48]
Additional event data.
Definition: ena.h:22

References data, high, len, low, and tmp.

Referenced by initrd_swap().

◆ initrd_swap()

static void initrd_swap ( struct image low,
struct image high 
)
static

Swap position of two adjacent initrds.

Parameters
lowLower initrd
highHigher initrd

Definition at line 118 of file initrd.c.

118  {
119  size_t low_len;
120  size_t high_len;
121  size_t len;
122  void *data;
123 
124  DBGC ( &images, "INITRD swapping %s [%#08lx,%#08lx)<->[%#08lx,%#08lx) "
125  "%s\n", low->name, virt_to_phys ( low->data ),
126  ( virt_to_phys ( low->data ) + low->len ),
127  virt_to_phys ( high->data ),
128  ( virt_to_phys ( high->data ) + high->len ), high->name );
129 
130  /* Calculate padded lengths */
131  low_len = initrd_align ( low->len );
132  high_len = initrd_align ( high->len );
133  len = ( low_len + high_len );
134  data = low->rwdata;
135  assert ( high->data == ( data + low_len ) );
136 
137  /* Adjust data pointers */
138  high->data -= low_len;
139  low->data += high_len;
140  assert ( high->data == data );
141 
142  /* Swap content via triple reversal */
143  initrd_reverse ( data, len );
144  initrd_reverse ( low->rwdata, low_len );
145  initrd_reverse ( high->rwdata, high_len );
146 }
static void initrd_reverse(void *data, size_t len)
Reverse aligned memory region.
Definition: initrd.c:99
uint32_t low
Low 16 bits of address.
Definition: myson.h:19
#define DBGC(...)
Definition: compiler.h:505
static size_t initrd_align(size_t len)
Align initrd length.
Definition: initrd.h:29
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
ring len
Length.
Definition: dwmac.h:231
uint32_t high
High 32 bits of address.
Definition: myson.h:20
struct list_head images
List of registered images.
Definition: image.c:58
uint8_t data[48]
Additional event data.
Definition: ena.h:22

References assert(), data, DBGC, high, images, initrd_align(), initrd_reverse(), len, and low.

Referenced by initrd_swap_any().

◆ initrd_swap_any()

static int initrd_swap_any ( physaddr_t  start,
physaddr_t  end 
)
static

Swap position of any two adjacent initrds not currently in the correct order.

Parameters
startStart of reshuffle region
endEnd of reshuffle region
Return values
swappedA pair of initrds was swapped

Definition at line 155 of file initrd.c.

155  {
156  struct image *low;
157  struct image *high;
158  const void *adjacent;
160 
161  /* Find any pair of initrds that can be swapped */
162  for_each_image ( low ) {
163 
164  /* Ignore images wholly outside the reshuffle region */
165  addr = virt_to_phys ( low->data );
166  if ( ( addr < start ) || ( addr >= end ) )
167  continue;
168 
169  /* Calculate location of adjacent image (if any) */
170  adjacent = ( low->data + initrd_align ( low->len ) );
171 
172  /* Search for adjacent image */
173  for_each_image ( high ) {
174 
175  /* Ignore images wholly outside the reshuffle region */
176  addr = virt_to_phys ( high->data );
177  if ( ( addr < start ) || ( addr >= end ) )
178  continue;
179 
180  /* Stop search if all remaining potential
181  * adjacent images are already in the correct
182  * order.
183  */
184  if ( high == low )
185  break;
186 
187  /* If we have found the adjacent image, swap and exit */
188  if ( high->data == adjacent ) {
189  initrd_swap ( low, high );
190  return 1;
191  }
192  }
193  }
194 
195  /* Nothing swapped */
196  return 0;
197 }
uint32_t low
Low 16 bits of address.
Definition: myson.h:19
An executable image.
Definition: image.h:23
static size_t initrd_align(size_t len)
Align initrd length.
Definition: initrd.h:29
uint32_t start
Starting offset.
Definition: netvsc.h:12
uint32_t high
High 32 bits of address.
Definition: myson.h:20
#define for_each_image(image)
Iterate over all registered images.
Definition: image.h:190
uint32_t addr
Buffer address.
Definition: dwmac.h:20
static void initrd_swap(struct image *low, struct image *high)
Swap position of two adjacent initrds.
Definition: initrd.c:118
unsigned long physaddr_t
Definition: stdint.h:20
uint32_t end
Ending offset.
Definition: netvsc.h:18

References addr, end, for_each_image, high, initrd_align(), initrd_swap(), low, and start.

Referenced by initrd_reshuffle().

◆ initrd_dump()

static void initrd_dump ( void  )
static

Dump initrd locations (for debug)

Definition at line 203 of file initrd.c.

203  {
204  struct image *initrd;
205 
206  /* Do nothing unless debugging is enabled */
207  if ( ! DBG_LOG )
208  return;
209 
210  /* Dump initrd locations */
211  for_each_image ( initrd ) {
212  DBGC ( &images, "INITRD %s at [%#08lx,%#08lx)\n",
213  initrd->name, virt_to_phys ( initrd->data ),
214  ( virt_to_phys ( initrd->data ) + initrd->len ) );
215  DBGC2_MD5A ( &images, virt_to_phys ( initrd->data ),
216  initrd->data, initrd->len );
217  }
218 }
const void * data
Read-only data.
Definition: image.h:50
#define DBGC(...)
Definition: compiler.h:505
An executable image.
Definition: image.h:23
#define DBGC2_MD5A(...)
Definition: compiler.h:525
#define for_each_image(image)
Iterate over all registered images.
Definition: image.h:190
size_t len
Length of raw file image.
Definition: image.h:55
struct list_head images
List of registered images.
Definition: image.c:58
#define DBG_LOG
Definition: compiler.h:317
char * name
Name.
Definition: image.h:37

References image::data, DBG_LOG, DBGC, DBGC2_MD5A, for_each_image, images, image::len, and image::name.

Referenced by initrd_reshuffle().

◆ initrd_reshuffle()

void initrd_reshuffle ( void  )

Reshuffle initrds into desired order at top of memory.

After this function returns, the initrds have been rearranged in memory and the external heap structures will have been corrupted. Reshuffling must therefore take place immediately prior to jumping to the loaded OS kernel; no further execution within iPXE is permitted.

Definition at line 229 of file initrd.c.

229  {
231  physaddr_t end;
232 
233  /* Calculate limits of reshuffle region */
234  start = uheap_limit;
236 
237  /* Debug */
238  initrd_dump();
239 
240  /* Squash initrds as high as possible in memory */
242 
243  /* Bubble-sort initrds into desired order */
244  while ( initrd_swap_any ( start, end ) ) {}
245 
246  /* Debug */
247  initrd_dump();
248 }
static physaddr_t initrd_end
End of reshuffle region.
Definition: initrd.c:42
uint32_t start
Starting offset.
Definition: netvsc.h:12
static void initrd_dump(void)
Dump initrd locations (for debug)
Definition: initrd.c:203
static void initrd_squash_high(physaddr_t start, physaddr_t end)
Squash initrds as high as possible in memory.
Definition: initrd.c:50
unsigned long physaddr_t
Definition: stdint.h:20
physaddr_t uheap_limit
Minimum possible start of external heap.
Definition: uheap.c:54
uint32_t end
Ending offset.
Definition: netvsc.h:18
static int initrd_swap_any(physaddr_t start, physaddr_t end)
Swap position of any two adjacent initrds not currently in the correct order.
Definition: initrd.c:155
physaddr_t uheap_end
End of external heap.
Definition: uheap.c:60

References end, initrd_dump(), initrd_end, initrd_squash_high(), initrd_swap_any(), start, uheap_end, and uheap_limit.

Referenced by bzimage_load_initrds(), and lkrn_exec().

◆ initrd_load()

static size_t initrd_load ( struct image initrd,
void *  address 
)
static

Load initrd.

Parameters
initrdinitrd image
addressAddress at which to load, or NULL
Return values
lenLength of loaded image, excluding zero-padding

Definition at line 257 of file initrd.c.

257  {
258  const char *filename = cpio_name ( initrd );
259  struct cpio_header cpio;
260  size_t offset;
261  size_t cpio_len;
262  size_t len;
263  unsigned int i;
264 
265  /* Sanity check */
266  assert ( ( address == NULL ) ||
267  ( ( virt_to_phys ( address ) & ( INITRD_ALIGN - 1 ) ) == 0 ));
268 
269  /* Skip hidden images */
270  if ( initrd->flags & IMAGE_HIDDEN )
271  return 0;
272 
273  /* Determine length of cpio headers for non-prebuilt images */
274  len = 0;
275  for ( i = 0 ; ( cpio_len = cpio_header ( initrd, i, &cpio ) ) ; i++ )
276  len += ( cpio_len + cpio_pad_len ( cpio_len ) );
277 
278  /* Copy in initrd image body and construct any cpio headers */
279  if ( address ) {
280  memmove ( ( address + len ), initrd->data, initrd->len );
281  memset ( address, 0, len );
282  offset = 0;
283  for ( i = 0 ; ( cpio_len = cpio_header ( initrd, i, &cpio ) ) ;
284  i++ ) {
285  memcpy ( ( address + offset ), &cpio,
286  sizeof ( cpio ) );
287  memcpy ( ( address + offset + sizeof ( cpio ) ),
288  filename, ( cpio_len - sizeof ( cpio ) ) );
289  offset += ( cpio_len + cpio_pad_len ( cpio_len ) );
290  }
291  assert ( offset == len );
292  DBGC ( &images, "INITRD %s [%#08lx,%#08lx,%#08lx)%s%s\n",
293  initrd->name, virt_to_phys ( address ),
294  ( virt_to_phys ( address ) + offset ),
295  ( virt_to_phys ( address ) + offset + initrd->len ),
296  ( filename ? " " : "" ), ( filename ? filename : "" ) );
297  DBGC2_MD5A ( &images, ( virt_to_phys ( address ) + offset ),
298  ( address + offset ), initrd->len );
299  }
300  len += initrd->len;
301 
302  return len;
303 }
unsigned int flags
Flags.
Definition: image.h:39
A CPIO archive header.
Definition: cpio.h:20
const void * data
Read-only data.
Definition: image.h:50
uint64_t address
Base address.
Definition: ena.h:24
#define DBGC(...)
Definition: compiler.h:505
#define DBGC2_MD5A(...)
Definition: compiler.h:525
static size_t cpio_pad_len(size_t len)
Get CPIO header zero-padding length.
Definition: cpio.h:81
#define INITRD_ALIGN
Initial ramdisk chunk alignment.
Definition: initrd.h:16
void * memcpy(void *dest, const void *src, size_t len) __nonnull
size_t cpio_header(struct image *image, unsigned int index, struct cpio_header *cpio)
Construct CPIO header for image, if applicable.
Definition: cpio.c:155
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
ring len
Length.
Definition: dwmac.h:231
size_t len
Length of raw file image.
Definition: image.h:55
struct list_head images
List of registered images.
Definition: image.c:58
#define IMAGE_HIDDEN
Image will be hidden from enumeration.
Definition: image.h:85
void * memmove(void *dest, const void *src, size_t len) __nonnull
uint16_t offset
Offset to command line.
Definition: bzimage.h:8
char * name
Name.
Definition: image.h:37
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
void * memset(void *dest, int character, size_t len) __nonnull
static const char * cpio_name(struct image *image)
Get CPIO image name.
Definition: cpio.h:70

References address, assert(), cpio_header(), cpio_name(), cpio_pad_len(), image::data, DBGC, DBGC2_MD5A, image::flags, IMAGE_HIDDEN, images, INITRD_ALIGN, image::len, len, memcpy(), memmove(), memset(), image::name, NULL, and offset.

Referenced by initrd_load_all().

◆ initrd_load_all()

size_t initrd_load_all ( void *  address)

Load all initrds.

Parameters
addressLoad address, or NULL
Return values
lenLength

This function is called after the point of no return, when the external heap has been corrupted by reshuffling and there is no way to resume normal execution. The caller must have previously ensured that there is no way for installation to this address to fail.

Definition at line 317 of file initrd.c.

317  {
318  struct image *initrd;
319  size_t len = 0;
320  size_t pad_len;
321  void *dest;
322 
323  /* Load all initrds */
324  for_each_image ( initrd ) {
325 
326  /* Zero-pad to next INITRD_ALIGN boundary */
327  pad_len = ( ( -len ) & ( INITRD_ALIGN - 1 ) );
328  if ( address )
329  memset ( ( address + len ), 0, pad_len );
330  len += pad_len;
331  assert ( len == initrd_align ( len ) );
332 
333  /* Load initrd */
334  dest = ( address ? ( address + len ) : NULL );
335  len += initrd_load ( initrd, dest );
336  }
337 
338  return len;
339 }
uint64_t address
Base address.
Definition: ena.h:24
static size_t initrd_load(struct image *initrd, void *address)
Load initrd.
Definition: initrd.c:257
An executable image.
Definition: image.h:23
static size_t initrd_align(size_t len)
Align initrd length.
Definition: initrd.h:29
#define INITRD_ALIGN
Initial ramdisk chunk alignment.
Definition: initrd.h:16
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
ring len
Length.
Definition: dwmac.h:231
#define for_each_image(image)
Iterate over all registered images.
Definition: image.h:190
long pad_len
Definition: bigint.h:30
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:150
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
void * memset(void *dest, int character, size_t len) __nonnull

References address, assert(), dest, for_each_image, INITRD_ALIGN, initrd_align(), initrd_load(), len, memset(), NULL, and pad_len.

Referenced by bzimage_load_initrds(), initrd_len(), and lkrn_exec().

◆ initrd_region()

int initrd_region ( size_t  len,
struct memmap_region region 
)

Calculate post-reshuffle initrd load region.

Parameters
lenLength of initrds (from initrd_len())
regionRegion descriptor to fill in
Return values
rcReturn status code

If successful, then any suitably aligned range within the region may be used as the load address after reshuffling. The caller does not need to call prep_segment() for a range in this region. (Calling prep_segment() would probably fail, since prior to reshuffling the region is still in use by the external heap.)

Definition at line 354 of file initrd.c.

354  {
355  physaddr_t min;
356  size_t available;
357 
358  /* Calculate limits of available space for initrds */
359  min = uheap_limit;
360  available = ( ( initrd_end ? initrd_end : uheap_end ) - min );
361  if ( available < len )
362  return -ENOSPC;
363  DBGC ( &images, "INITRD post-reshuffle region is [%#08lx,%#08lx)\n",
364  min, ( min + available ) );
365 
366  /* Populate region descriptor */
367  region->min = min;
368  region->max = ( min + available - 1 );
369  region->flags = MEMMAP_FL_MEMORY;
370  region->name = "initrd";
371 
372  return 0;
373 }
uint64_t max
Maximum address in region.
Definition: memmap.h:52
#define DBGC(...)
Definition: compiler.h:505
#define min(x, y)
Definition: ath.h:35
static physaddr_t initrd_end
End of reshuffle region.
Definition: initrd.c:42
ring len
Length.
Definition: dwmac.h:231
unsigned int flags
Region flags.
Definition: memmap.h:54
struct list_head images
List of registered images.
Definition: image.c:58
const char * name
Region name (for debug messages)
Definition: memmap.h:56
unsigned long physaddr_t
Definition: stdint.h:20
#define ENOSPC
No space left on device.
Definition: errno.h:549
physaddr_t uheap_limit
Minimum possible start of external heap.
Definition: uheap.c:54
#define MEMMAP_FL_MEMORY
Contains memory.
Definition: memmap.h:59
uint64_t min
Minimum address in region.
Definition: memmap.h:50
physaddr_t uheap_end
End of external heap.
Definition: uheap.c:60

References DBGC, ENOSPC, memmap_region::flags, images, initrd_end, len, memmap_region::max, MEMMAP_FL_MEMORY, min, memmap_region::min, memmap_region::name, uheap_end, and uheap_limit.

Referenced by bzimage_check_initrds(), and lkrn_exec().

◆ initrd_startup()

static void initrd_startup ( void  )
static

initrd startup function

Definition at line 379 of file initrd.c.

379  {
380 
381  /* Record address above which reshuffling cannot take place.
382  * If any external heap allocations have been made during
383  * driver startup (e.g. large host memory blocks for
384  * Infiniband devices, which may still be in use at the time
385  * of rearranging if a SAN device is hooked), then we must not
386  * overwrite these allocations during reshuffling.
387  */
389  if ( initrd_end ) {
390  DBGC ( &images, "INITRD limiting reshuffling to below "
391  "%#08lx\n", initrd_end );
392  }
393 }
#define DBGC(...)
Definition: compiler.h:505
physaddr_t uheap_start
Start of external heap.
Definition: uheap.c:57
static physaddr_t initrd_end
End of reshuffle region.
Definition: initrd.c:42
struct list_head images
List of registered images.
Definition: image.c:58

References DBGC, images, initrd_end, and uheap_start.

◆ __startup_fn()

struct startup_fn startup_initrd __startup_fn ( STARTUP_LATE  )

initrd startup function

Variable Documentation

◆ initrd_end

physaddr_t initrd_end
static

End of reshuffle region.

Definition at line 42 of file initrd.c.

Referenced by comboot_fetch_kernel(), initrd_region(), initrd_reshuffle(), and initrd_startup().