Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(584)

Unified Diff: src/platform/vboot_reference/vkernel/kernel_image.c

Issue 2283005: Modifying the kernel_utility tool to create our magic blob. (Closed) Base URL: ssh://git@chromiumos-git/chromeos
Patch Set: respond to feedback Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/platform/vboot_reference/vkernel/include/kernel_image.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/platform/vboot_reference/vkernel/kernel_image.c
diff --git a/src/platform/vboot_reference/vkernel/kernel_image.c b/src/platform/vboot_reference/vkernel/kernel_image.c
index 5eeb784f679599b12eba5d2b92099f1466e7c29a..e1d6a6900e9dcbd75b0127cdd63112e86dd8e699 100644
--- a/src/platform/vboot_reference/vkernel/kernel_image.c
+++ b/src/platform/vboot_reference/vkernel/kernel_image.c
@@ -6,9 +6,8 @@
* (Userland portion)
*/
-#include "kernel_image.h"
-
#include <fcntl.h>
+#include <stddef.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -16,6 +15,8 @@
#include "cryptolib.h"
#include "file_keys.h"
+#include "kernel_image.h"
gauravsh 2010/05/27 18:06:04 oops, I meant only #include kernel_blob.h should g
+#include "kernel_blob.h"
#include "rollback_index.h"
#include "signature_digest.h"
#include "utility.h"
@@ -32,6 +33,7 @@ KernelImage* KernelImageNew(void) {
image->preamble_signature = NULL;
image->kernel_signature = NULL;
image->kernel_data = NULL;
+ image->padded_header_size = 0x4000;
}
return image;
}
@@ -47,9 +49,23 @@ void KernelImageFree(KernelImage* image) {
}
}
+uint64_t GetHeaderSizeOnDisk(const KernelImage* image) {
+ uint64_t kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
+ uint64_t kernel_key_signature_len =
+ siglen_map[image->firmware_sign_algorithm];
+
+ return FIELD_LEN(magic) +
+ GetKernelHeaderLen(image) +
+ kernel_key_signature_len +
+ GetKernelPreambleLen(image->kernel_sign_algorithm) +
+ kernel_signature_len;
+}
+
+
KernelImage* ReadKernelImage(const char* input_file) {
uint64_t file_size;
- int image_len = 0; /* Total size of the kernel image. */
+ uint64_t on_disk_header_size;
+ uint64_t on_disk_padding;
int header_len = 0;
int firmware_sign_key_len;
int kernel_key_signature_len;
@@ -64,9 +80,8 @@ KernelImage* ReadKernelImage(const char* input_file) {
return NULL;
kernel_buf = BufferFromFile(input_file, &file_size);
- image_len = file_size;
- st.remaining_len = image_len;
+ st.remaining_len = file_size;
st.remaining_buf = kernel_buf;
st.overrun = 0;
@@ -141,11 +156,21 @@ KernelImage* ReadKernelImage(const char* input_file) {
StatefulMemcpy(&st, &image->padded_header_size,
FIELD_LEN(padded_header_size));
- /* Read config and kernel signatures. */
- image->preamble_signature = (uint8_t*) Malloc(kernel_signature_len);
- StatefulMemcpy(&st, image->preamble_signature, kernel_signature_len);
+ /* Read preamble and kernel signatures. */
image->kernel_signature = (uint8_t*) Malloc(kernel_signature_len);
StatefulMemcpy(&st, image->kernel_signature, kernel_signature_len);
+ image->preamble_signature = (uint8_t*) Malloc(kernel_signature_len);
+ StatefulMemcpy(&st, image->preamble_signature, kernel_signature_len);
+
+ /* Skip over the rest of the padded header, unless we're already past it. */
+ on_disk_header_size = file_size - st.remaining_len;
+ if (image->padded_header_size > on_disk_header_size) {
+ on_disk_padding = image->padded_header_size - on_disk_header_size;
+ if (st.remaining_len < on_disk_padding)
+ st.overrun = -1;
+ st.remaining_buf += on_disk_padding;
+ st.remaining_len -= on_disk_padding;
+ }
/* Read kernel image data. */
image->kernel_data = (uint8_t*) Malloc(image->kernel_len);
@@ -250,22 +275,21 @@ uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) {
uint8_t* kernel_blob = NULL;
uint8_t* header_blob = NULL;
MemcpyState st;
+ uint64_t on_disk_header_size;
+ uint64_t on_disk_padding = 0;
if (!image)
return NULL;
kernel_key_signature_len = siglen_map[image->firmware_sign_algorithm];
kernel_signature_len = siglen_map[image->kernel_sign_algorithm];
- *blob_len = (FIELD_LEN(magic) +
- GetKernelHeaderLen(image) +
- kernel_key_signature_len +
- GetKernelPreambleLen(image->kernel_sign_algorithm) +
- kernel_signature_len +
- image->kernel_len);
+ on_disk_header_size = GetHeaderSizeOnDisk(image);
+ if (image->padded_header_size > on_disk_header_size)
+ on_disk_padding = image->padded_header_size - on_disk_header_size;
+ *blob_len = on_disk_header_size + on_disk_padding + image->kernel_len;
kernel_blob = (uint8_t*) Malloc(*blob_len);
st.remaining_len = *blob_len;
st.remaining_buf = kernel_blob;
st.overrun = 0;
-
header_blob = GetKernelHeaderBlob(image);
StatefulMemcpy_r(&st, image->magic, FIELD_LEN(magic));
@@ -281,6 +305,9 @@ uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) {
FIELD_LEN(padded_header_size));
StatefulMemcpy_r(&st, image->kernel_signature, kernel_signature_len);
StatefulMemcpy_r(&st, image->preamble_signature, kernel_signature_len);
+ /* Copy a bunch of zeros to pad out the header */
+ if (on_disk_padding)
+ StatefulMemset_r(&st, 0, on_disk_padding);
StatefulMemcpy_r(&st, image->kernel_data, image->kernel_len);
Free(header_blob);
@@ -293,7 +320,7 @@ uint8_t* GetKernelBlob(const KernelImage* image, uint64_t* blob_len) {
return kernel_blob;
}
-int WriteKernelImage(const char* input_file,
+int WriteKernelImage(const char* output_file,
const KernelImage* image,
int is_only_vblock) {
int fd;
@@ -303,9 +330,9 @@ int WriteKernelImage(const char* input_file,
if (!image)
return 0;
- if (-1 == (fd = creat(input_file, S_IRWXU))) {
+ if (-1 == (fd = creat(output_file, S_IRWXU))) {
debug("Couldn't open file for writing kernel image: %s\n",
- input_file);
+ output_file);
return 0;
}
kernel_blob = GetKernelBlob(image, &blob_len);
@@ -316,7 +343,7 @@ int WriteKernelImage(const char* input_file,
if (!is_only_vblock) {
if (blob_len != write(fd, kernel_blob, blob_len)) {
debug("Couldn't write Kernel Image to file: %s\n",
- input_file);
+ output_file);
success = 0;
}
} else {
@@ -324,7 +351,7 @@ int WriteKernelImage(const char* input_file,
int vblock_len = blob_len - (image->kernel_len);
if (vblock_len != write(fd, kernel_blob, vblock_len)) {
debug("Couldn't write Kernel Image Verification block to file: %s\n",
- input_file);
+ output_file);
success = 0;
}
}
@@ -334,9 +361,16 @@ int WriteKernelImage(const char* input_file,
}
void PrintKernelImage(const KernelImage* image) {
+ uint64_t header_size;
+
if (!image)
return;
+ header_size = GetHeaderSizeOnDisk(image);
+ if (image->padded_header_size > header_size)
+ header_size = image->padded_header_size;
+
+
/* Print header. */
printf("Header Version = %d\n"
"Header Length = %d\n"
@@ -351,15 +385,17 @@ void PrintKernelImage(const KernelImage* image) {
/* TODO(gauravsh): Output hash and key signature here? */
/* Print preamble. */
printf("Kernel Version = %d\n"
- "kernel Length = %" PRId64 "\n"
- "Bootloader Offset = %" PRId64 "\n"
- "Bootloader Size = %" PRId64 "\n"
- "Padded Header Size = %" PRId64 "\n",
+ "kernel Length = %" PRId64 " (0x%" PRIx64 ")\n"
+ "Bootloader Offset = %" PRId64 " (0x%" PRIx64 ")\n"
+ "Bootloader Size = %" PRId64 " (0x%" PRIx64 ")\n"
+ "Padded Header Size = %" PRId64 " (0x%" PRIx64 ")\n\n"
+ "Actual Header Size on disk = %" PRIu64 " (0x%" PRIx64 ")\n",
image->kernel_version,
- image->kernel_len,
- image->bootloader_offset,
- image->bootloader_size,
- image->padded_header_size);
+ image->kernel_len, image->kernel_len,
+ image->bootloader_offset, image->bootloader_offset,
+ image->bootloader_size, image->bootloader_size,
+ image->padded_header_size, image->padded_header_size,
+ header_size, header_size);
/* TODO(gauravsh): Output kernel signature here? */
}
@@ -547,3 +583,150 @@ void PrintKernelEntry(kernel_entry* entry) {
debug("Boot Tries Remaining = %d\n", entry->boot_tries_remaining);
debug("Boot Success Flag = %d\n", entry->boot_success_flag);
}
+
+// Return the smallest integral multiple of [alignment] that is equal to or
+// greater than [val]. Used to determine the number of
+// pages/sectors/blocks/whatever needed to contain [val] items/bytes/etc.
+static uint64_t roundup(uint64_t val, uint64_t alignment) {
+ uint64_t rem = val % alignment;
+ if ( rem )
+ return val + (alignment - rem);
+ return val;
+}
+
+// Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we
+// don't find one, we'll use the whole thing.
+static unsigned int find_cmdline_start(char *input, unsigned int max_len) {
+ int start = 0;
+ int i;
+ for(i = 0; i < max_len-1 && input[i]; i++) {
+ if (input[i] == '-' && input[i+1] == '-') { // found a "--"
+ if ((i == 0 || input[i-1] == ' ') && // nothing before it
+ (i+2 >= max_len || input[i+2] == ' ')) { // nothing after it
+ start = i+2; // note: hope there's a trailing '\0'
+ break;
+ }
+ }
+ }
+ while(input[start] == ' ') // skip leading spaces
+ start++;
+
+ return start;
+}
+
+uint8_t* GenerateKernelBlob(const char* kernel_file,
+ const char* config_file,
+ const char* bootloader_file,
+ uint64_t* ret_blob_len,
+ uint64_t* ret_bootloader_offset,
+ uint64_t* ret_bootloader_size) {
+ uint8_t* kernel_buf;
+ uint8_t* config_buf;
+ uint8_t* bootloader_buf;
+ uint8_t* blob = 0;
+ uint64_t kernel_size;
+ uint64_t config_size;
+ uint64_t bootloader_size;
+ uint64_t blob_size;
+ uint64_t kernel32_start = 0;
+ uint64_t kernel32_size = 0;
+ uint64_t bootloader_mem_start;
+ uint64_t bootloader_mem_size;
+ uint64_t now;
+ struct linux_kernel_header *lh = 0;
+ struct linux_kernel_params *params = 0;
+ uint32_t cmdline_addr;
+ uint64_t i;
+
+ // Read the input files.
+ kernel_buf = BufferFromFile(kernel_file, &kernel_size);
+ if (!kernel_buf)
+ goto done0;
+
+ config_buf = BufferFromFile(config_file, &config_size);
+ if (!config_buf)
+ goto done1;
+ if (config_size < CROS_CONFIG_SIZE) // need room for trailing '\0'
+ goto done1;
+
+ // Replace any newlines with spaces in the config file.
+ for (i=0; i < config_size; i++)
+ if (config_buf[i] == '\n')
+ config_buf[i] = ' ';
+
+ bootloader_buf = BufferFromFile(bootloader_file, &bootloader_size);
+ if (!bootloader_buf)
+ goto done2;
+
+ // The first part of vmlinuz is a header, followed by a real-mode boot stub.
+ // We only want the 32-bit part.
+ if (kernel_size) {
+ lh = (struct linux_kernel_header *)kernel_buf;
+ kernel32_start = (lh->setup_sects+1) << 9;
+ kernel32_size = kernel_size - kernel32_start;
+ }
+
+ // Allocate and zero the blob we need.
+ blob_size = roundup(kernel32_size, CROS_ALIGN) +
+ CROS_CONFIG_SIZE +
+ CROS_PARAMS_SIZE +
+ roundup(bootloader_size, CROS_ALIGN);
+ blob = (uint8_t *)Malloc(blob_size);
+ if (!blob)
+ goto done3;
+ Memset(blob, 0, blob_size);
+ now = 0;
+
+ // Copy the 32-bit kernel.
+ if (kernel32_size)
+ Memcpy(blob + now, kernel_buf + kernel32_start, kernel32_size);
+ now += roundup(now + kernel32_size, CROS_ALIGN);
+
+ // Find the load address of the commandline. We'll need it later.
+ cmdline_addr = CROS_32BIT_ENTRY_ADDR + now
+ + find_cmdline_start((char *)config_buf, config_size);
+
+ // Copy the config.
+ if (config_size)
+ Memcpy(blob + now, config_buf, config_size);
+ now += CROS_CONFIG_SIZE;
+
+ // The zeropage data is next. Overlay the linux_kernel_header onto it, and
+ // tweak a few fields.
+ params = (struct linux_kernel_params *)(blob + now);
+
+ if (kernel_size)
+ Memcpy(&(params->setup_sects), &(lh->setup_sects),
+ sizeof(*lh) - offsetof(struct linux_kernel_header, setup_sects));
+ params->boot_flag = 0;
+ params->ramdisk_image = 0; // we don't support initrd
+ params->ramdisk_size = 0;
+ params->type_of_loader = 0xff;
+ params->cmd_line_ptr = cmdline_addr;
+ now += CROS_PARAMS_SIZE;
+
+ // Finally, append the bootloader. Remember where it will load in memory, too.
+ bootloader_mem_start = CROS_32BIT_ENTRY_ADDR + now;
+ bootloader_mem_size = roundup(bootloader_size, CROS_ALIGN);
+ if (bootloader_size)
+ Memcpy(blob + now, bootloader_buf, bootloader_size);
+ now += bootloader_mem_size;
+
+ // Pass back some info.
+ if (ret_blob_len)
+ *ret_blob_len = blob_size;
+ if (ret_bootloader_offset)
+ *ret_bootloader_offset = bootloader_mem_start;
+ if (ret_bootloader_size)
+ *ret_bootloader_size = bootloader_mem_size;
+
+ // Clean up and return the blob.
+done3:
+ Free(bootloader_buf);
+done2:
+ Free(config_buf);
+done1:
+ Free(kernel_buf);
+done0:
+ return blob;
+}
« no previous file with comments | « src/platform/vboot_reference/vkernel/include/kernel_image.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698