mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-24 02:05:01 +00:00
When disabling verity with make_dev_ssh.sh, a bug in vbutil_kernel caused the re-signed kernel size to be the entire kernel partition instead of just the necessary bits. Until we can improve the test coverage, I'm rolling back the changes that introduced this bug. BUG=chromium:418647 BRANCH=ToT TEST=manual Created a new test image with these changes. You can install it and disable dm-verity and it works (although there seems to be an unrelated browser startup issue on ToT). Change-Id: I48e8427b05e191c9894c42056429a79d57bfc78d Signed-off-by: Bill Richardson <wfrichar@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/220935 Reviewed-by: Randall Spangler <rspangler@chromium.org>
619 lines
19 KiB
C
619 lines
19 KiB
C
/*
|
|
* Copyright 2014 The Chromium OS Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <inttypes.h> /* For PRIu64 */
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "futility.h"
|
|
#include "host_common.h"
|
|
#include "kernel_blob.h"
|
|
#include "util_misc.h"
|
|
#include "vb1_helper.h"
|
|
|
|
/****************************************************************************/
|
|
/* Here are globals containing all the bits & pieces I'm working on.
|
|
*
|
|
* kernel vblock = keyblock + kernel preamble + padding to 64K (or whatever)
|
|
* kernel blob = 32-bit kernel + config file + params + bootloader stub
|
|
* kernel partition = kernel vblock + kernel blob
|
|
*
|
|
* The VbKernelPreambleHeader.preamble_size includes the padding.
|
|
*/
|
|
|
|
/* The keyblock, preamble, and kernel blob are kept in separate places. */
|
|
static VbKeyBlockHeader *g_keyblock;
|
|
static VbKernelPreambleHeader *g_preamble;
|
|
static uint8_t *g_kernel_blob_data;
|
|
static uint64_t g_kernel_blob_size;
|
|
|
|
/* These refer to individual parts within the kernel blob. */
|
|
static uint8_t *g_kernel_data;
|
|
static uint64_t g_kernel_size;
|
|
static uint8_t *g_config_data;
|
|
static uint64_t g_config_size;
|
|
static uint8_t *g_param_data;
|
|
static uint64_t g_param_size;
|
|
static uint8_t *g_bootloader_data;
|
|
static uint64_t g_bootloader_size;
|
|
|
|
static uint64_t g_ondisk_bootloader_addr;
|
|
|
|
|
|
/*
|
|
* Read the kernel command line from a file. Get rid of \n characters along
|
|
* the way and verify that the line fits into a 4K buffer.
|
|
*
|
|
* Return the buffer contaning the line on success (and set the line length
|
|
* using the passed in parameter), or NULL in case something goes wrong.
|
|
*/
|
|
uint8_t *ReadConfigFile(const char *config_file, uint64_t *config_size)
|
|
{
|
|
uint8_t *config_buf;
|
|
int i;
|
|
|
|
config_buf = ReadFile(config_file, config_size);
|
|
if (!config_buf)
|
|
return NULL;
|
|
Debug(" config file size=0x%" PRIx64 "\n", *config_size);
|
|
if (CROS_CONFIG_SIZE <= *config_size) { /* room for trailing '\0' */
|
|
fprintf(stderr, "Config file %s is too large (>= %d bytes)\n",
|
|
config_file, CROS_CONFIG_SIZE);
|
|
return NULL;
|
|
}
|
|
|
|
/* Replace newlines with spaces */
|
|
for (i = 0; i < *config_size; i++)
|
|
if ('\n' == config_buf[i])
|
|
config_buf[i] = ' ';
|
|
|
|
return config_buf;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
/* 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(uint8_t *buf_ptr, unsigned int max_len)
|
|
{
|
|
char *input = (char *)buf_ptr;
|
|
int start = 0;
|
|
int i;
|
|
for (i = 0; i < max_len - 1 && input[i]; i++) {
|
|
if ('-' == input[i] && '-' == input[i + 1]) {
|
|
if ((i == 0 || ' ' == input[i - 1]) &&
|
|
(i + 2 >= max_len || ' ' == input[i + 2])) {
|
|
/* found "--" with nothing before or after it */
|
|
start = i + 2; /* hope for a trailing '\0' */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
while (' ' == input[start]) /* skip leading spaces */
|
|
start++;
|
|
|
|
return start;
|
|
}
|
|
|
|
/* Offset of kernel command line string from the start of the kernel blob */
|
|
uint64_t KernelCmdLineOffset(VbKernelPreambleHeader *preamble)
|
|
{
|
|
return preamble->bootloader_address - preamble->body_load_address -
|
|
CROS_CONFIG_SIZE - CROS_PARAMS_SIZE;
|
|
}
|
|
|
|
/* Returns the size of the 32-bit kernel, or negative on error. */
|
|
static int KernelSize(uint8_t *kernel_buf, uint64_t kernel_size,
|
|
enum arch_t arch)
|
|
{
|
|
uint64_t kernel32_start = 0;
|
|
struct linux_kernel_params *lh;
|
|
|
|
/* Except for x86, the kernel is the kernel. */
|
|
if (arch != ARCH_X86)
|
|
return kernel_size;
|
|
|
|
/* The first part of the x86 vmlinuz is a header, followed by
|
|
* a real-mode boot stub. We only want the 32-bit part. */
|
|
lh = (struct linux_kernel_params *)kernel_buf;
|
|
kernel32_start = (lh->setup_sects + 1) << 9;
|
|
if (kernel32_start >= kernel_size) {
|
|
fprintf(stderr, "Malformed kernel\n");
|
|
return -1;
|
|
}
|
|
return kernel_size - kernel32_start;
|
|
}
|
|
|
|
/* This extracts g_kernel_* and g_param_* from a standard vmlinuz file.
|
|
* It returns nonzero on error. */
|
|
static int PickApartVmlinuz(uint8_t *kernel_buf, uint64_t kernel_size,
|
|
enum arch_t arch,
|
|
uint64_t kernel_body_load_address)
|
|
{
|
|
uint64_t kernel32_start = 0;
|
|
uint64_t kernel32_size = kernel_size;
|
|
struct linux_kernel_params *lh, *params;
|
|
|
|
/* Except for x86, the kernel is the kernel. */
|
|
if (arch == ARCH_X86) {
|
|
/* The first part of the x86 vmlinuz is a header, followed by
|
|
* a real-mode boot stub. We only want the 32-bit part. */
|
|
lh = (struct linux_kernel_params *)kernel_buf;
|
|
kernel32_start = (lh->setup_sects + 1) << 9;
|
|
if (kernel32_start >= kernel_size) {
|
|
fprintf(stderr, "Malformed kernel\n");
|
|
return -1;
|
|
}
|
|
kernel32_size = kernel_size - kernel32_start;
|
|
|
|
/* Copy the original zeropage data from kernel_buf into
|
|
* g_param_data, then tweak a few fields for our purposes */
|
|
params = (struct linux_kernel_params *)(g_param_data);
|
|
Memcpy(&(params->setup_sects), &(lh->setup_sects),
|
|
offsetof(struct linux_kernel_params, e820_entries)
|
|
- offsetof(struct linux_kernel_params, setup_sects));
|
|
params->boot_flag = 0;
|
|
params->ramdisk_image = 0; /* we don't support initrd */
|
|
params->ramdisk_size = 0;
|
|
params->type_of_loader = 0xff;
|
|
/* We need to point to the kernel commandline arg. On disk, it
|
|
* will come right after the 32-bit part of the kernel. */
|
|
params->cmd_line_ptr = kernel_body_load_address +
|
|
roundup(kernel32_size, CROS_ALIGN) +
|
|
find_cmdline_start(g_config_data, g_config_size);
|
|
Debug(" cmdline_addr=0x%x\n", params->cmd_line_ptr);
|
|
Debug(" version=0x%x\n", params->version);
|
|
Debug(" kernel_alignment=0x%x\n", params->kernel_alignment);
|
|
Debug(" relocatable_kernel=0x%x\n", params->relocatable_kernel);
|
|
/* Add a fake e820 memory map with 2 entries. */
|
|
params->n_e820_entry = 2;
|
|
params->e820_entries[0].start_addr = 0x00000000;
|
|
params->e820_entries[0].segment_size = 0x00001000;
|
|
params->e820_entries[0].segment_type = E820_TYPE_RAM;
|
|
params->e820_entries[1].start_addr = 0xfffff000;
|
|
params->e820_entries[1].segment_size = 0x00001000;
|
|
params->e820_entries[1].segment_type = E820_TYPE_RESERVED;
|
|
}
|
|
|
|
Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start);
|
|
Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size);
|
|
|
|
/* Keep just the 32-bit kernel. */
|
|
if (kernel32_size) {
|
|
g_kernel_size = kernel32_size;
|
|
Memcpy(g_kernel_data, kernel_buf + kernel32_start,
|
|
g_kernel_size);
|
|
}
|
|
|
|
/* done */
|
|
return 0;
|
|
}
|
|
|
|
/* Split a kernel blob into separate g_kernel, g_param, g_config, and
|
|
* g_bootloader parts. */
|
|
static void UnpackKernelBlob(uint8_t *kernel_blob_data)
|
|
{
|
|
uint64_t now;
|
|
|
|
/* We have to work backwards from the end, because the preamble
|
|
only describes the bootloader stub. */
|
|
|
|
/* Where does the bootloader stub begin? */
|
|
now = g_preamble->bootloader_address - g_preamble->body_load_address;
|
|
|
|
/* Bootloader is at the end */
|
|
g_bootloader_size = g_preamble->bootloader_size;
|
|
g_bootloader_data = kernel_blob_data + now;
|
|
/* TODO: What to do if this is beyond the end of the blob? */
|
|
|
|
Debug("bootloader_size = 0x%" PRIx64 "\n", g_bootloader_size);
|
|
Debug("bootloader_ofs = 0x%" PRIx64 "\n", now);
|
|
|
|
/* Before that is the params */
|
|
now -= CROS_PARAMS_SIZE;
|
|
g_param_size = CROS_PARAMS_SIZE;
|
|
g_param_data = kernel_blob_data + now;
|
|
Debug("param_ofs = 0x%" PRIx64 "\n", now);
|
|
|
|
/* Before that is the config */
|
|
now -= CROS_CONFIG_SIZE;
|
|
g_config_size = CROS_CONFIG_SIZE;
|
|
g_config_data = kernel_blob_data + now;
|
|
Debug("config_ofs = 0x%" PRIx64 "\n", now);
|
|
|
|
/* The kernel starts at offset 0 and extends up to the config */
|
|
g_kernel_data = kernel_blob_data;
|
|
g_kernel_size = now;
|
|
Debug("kernel_size = 0x%" PRIx64 "\n", g_kernel_size);
|
|
}
|
|
|
|
|
|
/* Replaces the config section of the specified kernel blob.
|
|
* Return nonzero on error. */
|
|
int UpdateKernelBlobConfig(uint8_t *kblob_data, uint64_t kblob_size,
|
|
uint8_t *config_data, uint64_t config_size)
|
|
{
|
|
/* We should have already examined this blob. If not, we could do it
|
|
* again, but it's more likely due to an error. */
|
|
if (kblob_data != g_kernel_blob_data ||
|
|
kblob_size != g_kernel_blob_size) {
|
|
fprintf(stderr, "Trying to update some other blob\n");
|
|
return -1;
|
|
}
|
|
|
|
Memset(g_config_data, 0, g_config_size);
|
|
Memcpy(g_config_data, config_data, config_size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Split a kernel partition into separate vblock and blob parts. */
|
|
uint8_t *UnpackKPart(uint8_t *kpart_data, uint64_t kpart_size,
|
|
uint64_t padding,
|
|
VbKeyBlockHeader **keyblock_ptr,
|
|
VbKernelPreambleHeader **preamble_ptr,
|
|
uint64_t *blob_size_ptr)
|
|
{
|
|
VbKeyBlockHeader *keyblock;
|
|
VbKernelPreambleHeader *preamble;
|
|
uint64_t now = 0;
|
|
|
|
/* Sanity-check the keyblock */
|
|
keyblock = (VbKeyBlockHeader *)kpart_data;
|
|
Debug("Keyblock is 0x%" PRIx64 " bytes\n", keyblock->key_block_size);
|
|
now += keyblock->key_block_size;
|
|
if (now > kpart_size) {
|
|
fprintf(stderr,
|
|
"key_block_size advances past the end of the blob\n");
|
|
return NULL;
|
|
}
|
|
if (now > padding) {
|
|
fprintf(stderr,
|
|
"key_block_size advances past %" PRIu64
|
|
" byte padding\n",
|
|
padding);
|
|
return NULL;
|
|
}
|
|
|
|
/* LGTM */
|
|
g_keyblock = keyblock;
|
|
|
|
/* And the preamble */
|
|
preamble = (VbKernelPreambleHeader *)(kpart_data + now);
|
|
Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size);
|
|
now += preamble->preamble_size;
|
|
if (now > kpart_size) {
|
|
fprintf(stderr,
|
|
"preamble_size advances past the end of the blob\n");
|
|
return NULL;
|
|
}
|
|
if (now > padding) {
|
|
fprintf(stderr, "preamble_size advances past %" PRIu64
|
|
" byte padding\n", padding);
|
|
return NULL;
|
|
}
|
|
/* LGTM */
|
|
Debug(" kernel_version = %d\n", preamble->kernel_version);
|
|
Debug(" bootloader_address = 0x%" PRIx64 "\n",
|
|
preamble->bootloader_address);
|
|
Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size);
|
|
Debug(" kern_blob_size = 0x%" PRIx64 "\n",
|
|
preamble->body_signature.data_size);
|
|
g_preamble = preamble;
|
|
g_ondisk_bootloader_addr = g_preamble->bootloader_address;
|
|
|
|
Debug("kernel blob is at offset 0x%" PRIx64 "\n", now);
|
|
g_kernel_blob_data = kpart_data + now;
|
|
g_kernel_blob_size = kpart_size - now;
|
|
|
|
/* Sanity check */
|
|
if (g_kernel_blob_size < preamble->body_signature.data_size)
|
|
fprintf(stderr,
|
|
"Warning: kernel file only has 0x%" PRIx64 " bytes\n",
|
|
g_kernel_blob_size);
|
|
|
|
/* Update the blob pointers */
|
|
UnpackKernelBlob(g_kernel_blob_data);
|
|
|
|
if (keyblock_ptr)
|
|
*keyblock_ptr = keyblock;
|
|
if (preamble_ptr)
|
|
*preamble_ptr = preamble;
|
|
if (blob_size_ptr)
|
|
*blob_size_ptr = g_kernel_blob_size;
|
|
|
|
return g_kernel_blob_data;
|
|
}
|
|
|
|
uint8_t *SignKernelBlob(uint8_t *kernel_blob, uint64_t kernel_size,
|
|
uint64_t padding,
|
|
int version, uint64_t kernel_body_load_address,
|
|
VbKeyBlockHeader *keyblock, VbPrivateKey *signpriv_key,
|
|
uint64_t *vblock_size_ptr)
|
|
{
|
|
VbSignature *body_sig;
|
|
VbKernelPreambleHeader *preamble;
|
|
uint64_t min_size = padding > keyblock->key_block_size
|
|
? padding - keyblock->key_block_size : 0;
|
|
void *outbuf;
|
|
uint64_t outsize;
|
|
|
|
/* Sign the kernel data */
|
|
body_sig = CalculateSignature(kernel_blob, kernel_size, signpriv_key);
|
|
if (!body_sig) {
|
|
fprintf(stderr, "Error calculating body signature\n");
|
|
return NULL;
|
|
}
|
|
|
|
/* Create preamble */
|
|
preamble = CreateKernelPreamble(version,
|
|
kernel_body_load_address,
|
|
g_ondisk_bootloader_addr,
|
|
g_bootloader_size,
|
|
body_sig, min_size,
|
|
signpriv_key);
|
|
if (!preamble) {
|
|
fprintf(stderr, "Error creating preamble.\n");
|
|
return 0;
|
|
}
|
|
|
|
outsize = keyblock->key_block_size + preamble->preamble_size;
|
|
outbuf = malloc(outsize);
|
|
Memset(outbuf, 0, outsize);
|
|
Memcpy(outbuf, keyblock, keyblock->key_block_size);
|
|
Memcpy(outbuf + keyblock->key_block_size,
|
|
preamble, preamble->preamble_size);
|
|
|
|
if (vblock_size_ptr)
|
|
*vblock_size_ptr = outsize;
|
|
return outbuf;
|
|
}
|
|
|
|
/* Returns zero on success */
|
|
int WriteSomeParts(const char *outfile,
|
|
void *part1_data, uint64_t part1_size,
|
|
void *part2_data, uint64_t part2_size)
|
|
{
|
|
FILE *f;
|
|
|
|
/* Write the output file */
|
|
Debug("writing %s with 0x%" PRIx64 ", 0x%" PRIx64 "\n",
|
|
outfile, part1_size, part2_size);
|
|
|
|
f = fopen(outfile, "wb");
|
|
if (!f) {
|
|
fprintf(stderr, "Can't open output file %s: %s\n",
|
|
outfile, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
if (part1_data && part1_size) {
|
|
if (1 != fwrite(part1_data, part1_size, 1, f)) {
|
|
fprintf(stderr, "Can't write output file %s: %s\n",
|
|
outfile, strerror(errno));
|
|
fclose(f);
|
|
unlink(outfile);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (part2_data && part2_size) {
|
|
if (1 != fwrite(part2_data, part2_size, 1, f)) {
|
|
fprintf(stderr, "Can't write output file %s: %s\n",
|
|
outfile, strerror(errno));
|
|
fclose(f);
|
|
unlink(outfile);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
/* Success */
|
|
return 0;
|
|
}
|
|
|
|
/* Returns 0 on success */
|
|
int VerifyKernelBlob(uint8_t *kernel_blob,
|
|
uint64_t kernel_size,
|
|
VbPublicKey *signpub_key,
|
|
const char *keyblock_outfile,
|
|
uint64_t min_version)
|
|
{
|
|
VbPublicKey *data_key;
|
|
RSAPublicKey *rsa;
|
|
int rv = -1;
|
|
|
|
if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size,
|
|
signpub_key, (0 == signpub_key))) {
|
|
fprintf(stderr, "Error verifying key block.\n");
|
|
goto done;
|
|
}
|
|
|
|
printf("Key block:\n");
|
|
data_key = &g_keyblock->data_key;
|
|
printf(" Signature: %s\n",
|
|
signpub_key ? "valid" : "ignored");
|
|
printf(" Size: 0x%" PRIx64 "\n",
|
|
g_keyblock->key_block_size);
|
|
printf(" Flags: %" PRIu64 " ",
|
|
g_keyblock->key_block_flags);
|
|
if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0)
|
|
printf(" !DEV");
|
|
if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1)
|
|
printf(" DEV");
|
|
if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)
|
|
printf(" !REC");
|
|
if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)
|
|
printf(" REC");
|
|
printf("\n");
|
|
printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm,
|
|
(data_key->algorithm < kNumAlgorithms ?
|
|
algo_strings[data_key->algorithm] : "(invalid)"));
|
|
printf(" Data key version: %" PRIu64 "\n", data_key->key_version);
|
|
printf(" Data key sha1sum: ");
|
|
PrintPubKeySha1Sum(data_key);
|
|
printf("\n");
|
|
|
|
if (keyblock_outfile) {
|
|
FILE *f = NULL;
|
|
f = fopen(keyblock_outfile, "wb");
|
|
if (!f) {
|
|
fprintf(stderr, "Can't open key block file %s: %s\n",
|
|
keyblock_outfile, strerror(errno));
|
|
goto done;
|
|
}
|
|
if (1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) {
|
|
fprintf(stderr, "Can't write key block file %s: %s\n",
|
|
keyblock_outfile, strerror(errno));
|
|
fclose(f);
|
|
goto done;
|
|
}
|
|
fclose(f);
|
|
}
|
|
|
|
if (data_key->key_version < (min_version >> 16)) {
|
|
fprintf(stderr, "Data key version %" PRIu64
|
|
" is lower than minimum %" PRIu64 ".\n",
|
|
data_key->key_version, (min_version >> 16));
|
|
goto done;
|
|
}
|
|
|
|
rsa = PublicKeyToRSA(data_key);
|
|
if (!rsa) {
|
|
fprintf(stderr, "Error parsing data key.\n");
|
|
goto done;
|
|
}
|
|
|
|
/* Verify preamble */
|
|
if (0 != VerifyKernelPreamble(g_preamble,
|
|
g_preamble->preamble_size, rsa)) {
|
|
fprintf(stderr, "Error verifying preamble.\n");
|
|
goto done;
|
|
}
|
|
|
|
printf("Preamble:\n");
|
|
printf(" Size: 0x%" PRIx64 "\n",
|
|
g_preamble->preamble_size);
|
|
printf(" Header version: %" PRIu32 ".%" PRIu32 "\n",
|
|
g_preamble->header_version_major,
|
|
g_preamble->header_version_minor);
|
|
printf(" Kernel version: %" PRIu64 "\n",
|
|
g_preamble->kernel_version);
|
|
printf(" Body load address: 0x%" PRIx64 "\n",
|
|
g_preamble->body_load_address);
|
|
printf(" Body size: 0x%" PRIx64 "\n",
|
|
g_preamble->body_signature.data_size);
|
|
printf(" Bootloader address: 0x%" PRIx64 "\n",
|
|
g_preamble->bootloader_address);
|
|
printf(" Bootloader size: 0x%" PRIx64 "\n",
|
|
g_preamble->bootloader_size);
|
|
|
|
if (g_preamble->kernel_version < (min_version & 0xFFFF)) {
|
|
fprintf(stderr,
|
|
"Kernel version %" PRIu64 " is lower than minimum %"
|
|
PRIu64 ".\n", g_preamble->kernel_version,
|
|
(min_version & 0xFFFF));
|
|
goto done;
|
|
}
|
|
|
|
/* Verify body */
|
|
if (0 != VerifyData(kernel_blob, kernel_size,
|
|
&g_preamble->body_signature, rsa)) {
|
|
fprintf(stderr, "Error verifying kernel body.\n");
|
|
goto done;
|
|
}
|
|
printf("Body verification succeeded.\n");
|
|
|
|
printf("Config:\n%s\n", kernel_blob + KernelCmdLineOffset(g_preamble));
|
|
|
|
rv = 0;
|
|
done:
|
|
return rv;
|
|
}
|
|
|
|
|
|
uint8_t *CreateKernelBlob(uint8_t *vmlinuz_buf, uint64_t vmlinuz_size,
|
|
enum arch_t arch, uint64_t kernel_body_load_address,
|
|
uint8_t *config_data, uint64_t config_size,
|
|
uint8_t *bootloader_data, uint64_t bootloader_size,
|
|
uint64_t *blob_size_ptr)
|
|
{
|
|
uint64_t now = 0;
|
|
int tmp;
|
|
|
|
/* We have all the parts. How much room do we need? */
|
|
tmp = KernelSize(vmlinuz_buf, vmlinuz_size, arch);
|
|
if (tmp < 0)
|
|
return NULL;
|
|
g_kernel_size = tmp;
|
|
g_config_size = CROS_CONFIG_SIZE;
|
|
g_param_size = CROS_PARAMS_SIZE;
|
|
g_bootloader_size = roundup(bootloader_size, CROS_ALIGN);
|
|
g_kernel_blob_size = roundup(g_kernel_size, CROS_ALIGN) +
|
|
g_config_size + g_param_size + g_bootloader_size;
|
|
Debug("g_kernel_blob_size 0x%" PRIx64 "\n", g_kernel_blob_size);
|
|
|
|
/* Allocate space for the blob. */
|
|
g_kernel_blob_data = malloc(g_kernel_blob_size);
|
|
Memset(g_kernel_blob_data, 0, g_kernel_blob_size);
|
|
|
|
/* Assign the sub-pointers */
|
|
g_kernel_data = g_kernel_blob_data + now;
|
|
Debug("g_kernel_size 0x%" PRIx64 " ofs 0x%" PRIx64 "\n",
|
|
g_kernel_size, now);
|
|
now += roundup(g_kernel_size, CROS_ALIGN);
|
|
|
|
g_config_data = g_kernel_blob_data + now;
|
|
Debug("g_config_size 0x%" PRIx64 " ofs 0x%" PRIx64 "\n",
|
|
g_config_size, now);
|
|
now += g_config_size;
|
|
|
|
g_param_data = g_kernel_blob_data + now;
|
|
Debug("g_param_size 0x%" PRIx64 " ofs 0x%" PRIx64 "\n",
|
|
g_param_size, now);
|
|
now += g_param_size;
|
|
|
|
g_bootloader_data = g_kernel_blob_data + now;
|
|
Debug("g_bootloader_size 0x%" PRIx64 " ofs 0x%" PRIx64 "\n",
|
|
g_bootloader_size, now);
|
|
g_ondisk_bootloader_addr = kernel_body_load_address + now;
|
|
Debug("g_ondisk_bootloader_addr 0x%" PRIx64 "\n",
|
|
g_ondisk_bootloader_addr);
|
|
|
|
/* Copy the kernel and params bits into the correct places */
|
|
if (0 != PickApartVmlinuz(vmlinuz_buf, vmlinuz_size,
|
|
arch, kernel_body_load_address)) {
|
|
fprintf(stderr, "Error picking apart kernel file.\n");
|
|
free(g_kernel_blob_data);
|
|
g_kernel_blob_data = NULL;
|
|
g_kernel_blob_size = 0;
|
|
return NULL;
|
|
}
|
|
|
|
/* Copy the other bits too */
|
|
Memcpy(g_config_data, config_data, config_size);
|
|
Memcpy(g_bootloader_data, bootloader_data, bootloader_size);
|
|
|
|
if (blob_size_ptr)
|
|
*blob_size_ptr = g_kernel_blob_size;
|
|
return g_kernel_blob_data;
|
|
}
|