mirror of
https://github.com/google/pebble.git
synced 2025-11-21 06:50:54 -05:00
Import of the watch repository from Pebble
This commit is contained in:
178
platform/snowy/boot/src/util/version.c
Normal file
178
platform/snowy/boot/src/util/version.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "drivers/crc.h"
|
||||
#include "drivers/flash.h"
|
||||
#include "flash_region.h"
|
||||
#include "git_version.auto.h"
|
||||
#include "system/firmware_storage.h"
|
||||
#include "system/passert.h"
|
||||
#include "version.h"
|
||||
|
||||
//! The linker inserts the build id as an "elf external note" structure:
|
||||
struct ElfExternalNote {
|
||||
uint32_t name_length;
|
||||
uint32_t data_length;
|
||||
uint32_t type; // NT_GNU_BUILD_ID = 3
|
||||
uint8_t data[]; // concatenated name ('GNU') + data (build id)
|
||||
};
|
||||
|
||||
//! This symbol and its contents are provided by the linker script, see the
|
||||
//! .note.gnu.build-id section in src/fw/stm32f2xx_flash_fw.ld
|
||||
extern const struct ElfExternalNote TINTIN_BUILD_ID;
|
||||
|
||||
const FirmwareMetadata TINTIN_METADATA __attribute__ ((section (".pbl_fw_version"))) = {
|
||||
.version_timestamp = GIT_TIMESTAMP,
|
||||
.version_tag = GIT_TAG,
|
||||
.version_short = GIT_REVISION,
|
||||
|
||||
#ifdef RECOVERY_FW
|
||||
.is_recovery_firmware = true,
|
||||
#else
|
||||
.is_recovery_firmware = false,
|
||||
#endif
|
||||
|
||||
#if defined(BOARD_BIGBOARD)
|
||||
.hw_platform = FirmwareMetadataPlatformPebbleOneBigboard,
|
||||
#elif defined(BOARD_BB2)
|
||||
.hw_platform = FirmwareMetadataPlatformPebbleOneBigboard2,
|
||||
#elif defined(BOARD_V2_0)
|
||||
.hw_platform = FirmwareMetadataPlatformPebbleTwoPointZero,
|
||||
#elif defined(BOARD_V1_5)
|
||||
.hw_platform = FirmwareMetadataPlatformPebbleOnePointFive,
|
||||
#elif defined(BOARD_EV2_4)
|
||||
.hw_platform = FirmwareMetadataPlatformPebbleOneEV2_4,
|
||||
#else
|
||||
.hw_platform = FirmwareMetadataPlatformUnknown,
|
||||
#endif
|
||||
|
||||
.metadata_version = FW_METADATA_CURRENT_STRUCT_VERSION,
|
||||
};
|
||||
|
||||
bool version_copy_running_fw_metadata(FirmwareMetadata *out_metadata) {
|
||||
if (out_metadata == NULL) {
|
||||
return false;
|
||||
}
|
||||
memcpy(out_metadata, &TINTIN_METADATA, sizeof(FirmwareMetadata));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool prv_version_copy_flash_fw_metadata(FirmwareMetadata *out_metadata, uint32_t flash_address) {
|
||||
if (out_metadata == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FirmwareDescription firmware_description = firmware_storage_read_firmware_description(flash_address);
|
||||
if (!firmware_storage_check_valid_firmware_description(&firmware_description)) {
|
||||
memset(out_metadata, 0, sizeof(FirmwareMetadata));
|
||||
return false;
|
||||
}
|
||||
// The FirmwareMetadata is stored at the end of the binary:
|
||||
uint32_t offset = firmware_description.description_length + firmware_description.firmware_length - sizeof(FirmwareMetadata);
|
||||
flash_read_bytes((uint8_t*)out_metadata, flash_address + offset, sizeof(FirmwareMetadata));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool version_copy_recovery_fw_metadata(FirmwareMetadata *out_metadata) {
|
||||
return prv_version_copy_flash_fw_metadata(out_metadata, FLASH_REGION_SAFE_FIRMWARE_BEGIN);
|
||||
}
|
||||
|
||||
bool version_copy_update_fw_metadata(FirmwareMetadata *out_metadata) {
|
||||
return prv_version_copy_flash_fw_metadata(out_metadata, FLASH_REGION_FIRMWARE_SCRATCH_BEGIN);
|
||||
}
|
||||
|
||||
bool version_copy_recovery_fw_version(char* dest, const int dest_len_bytes) {
|
||||
FirmwareMetadata out_metadata;
|
||||
bool success = version_copy_recovery_fw_metadata(&out_metadata);
|
||||
if (success) {
|
||||
strncpy(dest, out_metadata.version_tag, dest_len_bytes);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool version_is_prf_installed(void) {
|
||||
FirmwareDescription firmware_description =
|
||||
firmware_storage_read_firmware_description(FLASH_REGION_SAFE_FIRMWARE_BEGIN);
|
||||
if (!firmware_storage_check_valid_firmware_description(&firmware_description)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t flash_address = FLASH_REGION_SAFE_FIRMWARE_BEGIN + firmware_description.description_length;
|
||||
uint32_t crc = crc_calculate_flash(flash_address, firmware_description.firmware_length);
|
||||
return crc == firmware_description.checksum;
|
||||
}
|
||||
|
||||
const uint8_t * version_get_build_id(size_t *out_len) {
|
||||
if (out_len) {
|
||||
*out_len = TINTIN_BUILD_ID.data_length;
|
||||
}
|
||||
return &TINTIN_BUILD_ID.data[TINTIN_BUILD_ID.name_length];
|
||||
}
|
||||
|
||||
void version_copy_build_id_hex_string(char *buffer, size_t buffer_bytes_left) {
|
||||
size_t build_id_bytes_left;
|
||||
const uint8_t *build_id = version_get_build_id(&build_id_bytes_left);
|
||||
while (buffer_bytes_left >= 3 /* 2 hex digits, plus zero terminator */
|
||||
&& build_id_bytes_left > 0) {
|
||||
snprintf(buffer, buffer_bytes_left, "%02x", *build_id);
|
||||
|
||||
buffer += 2;
|
||||
buffer_bytes_left -= 2;
|
||||
|
||||
build_id += 1;
|
||||
build_id_bytes_left -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void version_fw_version_to_major_minor(unsigned int *major, unsigned int *minor,
|
||||
char *version_str) {
|
||||
// read in the two X's (vX.X)
|
||||
sscanf(version_str, "v%u.%u", major, minor);
|
||||
}
|
||||
|
||||
//! Compares its two arguments for order. Returns a negative integer, zero, or a positive integer
|
||||
//! if the first argument is less than, equal to, or greater than the second.
|
||||
static int8_t prv_version_compare_fw_version_tags(char *fw1_version, char *fw2_version) {
|
||||
unsigned int major1, minor1, major2, minor2;
|
||||
version_fw_version_to_major_minor(&major1, &minor1, fw1_version);
|
||||
version_fw_version_to_major_minor(&major2, &minor2, fw2_version);
|
||||
|
||||
if (major1 != major2) { // do the major versions differ?
|
||||
return (major1 - major2);
|
||||
}
|
||||
|
||||
if (minor1 != minor2) { // do the minor versions differ?
|
||||
return (minor1 - minor2);
|
||||
}
|
||||
|
||||
return (0); // versions are the same
|
||||
}
|
||||
|
||||
bool version_fw_downgrade_detected(void) {
|
||||
FirmwareMetadata running_meta_data, update_meta_data;
|
||||
version_copy_running_fw_metadata(&running_meta_data);
|
||||
version_copy_update_fw_metadata(&update_meta_data);
|
||||
|
||||
int rv = prv_version_compare_fw_version_tags(update_meta_data.version_tag,
|
||||
running_meta_data.version_tag);
|
||||
|
||||
// return true is the new firmware to be updated to is a version less than the old one.
|
||||
return (rv < 0);
|
||||
}
|
||||
Reference in New Issue
Block a user