iPXE
lkrn.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2025 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 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 #include <stdint.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <byteswap.h>
30 #include <ipxe/image.h>
31 #include <ipxe/memmap.h>
32 #include <ipxe/uaccess.h>
33 #include <ipxe/segment.h>
34 #include <ipxe/initrd.h>
35 #include <ipxe/io.h>
36 #include <ipxe/fdt.h>
37 #include <ipxe/init.h>
38 #include <ipxe/lkrn.h>
39 
40 /** @file
41  *
42  * Linux kernel image format
43  *
44  */
45 
46 /**
47  * Parse kernel image
48  *
49  * @v image Kernel image
50  * @v ctx Kernel image context
51  * @ret rc Return status code
52  */
53 static int lkrn_parse ( struct image *image, struct lkrn_context *ctx ) {
54  const struct lkrn_header *hdr;
55 
56  /* Initialise context */
57  memset ( ctx, 0, sizeof ( *ctx ) );
58 
59  /* Read image header */
60  if ( image->len < sizeof ( *hdr ) ) {
61  DBGC ( image, "LKRN %s too short for header\n", image->name );
62  return -ENOEXEC;
63  }
64  hdr = image->data;
65 
66  /* Check magic value */
67  if ( hdr->magic != cpu_to_le32 ( LKRN_MAGIC_ARCH ) ) {
68  DBGC ( image, "LKRN %s bad magic value %#08x\n",
69  image->name, le32_to_cpu ( hdr->magic ) );
70  return -ENOEXEC;
71  }
72 
73  /* Record load offset */
74  ctx->offset = le64_to_cpu ( hdr->text_offset );
75  if ( ctx->offset & ( ctx->offset - 1 ) ) {
76  DBGC ( image, "LKRN %s offset %#zx is not a power of two\n",
77  image->name, ctx->offset );
78  return -ENOEXEC;
79  }
80 
81  /* Record and check image size */
82  ctx->filesz = image->len;
83  ctx->memsz = le64_to_cpu ( hdr->image_size );
84  if ( ctx->filesz > ctx->memsz ) {
85  DBGC ( image, "LKRN %s invalid image size %#zx/%#zx\n",
86  image->name, ctx->filesz, ctx->memsz );
87  return -ENOEXEC;
88  }
89 
90  return 0;
91 }
92 
93 /**
94  * Locate start of RAM
95  *
96  * @v image Kernel image
97  * @v ctx Kernel image context
98  * @ret rc Return status code
99  */
100 static int lkrn_ram ( struct image *image, struct lkrn_context *ctx ) {
101  struct memmap_region region;
102 
103  /* Locate start of RAM */
104  for_each_memmap ( &region, 0 ) {
105  DBGC_MEMMAP ( image, &region );
106  if ( ! ( region.flags & MEMMAP_FL_MEMORY ) )
107  continue;
108  ctx->ram = region.min;
109  DBGC ( image, "LKRN %s RAM starts at %#08lx\n",
110  image->name, ctx->ram );
111  return 0;
112  }
113 
114  DBGC ( image, "LKRN %s found no RAM\n", image->name );
115  return -ENOTSUP;
116 }
117 
118 /**
119  * Execute kernel image
120  *
121  * @v image Kernel image
122  * @ret rc Return status code
123  */
124 static int lkrn_exec ( struct image *image ) {
125  static struct image fdtimg = {
126  .refcnt = REF_INIT ( free_image ),
127  .name = "<FDT>",
128  .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ),
129  };
130  struct lkrn_context ctx;
131  struct memmap_region region;
132  struct fdt_header *fdt;
133  size_t initrdsz;
134  size_t totalsz;
135  void *dest;
136  int rc;
137 
138  /* Parse header */
139  if ( ( rc = lkrn_parse ( image, &ctx ) ) != 0 )
140  goto err_parse;
141 
142  /* Locate start of RAM */
143  if ( ( rc = lkrn_ram ( image, &ctx ) ) != 0 )
144  goto err_ram;
145 
146  /* Place kernel at specified address from start of RAM */
147  ctx.entry = ( ctx.ram + ctx.offset );
148  DBGC ( image, "LKRN %s loading to [%#08lx,%#08lx,%#08lx)\n",
149  image->name, ctx.entry, ( ctx.entry + ctx.filesz ),
150  ( ctx.entry + ctx.memsz ) );
151 
152  /* Place initrd after kernel, aligned to the kernel's image offset */
153  ctx.initrd = ( ctx.ram + initrd_align ( ctx.offset + ctx.memsz ) );
154  ctx.initrd = ( ( ctx.initrd + ctx.offset - 1 ) & ~( ctx.offset - 1 ) );
155  initrdsz = initrd_len();
156  if ( initrdsz ) {
157  DBGC ( image, "LKRN %s initrd at [%#08lx,%#08lx)\n",
158  image->name, ctx.initrd, ( ctx.initrd + initrdsz ) );
159  }
160 
161  /* Place device tree after initrd */
162  ctx.fdt = ( ctx.initrd + initrd_align ( initrdsz ) );
163 
164  /* Construct device tree and post-initrd image */
165  if ( ( rc = fdt_create ( &fdt, image->cmdline, ctx.initrd,
166  initrdsz ) ) != 0 ) {
167  goto err_fdt;
168  }
169  fdtimg.data = fdt;
170  fdtimg.len = be32_to_cpu ( fdt->totalsize );
171  list_add_tail ( &fdtimg.list, &images );
172  DBGC ( image, "LKRN %s FDT at [%08lx,%08lx)\n",
173  image->name, ctx.fdt, ( ctx.fdt + fdtimg.len ) );
174 
175  /* Find post-reshuffle region */
176  if ( ( rc = initrd_region ( initrdsz, &region ) ) != 0 ) {
177  DBGC ( image, "LKRN %s no available region: %s\n",
178  image->name, strerror ( rc ) );
179  goto err_region;
180  }
181 
182  /* Check that everything can be placed at its target addresses */
183  totalsz = ( ctx.fdt + fdtimg.len - ctx.ram );
184  if ( ( ctx.entry >= region.min ) &&
185  ( ( ctx.offset + totalsz ) <= memmap_size ( &region ) ) ) {
186  /* Target addresses are within the reshuffle region */
187  DBGC ( image, "LKRN %s fits within reshuffle region\n",
188  image->name );
189  } else {
190  /* Target addresses are outside the reshuffle region */
191  if ( ( rc = prep_segment ( phys_to_virt ( ctx.entry ),
192  totalsz, totalsz ) ) != 0 ) {
193  DBGC ( image, "LKRN %s could not prepare segment: "
194  "%s\n", image->name, strerror ( rc ) );
195  goto err_segment;
196  }
197  }
198 
199  /* This is the point of no return: we are about to reshuffle
200  * and thereby destroy the external heap. No errors are
201  * allowed to occur after this point.
202  */
203 
204  /* Shut down ready for boot */
205  shutdown_boot();
206 
207  /* Prepend kernel to reshuffle list, reshuffle, and remove kernel */
208  list_add ( &image->list, &images );
210  list_del ( &image->list );
211 
212  /* Load kernel to entry point and zero bss */
213  dest = phys_to_virt ( ctx.entry );
214  memmove ( dest, image->data, ctx.filesz );
215  memset ( ( dest + ctx.filesz ), 0, ( ctx.memsz - ctx.filesz ) );
216 
217  /* Load initrds and device tree */
218  dest = phys_to_virt ( ctx.initrd );
219  initrd_load_all ( dest );
220 
221  /* Jump to kernel entry point */
222  DBGC ( image, "LKRN %s jumping to kernel at %#08lx\n",
223  image->name, ctx.entry );
224  lkrn_jump ( ctx.entry, ctx.fdt );
225 
226  /* There is no way for the image to return, since we provide
227  * no return address.
228  */
229  assert ( 0 );
230 
231  return -ECANCELED; /* -EIMPOSSIBLE */
232 
233  err_segment:
234  err_region:
235  list_del ( &fdtimg.list );
236  fdt_remove ( fdt );
237  err_fdt:
238  err_ram:
239  err_parse:
240  return rc;
241 }
242 
243 /**
244  * Probe kernel image
245  *
246  * @v image Kernel image
247  * @ret rc Return status code
248  */
249 static int lkrn_probe ( struct image *image ) {
250  struct lkrn_context ctx;
251  int rc;
252 
253  /* Parse header */
254  if ( ( rc = lkrn_parse ( image, &ctx ) ) != 0 )
255  return rc;
256 
257  DBGC ( image, "LKRN %s is a Linux kernel\n", image->name );
258  return 0;
259 }
260 
261 /** Linux kernel image type */
262 struct image_type lkrn_image_type __image_type ( PROBE_NORMAL ) = {
263  .name = "lkrn",
264  .probe = lkrn_probe,
265  .exec = lkrn_exec,
266 };
267 
268 /**
269  * Parse compressed kernel image
270  *
271  * @v image Compressed kernel image
272  * @v zctx Compressed kernel image context
273  * @ret rc Return status code
274  */
275 static int zimg_parse ( struct image *image, struct zimg_context *zctx ) {
276  const struct zimg_header *zhdr;
277 
278  /* Initialise context */
279  memset ( zctx, 0, sizeof ( *zctx ) );
280 
281  /* Parse header */
282  if ( image->len < sizeof ( *zhdr ) ) {
283  DBGC ( image, "ZIMG %s too short for header\n",
284  image->name );
285  return -ENOEXEC;
286  }
287  zhdr = image->data;
288 
289  /* Check magic value */
290  if ( zhdr->magic != cpu_to_le32 ( ZIMG_MAGIC ) ) {
291  DBGC ( image, "ZIMG %s bad magic value %#08x\n",
292  image->name, le32_to_cpu ( zhdr->magic ) );
293  return -ENOEXEC;
294  }
295 
296  /* Record and check offset and length */
297  zctx->offset = le32_to_cpu ( zhdr->offset );
298  zctx->len = le32_to_cpu ( zhdr->len );
299  if ( ( zctx->offset > image->len ) ||
300  ( zctx->len > ( image->len - zctx->offset ) ) ) {
301  DBGC ( image, "ZIMG %s bad range [+%#zx,+%#zx)/%#zx\n",
302  image->name, zctx->offset,
303  (zctx->offset + zctx->len ), image->len );
304  return -ENOEXEC;
305  }
306 
307  /* Record compression type */
308  zctx->type.raw = zhdr->type;
309 
310  return 0;
311 }
312 
313 /**
314  * Extract compresed kernel image
315  *
316  * @v image Compressed kernel image
317  * @v extracted Extracted image
318  * @ret rc Return status code
319  */
320 static int zimg_extract ( struct image *image, struct image *extracted ) {
321  struct zimg_context zctx;
322  const void *payload;
323  int rc;
324 
325  /* Parse header */
326  if ( ( rc = zimg_parse ( image, &zctx ) ) != 0 )
327  return rc;
328  DBGC ( image, "ZIMG %s has %s-compressed payload at [+%#zx,+%#zx)\n",
329  image->name, zctx.type.string, zctx.offset,
330  ( zctx.offset + zctx.len ) );
331 
332  /* Extract compressed payload */
333  payload = ( image->data + zctx.offset );
334  if ( ( rc = image_set_data ( extracted, payload, zctx.len ) ) != 0 ) {
335  DBGC ( image, "ZIMG %s could not extract: %s\n",
336  image->name, strerror ( rc ) );
337  return rc;
338  }
339 
340  return 0;
341 }
342 
343 /**
344  * Probe compressed kernel image
345  *
346  * @v image Compressed kernel image
347  * @ret rc Return status code
348  */
349 static int zimg_probe ( struct image *image ) {
350  struct zimg_context zctx;
351  int rc;
352 
353  /* Parse header */
354  if ( ( rc = zimg_parse ( image, &zctx ) ) != 0 )
355  return rc;
356 
357  DBGC ( image, "ZIMG %s is a %s-compressed Linux kernel\n",
358  image->name, zctx.type.string );
359  return 0;
360 }
361 
362 /** Linux kernel compressed image type */
363 struct image_type zimg_image_type __image_type ( PROBE_NORMAL ) = {
364  .name = "zimg",
365  .probe = zimg_probe,
366  .extract = zimg_extract,
367  .exec = image_extract_exec,
368 };
size_t offset
Offset to compressed data.
Definition: lkrn.h:83
iPXE I/O API
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
uint32_t offset
Offset to payload.
Definition: lkrn.h:68
#define le32_to_cpu(value)
Definition: byteswap.h:113
#define list_add(new, head)
Add a new entry to the head of a list.
Definition: list.h:69
Error codes.
const void * data
Read-only data.
Definition: image.h:50
Device tree header.
Definition: fdt.h:18
struct golan_inbox_hdr hdr
Message header.
Definition: CIB_PRM.h:28
#define ENOEXEC
Exec format error.
Definition: errno.h:519
Kernel image context.
Definition: lkrn.h:43
#define DBGC(...)
Definition: compiler.h:505
An executable image type.
Definition: image.h:94
#define PROBE_NORMAL
Normal image probe priority.
Definition: image.h:155
int initrd_region(size_t len, struct memmap_region *region)
Calculate post-reshuffle initrd load region.
Definition: initrd.c:354
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
Compressed kernel image context.
Definition: lkrn.h:81
An executable image.
Definition: image.h:23
static int lkrn_probe(struct image *image)
Probe kernel image.
Definition: lkrn.c:249
struct golan_eq_context ctx
Definition: CIB_PRM.h:28
static size_t initrd_align(size_t len)
Align initrd length.
Definition: initrd.h:29
#define DBGC_MEMMAP(...)
Definition: memmap.h:206
void initrd_reshuffle(void)
Reshuffle initrds into desired order at top of memory.
Definition: initrd.c:229
#define ECANCELED
Operation canceled.
Definition: errno.h:343
char * name
Name of this image type.
Definition: image.h:96
#define ENOTSUP
Operation not supported.
Definition: errno.h:589
char * cmdline
Command line to pass to image.
Definition: image.h:42
uint32_t magic
Magic.
Definition: lkrn.h:66
#define list_del(list)
Delete an entry from a list.
Definition: list.h:119
Executable image segments.
Compressed kernel image header.
Definition: lkrn.h:62
void free_image(struct refcnt *refcnt)
Free executable image.
Definition: image.c:85
static int zimg_probe(struct image *image)
Probe compressed kernel image.
Definition: lkrn.c:349
static int lkrn_ram(struct image *image, struct lkrn_context *ctx)
Locate start of RAM.
Definition: lkrn.c:100
uint32_t type
Compression type.
Definition: lkrn.h:74
#define IMAGE_STATIC
Image is statically allocated.
Definition: image.h:88
#define be32_to_cpu(value)
Definition: byteswap.h:116
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
Access to external ("user") memory.
struct image_type lkrn_image_type __image_type(PROBE_NORMAL)
Linux kernel image type.
Executable images.
#define for_each_memmap(region, hide)
Iterate over memory regions.
Definition: memmap.h:183
#define list_add_tail(new, head)
Add a new entry to the tail of a list.
Definition: list.h:93
size_t initrd_load_all(void *address)
Load all initrds.
Definition: initrd.c:317
void fdt_remove(struct fdt_header *hdr)
Remove device tree.
Definition: fdt.c:1458
#define cpu_to_le32(value)
Definition: byteswap.h:107
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
void lkrn_jump(physaddr_t entry, physaddr_t fdt)
Jump to kernel entry point.
union zimg_context::@637 type
Compression type.
unsigned int flags
Region flags.
Definition: memmap.h:54
size_t len
Length of raw file image.
Definition: image.h:55
struct list_head images
List of registered images.
Definition: image.c:58
uint32_t len
Length of payload.
Definition: lkrn.h:70
#define ZIMG_MAGIC
Compressed kernel image magic value.
Definition: lkrn.h:78
static int lkrn_exec(struct image *image)
Execute kernel image.
Definition: lkrn.c:124
size_t len
Length of compressed data.
Definition: lkrn.h:85
void * memmove(void *dest, const void *src, size_t len) __nonnull
Kernel image header.
Definition: lkrn.h:15
int image_set_data(struct image *image, const void *data, size_t len)
Set image data.
Definition: image.c:269
Initial ramdisk (initrd) reshuffling.
A device tree.
Definition: fdt.h:88
static int zimg_extract(struct image *image, struct image *extracted)
Extract compresed kernel image.
Definition: lkrn.c:320
static int lkrn_parse(struct image *image, struct lkrn_context *ctx)
Parse kernel image.
Definition: lkrn.c:53
static uint64_t memmap_size(const struct memmap_region *region)
Get remaining size of memory region (from the described address upwards)
Definition: memmap.h:98
#define MEMMAP_FL_MEMORY
Contains memory.
Definition: memmap.h:59
#define IMAGE_STATIC_NAME
Image name is statically allocated.
Definition: image.h:91
Flattened Device Tree.
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 REF_INIT(free_fn)
Initialise a static reference counter.
Definition: refcnt.h:77
Linux kernel images.
uint64_t min
Minimum address in region.
Definition: memmap.h:50
uint32_t raw
Raw type.
Definition: lkrn.h:89
int prep_segment(void *segment, size_t filesz, size_t memsz)
Prepare segment for loading.
Definition: segment.c:61
A memory region descriptor.
Definition: memmap.h:48
struct list_head list
List of registered images.
Definition: image.h:28
#define LKRN_MAGIC_ARCH
Definition: lkrn.h:15
#define le64_to_cpu(value)
Definition: byteswap.h:114
static void shutdown_boot(void)
Shut down system for OS boot.
Definition: init.h:77
int fdt_create(struct fdt_header **hdr, const char *cmdline, physaddr_t initrd, size_t initrd_len)
Create device tree.
Definition: fdt.c:1407
char * name
Name.
Definition: image.h:37
char string[5]
Printable string.
Definition: lkrn.h:91
System memory map.
String functions.
static int zimg_parse(struct image *image, struct zimg_context *zctx)
Parse compressed kernel image.
Definition: lkrn.c:275
int image_extract_exec(struct image *image)
Extract and execute image.
Definition: archive.c:107
void * memset(void *dest, int character, size_t len) __nonnull
#define initrd_len
Definition: runtime.c:63
struct refcnt refcnt
Reference count.
Definition: image.h:25