|
@@ -42,9 +42,11 @@ FEATURE ( FEATURE_IMAGE, "bzImage", DHCP_EB_FEATURE_BZIMAGE, 1 );
|
42
|
42
|
struct image_type bzimage_image_type __image_type ( PROBE_NORMAL );
|
43
|
43
|
|
44
|
44
|
/**
|
45
|
|
- * bzImage load context
|
|
45
|
+ * bzImage context
|
46
|
46
|
*/
|
47
|
|
-struct bzimage_load_context {
|
|
47
|
+struct bzimage_context {
|
|
48
|
+ /** Boot protocol version */
|
|
49
|
+ unsigned int version;
|
48
|
50
|
/** Real-mode kernel portion load segment address */
|
49
|
51
|
unsigned int rm_kernel_seg;
|
50
|
52
|
/** Real-mode kernel portion load address */
|
|
@@ -55,28 +57,14 @@ struct bzimage_load_context {
|
55
|
57
|
size_t rm_heap;
|
56
|
58
|
/** Command line (offset from rm_kernel) */
|
57
|
59
|
size_t rm_cmdline;
|
|
60
|
+ /** Command line maximum length */
|
|
61
|
+ size_t cmdline_size;
|
58
|
62
|
/** Real-mode kernel portion total memory size */
|
59
|
63
|
size_t rm_memsz;
|
60
|
64
|
/** Non-real-mode kernel portion load address */
|
61
|
65
|
userptr_t pm_kernel;
|
62
|
66
|
/** Non-real-mode kernel portion file and memory size */
|
63
|
67
|
size_t pm_sz;
|
64
|
|
-};
|
65
|
|
-
|
66
|
|
-/**
|
67
|
|
- * bzImage execution context
|
68
|
|
- */
|
69
|
|
-struct bzimage_exec_context {
|
70
|
|
- /** Real-mode kernel portion load segment address */
|
71
|
|
- unsigned int rm_kernel_seg;
|
72
|
|
- /** Real-mode kernel portion load address */
|
73
|
|
- userptr_t rm_kernel;
|
74
|
|
- /** Real-mode heap top (offset from rm_kernel) */
|
75
|
|
- size_t rm_heap;
|
76
|
|
- /** Command line (offset from rm_kernel) */
|
77
|
|
- size_t rm_cmdline;
|
78
|
|
- /** Command line maximum length */
|
79
|
|
- size_t cmdline_size;
|
80
|
68
|
/** Video mode */
|
81
|
69
|
unsigned int vid_mode;
|
82
|
70
|
/** Memory limit */
|
|
@@ -85,18 +73,178 @@ struct bzimage_exec_context {
|
85
|
73
|
physaddr_t ramdisk_image;
|
86
|
74
|
/** Initrd size */
|
87
|
75
|
physaddr_t ramdisk_size;
|
|
76
|
+
|
|
77
|
+ /** Command line magic block */
|
|
78
|
+ struct bzimage_cmdline cmdline_magic;
|
|
79
|
+ /** bzImage header */
|
|
80
|
+ struct bzimage_header bzhdr;
|
88
|
81
|
};
|
89
|
82
|
|
|
83
|
+/**
|
|
84
|
+ * Parse bzImage header
|
|
85
|
+ *
|
|
86
|
+ * @v image bzImage file
|
|
87
|
+ * @v bzimg bzImage context
|
|
88
|
+ * @v src bzImage to parse
|
|
89
|
+ * @ret rc Return status code
|
|
90
|
+ */
|
|
91
|
+static int bzimage_parse_header ( struct image *image,
|
|
92
|
+ struct bzimage_context *bzimg,
|
|
93
|
+ userptr_t src ) {
|
|
94
|
+ unsigned int syssize;
|
|
95
|
+ int is_bzimage;
|
|
96
|
+
|
|
97
|
+ /* Sanity check */
|
|
98
|
+ if ( image->len < ( BZI_HDR_OFFSET + sizeof ( bzimg->bzhdr ) ) ) {
|
|
99
|
+ DBGC ( image, "bzImage %p too short for kernel header\n",
|
|
100
|
+ image );
|
|
101
|
+ return -ENOEXEC;
|
|
102
|
+ }
|
|
103
|
+
|
|
104
|
+ /* Read in header structures */
|
|
105
|
+ memset ( bzimg, 0, sizeof ( *bzimg ) );
|
|
106
|
+ copy_from_user ( &bzimg->cmdline_magic, src, BZI_CMDLINE_OFFSET,
|
|
107
|
+ sizeof ( bzimg->cmdline_magic ) );
|
|
108
|
+ copy_from_user ( &bzimg->bzhdr, src, BZI_HDR_OFFSET,
|
|
109
|
+ sizeof ( bzimg->bzhdr ) );
|
|
110
|
+
|
|
111
|
+ /* Calculate size of real-mode portion */
|
|
112
|
+ bzimg->rm_filesz =
|
|
113
|
+ ( ( bzimg->bzhdr.setup_sects ? bzimg->bzhdr.setup_sects : 4 ) + 1 ) << 9;
|
|
114
|
+ if ( bzimg->rm_filesz > image->len ) {
|
|
115
|
+ DBGC ( image, "bzImage %p too short for %zd byte of setup\n",
|
|
116
|
+ image, bzimg->rm_filesz );
|
|
117
|
+ return -ENOEXEC;
|
|
118
|
+ }
|
|
119
|
+ bzimg->rm_memsz = BZI_ASSUMED_RM_SIZE;
|
|
120
|
+
|
|
121
|
+ /* Calculate size of protected-mode portion */
|
|
122
|
+ bzimg->pm_sz = ( image->len - bzimg->rm_filesz );
|
|
123
|
+ syssize = ( ( bzimg->pm_sz + 15 ) / 16 );
|
|
124
|
+
|
|
125
|
+ /* Check for signatures and determine version */
|
|
126
|
+ if ( bzimg->bzhdr.boot_flag != BZI_BOOT_FLAG ) {
|
|
127
|
+ DBGC ( image, "bzImage %p missing 55AA signature\n", image );
|
|
128
|
+ return -ENOEXEC;
|
|
129
|
+ }
|
|
130
|
+ if ( bzimg->bzhdr.header == BZI_SIGNATURE ) {
|
|
131
|
+ /* 2.00+ */
|
|
132
|
+ bzimg->version = bzimg->bzhdr.version;
|
|
133
|
+ } else {
|
|
134
|
+ /* Pre-2.00. Check that the syssize field is correct,
|
|
135
|
+ * as a guard against accepting arbitrary binary data,
|
|
136
|
+ * since the 55AA check is pretty lax. Note that the
|
|
137
|
+ * syssize field is unreliable for protocols between
|
|
138
|
+ * 2.00 and 2.03 inclusive, so we should not always
|
|
139
|
+ * check this field.
|
|
140
|
+ */
|
|
141
|
+ bzimg->version = 0x0100;
|
|
142
|
+ if ( bzimg->bzhdr.syssize != syssize ) {
|
|
143
|
+ DBGC ( image, "bzImage %p bad syssize %x (expected "
|
|
144
|
+ "%x)\n", image, bzimg->bzhdr.syssize, syssize );
|
|
145
|
+ return -ENOEXEC;
|
|
146
|
+ }
|
|
147
|
+ }
|
|
148
|
+
|
|
149
|
+ /* Determine image type */
|
|
150
|
+ is_bzimage = ( ( bzimg->version >= 0x0200 ) ?
|
|
151
|
+ ( bzimg->bzhdr.loadflags & BZI_LOAD_HIGH ) : 0 );
|
|
152
|
+
|
|
153
|
+ /* Calculate load address of real-mode portion */
|
|
154
|
+ bzimg->rm_kernel_seg = ( is_bzimage ? 0x1000 : 0x9000 );
|
|
155
|
+ bzimg->rm_kernel = real_to_user ( bzimg->rm_kernel_seg, 0 );
|
|
156
|
+
|
|
157
|
+ /* Allow space for the stack and heap */
|
|
158
|
+ bzimg->rm_memsz += BZI_STACK_SIZE;
|
|
159
|
+ bzimg->rm_heap = bzimg->rm_memsz;
|
|
160
|
+
|
|
161
|
+ /* Allow space for the command line */
|
|
162
|
+ bzimg->rm_cmdline = bzimg->rm_memsz;
|
|
163
|
+ bzimg->rm_memsz += BZI_CMDLINE_SIZE;
|
|
164
|
+
|
|
165
|
+ /* Calculate load address of protected-mode portion */
|
|
166
|
+ bzimg->pm_kernel = phys_to_user ( is_bzimage ? BZI_LOAD_HIGH_ADDR
|
|
167
|
+ : BZI_LOAD_LOW_ADDR );
|
|
168
|
+
|
|
169
|
+ /* Extract video mode */
|
|
170
|
+ bzimg->vid_mode = bzimg->bzhdr.vid_mode;
|
|
171
|
+
|
|
172
|
+ /* Extract memory limit */
|
|
173
|
+ bzimg->mem_limit = ( ( bzimg->version >= 0x0203 ) ?
|
|
174
|
+ bzimg->bzhdr.initrd_addr_max : BZI_INITRD_MAX );
|
|
175
|
+
|
|
176
|
+ /* Extract command line size */
|
|
177
|
+ bzimg->cmdline_size = ( ( bzimg->version >= 0x0206 ) ?
|
|
178
|
+ bzimg->bzhdr.cmdline_size : BZI_CMDLINE_SIZE );
|
|
179
|
+
|
|
180
|
+ DBGC ( image, "bzImage %p version %04x RM %#lx+%#zx PM %#lx+%#zx "
|
|
181
|
+ "cmdlen %zd\n", image, bzimg->version,
|
|
182
|
+ user_to_phys ( bzimg->rm_kernel, 0 ), bzimg->rm_filesz,
|
|
183
|
+ user_to_phys ( bzimg->pm_kernel, 0 ), bzimg->pm_sz,
|
|
184
|
+ bzimg->cmdline_size );
|
|
185
|
+
|
|
186
|
+ return 0;
|
|
187
|
+}
|
|
188
|
+
|
|
189
|
+/**
|
|
190
|
+ * Update bzImage header in loaded kernel
|
|
191
|
+ *
|
|
192
|
+ * @v image bzImage file
|
|
193
|
+ * @v bzimg bzImage context
|
|
194
|
+ * @v dst bzImage to update
|
|
195
|
+ */
|
|
196
|
+static void bzimage_update_header ( struct image *image,
|
|
197
|
+ struct bzimage_context *bzimg,
|
|
198
|
+ userptr_t dst ) {
|
|
199
|
+
|
|
200
|
+ /* Set loader type */
|
|
201
|
+ if ( bzimg->version >= 0x0200 )
|
|
202
|
+ bzimg->bzhdr.type_of_loader = BZI_LOADER_TYPE_GPXE;
|
|
203
|
+
|
|
204
|
+ /* Set heap end pointer */
|
|
205
|
+ if ( bzimg->version >= 0x0201 ) {
|
|
206
|
+ bzimg->bzhdr.heap_end_ptr = ( bzimg->rm_heap - 0x200 );
|
|
207
|
+ bzimg->bzhdr.loadflags |= BZI_CAN_USE_HEAP;
|
|
208
|
+ }
|
|
209
|
+
|
|
210
|
+ /* Set command line */
|
|
211
|
+ if ( bzimg->version >= 0x0202 ) {
|
|
212
|
+ bzimg->bzhdr.cmd_line_ptr = user_to_phys ( bzimg->rm_kernel,
|
|
213
|
+ bzimg->rm_cmdline );
|
|
214
|
+ } else {
|
|
215
|
+ bzimg->cmdline_magic.magic = BZI_CMDLINE_MAGIC;
|
|
216
|
+ bzimg->cmdline_magic.offset = bzimg->rm_cmdline;
|
|
217
|
+ bzimg->bzhdr.setup_move_size = bzimg->rm_memsz;
|
|
218
|
+ }
|
|
219
|
+
|
|
220
|
+ /* Set video mode */
|
|
221
|
+ bzimg->bzhdr.vid_mode = bzimg->vid_mode;
|
|
222
|
+
|
|
223
|
+ /* Set initrd address */
|
|
224
|
+ if ( bzimg->version >= 0x0200 ) {
|
|
225
|
+ bzimg->bzhdr.ramdisk_image = bzimg->ramdisk_image;
|
|
226
|
+ bzimg->bzhdr.ramdisk_size = bzimg->ramdisk_size;
|
|
227
|
+ }
|
|
228
|
+
|
|
229
|
+ /* Write out header structures */
|
|
230
|
+ copy_to_user ( dst, BZI_CMDLINE_OFFSET, &bzimg->cmdline_magic,
|
|
231
|
+ sizeof ( bzimg->cmdline_magic ) );
|
|
232
|
+ copy_to_user ( dst, BZI_HDR_OFFSET, &bzimg->bzhdr,
|
|
233
|
+ sizeof ( bzimg->bzhdr ) );
|
|
234
|
+
|
|
235
|
+ DBGC ( image, "bzImage %p vidmode %d\n", image, bzimg->vid_mode );
|
|
236
|
+}
|
|
237
|
+
|
90
|
238
|
/**
|
91
|
239
|
* Parse kernel command line for bootloader parameters
|
92
|
240
|
*
|
93
|
241
|
* @v image bzImage file
|
94
|
|
- * @v exec_ctx Execution context
|
|
242
|
+ * @v bzimg bzImage context
|
95
|
243
|
* @v cmdline Kernel command line
|
96
|
244
|
* @ret rc Return status code
|
97
|
245
|
*/
|
98
|
246
|
static int bzimage_parse_cmdline ( struct image *image,
|
99
|
|
- struct bzimage_exec_context *exec_ctx,
|
|
247
|
+ struct bzimage_context *bzimg,
|
100
|
248
|
const char *cmdline ) {
|
101
|
249
|
char *vga;
|
102
|
250
|
char *mem;
|
|
@@ -105,13 +253,13 @@ static int bzimage_parse_cmdline ( struct image *image,
|
105
|
253
|
if ( ( vga = strstr ( cmdline, "vga=" ) ) ) {
|
106
|
254
|
vga += 4;
|
107
|
255
|
if ( strcmp ( vga, "normal" ) == 0 ) {
|
108
|
|
- exec_ctx->vid_mode = BZI_VID_MODE_NORMAL;
|
|
256
|
+ bzimg->vid_mode = BZI_VID_MODE_NORMAL;
|
109
|
257
|
} else if ( strcmp ( vga, "ext" ) == 0 ) {
|
110
|
|
- exec_ctx->vid_mode = BZI_VID_MODE_EXT;
|
|
258
|
+ bzimg->vid_mode = BZI_VID_MODE_EXT;
|
111
|
259
|
} else if ( strcmp ( vga, "ask" ) == 0 ) {
|
112
|
|
- exec_ctx->vid_mode = BZI_VID_MODE_ASK;
|
|
260
|
+ bzimg->vid_mode = BZI_VID_MODE_ASK;
|
113
|
261
|
} else {
|
114
|
|
- exec_ctx->vid_mode = strtoul ( vga, &vga, 0 );
|
|
262
|
+ bzimg->vid_mode = strtoul ( vga, &vga, 0 );
|
115
|
263
|
if ( *vga && ( *vga != ' ' ) ) {
|
116
|
264
|
DBGC ( image, "bzImage %p strange \"vga=\""
|
117
|
265
|
"terminator '%c'\n", image, *vga );
|
|
@@ -122,17 +270,17 @@ static int bzimage_parse_cmdline ( struct image *image,
|
122
|
270
|
/* Look for "mem=" */
|
123
|
271
|
if ( ( mem = strstr ( cmdline, "mem=" ) ) ) {
|
124
|
272
|
mem += 4;
|
125
|
|
- exec_ctx->mem_limit = strtoul ( mem, &mem, 0 );
|
|
273
|
+ bzimg->mem_limit = strtoul ( mem, &mem, 0 );
|
126
|
274
|
switch ( *mem ) {
|
127
|
275
|
case 'G':
|
128
|
276
|
case 'g':
|
129
|
|
- exec_ctx->mem_limit <<= 10;
|
|
277
|
+ bzimg->mem_limit <<= 10;
|
130
|
278
|
case 'M':
|
131
|
279
|
case 'm':
|
132
|
|
- exec_ctx->mem_limit <<= 10;
|
|
280
|
+ bzimg->mem_limit <<= 10;
|
133
|
281
|
case 'K':
|
134
|
282
|
case 'k':
|
135
|
|
- exec_ctx->mem_limit <<= 10;
|
|
283
|
+ bzimg->mem_limit <<= 10;
|
136
|
284
|
break;
|
137
|
285
|
case '\0':
|
138
|
286
|
case ' ':
|
|
@@ -142,7 +290,7 @@ static int bzimage_parse_cmdline ( struct image *image,
|
142
|
290
|
"terminator '%c'\n", image, *mem );
|
143
|
291
|
break;
|
144
|
292
|
}
|
145
|
|
- exec_ctx->mem_limit -= 1;
|
|
293
|
+ bzimg->mem_limit -= 1;
|
146
|
294
|
}
|
147
|
295
|
|
148
|
296
|
return 0;
|
|
@@ -152,20 +300,20 @@ static int bzimage_parse_cmdline ( struct image *image,
|
152
|
300
|
* Set command line
|
153
|
301
|
*
|
154
|
302
|
* @v image bzImage image
|
155
|
|
- * @v exec_ctx Execution context
|
|
303
|
+ * @v bzimg bzImage context
|
156
|
304
|
* @v cmdline Kernel command line
|
157
|
305
|
* @ret rc Return status code
|
158
|
306
|
*/
|
159
|
307
|
static int bzimage_set_cmdline ( struct image *image,
|
160
|
|
- struct bzimage_exec_context *exec_ctx,
|
|
308
|
+ struct bzimage_context *bzimg,
|
161
|
309
|
const char *cmdline ) {
|
162
|
310
|
size_t cmdline_len;
|
163
|
311
|
|
164
|
312
|
/* Copy command line down to real-mode portion */
|
165
|
313
|
cmdline_len = ( strlen ( cmdline ) + 1 );
|
166
|
|
- if ( cmdline_len > exec_ctx->cmdline_size )
|
167
|
|
- cmdline_len = exec_ctx->cmdline_size;
|
168
|
|
- copy_to_user ( exec_ctx->rm_kernel, exec_ctx->rm_cmdline,
|
|
314
|
+ if ( cmdline_len > bzimg->cmdline_size )
|
|
315
|
+ cmdline_len = bzimg->cmdline_size;
|
|
316
|
+ copy_to_user ( bzimg->rm_kernel, bzimg->rm_cmdline,
|
169
|
317
|
cmdline, cmdline_len );
|
170
|
318
|
DBGC ( image, "bzImage %p command line \"%s\"\n", image, cmdline );
|
171
|
319
|
|
|
@@ -217,14 +365,16 @@ static size_t bzimage_load_initrd ( struct image *image,
|
217
|
365
|
}
|
218
|
366
|
|
219
|
367
|
/* Copy in initrd image body */
|
|
368
|
+ if ( address )
|
|
369
|
+ memcpy_user ( address, offset, initrd->data, 0, initrd->len );
|
|
370
|
+ offset += initrd->len;
|
220
|
371
|
if ( address ) {
|
221
|
372
|
DBGC ( image, "bzImage %p has initrd %p at [%lx,%lx)\n",
|
222
|
|
- image, initrd, address, ( address + offset ) );
|
223
|
|
- memcpy_user ( address, offset, initrd->data, 0,
|
224
|
|
- initrd->len );
|
|
373
|
+ image, initrd, user_to_phys ( address, 0 ),
|
|
374
|
+ user_to_phys ( address, offset ) );
|
225
|
375
|
}
|
226
|
|
- offset += initrd->len;
|
227
|
376
|
|
|
377
|
+ /* Round up to 4-byte boundary */
|
228
|
378
|
offset = ( ( offset + 0x03 ) & ~0x03 );
|
229
|
379
|
return offset;
|
230
|
380
|
}
|
|
@@ -233,20 +383,19 @@ static size_t bzimage_load_initrd ( struct image *image,
|
233
|
383
|
* Load initrds, if any
|
234
|
384
|
*
|
235
|
385
|
* @v image bzImage image
|
236
|
|
- * @v exec_ctx Execution context
|
|
386
|
+ * @v bzimg bzImage context
|
237
|
387
|
* @ret rc Return status code
|
238
|
388
|
*/
|
239
|
389
|
static int bzimage_load_initrds ( struct image *image,
|
240
|
|
- struct bzimage_exec_context *exec_ctx ) {
|
|
390
|
+ struct bzimage_context *bzimg ) {
|
241
|
391
|
struct image *initrd;
|
242
|
392
|
size_t total_len = 0;
|
243
|
393
|
physaddr_t address;
|
244
|
394
|
int rc;
|
245
|
395
|
|
246
|
396
|
/* Add up length of all initrd images */
|
247
|
|
- for_each_image ( initrd ) {
|
|
397
|
+ for_each_image ( initrd )
|
248
|
398
|
total_len += bzimage_load_initrd ( image, initrd, UNULL );
|
249
|
|
- }
|
250
|
399
|
|
251
|
400
|
/* Give up if no initrd images found */
|
252
|
401
|
if ( ! total_len )
|
|
@@ -268,7 +417,7 @@ static int bzimage_load_initrds ( struct image *image,
|
268
|
417
|
return -ENOBUFS;
|
269
|
418
|
}
|
270
|
419
|
/* Check that we are within the kernel's range */
|
271
|
|
- if ( ( address + total_len - 1 ) > exec_ctx->mem_limit )
|
|
420
|
+ if ( ( address + total_len - 1 ) > bzimg->mem_limit )
|
272
|
421
|
continue;
|
273
|
422
|
/* Prepare and verify segment */
|
274
|
423
|
if ( ( rc = prep_segment ( phys_to_user ( address ), 0,
|
|
@@ -279,8 +428,8 @@ static int bzimage_load_initrds ( struct image *image,
|
279
|
428
|
}
|
280
|
429
|
|
281
|
430
|
/* Record initrd location */
|
282
|
|
- exec_ctx->ramdisk_image = address;
|
283
|
|
- exec_ctx->ramdisk_size = total_len;
|
|
431
|
+ bzimg->ramdisk_image = address;
|
|
432
|
+ bzimg->ramdisk_size = total_len;
|
284
|
433
|
|
285
|
434
|
/* Construct initrd */
|
286
|
435
|
DBGC ( image, "bzImage %p constructing initrd at [%lx,%lx)\n",
|
|
@@ -300,60 +449,37 @@ static int bzimage_load_initrds ( struct image *image,
|
300
|
449
|
* @ret rc Return status code
|
301
|
450
|
*/
|
302
|
451
|
static int bzimage_exec ( struct image *image ) {
|
303
|
|
- struct bzimage_exec_context exec_ctx;
|
304
|
|
- struct bzimage_header bzhdr;
|
|
452
|
+ struct bzimage_context bzimg;
|
305
|
453
|
const char *cmdline = ( image->cmdline ? image->cmdline : "" );
|
306
|
454
|
int rc;
|
307
|
455
|
|
308
|
|
- /* Initialise context */
|
309
|
|
- memset ( &exec_ctx, 0, sizeof ( exec_ctx ) );
|
310
|
|
-
|
311
|
|
- /* Retrieve kernel header */
|
312
|
|
- exec_ctx.rm_kernel_seg = image->priv.ul;
|
313
|
|
- exec_ctx.rm_kernel = real_to_user ( exec_ctx.rm_kernel_seg, 0 );
|
314
|
|
- copy_from_user ( &bzhdr, exec_ctx.rm_kernel, BZI_HDR_OFFSET,
|
315
|
|
- sizeof ( bzhdr ) );
|
316
|
|
- exec_ctx.rm_cmdline = exec_ctx.rm_heap =
|
317
|
|
- ( bzhdr.heap_end_ptr + 0x200 );
|
318
|
|
- exec_ctx.vid_mode = bzhdr.vid_mode;
|
319
|
|
- if ( bzhdr.version >= 0x0203 ) {
|
320
|
|
- exec_ctx.mem_limit = bzhdr.initrd_addr_max;
|
321
|
|
- } else {
|
322
|
|
- exec_ctx.mem_limit = BZI_INITRD_MAX;
|
323
|
|
- }
|
324
|
|
- if ( bzhdr.version >= 0x0206 ) {
|
325
|
|
- exec_ctx.cmdline_size = bzhdr.cmdline_size;
|
326
|
|
- } else {
|
327
|
|
- exec_ctx.cmdline_size = BZI_CMDLINE_SIZE;
|
328
|
|
- }
|
329
|
|
- DBG ( "cmdline_size = %zd\n", exec_ctx.cmdline_size );
|
|
456
|
+ /* Read and parse header from loaded kernel */
|
|
457
|
+ if ( ( rc = bzimage_parse_header ( image, &bzimg,
|
|
458
|
+ image->priv.user ) ) != 0 )
|
|
459
|
+ return rc;
|
|
460
|
+ assert ( bzimg.rm_kernel == image->priv.user );
|
330
|
461
|
|
331
|
462
|
/* Parse command line for bootloader parameters */
|
332
|
|
- if ( ( rc = bzimage_parse_cmdline ( image, &exec_ctx, cmdline ) ) != 0)
|
|
463
|
+ if ( ( rc = bzimage_parse_cmdline ( image, &bzimg, cmdline ) ) != 0)
|
333
|
464
|
return rc;
|
334
|
465
|
|
335
|
466
|
/* Store command line */
|
336
|
|
- if ( ( rc = bzimage_set_cmdline ( image, &exec_ctx, cmdline ) ) != 0 )
|
|
467
|
+ if ( ( rc = bzimage_set_cmdline ( image, &bzimg, cmdline ) ) != 0 )
|
337
|
468
|
return rc;
|
338
|
469
|
|
339
|
470
|
/* Load any initrds */
|
340
|
|
- if ( ( rc = bzimage_load_initrds ( image, &exec_ctx ) ) != 0 )
|
|
471
|
+ if ( ( rc = bzimage_load_initrds ( image, &bzimg ) ) != 0 )
|
341
|
472
|
return rc;
|
342
|
473
|
|
343
|
|
- /* Update and store kernel header */
|
344
|
|
- bzhdr.vid_mode = exec_ctx.vid_mode;
|
345
|
|
- bzhdr.ramdisk_image = exec_ctx.ramdisk_image;
|
346
|
|
- bzhdr.ramdisk_size = exec_ctx.ramdisk_size;
|
347
|
|
- copy_to_user ( exec_ctx.rm_kernel, BZI_HDR_OFFSET, &bzhdr,
|
348
|
|
- sizeof ( bzhdr ) );
|
|
474
|
+ /* Update kernel header */
|
|
475
|
+ bzimage_update_header ( image, &bzimg, bzimg.rm_kernel );
|
349
|
476
|
|
350
|
477
|
/* Prepare for exiting */
|
351
|
478
|
shutdown ( SHUTDOWN_BOOT );
|
352
|
479
|
|
353
|
480
|
DBGC ( image, "bzImage %p jumping to RM kernel at %04x:0000 "
|
354
|
|
- "(stack %04x:%04zx)\n", image,
|
355
|
|
- ( exec_ctx.rm_kernel_seg + 0x20 ),
|
356
|
|
- exec_ctx.rm_kernel_seg, exec_ctx.rm_heap );
|
|
481
|
+ "(stack %04x:%04zx)\n", image, ( bzimg.rm_kernel_seg + 0x20 ),
|
|
482
|
+ bzimg.rm_kernel_seg, bzimg.rm_heap );
|
357
|
483
|
|
358
|
484
|
/* Jump to the kernel */
|
359
|
485
|
__asm__ __volatile__ ( REAL_CODE ( "movw %w0, %%ds\n\t"
|
|
@@ -365,9 +491,9 @@ static int bzimage_exec ( struct image *image ) {
|
365
|
491
|
"pushw %w2\n\t"
|
366
|
492
|
"pushw $0\n\t"
|
367
|
493
|
"lret\n\t" )
|
368
|
|
- : : "r" ( exec_ctx.rm_kernel_seg ),
|
369
|
|
- "r" ( exec_ctx.rm_heap ),
|
370
|
|
- "r" ( exec_ctx.rm_kernel_seg + 0x20 ) );
|
|
494
|
+ : : "r" ( bzimg.rm_kernel_seg ),
|
|
495
|
+ "r" ( bzimg.rm_heap ),
|
|
496
|
+ "r" ( bzimg.rm_kernel_seg + 0x20 ) );
|
371
|
497
|
|
372
|
498
|
/* There is no way for the image to return, since we provide
|
373
|
499
|
* no return address.
|
|
@@ -378,192 +504,49 @@ static int bzimage_exec ( struct image *image ) {
|
378
|
504
|
}
|
379
|
505
|
|
380
|
506
|
/**
|
381
|
|
- * Load and parse bzImage header
|
382
|
|
- *
|
383
|
|
- * @v image bzImage file
|
384
|
|
- * @v load_ctx Load context
|
385
|
|
- * @v bzhdr Buffer for bzImage header
|
386
|
|
- * @ret rc Return status code
|
387
|
|
- */
|
388
|
|
-static int bzimage_load_header ( struct image *image,
|
389
|
|
- struct bzimage_load_context *load_ctx,
|
390
|
|
- struct bzimage_header *bzhdr ) {
|
391
|
|
-
|
392
|
|
- /* Sanity check */
|
393
|
|
- if ( image->len < ( BZI_HDR_OFFSET + sizeof ( *bzhdr ) ) ) {
|
394
|
|
- DBGC ( image, "bzImage %p too short for kernel header\n",
|
395
|
|
- image );
|
396
|
|
- return -ENOEXEC;
|
397
|
|
- }
|
398
|
|
-
|
399
|
|
- /* Read and verify header */
|
400
|
|
- copy_from_user ( bzhdr, image->data, BZI_HDR_OFFSET,
|
401
|
|
- sizeof ( *bzhdr ) );
|
402
|
|
- if ( bzhdr->header != BZI_SIGNATURE ) {
|
403
|
|
- DBGC ( image, "bzImage %p bad signature %08x\n",
|
404
|
|
- image, bzhdr->header );
|
405
|
|
- return -ENOEXEC;
|
406
|
|
- }
|
407
|
|
-
|
408
|
|
- /* We don't support ancient kernels */
|
409
|
|
- if ( bzhdr->version < 0x0200 ) {
|
410
|
|
- DBGC ( image, "bzImage %p version %04x not supported\n",
|
411
|
|
- image, bzhdr->version );
|
412
|
|
- return -ENOTSUP;
|
413
|
|
- }
|
414
|
|
-
|
415
|
|
- /* Calculate load address and size of real-mode portion */
|
416
|
|
- load_ctx->rm_kernel_seg = ( ( bzhdr->loadflags & BZI_LOAD_HIGH ) ?
|
417
|
|
- 0x1000 : /* 1000:0000 (bzImage) */
|
418
|
|
- 0x9000 ); /* 9000:0000 (zImage) */
|
419
|
|
- load_ctx->rm_kernel = real_to_user ( load_ctx->rm_kernel_seg, 0 );
|
420
|
|
- load_ctx->rm_filesz =
|
421
|
|
- ( ( bzhdr->setup_sects ? bzhdr->setup_sects : 4 ) + 1 ) << 9;
|
422
|
|
- load_ctx->rm_memsz = BZI_ASSUMED_RM_SIZE;
|
423
|
|
- if ( load_ctx->rm_filesz > image->len ) {
|
424
|
|
- DBGC ( image, "bzImage %p too short for %zd byte of setup\n",
|
425
|
|
- image, load_ctx->rm_filesz );
|
426
|
|
- return -ENOEXEC;
|
427
|
|
- }
|
428
|
|
-
|
429
|
|
- /* Calculate load address and size of non-real-mode portion */
|
430
|
|
- load_ctx->pm_kernel = ( ( bzhdr->loadflags & BZI_LOAD_HIGH ) ?
|
431
|
|
- phys_to_user ( BZI_LOAD_HIGH_ADDR ) :
|
432
|
|
- phys_to_user ( BZI_LOAD_LOW_ADDR ) );
|
433
|
|
- load_ctx->pm_sz = ( image->len - load_ctx->rm_filesz );
|
434
|
|
-
|
435
|
|
- DBGC ( image, "bzImage %p version %04x RM %#zx bytes PM %#zx bytes\n",
|
436
|
|
- image, bzhdr->version, load_ctx->rm_filesz, load_ctx->pm_sz );
|
437
|
|
- return 0;
|
438
|
|
-}
|
439
|
|
-
|
440
|
|
-/**
|
441
|
|
- * Load real-mode portion of bzImage
|
|
507
|
+ * Load bzImage image into memory
|
442
|
508
|
*
|
443
|
509
|
* @v image bzImage file
|
444
|
|
- * @v load_ctx Load context
|
445
|
510
|
* @ret rc Return status code
|
446
|
511
|
*/
|
447
|
|
-static int bzimage_load_real ( struct image *image,
|
448
|
|
- struct bzimage_load_context *load_ctx ) {
|
|
512
|
+int bzimage_load ( struct image *image ) {
|
|
513
|
+ struct bzimage_context bzimg;
|
449
|
514
|
int rc;
|
450
|
515
|
|
451
|
|
- /* Allow space for the stack and heap */
|
452
|
|
- load_ctx->rm_memsz += BZI_STACK_SIZE;
|
453
|
|
- load_ctx->rm_heap = load_ctx->rm_memsz;
|
|
516
|
+ /* Read and parse header from image */
|
|
517
|
+ if ( ( rc = bzimage_parse_header ( image, &bzimg,
|
|
518
|
+ image->data ) ) != 0 )
|
|
519
|
+ return rc;
|
454
|
520
|
|
455
|
|
- /* Allow space for the command line */
|
456
|
|
- load_ctx->rm_cmdline = load_ctx->rm_memsz;
|
457
|
|
- load_ctx->rm_memsz += BZI_CMDLINE_SIZE;
|
|
521
|
+ /* This is a bzImage image, valid or otherwise */
|
|
522
|
+ if ( ! image->type )
|
|
523
|
+ image->type = &bzimage_image_type;
|
458
|
524
|
|
459
|
|
- /* Prepare, verify, and load the real-mode segment */
|
460
|
|
- if ( ( rc = prep_segment ( load_ctx->rm_kernel, load_ctx->rm_filesz,
|
461
|
|
- load_ctx->rm_memsz ) ) != 0 ) {
|
|
525
|
+ /* Prepare segments */
|
|
526
|
+ if ( ( rc = prep_segment ( bzimg.rm_kernel, bzimg.rm_filesz,
|
|
527
|
+ bzimg.rm_memsz ) ) != 0 ) {
|
462
|
528
|
DBGC ( image, "bzImage %p could not prepare RM segment: %s\n",
|
463
|
529
|
image, strerror ( rc ) );
|
464
|
530
|
return rc;
|
465
|
531
|
}
|
466
|
|
- memcpy_user ( load_ctx->rm_kernel, 0, image->data, 0,
|
467
|
|
- load_ctx->rm_filesz );
|
468
|
|
-
|
469
|
|
- return 0;
|
470
|
|
-}
|
471
|
|
-
|
472
|
|
-/**
|
473
|
|
- * Load non-real-mode portion of bzImage
|
474
|
|
- *
|
475
|
|
- * @v image bzImage file
|
476
|
|
- * @v load_ctx Load context
|
477
|
|
- * @ret rc Return status code
|
478
|
|
- */
|
479
|
|
-static int bzimage_load_non_real ( struct image *image,
|
480
|
|
- struct bzimage_load_context *load_ctx ) {
|
481
|
|
- int rc;
|
482
|
|
-
|
483
|
|
- /* Prepare, verify and load the non-real-mode segment */
|
484
|
|
- if ( ( rc = prep_segment ( load_ctx->pm_kernel, load_ctx->pm_sz,
|
485
|
|
- load_ctx->pm_sz ) ) != 0 ) {
|
|
532
|
+ if ( ( rc = prep_segment ( bzimg.pm_kernel, bzimg.pm_sz,
|
|
533
|
+ bzimg.pm_sz ) ) != 0 ) {
|
486
|
534
|
DBGC ( image, "bzImage %p could not prepare PM segment: %s\n",
|
487
|
535
|
image, strerror ( rc ) );
|
488
|
536
|
return rc;
|
489
|
537
|
}
|
490
|
|
- memcpy_user ( load_ctx->pm_kernel, 0, image->data, load_ctx->rm_filesz,
|
491
|
|
- load_ctx->pm_sz );
|
492
|
|
-
|
493
|
|
- return 0;
|
494
|
|
-}
|
495
|
|
-
|
496
|
|
-/**
|
497
|
|
- * Update and store bzImage header
|
498
|
|
- *
|
499
|
|
- * @v image bzImage file
|
500
|
|
- * @v load_ctx Load context
|
501
|
|
- * @v bzhdr Original bzImage header
|
502
|
|
- * @ret rc Return status code
|
503
|
|
- */
|
504
|
|
-static int bzimage_write_header ( struct image *image __unused,
|
505
|
|
- struct bzimage_load_context *load_ctx,
|
506
|
|
- struct bzimage_header *bzhdr ) {
|
507
|
|
- struct bzimage_cmdline cmdline;
|
508
|
|
-
|
509
|
|
- /* Update the header and copy it into the loaded kernel */
|
510
|
|
- bzhdr->type_of_loader = BZI_LOADER_TYPE_GPXE;
|
511
|
|
- if ( bzhdr->version >= 0x0201 ) {
|
512
|
|
- bzhdr->heap_end_ptr = ( load_ctx->rm_heap - 0x200 );
|
513
|
|
- bzhdr->loadflags |= BZI_CAN_USE_HEAP;
|
514
|
|
- }
|
515
|
|
- if ( bzhdr->version >= 0x0202 ) {
|
516
|
|
- bzhdr->cmd_line_ptr = user_to_phys ( load_ctx->rm_kernel,
|
517
|
|
- load_ctx->rm_cmdline );
|
518
|
|
- } else {
|
519
|
|
- cmdline.magic = BZI_CMDLINE_MAGIC;
|
520
|
|
- cmdline.offset = load_ctx->rm_cmdline;
|
521
|
|
- copy_to_user ( load_ctx->rm_kernel, BZI_CMDLINE_OFFSET,
|
522
|
|
- &cmdline, sizeof ( cmdline ) );
|
523
|
|
- bzhdr->setup_move_size = load_ctx->rm_memsz;
|
524
|
|
- }
|
525
|
|
- copy_to_user ( load_ctx->rm_kernel, BZI_HDR_OFFSET,
|
526
|
|
- bzhdr, sizeof ( *bzhdr ) );
|
527
|
|
-
|
528
|
|
- return 0;
|
529
|
|
-}
|
530
|
|
-
|
531
|
|
-/**
|
532
|
|
- * Load bzImage image into memory
|
533
|
|
- *
|
534
|
|
- * @v image bzImage file
|
535
|
|
- * @ret rc Return status code
|
536
|
|
- */
|
537
|
|
-int bzimage_load ( struct image *image ) {
|
538
|
|
- struct bzimage_load_context load_ctx;
|
539
|
|
- struct bzimage_header bzhdr;
|
540
|
|
- int rc;
|
541
|
|
-
|
542
|
|
- /* Initialise context */
|
543
|
|
- memset ( &load_ctx, 0, sizeof ( load_ctx ) );
|
544
|
538
|
|
545
|
|
- /* Load and verify header */
|
546
|
|
- if ( ( rc = bzimage_load_header ( image, &load_ctx, &bzhdr ) ) != 0 )
|
547
|
|
- return rc;
|
548
|
|
-
|
549
|
|
- /* This is a bzImage image, valid or otherwise */
|
550
|
|
- if ( ! image->type )
|
551
|
|
- image->type = &bzimage_image_type;
|
552
|
|
-
|
553
|
|
- /* Load real-mode portion */
|
554
|
|
- if ( ( rc = bzimage_load_real ( image, &load_ctx ) ) != 0 )
|
555
|
|
- return rc;
|
556
|
|
-
|
557
|
|
- /* Load non-real-mode portion */
|
558
|
|
- if ( ( rc = bzimage_load_non_real ( image, &load_ctx ) ) != 0 )
|
559
|
|
- return rc;
|
|
539
|
+ /* Load segments */
|
|
540
|
+ memcpy_user ( bzimg.rm_kernel, 0, image->data,
|
|
541
|
+ 0, bzimg.rm_filesz );
|
|
542
|
+ memcpy_user ( bzimg.pm_kernel, 0, image->data,
|
|
543
|
+ bzimg.rm_filesz, bzimg.pm_sz );
|
560
|
544
|
|
561
|
545
|
/* Update and write out header */
|
562
|
|
- if ( ( rc = bzimage_write_header ( image, &load_ctx, &bzhdr ) ) != 0 )
|
563
|
|
- return rc;
|
|
546
|
+ bzimage_update_header ( image, &bzimg, bzimg.rm_kernel );
|
564
|
547
|
|
565
|
548
|
/* Record real-mode segment in image private data field */
|
566
|
|
- image->priv.ul = load_ctx.rm_kernel_seg;
|
|
549
|
+ image->priv.user = bzimg.rm_kernel;
|
567
|
550
|
|
568
|
551
|
return 0;
|
569
|
552
|
}
|