mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-18 13:11:31 +00:00
Merge branch '2019-07-24-master-imports'
- Various Android related changes including A/B update and BCB updates - Assorted minor fixes
This commit is contained in:
commit
a9aa4c5700
35 changed files with 954 additions and 114 deletions
1
Documentation/.gitignore
vendored
1
Documentation/.gitignore
vendored
|
@ -1,2 +1 @@
|
|||
output
|
||||
*.pyc
|
||||
|
|
|
@ -276,7 +276,7 @@ int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc,
|
|||
return ARM_PSCI_RET_SUCCESS;
|
||||
}
|
||||
|
||||
void __secure psci_cpu_off(void)
|
||||
s32 __secure psci_cpu_off(void)
|
||||
{
|
||||
psci_cpu_off_common();
|
||||
|
||||
|
|
|
@ -516,6 +516,21 @@ enum {
|
|||
*/
|
||||
void mmu_page_table_flush(unsigned long start, unsigned long stop);
|
||||
|
||||
#ifdef CONFIG_ARMV7_PSCI
|
||||
void psci_arch_cpu_entry(void);
|
||||
u32 psci_version(void);
|
||||
s32 psci_features(u32 function_id, u32 psci_fid);
|
||||
s32 psci_cpu_off(void);
|
||||
s32 psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc,
|
||||
u32 context_id);
|
||||
s32 psci_affinity_info(u32 function_id, u32 target_affinity,
|
||||
u32 lowest_affinity_level);
|
||||
u32 psci_migrate_info_type(void);
|
||||
void psci_system_off(void);
|
||||
void psci_system_reset(void);
|
||||
s32 psci_features(u32 function_id, u32 psci_fid);
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#define arch_align_stack(x) (x)
|
||||
|
|
|
@ -298,7 +298,7 @@ __secure s32 psci_affinity_info(u32 __always_unused function_id,
|
|||
return psci_state[cpu];
|
||||
}
|
||||
|
||||
__secure s32 psci_migrate_info_type(u32 function_id)
|
||||
__secure u32 psci_migrate_info_type(void)
|
||||
{
|
||||
/* Trusted OS is either not present or does not require migration */
|
||||
return 2;
|
||||
|
|
|
@ -30,7 +30,7 @@ u8 psci_state[STM32MP1_PSCI_NR_CPUS] __secure_data = {
|
|||
PSCI_AFFINITY_LEVEL_ON,
|
||||
PSCI_AFFINITY_LEVEL_OFF};
|
||||
|
||||
void __secure psci_set_state(int cpu, u8 state)
|
||||
static inline void psci_set_state(int cpu, u8 state)
|
||||
{
|
||||
psci_state[cpu] = state;
|
||||
dsb();
|
||||
|
@ -67,7 +67,7 @@ void __secure psci_arch_cpu_entry(void)
|
|||
writel(0xFFFFFFFF, TAMP_BACKUP_MAGIC_NUMBER);
|
||||
}
|
||||
|
||||
int __secure psci_features(u32 function_id, u32 psci_fid)
|
||||
s32 __secure psci_features(u32 function_id, u32 psci_fid)
|
||||
{
|
||||
switch (psci_fid) {
|
||||
case ARM_PSCI_0_2_FN_PSCI_VERSION:
|
||||
|
@ -82,12 +82,12 @@ int __secure psci_features(u32 function_id, u32 psci_fid)
|
|||
return ARM_PSCI_RET_NI;
|
||||
}
|
||||
|
||||
unsigned int __secure psci_version(u32 function_id)
|
||||
u32 __secure psci_version(void)
|
||||
{
|
||||
return ARM_PSCI_VER_1_0;
|
||||
}
|
||||
|
||||
int __secure psci_affinity_info(u32 function_id, u32 target_affinity,
|
||||
s32 __secure psci_affinity_info(u32 function_id, u32 target_affinity,
|
||||
u32 lowest_affinity_level)
|
||||
{
|
||||
u32 cpu = target_affinity & MPIDR_AFF0;
|
||||
|
@ -104,7 +104,7 @@ int __secure psci_affinity_info(u32 function_id, u32 target_affinity,
|
|||
return psci_state[cpu];
|
||||
}
|
||||
|
||||
int __secure psci_migrate_info_type(u32 function_id)
|
||||
u32 __secure psci_migrate_info_type(void)
|
||||
{
|
||||
/*
|
||||
* in Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf
|
||||
|
@ -116,7 +116,7 @@ int __secure psci_migrate_info_type(u32 function_id)
|
|||
return 2;
|
||||
}
|
||||
|
||||
int __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc,
|
||||
s32 __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc,
|
||||
u32 context_id)
|
||||
{
|
||||
u32 cpu = target_cpu & MPIDR_AFF0;
|
||||
|
@ -161,7 +161,7 @@ int __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc,
|
|||
return ARM_PSCI_RET_SUCCESS;
|
||||
}
|
||||
|
||||
int __secure psci_cpu_off(u32 function_id)
|
||||
s32 __secure psci_cpu_off(void)
|
||||
{
|
||||
u32 cpu;
|
||||
|
||||
|
@ -181,7 +181,7 @@ int __secure psci_cpu_off(u32 function_id)
|
|||
wfi();
|
||||
}
|
||||
|
||||
void __secure psci_system_reset(u32 function_id)
|
||||
void __secure psci_system_reset(void)
|
||||
{
|
||||
/* System reset */
|
||||
writel(RCC_MP_GRSTCSETR_MPSYSRST, RCC_MP_GRSTCSETR);
|
||||
|
@ -190,7 +190,7 @@ void __secure psci_system_reset(u32 function_id)
|
|||
wfi();
|
||||
}
|
||||
|
||||
void __secure psci_system_off(u32 function_id)
|
||||
void __secure psci_system_off(void)
|
||||
{
|
||||
/* System Off is not managed, waiting user power off
|
||||
* TODO: handle I2C write in PMIC Main Control register bit 0 = SWOFF
|
||||
|
|
|
@ -130,7 +130,7 @@ void psci_arch_init(void)
|
|||
|
||||
u32 uniphier_psci_holding_pen_release __secure_data = 0xffffffff;
|
||||
|
||||
int __secure psci_cpu_on(u32 function_id, u32 cpuid, u32 entry_point,
|
||||
s32 __secure psci_cpu_on(u32 function_id, u32 cpuid, u32 entry_point,
|
||||
u32 context_id)
|
||||
{
|
||||
u32 cpu = cpuid & 0xff;
|
||||
|
@ -155,7 +155,7 @@ int __secure psci_cpu_on(u32 function_id, u32 cpuid, u32 entry_point,
|
|||
return PSCI_RET_SUCCESS;
|
||||
}
|
||||
|
||||
void __secure psci_system_reset(u32 function_id)
|
||||
void __secure psci_system_reset(void)
|
||||
{
|
||||
reset_cpu(0);
|
||||
}
|
||||
|
|
17
cmd/Kconfig
17
cmd/Kconfig
|
@ -735,7 +735,7 @@ config CMD_FASTBOOT
|
|||
Android devices. Fastboot requires either the network stack
|
||||
enabled or support for acting as a USB device.
|
||||
|
||||
See doc/README.android-fastboot for more information.
|
||||
See doc/android/fastboot.txt for more information.
|
||||
|
||||
config CMD_FDC
|
||||
bool "fdcboot - Boot from floppy device"
|
||||
|
@ -1198,6 +1198,21 @@ config CMD_SETEXPR
|
|||
|
||||
endmenu
|
||||
|
||||
menu "Android support commands"
|
||||
|
||||
config CMD_AB_SELECT
|
||||
bool "ab_select"
|
||||
default n
|
||||
depends on ANDROID_AB
|
||||
help
|
||||
On Android devices with more than one boot slot (multiple copies of
|
||||
the kernel and system images) this provides a command to select which
|
||||
slot should be used to boot from and register the boot attempt. This
|
||||
is used by the new A/B update model where one slot is updated in the
|
||||
background while running from the other slot.
|
||||
|
||||
endmenu
|
||||
|
||||
if NET
|
||||
|
||||
menuconfig CMD_NET
|
||||
|
|
|
@ -12,6 +12,7 @@ obj-y += version.o
|
|||
|
||||
# command
|
||||
obj-$(CONFIG_CMD_AES) += aes.o
|
||||
obj-$(CONFIG_CMD_AB_SELECT) += ab_select.o
|
||||
obj-$(CONFIG_CMD_ADC) += adc.o
|
||||
obj-$(CONFIG_CMD_ARMFLASH) += armflash.o
|
||||
obj-y += blk_common.o
|
||||
|
|
52
cmd/ab_select.c
Normal file
52
cmd/ab_select.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*/
|
||||
|
||||
#include <android_ab.h>
|
||||
#include <command.h>
|
||||
|
||||
static int do_ab_select(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
int ret;
|
||||
struct blk_desc *dev_desc;
|
||||
disk_partition_t part_info;
|
||||
char slot[2];
|
||||
|
||||
if (argc != 4)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
/* Lookup the "misc" partition from argv[2] and argv[3] */
|
||||
if (part_get_info_by_dev_and_name_or_num(argv[2], argv[3],
|
||||
&dev_desc, &part_info) < 0) {
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
ret = ab_select_slot(dev_desc, &part_info);
|
||||
if (ret < 0) {
|
||||
printf("Android boot failed, error %d.\n", ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
/* Android standard slot names are 'a', 'b', ... */
|
||||
slot[0] = BOOT_SLOT_NAME(ret);
|
||||
slot[1] = '\0';
|
||||
env_set(argv[1], slot);
|
||||
printf("ANDROID: Booting slot: %s\n", slot);
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(ab_select, 4, 0, do_ab_select,
|
||||
"Select the slot used to boot from and register the boot attempt.",
|
||||
"<slot_var_name> <interface> <dev[:part|#part_name]>\n"
|
||||
" - Load the slot metadata from the partition 'part' on\n"
|
||||
" device type 'interface' instance 'dev' and store the active\n"
|
||||
" slot in the 'slot_var_name' variable. This also updates the\n"
|
||||
" Android slot metadata with a boot attempt, which can cause\n"
|
||||
" successive calls to this function to return a different result\n"
|
||||
" if the returned slot runs out of boot attempts.\n"
|
||||
" - If 'part_name' is passed, preceded with a # instead of :, the\n"
|
||||
" partition name whose label is 'part_name' will be looked up in\n"
|
||||
" the partition table. This is commonly the \"misc\" partition.\n"
|
||||
);
|
68
cmd/bcb.c
68
cmd/bcb.c
|
@ -24,17 +24,17 @@ static struct bootloader_message bcb = { { 0 } };
|
|||
|
||||
static int bcb_cmd_get(char *cmd)
|
||||
{
|
||||
if (!strncmp(cmd, "load", sizeof("load")))
|
||||
if (!strcmp(cmd, "load"))
|
||||
return BCB_CMD_LOAD;
|
||||
if (!strncmp(cmd, "set", sizeof("set")))
|
||||
if (!strcmp(cmd, "set"))
|
||||
return BCB_CMD_FIELD_SET;
|
||||
if (!strncmp(cmd, "clear", sizeof("clear")))
|
||||
if (!strcmp(cmd, "clear"))
|
||||
return BCB_CMD_FIELD_CLEAR;
|
||||
if (!strncmp(cmd, "test", sizeof("test")))
|
||||
if (!strcmp(cmd, "test"))
|
||||
return BCB_CMD_FIELD_TEST;
|
||||
if (!strncmp(cmd, "store", sizeof("store")))
|
||||
if (!strcmp(cmd, "store"))
|
||||
return BCB_CMD_STORE;
|
||||
if (!strncmp(cmd, "dump", sizeof("dump")))
|
||||
if (!strcmp(cmd, "dump"))
|
||||
return BCB_CMD_FIELD_DUMP;
|
||||
else
|
||||
return -1;
|
||||
|
@ -46,9 +46,6 @@ static int bcb_is_misused(int argc, char *const argv[])
|
|||
|
||||
switch (cmd) {
|
||||
case BCB_CMD_LOAD:
|
||||
if (argc != 3)
|
||||
goto err;
|
||||
break;
|
||||
case BCB_CMD_FIELD_SET:
|
||||
if (argc != 3)
|
||||
goto err;
|
||||
|
@ -86,23 +83,23 @@ err:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int bcb_field_get(char *name, char **field, int *size)
|
||||
static int bcb_field_get(char *name, char **fieldp, int *sizep)
|
||||
{
|
||||
if (!strncmp(name, "command", sizeof("command"))) {
|
||||
*field = bcb.command;
|
||||
*size = sizeof(bcb.command);
|
||||
} else if (!strncmp(name, "status", sizeof("status"))) {
|
||||
*field = bcb.status;
|
||||
*size = sizeof(bcb.status);
|
||||
} else if (!strncmp(name, "recovery", sizeof("recovery"))) {
|
||||
*field = bcb.recovery;
|
||||
*size = sizeof(bcb.recovery);
|
||||
} else if (!strncmp(name, "stage", sizeof("stage"))) {
|
||||
*field = bcb.stage;
|
||||
*size = sizeof(bcb.stage);
|
||||
} else if (!strncmp(name, "reserved", sizeof("reserved"))) {
|
||||
*field = bcb.reserved;
|
||||
*size = sizeof(bcb.reserved);
|
||||
if (!strcmp(name, "command")) {
|
||||
*fieldp = bcb.command;
|
||||
*sizep = sizeof(bcb.command);
|
||||
} else if (!strcmp(name, "status")) {
|
||||
*fieldp = bcb.status;
|
||||
*sizep = sizeof(bcb.status);
|
||||
} else if (!strcmp(name, "recovery")) {
|
||||
*fieldp = bcb.recovery;
|
||||
*sizep = sizeof(bcb.recovery);
|
||||
} else if (!strcmp(name, "stage")) {
|
||||
*fieldp = bcb.stage;
|
||||
*sizep = sizeof(bcb.stage);
|
||||
} else if (!strcmp(name, "reserved")) {
|
||||
*fieldp = bcb.reserved;
|
||||
*sizep = sizeof(bcb.reserved);
|
||||
} else {
|
||||
printf("Error: Unknown bcb field '%s'\n", name);
|
||||
return -1;
|
||||
|
@ -111,8 +108,8 @@ static int bcb_field_get(char *name, char **field, int *size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_bcb_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
static int do_bcb_load(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
struct blk_desc *desc;
|
||||
disk_partition_t info;
|
||||
|
@ -122,28 +119,28 @@ do_bcb_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|||
|
||||
ret = blk_get_device_by_str("mmc", argv[1], &desc);
|
||||
if (ret < 0)
|
||||
goto err_1;
|
||||
goto err_read_fail;
|
||||
|
||||
part = simple_strtoul(argv[2], &endp, 0);
|
||||
if (*endp == '\0') {
|
||||
ret = part_get_info(desc, part, &info);
|
||||
if (ret)
|
||||
goto err_1;
|
||||
goto err_read_fail;
|
||||
} else {
|
||||
part = part_get_info_by_name(desc, argv[2], &info);
|
||||
if (part < 0) {
|
||||
ret = part;
|
||||
goto err_1;
|
||||
goto err_read_fail;
|
||||
}
|
||||
}
|
||||
|
||||
cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), info.blksz);
|
||||
if (cnt > info.size)
|
||||
goto err_2;
|
||||
goto err_too_small;
|
||||
|
||||
if (blk_dread(desc, info.start, cnt, &bcb) != cnt) {
|
||||
ret = -EIO;
|
||||
goto err_1;
|
||||
goto err_read_fail;
|
||||
}
|
||||
|
||||
bcb_dev = desc->devnum;
|
||||
|
@ -151,10 +148,10 @@ do_bcb_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|||
debug("%s: Loaded from mmc %d:%d\n", __func__, bcb_dev, bcb_part);
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
err_1:
|
||||
err_read_fail:
|
||||
printf("Error: mmc %s:%s read failed (%d)\n", argv[1], argv[2], ret);
|
||||
goto err;
|
||||
err_2:
|
||||
err_too_small:
|
||||
printf("Error: mmc %s:%s too small!", argv[1], argv[2]);
|
||||
goto err;
|
||||
err:
|
||||
|
@ -307,7 +304,8 @@ static int do_bcb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
|||
return CMD_RET_USAGE;
|
||||
|
||||
if (bcb_is_misused(argc, argv)) {
|
||||
/* We try to improve the user experience by reporting the
|
||||
/*
|
||||
* We try to improve the user experience by reporting the
|
||||
* root-cause of misusage, so don't return CMD_RET_USAGE,
|
||||
* since the latter prints out the full-blown help text
|
||||
*/
|
||||
|
|
16
cmd/part.c
16
cmd/part.c
|
@ -24,6 +24,7 @@
|
|||
enum cmd_part_info {
|
||||
CMD_PART_INFO_START = 0,
|
||||
CMD_PART_INFO_SIZE,
|
||||
CMD_PART_INFO_NUMBER
|
||||
};
|
||||
|
||||
static int do_part_uuid(int argc, char * const argv[])
|
||||
|
@ -149,6 +150,9 @@ static int do_part_info(int argc, char * const argv[], enum cmd_part_info param)
|
|||
case CMD_PART_INFO_SIZE:
|
||||
snprintf(buf, sizeof(buf), LBAF, info.size);
|
||||
break;
|
||||
case CMD_PART_INFO_NUMBER:
|
||||
snprintf(buf, sizeof(buf), "%d", part);
|
||||
break;
|
||||
default:
|
||||
printf("** Unknown cmd_part_info value: %d\n", param);
|
||||
return 1;
|
||||
|
@ -172,6 +176,11 @@ static int do_part_size(int argc, char * const argv[])
|
|||
return do_part_info(argc, argv, CMD_PART_INFO_SIZE);
|
||||
}
|
||||
|
||||
static int do_part_number(int argc, char * const argv[])
|
||||
{
|
||||
return do_part_info(argc, argv, CMD_PART_INFO_NUMBER);
|
||||
}
|
||||
|
||||
static int do_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
|
@ -185,6 +194,8 @@ static int do_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|||
return do_part_start(argc - 2, argv + 2);
|
||||
else if (!strcmp(argv[1], "size"))
|
||||
return do_part_size(argc - 2, argv + 2);
|
||||
else if (!strcmp(argv[1], "number"))
|
||||
return do_part_number(argc - 2, argv + 2);
|
||||
|
||||
return CMD_RET_USAGE;
|
||||
}
|
||||
|
@ -206,5 +217,8 @@ U_BOOT_CMD(
|
|||
" part can be either partition number or partition name\n"
|
||||
"part size <interface> <dev> <part> <varname>\n"
|
||||
" - set environment variable to the size of the partition (in blocks)\n"
|
||||
" part can be either partition number or partition name"
|
||||
" part can be either partition number or partition name\n"
|
||||
"part number <interface> <dev> <part> <varname>\n"
|
||||
" - set environment variable to the partition number using the partition name\n"
|
||||
" part must be specified as partition name"
|
||||
);
|
||||
|
|
|
@ -821,6 +821,16 @@ config UPDATE_TFTP_MSEC_MAX
|
|||
default 100
|
||||
depends on UPDATE_TFTP
|
||||
|
||||
config ANDROID_AB
|
||||
bool "Android A/B updates"
|
||||
default n
|
||||
help
|
||||
If enabled, adds support for the new Android A/B update model. This
|
||||
allows the bootloader to select which slot to boot from based on the
|
||||
information provided by userspace via the Android boot_ctrl HAL. This
|
||||
allows a bootloader to try a new version of the system but roll back
|
||||
to previous version if the new one didn't boot all the way.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Blob list"
|
||||
|
|
|
@ -107,6 +107,7 @@ endif
|
|||
endif
|
||||
|
||||
obj-y += image.o
|
||||
obj-$(CONFIG_ANDROID_AB) += android_ab.o
|
||||
obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
|
||||
obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o
|
||||
obj-$(CONFIG_$(SPL_TPL_)FIT) += image-fit.o
|
||||
|
|
300
common/android_ab.c
Normal file
300
common/android_ab.c
Normal file
|
@ -0,0 +1,300 @@
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <android_ab.h>
|
||||
#include <android_bootloader_message.h>
|
||||
#include <linux/err.h>
|
||||
#include <memalign.h>
|
||||
#include <u-boot/crc.h>
|
||||
|
||||
/**
|
||||
* Compute the CRC-32 of the bootloader control struct.
|
||||
*
|
||||
* Only the bytes up to the crc32_le field are considered for the CRC-32
|
||||
* calculation.
|
||||
*
|
||||
* @param[in] abc bootloader control block
|
||||
*
|
||||
* @return crc32 sum
|
||||
*/
|
||||
static uint32_t ab_control_compute_crc(struct bootloader_control *abc)
|
||||
{
|
||||
return crc32(0, (void *)abc, offsetof(typeof(*abc), crc32_le));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize bootloader_control to the default value.
|
||||
*
|
||||
* It allows us to boot all slots in order from the first one. This value
|
||||
* should be used when the bootloader message is corrupted, but not when
|
||||
* a valid message indicates that all slots are unbootable.
|
||||
*
|
||||
* @param[in] abc bootloader control block
|
||||
*
|
||||
* @return 0 on success and a negative on error
|
||||
*/
|
||||
static int ab_control_default(struct bootloader_control *abc)
|
||||
{
|
||||
int i;
|
||||
const struct slot_metadata metadata = {
|
||||
.priority = 15,
|
||||
.tries_remaining = 7,
|
||||
.successful_boot = 0,
|
||||
.verity_corrupted = 0,
|
||||
.reserved = 0
|
||||
};
|
||||
|
||||
if (!abc)
|
||||
return -EFAULT;
|
||||
|
||||
memcpy(abc->slot_suffix, "a\0\0\0", 4);
|
||||
abc->magic = BOOT_CTRL_MAGIC;
|
||||
abc->version = BOOT_CTRL_VERSION;
|
||||
abc->nb_slot = NUM_SLOTS;
|
||||
memset(abc->reserved0, 0, sizeof(abc->reserved0));
|
||||
for (i = 0; i < abc->nb_slot; ++i)
|
||||
abc->slot_info[i] = metadata;
|
||||
|
||||
memset(abc->reserved1, 0, sizeof(abc->reserved1));
|
||||
abc->crc32_le = ab_control_compute_crc(abc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the boot_control struct from disk into newly allocated memory.
|
||||
*
|
||||
* This function allocates and returns an integer number of disk blocks,
|
||||
* based on the block size of the passed device to help performing a
|
||||
* read-modify-write operation on the boot_control struct.
|
||||
* The boot_control struct offset (2 KiB) must be a multiple of the device
|
||||
* block size, for simplicity.
|
||||
*
|
||||
* @param[in] dev_desc Device where to read the boot_control struct from
|
||||
* @param[in] part_info Partition in 'dev_desc' where to read from, normally
|
||||
* the "misc" partition should be used
|
||||
* @param[out] pointer to pointer to bootloader_control data
|
||||
* @return 0 on success and a negative on error
|
||||
*/
|
||||
static int ab_control_create_from_disk(struct blk_desc *dev_desc,
|
||||
const disk_partition_t *part_info,
|
||||
struct bootloader_control **abc)
|
||||
{
|
||||
ulong abc_offset, abc_blocks, ret;
|
||||
|
||||
abc_offset = offsetof(struct bootloader_message_ab, slot_suffix);
|
||||
if (abc_offset % part_info->blksz) {
|
||||
log_err("ANDROID: Boot control block not block aligned.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
abc_offset /= part_info->blksz;
|
||||
|
||||
abc_blocks = DIV_ROUND_UP(sizeof(struct bootloader_control),
|
||||
part_info->blksz);
|
||||
if (abc_offset + abc_blocks > part_info->size) {
|
||||
log_err("ANDROID: boot control partition too small. Need at");
|
||||
log_err(" least %lu blocks but have %lu blocks.\n",
|
||||
abc_offset + abc_blocks, part_info->size);
|
||||
return -EINVAL;
|
||||
}
|
||||
*abc = malloc_cache_aligned(abc_blocks * part_info->blksz);
|
||||
if (!*abc)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = blk_dread(dev_desc, part_info->start + abc_offset, abc_blocks,
|
||||
*abc);
|
||||
if (IS_ERR_VALUE(ret)) {
|
||||
log_err("ANDROID: Could not read from boot ctrl partition\n");
|
||||
free(*abc);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
log_debug("ANDROID: Loaded ABC, %lu blocks\n", abc_blocks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the loaded boot_control block.
|
||||
*
|
||||
* Store back to the same location it was read from with
|
||||
* ab_control_create_from_misc().
|
||||
*
|
||||
* @param[in] dev_desc Device where we should write the boot_control struct
|
||||
* @param[in] part_info Partition on the 'dev_desc' where to write
|
||||
* @param[in] abc Pointer to the boot control struct and the extra bytes after
|
||||
* it up to the nearest block boundary
|
||||
* @return 0 on success and a negative on error
|
||||
*/
|
||||
static int ab_control_store(struct blk_desc *dev_desc,
|
||||
const disk_partition_t *part_info,
|
||||
struct bootloader_control *abc)
|
||||
{
|
||||
ulong abc_offset, abc_blocks, ret;
|
||||
|
||||
abc_offset = offsetof(struct bootloader_message_ab, slot_suffix) /
|
||||
part_info->blksz;
|
||||
abc_blocks = DIV_ROUND_UP(sizeof(struct bootloader_control),
|
||||
part_info->blksz);
|
||||
ret = blk_dwrite(dev_desc, part_info->start + abc_offset, abc_blocks,
|
||||
abc);
|
||||
if (IS_ERR_VALUE(ret)) {
|
||||
log_err("ANDROID: Could not write back the misc partition\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two slots.
|
||||
*
|
||||
* The function determines slot which is should we boot from among the two.
|
||||
*
|
||||
* @param[in] a The first bootable slot metadata
|
||||
* @param[in] b The second bootable slot metadata
|
||||
* @return Negative if the slot "a" is better, positive of the slot "b" is
|
||||
* better or 0 if they are equally good.
|
||||
*/
|
||||
static int ab_compare_slots(const struct slot_metadata *a,
|
||||
const struct slot_metadata *b)
|
||||
{
|
||||
/* Higher priority is better */
|
||||
if (a->priority != b->priority)
|
||||
return b->priority - a->priority;
|
||||
|
||||
/* Higher successful_boot value is better, in case of same priority */
|
||||
if (a->successful_boot != b->successful_boot)
|
||||
return b->successful_boot - a->successful_boot;
|
||||
|
||||
/* Higher tries_remaining is better to ensure round-robin */
|
||||
if (a->tries_remaining != b->tries_remaining)
|
||||
return b->tries_remaining - a->tries_remaining;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ab_select_slot(struct blk_desc *dev_desc, disk_partition_t *part_info)
|
||||
{
|
||||
struct bootloader_control *abc = NULL;
|
||||
u32 crc32_le;
|
||||
int slot, i, ret;
|
||||
bool store_needed = false;
|
||||
char slot_suffix[4];
|
||||
|
||||
ret = ab_control_create_from_disk(dev_desc, part_info, &abc);
|
||||
if (ret < 0) {
|
||||
/*
|
||||
* This condition represents an actual problem with the code or
|
||||
* the board setup, like an invalid partition information.
|
||||
* Signal a repair mode and do not try to boot from either slot.
|
||||
*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
crc32_le = ab_control_compute_crc(abc);
|
||||
if (abc->crc32_le != crc32_le) {
|
||||
log_err("ANDROID: Invalid CRC-32 (expected %.8x, found %.8x),",
|
||||
crc32_le, abc->crc32_le);
|
||||
log_err("re-initializing A/B metadata.\n");
|
||||
|
||||
ret = ab_control_default(abc);
|
||||
if (ret < 0) {
|
||||
free(abc);
|
||||
return -ENODATA;
|
||||
}
|
||||
store_needed = true;
|
||||
}
|
||||
|
||||
if (abc->magic != BOOT_CTRL_MAGIC) {
|
||||
log_err("ANDROID: Unknown A/B metadata: %.8x\n", abc->magic);
|
||||
free(abc);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
if (abc->version > BOOT_CTRL_VERSION) {
|
||||
log_err("ANDROID: Unsupported A/B metadata version: %.8x\n",
|
||||
abc->version);
|
||||
free(abc);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point a valid boot control metadata is stored in abc,
|
||||
* followed by other reserved data in the same block. We select a with
|
||||
* the higher priority slot that
|
||||
* - is not marked as corrupted and
|
||||
* - either has tries_remaining > 0 or successful_boot is true.
|
||||
* If the selected slot has a false successful_boot, we also decrement
|
||||
* the tries_remaining until it eventually becomes unbootable because
|
||||
* tries_remaining reaches 0. This mechanism produces a bootloader
|
||||
* induced rollback, typically right after a failed update.
|
||||
*/
|
||||
|
||||
/* Safety check: limit the number of slots. */
|
||||
if (abc->nb_slot > ARRAY_SIZE(abc->slot_info)) {
|
||||
abc->nb_slot = ARRAY_SIZE(abc->slot_info);
|
||||
store_needed = true;
|
||||
}
|
||||
|
||||
slot = -1;
|
||||
for (i = 0; i < abc->nb_slot; ++i) {
|
||||
if (abc->slot_info[i].verity_corrupted ||
|
||||
!abc->slot_info[i].tries_remaining) {
|
||||
log_debug("ANDROID: unbootable slot %d tries: %d, ",
|
||||
i, abc->slot_info[i].tries_remaining);
|
||||
log_debug("corrupt: %d\n",
|
||||
abc->slot_info[i].verity_corrupted);
|
||||
continue;
|
||||
}
|
||||
log_debug("ANDROID: bootable slot %d pri: %d, tries: %d, ",
|
||||
i, abc->slot_info[i].priority,
|
||||
abc->slot_info[i].tries_remaining);
|
||||
log_debug("corrupt: %d, successful: %d\n",
|
||||
abc->slot_info[i].verity_corrupted,
|
||||
abc->slot_info[i].successful_boot);
|
||||
|
||||
if (slot < 0 ||
|
||||
ab_compare_slots(&abc->slot_info[i],
|
||||
&abc->slot_info[slot]) < 0) {
|
||||
slot = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (slot >= 0 && !abc->slot_info[slot].successful_boot) {
|
||||
log_err("ANDROID: Attempting slot %c, tries remaining %d\n",
|
||||
BOOT_SLOT_NAME(slot),
|
||||
abc->slot_info[slot].tries_remaining);
|
||||
abc->slot_info[slot].tries_remaining--;
|
||||
store_needed = true;
|
||||
}
|
||||
|
||||
if (slot >= 0) {
|
||||
/*
|
||||
* Legacy user-space requires this field to be set in the BCB.
|
||||
* Newer releases load this slot suffix from the command line
|
||||
* or the device tree.
|
||||
*/
|
||||
memset(slot_suffix, 0, sizeof(slot_suffix));
|
||||
slot_suffix[0] = BOOT_SLOT_NAME(slot);
|
||||
if (memcmp(abc->slot_suffix, slot_suffix,
|
||||
sizeof(slot_suffix))) {
|
||||
memcpy(abc->slot_suffix, slot_suffix,
|
||||
sizeof(slot_suffix));
|
||||
store_needed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (store_needed) {
|
||||
abc->crc32_le = ab_control_compute_crc(abc);
|
||||
ab_control_store(dev_desc, part_info, abc);
|
||||
}
|
||||
free(abc);
|
||||
|
||||
if (slot < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return slot;
|
||||
}
|
|
@ -52,6 +52,8 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
|
|||
ulong *os_data, ulong *os_len)
|
||||
{
|
||||
u32 kernel_addr = android_image_get_kernel_addr(hdr);
|
||||
const struct image_header *ihdr = (const struct image_header *)
|
||||
((uintptr_t)hdr + hdr->page_size);
|
||||
|
||||
/*
|
||||
* Not all Android tools use the id field for signing the image with
|
||||
|
@ -93,11 +95,19 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify,
|
|||
env_set("bootargs", newbootargs);
|
||||
|
||||
if (os_data) {
|
||||
*os_data = (ulong)hdr;
|
||||
*os_data += hdr->page_size;
|
||||
if (image_get_magic(ihdr) == IH_MAGIC) {
|
||||
*os_data = image_get_data(ihdr);
|
||||
} else {
|
||||
*os_data = (ulong)hdr;
|
||||
*os_data += hdr->page_size;
|
||||
}
|
||||
}
|
||||
if (os_len) {
|
||||
if (image_get_magic(ihdr) == IH_MAGIC)
|
||||
*os_len = image_get_data_size(ihdr);
|
||||
else
|
||||
*os_len = hdr->kernel_size;
|
||||
}
|
||||
if (os_len)
|
||||
*os_len = hdr->kernel_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -131,7 +141,9 @@ ulong android_image_get_kcomp(const struct andr_img_hdr *hdr)
|
|||
{
|
||||
const void *p = (void *)((uintptr_t)hdr + hdr->page_size);
|
||||
|
||||
if (get_unaligned_le32(p) == LZ4F_MAGIC)
|
||||
if (image_get_magic((image_header_t *)p) == IH_MAGIC)
|
||||
return image_get_comp((image_header_t *)p);
|
||||
else if (get_unaligned_le32(p) == LZ4F_MAGIC)
|
||||
return IH_COMP_LZ4;
|
||||
else
|
||||
return IH_COMP_NONE;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2010-2011 Calxeda, Inc.
|
||||
* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
@ -39,6 +40,7 @@ struct menu {
|
|||
char *(*item_choice)(void *);
|
||||
void *item_choice_data;
|
||||
struct list_head items;
|
||||
int item_cnt;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -271,7 +273,7 @@ int menu_get_choice(struct menu *m, void **choice)
|
|||
if (!m || !choice)
|
||||
return -EINVAL;
|
||||
|
||||
if (!m->prompt)
|
||||
if (!m->prompt || m->item_cnt == 1)
|
||||
return menu_default_choice(m, choice);
|
||||
|
||||
return menu_interactive_choice(m, choice);
|
||||
|
@ -323,6 +325,7 @@ int menu_item_add(struct menu *m, char *item_key, void *item_data)
|
|||
item->data = item_data;
|
||||
|
||||
list_add_tail(&item->list, &m->items);
|
||||
m->item_cnt++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -374,6 +377,7 @@ struct menu *menu_create(char *title, int timeout, int prompt,
|
|||
m->item_data_print = item_data_print;
|
||||
m->item_choice = item_choice;
|
||||
m->item_choice_data = item_choice_data;
|
||||
m->item_cnt = 0;
|
||||
|
||||
if (title) {
|
||||
m->title = strdup(title);
|
||||
|
|
|
@ -918,6 +918,20 @@ config SPL_SATA_SUPPORT
|
|||
expense and power consumption. This enables loading from SATA
|
||||
using a configured device.
|
||||
|
||||
config SPL_SATA_RAW_U_BOOT_USE_SECTOR
|
||||
bool "SATA raw mode: by sector"
|
||||
depends on SPL_SATA_SUPPORT
|
||||
help
|
||||
Use sector number for specifying U-Boot location on SATA disk in
|
||||
raw mode.
|
||||
|
||||
config SPL_SATA_RAW_U_BOOT_SECTOR
|
||||
hex "Sector on the SATA disk to load U-Boot from"
|
||||
depends on SPL_SATA_RAW_U_BOOT_USE_SECTOR
|
||||
help
|
||||
Sector on the SATA disk to load U-Boot from, when the SATA disk is being
|
||||
used in raw mode. Units: SATA disk sectors (1 sector = 512 bytes).
|
||||
|
||||
config SPL_SERIAL_SUPPORT
|
||||
bool "Support serial"
|
||||
select SPL_PRINTF
|
||||
|
|
|
@ -25,6 +25,37 @@
|
|||
#define CONFIG_SPL_FS_LOAD_PAYLOAD_NAME "u-boot.img"
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SPL_SATA_RAW_U_BOOT_SECTOR
|
||||
/* Dummy value to make the compiler happy */
|
||||
#define CONFIG_SPL_SATA_RAW_U_BOOT_SECTOR 0x100
|
||||
#endif
|
||||
|
||||
static int spl_sata_load_image_raw(struct spl_image_info *spl_image,
|
||||
struct blk_desc *stor_dev, unsigned long sector)
|
||||
{
|
||||
struct image_header *header;
|
||||
unsigned long count;
|
||||
u32 image_size_sectors;
|
||||
int ret;
|
||||
|
||||
header = spl_get_load_buffer(-sizeof(*header), stor_dev->blksz);
|
||||
count = blk_dread(stor_dev, sector, 1, header);
|
||||
if (count == 0)
|
||||
return -EIO;
|
||||
|
||||
ret = spl_parse_image_header(spl_image, header);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
image_size_sectors = DIV_ROUND_UP(spl_image->size, stor_dev->blksz);
|
||||
count = blk_dread(stor_dev, sector, image_size_sectors,
|
||||
(void *)spl_image->load_addr);
|
||||
if (count != image_size_sectors)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spl_sata_load_image(struct spl_image_info *spl_image,
|
||||
struct spl_boot_device *bootdev)
|
||||
{
|
||||
|
@ -59,6 +90,9 @@ static int spl_sata_load_image(struct spl_image_info *spl_image,
|
|||
err = spl_load_image_fat(spl_image, stor_dev,
|
||||
CONFIG_SYS_SATA_FAT_BOOT_PARTITION,
|
||||
CONFIG_SPL_FS_LOAD_PAYLOAD_NAME);
|
||||
} else if (IS_ENABLED(CONFIG_SPL_SATA_RAW_U_BOOT_USE_SECTOR)) {
|
||||
err = spl_sata_load_image_raw(spl_image, stor_dev,
|
||||
CONFIG_SPL_SATA_RAW_U_BOOT_SECTOR);
|
||||
}
|
||||
}
|
||||
if (err) {
|
||||
|
|
|
@ -20,6 +20,7 @@ CONFIG_PRE_CON_BUF_ADDR=0xf0000
|
|||
CONFIG_LOG_MAX_LEVEL=6
|
||||
CONFIG_LOG_ERROR_RETURN=y
|
||||
CONFIG_DISPLAY_BOARDINFO_LATE=y
|
||||
CONFIG_ANDROID_AB=y
|
||||
CONFIG_CMD_CPU=y
|
||||
CONFIG_CMD_LICENSE=y
|
||||
CONFIG_CMD_BOOTZ=y
|
||||
|
@ -47,6 +48,7 @@ CONFIG_CMD_REMOTEPROC=y
|
|||
CONFIG_CMD_SPI=y
|
||||
CONFIG_CMD_USB=y
|
||||
CONFIG_CMD_AXI=y
|
||||
CONFIG_CMD_AB_SELECT=y
|
||||
CONFIG_CMD_TFTPPUT=y
|
||||
CONFIG_CMD_TFTPSRV=y
|
||||
CONFIG_CMD_RARP=y
|
||||
|
|
68
disk/part.c
68
disk/part.c
|
@ -674,6 +674,74 @@ int part_get_info_by_name(struct blk_desc *dev_desc, const char *name,
|
|||
return part_get_info_by_name_type(dev_desc, name, info, PART_TYPE_ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get partition info from device number and partition name.
|
||||
*
|
||||
* Parse a device number and partition name string in the form of
|
||||
* "device_num#partition_name", for example "0#misc". If the partition
|
||||
* is found, sets dev_desc and part_info accordingly with the information
|
||||
* of the partition with the given partition_name.
|
||||
*
|
||||
* @param[in] dev_iface Device interface
|
||||
* @param[in] dev_part_str Input string argument, like "0#misc"
|
||||
* @param[out] dev_desc Place to store the device description pointer
|
||||
* @param[out] part_info Place to store the partition information
|
||||
* @return 0 on success, or a negative on error
|
||||
*/
|
||||
static int part_get_info_by_dev_and_name(const char *dev_iface,
|
||||
const char *dev_part_str,
|
||||
struct blk_desc **dev_desc,
|
||||
disk_partition_t *part_info)
|
||||
{
|
||||
char *ep;
|
||||
const char *part_str;
|
||||
int dev_num;
|
||||
|
||||
part_str = strchr(dev_part_str, '#');
|
||||
if (!part_str || part_str == dev_part_str)
|
||||
return -EINVAL;
|
||||
|
||||
dev_num = simple_strtoul(dev_part_str, &ep, 16);
|
||||
if (ep != part_str) {
|
||||
/* Not all the first part before the # was parsed. */
|
||||
return -EINVAL;
|
||||
}
|
||||
part_str++;
|
||||
|
||||
*dev_desc = blk_get_dev(dev_iface, dev_num);
|
||||
if (!*dev_desc) {
|
||||
printf("Could not find %s %d\n", dev_iface, dev_num);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (part_get_info_by_name(*dev_desc, part_str, part_info) < 0) {
|
||||
printf("Could not find \"%s\" partition\n", part_str);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int part_get_info_by_dev_and_name_or_num(const char *dev_iface,
|
||||
const char *dev_part_str,
|
||||
struct blk_desc **dev_desc,
|
||||
disk_partition_t *part_info)
|
||||
{
|
||||
/* Split the part_name if passed as "$dev_num#part_name". */
|
||||
if (!part_get_info_by_dev_and_name(dev_iface, dev_part_str,
|
||||
dev_desc, part_info))
|
||||
return 0;
|
||||
/*
|
||||
* Couldn't lookup by name, try looking up the partition description
|
||||
* directly.
|
||||
*/
|
||||
if (blk_get_device_part_str(dev_iface, dev_part_str,
|
||||
dev_desc, part_info, 1) < 0) {
|
||||
printf("Couldn't find partition %s %s\n",
|
||||
dev_iface, dev_part_str);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void part_set_generic_name(const struct blk_desc *dev_desc,
|
||||
int part_num, char *name)
|
||||
{
|
||||
|
|
1
doc/.gitignore
vendored
Normal file
1
doc/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
output
|
67
doc/android/ab.txt
Normal file
67
doc/android/ab.txt
Normal file
|
@ -0,0 +1,67 @@
|
|||
Android A/B updates
|
||||
===================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
A/B system updates ensures modern approach for system update. This feature
|
||||
allows one to use two sets (or more) of partitions referred to as slots
|
||||
(normally slot A and slot B). The system runs from the current slot while the
|
||||
partitions in the unused slot can be updated [1].
|
||||
|
||||
A/B enablement
|
||||
--------------
|
||||
|
||||
The A/B updates support can be activated by specifying next options in
|
||||
your board configuration file:
|
||||
|
||||
CONFIG_ANDROID_AB=y
|
||||
CONFIG_CMD_AB_SELECT=y
|
||||
|
||||
The disk space on target device must be partitioned in a way so that each
|
||||
partition which needs to be updated has two or more instances. The name of
|
||||
each instance must be formed by adding suffixes: _a, _b, _c, etc.
|
||||
For example: boot_a, boot_b, system_a, system_b, vendor_a, vendor_b.
|
||||
|
||||
As a result you can use 'ab_select' command to ensure A/B boot process in your
|
||||
boot script. This command analyzes and processes A/B metadata stored on a
|
||||
special partition (e.g. "misc") and determines which slot should be used for
|
||||
booting up.
|
||||
|
||||
Command usage
|
||||
-------------
|
||||
|
||||
ab_select <slot_var_name> <interface> <dev[:part_number|#part_name]>
|
||||
|
||||
for example:
|
||||
|
||||
=> ab_select slot_name mmc 1:4
|
||||
|
||||
or
|
||||
|
||||
=> ab_select slot_name mmc 1#misc
|
||||
|
||||
Result:
|
||||
|
||||
=> printenv slot_name
|
||||
slot_name=a
|
||||
|
||||
Based on this slot information, the current boot partition should be defined,
|
||||
and next kernel command line parameters should be generated:
|
||||
|
||||
- androidboot.slot_suffix=
|
||||
- root=
|
||||
|
||||
For example:
|
||||
|
||||
androidboot.slot_suffix=_a root=/dev/mmcblk1p12
|
||||
|
||||
A/B metadata is organized according to AOSP reference [2]. On the first system
|
||||
start with A/B enabled, when 'misc' partition doesn't contain required data,
|
||||
the default A/B metadata will be created and written to 'misc' partition.
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
[1] https://source.android.com/devices/tech/ota/ab
|
||||
[2] bootable/recovery/bootloader_message/include/bootloader_message/bootloader_message.h
|
|
@ -170,7 +170,7 @@ except ImportError:
|
|||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
html_logo = '../tools/logos/u-boot_logo.svg'
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
|
|
|
@ -39,6 +39,8 @@ from docutils.statemachine import ViewList
|
|||
from docutils.parsers.rst import directives, Directive
|
||||
from sphinx.ext.autodoc import AutodocReporter
|
||||
|
||||
import kernellog
|
||||
|
||||
__version__ = '1.0'
|
||||
|
||||
class KernelDocDirective(Directive):
|
||||
|
@ -86,7 +88,8 @@ class KernelDocDirective(Directive):
|
|||
cmd += [filename]
|
||||
|
||||
try:
|
||||
env.app.verbose('calling kernel-doc \'%s\'' % (" ".join(cmd)))
|
||||
kernellog.verbose(env.app,
|
||||
'calling kernel-doc \'%s\'' % (" ".join(cmd)))
|
||||
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
out, err = p.communicate()
|
||||
|
@ -96,7 +99,8 @@ class KernelDocDirective(Directive):
|
|||
if p.returncode != 0:
|
||||
sys.stderr.write(err)
|
||||
|
||||
env.app.warn('kernel-doc \'%s\' failed with return code %d' % (" ".join(cmd), p.returncode))
|
||||
kernellog.warn(env.app,
|
||||
'kernel-doc \'%s\' failed with return code %d' % (" ".join(cmd), p.returncode))
|
||||
return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
|
||||
elif env.config.kerneldoc_verbosity > 0:
|
||||
sys.stderr.write(err)
|
||||
|
@ -128,8 +132,8 @@ class KernelDocDirective(Directive):
|
|||
return node.children
|
||||
|
||||
except Exception as e: # pylint: disable=W0703
|
||||
env.app.warn('kernel-doc \'%s\' processing failed with: %s' %
|
||||
(" ".join(cmd), str(e)))
|
||||
kernellog.warn(env.app, 'kernel-doc \'%s\' processing failed with: %s' %
|
||||
(" ".join(cmd), str(e)))
|
||||
return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
|
||||
|
||||
def setup(app):
|
||||
|
|
28
doc/sphinx/kernellog.py
Normal file
28
doc/sphinx/kernellog.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Sphinx has deprecated its older logging interface, but the replacement
|
||||
# only goes back to 1.6. So here's a wrapper layer to keep around for
|
||||
# as long as we support 1.4.
|
||||
#
|
||||
import sphinx
|
||||
|
||||
if sphinx.__version__[:3] >= '1.6':
|
||||
UseLogging = True
|
||||
from sphinx.util import logging
|
||||
logger = logging.getLogger('kerneldoc')
|
||||
else:
|
||||
UseLogging = False
|
||||
|
||||
def warn(app, message):
|
||||
if UseLogging:
|
||||
logger.warning(message)
|
||||
else:
|
||||
app.warn(message)
|
||||
|
||||
def verbose(app, message):
|
||||
if UseLogging:
|
||||
logger.verbose(message)
|
||||
else:
|
||||
app.verbose(message)
|
||||
|
||||
|
|
@ -60,6 +60,8 @@ import sphinx
|
|||
from sphinx.util.nodes import clean_astext
|
||||
from six import iteritems
|
||||
|
||||
import kernellog
|
||||
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
if PY3:
|
||||
|
@ -171,20 +173,20 @@ def setupTools(app):
|
|||
This function is called once, when the builder is initiated.
|
||||
"""
|
||||
global dot_cmd, convert_cmd # pylint: disable=W0603
|
||||
app.verbose("kfigure: check installed tools ...")
|
||||
kernellog.verbose(app, "kfigure: check installed tools ...")
|
||||
|
||||
dot_cmd = which('dot')
|
||||
convert_cmd = which('convert')
|
||||
|
||||
if dot_cmd:
|
||||
app.verbose("use dot(1) from: " + dot_cmd)
|
||||
kernellog.verbose(app, "use dot(1) from: " + dot_cmd)
|
||||
else:
|
||||
app.warn("dot(1) not found, for better output quality install "
|
||||
"graphviz from http://www.graphviz.org")
|
||||
kernellog.warn(app, "dot(1) not found, for better output quality install "
|
||||
"graphviz from http://www.graphviz.org")
|
||||
if convert_cmd:
|
||||
app.verbose("use convert(1) from: " + convert_cmd)
|
||||
kernellog.verbose(app, "use convert(1) from: " + convert_cmd)
|
||||
else:
|
||||
app.warn(
|
||||
kernellog.warn(app,
|
||||
"convert(1) not found, for SVG to PDF conversion install "
|
||||
"ImageMagick (https://www.imagemagick.org)")
|
||||
|
||||
|
@ -220,12 +222,13 @@ def convert_image(img_node, translator, src_fname=None):
|
|||
|
||||
# in kernel builds, use 'make SPHINXOPTS=-v' to see verbose messages
|
||||
|
||||
app.verbose('assert best format for: ' + img_node['uri'])
|
||||
kernellog.verbose(app, 'assert best format for: ' + img_node['uri'])
|
||||
|
||||
if in_ext == '.dot':
|
||||
|
||||
if not dot_cmd:
|
||||
app.verbose("dot from graphviz not available / include DOT raw.")
|
||||
kernellog.verbose(app,
|
||||
"dot from graphviz not available / include DOT raw.")
|
||||
img_node.replace_self(file2literal(src_fname))
|
||||
|
||||
elif translator.builder.format == 'latex':
|
||||
|
@ -252,7 +255,8 @@ def convert_image(img_node, translator, src_fname=None):
|
|||
|
||||
if translator.builder.format == 'latex':
|
||||
if convert_cmd is None:
|
||||
app.verbose("no SVG to PDF conversion available / include SVG raw.")
|
||||
kernellog.verbose(app,
|
||||
"no SVG to PDF conversion available / include SVG raw.")
|
||||
img_node.replace_self(file2literal(src_fname))
|
||||
else:
|
||||
dst_fname = path.join(translator.builder.outdir, fname + '.pdf')
|
||||
|
@ -265,18 +269,19 @@ def convert_image(img_node, translator, src_fname=None):
|
|||
_name = dst_fname[len(translator.builder.outdir) + 1:]
|
||||
|
||||
if isNewer(dst_fname, src_fname):
|
||||
app.verbose("convert: {out}/%s already exists and is newer" % _name)
|
||||
kernellog.verbose(app,
|
||||
"convert: {out}/%s already exists and is newer" % _name)
|
||||
|
||||
else:
|
||||
ok = False
|
||||
mkdir(path.dirname(dst_fname))
|
||||
|
||||
if in_ext == '.dot':
|
||||
app.verbose('convert DOT to: {out}/' + _name)
|
||||
kernellog.verbose(app, 'convert DOT to: {out}/' + _name)
|
||||
ok = dot2format(app, src_fname, dst_fname)
|
||||
|
||||
elif in_ext == '.svg':
|
||||
app.verbose('convert SVG to: {out}/' + _name)
|
||||
kernellog.verbose(app, 'convert SVG to: {out}/' + _name)
|
||||
ok = svg2pdf(app, src_fname, dst_fname)
|
||||
|
||||
if not ok:
|
||||
|
@ -305,7 +310,8 @@ def dot2format(app, dot_fname, out_fname):
|
|||
with open(out_fname, "w") as out:
|
||||
exit_code = subprocess.call(cmd, stdout = out)
|
||||
if exit_code != 0:
|
||||
app.warn("Error #%d when calling: %s" % (exit_code, " ".join(cmd)))
|
||||
kernellog.warn(app,
|
||||
"Error #%d when calling: %s" % (exit_code, " ".join(cmd)))
|
||||
return bool(exit_code == 0)
|
||||
|
||||
def svg2pdf(app, svg_fname, pdf_fname):
|
||||
|
@ -322,7 +328,7 @@ def svg2pdf(app, svg_fname, pdf_fname):
|
|||
# use stdout and stderr from parent
|
||||
exit_code = subprocess.call(cmd)
|
||||
if exit_code != 0:
|
||||
app.warn("Error #%d when calling: %s" % (exit_code, " ".join(cmd)))
|
||||
kernellog.warn(app, "Error #%d when calling: %s" % (exit_code, " ".join(cmd)))
|
||||
return bool(exit_code == 0)
|
||||
|
||||
|
||||
|
@ -415,15 +421,15 @@ def visit_kernel_render(self, node):
|
|||
app = self.builder.app
|
||||
srclang = node.get('srclang')
|
||||
|
||||
app.verbose('visit kernel-render node lang: "%s"' % (srclang))
|
||||
kernellog.verbose(app, 'visit kernel-render node lang: "%s"' % (srclang))
|
||||
|
||||
tmp_ext = RENDER_MARKUP_EXT.get(srclang, None)
|
||||
if tmp_ext is None:
|
||||
app.warn('kernel-render: "%s" unknown / include raw.' % (srclang))
|
||||
kernellog.warn(app, 'kernel-render: "%s" unknown / include raw.' % (srclang))
|
||||
return
|
||||
|
||||
if not dot_cmd and tmp_ext == '.dot':
|
||||
app.verbose("dot from graphviz not available / include raw.")
|
||||
kernellog.verbose(app, "dot from graphviz not available / include raw.")
|
||||
return
|
||||
|
||||
literal_block = node[0]
|
||||
|
|
|
@ -216,7 +216,7 @@ As an example, consider this FIT:
|
|||
kernel = "kernel-1";
|
||||
fdt = "fdt-1";
|
||||
};
|
||||
conf-1 {
|
||||
conf-2 {
|
||||
kernel = "kernel-2";
|
||||
fdt = "fdt-2";
|
||||
};
|
||||
|
@ -232,7 +232,7 @@ configuration 3 with kernel 1 and fdt 2:
|
|||
kernel = "kernel-1";
|
||||
fdt = "fdt-1";
|
||||
};
|
||||
conf-1 {
|
||||
conf-2 {
|
||||
kernel = "kernel-2";
|
||||
fdt = "fdt-2";
|
||||
};
|
||||
|
@ -337,6 +337,7 @@ WARNING: When relying on signed FIT images with required signature check
|
|||
the legacy image format is default disabled by not defining
|
||||
CONFIG_LEGACY_IMAGE_FORMAT
|
||||
|
||||
|
||||
Testing
|
||||
-------
|
||||
An easy way to test signing and verification is to use the test script
|
||||
|
@ -349,6 +350,8 @@ A sample run is show below:
|
|||
$ make O=sandbox sandbox_config
|
||||
$ make O=sandbox
|
||||
$ O=sandbox ./test/vboot/vboot_test.sh
|
||||
|
||||
|
||||
Simple Verified Boot Test
|
||||
=========================
|
||||
|
||||
|
|
34
include/android_ab.h
Normal file
34
include/android_ab.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*/
|
||||
|
||||
#ifndef __ANDROID_AB_H
|
||||
#define __ANDROID_AB_H
|
||||
|
||||
#include <common.h>
|
||||
|
||||
/* Android standard boot slot names are 'a', 'b', 'c', ... */
|
||||
#define BOOT_SLOT_NAME(slot_num) ('a' + (slot_num))
|
||||
|
||||
/* Number of slots */
|
||||
#define NUM_SLOTS 2
|
||||
|
||||
/**
|
||||
* Select the slot where to boot from.
|
||||
*
|
||||
* On Android devices with more than one boot slot (multiple copies of the
|
||||
* kernel and system images) selects which slot should be used to boot from and
|
||||
* registers the boot attempt. This is used in by the new A/B update model where
|
||||
* one slot is updated in the background while running from the other slot. If
|
||||
* the selected slot did not successfully boot in the past, a boot attempt is
|
||||
* registered before returning from this function so it isn't selected
|
||||
* indefinitely.
|
||||
*
|
||||
* @param[in] dev_desc Place to store the device description pointer
|
||||
* @param[in] part_info Place to store the partition information
|
||||
* @return The slot number (>= 0) on success, or a negative on error
|
||||
*/
|
||||
int ab_select_slot(struct blk_desc *dev_desc, disk_partition_t *part_info);
|
||||
|
||||
#endif /* __ANDROID_AB_H */
|
|
@ -254,11 +254,11 @@
|
|||
#endif
|
||||
|
||||
#if defined(CONFIG_DM_PCI)
|
||||
#define BOOTENV_RUN_NET_PCI_ENUM "run boot_net_pci_enum; "
|
||||
#define BOOTENV_RUN_PCI_ENUM "run boot_pci_enum; "
|
||||
#define BOOTENV_SHARED_PCI \
|
||||
"boot_net_pci_enum=pci enum\0"
|
||||
"boot_pci_enum=pci enum\0"
|
||||
#else
|
||||
#define BOOTENV_RUN_NET_PCI_ENUM
|
||||
#define BOOTENV_RUN_PCI_ENUM
|
||||
#define BOOTENV_SHARED_PCI
|
||||
#endif
|
||||
|
||||
|
@ -281,10 +281,24 @@
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_CMD_VIRTIO
|
||||
#define BOOTENV_SHARED_VIRTIO BOOTENV_SHARED_BLKDEV(virtio)
|
||||
#define BOOTENV_RUN_VIRTIO_INIT "run virtio_init; "
|
||||
#define BOOTENV_SET_VIRTIO_NEED_INIT "virtio_need_init=; "
|
||||
#define BOOTENV_SHARED_VIRTIO \
|
||||
"virtio_init=" \
|
||||
"if ${virtio_need_init}; then " \
|
||||
"virtio_need_init=false; " \
|
||||
"virtio scan; " \
|
||||
"fi\0" \
|
||||
\
|
||||
"virtio_boot=" \
|
||||
BOOTENV_RUN_PCI_ENUM \
|
||||
BOOTENV_RUN_VIRTIO_INIT \
|
||||
BOOTENV_SHARED_BLKDEV_BODY(virtio)
|
||||
#define BOOTENV_DEV_VIRTIO BOOTENV_DEV_BLKDEV
|
||||
#define BOOTENV_DEV_NAME_VIRTIO BOOTENV_DEV_NAME_BLKDEV
|
||||
#else
|
||||
#define BOOTENV_RUN_VIRTIO_INIT
|
||||
#define BOOTENV_SET_VIRTIO_NEED_INIT
|
||||
#define BOOTENV_SHARED_VIRTIO
|
||||
#define BOOTENV_DEV_VIRTIO \
|
||||
BOOT_TARGET_DEVICES_references_VIRTIO_without_CONFIG_CMD_VIRTIO
|
||||
|
@ -350,7 +364,7 @@
|
|||
#define BOOTENV_DEV_DHCP(devtypeu, devtypel, instance) \
|
||||
"bootcmd_dhcp=" \
|
||||
BOOTENV_RUN_NET_USB_START \
|
||||
BOOTENV_RUN_NET_PCI_ENUM \
|
||||
BOOTENV_RUN_PCI_ENUM \
|
||||
"if dhcp ${scriptaddr} ${boot_script_dhcp}; then " \
|
||||
"source ${scriptaddr}; " \
|
||||
"fi;" \
|
||||
|
@ -369,7 +383,7 @@
|
|||
#define BOOTENV_DEV_PXE(devtypeu, devtypel, instance) \
|
||||
"bootcmd_pxe=" \
|
||||
BOOTENV_RUN_NET_USB_START \
|
||||
BOOTENV_RUN_NET_PCI_ENUM \
|
||||
BOOTENV_RUN_PCI_ENUM \
|
||||
"dhcp; " \
|
||||
"if pxe get; then " \
|
||||
"pxe boot; " \
|
||||
|
@ -465,6 +479,7 @@
|
|||
"distro_bootcmd=" BOOTENV_SET_SCSI_NEED_INIT \
|
||||
BOOTENV_SET_NVME_NEED_INIT \
|
||||
BOOTENV_SET_IDE_NEED_INIT \
|
||||
BOOTENV_SET_VIRTIO_NEED_INIT \
|
||||
"for target in ${boot_targets}; do " \
|
||||
"run bootcmd_${target}; " \
|
||||
"done\0"
|
||||
|
|
|
@ -23,6 +23,18 @@
|
|||
#define VBMETA_PART ""
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CMD_AB_SELECT)
|
||||
#define COMMON_PARTS \
|
||||
"name=boot_a,size=20M,uuid=${uuid_gpt_boot_a};" \
|
||||
"name=boot_b,size=20M,uuid=${uuid_gpt_boot_b};" \
|
||||
"name=system_a,size=1024M,uuid=${uuid_gpt_system_a};" \
|
||||
"name=system_b,size=1024M,uuid=${uuid_gpt_system_b};"
|
||||
#else
|
||||
#define COMMON_PARTS \
|
||||
"name=boot,size=20M,uuid=${uuid_gpt_boot};" \
|
||||
"name=system,size=1024M,uuid=${uuid_gpt_system};"
|
||||
#endif
|
||||
|
||||
#ifndef PARTS_DEFAULT
|
||||
/* Define the default GPT table for eMMC */
|
||||
#define PARTS_DEFAULT \
|
||||
|
@ -38,8 +50,7 @@
|
|||
"name=uboot-env,start=2432K,size=256K,uuid=${uuid_gpt_reserved};" \
|
||||
"name=misc,size=128K,uuid=${uuid_gpt_misc};" \
|
||||
"name=recovery,size=40M,uuid=${uuid_gpt_recovery};" \
|
||||
"name=boot,size=10M,uuid=${uuid_gpt_boot};" \
|
||||
"name=system,size=1024M,uuid=${uuid_gpt_system};" \
|
||||
COMMON_PARTS \
|
||||
"name=vendor,size=256M,uuid=${uuid_gpt_vendor};" \
|
||||
VBMETA_PART \
|
||||
"name=userdata,size=-,uuid=${uuid_gpt_userdata}"
|
||||
|
@ -58,6 +69,35 @@
|
|||
#define AVB_VERIFY_CMD ""
|
||||
#endif
|
||||
|
||||
#define CONTROL_PARTITION "misc"
|
||||
|
||||
#if defined(CONFIG_CMD_AB_SELECT)
|
||||
#define AB_SELECT \
|
||||
"if part number mmc 1 " CONTROL_PARTITION " control_part_number; " \
|
||||
"then " \
|
||||
"echo " CONTROL_PARTITION \
|
||||
" partition number:${control_part_number};" \
|
||||
"ab_select slot_name mmc ${mmcdev}:${control_part_number};" \
|
||||
"else " \
|
||||
"echo " CONTROL_PARTITION " partition not found;" \
|
||||
"exit;" \
|
||||
"fi;" \
|
||||
"setenv slot_suffix _${slot_name};" \
|
||||
"if part number mmc ${mmcdev} system${slot_suffix} " \
|
||||
"system_part_number; then " \
|
||||
"setenv bootargs_ab " \
|
||||
"ro root=/dev/mmcblk${mmcdev}p${system_part_number} " \
|
||||
"rootwait init=/init skip_initramfs " \
|
||||
"androidboot.slot_suffix=${slot_suffix};" \
|
||||
"echo A/B cmdline addition: ${bootargs_ab};" \
|
||||
"setenv bootargs ${bootargs} ${bootargs_ab};" \
|
||||
"else " \
|
||||
"echo system${slot_suffix} partition not found;" \
|
||||
"fi;"
|
||||
#else
|
||||
#define AB_SELECT ""
|
||||
#endif
|
||||
|
||||
#define DEFAULT_COMMON_BOOT_TI_ARGS \
|
||||
"console=" CONSOLEDEV ",115200n8\0" \
|
||||
"fdtfile=undefined\0" \
|
||||
|
@ -86,10 +126,16 @@
|
|||
"mmc dev $mmcdev; " \
|
||||
"mmc rescan; " \
|
||||
AVB_VERIFY_CHECK \
|
||||
"part start mmc ${mmcdev} boot boot_start; " \
|
||||
"part size mmc ${mmcdev} boot boot_size; " \
|
||||
"mmc read ${loadaddr} ${boot_start} ${boot_size}; " \
|
||||
"bootm ${loadaddr}#${fdtfile};\0 "
|
||||
AB_SELECT \
|
||||
"if part start mmc ${mmcdev} boot${slot_suffix} boot_start; " \
|
||||
"then " \
|
||||
"part size mmc ${mmcdev} boot${slot_suffix} " \
|
||||
"boot_size; " \
|
||||
"mmc read ${loadaddr} ${boot_start} ${boot_size}; " \
|
||||
"bootm ${loadaddr}#${fdtfile}; " \
|
||||
"else " \
|
||||
"echo boot${slot_suffix} partition not found; " \
|
||||
"fi;\0"
|
||||
|
||||
#ifdef CONFIG_OMAP54XX
|
||||
|
||||
|
|
|
@ -201,6 +201,27 @@ int part_get_info_by_name_type(struct blk_desc *dev_desc, const char *name,
|
|||
int part_get_info_by_name(struct blk_desc *dev_desc,
|
||||
const char *name, disk_partition_t *info);
|
||||
|
||||
/**
|
||||
* Get partition info from dev number + part name, or dev number + part number.
|
||||
*
|
||||
* Parse a device number and partition description (either name or number)
|
||||
* in the form of device number plus partition name separated by a "#"
|
||||
* (like "device_num#partition_name") or a device number plus a partition number
|
||||
* separated by a ":". For example both "0#misc" and "0:1" can be valid
|
||||
* partition descriptions for a given interface. If the partition is found, sets
|
||||
* dev_desc and part_info accordingly with the information of the partition.
|
||||
*
|
||||
* @param[in] dev_iface Device interface
|
||||
* @param[in] dev_part_str Input partition description, like "0#misc" or "0:1"
|
||||
* @param[out] dev_desc Place to store the device description pointer
|
||||
* @param[out] part_info Place to store the partition information
|
||||
* @return 0 on success, or a negative on error
|
||||
*/
|
||||
int part_get_info_by_dev_and_name_or_num(const char *dev_iface,
|
||||
const char *dev_part_str,
|
||||
struct blk_desc **dev_desc,
|
||||
disk_partition_t *part_info);
|
||||
|
||||
/**
|
||||
* part_set_generic_name() - create generic partition like hda1 or sdb2
|
||||
*
|
||||
|
|
|
@ -130,7 +130,7 @@ struct dm_rproc_ops {
|
|||
/* Accessor */
|
||||
#define rproc_get_ops(dev) ((struct dm_rproc_ops *)(dev)->driver->ops)
|
||||
|
||||
#ifdef CONFIG_REMOTEPROC
|
||||
#if CONFIG_IS_ENABLED(REMOTEPROC)
|
||||
/**
|
||||
* rproc_init() - Initialize all bound remote proc devices
|
||||
* @return 0 if all ok, else appropriate error value.
|
||||
|
|
|
@ -212,7 +212,7 @@ my $anon_struct_union = 0;
|
|||
my $type_constant = '\b``([^\`]+)``\b';
|
||||
my $type_constant2 = '\%([-_\w]+)';
|
||||
my $type_func = '(\w+)\(\)';
|
||||
my $type_param = '\@(\w*(\.\w+)*(\.\.\.)?)';
|
||||
my $type_param = '\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)';
|
||||
my $type_fp_param = '\@(\w+)\(\)'; # Special RST handling for func ptr params
|
||||
my $type_env = '(\$\w+)';
|
||||
my $type_enum = '\&(enum\s*([_\w]+))';
|
||||
|
@ -1062,7 +1062,7 @@ sub dump_struct($$) {
|
|||
my $x = shift;
|
||||
my $file = shift;
|
||||
|
||||
if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) {
|
||||
if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) {
|
||||
my $decl_type = $1;
|
||||
$declaration_name = $2;
|
||||
my $members = $3;
|
||||
|
@ -1073,8 +1073,9 @@ sub dump_struct($$) {
|
|||
# strip comments:
|
||||
$members =~ s/\/\*.*?\*\///gos;
|
||||
# strip attributes
|
||||
$members =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i;
|
||||
$members =~ s/__aligned\s*\([^;]*\)//gos;
|
||||
$members =~ s/\s*__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)//gi;
|
||||
$members =~ s/\s*__aligned\s*\([^;]*\)//gos;
|
||||
$members =~ s/\s*__packed\s*//gos;
|
||||
$members =~ s/\s*CRYPTO_MINALIGN_ATTR//gos;
|
||||
# replace DECLARE_BITMAP
|
||||
$members =~ s/DECLARE_BITMAP\s*\(([^,)]+),\s*([^,)]+)\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos;
|
||||
|
@ -1148,20 +1149,20 @@ sub dump_struct($$) {
|
|||
}
|
||||
}
|
||||
}
|
||||
$members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)}([^\{\}\;]*)\;/$newmember/;
|
||||
$members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/$newmember/;
|
||||
}
|
||||
|
||||
# Ignore other nested elements, like enums
|
||||
$members =~ s/({[^\{\}]*})//g;
|
||||
$members =~ s/(\{[^\{\}]*\})//g;
|
||||
|
||||
create_parameterlist($members, ';', $file, $declaration_name);
|
||||
check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual);
|
||||
|
||||
# Adjust declaration for better display
|
||||
$declaration =~ s/([{;])/$1\n/g;
|
||||
$declaration =~ s/}\s+;/};/g;
|
||||
$declaration =~ s/([\{;])/$1\n/g;
|
||||
$declaration =~ s/\}\s+;/};/g;
|
||||
# Better handle inlined enums
|
||||
do {} while ($declaration =~ s/(enum\s+{[^}]+),([^\n])/$1,\n$2/);
|
||||
do {} while ($declaration =~ s/(enum\s+\{[^\}]+),([^\n])/$1,\n$2/);
|
||||
|
||||
my @def_args = split /\n/, $declaration;
|
||||
my $level = 1;
|
||||
|
@ -1171,12 +1172,12 @@ sub dump_struct($$) {
|
|||
$clause =~ s/\s+$//;
|
||||
$clause =~ s/\s+/ /;
|
||||
next if (!$clause);
|
||||
$level-- if ($clause =~ m/(})/ && $level > 1);
|
||||
$level-- if ($clause =~ m/(\})/ && $level > 1);
|
||||
if (!($clause =~ m/^\s*#/)) {
|
||||
$declaration .= "\t" x $level;
|
||||
}
|
||||
$declaration .= "\t" . $clause . "\n";
|
||||
$level++ if ($clause =~ m/({)/ && !($clause =~m/}/));
|
||||
$level++ if ($clause =~ m/(\{)/ && !($clause =~m/\}/));
|
||||
}
|
||||
output_declaration($declaration_name,
|
||||
'struct',
|
||||
|
@ -1244,7 +1245,7 @@ sub dump_enum($$) {
|
|||
# strip #define macros inside enums
|
||||
$x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos;
|
||||
|
||||
if ($x =~ /enum\s+(\w+)\s*{(.*)}/) {
|
||||
if ($x =~ /enum\s+(\w+)\s*\{(.*)\}/) {
|
||||
$declaration_name = $1;
|
||||
my $members = $2;
|
||||
my %_members;
|
||||
|
@ -1381,7 +1382,7 @@ sub create_parameterlist($$$$) {
|
|||
} elsif ($arg =~ m/\(.+\)\s*\(/) {
|
||||
# pointer-to-function
|
||||
$arg =~ tr/#/,/;
|
||||
$arg =~ m/[^\(]+\(\*?\s*([\w\.]*)\s*\)/;
|
||||
$arg =~ m/[^\(]+\([\w\s]*\*?\s*([\w\.]*)\s*\)/;
|
||||
$param = $1;
|
||||
$type = $arg;
|
||||
$type =~ s/([^\(]+\(\*?)\s*$param/$1/;
|
||||
|
@ -1473,7 +1474,7 @@ sub push_parameter($$$$) {
|
|||
if (!defined $parameterdescs{$param} && $param !~ /^#/) {
|
||||
$parameterdescs{$param} = $undescribed;
|
||||
|
||||
if (show_warnings($type, $declaration_name)) {
|
||||
if (show_warnings($type, $declaration_name) && $param !~ /\./) {
|
||||
print STDERR
|
||||
"${file}:$.: warning: Function parameter or member '$param' not described in '$declaration_name'\n";
|
||||
++$warnings;
|
||||
|
@ -1785,7 +1786,7 @@ sub process_proto_type($$) {
|
|||
}
|
||||
|
||||
while (1) {
|
||||
if ( $x =~ /([^{};]*)([{};])(.*)/ ) {
|
||||
if ( $x =~ /([^\{\};]*)([\{\};])(.*)/ ) {
|
||||
if( length $prototype ) {
|
||||
$prototype .= " "
|
||||
}
|
||||
|
@ -1904,13 +1905,13 @@ sub process_name($$) {
|
|||
++$warnings;
|
||||
}
|
||||
|
||||
if ($identifier =~ m/^struct/) {
|
||||
if ($identifier =~ m/^struct\b/) {
|
||||
$decl_type = 'struct';
|
||||
} elsif ($identifier =~ m/^union/) {
|
||||
} elsif ($identifier =~ m/^union\b/) {
|
||||
$decl_type = 'union';
|
||||
} elsif ($identifier =~ m/^enum/) {
|
||||
} elsif ($identifier =~ m/^enum\b/) {
|
||||
$decl_type = 'enum';
|
||||
} elsif ($identifier =~ m/^typedef/) {
|
||||
} elsif ($identifier =~ m/^typedef\b/) {
|
||||
$decl_type = 'typedef';
|
||||
} else {
|
||||
$decl_type = 'function';
|
||||
|
|
75
test/py/tests/test_android/test_ab.py
Normal file
75
test/py/tests/test_android/test_ab.py
Normal file
|
@ -0,0 +1,75 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
# (C) Copyright 2018 Texas Instruments, <www.ti.com>
|
||||
|
||||
# Test A/B update commands.
|
||||
|
||||
import os
|
||||
import pytest
|
||||
import u_boot_utils
|
||||
|
||||
class ABTestDiskImage(object):
|
||||
"""Disk Image used by the A/B tests."""
|
||||
|
||||
def __init__(self, u_boot_console):
|
||||
"""Initialize a new ABTestDiskImage object.
|
||||
|
||||
Args:
|
||||
u_boot_console: A U-Boot console.
|
||||
|
||||
Returns:
|
||||
Nothing.
|
||||
"""
|
||||
|
||||
filename = 'test_ab_disk_image.bin'
|
||||
|
||||
persistent = u_boot_console.config.persistent_data_dir + '/' + filename
|
||||
self.path = u_boot_console.config.result_dir + '/' + filename
|
||||
|
||||
with u_boot_utils.persistent_file_helper(u_boot_console.log, persistent):
|
||||
if os.path.exists(persistent):
|
||||
u_boot_console.log.action('Disk image file ' + persistent +
|
||||
' already exists')
|
||||
else:
|
||||
u_boot_console.log.action('Generating ' + persistent)
|
||||
fd = os.open(persistent, os.O_RDWR | os.O_CREAT)
|
||||
os.ftruncate(fd, 524288)
|
||||
os.close(fd)
|
||||
cmd = ('sgdisk', persistent)
|
||||
u_boot_utils.run_and_log(u_boot_console, cmd)
|
||||
|
||||
cmd = ('sgdisk', '--new=1:64:512', '--change-name=1:misc',
|
||||
persistent)
|
||||
u_boot_utils.run_and_log(u_boot_console, cmd)
|
||||
cmd = ('sgdisk', '--load-backup=' + persistent)
|
||||
u_boot_utils.run_and_log(u_boot_console, cmd)
|
||||
|
||||
cmd = ('cp', persistent, self.path)
|
||||
u_boot_utils.run_and_log(u_boot_console, cmd)
|
||||
|
||||
di = None
|
||||
@pytest.fixture(scope='function')
|
||||
def ab_disk_image(u_boot_console):
|
||||
global di
|
||||
if not di:
|
||||
di = ABTestDiskImage(u_boot_console)
|
||||
return di
|
||||
|
||||
@pytest.mark.boardspec('sandbox')
|
||||
@pytest.mark.buildconfigspec('android_ab')
|
||||
@pytest.mark.buildconfigspec('cmd_ab_select')
|
||||
@pytest.mark.requiredtool('sgdisk')
|
||||
def test_ab(ab_disk_image, u_boot_console):
|
||||
"""Test the 'ab_select' command."""
|
||||
|
||||
u_boot_console.run_command('host bind 0 ' + ab_disk_image.path)
|
||||
|
||||
output = u_boot_console.run_command('ab_select slot_name host 0#misc')
|
||||
assert 're-initializing A/B metadata' in output
|
||||
assert 'Attempting slot a, tries remaining 7' in output
|
||||
output = u_boot_console.run_command('printenv slot_name')
|
||||
assert 'slot_name=a' in output
|
||||
|
||||
output = u_boot_console.run_command('ab_select slot_name host 0:1')
|
||||
assert 'Attempting slot b, tries remaining 7' in output
|
||||
output = u_boot_console.run_command('printenv slot_name')
|
||||
assert 'slot_name=b' in output
|
|
@ -8,7 +8,7 @@
|
|||
This tests Android Verified Boot 2.0 support in U-boot:
|
||||
|
||||
For additional details about how to build proper vbmeta partition
|
||||
check doc/README.avb2
|
||||
check doc/android/avb2.txt
|
||||
|
||||
For configuration verification:
|
||||
- Corrupt boot partition and check for failure
|
||||
|
|
Loading…
Add table
Reference in a new issue