mirror of
https://github.com/google/pebble.git
synced 2025-05-24 04:04:53 +00:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
50
platform/snowy/boot/src/util/attributes.h
Normal file
50
platform/snowy/boot/src/util/attributes.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__clang__)
|
||||
#define GCC_ONLY(x)
|
||||
#else
|
||||
#define GCC_ONLY(x) x
|
||||
#endif
|
||||
|
||||
// Function attributes
|
||||
#define FORMAT_FUNC(TYPE, STR_IDX, FIRST) __attribute__((__format__(TYPE, STR_IDX, FIRST)))
|
||||
|
||||
#define FORMAT_PRINTF(STR_IDX, FIRST) FORMAT_FUNC(__printf__, STR_IDX, FIRST)
|
||||
|
||||
#define ALWAYS_INLINE __attribute__((__always_inline__)) inline
|
||||
#define NOINLINE __attribute__((__noinline__))
|
||||
#define NORETURN __attribute__((__noreturn__)) void
|
||||
#define NAKED_FUNC __attribute__((__naked__))
|
||||
#define OPTIMIZE_FUNC(LVL) __attribute__((__optimize__(LVL)))
|
||||
#define CONST_FUNC __attribute__((__const__))
|
||||
#define PURE_FUNC __attribute__((__pure__))
|
||||
|
||||
// Variable attributes
|
||||
#define ATTR_CLEANUP(FUNC) __attribute__((__cleanup__(FUNC)))
|
||||
|
||||
// Structure attributes
|
||||
#define PACKED __attribute__((__packed__))
|
||||
|
||||
// General attributes
|
||||
#define USED __attribute__((__used__))
|
||||
#define UNUSED __attribute__((__unused__))
|
||||
#define WEAK __attribute__((__weak__))
|
||||
#define ALIAS(sym) __attribute__((__weak__, __alias__(sym)))
|
||||
#define SECTION(SEC) GCC_ONLY(__attribute__((__section__(SEC))))
|
||||
#define EXTERNALLY_VISIBLE GCC_ONLY(__attribute__((__externally_visible__)))
|
103
platform/snowy/boot/src/util/bitset.h
Normal file
103
platform/snowy/boot/src/util/bitset.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//! @file util/bitset.h
|
||||
//!
|
||||
//! Helper functions for dealing with a bitsets of various widths.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "system/passert.h"
|
||||
|
||||
static inline void bitset8_set(uint8_t* bitset, unsigned int index) {
|
||||
bitset[index / 8] |= (1 << (index % 8));
|
||||
}
|
||||
|
||||
static inline void bitset8_clear(uint8_t* bitset, unsigned int index) {
|
||||
bitset[index / 8] &= ~(1 << (index % 8));
|
||||
}
|
||||
|
||||
static inline void bitset8_update(uint8_t* bitset, unsigned int index, bool value) {
|
||||
if (value) {
|
||||
bitset8_set(bitset, index);
|
||||
} else {
|
||||
bitset8_clear(bitset, index);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool bitset8_get(const uint8_t* bitset, unsigned int index) {
|
||||
return bitset[index / 8] & (1 << (index % 8));
|
||||
}
|
||||
|
||||
static inline void bitset16_set(uint16_t* bitset, unsigned int index) {
|
||||
bitset[index / 16] |= (1 << (index % 16));
|
||||
}
|
||||
|
||||
static inline void bitset16_clear(uint16_t* bitset, unsigned int index) {
|
||||
bitset[index / 16] &= ~(1 << (index % 16));
|
||||
}
|
||||
|
||||
static inline void bitset16_update(uint16_t* bitset, unsigned int index, bool value) {
|
||||
if (value) {
|
||||
bitset16_set(bitset, index);
|
||||
} else {
|
||||
bitset16_clear(bitset, index);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool bitset16_get(const uint16_t* bitset, unsigned int index) {
|
||||
return bitset[index / 16] & (1 << (index % 16));
|
||||
}
|
||||
|
||||
static inline void bitset32_set(uint32_t* bitset, unsigned int index) {
|
||||
bitset[index / 32] |= (1 << (index % 32));
|
||||
}
|
||||
|
||||
static inline void bitset32_clear(uint32_t* bitset, unsigned int index) {
|
||||
bitset[index / 32] &= ~(1 << (index % 32));
|
||||
}
|
||||
|
||||
static inline void bitset32_clear_all(uint32_t* bitset, unsigned int width) {
|
||||
if (width > 32) {
|
||||
// TODO: revisit
|
||||
WTF;
|
||||
}
|
||||
*bitset &= ~((1 << (width + 1)) - 1);
|
||||
}
|
||||
|
||||
static inline void bitset32_update(uint32_t* bitset, unsigned int index, bool value) {
|
||||
if (value) {
|
||||
bitset32_set(bitset, index);
|
||||
} else {
|
||||
bitset32_clear(bitset, index);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool bitset32_get(const uint32_t* bitset, unsigned int index) {
|
||||
return bitset[index / 32] & (1 << (index % 32));
|
||||
}
|
||||
|
||||
#ifdef __arm__
|
||||
#define rotl32(x, shift) \
|
||||
__asm__ volatile ("ror %0,%0,%1" : "+r" (src) : "r" (32 - (shift)) :);
|
||||
#else
|
||||
#define rotl32(x, shift) \
|
||||
uint32_t s = shift % 32; \
|
||||
{x = ((x << (s)) | x >> (32 - (s)));}
|
||||
#endif
|
51
platform/snowy/boot/src/util/cobs.c
Normal file
51
platform/snowy/boot/src/util/cobs.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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 "cobs.h"
|
||||
|
||||
size_t cobs_encode(void *dst_ptr, const void *src_ptr, size_t length) {
|
||||
const char *src = src_ptr;
|
||||
char *dst = dst_ptr;
|
||||
uint8_t code = 0x01;
|
||||
size_t code_idx = 0;
|
||||
size_t dst_idx = 1;
|
||||
|
||||
for (size_t src_idx = 0; src_idx < length; ++src_idx) {
|
||||
if (src[src_idx] == '\0') {
|
||||
dst[code_idx] = code;
|
||||
code_idx = dst_idx++;
|
||||
code = 0x01;
|
||||
} else {
|
||||
dst[dst_idx++] = src[src_idx];
|
||||
code++;
|
||||
if (code == 0xff) {
|
||||
if (src_idx == length - 1) {
|
||||
// Special case: the final encoded block is 254 bytes long with no
|
||||
// zero after it. While it's technically a valid encoding if a
|
||||
// trailing zero is appended, it causes the output to be one byte
|
||||
// longer than it needs to be. This violates consistent overhead
|
||||
// contract and could overflow a carefully sized buffer.
|
||||
break;
|
||||
}
|
||||
dst[code_idx] = code;
|
||||
code_idx = dst_idx++;
|
||||
code = 0x01;
|
||||
}
|
||||
}
|
||||
}
|
||||
dst[code_idx] = code;
|
||||
return dst_idx;
|
||||
}
|
40
platform/snowy/boot/src/util/cobs.h
Normal file
40
platform/snowy/boot/src/util/cobs.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
//! An implementation of Consistent Overhead Byte Stuffing
|
||||
//!
|
||||
//! http://conferences.sigcomm.org/sigcomm/1997/papers/p062.pdf
|
||||
//! http://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing
|
||||
|
||||
//! Evaluates to the offset required when encoding in-place
|
||||
#define COBS_OVERHEAD(n) (((n) + 253) / 254)
|
||||
//! Evaluates to the maximum buffer size required to hold n bytes of data
|
||||
//! after COBS encoding.
|
||||
#define MAX_SIZE_AFTER_COBS_ENCODING(n) ((n) + COBS_OVERHEAD(n))
|
||||
|
||||
//! COBS-encode a buffer out to another buffer.
|
||||
//!
|
||||
//! @param [out] dst destination buffer. The buffer must be at least
|
||||
//! MAX_SIZE_AFTER_COBS_ENCODING(length) bytes long.
|
||||
//! @param [in] src source buffer
|
||||
//! @param length length of src
|
||||
size_t cobs_encode(void * restrict dst, const void * restrict src,
|
||||
size_t length);
|
48
platform/snowy/boot/src/util/crc32.c
Normal file
48
platform/snowy/boot/src/util/crc32.c
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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 "util/crc32.h"
|
||||
|
||||
// Nybble-wide table driven CRC-32 algorithm
|
||||
//
|
||||
// A compromise between speed and size, this algorithm uses a lookup table to
|
||||
// calculate the CRC four bits at a time with a size cost of only 64 bytes. By
|
||||
// contrast, a byte-wide algorithm requires a lookup table sixteen times larger!
|
||||
//
|
||||
// The lookup table is generated by the crc32_lut.py
|
||||
|
||||
static const uint32_t s_lookup_table[] = {
|
||||
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
|
||||
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
|
||||
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
|
||||
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
|
||||
};
|
||||
|
||||
uint32_t crc32(uint32_t crc, const void * restrict data, size_t length) {
|
||||
if (data == 0) {
|
||||
return 0;
|
||||
}
|
||||
const uint8_t * restrict bytes = data;
|
||||
|
||||
crc ^= 0xffffffff;
|
||||
while (length--) {
|
||||
crc = (crc >> 4) ^ s_lookup_table[(crc ^ *bytes) & 0xf];
|
||||
crc = (crc >> 4) ^ s_lookup_table[(crc ^ (*bytes >> 4)) & 0xf];
|
||||
bytes++;
|
||||
}
|
||||
crc ^= 0xffffffff;
|
||||
return crc;
|
||||
}
|
67
platform/snowy/boot/src/util/crc32.h
Normal file
67
platform/snowy/boot/src/util/crc32.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//! \file
|
||||
//! Calculate the CRC-32 checksum of data.
|
||||
//!
|
||||
//! The checksum is the standard CRC-32 used by zlib, PNG and others.
|
||||
//! The model parameters for the algorithm, as described in A Painless Guide to
|
||||
//! CRC Error Detection Algorithms (http://www.zlib.net/crc_v3.txt), are:
|
||||
//! Name: "CRC-32"
|
||||
//! Width: 32
|
||||
//! Poly: 04C11DB7
|
||||
//! Init: FFFFFFFF
|
||||
//! RefIn: True
|
||||
//! RefOut: True
|
||||
//! XorOut: FFFFFFFF
|
||||
//! Check: CBF43926
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
//! Update a running CRC-32 checksum with the bytes of data and return the
|
||||
//! updated CRC-32. If data is NULL, the function returns the required initial
|
||||
//! value for the CRC.
|
||||
//!
|
||||
//! This function is drop-in compatible with zlib's crc32 function.
|
||||
//!
|
||||
//! \par Usage
|
||||
//! \code
|
||||
//! uint32_t crc = crc32(0, NULL, 0);
|
||||
//! while (read_buffer(data, length)) {
|
||||
//! crc = crc32(crc, data, length);
|
||||
//! }
|
||||
//! \endcode
|
||||
uint32_t crc32(uint32_t crc, const void * restrict data, size_t length);
|
||||
|
||||
//! The initial CRC register value for a standard CRC-32 checksum.
|
||||
//!
|
||||
//! It is the same value as is returned by the `crc32` function when data is
|
||||
//! NULL.
|
||||
//!
|
||||
//! \code
|
||||
//! assert(CRC32_INIT == crc32(0, NULL, 0));
|
||||
//! \endcode
|
||||
#define CRC32_INIT (0)
|
||||
|
||||
//! The residue constant of the CRC-32 algorithm.
|
||||
//!
|
||||
//! If the CRC-32 value of a message is appended (little-endian) onto the
|
||||
//! end of the message, the CRC-32 of the concatenated message and CRC will be
|
||||
//! equal to CRC32_RESIDUE if the message has not been corrupted in transit.
|
||||
#define CRC32_RESIDUE (0x2144DF1C)
|
44
platform/snowy/boot/src/util/delay.c
Normal file
44
platform/snowy/boot/src/util/delay.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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 "delay.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
void delay_us(uint32_t us) {
|
||||
// Empirically (measured on a bb2), 1 loop = ~47ns. (sysclk @
|
||||
// 64MHz, prefetch disabled) Alignment of code will have some impact on how
|
||||
// long this actually takes
|
||||
uint32_t delay_loops = us * 22;
|
||||
|
||||
__asm volatile (
|
||||
"spinloop: \n"
|
||||
" subs %[delay_loops], #1 \n"
|
||||
" bne spinloop \n"
|
||||
: [delay_loops] "+r" (delay_loops) // read-write operand
|
||||
:
|
||||
: "cc"
|
||||
);
|
||||
}
|
||||
|
||||
void delay_ms(uint32_t millis) {
|
||||
// delay_us(millis*1000) is not used because a long delay could easily
|
||||
// overflow the veriable. Without the outer loop, a delay of even five
|
||||
// seconds would overflow.
|
||||
while (millis--) {
|
||||
delay_us(1000);
|
||||
}
|
||||
}
|
28
platform/snowy/boot/src/util/delay.h
Normal file
28
platform/snowy/boot/src/util/delay.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
//! Carefully timed spinloop that allows one to delay at a microsecond
|
||||
//! granularity.
|
||||
void delay_us(uint32_t us);
|
||||
|
||||
//! Waits for a certain amount of milliseconds by busy-waiting.
|
||||
//!
|
||||
//! @param millis The number of milliseconds to wait for
|
||||
void delay_ms(uint32_t millis);
|
201
platform/snowy/boot/src/util/misc.c
Normal file
201
platform/snowy/boot/src/util/misc.c
Normal file
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* 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 "misc.h"
|
||||
#include "system/logging.h"
|
||||
#include "system/passert.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
int32_t sign_extend(uint32_t a, int bits) {
|
||||
if (bits == 32) {
|
||||
return a;
|
||||
}
|
||||
|
||||
// http://graphics.stanford.edu/~seander/bithacks.html#VariableSignExtend
|
||||
int const m = 1U << (bits - 1); // mask can be pre-computed if b is fixed
|
||||
|
||||
a = a & ((1U << bits) - 1); // (Skip this if bits in x above position b are already zero.)
|
||||
return (a ^ m) - m;
|
||||
}
|
||||
|
||||
int32_t serial_distance32(uint32_t a, uint32_t b) {
|
||||
return serial_distance(a, b, 32);
|
||||
}
|
||||
|
||||
int32_t serial_distance(uint32_t a, uint32_t b, int bits) {
|
||||
// See https://en.wikipedia.org/wiki/Serial_Number_Arithmetic
|
||||
const int64_t a_minus_b = a - b;
|
||||
const int64_t b_minus_a = b - a;
|
||||
const bool a_is_earlier_than_b = (a < b && b_minus_a < (1 << (bits - 1))) || (a > b && a_minus_b > (1 << (bits - 1)));
|
||||
return sign_extend(a_is_earlier_than_b ? -a_minus_b : b_minus_a, bits);
|
||||
}
|
||||
|
||||
int ceil_log_two(uint32_t n) {
|
||||
// clz stands for Count Leading Zeroes. We use it to find the MSB
|
||||
int msb = 31 - __builtin_clz(n);
|
||||
// popcount counts the number of set bits in a word (1's)
|
||||
bool power_of_two = __builtin_popcount(n) == 1;
|
||||
// if not exact power of two, use the next power of two
|
||||
// we want to err on the side of caution and want to
|
||||
// always round up
|
||||
return ((power_of_two) ? msb : (msb + 1));
|
||||
}
|
||||
|
||||
uint8_t count_bits_set(uint8_t *bitset_bytes, int num_bits) {
|
||||
uint8_t num_bits_set = 0;
|
||||
int num_bytes = (num_bits + 7) / 8;
|
||||
if ((num_bits % 8) != 0) {
|
||||
bitset_bytes[num_bytes] &= ((0x1 << (num_bits)) - 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_bytes; i++) {
|
||||
num_bits_set += __builtin_popcount(bitset_bytes[i]);
|
||||
}
|
||||
|
||||
return (num_bits_set);
|
||||
}
|
||||
|
||||
void itoa(uint32_t num, char *buffer, int buffer_length) {
|
||||
if (buffer_length < 11) {
|
||||
PBL_LOG(LOG_LEVEL_WARNING, "ito buffer too small");
|
||||
return;
|
||||
}
|
||||
*buffer++ = '0';
|
||||
*buffer++ = 'x';
|
||||
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
uint32_t digit = (num & (0xf << (i * 4))) >> (i * 4);
|
||||
|
||||
char c;
|
||||
if (digit < 0xa) {
|
||||
c = '0' + digit;
|
||||
} else if (digit < 0x10) {
|
||||
c = 'a' + (digit - 0xa);
|
||||
} else {
|
||||
c = ' ';
|
||||
}
|
||||
|
||||
*buffer++ = c;
|
||||
}
|
||||
*buffer = '\0';
|
||||
}
|
||||
|
||||
static int8_t ascii_hex_to_int(const uint8_t c) {
|
||||
if (isdigit(c)) return c - '0';
|
||||
if (isupper(c)) return (c - 'A') + 10;
|
||||
if (islower(c)) return (c - 'a') + 10;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static uint8_t ascii_hex_to_uint(const uint8_t msb, const uint8_t lsb) {
|
||||
return 16 * ascii_hex_to_int(msb) + ascii_hex_to_int(lsb);
|
||||
}
|
||||
|
||||
uintptr_t str_to_address(const char *address_str) {
|
||||
unsigned int address_str_length = strlen(address_str);
|
||||
|
||||
if (address_str_length < 3) return -1; // Invalid address, must be at least 0x[0-9a-f]+
|
||||
if (address_str[0] != '0' || address_str[1] != 'x') return -1; // Incorrect address prefix.
|
||||
|
||||
address_str += 2;
|
||||
|
||||
uintptr_t address = 0;
|
||||
for (; *address_str; ++address_str) {
|
||||
int8_t c = ascii_hex_to_int(*address_str);
|
||||
if (c == -1) return -1; // Unexpected character
|
||||
|
||||
address = (address * 16) + c;
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
bool convert_bt_addr_hex_str_to_bd_addr(const char *hex_str, uint8_t *bd_addr, const unsigned int bd_addr_size) {
|
||||
const int len = strlen(hex_str);
|
||||
if (len != 12) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t* src = (uint8_t*) hex_str;
|
||||
uint8_t* dest = bd_addr + bd_addr_size - 1;
|
||||
|
||||
for (unsigned int i = 0; i < bd_addr_size; ++i, src += 2, --dest) {
|
||||
*dest = ascii_hex_to_uint(src[0], src[1]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t next_exponential_backoff(uint32_t *attempt, uint32_t initial_value, uint32_t max_value) {
|
||||
if (*attempt > 31) {
|
||||
return max_value;
|
||||
}
|
||||
uint32_t backoff_multiplier = 0x1 << (*attempt)++;
|
||||
uint32_t next_value = initial_value * backoff_multiplier;
|
||||
return MIN(next_value, max_value);
|
||||
}
|
||||
|
||||
// Based on DJB2 Hash
|
||||
uint32_t hash(const uint8_t *bytes, const uint32_t length) {
|
||||
uint32_t hash = 5381;
|
||||
|
||||
if (length == 0) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
uint8_t c;
|
||||
const uint8_t *last_byte = bytes + length;
|
||||
while (bytes++ != last_byte) {
|
||||
c = *bytes;
|
||||
hash = ((hash << 5) + hash) + c;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
const char *bool_to_str(bool b) {
|
||||
if (b) {
|
||||
return "yes";
|
||||
} else {
|
||||
return "no";
|
||||
}
|
||||
}
|
||||
|
||||
// Override libgcc's table-driven __builtin_popcount implementation
|
||||
#ifdef __arm__
|
||||
int __popcountsi2(uint32_t val) {
|
||||
// Adapted from http://www.sciencezero.org/index.php?title=ARM%3a_Count_ones_%28bit_count%29
|
||||
uint32_t tmp;
|
||||
__asm("and %[tmp], %[val], #0xaaaaaaaa\n\t"
|
||||
"sub %[val], %[val], %[tmp], lsr #1\n\t"
|
||||
|
||||
"and %[tmp], %[val], #0xcccccccc\n\t"
|
||||
"and %[val], %[val], #0x33333333\n\t"
|
||||
"add %[val], %[val], %[tmp], lsr #2\n\t"
|
||||
|
||||
"add %[val], %[val], %[val], lsr #4\n\t"
|
||||
"and %[val], %[val], #0x0f0f0f0f\n\t"
|
||||
|
||||
"add %[val], %[val], %[val], lsr #8\n\t"
|
||||
"add %[val], %[val], %[val], lsr #16\n\t"
|
||||
"and %[val], %[val], #63\n\t"
|
||||
: [val] "+l" (val), [tmp] "=&l" (tmp));
|
||||
return val;
|
||||
}
|
||||
#endif // __arm__
|
107
platform/snowy/boot/src/util/misc.h
Normal file
107
platform/snowy/boot/src/util/misc.h
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
#define ABS(a) (((a) > 0) ? (a) : -1 * (a))
|
||||
#define CLIP(n, min, max) ((n)<(min)?(min):((n)>(max)?(max):(n)))
|
||||
|
||||
#define MHZ_TO_HZ(hz) (((uint32_t)(hz)) * 1000000)
|
||||
|
||||
#define KiBYTES(k) ((k) * 1024) // Bytes to Kibibytes
|
||||
#define MiBYTES(m) ((m) * 1024 * 1024) // Bytes to Mebibytes
|
||||
#define EiBYTES(e) ((e) * 1024 * 1024 * 1024 * 1024 * 1024 * 1024) // Bytes to Exbibytes
|
||||
|
||||
// Stolen from http://stackoverflow.com/a/8488201
|
||||
#define GET_FILE_NAME(file) (strrchr(file, '/') ? (strrchr(file, '/') + 1) : (file))
|
||||
|
||||
#define ARRAY_LENGTH(array) (sizeof((array))/sizeof((array)[0]))
|
||||
|
||||
#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
|
||||
|
||||
static inline void swap16(int16_t *a, int16_t *b) {
|
||||
int16_t t = *a;
|
||||
*a = *b;
|
||||
*b = t;
|
||||
}
|
||||
|
||||
int32_t sign_extend(uint32_t a, int bits);
|
||||
|
||||
//! Calculates the distance (end - start), taking a roll-over into account as good as it can get.
|
||||
int32_t serial_distance32(uint32_t start, uint32_t end);
|
||||
|
||||
//! Calculates the distance (end - start), taking a roll-over into account as good as it can get.
|
||||
//! @param bits the number of bits that are valid in start and end.
|
||||
int32_t serial_distance(uint32_t start, uint32_t end, int bits);
|
||||
|
||||
void itoa(uint32_t num, char *buffer, int buffer_length);
|
||||
|
||||
/*
|
||||
* find the log base two of a number rounded up
|
||||
*/
|
||||
int ceil_log_two(uint32_t n);
|
||||
|
||||
//! Count the number of bits that are set to 1 in a multi-byte bitset.
|
||||
//! @param bitset_bytes The bytes of the bitset
|
||||
//! @param num_bits The width of the bitset
|
||||
//! @note this function zeroes out any bits in the last byte if there
|
||||
//! are more bits than num_bits.
|
||||
uint8_t count_bits_set(uint8_t *bitset_bytes, int num_bits);
|
||||
|
||||
uintptr_t str_to_address(const char *address_str);
|
||||
|
||||
uint32_t hash(const uint8_t *bytes, const uint32_t length);
|
||||
|
||||
const char *bool_to_str(bool b);
|
||||
|
||||
//! @param hex 12-digit hex string representing a BT address
|
||||
//! @param addr Points to a SS1 BD_ADDR_t as defined in BTBTypes.h
|
||||
//! @return True on success
|
||||
bool convert_bt_addr_hex_str_to_bd_addr(const char *hex_str, uint8_t *bd_addr, const unsigned int bd_addr_size);
|
||||
|
||||
/**
|
||||
* Compute the next backoff interval using a bounded binary expoential backoff formula.
|
||||
*
|
||||
* @param[in,out] attempt The number of retries performed so far. This count will be incremented by
|
||||
* the function.
|
||||
* @param[in] initial_value The inital backoff interval. Subsequent backoff attempts will be this
|
||||
* number multiplied by a power of 2.
|
||||
* @param[in] max_value The maximum backoff interval that returned by the function.
|
||||
* @return The next backoff interval.
|
||||
*/
|
||||
uint32_t next_exponential_backoff(uint32_t *attempt, uint32_t initial_value, uint32_t max_value);
|
||||
|
||||
/*
|
||||
* The -Wtype-limits flag generated an error with the previous IS_SIGNED maco.
|
||||
* If an unsigned number was passed in the macro would check if the unsigned number was less than 0.
|
||||
*/
|
||||
#define IS_SIGNED(var) (__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(__typeof__(var), unsigned char), false, \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(__typeof__(var), unsigned short), false, \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(__typeof__(var), unsigned int), false, \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(__typeof__(var), unsigned long), false, \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(__typeof__(var), unsigned long long), false, true))))) \
|
||||
)
|
80
platform/snowy/boot/src/util/net.h
Normal file
80
platform/snowy/boot/src/util/net.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// When compiling test, the host OS might have conflicting defines for this:
|
||||
#undef ntohs
|
||||
#undef htons
|
||||
#undef ntohl
|
||||
#undef htonl
|
||||
#undef ltohs
|
||||
#undef ltohl
|
||||
|
||||
static inline uint16_t ntohs(uint16_t v) {
|
||||
// return ((v & 0x00ff) << 8) | ((v & 0xff00) >> 8);
|
||||
return __builtin_bswap16(v);
|
||||
}
|
||||
|
||||
static inline uint16_t htons(uint16_t v) {
|
||||
return ntohs(v);
|
||||
}
|
||||
|
||||
static inline uint32_t ntohl(uint32_t v) {
|
||||
// return ((v & 0x000000ff) << 24) |
|
||||
// ((v & 0x0000ff00) << 8) |
|
||||
// ((v & 0x00ff0000) >> 8) |
|
||||
// ((v & 0xff000000) >> 24);
|
||||
return __builtin_bswap32(v);
|
||||
}
|
||||
|
||||
static inline uint32_t htonl(uint32_t v) {
|
||||
return ntohl(v);
|
||||
}
|
||||
|
||||
#define ltohs(v) (v)
|
||||
#define ltohl(v) (v)
|
||||
|
||||
// Types for values in network byte-order. They are wrapped in structs so that
|
||||
// the compiler will disallow implicit casting of these types to or from
|
||||
// integral types. This way it is a compile error to try using variables of
|
||||
// these types without first performing a byte-order conversion.
|
||||
// There is no overhead for wrapping the values in structs.
|
||||
typedef struct net16 {
|
||||
uint16_t v;
|
||||
} net16;
|
||||
|
||||
typedef struct net32 {
|
||||
uint32_t v;
|
||||
} net32;
|
||||
|
||||
static inline uint16_t ntoh16(net16 net) {
|
||||
return ntohs(net.v);
|
||||
}
|
||||
|
||||
static inline net16 hton16(uint16_t v) {
|
||||
return (net16){ htons(v) };
|
||||
}
|
||||
|
||||
static inline uint32_t ntoh32(net32 net) {
|
||||
return ntohl(net.v);
|
||||
}
|
||||
|
||||
static inline net32 hton32(uint32_t v) {
|
||||
return (net32){ htonl(v) };
|
||||
}
|
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);
|
||||
}
|
97
platform/snowy/boot/src/util/version.h
Normal file
97
platform/snowy/boot/src/util/version.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define FW_METADATA_CURRENT_STRUCT_VERSION 0x1
|
||||
#define FW_METADATA_VERSION_SHORT_BYTES 8
|
||||
#define FW_METADATA_VERSION_TAG_BYTES 32
|
||||
|
||||
typedef enum {
|
||||
FirmwareMetadataPlatformUnknown = 0,
|
||||
FirmwareMetadataPlatformPebbleOneEV1 = 1,
|
||||
FirmwareMetadataPlatformPebbleOneEV2 = 2,
|
||||
FirmwareMetadataPlatformPebbleOneEV2_3 = 3,
|
||||
FirmwareMetadataPlatformPebbleOneEV2_4 = 4,
|
||||
FirmwareMetadataPlatformPebbleOnePointFive = 5,
|
||||
FirmwareMetadataPlatformPebbleTwoPointZero = 6,
|
||||
FirmwareMetadataPlatformPebbleOneBigboard = 0xff,
|
||||
FirmwareMetadataPlatformPebbleOneBigboard2 = 0xfe,
|
||||
} FirmwareMetadataPlatform;
|
||||
|
||||
// WARNING: changes in this struct must be reflected in:
|
||||
// - iOS/PebblePrivateKit/PebblePrivateKit/PBBundle.m
|
||||
|
||||
struct FirmwareMetadata {
|
||||
uint32_t version_timestamp;
|
||||
char version_tag[FW_METADATA_VERSION_TAG_BYTES];
|
||||
char version_short[FW_METADATA_VERSION_SHORT_BYTES];
|
||||
const bool is_recovery_firmware;
|
||||
const uint8_t hw_platform;
|
||||
const uint8_t metadata_version; //!< This should be the last field, since we put the meta data struct at the end of the fw binary.
|
||||
} __attribute__((__packed__));
|
||||
typedef struct FirmwareMetadata FirmwareMetadata;
|
||||
|
||||
extern const FirmwareMetadata TINTIN_METADATA;
|
||||
|
||||
//! Copies the version metadata of the running firmware in the provided struct.
|
||||
//! @param[out] out_metadata pointer to a FirmwareMetadata to which to copy the version metadata
|
||||
//! @returns true if it successfully copied the version metadata.
|
||||
bool version_copy_running_fw_metadata(FirmwareMetadata *out_metadata);
|
||||
|
||||
//! Copies the version metadata of the recovery firmware in the provided struct.
|
||||
//! If there is no valid metadata available, the struct will be wiped to be all zeroes.
|
||||
//! @param[out] out_metadata pointer to a FirmwareMetadata to which to copy the version metadata
|
||||
//! @returns true if it successfully copied the version metadata.
|
||||
bool version_copy_recovery_fw_metadata(FirmwareMetadata *out_metadata);
|
||||
|
||||
//! Copies the version metadata of the update firmware located in
|
||||
//! FLASH_REGION_FIRMWARE_SCRATCH_BEGIN into the provided struct.
|
||||
//! If there is no valid metadata available, the struct will be wiped to be all zeroes.
|
||||
//! @param[out] out_metadata pointer to a FirmwareMetadata to which to copy the version metadata
|
||||
//! @returns true if it successfully copied the version metadata.
|
||||
bool version_copy_update_fw_metadata(FirmwareMetadata *out_metadata);
|
||||
|
||||
//! Read recovery version_short from flash and copy to dest; copy at most
|
||||
//! dest_len_bytes - 1 before being null-terminated via strncpy()
|
||||
//!
|
||||
//! @param dest: char[dest_len_bytes]
|
||||
//! @returns true on success, false otherwise
|
||||
bool version_copy_recovery_fw_version(char* dest, const int dest_len_bytes);
|
||||
|
||||
//! Checks to see if a valid PRF is installed with a correct checksum.
|
||||
//! @return true if a PRF is installed, false otherwise.
|
||||
bool version_is_prf_installed(void);
|
||||
|
||||
//! @return Pointer to the GNU build id data. This is a hash of the firmware
|
||||
//! that is generated by the linker and uniquely identifies the binary.
|
||||
//! @param[out] out_len The length of the build id in bytes.
|
||||
const uint8_t * version_get_build_id(size_t *out_len);
|
||||
|
||||
//! Copies a hex C-string of the build id into the supplied buffer.
|
||||
//! Get the build id from an elf, using `arm-none-eabi-readelf -n tintin_fw.elf`
|
||||
//! @param[out] buffer The buffer into which the string should be copied.
|
||||
//! @param max_length The length of buffer.
|
||||
void version_copy_build_id_hex_string(char *buffer, size_t max_length);
|
||||
|
||||
//! Checks the firmware stored in FLASH_REGION_FIRMWARE_SCRATCH_BEGIN and compares it to the
|
||||
//! currently running firmware.
|
||||
//! @returns true if a downgrade is detected.
|
||||
bool version_fw_downgrade_detected(void);
|
Loading…
Add table
Add a link
Reference in a new issue