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>

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

51  {
52  userptr_t current = top;
53  struct image *initrd;
54  struct image *highest;
55  size_t len;
56 
57  /* Squash up any initrds already within or below the region */
58  while ( 1 ) {
59 
60  /* Find the highest image not yet in its final position */
61  highest = NULL;
62  for_each_image ( initrd ) {
63  if ( ( userptr_sub ( initrd->data, current ) < 0 ) &&
64  ( ( highest == NULL ) ||
65  ( userptr_sub ( initrd->data,
66  highest->data ) > 0 ) ) ) {
67  highest = initrd;
68  }
69  }
70  if ( ! highest )
71  break;
72 
73  /* Move this image to its final position */
74  len = ( ( highest->len + INITRD_ALIGN - 1 ) &
75  ~( INITRD_ALIGN - 1 ) );
76  current = userptr_sub ( current, len );
77  DBGC ( &images, "INITRD squashing %s [%#08lx,%#08lx)->"
78  "[%#08lx,%#08lx)\n", highest->name,
79  user_to_phys ( highest->data, 0 ),
80  user_to_phys ( highest->data, highest->len ),
81  user_to_phys ( current, 0 ),
82  user_to_phys ( current, highest->len ) );
83  memmove_user ( current, 0, highest->data, 0, highest->len );
84  highest->data = current;
85  }
86 
87  /* Copy any remaining initrds (e.g. embedded images) to the region */
88  for_each_image ( initrd ) {
89  if ( userptr_sub ( initrd->data, top ) >= 0 ) {
90  len = ( ( initrd->len + INITRD_ALIGN - 1 ) &
91  ~( INITRD_ALIGN - 1 ) );
92  current = userptr_sub ( current, len );
93  DBGC ( &images, "INITRD copying %s [%#08lx,%#08lx)->"
94  "[%#08lx,%#08lx)\n", initrd->name,
95  user_to_phys ( initrd->data, 0 ),
96  user_to_phys ( initrd->data, initrd->len ),
97  user_to_phys ( current, 0 ),
98  user_to_phys ( current, initrd->len ) );
99  memcpy_user ( current, 0, initrd->data, 0,
100  initrd->len );
101  initrd->data = current;
102  }
103  }
104 
105  return current;
106 }
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 INITRD_ALIGN
Minimum alignment for initrds.
Definition: initrd.h:19
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:149
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:56
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:362
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 116 of file initrd.c.

117  {
118  size_t len = 0;
119  size_t frag_len;
120  size_t new_len;
121 
122  DBGC ( &images, "INITRD swapping %s [%#08lx,%#08lx)<->[%#08lx,%#08lx) "
123  "%s\n", low->name, user_to_phys ( low->data, 0 ),
124  user_to_phys ( low->data, low->len ),
125  user_to_phys ( high->data, 0 ),
126  user_to_phys ( high->data, high->len ), high->name );
127 
128  /* Round down length of free space */
129  free_len &= ~( INITRD_ALIGN - 1 );
130  assert ( free_len > 0 );
131 
132  /* Swap image data */
133  while ( len < high->len ) {
134 
135  /* Calculate maximum fragment length */
136  frag_len = ( high->len - len );
137  if ( frag_len > free_len )
138  frag_len = free_len;
139  new_len = ( ( len + frag_len + INITRD_ALIGN - 1 ) &
140  ~( INITRD_ALIGN - 1 ) );
141 
142  /* Swap fragments */
143  memcpy_user ( free, 0, high->data, len, frag_len );
144  memmove_user ( low->data, new_len, low->data, len, low->len );
145  memcpy_user ( low->data, len, free, 0, frag_len );
146  len = new_len;
147  }
148 
149  /* Adjust data pointers */
150  high->data = low->data;
151  low->data = userptr_add ( low->data, len );
152 }
unsigned long user_to_phys(userptr_t userptr, off_t offset)
Convert user pointer to physical address.
#define DBGC(...)
Definition: compiler.h:505
#define INITRD_ALIGN
Minimum alignment for initrds.
Definition: initrd.h:19
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 low
Low 16 bits of address.
Definition: intel.h:21
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
struct list_head images
List of registered images.
Definition: image.c:56
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.
uint32_t high
High 32 bits of address.
Definition: intel.h:22
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 161 of file initrd.c.

161  {
162  struct image *low;
163  struct image *high;
164  size_t padded_len;
165  userptr_t adjacent;
166 
167  /* Find any pair of initrds that can be swapped */
168  for_each_image ( low ) {
169 
170  /* Calculate location of adjacent image (if any) */
171  padded_len = ( ( low->len + INITRD_ALIGN - 1 ) &
172  ~( INITRD_ALIGN - 1 ) );
173  adjacent = userptr_add ( low->data, padded_len );
174 
175  /* Search for adjacent image */
176  for_each_image ( high ) {
177 
178  /* If we have found the adjacent image, swap and exit */
179  if ( high->data == adjacent ) {
180  initrd_swap ( low, high, free, free_len );
181  return 1;
182  }
183 
184  /* Stop search if all remaining potential
185  * adjacent images are already in the correct
186  * order.
187  */
188  if ( high == low )
189  break;
190  }
191  }
192 
193  /* Nothing swapped */
194  return 0;
195 }
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:116
An executable image.
Definition: image.h:24
#define INITRD_ALIGN
Minimum alignment for initrds.
Definition: initrd.h:19
userptr_t userptr_add(userptr_t userptr, off_t offset)
Add offset to user pointer.
uint32_t low
Low 16 bits of address.
Definition: intel.h:21
#define for_each_image(image)
Iterate over all registered images.
Definition: image.h:149
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
uint32_t high
High 32 bits of address.
Definition: intel.h:22
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 201 of file initrd.c.

201  {
202  struct image *initrd;
203 
204  /* Do nothing unless debugging is enabled */
205  if ( ! DBG_LOG )
206  return;
207 
208  /* Dump initrd locations */
209  for_each_image ( initrd ) {
210  DBGC ( &images, "INITRD %s at [%#08lx,%#08lx)\n",
211  initrd->name, user_to_phys ( initrd->data, 0 ),
212  user_to_phys ( initrd->data, initrd->len ) );
213  DBGC2_MD5A ( &images, user_to_phys ( initrd->data, 0 ),
214  user_to_virt ( initrd->data, 0 ), initrd->len );
215  }
216 }
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:149
size_t len
Length of raw file image.
Definition: image.h:43
struct list_head images
List of registered images.
Definition: image.c:56
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 229 of file initrd.c.

229  {
230  userptr_t top;
231  userptr_t used;
232  userptr_t free;
233  size_t free_len;
234 
235  /* Calculate limits of available space for initrds */
236  top = initrd_top;
237  if ( userptr_sub ( initrd_bottom, bottom ) > 0 )
239 
240  /* Debug */
241  DBGC ( &images, "INITRD region [%#08lx,%#08lx)\n",
242  user_to_phys ( bottom, 0 ), user_to_phys ( top, 0 ) );
243  initrd_dump();
244 
245  /* Squash initrds as high as possible in memory */
246  used = initrd_squash_high ( top );
247 
248  /* Calculate available free space */
249  free = bottom;
250  free_len = userptr_sub ( used, free );
251 
252  /* Bubble-sort initrds into desired order */
253  while ( initrd_swap_any ( free, free_len ) ) {}
254 
255  /* Debug */
256  initrd_dump();
257 }
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:161
userptr_t initrd_bottom
Minimum address available for initrd.
Definition: initrd.c:43
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:40
static void initrd_dump(void)
Dump initrd locations (for debug)
Definition: initrd.c:201
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:56
static userptr_t initrd_squash_high(userptr_t top)
Squash initrds as high as possible in memory.
Definition: initrd.c:51
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 266 of file initrd.c.

266  {
267  userptr_t top;
268  size_t available;
269 
270  /* Calculate limits of available space for initrds */
271  top = initrd_top;
272  if ( userptr_sub ( initrd_bottom, bottom ) > 0 )
274  available = userptr_sub ( top, bottom );
275 
276  /* Allow for a sensible minimum amount of free space */
278 
279  /* Check for available space */
280  return ( ( len < available ) ? 0 : -ENOBUFS );
281 }
userptr_t initrd_bottom
Minimum address available for initrd.
Definition: initrd.c:43
#define INITRD_MIN_FREE_LEN
Minimum free space required to reshuffle initrds.
Definition: initrd.h:25
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:40
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 287 of file initrd.c.

287  {
288  size_t len;
289 
290  /* Record largest memory block available. Do this after any
291  * allocations made during driver startup (e.g. large host
292  * memory blocks for Infiniband devices, which may still be in
293  * use at the time of rearranging if a SAN device is hooked)
294  * but before any allocations for downloaded images (which we
295  * can safely reuse when rearranging).
296  */
299 }
userptr_t initrd_bottom
Minimum address available for initrd.
Definition: initrd.c:43
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:40
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 40 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 43 of file initrd.c.

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