OLD | NEW |
---|---|
1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 * Use of this source code is governed by a BSD-style license that can be | 2 * Use of this source code is governed by a BSD-style license that can be |
3 * found in the LICENSE file. | 3 * found in the LICENSE file. |
4 * | 4 * |
5 * Functions for generating and manipulating a verified boot kernel image. | 5 * Functions for generating and manipulating a verified boot kernel image. |
6 * (Userland portion) | 6 * (Userland portion) |
7 */ | 7 */ |
8 | 8 |
9 #include "kernel_image.h" | |
10 | |
11 #include <fcntl.h> | 9 #include <fcntl.h> |
10 #include <stddef.h> | |
12 #include <stdio.h> | 11 #include <stdio.h> |
13 #include <sys/types.h> | 12 #include <sys/types.h> |
14 #include <sys/stat.h> | 13 #include <sys/stat.h> |
15 #include <unistd.h> | 14 #include <unistd.h> |
16 | 15 |
17 #include "cryptolib.h" | 16 #include "cryptolib.h" |
18 #include "file_keys.h" | 17 #include "file_keys.h" |
18 #include "kernel_image.h" | |
gauravsh
2010/05/27 18:06:04
oops, I meant only #include kernel_blob.h should g
| |
19 #include "kernel_blob.h" | |
19 #include "rollback_index.h" | 20 #include "rollback_index.h" |
20 #include "signature_digest.h" | 21 #include "signature_digest.h" |
21 #include "utility.h" | 22 #include "utility.h" |
22 | 23 |
23 /* Macro to determine the size of a field structure in the KernelImage | 24 /* Macro to determine the size of a field structure in the KernelImage |
24 * structure. */ | 25 * structure. */ |
25 #define FIELD_LEN(field) (sizeof(((KernelImage*)0)->field)) | 26 #define FIELD_LEN(field) (sizeof(((KernelImage*)0)->field)) |
26 | 27 |
27 KernelImage* KernelImageNew(void) { | 28 KernelImage* KernelImageNew(void) { |
28 KernelImage* image = (KernelImage*) Malloc(sizeof(KernelImage)); | 29 KernelImage* image = (KernelImage*) Malloc(sizeof(KernelImage)); |
29 if (image) { | 30 if (image) { |
30 image->kernel_sign_key = NULL; | 31 image->kernel_sign_key = NULL; |
31 image->kernel_key_signature = NULL; | 32 image->kernel_key_signature = NULL; |
32 image->preamble_signature = NULL; | 33 image->preamble_signature = NULL; |
33 image->kernel_signature = NULL; | 34 image->kernel_signature = NULL; |
34 image->kernel_data = NULL; | 35 image->kernel_data = NULL; |
36 image->padded_header_size = 0x4000; | |
35 } | 37 } |
36 return image; | 38 return image; |
37 } | 39 } |
38 | 40 |
39 void KernelImageFree(KernelImage* image) { | 41 void KernelImageFree(KernelImage* image) { |
40 if (image) { | 42 if (image) { |
41 Free(image->kernel_sign_key); | 43 Free(image->kernel_sign_key); |
42 Free(image->kernel_key_signature); | 44 Free(image->kernel_key_signature); |
43 Free(image->preamble_signature); | 45 Free(image->preamble_signature); |
44 Free(image->kernel_signature); | 46 Free(image->kernel_signature); |
45 Free(image->kernel_data); | 47 Free(image->kernel_data); |
46 Free(image); | 48 Free(image); |
47 } | 49 } |
48 } | 50 } |
49 | 51 |
52 uint64_t GetHeaderSizeOnDisk(const KernelImage* image) { | |
53 uint64_t kernel_signature_len = siglen_map[image->kernel_sign_algorithm]; | |
54 uint64_t kernel_key_signature_len = | |
55 siglen_map[image->firmware_sign_algorithm]; | |
56 | |
57 return FIELD_LEN(magic) + | |
58 GetKernelHeaderLen(image) + | |
59 kernel_key_signature_len + | |
60 GetKernelPreambleLen(image->kernel_sign_algorithm) + | |
61 kernel_signature_len; | |
62 } | |
63 | |
64 | |
50 KernelImage* ReadKernelImage(const char* input_file) { | 65 KernelImage* ReadKernelImage(const char* input_file) { |
51 uint64_t file_size; | 66 uint64_t file_size; |
52 int image_len = 0; /* Total size of the kernel image. */ | 67 uint64_t on_disk_header_size; |
68 uint64_t on_disk_padding; | |
53 int header_len = 0; | 69 int header_len = 0; |
54 int firmware_sign_key_len; | 70 int firmware_sign_key_len; |
55 int kernel_key_signature_len; | 71 int kernel_key_signature_len; |
56 int kernel_sign_key_len; | 72 int kernel_sign_key_len; |
57 int kernel_signature_len; | 73 int kernel_signature_len; |
58 uint8_t* kernel_buf; | 74 uint8_t* kernel_buf; |
59 uint8_t header_checksum[FIELD_LEN(header_checksum)]; | 75 uint8_t header_checksum[FIELD_LEN(header_checksum)]; |
60 MemcpyState st; | 76 MemcpyState st; |
61 KernelImage* image = KernelImageNew(); | 77 KernelImage* image = KernelImageNew(); |
62 | 78 |
63 if (!image) | 79 if (!image) |
64 return NULL; | 80 return NULL; |
65 | 81 |
66 kernel_buf = BufferFromFile(input_file, &file_size); | 82 kernel_buf = BufferFromFile(input_file, &file_size); |
67 image_len = file_size; | |
68 | 83 |
69 st.remaining_len = image_len; | 84 st.remaining_len = file_size; |
70 st.remaining_buf = kernel_buf; | 85 st.remaining_buf = kernel_buf; |
71 st.overrun = 0; | 86 st.overrun = 0; |
72 | 87 |
73 /* Read and compare magic bytes. */ | 88 /* Read and compare magic bytes. */ |
74 StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE); | 89 StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE); |
75 | 90 |
76 if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) { | 91 if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) { |
77 debug("Wrong Kernel Magic.\n"); | 92 debug("Wrong Kernel Magic.\n"); |
78 Free(kernel_buf); | 93 Free(kernel_buf); |
79 return NULL; | 94 return NULL; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
134 kernel_key_signature_len); | 149 kernel_key_signature_len); |
135 | 150 |
136 /* Read the kernel preamble. */ | 151 /* Read the kernel preamble. */ |
137 StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version)); | 152 StatefulMemcpy(&st, &image->kernel_version, FIELD_LEN(kernel_version)); |
138 StatefulMemcpy(&st, &image->kernel_len, FIELD_LEN(kernel_len)); | 153 StatefulMemcpy(&st, &image->kernel_len, FIELD_LEN(kernel_len)); |
139 StatefulMemcpy(&st, &image->bootloader_offset, FIELD_LEN(bootloader_offset)); | 154 StatefulMemcpy(&st, &image->bootloader_offset, FIELD_LEN(bootloader_offset)); |
140 StatefulMemcpy(&st, &image->bootloader_size, FIELD_LEN(bootloader_size)); | 155 StatefulMemcpy(&st, &image->bootloader_size, FIELD_LEN(bootloader_size)); |
141 StatefulMemcpy(&st, &image->padded_header_size, | 156 StatefulMemcpy(&st, &image->padded_header_size, |
142 FIELD_LEN(padded_header_size)); | 157 FIELD_LEN(padded_header_size)); |
143 | 158 |
144 /* Read config and kernel signatures. */ | 159 /* Read preamble and kernel signatures. */ |
160 image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len); | |
161 StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len); | |
145 image->preamble_signature = (uint8_t*) Malloc(kernel_signature_len); | 162 image->preamble_signature = (uint8_t*) Malloc(kernel_signature_len); |
146 StatefulMemcpy(&st, image->preamble_signature, kernel_signature_len); | 163 StatefulMemcpy(&st, image->preamble_signature, kernel_signature_len); |
147 image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len); | 164 |
148 StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len); | 165 /* Skip over the rest of the padded header, unless we're already past it. */ |
166 on_disk_header_size = file_size - st.remaining_len; | |
167 if (image->padded_header_size > on_disk_header_size) { | |
168 on_disk_padding = image->padded_header_size - on_disk_header_size; | |
169 if (st.remaining_len < on_disk_padding) | |
170 st.overrun = -1; | |
171 st.remaining_buf += on_disk_padding; | |
172 st.remaining_len -= on_disk_padding; | |
173 } | |
149 | 174 |
150 /* Read kernel image data. */ | 175 /* Read kernel image data. */ |
151 image->kernel_data = (uint8_t*) Malloc(image->kernel_len); | 176 image->kernel_data = (uint8_t*) Malloc(image->kernel_len); |
152 StatefulMemcpy(&st, image->kernel_data, image->kernel_len); | 177 StatefulMemcpy(&st, image->kernel_data, image->kernel_len); |
153 | 178 |
154 if(st.overrun || st.remaining_len != 0) { /* Overrun or underrun. */ | 179 if(st.overrun || st.remaining_len != 0) { /* Overrun or underrun. */ |
155 Free(kernel_buf); | 180 Free(kernel_buf); |
156 return NULL; | 181 return NULL; |
157 } | 182 } |
158 Free(kernel_buf); | 183 Free(kernel_buf); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
243 } | 268 } |
244 return preamble_blob; | 269 return preamble_blob; |
245 } | 270 } |
246 | 271 |
247 uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) { | 272 uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) { |
248 int kernel_key_signature_len; | 273 int kernel_key_signature_len; |
249 int kernel_signature_len; | 274 int kernel_signature_len; |
250 uint8_t* kernel_blob = NULL; | 275 uint8_t* kernel_blob = NULL; |
251 uint8_t* header_blob = NULL; | 276 uint8_t* header_blob = NULL; |
252 MemcpyState st; | 277 MemcpyState st; |
278 uint64_t on_disk_header_size; | |
279 uint64_t on_disk_padding = 0; | |
253 | 280 |
254 if (!image) | 281 if (!image) |
255 return NULL; | 282 return NULL; |
256 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm]; | 283 kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm]; |
257 kernel_signature_len = siglen_map[image->kernel_sign_algorithm]; | 284 kernel_signature_len = siglen_map[image->kernel_sign_algorithm]; |
258 *blob_len = (FIELD_LEN(magic) + | 285 on_disk_header_size = GetHeaderSizeOnDisk(image); |
259 GetKernelHeaderLen(image) + | 286 if (image->padded_header_size > on_disk_header_size) |
260 kernel_key_signature_len + | 287 on_disk_padding = image->padded_header_size - on_disk_header_size; |
261 GetKernelPreambleLen(image->kernel_sign_algorithm) + | 288 *blob_len = on_disk_header_size + on_disk_padding + image->kernel_len; |
262 kernel_signature_len + | |
263 image->kernel_len); | |
264 kernel_blob = (uint8_t*) Malloc(*blob_len); | 289 kernel_blob = (uint8_t*) Malloc(*blob_len); |
265 st.remaining_len = *blob_len; | 290 st.remaining_len = *blob_len; |
266 st.remaining_buf = kernel_blob; | 291 st.remaining_buf = kernel_blob; |
267 st.overrun = 0; | 292 st.overrun = 0; |
268 | |
269 header_blob = GetKernelHeaderBlob(image); | 293 header_blob = GetKernelHeaderBlob(image); |
270 | 294 |
271 StatefulMemcpy_r(&st, image->magic, FIELD_LEN(magic)); | 295 StatefulMemcpy_r(&st, image->magic, FIELD_LEN(magic)); |
272 StatefulMemcpy_r(&st, header_blob, GetKernelHeaderLen(image)); | 296 StatefulMemcpy_r(&st, header_blob, GetKernelHeaderLen(image)); |
273 StatefulMemcpy_r(&st, image->kernel_key_signature, kernel_key_signature_len); | 297 StatefulMemcpy_r(&st, image->kernel_key_signature, kernel_key_signature_len); |
274 /* Copy over kernel preamble blob (including signatures.) */ | 298 /* Copy over kernel preamble blob (including signatures.) */ |
275 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version)); | 299 StatefulMemcpy_r(&st, &image->kernel_version, FIELD_LEN(kernel_version)); |
276 StatefulMemcpy_r(&st, &image->kernel_len, FIELD_LEN(kernel_len)); | 300 StatefulMemcpy_r(&st, &image->kernel_len, FIELD_LEN(kernel_len)); |
277 StatefulMemcpy_r(&st, &image->bootloader_offset, | 301 StatefulMemcpy_r(&st, &image->bootloader_offset, |
278 FIELD_LEN(bootloader_offset)); | 302 FIELD_LEN(bootloader_offset)); |
279 StatefulMemcpy_r(&st, &image->bootloader_size, FIELD_LEN(bootloader_size)); | 303 StatefulMemcpy_r(&st, &image->bootloader_size, FIELD_LEN(bootloader_size)); |
280 StatefulMemcpy_r(&st, &image->padded_header_size, | 304 StatefulMemcpy_r(&st, &image->padded_header_size, |
281 FIELD_LEN(padded_header_size)); | 305 FIELD_LEN(padded_header_size)); |
282 StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len); | 306 StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len); |
283 StatefulMemcpy_r(&st, image->preamble_signature, kernel_signature_len); | 307 StatefulMemcpy_r(&st, image->preamble_signature, kernel_signature_len); |
308 /* Copy a bunch of zeros to pad out the header */ | |
309 if (on_disk_padding) | |
310 StatefulMemset_r(&st, 0, on_disk_padding); | |
284 StatefulMemcpy_r(&st, image->kernel_data, image->kernel_len); | 311 StatefulMemcpy_r(&st, image->kernel_data, image->kernel_len); |
285 | 312 |
286 Free(header_blob); | 313 Free(header_blob); |
287 | 314 |
288 if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */ | 315 if (st.overrun || st.remaining_len != 0) { /* Underrun or Overrun. */ |
289 debug("GetKernelBlob() failed.\n"); | 316 debug("GetKernelBlob() failed.\n"); |
290 Free(kernel_blob); | 317 Free(kernel_blob); |
291 return NULL; | 318 return NULL; |
292 } | 319 } |
293 return kernel_blob; | 320 return kernel_blob; |
294 } | 321 } |
295 | 322 |
296 int WriteKernelImage(const char* input_file, | 323 int WriteKernelImage(const char* output_file, |
297 const KernelImage* image, | 324 const KernelImage* image, |
298 int is_only_vblock) { | 325 int is_only_vblock) { |
299 int fd; | 326 int fd; |
300 int success = 1; | 327 int success = 1; |
301 uint8_t* kernel_blob; | 328 uint8_t* kernel_blob; |
302 uint64_t blob_len; | 329 uint64_t blob_len; |
303 | 330 |
304 if (!image) | 331 if (!image) |
305 return 0; | 332 return 0; |
306 if (-1 == (fd = creat(input_file, S_IRWXU))) { | 333 if (-1 == (fd = creat(output_file, S_IRWXU))) { |
307 debug("Couldn't open file for writing kernel image: %s\n", | 334 debug("Couldn't open file for writing kernel image: %s\n", |
308 input_file); | 335 output_file); |
309 return 0; | 336 return 0; |
310 } | 337 } |
311 kernel_blob = GetKernelBlob(image, &blob_len); | 338 kernel_blob = GetKernelBlob(image, &blob_len); |
312 if (!kernel_blob) { | 339 if (!kernel_blob) { |
313 debug("Couldn't create kernel blob from KernelImage.\n"); | 340 debug("Couldn't create kernel blob from KernelImage.\n"); |
314 return 0; | 341 return 0; |
315 } | 342 } |
316 if (!is_only_vblock) { | 343 if (!is_only_vblock) { |
317 if (blob_len != write(fd, kernel_blob, blob_len)) { | 344 if (blob_len != write(fd, kernel_blob, blob_len)) { |
318 debug("Couldn't write Kernel Image to file: %s\n", | 345 debug("Couldn't write Kernel Image to file: %s\n", |
319 input_file); | 346 output_file); |
320 success = 0; | 347 success = 0; |
321 } | 348 } |
322 } else { | 349 } else { |
323 /* Exclude kernel_data. */ | 350 /* Exclude kernel_data. */ |
324 int vblock_len = blob_len - (image->kernel_len); | 351 int vblock_len = blob_len - (image->kernel_len); |
325 if (vblock_len != write(fd, kernel_blob, vblock_len)) { | 352 if (vblock_len != write(fd, kernel_blob, vblock_len)) { |
326 debug("Couldn't write Kernel Image Verification block to file: %s\n", | 353 debug("Couldn't write Kernel Image Verification block to file: %s\n", |
327 input_file); | 354 output_file); |
328 success = 0; | 355 success = 0; |
329 } | 356 } |
330 } | 357 } |
331 Free(kernel_blob); | 358 Free(kernel_blob); |
332 close(fd); | 359 close(fd); |
333 return success; | 360 return success; |
334 } | 361 } |
335 | 362 |
336 void PrintKernelImage(const KernelImage* image) { | 363 void PrintKernelImage(const KernelImage* image) { |
364 uint64_t header_size; | |
365 | |
337 if (!image) | 366 if (!image) |
338 return; | 367 return; |
339 | 368 |
369 header_size = GetHeaderSizeOnDisk(image); | |
370 if (image->padded_header_size > header_size) | |
371 header_size = image->padded_header_size; | |
372 | |
373 | |
340 /* Print header. */ | 374 /* Print header. */ |
341 printf("Header Version = %d\n" | 375 printf("Header Version = %d\n" |
342 "Header Length = %d\n" | 376 "Header Length = %d\n" |
343 "Kernel Key Signature Algorithm = %s\n" | 377 "Kernel Key Signature Algorithm = %s\n" |
344 "Kernel Signature Algorithm = %s\n" | 378 "Kernel Signature Algorithm = %s\n" |
345 "Kernel Key Version = %d\n\n", | 379 "Kernel Key Version = %d\n\n", |
346 image->header_version, | 380 image->header_version, |
347 image->header_len, | 381 image->header_len, |
348 algo_strings[image->firmware_sign_algorithm], | 382 algo_strings[image->firmware_sign_algorithm], |
349 algo_strings[image->kernel_sign_algorithm], | 383 algo_strings[image->kernel_sign_algorithm], |
350 image->kernel_key_version); | 384 image->kernel_key_version); |
351 /* TODO(gauravsh): Output hash and key signature here? */ | 385 /* TODO(gauravsh): Output hash and key signature here? */ |
352 /* Print preamble. */ | 386 /* Print preamble. */ |
353 printf("Kernel Version = %d\n" | 387 printf("Kernel Version = %d\n" |
354 "kernel Length = %" PRId64 "\n" | 388 "kernel Length = %" PRId64 " (0x%" PRIx64 ")\n" |
355 "Bootloader Offset = %" PRId64 "\n" | 389 "Bootloader Offset = %" PRId64 " (0x%" PRIx64 ")\n" |
356 "Bootloader Size = %" PRId64 "\n" | 390 "Bootloader Size = %" PRId64 " (0x%" PRIx64 ")\n" |
357 "Padded Header Size = %" PRId64 "\n", | 391 "Padded Header Size = %" PRId64 " (0x%" PRIx64 ")\n\n" |
392 "Actual Header Size on disk = %" PRIu64 " (0x%" PRIx64 ")\n", | |
358 image->kernel_version, | 393 image->kernel_version, |
359 image->kernel_len, | 394 image->kernel_len, image->kernel_len, |
360 image->bootloader_offset, | 395 image->bootloader_offset, image->bootloader_offset, |
361 image->bootloader_size, | 396 image->bootloader_size, image->bootloader_size, |
362 image->padded_header_size); | 397 image->padded_header_size, image->padded_header_size, |
398 header_size, header_size); | |
363 /* TODO(gauravsh): Output kernel signature here? */ | 399 /* TODO(gauravsh): Output kernel signature here? */ |
364 } | 400 } |
365 | 401 |
366 | 402 |
367 int VerifyKernelImage(const RSAPublicKey* firmware_key, | 403 int VerifyKernelImage(const RSAPublicKey* firmware_key, |
368 const KernelImage* image, | 404 const KernelImage* image, |
369 const int dev_mode) { | 405 const int dev_mode) { |
370 RSAPublicKey* kernel_sign_key = NULL; | 406 RSAPublicKey* kernel_sign_key = NULL; |
371 uint8_t* header_digest = NULL; | 407 uint8_t* header_digest = NULL; |
372 uint8_t* preamble_digest = NULL; | 408 uint8_t* preamble_digest = NULL; |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
540 Free(kernel_signature); | 576 Free(kernel_signature); |
541 Free(kernel_buf); | 577 Free(kernel_buf); |
542 return 1; | 578 return 1; |
543 } | 579 } |
544 | 580 |
545 void PrintKernelEntry(kernel_entry* entry) { | 581 void PrintKernelEntry(kernel_entry* entry) { |
546 debug("Boot Priority = %d\n", entry->boot_priority); | 582 debug("Boot Priority = %d\n", entry->boot_priority); |
547 debug("Boot Tries Remaining = %d\n", entry->boot_tries_remaining); | 583 debug("Boot Tries Remaining = %d\n", entry->boot_tries_remaining); |
548 debug("Boot Success Flag = %d\n", entry->boot_success_flag); | 584 debug("Boot Success Flag = %d\n", entry->boot_success_flag); |
549 } | 585 } |
586 | |
587 // Return the smallest integral multiple of [alignment] that is equal to or | |
588 // greater than [val]. Used to determine the number of | |
589 // pages/sectors/blocks/whatever needed to contain [val] items/bytes/etc. | |
590 static uint64_t roundup(uint64_t val, uint64_t alignment) { | |
591 uint64_t rem = val % alignment; | |
592 if ( rem ) | |
593 return val + (alignment - rem); | |
594 return val; | |
595 } | |
596 | |
597 // Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we | |
598 // don't find one, we'll use the whole thing. | |
599 static unsigned int find_cmdline_start(char *input, unsigned int max_len) { | |
600 int start = 0; | |
601 int i; | |
602 for(i = 0; i < max_len-1 && input[i]; i++) { | |
603 if (input[i] == '-' && input[i+1] == '-') { // found a "--" | |
604 if ((i == 0 || input[i-1] == ' ') && // nothing before it | |
605 (i+2 >= max_len || input[i+2] == ' ')) { // nothing after it | |
606 start = i+2; // note: hope there's a trailing '\0' | |
607 break; | |
608 } | |
609 } | |
610 } | |
611 while(input[start] == ' ') // skip leading spaces | |
612 start++; | |
613 | |
614 return start; | |
615 } | |
616 | |
617 uint8_t* GenerateKernelBlob(const char* kernel_file, | |
618 const char* config_file, | |
619 const char* bootloader_file, | |
620 uint64_t* ret_blob_len, | |
621 uint64_t* ret_bootloader_offset, | |
622 uint64_t* ret_bootloader_size) { | |
623 uint8_t* kernel_buf; | |
624 uint8_t* config_buf; | |
625 uint8_t* bootloader_buf; | |
626 uint8_t* blob = 0; | |
627 uint64_t kernel_size; | |
628 uint64_t config_size; | |
629 uint64_t bootloader_size; | |
630 uint64_t blob_size; | |
631 uint64_t kernel32_start = 0; | |
632 uint64_t kernel32_size = 0; | |
633 uint64_t bootloader_mem_start; | |
634 uint64_t bootloader_mem_size; | |
635 uint64_t now; | |
636 struct linux_kernel_header *lh = 0; | |
637 struct linux_kernel_params *params = 0; | |
638 uint32_t cmdline_addr; | |
639 uint64_t i; | |
640 | |
641 // Read the input files. | |
642 kernel_buf = BufferFromFile(kernel_file, &kernel_size); | |
643 if (!kernel_buf) | |
644 goto done0; | |
645 | |
646 config_buf = BufferFromFile(config_file, &config_size); | |
647 if (!config_buf) | |
648 goto done1; | |
649 if (config_size < CROS_CONFIG_SIZE) // need room for trailing '\0' | |
650 goto done1; | |
651 | |
652 // Replace any newlines with spaces in the config file. | |
653 for (i=0; i < config_size; i++) | |
654 if (config_buf[i] == '\n') | |
655 config_buf[i] = ' '; | |
656 | |
657 bootloader_buf = BufferFromFile(bootloader_file, &bootloader_size); | |
658 if (!bootloader_buf) | |
659 goto done2; | |
660 | |
661 // The first part of vmlinuz is a header, followed by a real-mode boot stub. | |
662 // We only want the 32-bit part. | |
663 if (kernel_size) { | |
664 lh = (struct linux_kernel_header *)kernel_buf; | |
665 kernel32_start = (lh->setup_sects+1) << 9; | |
666 kernel32_size = kernel_size - kernel32_start; | |
667 } | |
668 | |
669 // Allocate and zero the blob we need. | |
670 blob_size = roundup(kernel32_size, CROS_ALIGN) + | |
671 CROS_CONFIG_SIZE + | |
672 CROS_PARAMS_SIZE + | |
673 roundup(bootloader_size, CROS_ALIGN); | |
674 blob = (uint8_t *)Malloc(blob_size); | |
675 if (!blob) | |
676 goto done3; | |
677 Memset(blob, 0, blob_size); | |
678 now = 0; | |
679 | |
680 // Copy the 32-bit kernel. | |
681 if (kernel32_size) | |
682 Memcpy(blob + now, kernel_buf + kernel32_start, kernel32_size); | |
683 now += roundup(now + kernel32_size, CROS_ALIGN); | |
684 | |
685 // Find the load address of the commandline. We'll need it later. | |
686 cmdline_addr = CROS_32BIT_ENTRY_ADDR + now | |
687 + find_cmdline_start((char *)config_buf, config_size); | |
688 | |
689 // Copy the config. | |
690 if (config_size) | |
691 Memcpy(blob + now, config_buf, config_size); | |
692 now += CROS_CONFIG_SIZE; | |
693 | |
694 // The zeropage data is next. Overlay the linux_kernel_header onto it, and | |
695 // tweak a few fields. | |
696 params = (struct linux_kernel_params *)(blob + now); | |
697 | |
698 if (kernel_size) | |
699 Memcpy(&(params->setup_sects), &(lh->setup_sects), | |
700 sizeof(*lh) - offsetof(struct linux_kernel_header, setup_sects)); | |
701 params->boot_flag = 0; | |
702 params->ramdisk_image = 0; // we don't support initrd | |
703 params->ramdisk_size = 0; | |
704 params->type_of_loader = 0xff; | |
705 params->cmd_line_ptr = cmdline_addr; | |
706 now += CROS_PARAMS_SIZE; | |
707 | |
708 // Finally, append the bootloader. Remember where it will load in memory, too. | |
709 bootloader_mem_start = CROS_32BIT_ENTRY_ADDR + now; | |
710 bootloader_mem_size = roundup(bootloader_size, CROS_ALIGN); | |
711 if (bootloader_size) | |
712 Memcpy(blob + now, bootloader_buf, bootloader_size); | |
713 now += bootloader_mem_size; | |
714 | |
715 // Pass back some info. | |
716 if (ret_blob_len) | |
717 *ret_blob_len = blob_size; | |
718 if (ret_bootloader_offset) | |
719 *ret_bootloader_offset = bootloader_mem_start; | |
720 if (ret_bootloader_size) | |
721 *ret_bootloader_size = bootloader_mem_size; | |
722 | |
723 // Clean up and return the blob. | |
724 done3: | |
725 Free(bootloader_buf); | |
726 done2: | |
727 Free(config_buf); | |
728 done1: | |
729 Free(kernel_buf); | |
730 done0: | |
731 return blob; | |
732 } | |
OLD | NEW |