Chromium Code Reviews| 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 |