iPXE
Functions | Variables
initrd.c File Reference

Initial ramdisk (initrd) reshuffling. More...

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

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
 
static userptr_t initrd_squash_high (userptr_t top)
 Squash initrds as high as possible in memory. More...
 
static void initrd_swap (struct image *low, struct image *high, userptr_t free, size_t free_len)
 Swap position of two adjacent initrds. More...
 
static int initrd_swap_any (userptr_t free, size_t free_len)
 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 (userptr_t bottom)
 Reshuffle initrds into desired order at top of memory. More...
 
int initrd_reshuffle_check (size_t len, userptr_t bottom)
 Check that there is enough space to reshuffle initrds. More...
 
static void initrd_startup (void)
 initrd startup function More...
 
struct startup_fn startup_initrd __startup_fn (STARTUP_LATE)
 initrd startup function More...
 

Variables

userptr_t initrd_top
 Maximum address available for initrd. More...
 
userptr_t initrd_bottom
 Minimum address available for initrd. 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 userptr_t initrd_squash_high ( userptr_t  top)
static

Squash initrds as high as possible in memory.

Parameters
topHighest possible address
Return values
usedLowest address used by initrds

Definition at line 52 of file initrd.c.

52  {
53  userptr_t current = top;
54  struct image *initrd;
55  struct image *highest;
56  size_t len;
57 
58  /* Squash up any initrds already within or below the region */
59  while ( 1 ) {
60 
61  /* Find the highest image not yet in its final position */
62  highest = NULL;
63  for_each_image ( initrd ) {
64  if ( ( userptr_sub ( initrd->data, current ) < 0 ) &&
65  ( ( highest == NULL ) ||
66  ( userptr_sub ( initrd->data,
67  highest->data ) > 0 ) ) ) {
68  highest = initrd;
69  }
70  }
71  if ( ! highest )
72  break;
73 
74  /* Move this image to its final position */
75  len = ( ( highest->len + INITRD_ALIGN - 1 ) &
76  ~( INITRD_ALIGN - 1 ) );
77  current = userptr_sub ( current, len );
78  DBGC ( &images, "INITRD squashing %s [%#08lx,%#08lx)->"
79  "[%#08lx,%#08lx)\n", highest->name,
80  user_to_phys ( highest->data, 0 ),
81  user_to_phys ( highest->data, highest->len ),
82  user_to_phys ( current, 0 ),
83  user_to_phys ( current, highest->len ) );
84  memmove_user ( current, 0, highest->data, 0, highest->len );
85  highest->data = current;
86  }
87 
88  /* Copy any remaining initrds (e.g. embedded images) to the region */
89  for_each_image ( initrd ) {
90  if ( userptr_sub ( initrd->data, top ) >= 0 ) {
91  len = ( ( initrd->len + INITRD_ALIGN - 1 ) &
92  ~( INITRD_ALIGN - 1 ) );
93  current = userptr_sub ( current, len );
94  DBGC ( &images, "INITRD copying %s [%#08lx,%#08lx)->"
95  "[%#08lx,%#08lx)\n", initrd->name,
96  user_to_phys ( initrd->data, 0 ),
97  user_to_phys ( initrd->data, initrd->len ),
98  user_to_phys ( current, 0 ),
99  user_to_phys ( current, initrd->len ) );
100  memcpy_user ( current, 0, initrd->data, 0,
101  initrd->len );
102  initrd->data = current;
103  }
104  }
105 
106  return current;
107 }
userptr_t data
Raw file image.
Definition: image.h:41
unsigned long user_to_phys(userptr_t userptr, off_t offset)
Convert user pointer to physical address.
#define DBGC(...)
Definition: compiler.h:505
An executable image.
Definition: image.h:24
off_t userptr_sub(userptr_t userptr, userptr_t subtrahend)
Subtract user pointers.
#define for_each_image(image)
Iterate over all registered images.
Definition: image.h:172
size_t len
Length of raw file image.
Definition: image.h:43
static userptr_t top
Top of heap.
struct list_head images
List of registered images.
Definition: image.c:57
#define INITRD_ALIGN
Alignment for CPIO archives within an initrd.
Definition: cpio.h:57
uint32_t len
Length.
Definition: ena.h:14
void memmove_user(userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, size_t len)
Copy data between user buffers, allowing for overlap.
char * name
Name.
Definition: image.h:34
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
void memcpy_user(userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, size_t len)
Copy data between user buffers.
unsigned long userptr_t
A pointer to a user buffer.
Definition: uaccess.h:33

References image::data, DBGC, for_each_image, images, INITRD_ALIGN, len, image::len, memcpy_user(), memmove_user(), image::name, NULL, top, user_to_phys(), and userptr_sub().

Referenced by initrd_reshuffle().

◆ initrd_swap()

static void initrd_swap ( struct image low,
struct image high,
userptr_t  free,
size_t  free_len 
)
static

Swap position of two adjacent initrds.

Parameters
lowLower initrd
highHigher initrd
freeFree space
free_lenLength of free space

Definition at line 117 of file initrd.c.

118  {
119  size_t len = 0;
120  size_t frag_len;
121  size_t new_len;
122 
123  DBGC ( &images, "INITRD swapping %s [%#08lx,%#08lx)<->[%#08lx,%#08lx) "
124  "%s\n", low->name, user_to_phys ( low->data, 0 ),
125  user_to_phys ( low->data, low->len ),
126  user_to_phys ( high->data, 0 ),
127  user_to_phys ( high->data, high->len ), high->name );
128 
129  /* Round down length of free space */
130  free_len &= ~( INITRD_ALIGN - 1 );
131  assert ( free_len > 0 );
132 
133  /* Swap image data */
134  while ( len < high->len ) {
135 
136  /* Calculate maximum fragment length */
137  frag_len = ( high->len - len );
138  if ( frag_len > free_len )
139  frag_len = free_len;
140  new_len = ( ( len + frag_len + INITRD_ALIGN - 1 ) &
141  ~( INITRD_ALIGN - 1 ) );
142 
143  /* Swap fragments */
144  memcpy_user ( free, 0, high->data, len, frag_len );
145  memmove_user ( low->data, new_len, low->data, len, low->len );
146  memcpy_user ( low->data, len, free, 0, frag_len );
147  len = new_len;
148  }
149 
150  /* Adjust data pointers */
151  high->data = low->data;
152  low->data = userptr_add ( low->data, len );
153 }
uint32_t low
Low 16 bits of address.
Definition: myson.h:19
unsigned long user_to_phys(userptr_t userptr, off_t offset)
Convert user pointer to physical address.
#define DBGC(...)
Definition: compiler.h:505
userptr_t userptr_add(userptr_t userptr, off_t offset)
Add offset to user pointer.
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
uint32_t high
High 32 bits of address.
Definition: myson.h:20
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
struct list_head images
List of registered images.
Definition: image.c:57
#define INITRD_ALIGN
Alignment for CPIO archives within an initrd.
Definition: cpio.h:57
uint32_t len
Length.
Definition: ena.h:14
void memmove_user(userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, size_t len)
Copy data between user buffers, allowing for overlap.
void memcpy_user(userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, size_t len)
Copy data between user buffers.

References assert(), DBGC, free, high, images, INITRD_ALIGN, len, low, memcpy_user(), memmove_user(), user_to_phys(), and userptr_add().

Referenced by initrd_swap_any().

◆ initrd_swap_any()

static int initrd_swap_any ( userptr_t  free,
size_t  free_len 
)
static

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

Parameters
freeFree space
free_lenLength of free space
Return values
swappedA pair of initrds was swapped

Definition at line 162 of file initrd.c.

162  {
163  struct image *low;
164  struct image *high;
165  size_t padded_len;
166  userptr_t adjacent;
167 
168  /* Find any pair of initrds that can be swapped */
169  for_each_image ( low ) {
170 
171  /* Calculate location of adjacent image (if any) */
172  padded_len = ( ( low->len + INITRD_ALIGN - 1 ) &
173  ~( INITRD_ALIGN - 1 ) );
174  adjacent = userptr_add ( low->data, padded_len );
175 
176  /* Search for adjacent image */
177  for_each_image ( high ) {
178 
179  /* Stop search if all remaining potential
180  * adjacent images are already in the correct
181  * order.
182  */
183  if ( high == low )
184  break;
185 
186  /* If we have found the adjacent image, swap and exit */
187  if ( high->data == adjacent ) {
188  initrd_swap ( low, high, free, free_len );
189  return 1;
190  }
191  }
192  }
193 
194  /* Nothing swapped */
195  return 0;
196 }
static void initrd_swap(struct image *low, struct image *high, userptr_t free, size_t free_len)
Swap position of two adjacent initrds.
Definition: initrd.c:117
uint32_t low
Low 16 bits of address.
Definition: myson.h:19
An executable image.
Definition: image.h:24
userptr_t userptr_add(userptr_t userptr, off_t offset)
Add offset to user pointer.
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:172
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
#define INITRD_ALIGN
Alignment for CPIO archives within an initrd.
Definition: cpio.h:57
unsigned long userptr_t
A pointer to a user buffer.
Definition: uaccess.h:33

References for_each_image, free, high, INITRD_ALIGN, initrd_swap(), low, and userptr_add().

Referenced by initrd_reshuffle().

◆ initrd_dump()

static void initrd_dump ( void  )
static

Dump initrd locations (for debug)

Definition at line 202 of file initrd.c.

202  {
203  struct image *initrd;
204 
205  /* Do nothing unless debugging is enabled */
206  if ( ! DBG_LOG )
207  return;
208 
209  /* Dump initrd locations */
210  for_each_image ( initrd ) {
211  DBGC ( &images, "INITRD %s at [%#08lx,%#08lx)\n",
212  initrd->name, user_to_phys ( initrd->data, 0 ),
213  user_to_phys ( initrd->data, initrd->len ) );
214  DBGC2_MD5A ( &images, user_to_phys ( initrd->data, 0 ),
215  user_to_virt ( initrd->data, 0 ), initrd->len );
216  }
217 }
userptr_t data
Raw file image.
Definition: image.h:41
unsigned long user_to_phys(userptr_t userptr, off_t offset)
Convert user pointer to physical address.
#define DBGC(...)
Definition: compiler.h:505
An executable image.
Definition: image.h:24
#define DBGC2_MD5A(...)
Definition: compiler.h:525
#define for_each_image(image)
Iterate over all registered images.
Definition: image.h:172
size_t len
Length of raw file image.
Definition: image.h:43
struct list_head images
List of registered images.
Definition: image.c:57
void * user_to_virt(userptr_t userptr, off_t offset)
Convert user pointer to virtual address.
#define DBG_LOG
Definition: compiler.h:317
char * name
Name.
Definition: image.h:34

References image::data, DBG_LOG, DBGC, DBGC2_MD5A, for_each_image, images, image::len, image::name, user_to_phys(), and user_to_virt().

Referenced by initrd_reshuffle().

◆ initrd_reshuffle()

void initrd_reshuffle ( userptr_t  bottom)

Reshuffle initrds into desired order at top of memory.

Parameters
bottomLowest address available for initrds

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 230 of file initrd.c.

230  {
231  userptr_t top;
232  userptr_t used;
233  userptr_t free;
234  size_t free_len;
235 
236  /* Calculate limits of available space for initrds */
237  top = initrd_top;
238  if ( userptr_sub ( initrd_bottom, bottom ) > 0 )
240 
241  /* Debug */
242  DBGC ( &images, "INITRD region [%#08lx,%#08lx)\n",
243  user_to_phys ( bottom, 0 ), user_to_phys ( top, 0 ) );
244  initrd_dump();
245 
246  /* Squash initrds as high as possible in memory */
247  used = initrd_squash_high ( top );
248 
249  /* Calculate available free space */
250  free = bottom;
251  free_len = userptr_sub ( used, free );
252 
253  /* Bubble-sort initrds into desired order */
254  while ( initrd_swap_any ( free, free_len ) ) {}
255 
256  /* Debug */
257  initrd_dump();
258 }
static int initrd_swap_any(userptr_t free, size_t free_len)
Swap position of any two adjacent initrds not currently in the correct order.
Definition: initrd.c:162
userptr_t initrd_bottom
Minimum address available for initrd.
Definition: initrd.c:44
unsigned long user_to_phys(userptr_t userptr, off_t offset)
Convert user pointer to physical address.
#define DBGC(...)
Definition: compiler.h:505
static userptr_t bottom
Bottom of heap (current lowest allocated block)
off_t userptr_sub(userptr_t userptr, userptr_t subtrahend)
Subtract user pointers.
userptr_t initrd_top
Maximum address available for initrd.
Definition: initrd.c:41
static void initrd_dump(void)
Dump initrd locations (for debug)
Definition: initrd.c:202
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
static userptr_t top
Top of heap.
struct list_head images
List of registered images.
Definition: image.c:57
static userptr_t initrd_squash_high(userptr_t top)
Squash initrds as high as possible in memory.
Definition: initrd.c:52
unsigned long userptr_t
A pointer to a user buffer.
Definition: uaccess.h:33

References bottom, DBGC, free, images, initrd_bottom, initrd_dump(), initrd_squash_high(), initrd_swap_any(), initrd_top, top, user_to_phys(), and userptr_sub().

Referenced by bzimage_load_initrds().

◆ initrd_reshuffle_check()

int initrd_reshuffle_check ( size_t  len,
userptr_t  bottom 
)

Check that there is enough space to reshuffle initrds.

Parameters
lenTotal length of initrds (including padding)
bottomLowest address available for initrds
Return values
rcReturn status code

Definition at line 267 of file initrd.c.

267  {
268  userptr_t top;
269  size_t available;
270 
271  /* Calculate limits of available space for initrds */
272  top = initrd_top;
273  if ( userptr_sub ( initrd_bottom, bottom ) > 0 )
275  available = userptr_sub ( top, bottom );
276 
277  /* Allow for a sensible minimum amount of free space */
279 
280  /* Check for available space */
281  return ( ( len < available ) ? 0 : -ENOBUFS );
282 }
userptr_t initrd_bottom
Minimum address available for initrd.
Definition: initrd.c:44
#define INITRD_MIN_FREE_LEN
Minimum free space required to reshuffle initrds.
Definition: initrd.h:18
static userptr_t bottom
Bottom of heap (current lowest allocated block)
off_t userptr_sub(userptr_t userptr, userptr_t subtrahend)
Subtract user pointers.
userptr_t initrd_top
Maximum address available for initrd.
Definition: initrd.c:41
static userptr_t top
Top of heap.
uint32_t len
Length.
Definition: ena.h:14
#define ENOBUFS
No buffer space available.
Definition: errno.h:498
unsigned long userptr_t
A pointer to a user buffer.
Definition: uaccess.h:33

References bottom, ENOBUFS, initrd_bottom, INITRD_MIN_FREE_LEN, initrd_top, len, top, and userptr_sub().

Referenced by bzimage_check_initrds().

◆ initrd_startup()

static void initrd_startup ( void  )
static

initrd startup function

Definition at line 288 of file initrd.c.

288  {
289  size_t len;
290 
291  /* Record largest memory block available. Do this after any
292  * allocations made during driver startup (e.g. large host
293  * memory blocks for Infiniband devices, which may still be in
294  * use at the time of rearranging if a SAN device is hooked)
295  * but before any allocations for downloaded images (which we
296  * can safely reuse when rearranging).
297  */
300 }
userptr_t initrd_bottom
Minimum address available for initrd.
Definition: initrd.c:44
userptr_t userptr_add(userptr_t userptr, off_t offset)
Add offset to user pointer.
userptr_t initrd_top
Maximum address available for initrd.
Definition: initrd.c:41
uint32_t len
Length.
Definition: ena.h:14
size_t largest_memblock(userptr_t *start)
Find largest usable memory region.

References initrd_bottom, initrd_top, largest_memblock(), len, and userptr_add().

◆ __startup_fn()

struct startup_fn startup_initrd __startup_fn ( STARTUP_LATE  )

initrd startup function

Variable Documentation

◆ initrd_top

userptr_t initrd_top

Maximum address available for initrd.

Definition at line 41 of file initrd.c.

Referenced by initrd_reshuffle(), initrd_reshuffle_check(), and initrd_startup().

◆ initrd_bottom

userptr_t initrd_bottom

Minimum address available for initrd.

Definition at line 44 of file initrd.c.

Referenced by initrd_reshuffle(), initrd_reshuffle_check(), and initrd_startup().