blob: 83b6d6c11823f582f2ec2364c7e896be1b4b99ee [file] [log] [blame]
/* Copyright (c) 2013 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.
*
* Tests for VbTryLoadKernel()
*/
#include "2common.h"
#include "2misc.h"
#include "2nvstorage.h"
#include "2sysincludes.h"
#include "load_kernel_fw.h"
#include "test_common.h"
#include "vboot_api.h"
#include "vboot_kernel.h"
#include "vboot_test.h"
#define MAX_TEST_DISKS 10
#define DEFAULT_COUNT -1
typedef struct {
uint64_t bytes_per_lba;
uint64_t lba_count;
uint32_t flags;
const char *diskname;
} disk_desc_t;
typedef struct {
const char *name;
/* inputs for test case */
uint32_t want_flags;
vb2_error_t diskgetinfo_return_val;
disk_desc_t disks_to_provide[MAX_TEST_DISKS];
int disk_count_to_return;
vb2_error_t loadkernel_return_val[MAX_TEST_DISKS];
uint8_t external_expected[MAX_TEST_DISKS];
/* outputs from test */
uint32_t expected_recovery_request_val;
const char *expected_to_find_disk;
const char *expected_to_load_disk;
uint32_t expected_return_val;
} test_case_t;
/****************************************************************************/
/* Test cases */
static const char pickme[] = "correct choice";
#define DONT_CARE ((const char *)42)
test_case_t test[] = {
{
.name = "first drive (removable)",
.want_flags = VB_DISK_FLAG_REMOVABLE | VB_DISK_FLAG_FIXED,
.disks_to_provide = {
{4096, 100, VB_DISK_FLAG_REMOVABLE, pickme},
{4096, 100, VB_DISK_FLAG_FIXED, "holygrail"},
},
.disk_count_to_return = DEFAULT_COUNT,
.diskgetinfo_return_val = VB2_SUCCESS,
.loadkernel_return_val = {0},
.external_expected = {0},
.expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED,
.expected_to_find_disk = pickme,
.expected_to_load_disk = pickme,
.expected_return_val = VB2_SUCCESS
},
{
.name = "first drive (fixed)",
.want_flags = VB_DISK_FLAG_REMOVABLE | VB_DISK_FLAG_FIXED,
.disks_to_provide = {
{4096, 100, VB_DISK_FLAG_FIXED, pickme},
{4096, 100, VB_DISK_FLAG_REMOVABLE, "holygrail"},
},
.disk_count_to_return = DEFAULT_COUNT,
.diskgetinfo_return_val = VB2_SUCCESS,
.loadkernel_return_val = {0},
.external_expected = {0},
.expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED,
.expected_to_find_disk = pickme,
.expected_to_load_disk = pickme,
.expected_return_val = VB2_SUCCESS
},
{
.name = "first removable drive",
.want_flags = VB_DISK_FLAG_REMOVABLE,
.disks_to_provide = {
/* too small */
{512, 10, VB_DISK_FLAG_REMOVABLE, 0},
/* wrong LBA */
{511, 100, VB_DISK_FLAG_REMOVABLE, 0},
/* not a power of 2 */
{2047, 100, VB_DISK_FLAG_REMOVABLE, 0},
/* wrong type */
{512, 100, VB_DISK_FLAG_FIXED, 0},
/* wrong flags */
{512, 100, 0, 0},
/* still wrong flags */
{512, 100, -1, 0},
{4096, 100, VB_DISK_FLAG_REMOVABLE, pickme},
/* already got one */
{512, 100, VB_DISK_FLAG_REMOVABLE, "holygrail"},
},
.disk_count_to_return = DEFAULT_COUNT,
.diskgetinfo_return_val = VB2_SUCCESS,
.loadkernel_return_val = {0},
.external_expected = {0},
.expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED,
.expected_to_find_disk = pickme,
.expected_to_load_disk = pickme,
.expected_return_val = VB2_SUCCESS
},
{
.name = "first removable drive (skip external GPT)",
.want_flags = VB_DISK_FLAG_REMOVABLE,
.disks_to_provide = {
/* too small */
{512, 10, VB_DISK_FLAG_REMOVABLE, 0},
/* wrong LBA */
{511, 100, VB_DISK_FLAG_REMOVABLE, 0},
/* not a power of 2 */
{2047, 100, VB_DISK_FLAG_REMOVABLE, 0},
/* wrong type */
{512, 100, VB_DISK_FLAG_FIXED, 0},
/* wrong flags */
{512, 100, 0, 0},
/* still wrong flags */
{512, 100, -1, 0},
{512, 100,
VB_DISK_FLAG_REMOVABLE | VB_DISK_FLAG_EXTERNAL_GPT,
pickme},
/* already got one */
{512, 100, VB_DISK_FLAG_REMOVABLE, "holygrail"},
},
.disk_count_to_return = DEFAULT_COUNT,
.diskgetinfo_return_val = VB2_SUCCESS,
.loadkernel_return_val = {0, 0},
.external_expected = {1, 0},
.expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED,
.expected_to_find_disk = pickme,
.expected_to_load_disk = pickme,
.expected_return_val = VB2_SUCCESS
},
{
.name = "second removable drive",
.want_flags = VB_DISK_FLAG_REMOVABLE,
.disks_to_provide = {
/* wrong flags */
{512, 100, 0, 0},
{512, 100, VB_DISK_FLAG_REMOVABLE, "not yet"},
{512, 100, VB_DISK_FLAG_REMOVABLE, pickme},
},
.disk_count_to_return = DEFAULT_COUNT,
.diskgetinfo_return_val = VB2_SUCCESS,
.loadkernel_return_val = {VB2_ERROR_LK_INVALID_KERNEL_FOUND, 0},
.expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED,
.expected_to_find_disk = pickme,
.expected_to_load_disk = pickme,
.expected_return_val = VB2_SUCCESS
},
{
.name = "first fixed drive",
.want_flags = VB_DISK_FLAG_FIXED,
.disks_to_provide = {
/* too small */
{512, 10, VB_DISK_FLAG_FIXED, 0},
/* wrong LBA */
{511, 100, VB_DISK_FLAG_FIXED, 0},
/* not a power of 2 */
{2047, 100, VB_DISK_FLAG_REMOVABLE, 0},
/* wrong type */
{512, 100, VB_DISK_FLAG_REMOVABLE, 0},
/* wrong flags */
{512, 100, 0, 0},
/* still wrong flags */
{512, 100, -1, 0},
/* flags */
{512, 100, VB_DISK_FLAG_REMOVABLE|VB_DISK_FLAG_FIXED,
0},
{512, 100, VB_DISK_FLAG_FIXED, pickme},
/* already got one */
{512, 100, VB_DISK_FLAG_FIXED, "holygrail"},
},
.disk_count_to_return = DEFAULT_COUNT,
.diskgetinfo_return_val = VB2_SUCCESS,
.loadkernel_return_val = {0},
.expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED,
.expected_to_find_disk = pickme,
.expected_to_load_disk = pickme,
.expected_return_val = VB2_SUCCESS
},
{
.name = "no drives at all",
.want_flags = VB_DISK_FLAG_FIXED,
.disks_to_provide = {},
.disk_count_to_return = DEFAULT_COUNT,
.diskgetinfo_return_val = VB2_SUCCESS,
.expected_recovery_request_val = VB2_RECOVERY_RW_NO_DISK,
.expected_to_find_disk = 0,
.expected_to_load_disk = 0,
.expected_return_val = VB2_ERROR_LK_NO_DISK_FOUND
},
{
.name = "VbExDiskGetInfo() error",
.want_flags = VB_DISK_FLAG_FIXED,
.disks_to_provide = {
{512, 10, VB_DISK_FLAG_REMOVABLE, 0},
{512, 100, VB_DISK_FLAG_FIXED, 0},
},
.disk_count_to_return = DEFAULT_COUNT,
.diskgetinfo_return_val = VB2_ERROR_UNKNOWN,
.expected_recovery_request_val = VB2_RECOVERY_RW_NO_DISK,
.expected_to_find_disk = 0,
.expected_to_load_disk = 0,
.expected_return_val = VB2_ERROR_LK_NO_DISK_FOUND,
},
{
.name = "invalid kernel",
.want_flags = VB_DISK_FLAG_FIXED,
.disks_to_provide = {
/* too small */
{512, 10, VB_DISK_FLAG_FIXED, 0},
/* wrong LBA */
{511, 100, VB_DISK_FLAG_FIXED, 0},
/* not a power of 2 */
{2047, 100, VB_DISK_FLAG_FIXED, 0},
/* wrong type */
{512, 100, VB_DISK_FLAG_REMOVABLE, 0},
/* wrong flags */
{512, 100, 0, 0},
/* still wrong flags */
{512, 100, -1, 0},
/* doesn't load */
{512, 100, VB_DISK_FLAG_FIXED, "corrupted kernel"},
/* doesn't load */
{512, 100, VB_DISK_FLAG_FIXED, "stateful partition"},
},
.disk_count_to_return = DEFAULT_COUNT,
.diskgetinfo_return_val = VB2_SUCCESS,
.loadkernel_return_val = {VB2_ERROR_LK_INVALID_KERNEL_FOUND,
VB2_ERROR_LK_NO_KERNEL_FOUND},
.expected_recovery_request_val = VB2_RECOVERY_RW_INVALID_OS,
.expected_to_find_disk = DONT_CARE,
.expected_to_load_disk = 0,
.expected_return_val = VB2_ERROR_LK_INVALID_KERNEL_FOUND,
},
{
.name = "invalid kernel, order flipped",
.want_flags = VB_DISK_FLAG_FIXED,
.disks_to_provide = {
{512, 1000, VB_DISK_FLAG_FIXED, "stateful partition"},
{512, 1000, VB_DISK_FLAG_FIXED, "corrupted kernel"},
},
.disk_count_to_return = DEFAULT_COUNT,
.diskgetinfo_return_val = VB2_SUCCESS,
.loadkernel_return_val = {VB2_ERROR_LK_NO_KERNEL_FOUND,
VB2_ERROR_LK_INVALID_KERNEL_FOUND},
.expected_recovery_request_val = VB2_RECOVERY_RW_INVALID_OS,
.expected_to_find_disk = DONT_CARE,
.expected_to_load_disk = 0,
.expected_return_val = VB2_ERROR_LK_INVALID_KERNEL_FOUND,
},
{
.name = "no Chrome OS partitions",
.want_flags = VB_DISK_FLAG_FIXED,
.disks_to_provide = {
{512, 100, VB_DISK_FLAG_FIXED, "stateful partition"},
{512, 1000, VB_DISK_FLAG_FIXED, "Chrubuntu"},
},
.disk_count_to_return = DEFAULT_COUNT,
.diskgetinfo_return_val = VB2_SUCCESS,
.loadkernel_return_val = {VB2_ERROR_LK_NO_KERNEL_FOUND,
VB2_ERROR_LK_NO_KERNEL_FOUND},
.expected_recovery_request_val = VB2_RECOVERY_RW_NO_KERNEL,
.expected_to_find_disk = DONT_CARE,
.expected_to_load_disk = 0,
.expected_return_val = VB2_ERROR_LK_NO_KERNEL_FOUND,
},
{
.name = "invalid kernel (removable)",
.want_flags = VB_DISK_FLAG_REMOVABLE,
.disks_to_provide = {
{512, 100, VB_DISK_FLAG_REMOVABLE, "corrupted"},
{512, 100, VB_DISK_FLAG_REMOVABLE, "data"},
},
.disk_count_to_return = DEFAULT_COUNT,
.diskgetinfo_return_val = VB2_SUCCESS,
.loadkernel_return_val = {VB2_ERROR_LK_INVALID_KERNEL_FOUND,
VB2_ERROR_LK_NO_KERNEL_FOUND},
.expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED,
.expected_to_find_disk = DONT_CARE,
.expected_to_load_disk = 0,
.expected_return_val = VB2_ERROR_LK_INVALID_KERNEL_FOUND,
},
{
.name = "no kernel (removable)",
.want_flags = VB_DISK_FLAG_REMOVABLE,
.disks_to_provide = {
{512, 100, VB_DISK_FLAG_REMOVABLE, "data"},
},
.disk_count_to_return = DEFAULT_COUNT,
.diskgetinfo_return_val = VB2_SUCCESS,
.loadkernel_return_val = {VB2_ERROR_LK_NO_KERNEL_FOUND},
.expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED,
.expected_to_find_disk = DONT_CARE,
.expected_to_load_disk = 0,
.expected_return_val = VB2_ERROR_LK_NO_KERNEL_FOUND,
},
};
/****************************************************************************/
/* Mock data */
static VbDiskInfo mock_disks[MAX_TEST_DISKS];
static test_case_t *t;
static int load_kernel_calls;
static uint32_t got_recovery_request_val;
static const char *got_find_disk;
static const char *got_load_disk;
static uint32_t got_return_val;
static uint32_t got_external_mismatch;
static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]
__attribute__((aligned(VB2_WORKBUF_ALIGN)));
static struct vb2_context *ctx;
/**
* Reset mock data (for use before each test)
*/
static void ResetMocks(int i)
{
TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx),
"vb2api_init failed");
memset(VbApiKernelGetParams(), 0, sizeof(VbSelectAndLoadKernelParams));
memset(&mock_disks, 0, sizeof(mock_disks));
load_kernel_calls = 0;
got_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED;
got_find_disk = 0;
got_load_disk = 0;
got_return_val = 0xdeadbeef;
t = test + i;
}
static int is_nonzero(const void *vptr, size_t count)
{
const char *p = (const char *)vptr;
while (count--)
if (*p++)
return 1;
return 0;
}
/****************************************************************************/
/* Mocked verification functions */
vb2_error_t VbExDiskGetInfo(VbDiskInfo **infos_ptr, uint32_t *count,
uint32_t disk_flags)
{
int i;
int num_disks = 0;
VB2_DEBUG("My %s\n", __FUNCTION__);
*infos_ptr = mock_disks;
for(i = 0; i < MAX_TEST_DISKS; i++) {
if (is_nonzero(&t->disks_to_provide[i],
sizeof(t->disks_to_provide[i]))) {
mock_disks[num_disks].bytes_per_lba =
t->disks_to_provide[i].bytes_per_lba;
mock_disks[num_disks].lba_count =
mock_disks[num_disks].streaming_lba_count =
t->disks_to_provide[i].lba_count;
mock_disks[num_disks].flags =
t->disks_to_provide[i].flags;
mock_disks[num_disks].handle = (VbExDiskHandle_t)
t->disks_to_provide[i].diskname;
VB2_DEBUG(" mock_disk[%d] %" PRIu64 " %" PRIu64
" %#x %s\n", i,
mock_disks[num_disks].bytes_per_lba,
mock_disks[num_disks].lba_count,
mock_disks[num_disks].flags,
(mock_disks[num_disks].handle
? (char *)mock_disks[num_disks].handle
: "0"));
num_disks++;
} else {
mock_disks[num_disks].handle =
(VbExDiskHandle_t)"INVALID";
}
}
if (t->disk_count_to_return >= 0)
*count = t->disk_count_to_return;
else
*count = num_disks;
VB2_DEBUG(" *count=%" PRIu32 "\n", *count);
VB2_DEBUG(" return %#x\n", t->diskgetinfo_return_val);
return t->diskgetinfo_return_val;
}
vb2_error_t VbExDiskFreeInfo(VbDiskInfo *infos,
VbExDiskHandle_t preserve_handle)
{
got_load_disk = (const char *)preserve_handle;
VB2_DEBUG("%s(): got_load_disk = %s\n", __FUNCTION__,
got_load_disk ? got_load_disk : "0");
return VB2_SUCCESS;
}
vb2_error_t LoadKernel(struct vb2_context *c,
VbSelectAndLoadKernelParams *params,
VbDiskInfo *disk_info)
{
got_find_disk = (const char *)params->disk_handle;
VB2_DEBUG("%s(%d): got_find_disk = %s\n", __FUNCTION__,
load_kernel_calls,
got_find_disk ? got_find_disk : "0");
if (t->external_expected[load_kernel_calls] !=
!!(disk_info->flags & VB_DISK_FLAG_EXTERNAL_GPT))
got_external_mismatch++;
return t->loadkernel_return_val[load_kernel_calls++];
}
void vb2_nv_set(struct vb2_context *c,
enum vb2_nv_param param,
uint32_t value)
{
if (param != VB2_NV_RECOVERY_REQUEST)
return;
VB2_DEBUG("%s(): got_recovery_request_val = %d (%#x)\n", __FUNCTION__,
value, value);
got_recovery_request_val = value;
}
/****************************************************************************/
static void VbTryLoadKernelTest(void)
{
int i;
int num_tests = sizeof(test) / sizeof(test[0]);
for (i = 0; i < num_tests; i++) {
printf("Test case: %s ...\n", test[i].name);
ResetMocks(i);
TEST_EQ(VbTryLoadKernel(ctx, test[i].want_flags),
t->expected_return_val, " return value");
TEST_EQ(got_recovery_request_val,
t->expected_recovery_request_val, " recovery_request");
if (t->expected_to_find_disk != DONT_CARE) {
TEST_PTR_EQ(got_find_disk, t->expected_to_find_disk,
" find disk");
TEST_PTR_EQ(got_load_disk, t->expected_to_load_disk,
" load disk");
}
TEST_EQ(got_external_mismatch, 0, " external GPT errors");
}
}
int main(void)
{
VbTryLoadKernelTest();
return gTestSuccess ? 0 : 255;
}