summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Kconfig16
-rw-r--r--lib/Makefile1
-rw-r--r--lib/efi_loader/Makefile7
-rw-r--r--lib/efi_loader/efi_bootmgr.c2
-rw-r--r--lib/efi_loader/efi_boottime.c2
-rw-r--r--lib/efi_loader/efi_capsule.c7
-rw-r--r--lib/efi_loader/efi_gop.c7
-rw-r--r--lib/efi_loader/efi_signature.c13
-rw-r--r--lib/efi_loader/efi_tcg2.c12
-rw-r--r--lib/efi_loader/efi_var_seed.S4
-rw-r--r--lib/efi_selftest/efi_selftest_block_device.c77
-rw-r--r--lib/fwu_updates/fwu.c4
-rw-r--r--lib/gunzip.c10
-rw-r--r--lib/libavb/avb_chain_partition_descriptor.c1
-rw-r--r--lib/libavb/avb_chain_partition_descriptor.h16
-rw-r--r--lib/libavb/avb_cmdline.c42
-rw-r--r--lib/libavb/avb_descriptor.c62
-rw-r--r--lib/libavb/avb_hashtree_descriptor.h3
-rw-r--r--lib/libavb/avb_property_descriptor.h8
-rw-r--r--lib/libavb/avb_rsa.c6
-rw-r--r--lib/libavb/avb_slot_verify.c311
-rw-r--r--lib/libavb/avb_slot_verify.h6
-rw-r--r--lib/libavb/avb_util.c46
-rw-r--r--lib/libavb/avb_util.h140
-rw-r--r--lib/libavb/avb_vbmeta_image.c1
-rw-r--r--lib/libavb/avb_vbmeta_image.h8
-rw-r--r--lib/libavb/avb_version.h2
-rw-r--r--lib/lmb.c6
-rw-r--r--lib/lwip/u-boot/lwipopts.h11
-rw-r--r--lib/pmbus.c877
-rw-r--r--lib/string.c70
-rw-r--r--lib/uuid.c2
32 files changed, 1432 insertions, 348 deletions
diff --git a/lib/Kconfig b/lib/Kconfig
index 9e0f0ad7d06..24e55ade4d3 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -283,6 +283,22 @@ config PANIC_HANG
development since you can try to debug the conditions that lead to
the situation.
+config PMBUS
+ bool "PMBus 1.x decoder and transport helpers"
+ depends on DM_I2C
+ help
+ Enable include/pmbus.h and lib/pmbus.c: standard PMBus 1.x
+ command codes, LINEAR11, LINEAR16, and DIRECT numeric format
+ decoders, the two stage SMBus block read helper used for
+ MFR_ID, MFR_MODEL, and MFR_REVISION reads, and the table
+ driven STATUS_* bit print helper.
+
+ This is the substrate for any pre kernel PMBus consumer in
+ U-Boot (board/nxp/common/vid.c rail trim, board local telemetry
+ diagnostics, future per chip regulator drivers under
+ drivers/power/regulator/). It is not a hwmon clone. See
+ doc/develop/pmbus.rst for the policy notes.
+
config REGEX
bool "Enable regular expression support"
default y if NET_LEGACY
diff --git a/lib/Makefile b/lib/Makefile
index d0ffabc2b47..222378a8531 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -53,6 +53,7 @@ obj-y += rc4.o
obj-$(CONFIG_RBTREE) += rbtree.o
obj-$(CONFIG_BITREVERSE) += bitrev.o
obj-y += list_sort.o
+obj-$(CONFIG_PMBUS) += pmbus.o
endif
obj-$(CONFIG_$(PHASE_)TPM) += tpm-common.o
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index d73ad43951b..567db518a8f 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -74,8 +74,11 @@ obj-$(CONFIG_EFI_SIGNATURE_SUPPORT) += efi_signature.o
obj-$(CONFIG_EFI_ECPT) += efi_conformance.o
obj-$(CONFIG_EFI_DEBUG_SUPPORT) += efi_debug_support.o
-EFI_VAR_SEED_FILE := $(subst $\",,$(CONFIG_EFI_VAR_SEED_FILE))
-$(obj)/efi_var_seed.o: $(srctree)/$(EFI_VAR_SEED_FILE)
+TMP_VAR_SEED := $(subst $\",,$(CONFIG_EFI_VAR_SEED_FILE))
+EFI_VAR_SEED_FILE := $(if $(filter /% ,$(TMP_VAR_SEED)) \
+ ,$(TMP_VAR_SEED),$(srctree)/$(TMP_VAR_SEED))
+AFLAGS_efi_var_seed.o := -DEFI_VAR_SEED_FILE=\"$(EFI_VAR_SEED_FILE)\"
+$(obj)/efi_var_seed.o: $(EFI_VAR_SEED_FILE)
ifeq ($(CONFIG_EFI_CAPSULE_AUTHENTICATE),y)
capsule_crt_path=($(subst $(quote),,$(CONFIG_EFI_CAPSULE_CRT_FILE)))
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index 8c9a9b5eb56..8938b214ceb 100644
--- a/lib/efi_loader/efi_bootmgr.c
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -934,6 +934,7 @@ static efi_status_t efi_bootmgr_delete_invalid_boot_option(struct eficonfig_medi
efi_status_t ret = EFI_SUCCESS;
u16 *delete_index_list = NULL, *p;
efi_uintn_t buf_size;
+ efi_guid_t guid;
buf_size = 128;
var_name16 = malloc(buf_size);
@@ -943,7 +944,6 @@ static efi_status_t efi_bootmgr_delete_invalid_boot_option(struct eficonfig_medi
var_name16[0] = 0;
for (;;) {
int index;
- efi_guid_t guid;
efi_uintn_t tmp;
ret = efi_next_variable_name(&buf_size, &var_name16, &guid);
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index de57823bd44..bcb01c92cf4 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -3895,7 +3895,7 @@ efi_status_t EFIAPI efi_disconnect_controller(
&number_of_children,
&child_handle_buffer);
if (r != EFI_SUCCESS)
- return r;
+ goto out;
sole_child = (number_of_children == 1);
if (child_handle) {
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index 52887f7c274..a77810fa15c 100644
--- a/lib/efi_loader/efi_capsule.c
+++ b/lib/efi_loader/efi_capsule.c
@@ -860,7 +860,11 @@ static efi_status_t get_dp_device(u16 *boot_var,
if (!buf)
return EFI_NOT_FOUND;
- efi_deserialize_load_option(&lo, buf, &size);
+ ret = efi_deserialize_load_option(&lo, buf, &size);
+ if (ret != EFI_SUCCESS) {
+ log_err("Invalid load option %ls\n", boot_var);
+ goto out;
+ }
if (lo.attributes & LOAD_OPTION_ACTIVE) {
efi_dp_split_file_path(lo.file_path, device_dp, &file_dp);
@@ -871,6 +875,7 @@ static efi_status_t get_dp_device(u16 *boot_var,
ret = EFI_NOT_FOUND;
}
+out:
free(buf);
return ret;
diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c
index 9403e09691e..ae44d140289 100644
--- a/lib/efi_loader/efi_gop.c
+++ b/lib/efi_loader/efi_gop.c
@@ -471,7 +471,7 @@ efi_status_t efi_gop_register(void)
{
struct efi_gop_obj *gopobj;
u32 bpix, format, col, row;
- u64 fb_base, fb_size;
+ u64 fb_size;
efi_status_t ret;
struct udevice *vdev;
struct video_priv *priv;
@@ -490,7 +490,6 @@ efi_status_t efi_gop_register(void)
row = video_get_ysize(vdev);
plat = dev_get_uclass_plat(vdev);
- fb_base = IS_ENABLED(CONFIG_VIDEO_COPY) ? plat->copy_base : plat->base;
fb_size = plat->size;
switch (bpix) {
@@ -528,7 +527,7 @@ efi_status_t efi_gop_register(void)
gopobj->mode.info = &gopobj->info;
gopobj->mode.info_size = sizeof(gopobj->info);
- gopobj->mode.fb_base = fb_base;
+ gopobj->mode.fb_base = (uintptr_t)priv->fb;
gopobj->mode.fb_size = fb_size;
gopobj->info.version = 0;
@@ -553,7 +552,7 @@ efi_status_t efi_gop_register(void)
}
gopobj->info.pixels_per_scanline = col;
gopobj->bpix = bpix;
- gopobj->fb = map_sysmem(fb_base, fb_size);
+ gopobj->fb = priv->fb;
gopobj->vdev = vdev;
return EFI_SUCCESS;
diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c
index 93a4f257016..c2be5cb61b3 100644
--- a/lib/efi_loader/efi_signature.c
+++ b/lib/efi_loader/efi_signature.c
@@ -647,7 +647,7 @@ static struct efi_signature_store *
efi_sigstore_parse_siglist(struct efi_signature_list *esl)
{
struct efi_signature_store *siglist = NULL;
- struct efi_sig_data *sig_data, *sig_data_next;
+ struct efi_sig_data *sig_data;
struct efi_signature_data *esd;
size_t left;
@@ -690,7 +690,6 @@ efi_sigstore_parse_siglist(struct efi_signature_list *esl)
memcpy(&siglist->sig_type, &esl->signature_type, sizeof(efi_guid_t));
/* Go through the list */
- sig_data_next = NULL;
left = esl->signature_list_size
- (sizeof(*esl) + esl->signature_header_size);
esd = (struct efi_signature_data *)
@@ -703,13 +702,15 @@ efi_sigstore_parse_siglist(struct efi_signature_list *esl)
goto err;
}
- sig_data = calloc(esl->signature_size
- - sizeof(esd->signature_owner), 1);
+ sig_data = calloc(1, sizeof(*sig_data));
if (!sig_data) {
EFI_PRINT("Out of memory\n");
goto err;
}
+ sig_data->next = siglist->sig_data_list;
+ siglist->sig_data_list = sig_data;
+
/* Append signature data */
memcpy(&sig_data->owner, &esd->signature_owner,
sizeof(efi_guid_t));
@@ -722,15 +723,11 @@ efi_sigstore_parse_siglist(struct efi_signature_list *esl)
}
memcpy(sig_data->data, esd->signature_data, sig_data->size);
- sig_data->next = sig_data_next;
- sig_data_next = sig_data;
-
/* Next */
esd = (struct efi_signature_data *)
((u8 *)esd + esl->signature_size);
left -= esl->signature_size;
}
- siglist->sig_data_list = sig_data_next;
return siglist;
diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c
index 1860dc50238..5f9bbe97455 100644
--- a/lib/efi_loader/efi_tcg2.c
+++ b/lib/efi_loader/efi_tcg2.c
@@ -352,8 +352,8 @@ efi_tcg2_get_eventlog(struct efi_tcg2_protocol *this,
}
if (tcg2_platform_get_tpm2(&dev)) {
- event_log_location = NULL;
- event_log_last_entry = NULL;
+ *event_log_location = 0;
+ *event_log_last_entry = 0;
*event_log_truncated = false;
ret = EFI_SUCCESS;
goto out;
@@ -1343,8 +1343,8 @@ efi_status_t efi_tcg2_measure_dtb(void *dtb)
header = dtb;
sha256_starts(&hash_ctx);
sha256_update(&hash_ctx, (u8 *)header, sizeof(struct fdt_header));
- sha256_update(&hash_ctx, (u8 *)dtb + fdt_off_dt_struct(dtb), fdt_size_dt_strings(dtb));
- sha256_update(&hash_ctx, (u8 *)dtb + fdt_off_dt_strings(dtb), fdt_size_dt_struct(dtb));
+ sha256_update(&hash_ctx, (u8 *)dtb + fdt_off_dt_struct(dtb), fdt_size_dt_struct(dtb));
+ sha256_update(&hash_ctx, (u8 *)dtb + fdt_off_dt_strings(dtb), fdt_size_dt_strings(dtb));
sha256_update(&hash_ctx, (u8 *)dtb + fdt_off_mem_rsvmap(dtb), rsvmap_size);
sha256_finish(&hash_ctx, blob->data + blob->blob_description_size);
@@ -1535,9 +1535,9 @@ static efi_status_t tcg2_measure_secure_boot_variable(struct udevice *dev)
if (!data && !secure_variables[i].accept_empty)
continue;
- if (u16_strcmp(u"DeployedMode", secure_variables[i].name))
+ if (!u16_strcmp(u"DeployedMode", secure_variables[i].name))
secure_variables[i].pcr_index = deployed_audit_pcr_index;
- if (u16_strcmp(u"AuditMode", secure_variables[i].name))
+ if (!u16_strcmp(u"AuditMode", secure_variables[i].name))
secure_variables[i].pcr_index = deployed_audit_pcr_index;
ret = tcg2_measure_variable(dev, secure_variables[i].pcr_index,
diff --git a/lib/efi_loader/efi_var_seed.S b/lib/efi_loader/efi_var_seed.S
index e0a40cf46c8..008a505d19e 100644
--- a/lib/efi_loader/efi_var_seed.S
+++ b/lib/efi_loader/efi_var_seed.S
@@ -5,13 +5,11 @@
* Copyright (c) 2020, Heinrich Schuchardt <[email protected]>
*/
-#include <config.h>
-
.section .rodata.efi_seed.init,"a"
.balign 16
.global __efi_var_file_begin
__efi_var_file_begin:
-.incbin CONFIG_EFI_VAR_SEED_FILE
+.incbin EFI_VAR_SEED_FILE
.global __efi_var_file_end
__efi_var_file_end:
.balign 16
diff --git a/lib/efi_selftest/efi_selftest_block_device.c b/lib/efi_selftest/efi_selftest_block_device.c
index 9c4be834eeb..847d93693ee 100644
--- a/lib/efi_selftest/efi_selftest_block_device.c
+++ b/lib/efi_selftest/efi_selftest_block_device.c
@@ -58,6 +58,9 @@ static const struct compressed_disk_image img = EFI_ST_DISK_IMG;
/* Decompressed disk image */
static u8 *image;
+/* Handles buffer */
+static efi_handle_t *handles;
+
/*
* Reset service of the block IO protocol.
*
@@ -170,6 +173,7 @@ static efi_status_t decompress(u8 **image)
static struct efi_block_io_media media;
static struct efi_block_io block_io = {
+ .revision = EFI_BLOCK_IO_PROTOCOL_REVISION3,
.media = &media,
.reset = reset,
.read_blocks = read_blocks,
@@ -276,6 +280,15 @@ static int teardown(void)
return EFI_ST_FAILURE;
}
}
+
+ if (handles) {
+ r = boottime->free_pool(handles);
+ if (r != EFI_SUCCESS) {
+ efi_st_error("Failed to free handles\n");
+ return EFI_ST_FAILURE;
+ }
+ }
+
return r;
}
@@ -303,7 +316,6 @@ static int execute(void)
{
efi_status_t ret;
efi_uintn_t no_handles, i, len;
- efi_handle_t *handles;
efi_handle_t handle_partition = NULL;
struct efi_device_path *dp_partition;
struct efi_block_io *block_io_protocol;
@@ -372,6 +384,7 @@ static int execute(void)
break;
}
ret = boottime->free_pool(handles);
+ handles = NULL; /* Avoid double free on teardown(). */
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to free pool memory\n");
return EFI_ST_FAILURE;
@@ -603,6 +616,68 @@ static int execute(void)
return EFI_ST_FAILURE;
}
+ /* Get all handles with block io. */
+ ret = boottime->locate_handle_buffer(BY_PROTOCOL,
+ &block_io_protocol_guid, NULL,
+ &no_handles, &handles);
+ switch (ret) {
+ case EFI_SUCCESS:
+ if (!no_handles || !handles) {
+ efi_st_error("Locate handle buffer bad handles\n");
+ return EFI_ST_FAILURE;
+ }
+ break;
+ case EFI_NOT_FOUND:
+ efi_st_error("No block IO protocol found though one installed in setup\n");
+ return EFI_ST_FAILURE;
+ default:
+ efi_st_error("Locate handle buffer failed\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Verify all handles with block io. */
+ for (i = 0; i < no_handles; ++i) {
+ u64 rev;
+
+ ret = boottime->open_protocol(handles[i],
+ &block_io_protocol_guid,
+ (void *)&block_io_protocol,
+ NULL, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to open block io protocol %d\n",
+ (unsigned int)i);
+ return EFI_ST_FAILURE;
+ }
+
+ /* Verify block io revision. */
+ rev = block_io_protocol->revision;
+ if (rev != EFI_BLOCK_IO_PROTOCOL_REVISION2 &&
+ rev != EFI_BLOCK_IO_PROTOCOL_REVISION3) {
+ efi_st_error("Bad block io revision %u\n",
+ (unsigned int)rev);
+ return EFI_ST_FAILURE;
+ }
+
+ /* Verify block io pointers. */
+ if (!block_io_protocol->media ||
+ !block_io_protocol->reset ||
+ !block_io_protocol->read_blocks ||
+ !block_io_protocol->write_blocks ||
+ !block_io_protocol->flush_blocks) {
+ efi_st_error("Bad block io pointer\n");
+ return EFI_ST_FAILURE;
+ }
+ }
+
+ /* Free handles buffer. */
+ ret = boottime->free_pool(handles);
+ handles = NULL; /* Avoid double free on teardown(). */
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to free block io handles\n");
+ return EFI_ST_FAILURE;
+ }
+
return EFI_ST_SUCCESS;
}
diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
index 2b11e5da061..e9bb1b4fc65 100644
--- a/lib/fwu_updates/fwu.c
+++ b/lib/fwu_updates/fwu.c
@@ -759,7 +759,7 @@ static int fwu_boottime_checks(void)
ret = uclass_first_device_err(UCLASS_FWU_MDATA, &g_dev);
if (ret) {
- log_debug("Cannot find fwu device\n");
+ log_err("Cannot find fwu device\n");
return ret;
}
@@ -771,7 +771,7 @@ static int fwu_boottime_checks(void)
ret = fwu_init();
if (ret) {
- log_debug("fwu_init() failed\n");
+ log_err("fwu_init() failed\n");
return ret;
}
diff --git a/lib/gunzip.c b/lib/gunzip.c
index 20cc14f9688..b30cbfc34ef 100644
--- a/lib/gunzip.c
+++ b/lib/gunzip.c
@@ -246,6 +246,16 @@ int gzwrite(unsigned char *src, size_t len, struct blk_desc *dev,
s.next_out = writebuf;
}
r = inflate(&s, Z_SYNC_FLUSH);
+ if (r == Z_BUF_ERROR && !s.avail_in && payload_size) {
+ /*
+ * The input chunk was exhausted at exactly
+ * the same time as the write buffer filled
+ * up, so no progress was possible. This is
+ * not fatal, let the outer loop refill the
+ * input chunk.
+ */
+ break;
+ }
if ((r != Z_OK) &&
(r != Z_STREAM_END)) {
printf("Error: inflate() returned %d\n", r);
diff --git a/lib/libavb/avb_chain_partition_descriptor.c b/lib/libavb/avb_chain_partition_descriptor.c
index e2993063103..0354276c64a 100644
--- a/lib/libavb/avb_chain_partition_descriptor.c
+++ b/lib/libavb/avb_chain_partition_descriptor.c
@@ -24,6 +24,7 @@ bool avb_chain_partition_descriptor_validate_and_byteswap(
dest->rollback_index_location = avb_be32toh(dest->rollback_index_location);
dest->partition_name_len = avb_be32toh(dest->partition_name_len);
dest->public_key_len = avb_be32toh(dest->public_key_len);
+ dest->flags = avb_be32toh(dest->flags);
if (dest->rollback_index_location < 1) {
avb_error("Invalid rollback index location value.\n");
diff --git a/lib/libavb/avb_chain_partition_descriptor.h b/lib/libavb/avb_chain_partition_descriptor.h
index 80e2271782e..31c7298d1df 100644
--- a/lib/libavb/avb_chain_partition_descriptor.h
+++ b/lib/libavb/avb_chain_partition_descriptor.h
@@ -16,6 +16,16 @@
extern "C" {
#endif
+/* Flags for chain descriptors.
+ *
+ * AVB_CHAIN_PARTITION_DESCRIPTOR_FLAGS_DO_NOT_USE_AB: Do not apply the default A/B
+ * partition logic to this partition. This is intentionally a negative boolean
+ * because A/B should be both the default and most used in practice.
+ */
+typedef enum {
+ AVB_CHAIN_PARTITION_DESCRIPTOR_FLAGS_DO_NOT_USE_AB = (1 << 0),
+} AvbChainPartitionDescriptorFlags;
+
/* A descriptor containing a pointer to signed integrity data stored
* on another partition. The descriptor contains the partition name in
* question (without the A/B suffix), the public key used to sign the
@@ -28,13 +38,17 @@ extern "C" {
*
* The |reserved| field is for future expansion and must be set to NUL
* bytes.
+ *
+ * Changes in v1.3:
+ * - flags field is added which supports AVB_CHAIN_PARTITION_DESCRIPTOR_FLAGS_DO_NOT_USE_AB
*/
typedef struct AvbChainPartitionDescriptor {
AvbDescriptor parent_descriptor;
uint32_t rollback_index_location;
uint32_t partition_name_len;
uint32_t public_key_len;
- uint8_t reserved[64];
+ uint32_t flags;
+ uint8_t reserved[60];
} AVB_ATTR_PACKED AvbChainPartitionDescriptor;
/* Copies |src| to |dest| and validates, byte-swapping fields in the
diff --git a/lib/libavb/avb_cmdline.c b/lib/libavb/avb_cmdline.c
index a58ce6c48c0..842629abe0e 100644
--- a/lib/libavb/avb_cmdline.c
+++ b/lib/libavb/avb_cmdline.c
@@ -7,8 +7,6 @@
#include "avb_sha.h"
#include "avb_util.h"
#include "avb_version.h"
-#include <log.h>
-#include <malloc.h>
#define NUM_GUIDS 3
@@ -149,30 +147,6 @@ static int cmdline_append_option(AvbSlotVerifyData* slot_data,
return 1;
}
-#define AVB_MAX_DIGITS_UINT64 32
-
-/* Writes |value| to |digits| in base 10 followed by a NUL byte.
- * Returns number of characters written excluding the NUL byte.
- */
-static size_t uint64_to_base10(uint64_t value,
- char digits[AVB_MAX_DIGITS_UINT64]) {
- char rev_digits[AVB_MAX_DIGITS_UINT64];
- size_t n, num_digits;
-
- for (num_digits = 0; num_digits < AVB_MAX_DIGITS_UINT64 - 1;) {
- rev_digits[num_digits++] = avb_div_by_10(&value) + '0';
- if (value == 0) {
- break;
- }
- }
-
- for (n = 0; n < num_digits; n++) {
- digits[n] = rev_digits[num_digits - 1 - n];
- }
- digits[n] = '\0';
- return n;
-}
-
static int cmdline_append_version(AvbSlotVerifyData* slot_data,
const char* key,
uint64_t major_version,
@@ -182,8 +156,8 @@ static int cmdline_append_version(AvbSlotVerifyData* slot_data,
char combined[AVB_MAX_DIGITS_UINT64 * 2 + 1];
size_t num_major_digits, num_minor_digits;
- num_major_digits = uint64_to_base10(major_version, major_digits);
- num_minor_digits = uint64_to_base10(minor_version, minor_digits);
+ num_major_digits = avb_uint64_to_base10(major_version, major_digits);
+ num_minor_digits = avb_uint64_to_base10(minor_version, minor_digits);
avb_memcpy(combined, major_digits, num_major_digits);
combined[num_major_digits] = '.';
avb_memcpy(combined + num_major_digits + 1, minor_digits, num_minor_digits);
@@ -196,7 +170,7 @@ static int cmdline_append_uint64_base10(AvbSlotVerifyData* slot_data,
const char* key,
uint64_t value) {
char digits[AVB_MAX_DIGITS_UINT64];
- uint64_to_base10(value, digits);
+ avb_uint64_to_base10(value, digits);
return cmdline_append_option(slot_data, key, digits);
}
@@ -359,11 +333,11 @@ AvbSlotVerifyResult avb_append_options(
// Should never get here because MANAGED_RESTART_AND_EIO is
// remapped by avb_manage_hashtree_error_mode().
avb_assert_not_reached();
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
- goto out;
- default:
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
- goto out;
+ break;
+ case AVB_HASHTREE_ERROR_MODE_PANIC:
+ verity_mode = "panicking";
+ dm_verity_mode = "panic_on_corruption";
+ break;
}
new_ret = avb_replace(
slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode);
diff --git a/lib/libavb/avb_descriptor.c b/lib/libavb/avb_descriptor.c
index 56a3a91fc23..f4ff16694e6 100644
--- a/lib/libavb/avb_descriptor.c
+++ b/lib/libavb/avb_descriptor.c
@@ -6,8 +6,6 @@
#include "avb_descriptor.h"
#include "avb_util.h"
#include "avb_vbmeta_image.h"
-#include <log.h>
-#include <malloc.h>
bool avb_descriptor_validate_and_byteswap(const AvbDescriptor* src,
AvbDescriptor* dest) {
@@ -31,6 +29,8 @@ bool avb_descriptor_foreach(const uint8_t* image_data,
const uint8_t* desc_start;
const uint8_t* desc_end;
const uint8_t* p;
+ uint64_t desc_offset = 0;
+ uint64_t desc_size = 0;
if (image_data == NULL) {
avb_error("image_data is NULL\n.");
@@ -42,6 +42,9 @@ bool avb_descriptor_foreach(const uint8_t* image_data,
goto out;
}
+ /* The data is supposed to have been cryptographically verified at this point,
+ * This check is just adding defense in depth.
+ */
if (image_size < sizeof(AvbVBMetaImageHeader)) {
avb_error("Length is smaller than header.\n");
goto out;
@@ -58,23 +61,53 @@ bool avb_descriptor_foreach(const uint8_t* image_data,
header = (const AvbVBMetaImageHeader*)image_data;
image_end = image_data + image_size;
- desc_start = image_data + sizeof(AvbVBMetaImageHeader) +
- avb_be64toh(header->authentication_data_block_size) +
- avb_be64toh(header->descriptors_offset);
+ /* Since the data is supposed to have been cryptographically verified at this
+ * point, being overflow-safe is just for defense.
+ * The following lines are overflow-safe version of:
+ * desc_offset = sizeof(AvbVBMetaImageHeader) +
+ * avb_be64toh(header->authentication_data_block_size)) +
+ * avb_be64toh(header->descriptors_offset)
+ */
+ if (!avb_safe_add(&desc_offset,
+ sizeof(AvbVBMetaImageHeader),
+ avb_be64toh(header->authentication_data_block_size))) {
+ avb_error("Invalid authentication data block size.\n");
+ goto out;
+ }
+ if (!avb_safe_add_to(&desc_offset, avb_be64toh(header->descriptors_offset))) {
+ avb_error("Invalid descriptors offset.\n");
+ goto out;
+ }
+
+ if (desc_offset > (uint64_t)(image_end - image_data)) {
+ avb_error("Descriptors not inside passed-in data.\n");
+ goto out;
+ }
- desc_end = desc_start + avb_be64toh(header->descriptors_size);
+ desc_start = image_data + desc_offset;
- if (desc_start < image_data || desc_start > image_end ||
- desc_end < image_data || desc_end > image_end || desc_end < desc_start) {
+ desc_size = avb_be64toh(header->descriptors_size);
+ if (desc_size > (uint64_t)(image_end - desc_start)) {
avb_error("Descriptors not inside passed-in data.\n");
goto out;
}
+ desc_end = desc_start + desc_size;
+
for (p = desc_start; p < desc_end;) {
- const AvbDescriptor* dh = (const AvbDescriptor*)p;
- avb_assert_aligned(dh);
- uint64_t nb_following = avb_be64toh(dh->num_bytes_following);
+ uint64_t nb_following;
uint64_t nb_total = 0;
+ const AvbDescriptor* dh;
+
+ if (sizeof(AvbDescriptor) > (size_t)(desc_end - p)) {
+ avb_error("Invalid descriptor length.\n");
+ goto out;
+ }
+
+ dh = (const AvbDescriptor*)p;
+ avb_assert_aligned(dh);
+ nb_following = avb_be64toh(dh->num_bytes_following);
+
if (!avb_safe_add(&nb_total, sizeof(AvbDescriptor), nb_following)) {
avb_error("Invalid descriptor length.\n");
goto out;
@@ -85,7 +118,7 @@ bool avb_descriptor_foreach(const uint8_t* image_data,
goto out;
}
- if (nb_total + p < desc_start || nb_total + p > desc_end) {
+ if (nb_total > (uint64_t)(desc_end - p)) {
avb_error("Invalid data in descriptors array.\n");
goto out;
}
@@ -94,10 +127,7 @@ bool avb_descriptor_foreach(const uint8_t* image_data,
goto out;
}
- if (!avb_safe_add_to((uint64_t*)(&p), nb_total)) {
- avb_error("Invalid descriptor length.\n");
- goto out;
- }
+ p += nb_total;
}
ret = true;
diff --git a/lib/libavb/avb_hashtree_descriptor.h b/lib/libavb/avb_hashtree_descriptor.h
index d7f3eb501a3..5f74c465fed 100644
--- a/lib/libavb/avb_hashtree_descriptor.h
+++ b/lib/libavb/avb_hashtree_descriptor.h
@@ -21,9 +21,12 @@ extern "C" {
* AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB: Do not apply the default A/B
* partition logic to this partition. This is intentionally a negative boolean
* because A/B should be both the default and most used in practice.
+ * AVB_HASHTREE_DESCRIPTOR_FLAGS_CHECK_AT_MOST_ONCE: supports to validate hashes
+ * at most once in DM-Verity.
*/
typedef enum {
AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB = (1 << 0),
+ AVB_HASHTREE_DESCRIPTOR_FLAGS_CHECK_AT_MOST_ONCE = (1 << 1),
} AvbHashtreeDescriptorFlags;
/* A descriptor containing information about a dm-verity hashtree.
diff --git a/lib/libavb/avb_property_descriptor.h b/lib/libavb/avb_property_descriptor.h
index 917c58f9fea..b4df1c433a6 100644
--- a/lib/libavb/avb_property_descriptor.h
+++ b/lib/libavb/avb_property_descriptor.h
@@ -18,10 +18,10 @@ extern "C" {
/* A descriptor for properties (free-form key/value pairs).
*
- * Following this struct are |key_num_bytes| bytes of key data,
- * followed by a NUL byte, then |value_num_bytes| bytes of value data,
- * followed by a NUL byte and then enough padding to make the combined
- * size a multiple of 8.
+ * Following this struct are |key_num_bytes| bytes of key data encoded
+ * as UTF-8, followed by a NUL byte, then |value_num_bytes| bytes of
+ * value data, followed by a NUL byte and then enough padding to make
+ * the combined size a multiple of 8.
*/
typedef struct AvbPropertyDescriptor {
AvbDescriptor parent_descriptor;
diff --git a/lib/libavb/avb_rsa.c b/lib/libavb/avb_rsa.c
index d7bf8905be2..b64749980c0 100644
--- a/lib/libavb/avb_rsa.c
+++ b/lib/libavb/avb_rsa.c
@@ -3,6 +3,11 @@
* Copyright (C) 2016 The Android Open Source Project
*/
+/* Copyright (c) 2011 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.
+ */
+
/* Implementation of RSA signature verification which uses a pre-processed
* key for computation. The code extends libmincrypt RSA verification code to
* support multiple RSA key lengths and hash digest algorithms.
@@ -12,7 +17,6 @@
#include "avb_sha.h"
#include "avb_util.h"
#include "avb_vbmeta_image.h"
-#include <malloc.h>
typedef struct IAvbKey {
unsigned int len; /* Length of n[] in number of uint32_t */
diff --git a/lib/libavb/avb_slot_verify.c b/lib/libavb/avb_slot_verify.c
index ae8e1dffa4c..d37ffed0148 100644
--- a/lib/libavb/avb_slot_verify.c
+++ b/lib/libavb/avb_slot_verify.c
@@ -14,8 +14,6 @@
#include "avb_util.h"
#include "avb_vbmeta_image.h"
#include "avb_version.h"
-#include <log.h>
-#include <malloc.h>
/* Maximum number of partitions that can be loaded with avb_slot_verify(). */
#define MAX_NUMBER_OF_LOADED_PARTITIONS 32
@@ -26,6 +24,9 @@
/* Maximum size of a vbmeta image - 64 KiB. */
#define VBMETA_MAX_SIZE (64 * 1024)
+/* Test buffer used to check the existence of a partition. */
+#define TEST_BUFFER_SIZE 1
+
static AvbSlotVerifyResult initialize_persistent_digest(
AvbOps* ops,
const char* part_name,
@@ -72,7 +73,7 @@ static AvbSlotVerifyResult load_full_partition(AvbOps* ops,
/* We are going to implicitly cast image_size from uint64_t to size_t in the
* following code, so we need to make sure that the cast is safe. */
if (image_size != (size_t)(image_size)) {
- avb_errorv(part_name, ": Partition size too large to load.\n", NULL);
+ avb_error(part_name, ": Partition size too large to load.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
}
@@ -83,16 +84,16 @@ static AvbSlotVerifyResult load_full_partition(AvbOps* ops,
if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
} else if (io_ret != AVB_IO_RESULT_OK) {
- avb_errorv(part_name, ": Error loading data from partition.\n", NULL);
+ avb_error(part_name, ": Error loading data from partition.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
}
if (*out_image_buf != NULL) {
+ *out_image_preloaded = true;
if (part_num_read != image_size) {
- avb_errorv(part_name, ": Read incorrect number of bytes.\n", NULL);
+ avb_error(part_name, ": Read incorrect number of bytes.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
}
- *out_image_preloaded = true;
}
}
@@ -112,11 +113,11 @@ static AvbSlotVerifyResult load_full_partition(AvbOps* ops,
if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
} else if (io_ret != AVB_IO_RESULT_OK) {
- avb_errorv(part_name, ": Error loading data from partition.\n", NULL);
+ avb_error(part_name, ": Error loading data from partition.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
}
if (part_num_read != image_size) {
- avb_errorv(part_name, ": Read incorrect number of bytes.\n", NULL);
+ avb_error(part_name, ": Read incorrect number of bytes.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
}
}
@@ -150,7 +151,7 @@ static AvbSlotVerifyResult read_persistent_digest(AvbOps* ops,
size_t stored_digest_size = 0;
if (ops->read_persistent_value == NULL) {
- avb_errorv(part_name, ": Persistent values are not implemented.\n", NULL);
+ avb_error(part_name, ": Persistent values are not implemented.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
}
persistent_value_name =
@@ -187,19 +188,17 @@ static AvbSlotVerifyResult read_persistent_digest(AvbOps* ops,
} else if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE) {
// Treat a missing persistent value as a verification error, which is
// ignoreable, rather than a metadata error which is not.
- avb_errorv(part_name, ": Persistent digest does not exist.\n", NULL);
+ avb_error(part_name, ": Persistent digest does not exist.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
} else if (io_ret == AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE ||
io_ret == AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE) {
- avb_errorv(
- part_name, ": Persistent digest is not of expected size.\n", NULL);
+ avb_error(part_name, ": Persistent digest is not of expected size.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
} else if (io_ret != AVB_IO_RESULT_OK) {
- avb_errorv(part_name, ": Error reading persistent digest.\n", NULL);
+ avb_error(part_name, ": Error reading persistent digest.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
} else if (expected_digest_size != stored_digest_size) {
- avb_errorv(
- part_name, ": Persistent digest is not of expected size.\n", NULL);
+ avb_error(part_name, ": Persistent digest is not of expected size.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
}
return AVB_SLOT_VERIFY_RESULT_OK;
@@ -225,23 +224,21 @@ static AvbSlotVerifyResult initialize_persistent_digest(
}
if (is_device_unlocked) {
- avb_debugv(part_name,
- ": Digest does not exist, device unlocked so not initializing "
- "digest.\n",
- NULL);
+ avb_debug(part_name,
+ ": Digest does not exist, device unlocked so not initializing "
+ "digest.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
}
// Device locked; initialize digest with given initial value.
- avb_debugv(part_name,
- ": Digest does not exist, initializing persistent digest.\n",
- NULL);
+ avb_debug(part_name,
+ ": Digest does not exist, initializing persistent digest.\n");
io_ret = ops->write_persistent_value(
ops, persistent_value_name, digest_size, initial_digest);
if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
} else if (io_ret != AVB_IO_RESULT_OK) {
- avb_errorv(part_name, ": Error initializing persistent digest.\n", NULL);
+ avb_error(part_name, ": Error initializing persistent digest.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
}
@@ -251,9 +248,8 @@ static AvbSlotVerifyResult initialize_persistent_digest(
// initial_digest ensures that this will not recurse again.
ret = read_persistent_digest(ops, part_name, digest_size, NULL, out_digest);
if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
- avb_errorv(part_name,
- ": Reading back initialized persistent digest failed!\n",
- NULL);
+ avb_error(part_name,
+ ": Reading back initialized persistent digest failed!\n");
}
return ret;
}
@@ -356,11 +352,11 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
} else if (io_ret != AVB_IO_RESULT_OK) {
- avb_errorv(part_name, ": Error determining partition size.\n", NULL);
+ avb_error(part_name, ": Error determining partition size.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
goto out;
}
- avb_debugv(part_name, ": Loading entire partition.\n", NULL);
+ avb_debug(part_name, ": Loading entire partition.\n");
}
ret = load_full_partition(
@@ -392,14 +388,14 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
digest = avb_sha512_final(&sha512_ctx);
digest_len = AVB_SHA512_DIGEST_SIZE;
} else {
- avb_errorv(part_name, ": Unsupported hash algorithm.\n", NULL);
+ avb_error(part_name, ": Unsupported hash algorithm.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
if (hash_desc.digest_len == 0) {
/* Expect a match to a persistent digest. */
- avb_debugv(part_name, ": No digest, using persistent digest.\n", NULL);
+ avb_debug(part_name, ": No digest, using persistent digest.\n");
expected_digest_len = digest_len;
expected_digest = expected_digest_buf;
avb_assert(expected_digest_len <= sizeof(expected_digest_buf));
@@ -418,16 +414,14 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
}
if (digest_len != expected_digest_len) {
- avb_errorv(
- part_name, ": Digest in descriptor not of expected size.\n", NULL);
+ avb_error(part_name, ": Digest in descriptor not of expected size.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
if (avb_safe_memcmp(digest, expected_digest, digest_len) != 0) {
- avb_errorv(part_name,
- ": Hash of data does not match digest in descriptor.\n",
- NULL);
+ avb_error(part_name,
+ ": Hash of data does not match digest in descriptor.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
goto out;
}
@@ -441,7 +435,7 @@ out:
image_buf != NULL) {
AvbPartitionData* loaded_partition;
if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) {
- avb_errorv(part_name, ": Too many loaded partitions.\n", NULL);
+ avb_error(part_name, ": Too many loaded partitions.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto fail;
}
@@ -451,6 +445,7 @@ out:
loaded_partition->data_size = image_size;
loaded_partition->data = image_buf;
loaded_partition->preloaded = image_preloaded;
+ loaded_partition->verify_result = ret;
image_buf = NULL;
}
@@ -493,11 +488,11 @@ static AvbSlotVerifyResult load_requested_partitions(
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
} else if (io_ret != AVB_IO_RESULT_OK) {
- avb_errorv(part_name, ": Error determining partition size.\n", NULL);
+ avb_error(part_name, ": Error determining partition size.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
goto out;
}
- avb_debugv(part_name, ": Loading entire partition.\n", NULL);
+ avb_debug(part_name, ": Loading entire partition.\n");
ret = load_full_partition(
ops, part_name, image_size, &image_buf, &image_preloaded);
@@ -507,7 +502,7 @@ static AvbSlotVerifyResult load_requested_partitions(
/* Move to slot_data. */
if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) {
- avb_errorv(part_name, ": Too many loaded partitions.\n", NULL);
+ avb_error(part_name, ": Too many loaded partitions.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
}
@@ -544,18 +539,19 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
AvbSlotVerifyFlags flags,
bool allow_verification_error,
AvbVBMetaImageFlags toplevel_vbmeta_flags,
- int rollback_index_location,
+ uint32_t rollback_index_location,
const char* partition_name,
size_t partition_name_len,
const uint8_t* expected_public_key,
size_t expected_public_key_length,
AvbSlotVerifyData* slot_data,
AvbAlgorithmType* out_algorithm_type,
- AvbCmdlineSubstList* out_additional_cmdline_subst) {
+ AvbCmdlineSubstList* out_additional_cmdline_subst,
+ bool use_ab_suffix) {
char full_partition_name[AVB_PART_NAME_MAX_SIZE];
AvbSlotVerifyResult ret;
AvbIOResult io_ret;
- size_t vbmeta_offset;
+ uint64_t vbmeta_offset;
size_t vbmeta_size;
uint8_t* vbmeta_buf = NULL;
size_t vbmeta_num_read;
@@ -599,17 +595,27 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
-
- /* Construct full partition name e.g. system_a. */
- if (!avb_str_concat(full_partition_name,
+ if (!use_ab_suffix) {
+ /*No ab_suffix, just copy the partition name as is.*/
+ if (partition_name_len >= AVB_PART_NAME_MAX_SIZE) {
+ avb_error("Partition name does not fit.\n");
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ goto out;
+ }
+ avb_memcpy(full_partition_name, partition_name, partition_name_len);
+ full_partition_name[partition_name_len] = '\0';
+ }else{
+ /* Construct full partition name e.g. system_a. */
+ if (!avb_str_concat(full_partition_name,
sizeof full_partition_name,
partition_name,
partition_name_len,
ab_suffix,
avb_strlen(ab_suffix))) {
- avb_error("Partition name and suffix does not fit.\n");
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
- goto out;
+ avb_error("Partition name and suffix does not fit.\n");
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ goto out;
+ }
}
/* If we're loading from the main vbmeta partition, the vbmeta struct is in
@@ -635,7 +641,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
} else if (io_ret != AVB_IO_RESULT_OK) {
- avb_errorv(full_partition_name, ": Error loading footer.\n", NULL);
+ avb_error(full_partition_name, ": Error loading footer.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
goto out;
}
@@ -643,43 +649,67 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf,
&footer)) {
- avb_debugv(full_partition_name, ": No footer detected.\n", NULL);
+ avb_debug(full_partition_name, ": No footer detected.\n");
} else {
/* Basic footer sanity check since the data is untrusted. */
if (footer.vbmeta_size > VBMETA_MAX_SIZE) {
- avb_errorv(
- full_partition_name, ": Invalid vbmeta size in footer.\n", NULL);
+ avb_error(full_partition_name, ": Invalid vbmeta size in footer.\n");
} else {
vbmeta_offset = footer.vbmeta_offset;
vbmeta_size = footer.vbmeta_size;
}
}
+ } else {
+ uint64_t partition_size = 0;
+ io_ret =
+ ops->get_size_of_partition(ops, full_partition_name, &partition_size);
+ if (io_ret == AVB_IO_RESULT_OK) {
+ if (partition_size < vbmeta_size && partition_size > 0) {
+ avb_debug(full_partition_name,
+ ": Using partition size as vbmeta size\n");
+ vbmeta_size = partition_size;
+ }
+ } else {
+ avb_debug(full_partition_name, ": Failed to get partition size\n");
+ // libavb might fall back to other partitions if current vbmeta partition
+ // isn't found. So AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION is recoverable,
+ // but other errors are not.
+ if (io_ret != AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ goto out;
+ }
+ }
}
- vbmeta_buf = avb_malloc(vbmeta_size);
- if (vbmeta_buf == NULL) {
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
- goto out;
- }
+ /* Use result from previous I/O operation to check the existence of the
+ * partition before allocating the big chunk of memory on heap
+ * for vbmeta later. `io_ret` will be used later to decide whether
+ * to fallback on the `boot` partition.
+ */
+ if (io_ret != AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) {
+ vbmeta_buf = avb_malloc(vbmeta_size);
+ if (vbmeta_buf == NULL) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
- if (vbmeta_offset != 0) {
- avb_debugv("Loading vbmeta struct in footer from partition '",
- full_partition_name,
- "'.\n",
- NULL);
- } else {
- avb_debugv("Loading vbmeta struct from partition '",
- full_partition_name,
- "'.\n",
- NULL);
- }
+ if (vbmeta_offset != 0) {
+ avb_debug("Loading vbmeta struct in footer from partition '",
+ full_partition_name,
+ "'.\n");
+ } else {
+ avb_debug("Loading vbmeta struct from partition '",
+ full_partition_name,
+ "'.\n");
+ }
- io_ret = ops->read_from_partition(ops,
- full_partition_name,
- vbmeta_offset,
- vbmeta_size,
- vbmeta_buf,
- &vbmeta_num_read);
+ io_ret = ops->read_from_partition(ops,
+ full_partition_name,
+ vbmeta_offset,
+ vbmeta_size,
+ vbmeta_buf,
+ &vbmeta_num_read);
+ }
if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
@@ -689,9 +719,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
*/
if (is_main_vbmeta && io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION &&
!look_for_vbmeta_footer) {
- avb_debugv(full_partition_name,
- ": No such partition. Trying 'boot' instead.\n",
- NULL);
+ avb_debug(full_partition_name,
+ ": No such partition. Trying 'boot' instead.\n");
ret = load_and_verify_vbmeta(ops,
requested_partitions,
ab_suffix,
@@ -705,10 +734,11 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
0 /* expected_public_key_length */,
slot_data,
out_algorithm_type,
- out_additional_cmdline_subst);
+ out_additional_cmdline_subst,
+ use_ab_suffix);
goto out;
} else {
- avb_errorv(full_partition_name, ": Error loading vbmeta data.\n", NULL);
+ avb_error(full_partition_name, ": Error loading vbmeta data.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
goto out;
}
@@ -729,11 +759,10 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
- avb_errorv(full_partition_name,
- ": Error verifying vbmeta image: ",
- avb_vbmeta_verify_result_to_string(vbmeta_ret),
- "\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Error verifying vbmeta image: ",
+ avb_vbmeta_verify_result_to_string(vbmeta_ret),
+ "\n");
if (!allow_verification_error) {
goto out;
}
@@ -742,17 +771,15 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
/* No way to continue this case. */
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
- avb_errorv(full_partition_name,
- ": Error verifying vbmeta image: invalid vbmeta header\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Error verifying vbmeta image: invalid vbmeta header\n");
goto out;
case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION:
/* No way to continue this case. */
ret = AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION;
- avb_errorv(full_partition_name,
- ": Error verifying vbmeta image: unsupported AVB version\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Error verifying vbmeta image: unsupported AVB version\n");
goto out;
}
@@ -766,14 +793,16 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
} else {
if (vbmeta_header.flags != 0) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
- avb_errorv(full_partition_name,
- ": chained vbmeta image has non-zero flags\n",
- NULL);
+ avb_error(full_partition_name,
+ ": chained vbmeta image has non-zero flags\n");
goto out;
}
}
uint32_t rollback_index_location_to_use = rollback_index_location;
+ if (is_main_vbmeta) {
+ rollback_index_location_to_use = vbmeta_header.rollback_index_location;
+ }
/* Check if key used to make signature matches what is expected. */
if (pk_data != NULL) {
@@ -781,10 +810,9 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
avb_assert(!is_main_vbmeta);
if (expected_public_key_length != pk_len ||
avb_safe_memcmp(expected_public_key, pk_data, pk_len) != 0) {
- avb_errorv(full_partition_name,
- ": Public key used to sign data does not match key in chain "
- "partition descriptor.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Public key used to sign data does not match key in chain "
+ "partition descriptor.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
if (!allow_verification_error) {
goto out;
@@ -827,16 +855,14 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
} else if (io_ret != AVB_IO_RESULT_OK) {
- avb_errorv(full_partition_name,
- ": Error while checking public key used to sign data.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Error while checking public key used to sign data.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
goto out;
}
if (!key_is_trusted) {
- avb_errorv(full_partition_name,
- ": Public key used to sign data rejected.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Public key used to sign data rejected.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
if (!allow_verification_error) {
goto out;
@@ -852,17 +878,15 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
} else if (io_ret != AVB_IO_RESULT_OK) {
- avb_errorv(full_partition_name,
- ": Error getting rollback index for location.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Error getting rollback index for location.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
goto out;
}
if (vbmeta_header.rollback_index < stored_rollback_index) {
- avb_errorv(
+ avb_error(
full_partition_name,
- ": Image rollback index is less than the stored rollback index.\n",
- NULL);
+ ": Image rollback index is less than the stored rollback index.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX;
if (!allow_verification_error) {
goto out;
@@ -878,7 +902,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
}
}
if (slot_data->num_vbmeta_images == MAX_NUMBER_OF_VBMETA_IMAGES) {
- avb_errorv(full_partition_name, ": Too many vbmeta images.\n", NULL);
+ avb_error(full_partition_name, ": Too many vbmeta images.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
}
@@ -902,8 +926,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
*/
if (vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
AvbSlotVerifyResult sub_ret;
- avb_debugv(
- full_partition_name, ": VERIFICATION_DISABLED bit is set.\n", NULL);
+ avb_debug(full_partition_name, ": VERIFICATION_DISABLED bit is set.\n");
/* If load_requested_partitions() fail it is always a fatal
* failure (e.g. ERROR_INVALID_ARGUMENT, ERROR_OOM, etc.) rather
* than recoverable (e.g. one where result_should_continue()
@@ -936,7 +959,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
AvbDescriptor desc;
if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
- avb_errorv(full_partition_name, ": Descriptor is invalid.\n", NULL);
+ avb_error(full_partition_name, ": Descriptor is invalid.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
@@ -966,31 +989,32 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
/* Only allow CHAIN_PARTITION descriptors in the main vbmeta image. */
if (!is_main_vbmeta) {
- avb_errorv(full_partition_name,
- ": Encountered chain descriptor not in main image.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Encountered chain descriptor not in main image.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
if (!avb_chain_partition_descriptor_validate_and_byteswap(
(AvbChainPartitionDescriptor*)descriptors[n], &chain_desc)) {
- avb_errorv(full_partition_name,
- ": Chain partition descriptor is invalid.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Chain partition descriptor is invalid.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
if (chain_desc.rollback_index_location == 0) {
- avb_errorv(full_partition_name,
- ": Chain partition has invalid "
- "rollback_index_location field.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Chain partition has invalid "
+ "rollback_index_location field.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
-
+ if ((chain_desc.flags & AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB) != 0){
+ use_ab_suffix = false;
+ }else{
+ use_ab_suffix = true;
+ }
chain_partition_name = ((const uint8_t*)descriptors[n]) +
sizeof(AvbChainPartitionDescriptor);
chain_public_key = chain_partition_name + chain_desc.partition_name_len;
@@ -1009,7 +1033,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
chain_desc.public_key_len,
slot_data,
NULL, /* out_algorithm_type */
- NULL /* out_additional_cmdline_subst */);
+ NULL, /* out_additional_cmdline_subst */
+ use_ab_suffix);
if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
ret = sub_ret;
if (!result_should_continue(ret)) {
@@ -1026,9 +1051,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
if (!avb_kernel_cmdline_descriptor_validate_and_byteswap(
(AvbKernelCmdlineDescriptor*)descriptors[n],
&kernel_cmdline_desc)) {
- avb_errorv(full_partition_name,
- ": Kernel cmdline descriptor is invalid.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Kernel cmdline descriptor is invalid.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
@@ -1038,9 +1062,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
if (!avb_validate_utf8(kernel_cmdline,
kernel_cmdline_desc.kernel_cmdline_length)) {
- avb_errorv(full_partition_name,
- ": Kernel cmdline is not valid UTF-8.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Kernel cmdline is not valid UTF-8.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
@@ -1100,8 +1123,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
if (!avb_hashtree_descriptor_validate_and_byteswap(
(AvbHashtreeDescriptor*)descriptors[n], &hashtree_desc)) {
- avb_errorv(
- full_partition_name, ": Hashtree descriptor is invalid.\n", NULL);
+ avb_error(full_partition_name, ": Hashtree descriptor is invalid.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
@@ -1155,7 +1177,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
"sha512") == 0) {
digest_len = AVB_SHA512_DIGEST_SIZE;
} else {
- avb_errorv(part_name, ": Unsupported hash algorithm.\n", NULL);
+ avb_error(part_name, ": Unsupported hash algorithm.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
@@ -1188,15 +1210,14 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
}
}
- if (rollback_index_location < 0 ||
- rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
- avb_errorv(
- full_partition_name, ": Invalid rollback_index_location.\n", NULL);
+ if (rollback_index_location_to_use >=
+ AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
+ avb_error(full_partition_name, ": Invalid rollback_index_location.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
- slot_data->rollback_indexes[rollback_index_location] =
+ slot_data->rollback_indexes[rollback_index_location_to_use] =
vbmeta_header.rollback_index;
if (out_algorithm_type != NULL) {
@@ -1315,7 +1336,7 @@ out:
static bool has_system_partition(AvbOps* ops, const char* ab_suffix) {
char part_name[AVB_PART_NAME_MAX_SIZE];
- char* system_part_name = "system";
+ const char* system_part_name = "system";
char guid_buf[37];
AvbIOResult io_ret;
@@ -1348,7 +1369,7 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
AvbSlotVerifyFlags flags,
AvbHashtreeErrorMode hashtree_error_mode,
AvbSlotVerifyData** out_data) {
- AvbSlotVerifyResult ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+ AvbSlotVerifyResult ret;
AvbSlotVerifyData* slot_data = NULL;
AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE;
bool using_boot_for_vbmeta = false;
@@ -1456,7 +1477,8 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
0 /* expected_public_key_length */,
slot_data,
&algorithm_type,
- additional_cmdline_subst);
+ additional_cmdline_subst,
+ true /*use_ab_suffix*/);
if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
goto fail;
}
@@ -1477,7 +1499,8 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
0 /* expected_public_key_length */,
slot_data,
&algorithm_type,
- additional_cmdline_subst);
+ additional_cmdline_subst,
+ true /*use_ab_suffix*/);
if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
goto fail;
}
@@ -1686,7 +1709,7 @@ const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result) {
return ret;
}
-void avb_slot_verify_data_calculate_vbmeta_digest(AvbSlotVerifyData* data,
+void avb_slot_verify_data_calculate_vbmeta_digest(const AvbSlotVerifyData* data,
AvbDigestType digest_type,
uint8_t* out_digest) {
bool ret = false;
diff --git a/lib/libavb/avb_slot_verify.h b/lib/libavb/avb_slot_verify.h
index 8d0fa536935..b86c96cbd06 100644
--- a/lib/libavb/avb_slot_verify.h
+++ b/lib/libavb/avb_slot_verify.h
@@ -69,7 +69,8 @@ typedef enum {
AVB_HASHTREE_ERROR_MODE_RESTART,
AVB_HASHTREE_ERROR_MODE_EIO,
AVB_HASHTREE_ERROR_MODE_LOGGING,
- AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO
+ AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO,
+ AVB_HASHTREE_ERROR_MODE_PANIC
} AvbHashtreeErrorMode;
/* Flags that influence how avb_slot_verify() works.
@@ -138,6 +139,7 @@ typedef struct {
uint8_t* data;
size_t data_size;
bool preloaded;
+ AvbSlotVerifyResult verify_result;
} AvbPartitionData;
/* AvbVBMetaData contains a vbmeta struct loaded from a partition when
@@ -291,7 +293,7 @@ typedef struct {
* in |out_digest| which must be large enough to hold a digest
* of the requested type.
*/
-void avb_slot_verify_data_calculate_vbmeta_digest(AvbSlotVerifyData* data,
+void avb_slot_verify_data_calculate_vbmeta_digest(const AvbSlotVerifyData* data,
AvbDigestType digest_type,
uint8_t* out_digest);
diff --git a/lib/libavb/avb_util.c b/lib/libavb/avb_util.c
index 8719ede15a7..25af46075a7 100644
--- a/lib/libavb/avb_util.c
+++ b/lib/libavb/avb_util.c
@@ -4,11 +4,17 @@
*/
#include "avb_util.h"
-#include <log.h>
-#include <malloc.h>
#include <stdarg.h>
+uint16_t avb_be16toh(uint16_t in) {
+ uint8_t* d = (uint8_t*)&in;
+ uint16_t ret;
+ ret = ((uint16_t)d[0]) << 8;
+ ret |= ((uint16_t)d[1]);
+ return ret;
+}
+
uint32_t avb_be32toh(uint32_t in) {
uint8_t* d = (uint8_t*)&in;
uint32_t ret;
@@ -33,6 +39,17 @@ uint64_t avb_be64toh(uint64_t in) {
return ret;
}
+/* Converts a 16-bit unsigned integer from host to big-endian byte order. */
+uint16_t avb_htobe16(uint16_t in) {
+ union {
+ uint16_t word;
+ uint8_t bytes[2];
+ } ret;
+ ret.bytes[0] = (in >> 8) & 0xff;
+ ret.bytes[1] = in & 0xff;
+ return ret.word;
+}
+
/* Converts a 32-bit unsigned integer from host to big-endian byte order. */
uint32_t avb_htobe32(uint32_t in) {
union {
@@ -159,6 +176,12 @@ bool avb_str_concat(char* buf,
size_t str2_len) {
uint64_t combined_len;
+ // Doesn't make sense to pass 0 for buf_size since there's
+ // no room for the terminating NUL byte.
+ if (buf_size == 0) {
+ return false;
+ }
+
if (!avb_safe_add(&combined_len, str1_len, str2_len)) {
avb_error("Overflow when adding string sizes.\n");
return false;
@@ -411,3 +434,22 @@ char* avb_bin2hex(const uint8_t* data, size_t data_len) {
hex_data[n * 2] = '\0';
return hex_data;
}
+
+size_t avb_uint64_to_base10(uint64_t value,
+ char digits[AVB_MAX_DIGITS_UINT64]) {
+ char rev_digits[AVB_MAX_DIGITS_UINT64];
+ size_t n, num_digits;
+
+ for (num_digits = 0; num_digits < AVB_MAX_DIGITS_UINT64 - 1;) {
+ rev_digits[num_digits++] = avb_div_by_10(&value) + '0';
+ if (value == 0) {
+ break;
+ }
+ }
+
+ for (n = 0; n < num_digits; n++) {
+ digits[n] = rev_digits[num_digits - 1 - n];
+ }
+ digits[n] = '\0';
+ return n;
+}
diff --git a/lib/libavb/avb_util.h b/lib/libavb/avb_util.h
index 26dc6b045ac..d0612cc97f3 100644
--- a/lib/libavb/avb_util.h
+++ b/lib/libavb/avb_util.h
@@ -16,9 +16,44 @@
extern "C" {
#endif
+#define AVB_CONCAT(x, y) x##y
#define AVB_STRINGIFY(x) #x
#define AVB_TO_STRING(x) AVB_STRINGIFY(x)
+#define AVB__COUNT_ARGS(_0, _1, _2, _3, _4, _5, _6, _7, x, ...) x
+#define AVB_COUNT_ARGS(...) \
+ AVB__COUNT_ARGS(, ##__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)
+
+#define AVB__REPEAT0(x)
+#define AVB__REPEAT1(x) x
+#define AVB__REPEAT2(x) AVB__REPEAT1(x) x
+#define AVB__REPEAT3(x) AVB__REPEAT2(x) x
+#define AVB__REPEAT4(x) AVB__REPEAT3(x) x
+#define AVB__REPEAT5(x) AVB__REPEAT4(x) x
+#define AVB__REPEAT6(x) AVB__REPEAT5(x) x
+#define AVB__REPEAT7(x) AVB__REPEAT6(x) x
+#define AVB__REPEAT(n, x) AVB_CONCAT(AVB__REPEAT, n)(x)
+#define AVB_REPEAT(n, x) AVB__REPEAT(n, x)
+
+#ifdef AVB_USE_PRINTF_LOGS
+#define AVB_LOG(level, message, ...) \
+ avb_printf("%s:%d: " level \
+ ": " AVB_REPEAT(AVB_COUNT_ARGS(message, ##__VA_ARGS__), "%s"), \
+ avb_basename(__FILE__), \
+ __LINE__, \
+ message, \
+ ##__VA_ARGS__)
+#else
+#define AVB_LOG(level, message, ...) \
+ avb_printv(avb_basename(__FILE__), \
+ ":", \
+ AVB_TO_STRING(__LINE__), \
+ ": " level ": ", \
+ message, \
+ ##__VA_ARGS__, \
+ NULL)
+#endif
+
#ifdef AVB_ENABLE_DEBUG
/* Aborts the program if |expr| is false.
*
@@ -30,21 +65,28 @@ extern "C" {
avb_fatal("assert fail: " #expr "\n"); \
} \
} while (0)
-#else
-#define avb_assert(expr)
-#endif
/* Aborts the program if reached.
*
* This has no effect unless AVB_ENABLE_DEBUG is defined.
*/
-#ifdef AVB_ENABLE_DEBUG
#define avb_assert_not_reached() \
do { \
avb_fatal("assert_not_reached()\n"); \
} while (0)
+
+/* Print functions, used for diagnostics.
+ *
+ * These have no effect unless AVB_ENABLE_DEBUG is defined.
+ */
+#define avb_debug(message, ...) \
+ do { \
+ AVB_LOG("DEBUG", message, ##__VA_ARGS__); \
+ } while (0)
#else
+#define avb_assert(expr)
#define avb_assert_not_reached()
+#define avb_debug(message, ...)
#endif
/* Aborts the program if |addr| is not word-aligned.
@@ -54,85 +96,42 @@ extern "C" {
#define avb_assert_aligned(addr) \
avb_assert((((uintptr_t)addr) & (AVB_ALIGNMENT_SIZE - 1)) == 0)
-#ifdef AVB_ENABLE_DEBUG
-/* Print functions, used for diagnostics.
- *
- * These have no effect unless AVB_ENABLE_DEBUG is defined.
- */
-#define avb_debug(message) \
- do { \
- avb_printv(avb_basename(__FILE__), \
- ":", \
- AVB_TO_STRING(__LINE__), \
- ": DEBUG: ", \
- message, \
- NULL); \
- } while (0)
-#define avb_debugv(message, ...) \
- do { \
- avb_printv(avb_basename(__FILE__), \
- ":", \
- AVB_TO_STRING(__LINE__), \
- ": DEBUG: ", \
- message, \
- ##__VA_ARGS__); \
- } while (0)
-#else
-#define avb_debug(message)
-#define avb_debugv(message, ...)
-#endif
-
/* Prints out a message. This is typically used if a runtime-error
* occurs.
*/
-#define avb_error(message) \
- do { \
- avb_printv(avb_basename(__FILE__), \
- ":", \
- AVB_TO_STRING(__LINE__), \
- ": ERROR: ", \
- message, \
- NULL); \
- } while (0)
-#define avb_errorv(message, ...) \
- do { \
- avb_printv(avb_basename(__FILE__), \
- ":", \
- AVB_TO_STRING(__LINE__), \
- ": ERROR: ", \
- message, \
- ##__VA_ARGS__); \
+#define avb_error(message, ...) \
+ do { \
+ AVB_LOG("ERROR", message, ##__VA_ARGS__); \
} while (0)
/* Prints out a message and calls avb_abort().
*/
-#define avb_fatal(message) \
- do { \
- avb_printv(avb_basename(__FILE__), \
- ":", \
- AVB_TO_STRING(__LINE__), \
- ": FATAL: ", \
- message, \
- NULL); \
- avb_abort(); \
- } while (0)
-#define avb_fatalv(message, ...) \
- do { \
- avb_printv(avb_basename(__FILE__), \
- ":", \
- AVB_TO_STRING(__LINE__), \
- ": FATAL: ", \
- message, \
- ##__VA_ARGS__); \
- avb_abort(); \
+#define avb_fatal(message, ...) \
+ do { \
+ AVB_LOG("FATAL", message, ##__VA_ARGS__); \
+ avb_abort(); \
} while (0)
+#ifndef AVB_USE_PRINTF_LOGS
+/* Deprecated legacy logging functions -- kept for client compatibility.
+ */
+#define avb_debugv(message, ...) avb_debug(message, ##__VA_ARGS__)
+#define avb_errorv(message, ...) avb_error(message, ##__VA_ARGS__)
+#define avb_fatalv(message, ...) avb_fatal(message, ##__VA_ARGS__)
+#endif
+
+/* Converts a 16-bit unsigned integer from big-endian to host byte order. */
+uint16_t avb_be16toh(uint16_t in) AVB_ATTR_WARN_UNUSED_RESULT;
+
/* Converts a 32-bit unsigned integer from big-endian to host byte order. */
uint32_t avb_be32toh(uint32_t in) AVB_ATTR_WARN_UNUSED_RESULT;
/* Converts a 64-bit unsigned integer from big-endian to host byte order. */
uint64_t avb_be64toh(uint64_t in) AVB_ATTR_WARN_UNUSED_RESULT;
+/* Converts a 16-bit unsigned integer from host to big-endian byte order. */
+uint16_t avb_htobe16(uint16_t in) AVB_ATTR_WARN_UNUSED_RESULT;
+
/* Converts a 32-bit unsigned integer from host to big-endian byte order. */
uint32_t avb_htobe32(uint32_t in) AVB_ATTR_WARN_UNUSED_RESULT;
@@ -261,6 +260,11 @@ void avb_uppercase(char* str);
*/
char* avb_bin2hex(const uint8_t* data, size_t data_len);
+/* Writes |value| to |digits| in base 10 followed by a NUL byte.
+ * Returns number of characters written excluding the NUL byte.
+ */
+#define AVB_MAX_DIGITS_UINT64 32
+size_t avb_uint64_to_base10(uint64_t value, char digits[AVB_MAX_DIGITS_UINT64]);
#ifdef __cplusplus
}
#endif
diff --git a/lib/libavb/avb_vbmeta_image.c b/lib/libavb/avb_vbmeta_image.c
index 384f5ac19e5..44d75fda322 100644
--- a/lib/libavb/avb_vbmeta_image.c
+++ b/lib/libavb/avb_vbmeta_image.c
@@ -254,6 +254,7 @@ void avb_vbmeta_image_header_to_host_byte_order(const AvbVBMetaImageHeader* src,
dest->rollback_index = avb_be64toh(dest->rollback_index);
dest->flags = avb_be32toh(dest->flags);
+ dest->rollback_index_location = avb_be32toh(dest->rollback_index_location);
}
const char* avb_vbmeta_verify_result_to_string(AvbVBMetaVerifyResult result) {
diff --git a/lib/libavb/avb_vbmeta_image.h b/lib/libavb/avb_vbmeta_image.h
index 24f8519ff60..221ccd1d383 100644
--- a/lib/libavb/avb_vbmeta_image.h
+++ b/lib/libavb/avb_vbmeta_image.h
@@ -157,10 +157,12 @@ typedef struct AvbVBMetaImageHeader {
*/
uint32_t flags;
- /* 124: Reserved to ensure |release_string| start on a 16-byte
- * boundary. Must be set to zeroes.
+ /* 124: The location of the rollback index defined in this header.
+ * Only valid for the main vbmeta. For chained partitions, the rollback
+ * index location must be specified in the AvbChainPartitionDescriptor
+ * and this value must be set to 0.
*/
- uint8_t reserved0[4];
+ uint32_t rollback_index_location;
/* 128: The release string from avbtool, e.g. "avbtool 1.0.0" or
* "avbtool 1.0.0 xyz_board Git-234abde89". Is guaranteed to be NUL
diff --git a/lib/libavb/avb_version.h b/lib/libavb/avb_version.h
index 57c6ece851c..e6f7798769d 100644
--- a/lib/libavb/avb_version.h
+++ b/lib/libavb/avb_version.h
@@ -18,7 +18,7 @@ extern "C" {
/* The version number of AVB - keep in sync with avbtool. */
#define AVB_VERSION_MAJOR 1
-#define AVB_VERSION_MINOR 1
+#define AVB_VERSION_MINOR 3
#define AVB_VERSION_SUB 0
/* Returns a NUL-terminated string for the libavb version in use. The
diff --git a/lib/lmb.c b/lib/lmb.c
index 77440a48486..ca00047f624 100644
--- a/lib/lmb.c
+++ b/lib/lmb.c
@@ -286,7 +286,7 @@ static long _lmb_free(struct alist *lmb_rgn_lst, phys_addr_t base,
/* Didn't find the region */
if (i == lmb_rgn_lst->count)
- return -1;
+ return -EFAULT;
/* Check to see if we are removing entire region */
if (rgnbegin == base && rgnend == end) {
@@ -752,9 +752,11 @@ static int _lmb_alloc_addr(phys_addr_t base, phys_size_t size, u32 flags)
base + size - 1, 1))
/* ok, reserve the memory */
return lmb_reserve(base, size, flags);
+
+ return -EINVAL;
}
- return -EINVAL;
+ return -EFAULT;
}
int lmb_alloc_mem(enum lmb_mem_type type, u64 align, phys_addr_t *addr,
diff --git a/lib/lwip/u-boot/lwipopts.h b/lib/lwip/u-boot/lwipopts.h
index 8dae004f1a2..1c1adc57c6b 100644
--- a/lib/lwip/u-boot/lwipopts.h
+++ b/lib/lwip/u-boot/lwipopts.h
@@ -72,6 +72,17 @@
#define PBUF_POOL_RESERVE 4
#define TFTP_BLOCKSIZE_THRESHOLD 4096
+/*
+ * Match the legacy U-Boot TFTP filename buffer. The legacy
+ * CONFIG_TFTP_FILE_NAME_MAX_LEN value is a buffer size including the trailing
+ * NUL, while lwIP's TFTP_MAX_FILENAME_LEN is the usable string length.
+ */
+#ifdef CONFIG_TFTP_FILE_NAME_MAX_LEN
+#define TFTP_MAX_FILENAME_LEN (CONFIG_TFTP_FILE_NAME_MAX_LEN - 1)
+#else
+#define TFTP_MAX_FILENAME_LEN 127
+#endif
+
#if defined(CONFIG_TFTP_BLOCKSIZE) && (CONFIG_TFTP_BLOCKSIZE > TFTP_BLOCKSIZE_THRESHOLD)
#define PBUF_POOL_SIZE (((CONFIG_TFTP_BLOCKSIZE + (IP_FRAG_MTU_USABLE - 1)) / \
IP_FRAG_MTU_USABLE) + PBUF_POOL_HEADROOM)
diff --git a/lib/pmbus.c b/lib/pmbus.c
new file mode 100644
index 00000000000..62a66593638
--- /dev/null
+++ b/lib/pmbus.c
@@ -0,0 +1,877 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2026 Free Mobile, Vincent Jardin
+ *
+ * PMBus 1.x decoders, transport helpers, and standard status bit
+ * tables for U-Boot. See include/pmbus.h for the API surface and
+ * doc/develop/pmbus.rst for the porting guide.
+ *
+ * Decoder math is implemented from the PMBus 1.3 specification:
+ * 1. Part I (transport): see
+ * doc/PMBus/PMBus_Specification_Rev_1_3_1_Part_I_20150313.{pdf,txt}
+ * 2. Part II (commands): see
+ * doc/PMBus/PMBus_Specification_Rev_1_3_1_Part_II_20150313.{pdf,txt}
+ *
+ * Reference Linux implementation: linux/drivers/hwmon/pmbus/pmbus_core.c
+ * (the kernel side `struct pmbus_data` caching and hwmon publication
+ * layers do not apply; only the arithmetic carries over).
+ *
+ * No code in this file may reference a specific board, SoC, or
+ * product. Per chip quirks (MPS DIRECT format LSBs, vendor registers,
+ * VID coercion, ADDR_VBOOT auto promotion, and the like) belong in
+ * per chip drivers under drivers/power/regulator/ or in board local
+ * files under board/<vendor>/<board>/.
+ */
+
+#include <ctype.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <pmbus.h>
+#include <limits.h>
+#include <linux/bitops.h>
+#include <power/regulator.h>
+
+static int pmbus_sign_extend(unsigned int v, unsigned int width)
+{
+ unsigned int mask = (1U << width) - 1U;
+ unsigned int sign = 1U << (width - 1U);
+
+ v &= mask;
+ if (v & sign)
+ v |= ~mask;
+ return (int)v;
+}
+
+s64 pmbus_reg2data_linear11(u16 raw)
+{
+ int mantissa = pmbus_sign_extend(raw & PB_LINEAR11_MANT_MASK,
+ PB_LINEAR11_MANT_BITS);
+ int exponent = pmbus_sign_extend((raw >> PB_LINEAR11_EXP_SHIFT) &
+ PB_LINEAR11_EXP_MASK,
+ PB_LINEAR11_EXP_BITS);
+ s64 micro;
+
+ /* Engineering value = mantissa * 2^exponent, scaled to micro units. */
+ micro = (s64)mantissa * 1000000LL;
+ if (exponent >= 0)
+ micro <<= exponent;
+ else
+ micro >>= -exponent;
+ return micro;
+}
+
+s64 pmbus_reg2data_linear16(u16 raw, u8 vout_mode)
+{
+ int exponent;
+ s64 micro;
+
+ /*
+ * VOUT_MODE bits[7:5] = mode; bits[4:0] = parameter. Linear mode
+ * (000) treats bits[4:0] as the signed 5-bit exponent. For other
+ * modes the caller must dispatch elsewhere.
+ */
+ if ((vout_mode & PB_VOUT_MODE_MODE_MASK) != PB_VOUT_MODE_LINEAR)
+ return 0;
+
+ exponent = pmbus_sign_extend(vout_mode & PB_VOUT_MODE_PARAM_MASK, 5);
+
+ /* Mantissa is unsigned 16-bit; scale to micro units. */
+ micro = (s64)raw * 1000000LL;
+ if (exponent >= 0)
+ micro <<= exponent;
+ else
+ micro >>= -exponent;
+ return micro;
+}
+
+s64 pmbus_reg2data_direct(s16 raw, int m, int b, int R)
+{
+ s64 acc;
+
+ if (m == 0)
+ return 0;
+
+ /*
+ * PMBus Part II sec 8.4: Y = (1/m) * (X * 10^-R - b)
+ *
+ * Pre scale acc to micro units so the final integer division by
+ * m absorbs the rounding loss into the least significant micro
+ * digit rather than into a coarser place.
+ */
+ acc = (s64)raw * 1000000LL;
+
+ /* Apply 10^-R: positive R means divide; negative R means multiply. */
+ while (R > 0) {
+ acc /= 10;
+ R--;
+ }
+ while (R < 0) {
+ acc *= 10;
+ R++;
+ }
+
+ /* Subtract the offset b, also in micro units. */
+ acc -= (s64)b * 1000000LL;
+
+ /* Final: divide by m. */
+ acc /= m;
+ return acc;
+}
+
+u16 pmbus_data2reg_linear16(s64 micro, u8 vout_mode)
+{
+ int exponent;
+ s64 raw;
+
+ if ((vout_mode & PB_VOUT_MODE_MODE_MASK) != PB_VOUT_MODE_LINEAR)
+ return 0;
+
+ exponent = pmbus_sign_extend(vout_mode & PB_VOUT_MODE_PARAM_MASK, 5);
+
+ /* raw = micro / (2^exponent * 10^6). */
+ raw = micro;
+ if (exponent >= 0)
+ raw >>= exponent;
+ else
+ raw <<= -exponent;
+ raw /= 1000000LL;
+
+ if (raw < 0)
+ raw = 0;
+ if (raw > U16_MAX)
+ raw = U16_MAX;
+ return (u16)raw;
+}
+
+u16 pmbus_data2reg_direct(s64 micro, int m, int b, int R)
+{
+ s64 acc;
+
+ if (m == 0)
+ return 0;
+
+ /*
+ * Inverse of pmbus_reg2data_direct(): X = (m * Y + b) * 10^R.
+ * Work in micro units throughout: acc = m * Y_micro + b * 10^6,
+ * then scale by 10^R, finally divide by 10^6 to get the raw
+ * chip count. Order chosen to match the decoder's quantisation
+ * pattern so a round trip (data2reg then reg2data) returns the
+ * input within +/- one LSB.
+ */
+ acc = (s64)m * micro + (s64)b * 1000000LL;
+
+ while (R > 0) {
+ acc *= 10;
+ R--;
+ }
+ while (R < 0) {
+ acc /= 10;
+ R++;
+ }
+
+ acc /= 1000000LL;
+
+ /* PMBus 1.3 Part II sec 8.4 mandates a signed 16 bit raw value. */
+ if (acc > S16_MAX)
+ acc = S16_MAX;
+ if (acc < S16_MIN)
+ acc = S16_MIN;
+ return (u16)(s16)acc;
+}
+
+s64 pmbus_reg2data(const struct pmbus_driver_info *info,
+ enum pmbus_sensor_classes class,
+ u16 raw, u8 vout_mode)
+{
+ if (!info || class >= PSC_NUM_CLASSES)
+ return 0;
+
+ switch (info->format[class]) {
+ case pmbus_fmt_linear:
+ if (class == PSC_VOLTAGE_OUT)
+ return pmbus_reg2data_linear16(raw, vout_mode);
+ return pmbus_reg2data_linear11(raw);
+
+ case pmbus_fmt_direct:
+ return pmbus_reg2data_direct((s16)raw,
+ info->m[class],
+ info->b[class],
+ info->R[class]);
+
+ case pmbus_fmt_vid:
+ case pmbus_fmt_ieee754:
+ /*
+ * Not yet wired up. Add when a consumer lands. VID needs
+ * the per page vrm_version table from the kernel's
+ * pmbus_reg2data_vid(); IEEE754 needs the half precision
+ * decoder from pmbus_reg2data_ieee754().
+ */
+ return 0;
+ }
+
+ return 0;
+}
+
+int pmbus_read_byte(struct udevice *dev, u8 cmd, u8 *val)
+{
+ return dm_i2c_read(dev, cmd, val, 1);
+}
+
+int pmbus_read_word(struct udevice *dev, u8 cmd, u16 *val)
+{
+ u8 raw[2];
+ int ret;
+
+ ret = dm_i2c_read(dev, cmd, raw, 2);
+ if (ret)
+ return ret;
+ *val = (u16)raw[0] | ((u16)raw[1] << 8);
+ return 0;
+}
+
+int pmbus_write_byte(struct udevice *dev, u8 cmd, u8 val)
+{
+ return dm_i2c_write(dev, cmd, &val, 1);
+}
+
+int pmbus_write_word(struct udevice *dev, u8 cmd, u16 val)
+{
+ u8 raw[2];
+
+ raw[0] = (u8)(val & 0xff); /* PMBus words are little-endian */
+ raw[1] = (u8)(val >> 8);
+ return dm_i2c_write(dev, cmd, raw, 2);
+}
+
+int pmbus_read_string(struct udevice *dev, u8 cmd, char *out, int outsz,
+ bool reverse_bytes)
+{
+ u8 raw[PMBUS_MFR_STRING_MAX + 1]; /* length byte + payload */
+ int ret, len, i;
+
+ if (outsz < 2)
+ return -EINVAL;
+
+ /* Stage 1: read the length byte. */
+ ret = dm_i2c_read(dev, cmd, raw, 1);
+ if (ret)
+ return ret;
+
+ len = raw[0];
+ if (len <= 0 || len > (int)sizeof(raw) - 1)
+ return -EBADMSG;
+ if (len > outsz - 1)
+ len = outsz - 1;
+
+ /* Stage 2: reread length + payload (some controllers mandate this). */
+ ret = dm_i2c_read(dev, cmd, raw, len + 1);
+ if (ret)
+ return ret;
+
+ if (reverse_bytes) {
+ for (i = 0; i < len; i++) {
+ u8 b = raw[len - i];
+
+ out[i] = isprint(b) ? (char)b : '.';
+ }
+ } else {
+ for (i = 0; i < len; i++) {
+ u8 b = raw[i + 1];
+
+ out[i] = isprint(b) ? (char)b : '.';
+ }
+ }
+ out[len] = '\0';
+ return len;
+}
+
+int pmbus_clear_faults(struct udevice *dev)
+{
+ return dm_i2c_write(dev, PMBUS_CLEAR_FAULTS, NULL, 0);
+}
+
+void pmbus_print_bits(u16 v, const struct pmbus_bit *tab)
+{
+ const struct pmbus_bit *t;
+ int first = 1;
+
+ if (v == 0) {
+ printf("clean");
+ return;
+ }
+ for (t = tab; t && t->name; t++) {
+ if (v & t->mask) {
+ printf("%s%s", first ? "" : "|", t->name);
+ first = 0;
+ }
+ }
+}
+
+void pmbus_print_status_bits(u8 reg, u16 v,
+ const struct pmbus_bit *std,
+ const struct pmbus_status_override *ovr)
+{
+ const struct pmbus_bit *s;
+ const struct pmbus_status_override *o;
+ int first = 1;
+
+ if (v == 0) {
+ printf("clean");
+ return;
+ }
+
+ /*
+ * Pass 1: walk the standard table in declared order so the
+ * printout retains the conventional bit-15-first ordering. For
+ * each set bit, prefer a chip override matching (reg, mask).
+ */
+ for (s = std; s && s->name; s++) {
+ const char *name;
+
+ if (!(v & s->mask))
+ continue;
+ name = s->name;
+ for (o = ovr; o && o->name; o++) {
+ if (o->reg == reg && o->mask == s->mask) {
+ name = o->name;
+ break;
+ }
+ }
+ printf("%s%s", first ? "" : "|", name);
+ first = 0;
+ }
+
+ /*
+ * Pass 2: print overrides whose mask is not in the standard
+ * table at all (chip-specific bit at a position the spec
+ * leaves RESERVED). These would otherwise be swallowed.
+ */
+ for (o = ovr; o && o->name; o++) {
+ bool in_std = false;
+
+ if (o->reg != reg)
+ continue;
+ if (!(v & o->mask))
+ continue;
+ for (s = std; s && s->name; s++) {
+ if (s->mask == o->mask) {
+ in_std = true;
+ break;
+ }
+ }
+ if (in_std)
+ continue;
+ printf("%s%s", first ? "" : "|", o->name);
+ first = 0;
+ }
+}
+
+/*
+ * Standard PMBus 1.3 status bit tables. Per-chip drivers may publish
+ * their own tables for vendor extended bits (e.g. NVM summary bits,
+ * DR MOS faults) but the standard layout below is the safe baseline.
+ *
+ * All tables are NULL terminated (`name = NULL` sentinel), matching
+ * the convention used elsewhere in U-Boot for driver tables.
+ */
+const struct pmbus_bit pmbus_status_word_bits[] = {
+ { PB_STATUS_VOUT, "VOUT" },
+ { PB_STATUS_IOUT_POUT, "IOUT_POUT" },
+ { PB_STATUS_INPUT, "INPUT" },
+ { PB_STATUS_WORD_MFR, "MFR" },
+ { PB_STATUS_POWER_GOOD_N, "PG#" },
+ { PB_STATUS_FANS, "FANS" },
+ { PB_STATUS_OTHER, "OTHER" },
+ { PB_STATUS_UNKNOWN, "UNKNOWN" },
+ { PB_STATUS_BUSY, "BUSY" },
+ { PB_STATUS_OFF, "OFF" },
+ { PB_STATUS_VOUT_OV, "VOUT_OV" },
+ { PB_STATUS_IOUT_OC, "IOUT_OC" },
+ { PB_STATUS_VIN_UV, "VIN_UV" },
+ { PB_STATUS_TEMPERATURE, "TEMP" },
+ { PB_STATUS_CML, "CML" },
+ { PB_STATUS_NONE_ABOVE, "NONE_ABOVE" },
+ { /* sentinel */ }
+};
+
+const struct pmbus_bit pmbus_status_vout_bits[] = {
+ { PB_VOLTAGE_OV_FAULT, "VOUT_OV_FAULT" },
+ { PB_VOLTAGE_OV_WARNING, "VOUT_OV_WARN" },
+ { PB_VOLTAGE_UV_WARNING, "VOUT_UV_WARN" },
+ { PB_VOLTAGE_UV_FAULT, "VOUT_UV_FAULT" },
+ { PB_VOLTAGE_VOUT_MAX_MIN_WARN, "VOUT_MAX_MIN_WARN" },
+ { /* sentinel */ }
+};
+
+const struct pmbus_bit pmbus_status_iout_bits[] = {
+ { PB_IOUT_OC_FAULT, "IOUT_OC_FAULT" },
+ { PB_IOUT_OC_LV_FAULT, "IOUT_OC_LV_FAULT" },
+ { PB_IOUT_OC_WARNING, "IOUT_OC_WARN" },
+ { PB_IOUT_UC_FAULT, "IOUT_UC_FAULT" },
+ { PB_CURRENT_SHARE_FAULT, "ISHARE_FAULT" },
+ { PB_POWER_LIMITING, "POWER_LIMITING" },
+ { PB_POUT_OP_FAULT, "POUT_OP_FAULT" },
+ { PB_POUT_OP_WARNING, "POUT_OP_WARN" },
+ { /* sentinel */ }
+};
+
+const struct pmbus_bit pmbus_status_input_bits[] = {
+ { PB_IIN_OC_FAULT, "IIN_OC_FAULT" },
+ { PB_IIN_OC_WARNING, "IIN_OC_WARN" },
+ { PB_PIN_OP_WARNING, "PIN_OP_WARN" },
+ { /* sentinel */ }
+};
+
+const struct pmbus_bit pmbus_status_temp_bits[] = {
+ { PB_TEMP_OT_FAULT, "OT_FAULT" },
+ { PB_TEMP_OT_WARNING, "OT_WARN" },
+ { PB_TEMP_UT_WARNING, "UT_WARN" },
+ { PB_TEMP_UT_FAULT, "UT_FAULT" },
+ { /* sentinel */ }
+};
+
+const struct pmbus_bit pmbus_status_cml_bits[] = {
+ { PB_CML_FAULT_INVALID_COMMAND, "INVALID_CMD" },
+ { PB_CML_FAULT_INVALID_DATA, "INVALID_DATA" },
+ { PB_CML_FAULT_PACKET_ERROR, "PEC" },
+ { PB_CML_FAULT_MEMORY, "MEM" },
+ { PB_CML_FAULT_PROCESSOR, "PROC" },
+ { PB_CML_FAULT_OTHER_COMM, "OTHER_COMM" },
+ { PB_CML_FAULT_OTHER_MEM_LOGIC, "OTHER_MEM_LOGIC" },
+ { /* sentinel */ }
+};
+
+/*
+ * Active device tracking + chip / vendor registries (consumed by the
+ * `pmbus` U-Boot CLI command in cmd/pmbus.c).
+ */
+
+#define PMBUS_MAX_CHIP_MATCHES 8
+#define PMBUS_MAX_VENDOR_HANDLERS 4
+
+static struct pmbus_active_dev pmbus_active_state;
+static const struct pmbus_chip_match *pmbus_chip_table[PMBUS_MAX_CHIP_MATCHES];
+static unsigned int pmbus_chip_table_n;
+static const struct pmbus_vendor_op *pmbus_vendor_table[PMBUS_MAX_VENDOR_HANDLERS];
+static unsigned int pmbus_vendor_table_n;
+
+const struct pmbus_active_dev *pmbus_active(void)
+{
+ return pmbus_active_state.valid ? &pmbus_active_state : NULL;
+}
+
+void pmbus_clear_active(void)
+{
+ memset(&pmbus_active_state, 0, sizeof(pmbus_active_state));
+}
+
+int pmbus_active_get_i2c(struct udevice **i2c_dev)
+{
+ struct udevice *bus;
+ int ret;
+
+ if (!pmbus_active_state.valid)
+ return -ENODEV;
+ ret = uclass_get_device_by_seq(UCLASS_I2C, pmbus_active_state.bus_seq, &bus);
+ if (ret)
+ return ret;
+ return i2c_get_chip(bus, pmbus_active_state.addr, 1, i2c_dev);
+}
+
+/* engineering value in micro units -> "I.FFF<unit>" (3 fractional digits) */
+static void pmbus_emit_micro(s64 micro, const char *unit)
+{
+ s64 abs_milli = (micro < 0 ? -micro : micro) / 1000LL;
+
+ printf("%lld.%03lld%s", (long long)(micro / 1000000LL),
+ (long long)(abs_milli % 1000LL), unit);
+}
+
+struct pmbus_telem_entry {
+ u8 reg;
+ const char *label;
+ enum pmbus_sensor_classes class;
+ const char *unit;
+};
+
+/*
+ * Telemetry register set, in print order. POUT is included so PSU
+ * class parts report input/output power; chips that do not implement
+ * a given command are skipped via pmbus_word_command_supported().
+ */
+static const struct pmbus_telem_entry pmbus_telem_table[] = {
+ { PMBUS_READ_VIN, "VIN ", PSC_VOLTAGE_IN, "V" },
+ { PMBUS_READ_VOUT, "VOUT", PSC_VOLTAGE_OUT, "V" },
+ { PMBUS_READ_IIN, "IIN ", PSC_CURRENT_IN, "A" },
+ { PMBUS_READ_IOUT, "IOUT", PSC_CURRENT_OUT, "A" },
+ { PMBUS_READ_POUT, "POUT", PSC_POWER, "W" },
+ { PMBUS_READ_TEMPERATURE_1, "TEMP", PSC_TEMPERATURE, "C" },
+};
+
+bool pmbus_word_command_supported(struct udevice *dev, u8 reg)
+{
+ u8 cml_before = 0, cml_after = 0;
+ bool have_cml;
+ u16 w;
+
+ have_cml = !pmbus_read_byte(dev, PMBUS_STATUS_CML, &cml_before);
+
+ if (pmbus_read_word(dev, reg, &w))
+ return false; /* NAK: unsupported command not ACKed */
+
+ if (have_cml && !(cml_before & PB_CML_FAULT_INVALID_COMMAND) &&
+ !pmbus_read_byte(dev, PMBUS_STATUS_CML, &cml_after) &&
+ (cml_after & PB_CML_FAULT_INVALID_COMMAND))
+ return false; /* ACKed but chip raised INVALID_COMMAND */
+
+ return true;
+}
+
+/* Telemetry of the currently selected page. */
+static void pmbus_print_telemetry_page(struct udevice *chip,
+ const struct pmbus_active_dev *act)
+{
+ u8 vout_mode = 0;
+ unsigned int i;
+
+ /*
+ * On a read failure vout_mode stays 0 (LINEAR, exponent 0). That is
+ * a silent mis-scale of every VOLTAGE_OUT reading, so make the
+ * fallback visible rather than printing a wrong voltage as if good.
+ */
+ if (pmbus_read_byte(chip, PMBUS_VOUT_MODE, &vout_mode))
+ printf(" (VOUT_MODE read failed; VOUT decode assumes LINEAR exp 0)\n");
+
+ for (i = 0; i < ARRAY_SIZE(pmbus_telem_table); i++) {
+ const struct pmbus_telem_entry *e = &pmbus_telem_table[i];
+ u16 raw = 0;
+
+ /*
+ * Class gating. A chip driver that declares classes_present
+ * lists exactly the sensors it implements (kernel-style
+ * per-chip sensor set), so unlisted classes are skipped
+ * silently -- this is what hides the MPS buck's uncalibrated
+ * POUT / IIN. A generic / undeclared device instead gets a
+ * live capability probe per class.
+ */
+ if (act->info && act->info->classes_present) {
+ if (!(act->info->classes_present & BIT(e->class)))
+ continue;
+ } else if (!pmbus_word_command_supported(chip, e->reg)) {
+ printf(" %s : (not supported)\n", e->label);
+ continue;
+ }
+
+ if (pmbus_read_word(chip, e->reg, &raw)) {
+ printf(" %s : (read failed)\n", e->label);
+ continue;
+ }
+
+ printf(" %s : raw=0x%04x ", e->label, raw);
+ if (act->info) {
+ u16 dec = raw;
+
+ /*
+ * Some DIRECT format parts (e.g. MPS) report
+ * temperature as 1 degC/LSB in the low byte only;
+ * mask there. LINEAR temperatures use all 16 bits
+ * and must NOT be masked.
+ */
+ if (e->class == PSC_TEMPERATURE &&
+ act->info->format[PSC_TEMPERATURE] == pmbus_fmt_direct)
+ dec = raw & 0x00ff;
+
+ pmbus_emit_micro(pmbus_reg2data(act->info, e->class,
+ dec, vout_mode),
+ e->unit);
+ } else if (e->class == PSC_VOLTAGE_OUT) {
+ pmbus_emit_micro(pmbus_reg2data_linear16(raw, vout_mode),
+ e->unit);
+ } else {
+ pmbus_emit_micro(pmbus_reg2data_linear11(raw), e->unit);
+ printf(" (LINEAR11 fallback)");
+ }
+ printf("\n");
+ }
+}
+
+void pmbus_print_telemetry(struct udevice *chip)
+{
+ const struct pmbus_active_dev *act = pmbus_active();
+ int npages, p;
+ u8 zero = 0;
+
+ if (!act)
+ return;
+
+ /*
+ * Multi-rail parts (PSU bricks) expose one rail per PMBUS_PAGE.
+ * Chip drivers set pmbus_driver_info.pages; the generic driver
+ * takes it from the DT `pmbus,num-pages` (default 1). We always
+ * write PMBUS_PAGE before reading a page -- including page 0 --
+ * because a device may power up selected on a different page, which
+ * is what made the 48V PSU read all-zeros before. Only valid pages
+ * (0..npages-1) are ever written, so we never induce the
+ * out-of-range-PAGE STATUS_CML fault and the device's sticky fault
+ * log is left untouched (no CLEAR_FAULTS, no scrubbing).
+ */
+ npages = (act->info && act->info->pages > 0) ? act->info->pages : 1;
+
+ for (p = 0; p < npages; p++) {
+ u8 pg = (u8)p;
+
+ if (dm_i2c_write(chip, PMBUS_PAGE, &pg, 1)) {
+ printf(" [page %d] PAGE select failed\n", p);
+ continue;
+ }
+ if (npages > 1)
+ printf(" [page %d]\n", p);
+ pmbus_print_telemetry_page(chip, act);
+ }
+
+ if (npages > 1)
+ dm_i2c_write(chip, PMBUS_PAGE, &zero, 1); /* leave on page 0 */
+}
+
+void pmbus_print_status_word(struct udevice *chip)
+{
+ const struct pmbus_active_dev *act = pmbus_active();
+ const struct pmbus_status_override *ovr =
+ (act && act->info) ? act->info->status_overrides : NULL;
+ u16 word = 0;
+
+ if (pmbus_read_word(chip, PMBUS_STATUS_WORD, &word)) {
+ printf(" STATUS_WORD (79h) = (read failed)\n");
+ return;
+ }
+ printf(" STATUS_WORD (79h) = 0x%04x [", word);
+ pmbus_print_status_bits(PMBUS_STATUS_WORD, word,
+ pmbus_status_word_bits, ovr);
+ printf("]\n");
+}
+
+static const struct pmbus_chip_match *pmbus_match_mfr(const char *id)
+{
+ unsigned int i;
+
+ if (!id || !id[0])
+ return NULL;
+ for (i = 0; i < pmbus_chip_table_n; i++) {
+ const struct pmbus_chip_match *m = pmbus_chip_table[i];
+ size_t plen = strlen(m->mfr_id);
+
+ if (strlen(id) >= plen && !strncmp(id, m->mfr_id, plen))
+ return m;
+ }
+ return NULL;
+}
+
+/*
+ * Walk UCLASS_REGULATOR looking for a regulator whose I2C parent
+ * bus seq + DT reg address match the requested (bus_seq, addr).
+ * Returns the regulator-name (uclass plat .name) on hit, or NULL if
+ * no UCLASS_REGULATOR device matches (chip not bound through DT, or
+ * CONFIG_DM_REGULATOR disabled).
+ */
+static const char *pmbus_lookup_regname(int bus_seq, u8 addr)
+{
+ struct uclass *uc;
+ struct udevice *r;
+
+ if (!IS_ENABLED(CONFIG_DM_REGULATOR))
+ return NULL;
+
+ if (uclass_get(UCLASS_REGULATOR, &uc))
+ return NULL;
+ uclass_foreach_dev(r, uc) {
+ struct dm_regulator_uclass_plat *up;
+ struct udevice *parent = dev_get_parent(r);
+ int ra;
+
+ if (!parent || device_get_uclass_id(parent) != UCLASS_I2C)
+ continue;
+ if (dev_seq(parent) != bus_seq)
+ continue;
+ ra = dev_read_addr(r);
+ if (ra < 0 || (u8)ra != addr)
+ continue;
+ up = dev_get_uclass_plat(r);
+ if (up && up->name)
+ return up->name;
+ return r->name;
+ }
+ return NULL;
+}
+
+int pmbus_set_active(int bus_seq, u8 addr)
+{
+ const struct pmbus_chip_match *match = NULL;
+ struct udevice *bus, *chip;
+ char id_fwd[PMBUS_MFR_STRING_MAX] = "";
+ char id_rev[PMBUS_MFR_STRING_MAX] = "";
+ const char *rname;
+ int ret;
+
+ pmbus_clear_active();
+
+ ret = uclass_get_device_by_seq(UCLASS_I2C, bus_seq, &bus);
+ if (ret)
+ return ret;
+ ret = i2c_get_chip(bus, addr, 1, &chip);
+ if (ret)
+ return ret;
+
+ pmbus_active_state.bus_seq = bus_seq;
+ pmbus_active_state.addr = addr;
+
+ /*
+ * Probe MFR_ID in both byte orders. Spec compliant chips return
+ * "MPS" / "TI" / etc. in the natural reading (forward); MPS NVM
+ * personalities store the string LSB first and need the reverse
+ * read. Chip table entries declare which one is canonical for
+ * the chip family they describe.
+ */
+ if (pmbus_read_string(chip, PMBUS_MFR_ID, id_fwd, sizeof(id_fwd), false) < 0)
+ id_fwd[0] = '\0';
+ if (pmbus_read_string(chip, PMBUS_MFR_ID, id_rev, sizeof(id_rev), true) < 0)
+ id_rev[0] = '\0';
+
+ match = pmbus_match_mfr(id_fwd);
+ if (match && !match->mfr_id_reverse) {
+ strlcpy(pmbus_active_state.mfr_id, id_fwd,
+ sizeof(pmbus_active_state.mfr_id));
+ } else {
+ match = pmbus_match_mfr(id_rev);
+ if (match && match->mfr_id_reverse) {
+ strlcpy(pmbus_active_state.mfr_id, id_rev,
+ sizeof(pmbus_active_state.mfr_id));
+ } else {
+ /* No registered match; cache the forward read as best effort. */
+ strlcpy(pmbus_active_state.mfr_id,
+ id_fwd[0] ? id_fwd : id_rev,
+ sizeof(pmbus_active_state.mfr_id));
+ }
+ }
+
+ if (match) {
+ pmbus_active_state.info = match->info;
+ if (match->vendor)
+ strlcpy(pmbus_active_state.vendor, match->vendor,
+ sizeof(pmbus_active_state.vendor));
+ }
+
+ /*
+ * No MFR_ID chip-match (a spec compliant part with no per chip
+ * driver, e.g. a Flex / Delta PSU): if a generic / chip
+ * UCLASS_REGULATOR is bound at this address, reuse its
+ * VOUT_MODE detected driver_info so telemetry decodes through
+ * the right per class formats instead of the blanket
+ * LINEAR16 / LINEAR11 fallback.
+ */
+ if (CONFIG_IS_ENABLED(DM_REGULATOR_PMBUS_HELPER) &&
+ !pmbus_active_state.info) {
+ const struct pmbus_driver_info *di =
+ pmbus_regulator_info_by_addr(bus_seq, addr);
+
+ if (di)
+ pmbus_active_state.info = di;
+ }
+
+ /*
+ * MFR_MODEL / MFR_REVISION are best effort. Use the same byte
+ * order the matched chip declared; if nothing matched, use the
+ * forward order.
+ */
+ {
+ bool reverse = match && match->mfr_id_reverse;
+
+ pmbus_active_state.mfr_reverse = reverse;
+ pmbus_read_string(chip, PMBUS_MFR_MODEL,
+ pmbus_active_state.mfr_model,
+ sizeof(pmbus_active_state.mfr_model), reverse);
+ pmbus_read_string(chip, PMBUS_MFR_REVISION,
+ pmbus_active_state.mfr_revision,
+ sizeof(pmbus_active_state.mfr_revision), reverse);
+ }
+
+ rname = pmbus_lookup_regname(bus_seq, addr);
+ if (rname)
+ strlcpy(pmbus_active_state.name, rname,
+ sizeof(pmbus_active_state.name));
+
+ pmbus_active_state.valid = true;
+ return 0;
+}
+
+int pmbus_register_chip(const struct pmbus_chip_match *match)
+{
+ if (!match || !match->mfr_id)
+ return -EINVAL;
+ if (pmbus_chip_table_n >= PMBUS_MAX_CHIP_MATCHES)
+ return -ENOSPC;
+ pmbus_chip_table[pmbus_chip_table_n++] = match;
+ return 0;
+}
+
+int pmbus_register_vendor_handler(const struct pmbus_vendor_op *op)
+{
+ if (!op || !op->vendor || !op->handler)
+ return -EINVAL;
+ if (pmbus_vendor_table_n >= PMBUS_MAX_VENDOR_HANDLERS)
+ return -ENOSPC;
+ pmbus_vendor_table[pmbus_vendor_table_n++] = op;
+ return 0;
+}
+
+const struct pmbus_vendor_op *pmbus_lookup_vendor(const char *vendor)
+{
+ unsigned int i;
+
+ if (!vendor)
+ return NULL;
+ for (i = 0; i < pmbus_vendor_table_n; i++)
+ if (!strcmp(pmbus_vendor_table[i]->vendor, vendor))
+ return pmbus_vendor_table[i];
+ return NULL;
+}
+
+unsigned int pmbus_vendor_count(void)
+{
+ return pmbus_vendor_table_n;
+}
+
+const struct pmbus_vendor_op *pmbus_vendor_at(unsigned int i)
+{
+ return i < pmbus_vendor_table_n ? pmbus_vendor_table[i] : NULL;
+}
+
+int pmbus_resolve_by_name(const char *name, int *bus_seq, u8 *addr)
+{
+ struct udevice *reg;
+ struct udevice *parent;
+ int ret;
+ int a;
+
+ if (!IS_ENABLED(CONFIG_DM_REGULATOR))
+ return -ENOSYS;
+
+ if (!name || !bus_seq || !addr)
+ return -EINVAL;
+
+ ret = regulator_get_by_platname(name, &reg);
+ if (ret)
+ return ret;
+
+ parent = dev_get_parent(reg);
+ if (!parent || device_get_uclass_id(parent) != UCLASS_I2C)
+ return -ENODEV;
+
+ a = dev_read_addr(reg);
+ if (a < 0 || a > 0x7f)
+ return -EINVAL;
+
+ *bus_seq = dev_seq(parent);
+ *addr = (u8)a;
+ return 0;
+}
diff --git a/lib/string.c b/lib/string.c
index 37ea8c29561..dbf2ce340df 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -263,12 +263,12 @@ char * strchr(const char * s, int c)
}
#endif
-const char *strchrnul(const char *s, int c)
+char *strchrnul(const char *s, int c)
{
for (; *s != (char)c; ++s)
if (*s == '\0')
break;
- return s;
+ return (char *)s;
}
#ifndef __HAVE_ARCH_STRRCHR
@@ -399,7 +399,6 @@ void kfree_const(const void *x)
}
-#ifndef __HAVE_ARCH_STRSPN
/**
* strspn - Calculate the length of the initial substring of @s which only
* contain letters in @accept
@@ -424,9 +423,7 @@ size_t strspn(const char *s, const char *accept)
return count;
}
-#endif
-#ifndef __HAVE_ARCH_STRPBRK
/**
* strpbrk - Find the first occurrence of a set of characters
* @cs: The string to be searched
@@ -444,9 +441,7 @@ char * strpbrk(const char * cs,const char * ct)
}
return NULL;
}
-#endif
-#ifndef __HAVE_ARCH_STRTOK
/**
* strtok - Split a string into tokens
* @s: The string to be searched
@@ -473,9 +468,7 @@ char * strtok(char * s,const char * ct)
___strtok = send;
return (sbegin);
}
-#endif
-#ifndef __HAVE_ARCH_STRSEP
/**
* strsep - Split a string into tokens
* @s: The string to be searched
@@ -501,35 +494,6 @@ char * strsep(char **s, const char *ct)
return sbegin;
}
-#endif
-
-#ifndef __HAVE_ARCH_STRSWAB
-/**
- * strswab - swap adjacent even and odd bytes in %NUL-terminated string
- * s: address of the string
- *
- * returns the address of the swapped string or NULL on error. If
- * string length is odd, last byte is untouched.
- */
-char *strswab(const char *s)
-{
- char *p, *q;
-
- if ((NULL == s) || ('\0' == *s)) {
- return (NULL);
- }
-
- for (p=(char *)s, q=p+1; (*p != '\0') && (*q != '\0'); p+=2, q+=2) {
- char tmp;
-
- tmp = *p;
- *p = *q;
- *q = tmp;
- }
-
- return (char *) s;
-}
-#endif
#ifndef __HAVE_ARCH_MEMSET
/**
@@ -702,7 +666,7 @@ void *memdup(const void *src, size_t len)
*
* @s1: string to be searched
* @s2: string to search for
- * @len: maximum number of characters in s2 to consider
+ * @len: maximum number of characters in s1 to consider
*
* Return: pointer to the first occurrence or NULL
*/
@@ -728,7 +692,6 @@ char *strnstr(const char *s1, const char *s2, size_t len)
*
* @s1: string to be searched
* @s2: string to search for
- * @len: maximum number of characters in s2 to consider
*
* Return: pointer to the first occurrence or NULL
*/
@@ -738,6 +701,33 @@ char *strstr(const char *s1, const char *s2)
}
#endif
+/**
+ * strcasestr() - Case insensitive substring search
+ *
+ * @haystack: string to be searched
+ * @needle: string to search for
+ *
+ * Return: pointer to the first occurrence or NULL
+ *
+ * The case of both strings are ignored.
+ */
+char *strcasestr(const char *haystack, const char *needle)
+{
+ size_t l1, l2;
+
+ l1 = strlen(haystack);
+ l2 = strlen(needle);
+
+ while (l1 >= l2) {
+ if (!strncasecmp(haystack, needle, l2))
+ return (char *)haystack;
+ haystack++;
+ l1--;
+ }
+
+ return NULL;
+}
+
#ifndef __HAVE_ARCH_MEMCHR
/**
* memchr - Find a character in an area of memory.
diff --git a/lib/uuid.c b/lib/uuid.c
index d7c164ea06b..16ca8f37751 100644
--- a/lib/uuid.c
+++ b/lib/uuid.c
@@ -95,6 +95,7 @@ static const struct {
"system", "EFI System Partition",
PARTITION_SYSTEM_GUID,
},
+#endif /* EFI_PARTITION */
#if defined(CONFIG_CMD_EFIDEBUG) || defined(CONFIG_EFI_CLIENT)
{
NULL, "Device Path",
@@ -304,7 +305,6 @@ static const struct {
{ "EFI_MEM_STATUS_CODE_REC", NULL, EFI_MEM_STATUS_CODE_REC },
{ "EFI_GUID_EFI_ACPI1", NULL, EFI_GUID_EFI_ACPI1 },
#endif
-#endif /* EFI_PARTITION */
#endif /* !USE_HOSTCC */
};