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