Browse Source

V1.0.0 Firmware / V1.05 Bootloader

v1.0.2-dev
Ken Carpenter 3 years ago
parent
commit
3ff22481e6
  1. 13
      DEVELOPMENT.md
  2. 2
      ports/stm32/Makefile
  3. 7
      ports/stm32/boards/Passport/.clang-format
  4. 4
      ports/stm32/boards/Passport/.reuse/dep5
  5. 16
      ports/stm32/boards/Passport/.vscode/c_cpp_properties.json
  6. 7
      ports/stm32/boards/Passport/.vscode/settings.json
  7. 4
      ports/stm32/boards/Passport/LICENSES/GPL-3.0-only.txt
  8. 4
      ports/stm32/boards/Passport/LICENSES/GPL-3.0-or-later.txt
  9. 438
      ports/stm32/boards/Passport/adc.c
  10. 16
      ports/stm32/boards/Passport/adc.h
  11. 20
      ports/stm32/boards/Passport/backlight.h
  12. 12
      ports/stm32/boards/Passport/bip39_utils.c
  13. 8
      ports/stm32/boards/Passport/bip39_utils.h
  14. 4109
      ports/stm32/boards/Passport/bip39_word_info.c
  15. 54
      ports/stm32/boards/Passport/board_init.c
  16. 2
      ports/stm32/boards/Passport/board_init.h
  17. 1
      ports/stm32/boards/Passport/bootloader/.gitignore
  18. 219
      ports/stm32/boards/Passport/bootloader/Makefile
  19. 142
      ports/stm32/boards/Passport/bootloader/bootloader_graphics.c
  20. 17
      ports/stm32/boards/Passport/bootloader/bootloader_graphics.h
  21. 137
      ports/stm32/boards/Passport/bootloader/flash.c
  22. 16
      ports/stm32/boards/Passport/bootloader/flash.h
  23. 35
      ports/stm32/boards/Passport/bootloader/link-script.ld
  24. 374
      ports/stm32/boards/Passport/bootloader/main.c
  25. 110
      ports/stm32/boards/Passport/bootloader/se-atecc608a.c
  26. 6
      ports/stm32/boards/Passport/bootloader/se-atecc608a.h
  27. BIN
      ports/stm32/boards/Passport/bootloader/secrets
  28. BIN
      ports/stm32/boards/Passport/bootloader/secrets-main-dev-se
  29. BIN
      ports/stm32/boards/Passport/bootloader/secrets-old
  30. BIN
      ports/stm32/boards/Passport/bootloader/secrets.unknown
  31. 19
      ports/stm32/boards/Passport/bootloader/splash.c
  32. 6
      ports/stm32/boards/Passport/bootloader/splash.h
  33. 4
      ports/stm32/boards/Passport/bootloader/startup.S
  34. 86
      ports/stm32/boards/Passport/bootloader/startup.s
  35. 243
      ports/stm32/boards/Passport/bootloader/ui.c
  36. 16
      ports/stm32/boards/Passport/bootloader/ui.h
  37. 299
      ports/stm32/boards/Passport/bootloader/update.c
  38. 6
      ports/stm32/boards/Passport/bootloader/update.h
  39. 123
      ports/stm32/boards/Passport/bootloader/verify.c
  40. 11
      ports/stm32/boards/Passport/bootloader/verify.h
  41. 6
      ports/stm32/boards/Passport/bootloader/version_info.h
  42. 196
      ports/stm32/boards/Passport/busy_bar.c
  43. 9
      ports/stm32/boards/Passport/busy_bar.h
  44. 269
      ports/stm32/boards/Passport/bytewords_word_info.c
  45. 34
      ports/stm32/boards/Passport/camera-ovm7690.c
  46. 5
      ports/stm32/boards/Passport/camera-ovm7690.h
  47. 4
      ports/stm32/boards/Passport/clang-format.txt
  48. 30
      ports/stm32/boards/Passport/common/backlight.c
  49. 4
      ports/stm32/boards/Passport/common/delay.c
  50. 187
      ports/stm32/boards/Passport/common/display.c
  51. 4
      ports/stm32/boards/Passport/common/gpio.c
  52. 100
      ports/stm32/boards/Passport/common/hash.c
  53. 64
      ports/stm32/boards/Passport/common/keypad-adp-5587.c
  54. 160
      ports/stm32/boards/Passport/common/lcd-sharp-ls018B7dh02.c
  55. 845
      ports/stm32/boards/Passport/common/passport_fonts.c
  56. 4
      ports/stm32/boards/Passport/common/pprng.c
  57. 72
      ports/stm32/boards/Passport/common/ring_buffer.c
  58. 315
      ports/stm32/boards/Passport/common/se.c
  59. 4
      ports/stm32/boards/Passport/common/spiflash.c
  60. 96
      ports/stm32/boards/Passport/common/utils.c
  61. 2
      ports/stm32/boards/Passport/debug-utils.c
  62. 2
      ports/stm32/boards/Passport/debug-utils.h
  63. 223
      ports/stm32/boards/Passport/dispatch.c
  64. 29
      ports/stm32/boards/Passport/dispatch.h
  65. 61
      ports/stm32/boards/Passport/docs/generic-wallet-export.md
  66. 71
      ports/stm32/boards/Passport/factory/test_ocd.py
  67. 142
      ports/stm32/boards/Passport/firmware_graphics.c
  68. 23
      ports/stm32/boards/Passport/firmware_graphics.h
  69. 159
      ports/stm32/boards/Passport/frequency.c
  70. 13
      ports/stm32/boards/Passport/frequency.h
  71. 5
      ports/stm32/boards/Passport/graphics/README
  72. 5
      ports/stm32/boards/Passport/graphics/c/.gitignore
  73. 24
      ports/stm32/boards/Passport/graphics/c/Makefile
  74. BIN
      ports/stm32/boards/Passport/graphics/c/busybar1.png
  75. BIN
      ports/stm32/boards/Passport/graphics/c/busybar2.png
  76. BIN
      ports/stm32/boards/Passport/graphics/c/busybar3.png
  77. BIN
      ports/stm32/boards/Passport/graphics/c/busybar4.png
  78. BIN
      ports/stm32/boards/Passport/graphics/c/busybar5.png
  79. BIN
      ports/stm32/boards/Passport/graphics/c/busybar6.png
  80. BIN
      ports/stm32/boards/Passport/graphics/c/busybar7.png
  81. 88
      ports/stm32/boards/Passport/graphics/c/cbuild.py
  82. 0
      ports/stm32/boards/Passport/graphics/c/splash.png
  83. 67
      ports/stm32/boards/Passport/graphics/graphics.py
  84. BIN
      ports/stm32/boards/Passport/graphics/loading1.png
  85. 6
      ports/stm32/boards/Passport/graphics/py/Makefile
  86. 0
      ports/stm32/boards/Passport/graphics/py/README.md
  87. 0
      ports/stm32/boards/Passport/graphics/py/arrow_down.txt
  88. 0
      ports/stm32/boards/Passport/graphics/py/arrow_up.txt
  89. 0
      ports/stm32/boards/Passport/graphics/py/battery_100.png
  90. 0
      ports/stm32/boards/Passport/graphics/py/battery_25.png
  91. 0
      ports/stm32/boards/Passport/graphics/py/battery_50.png
  92. 0
      ports/stm32/boards/Passport/graphics/py/battery_75.png
  93. 0
      ports/stm32/boards/Passport/graphics/py/battery_low.png
  94. 14
      ports/stm32/boards/Passport/graphics/py/build.py
  95. 2
      ports/stm32/boards/Passport/graphics/py/cylon.py
  96. BIN
      ports/stm32/boards/Passport/graphics/py/fcc-ce-logos.jpg
  97. BIN
      ports/stm32/boards/Passport/graphics/py/fcc-ce-logos.png
  98. 0
      ports/stm32/boards/Passport/graphics/py/fruit.png
  99. 87
      ports/stm32/boards/Passport/graphics/py/graphics.py
  100. BIN
      ports/stm32/boards/Passport/graphics/py/ie_logo.py

13
DEVELOPMENT.md

@ -51,7 +51,7 @@ You will need several shell windows or tabs open to interact with the various to
In one shell, make sure that you `cd` to the root `stm32` source folder, e.g., `cd ~/passport/ports/stm32`:
make BOARD=Passport
To include debug symbols for use in `ddd`, run the following:
make BOARD=Passport DEBUG=1
@ -71,6 +71,7 @@ private keys.
First, you need to build the `cosign` tool and copy it somewhere in your `PATH`:
sudo apt-get install libssl-dev
cd ports/stm32/boards/Passport/tools/cosign
make
cp x86/release/cosign ~/.local/bin # You can run `echo $PATH` to see the list of possible places you can put this file
@ -80,7 +81,7 @@ Next you need to sign the firmware twice. The `cosign` tool appends `-signed` t
Assuming you are still in the `ports/stm32` folder run the following:
# TODO: Update command arguments once final signing flow is in place
cosign -f build-Passport/firmware.bin -k 1 -v 0.9
cosign -f build-Passport/firmware.bin -k 1 -v 0.9
cosign -f build-Passport/firmware-signed.bin -k 2
You can also dump the contents of the firmware header with the following command:
@ -124,16 +125,18 @@ We use `telnet` to connect to the OpenOCD Server. Open a third shell and run th
From here can connect over JTAG and run a range of commands (see the help for OpenOCD for details):
Whenever you change any code in the `bootlaoder` folder or in the `common` folder, you will need to rebuild the bootloader (see above), and then flash it to the device with the following sequence in OpenOCD:
Whenever you change any code in the `bootloader` folder or in the `common` folder, you will need to rebuild the bootloader (see above), and then flash it to the device with the following sequence in OpenOCD:
reset halt
flash write_image erase boards/Passport/bootloader/bootloader.bin 0x8000000
flash write_image erase boards/Passport/bootloader/arm/release/bootloader.bin 0x8000000
reset
### TBD: Add docs on appending secrets to the end of the bootloader.bin file during development.
The following command sequence is one you will run repeatedly (i.e., after each build):
reset halt
flash write_image erase build-Passport/firmware-signed-signed.bin 0x8020000
flash write_image erase build-Passport/firmware-signed-signed.bin 0x8020000
reset
These commands do the following:

2
ports/stm32/Makefile

@ -119,7 +119,7 @@ ifeq ($(DEBUG), 1)
CFLAGS += -g -DPENDSV_DEBUG
COPT = -O0
else
COPT += -Os -DNDEBUG
COPT += -O2 -DNDEBUG
endif
# Options for mpy-cross

7
ports/stm32/boards/Passport/.clang-format

@ -0,0 +1,7 @@
---
# We'll use defaults from the LLVM style, but with 4 columns indentation.
BasedOnStyle: Mozilla
IndentWidth: 4
---
Language: Cpp
ColumnLimit: 120

4
ports/stm32/boards/Passport/.reuse/dep5

@ -12,9 +12,9 @@ Copyright: 2015, Kenneth MacKay
License: BSD-2-Clause
Files: graphics/*
Copyright: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
Copyright: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
License: GPL-3.0-or-later
Files: .vscode/settings.json TODO.txt bootloader/se-config.h clang-format.txt include/se-config.h modules/graphics.py pins.csv utils/README.md
Copyright: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
Copyright: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
License: GPL-3.0-or-later

16
ports/stm32/boards/Passport/.vscode/c_cpp_properties.json

@ -0,0 +1,16 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "gnu11",
"cppStandard": "gnu++14",
"intelliSenseMode": "gcc-x64"
}
],
"version": 4
}

7
ports/stm32/boards/Passport/.vscode/settings.json

@ -2,6 +2,9 @@
"files.associations": {
"array": "c",
"string": "c",
"string_view": "c"
}
"string_view": "c",
"algorithm": "c"
},
"python.linting.pylintEnabled": true,
"python.linting.enabled": true
}

4
ports/stm32/boards/Passport/LICENSES/GPL-3.0-only.txt

@ -574,10 +574,10 @@ version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.

4
ports/stm32/boards/Passport/LICENSES/GPL-3.0-or-later.txt

@ -574,10 +574,10 @@ version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.

438
ports/stm32/boards/Passport/adc.c

@ -1,18 +1,9 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// Copyright 2020 - Foundation Devices Inc.
//
/*
* Contains support for ADC3 - Board Revision
* and ADC2 for Power Monitor
* Init functions are called by board_init()
* read_boardrev() is called as needed, currently
* used by LCD display processing to determine active high/low for
* SPI1 NSS pin.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -47,19 +38,16 @@
static ADC_HandleTypeDef hadc3;
static ADC_HandleTypeDef hadc2;
/*
* adc2_init() - Sets up ADC2 which is used for Power Monitor and Noise inputs.
*/
HAL_StatusTypeDef adc2_init(void)
static HAL_StatusTypeDef adc2_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
HAL_StatusTypeDef ret = HAL_OK;
HAL_StatusTypeDef rc;
hadc2.Instance = ADC2;
ret = HAL_ADC_DeInit(&hadc2);
if(ret != HAL_OK) {
printf("Failed to DeInit ADC2\r\n");
return ret;
rc = HAL_ADC_DeInit(&hadc2);
if (rc != HAL_OK) {
printf("Failed to DeInit ADC2\n");
return rc;
}
__HAL_RCC_ADC12_CLK_ENABLE();
@ -107,25 +95,82 @@ HAL_StatusTypeDef adc2_init(void)
hadc3.Init.Oversampling.TriggeredMode = ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
hadc3.Init.Oversampling.OversamplingStopReset = ADC_REGOVERSAMPLING_CONTINUED_MODE;
ret = HAL_ADC_Init(&hadc2);
if (ret != HAL_OK)
rc = HAL_ADC_Init(&hadc2);
if (rc != HAL_OK)
{
printf("Failed to init ADC2\r\n");;
return ret;
printf("Failed to init ADC2\n");;
return rc;
}
/* Run the ADC calibration in single-ended mode */
ret = HAL_ADCEx_Calibration_Start(&hadc2, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);
if (ret != HAL_OK)
rc = HAL_ADCEx_Calibration_Start(&hadc2, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);
if (rc != HAL_OK)
{
printf("ADC3 calibration failed\r\n");
return ret;
printf("ADC3 calibration failed\n");
return rc;
}
return ret;
return HAL_OK;
}
void enable_noise(void) {
HAL_StatusTypeDef adc3_init(void)
{
HAL_StatusTypeDef rc;
hadc3.Instance = ADC3;
rc = HAL_ADC_DeInit(&hadc3);
if (rc != HAL_OK)
{
printf("Failed to deinit ADC3\n");
return rc;
}
__HAL_RCC_ADC3_CLK_ENABLE();
/**ADC3 GPIO Configuration
PC2_C ------> ADC3_INP0 - ALS_OUT
PC3_C ------> ADC3_INP1 - BDREV
*/
HAL_SYSCFG_AnalogSwitchConfig(SYSCFG_SWITCH_PC2 | SYSCFG_SWITCH_PC3,
SYSCFG_SWITCH_PC2_OPEN | SYSCFG_SWITCH_PC3_OPEN);
hadc3.Instance = ADC3;
hadc3.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2; // 4
hadc3.Init.Resolution = ADC_RESOLUTION_16B;
hadc3.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc3.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc3.Init.LowPowerAutoWait = DISABLE;
hadc3.Init.ContinuousConvMode = ENABLE; // DIS
hadc3.Init.NbrOfConversion = 1;
hadc3.Init.DiscontinuousConvMode = DISABLE;
hadc3.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc3.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
hadc3.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
hadc3.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
/*
* Perform oversampling to read multiple samples
* and compute the average in HW.
*/
hadc3.Init.OversamplingMode = ENABLE;
hadc3.Init.Oversampling.Ratio = 0x20; /* Bit for 32x oversampling */
hadc3.Init.Oversampling.RightBitShift = ADC_RIGHTBITSHIFT_5;
hadc3.Init.Oversampling.TriggeredMode = ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
hadc3.Init.Oversampling.OversamplingStopReset = ADC_REGOVERSAMPLING_CONTINUED_MODE;
rc = HAL_ADC_Init(&hadc3);
if (rc != HAL_OK)
{
printf("ADC3 init failed\n");
return rc;
}
return HAL_OK;
}
void adc_enable_noise(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/*
@ -143,13 +188,13 @@ void enable_noise(void) {
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_10, 1);
}
void disable_noise(void) {
void adc_disable_noise(void)
{
/*
* PD8 Amp2_enable
* PD9 Amp1_enable
* PD10 Noise Bias enable
*/
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8, 0);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_9, 0);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_10, 0);
@ -160,8 +205,12 @@ void disable_noise(void) {
* read_noise_inputs() - Reads the two noise output channels and returns
* the count values read.
*/
HAL_StatusTypeDef read_noise_inputs(uint32_t * noise1, uint32_t * noise2) {
HAL_StatusTypeDef ret = HAL_OK;
int adc_read_noise_inputs(
uint32_t *noise1,
uint32_t *noise2
)
{
HAL_StatusTypeDef rc;
ADC_ChannelConfTypeDef sConfig = {0};
/* Configure Noiseout 1 input Channel */
@ -174,35 +223,35 @@ HAL_StatusTypeDef read_noise_inputs(uint32_t * noise1, uint32_t * noise2) {
sConfig.Offset = 0;
sConfig.OffsetRightShift = DISABLE; /* No Right Offset Shift */
sConfig.OffsetSignedSaturation = DISABLE; /* No Signed Saturation */
ret = HAL_ADC_ConfigChannel(&hadc2, &sConfig);
if (ret != HAL_OK)
rc = HAL_ADC_ConfigChannel(&hadc2, &sConfig);
if (rc != HAL_OK)
{
printf("Failed to config ADC2 channel 8\r\n");;
return ret;
printf("Failed to config ADC2 channel 8\n");;
return -1;
}
/* Start processing for current (I) values */
ret = HAL_ADC_Start(&hadc2);
if (ret != HAL_OK)
rc = HAL_ADC_Start(&hadc2);
if (rc != HAL_OK)
{
printf("ADC2 start failed\r\n");
return ret;
printf("ADC2 start failed\n");
return -1;
}
ret = HAL_ADC_PollForConversion(&hadc2, HAL_MAX_DELAY);
if (ret != HAL_OK)
rc = HAL_ADC_PollForConversion(&hadc2, HAL_MAX_DELAY);
if (rc != HAL_OK)
{
printf("ADC2 poll for conversion failed\r\n");
return ret;
printf("ADC2 poll for conversion failed\n");
return -1;
}
*noise1 = HAL_ADC_GetValue(&hadc2);
ret = HAL_ADC_Stop(&hadc2);
if (ret != HAL_OK)
rc = HAL_ADC_Stop(&hadc2);
if (rc != HAL_OK)
{
printf("ADC2 start failed\r\n");
return ret;
printf("ADC2 start failed\n");
return -1;
}
/* Configure Noiseout 2 input Channel */
@ -210,45 +259,49 @@ HAL_StatusTypeDef read_noise_inputs(uint32_t * noise1, uint32_t * noise2) {
sConfig.Channel = ADC_CHANNEL_10;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5;
ret = HAL_ADC_ConfigChannel(&hadc2, &sConfig);
if (ret != HAL_OK)
rc = HAL_ADC_ConfigChannel(&hadc2, &sConfig);
if (rc != HAL_OK)
{
printf("Failed to config ADC2 channel 4\r\n");;
return ret;
printf("Failed to config ADC2 channel 4\n");;
return -1;
}
/* Now sample for Noise output 2 */
ret = HAL_ADC_Start(&hadc2);
if (ret != HAL_OK)
rc = HAL_ADC_Start(&hadc2);
if (rc != HAL_OK)
{
printf("ADC2 start failed\r\n");
return ret;
printf("ADC2 start failed\n");
return -1;
}
ret = HAL_ADC_PollForConversion(&hadc2, HAL_MAX_DELAY);
if (ret != HAL_OK)
rc = HAL_ADC_PollForConversion(&hadc2, HAL_MAX_DELAY);
if (rc != HAL_OK)
{
printf("ADC2 poll for conversion failed\r\n");
return ret;
printf("ADC2 poll for conversion failed\n");
return -1;
}
*noise2 = HAL_ADC_GetValue(&hadc2);
ret = HAL_ADC_Stop(&hadc2);
if (ret != HAL_OK)
rc = HAL_ADC_Stop(&hadc2);
if (rc != HAL_OK)
{
printf("ADC2 start failed\r\n");
return ret;
printf("ADC2 start failed\n");
return -1;
}
return ret;
return 0;
}
/*
* read_powermon() Reads the power monitor current and voltage channels
* adc_read_powermon() Reads the power monitor current and voltage channels
*/
HAL_StatusTypeDef read_powermon(uint16_t * current, uint16_t * voltage) {
HAL_StatusTypeDef ret = HAL_OK;
int adc_read_powermon(
uint16_t *current,
uint16_t *voltage
)
{
HAL_StatusTypeDef rc;
ADC_ChannelConfTypeDef sConfig = {0};
uint32_t adc_value_i;
@ -264,26 +317,26 @@ HAL_StatusTypeDef read_powermon(uint16_t * current, uint16_t * voltage) {
sConfig.Offset = 0;
sConfig.OffsetRightShift = DISABLE; /* No Right Offset Shift */
sConfig.OffsetSignedSaturation = DISABLE; /* No Signed Saturation */
ret = HAL_ADC_ConfigChannel(&hadc2, &sConfig);
if (ret != HAL_OK)
rc = HAL_ADC_ConfigChannel(&hadc2, &sConfig);
if (rc != HAL_OK)
{
printf("Failed to config ADC2 channel 8\r\n");;
return ret;
printf("Failed to config ADC2 channel 8\n");;
return -1;
}
// Start processing for current (I) values
ret = HAL_ADC_Start(&hadc2);
if (ret != HAL_OK)
rc = HAL_ADC_Start(&hadc2);
if (rc != HAL_OK)
{
printf("ADC2 start failed\r\n");
return ret;
printf("ADC2 start failed\n");
return -1;
}
ret = HAL_ADC_PollForConversion(&hadc2, HAL_MAX_DELAY);
if (ret != HAL_OK)
rc = HAL_ADC_PollForConversion(&hadc2, HAL_MAX_DELAY);
if (rc != HAL_OK)
{
printf("ADC2 poll for conversion failed\r\n");
return ret;
printf("ADC2 poll for conversion failed\n");
return -1;
}
adc_value_i = HAL_ADC_GetValue(&hadc2);
@ -294,11 +347,11 @@ HAL_StatusTypeDef read_powermon(uint16_t * current, uint16_t * voltage) {
*current = ((adc_value_i * REF_VOLTAGE_MV) / MAX_SAMPLES_CNT) / PWRMON_I_SENSE_RESISTOR;
ret = HAL_ADC_Stop(&hadc2);
if (ret != HAL_OK)
rc = HAL_ADC_Stop(&hadc2);
if (rc != HAL_OK)
{
printf("ADC2 start failed\r\n");
return ret;
printf("ADC2 start failed\n");
return -1;
}
/* Switch to the voltage channel */
@ -306,166 +359,177 @@ HAL_StatusTypeDef read_powermon(uint16_t * current, uint16_t * voltage) {
sConfig.Channel = ADC_CHANNEL_4;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5;
ret = HAL_ADC_ConfigChannel(&hadc2, &sConfig);
if (ret != HAL_OK)
rc = HAL_ADC_ConfigChannel(&hadc2, &sConfig);
if (rc != HAL_OK)
{
printf("Failed to config ADC2 channel 4\r\n");;
return ret;
printf("Failed to config ADC2 channel 4\n");;
return -1;
}
/* Now sample for voltage (V) */
ret = HAL_ADC_Start(&hadc2);
if (ret != HAL_OK)
rc = HAL_ADC_Start(&hadc2);
if (rc != HAL_OK)
{
printf("ADC2 start failed\r\n");
return ret;
printf("ADC2 start failed\n");
return -1;
}
ret = HAL_ADC_PollForConversion(&hadc2, HAL_MAX_DELAY);
if (ret != HAL_OK)
rc = HAL_ADC_PollForConversion(&hadc2, HAL_MAX_DELAY);
if (rc != HAL_OK)
{
printf("ADC2 poll for conversion failed\r\n");
return ret;
printf("ADC2 poll for conversion failed\n");
return -1;
}
adc_value_v = HAL_ADC_GetValue(&hadc2);
*voltage = (adc_value_v * REF_VOLTAGE_MV) / MAX_SAMPLES_CNT;
ret = HAL_ADC_Stop(&hadc2);
if (ret != HAL_OK)
rc = HAL_ADC_Stop(&hadc2);
if (rc != HAL_OK)
{
printf("ADC2 start failed\r\n");
return ret;
printf("ADC2 start failed\n");
return -1;
}
return ret;
return 0;
}
/*
* adc3_init() - Set up ADC3 which is used for the board revision
* adc_read_als() - Reads the ambient light sensor channel
* and returns a numeric value based on the milli-volts
* read divided by the number of milli-volts per revision.
*/
HAL_StatusTypeDef adc3_init(void)
int adc_read_als(
uint16_t *als
)
{
HAL_StatusTypeDef ret = HAL_OK;
HAL_StatusTypeDef rc;
ADC_ChannelConfTypeDef sConfig = {0};
uint32_t adc_value;
uint16_t millivolts;
hadc3.Instance = ADC3;
ret = HAL_ADC_DeInit(&hadc3);
if (ret != HAL_OK)
{
printf("Failed to deinit ADC3\r\n");
return ret;
}
/*
* PC3 ----> ADC3 INP1
*/
__HAL_RCC_ADC3_CLK_ENABLE();
/**ADC3 GPIO Configuration
PC3_C ------> ADC3_INP1
*/
HAL_SYSCFG_AnalogSwitchConfig(SYSCFG_SWITCH_PC3, SYSCFG_SWITCH_PC3_OPEN);
hadc3.Instance = ADC3;
hadc3.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2; // 4
hadc3.Init.Resolution = ADC_RESOLUTION_16B;
hadc3.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc3.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc3.Init.LowPowerAutoWait = DISABLE;
hadc3.Init.ContinuousConvMode = ENABLE; // DIS
hadc3.Init.NbrOfConversion = 1;
hadc3.Init.DiscontinuousConvMode = DISABLE;
hadc3.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc3.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
hadc3.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
hadc3.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
*als = 0;
/*
* Perform oversampling to read multiple samples
* and compute the average in HW.
*/
hadc3.Init.OversamplingMode = ENABLE;
hadc3.Init.Oversampling.Ratio = 0x20; /* Bit for 32x oversampling */
hadc3.Init.Oversampling.RightBitShift = ADC_RIGHTBITSHIFT_5;
hadc3.Init.Oversampling.TriggeredMode = ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
hadc3.Init.Oversampling.OversamplingStopReset = ADC_REGOVERSAMPLING_CONTINUED_MODE;
ret = HAL_ADC_Init(&hadc3);
if (ret != HAL_OK)
{
printf("ADC3 init failed\r\n");
return ret;
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
ret = HAL_ADC_ConfigChannel(&hadc3, &sConfig);
if (ret != HAL_OK)
rc = HAL_ADC_ConfigChannel(&hadc3, &sConfig);
if (rc != HAL_OK)
{
printf("Failed to config ADC3 channel\r\n");
printf("Failed to config ADC3 channel\n");
return -1;
}
/* Run the ADC calibration in single-ended mode */
ret = HAL_ADCEx_Calibration_Start(&hadc3, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);
if (ret != HAL_OK)
rc = HAL_ADCEx_Calibration_Start(&hadc3, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);
if (rc != HAL_OK)
{
printf("ADC3 calibration failed\n");
return -1;
}
rc = HAL_ADC_Start(&hadc3);
if (rc != HAL_OK)
{
printf("ADC3 start failed\n");
return -1;
}
rc = HAL_ADC_PollForConversion(&hadc3, HAL_MAX_DELAY);
if (rc != HAL_OK)
{
printf("ADC3 calibration failed\r\n");
printf("ADC3 poll for conversion failed\n");
return -1;
}
adc_value = HAL_ADC_GetValue(&hadc3);
HAL_ADC_Stop(&hadc3);
millivolts = (((adc_value) * REF_VOLTAGE_MV) / MAX_SAMPLES_CNT);
return ret;
*als = millivolts; /* Upper-level code will scale this as needed */
return 0;
}
/*
* read_boardrev() - Reads the board revision channel
* adc_read_boardrev() - Reads the board revision channel
* and returns a numeric value based on the milli-volts
* read divided by the number of milli-volts per revision.
*/
HAL_StatusTypeDef read_boardrev(uint16_t * board_rev)
int adc_read_boardrev(
uint16_t *board_rev
)
{
HAL_StatusTypeDef ret = HAL_OK;
HAL_StatusTypeDef rc;
ADC_ChannelConfTypeDef sConfig = {0};
uint32_t adc_value;
uint16_t millivolts;
ret = HAL_ADC_Start(&hadc3);
if (ret != HAL_OK)
*board_rev = 0;
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
rc = HAL_ADC_ConfigChannel(&hadc3, &sConfig);
if (rc != HAL_OK)
{
printf("ADC3 start failed\r\n");
return ret;
printf("Failed to config ADC3 channel\n");
return -1;
}
ret = HAL_ADC_PollForConversion(&hadc3, HAL_MAX_DELAY);
if (ret != HAL_OK)
/* Run the ADC calibration in single-ended mode */
rc = HAL_ADCEx_Calibration_Start(&hadc3, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);
if (rc != HAL_OK)
{
printf("ADC3 poll for conversion failed\r\n");
return ret;
printf("ADC3 calibration failed\n");
return -1;
}
rc = HAL_ADC_Start(&hadc3);
if (rc != HAL_OK)
{
printf("ADC3 start failed\n");
return -1;
}
rc = HAL_ADC_PollForConversion(&hadc3, HAL_MAX_DELAY);
if (rc != HAL_OK)
{
printf("ADC3 poll for conversion failed\n");
return -1;
}
adc_value = HAL_ADC_GetValue(&hadc3);
HAL_ADC_Stop(&hadc3);
/*
* The ADC consistently reads low when taking a single sample.
* For now add an offset to make sure that we can properly compute the board rev number
* TODO: This will need to be tested with the next board revision to make sure that it tracks properly.
*/
millivolts = (((adc_value) * REF_VOLTAGE_MV) / MAX_SAMPLES_CNT); // + BOARD_REV_MV_OFFSET;
millivolts = (((adc_value) * REF_VOLTAGE_MV) / MAX_SAMPLES_CNT);
/*
* Determine the board revision based on the milli-volts, probably will
* need a tolerance for example if we are looking for 100 mv increments
* then maybe have a +/- 6 mv window.
*
*/
printf("[%s] millivolts: %u\n", __func__, millivolts);
*board_rev = millivolts / MILLIVOLTS_PER_REVISION;
return ret;
return 0;
}
int adc_init(void)
{
HAL_StatusTypeDef rc;
rc = adc2_init();
if (rc != HAL_OK)
return -1;
rc = adc3_init();
if (rc != HAL_OK)
return -1;
return 0;
}

16
ports/stm32/boards/Passport/adc.h

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// Copyright 2020 - Foundation Devices Inc.
@ -7,12 +7,12 @@
#ifndef _ADC_H_
#define _ADC_H_
extern HAL_StatusTypeDef adc3_init(void);
extern HAL_StatusTypeDef adc2_init(void);
extern HAL_StatusTypeDef read_boardrev(uint16_t * board_rev);
extern HAL_StatusTypeDef read_powermon(uint16_t * current, uint16_t * voltage);
extern void enable_noise(void);
extern void disable_noise(void);
extern HAL_StatusTypeDef read_noise_inputs(uint32_t * noise1, uint32_t * noise2);
extern int adc_init(void);
extern int adc_read_als(uint16_t *als);
extern int adc_read_boardrev(uint16_t *board_rev);
extern int adc_read_powermon(uint16_t *current, uint16_t *voltage);
extern void adc_enable_noise(void);
extern void adc_disable_noise(void);
extern int adc_read_noise_inputs(uint32_t *noise1, uint32_t *noise2);
#endif //_ADC_H_

20
ports/stm32/boards/Passport/backlight.h

@ -1,20 +0,0 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// SPDX-FileCopyrightText: 2018 Coinkite, Inc.
// SPDX-License-Identifier: GPL-3.0-only
//
// Backlight driver for LED
#ifndef STM32_BACKLIGHT_H
#define STM32_BACKLIGHT_H
#include "stm32h7xx_hal.h"
#include <stdio.h>
#include <stdlib.h>
void backlight_init(void);
void backlight_intensity(uint16_t intensity);
#endif //STM32_BACKLIGHT_H

12
ports/stm32/boards/Passport/bip39_utils.c

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
@ -12,7 +12,7 @@
#include "bip39_utils.h"
extern word_info_t word_info[];
extern word_info_t bip39_word_info[];
#ifdef UNUSED_CODE
uint32_t letter_to_number(char ch) {
@ -77,19 +77,19 @@ uint8_t starts_with(const char* s, const char* prefix) {
}
// Fills in `matches` with a comma-separated list of matching words
void get_words_matching_prefix(char* prefix, char* matches, uint32_t matches_len, uint32_t max_matches) {
void get_words_matching_prefix(char* prefix, char* matches, uint32_t matches_len, uint32_t max_matches, const word_info_t* word_info, uint32_t num_words) {
char* pnext_match = matches;
char candidate_keypad_digits[MAX_WORD_LEN + 1];
uint32_t num_matches = 0;
uint32_t total_written = 0;
for (uint32_t i = 0; i < NUM_WORDS; i++) {
for (uint32_t i = 0; i < num_words; i++) {
snprintf(candidate_keypad_digits, MAX_WORD_LEN + 1, "%lu", word_info[i].keypad_digits);
if (starts_with(candidate_keypad_digits, prefix)) {
// This is a match, so convert the offsets to a real string and append to the buffer
uint32_t len = word_info_to_string(candidate_keypad_digits, word_info[i].offsets, pnext_match);
if (total_written + len > matches_len - 1) {
// Don't write this one, as there is not enough room
// Don't write this one, as there is not enough room
break;
}
total_written += len;
@ -112,5 +112,3 @@ void get_words_matching_prefix(char* prefix, char* matches, uint32_t matches_len
}
*pnext_match = 0;
}

8
ports/stm32/boards/Passport/bip39_utils.h

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
@ -6,7 +6,7 @@
// This structure stores the keypad digits required for a word (max 8 digits) in `keypad_digits`.
//
// The `offsets` field contains 8 sets of 2 bits each. Each 2-bit value is
// The `offsets` field contains 8 sets of 2 bits each. Each 2-bit value is
// an offset from the corresponding keypad digit:
//
// Examples:
@ -15,7 +15,7 @@
// On the '7' key, offset of 'p' is 0, 'q' is 1 and 'r' is 2, and 's' is 3.
//
// If keypad_digits is '234', representing the word 'beg', then the offsets
// are 'b'=b01, 'e'=b01, 'g'=b00. The bits are encoded starting at the high end of the
// are 'b'=b01, 'e'=b01, 'g'=b00. The bits are encoded starting at the high end of the
// 16-bit value, so the final `offsets` value for '234' and 'beg' is b0101000000000000 or 0x5000.
typedef struct {
@ -23,4 +23,4 @@ typedef struct {
uint16_t offsets;
} word_info_t;
void get_words_matching_prefix(char* prefix, char* matches, uint32_t matches_len, uint32_t max_matches);
void get_words_matching_prefix(char* prefix, char* matches, uint32_t matches_len, uint32_t max_matches, const word_info_t* word_info, uint32_t num_words);

4109
ports/stm32/boards/Passport/bip39_word_info.c

File diff suppressed because it is too large

54
ports/stm32/boards/Passport/board_init.c

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
@ -6,13 +6,18 @@
#include "stm32h7xx_hal.h"
#include "gpio.h"
#include "backlight.h"
#include "adc.h"
#include "backlight.h"
#include "camera-ovm7690.h"
#include "lcd-sharp-ls018B7dh02.h"
#include "display.h"
#include "frequency.h"
#include "gpio.h"
#include "image_conversion.h"
#include "py/mphal.h"
#include "lcd-sharp-ls018B7dh02.h"
#include "busy_bar.h"
#include "se.h"
#include "utils.h"
#include "se.h"
#define QR_IMAGE_SIZE (CAMERA_WIDTH * CAMERA_HEIGHT)
#define VIEWFINDER_IMAGE_SIZE ((240 * 303) / 8)
@ -20,28 +25,27 @@
uint8_t qr[QR_IMAGE_SIZE];
uint8_t dp[VIEWFINDER_IMAGE_SIZE];
void Passport_board_init(void)
void
Passport_board_init(void)
{
/* Enable the console UART */
frequency_update_console_uart();
printf("[%s]\n", __func__);
printf("%lu, %lu, %lu, %lu, %lu\n", HAL_RCC_GetSysClockFreq(), SystemCoreClock, HAL_RCC_GetHCLKFreq(), HAL_RCC_GetPCLK1Freq(), HAL_RCC_GetPCLK2Freq());
set_stack_sentinel();
gpio_init();
backlight_init();
lcd_init();
// backlight_init(); Not necessary as we call backlight_minimal_init() from the Backlight class in modfoundation.c
display_init(false);
camera_init();
adc2_init();
adc3_init();
#if 0
backlight_intensity(250);
camera_on();
while (1)
{
camera_snapshot();
convert_rgb565_to_grayscale_and_mono(camera_frame_buffer, qr, CAMERA_HEIGHT, CAMERA_WIDTH, dp, 240, 240);
lcd_update(dp, 0);
HAL_Delay(10);
}
#endif
}
adc_init();
busy_bar_init();
se_setup();
void Passport_board_early_init(void)
{
// check_stack("Passport_board_init() complete", true);
}
void
Passport_board_early_init(void)
{}

2
ports/stm32/boards/Passport/board_init.h

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//

1
ports/stm32/boards/Passport/bootloader/.gitignore

@ -0,0 +1 @@
version_info.c

219
ports/stm32/boards/Passport/bootloader/Makefile

@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
# SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
# SPDX-License-Identifier: GPL-3.0-only
#
# "Bootloader" Makefile
@ -12,6 +12,8 @@
# clobber - delete all build products
#
BOOTLOADER_VERSION = 1.05
# Toolchain
TOOLCHAIN = arm-none-eabi-
CC = $(TOOLCHAIN)gcc
@ -31,40 +33,58 @@ PASSPORT_PATH = ..
VPATH = $(HAL_DRIVERS_PATH)
VPATH += $(HAL_CMSIS_PATH)
VPATH += $(HAL_CMSIS_PATH)/gcc
VPATH += $(PASSPORT_PATH)/common
VPATH += $(PASSPORT_PATH)/common/micro-ecc
# Basename of all targets
TARGET_NAME = bootloader
TARGETDIR = arm
# Source files. Important: Add them also to link-script.ld to control placement.
OBJS += startup.o
OBJS += main.o
OBJS += flash.o
OBJS += update.o
OBJS += verify.o
OBJS += se-atecc608a.o
OBJS += delay.o
OBJS += hash.o
OBJS += pprng.o
OBJS += se.o
OBJS += sha256.o
OBJS += spiflash.o
OBJS += uECC.o
OBJS += utils.o
OBJS += system_stm32h7xx.o
OBJS += stm32h7xx_hal.o
OBJS += stm32h7xx_hal_rcc.o
OBJS += stm32h7xx_hal_rcc_ex.o
OBJS += stm32h7xx_hal_gpio.o
OBJS += stm32h7xx_hal_cortex.o
OBJS += stm32h7xx_hal_pwr.o
OBJS += stm32h7xx_hal_pwr_ex.o
OBJS += stm32h7xx_hal_spi.o
OBJS += stm32h7xx_hal_dma.o
# Files specific to the bootloader
SOURCES = startup_stm32h753xx.c
SOURCES += startup.c
SOURCES += bootloader_graphics.c
SOURCES += main.c
SOURCES += flash.c
SOURCES += splash.c
SOURCES += update.c
SOURCES += se-atecc608a.c
SOURCES += ui.c
SOURCES += verify.c
SOURCES += version_info.c
# Common files between bootloader and MP
SOURCES += backlight.c
SOURCES += delay.c
SOURCES += display.c
SOURCES += gpio.c
SOURCES += hash.c
SOURCES += lcd-sharp-ls018B7dh02.c
SOURCES += passport_fonts.c
SOURCES += pprng.c
SOURCES += se.c
SOURCES += sha256.c
SOURCES += spiflash.c
SOURCES += uECC.c
SOURCES += utils.c
SOURCES += system_stm32h7xx.c
SOURCES += stm32h7xx_hal.c
SOURCES += stm32h7xx_hal_rcc.c
SOURCES += stm32h7xx_hal_rcc_ex.c
SOURCES += stm32h7xx_hal_gpio.c
SOURCES += stm32h7xx_hal_cortex.c
SOURCES += stm32h7xx_hal_pwr.c
SOURCES += stm32h7xx_hal_pwr_ex.c
SOURCES += stm32h7xx_hal_spi.c
SOURCES += stm32h7xx_hal_dma.c
# Required for LCD support
SOURCES += stm32h7xx_hal_tim.c
SOURCES += stm32h7xx_hal_tim_ex.c
# Where we will end up in the memory map (at start of flash)
BL_FLASH_BASE = 0x08000000
@ -72,32 +92,52 @@ BL_FLASH_SIZE = 0x20000
BL_FLASH_LAST = 0x08020000
# SRAM4 is reserved for us.
BL_SRAM_BASE = 0x38000000
BL_SRAM_SIZE = 0x00008000
BL_SRAM_BASE = 0x20000000
BL_SRAM_SIZE = 0x00020000
# Final 2k bytes reserved for data (not code)
# - must be page-aligned, contains pairing secret
#BL_NVROM_BASE = 0x0801F000 # final area for ROM secrets
#BL_NVROM_SIZE = 0x1000
BL_NVROM_BASE = 0x081C0000 # temporary for development
BL_NVROM_SIZE = 0x1000
# Final 1k bytes reserved for data (not code)
BL_NVROM_BASE = 0x0801FF00 # final area for ROM secrets
#BL_NVROM_BASE = 0x081C0000 # temporary for development
BL_NVROM_SIZE = 0x100
# Compiler flags.
CFLAGS = -Wall --std=gnu99 -g
CFLAGS = -Wall -Werror --std=gnu99
CFLAGS += -Wno-address-of-packed-member
CFLAGS += -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard
CFLAGS += -ffunction-sections -fdata-sections
CFLAGS += -mtune=cortex-m7 -mcpu=cortex-m7 -DSTM32H753xx
CFLAGS += -I. -I$(PASSPORT_PATH)/include -I$(PASSPORT_PATH)/common/micro-ecc
CFLAGS += -DPASSPORT_BOOTLOADER
#CFLAGS += -DUSE_CRYPTO
CFLAGS += -DDEMO
CFLAGS += -DUSE_CRYPTO
ifeq ($(findstring production,$(MAKECMDGOALS)),production)
CFLAGS += -DPRODUCTION_BUILD
endif
#CFLAGS += -DCONVERSION_BUILD
ifeq ($(findstring locked,$(MAKECMDGOALS)),locked)
CFLAGS += -DLOCKED
endif
# Pass in the locations of stuff
CFLAGS += -D BL_FLASH_BASE=$(BL_FLASH_BASE) -D BL_FLASH_SIZE=$(BL_FLASH_SIZE)
CFLAGS += -D BL_NVROM_BASE=$(BL_NVROM_BASE) -D BL_NVROM_SIZE=$(BL_NVROM_SIZE)
CFLAGS += -D BL_SRAM_BASE=$(BL_SRAM_BASE) -D BL_SRAM_SIZE=$(BL_SRAM_SIZE)
CFLAGS += -D BL_SRAM_BASE=$(BL_SRAM_BASE) -D BL_SRAM_SIZE=$(BL_SRAM_SIZE)
CFLAGS += -D BL_FLASH_LAST=$(BL_FLASH_LAST)
ifeq ($(findstring debug,$(MAKECMDGOALS)),debug)
OBJDIR = $(TARGETDIR)/debug
CFLAGS += -g -DDEBUG
LDFLAGS += -g
else
OBJDIR = $(TARGETDIR)/release
CFLAGS += -O2
# Add keypad support for release builds
SOURCES += keypad-adp-5587.c
SOURCES += ring_buffer.c
SOURCES += stm32h7xx_hal_i2c.c
endif
OBJECTS = $(addprefix $(OBJDIR)/,$(SOURCES:.c=.o))
CC_SYMBOLS = -mcpu=cortex-m7
# Header file search path
@ -112,7 +152,7 @@ CFLAGS += $(foreach INC,$(INC_PATHS),-I$(INC))
#
LINKER_SCRIPT = link-script.ld
LDFLAGS += -flto -Wl,--gc-sections --specs=nano.specs -Wl,-T$(LINKER_SCRIPT)
LDFLAGS += -flto -Wl,--gc-sections -specs=nano.specs -Wl,-T$(LINKER_SCRIPT)
LDFLAGS += -nostartfiles
LDFLAGS += -Wl,--defsym,BL_FLASH_BASE=$(BL_FLASH_BASE)
LDFLAGS += -Wl,--defsym,BL_FLASH_SIZE=$(BL_FLASH_SIZE)
@ -120,100 +160,63 @@ LDFLAGS += -Wl,--defsym,BL_NVROM_BASE=$(BL_NVROM_BASE)
LDFLAGS += -Wl,--defsym,BL_NVROM_SIZE=$(BL_NVROM_SIZE)
LDFLAGS += -Wl,--defsym,BL_SRAM_BASE=$(BL_SRAM_BASE)
LDFLAGS += -Wl,--defsym,BL_SRAM_SIZE=$(BL_SRAM_SIZE)
LDFLAGS += -Wl,-Map=$(TARGET_NAME).map
LDFLAGS += -Wl,-Map=$(OBJDIR)/$(TARGET_NAME).map
ASFLAGS += -Wa,--defsym,BL_FLASH_BASE=$(BL_FLASH_BASE) -Wa,--defsym,BL_FLASH_SIZE=$(BL_FLASH_SIZE)
ASFLAGS += -Wa,--defsym,BL_SRAM_BASE=$(BL_SRAM_BASE) -Wa,--defsym,BL_SRAM_SIZE=$(BL_SRAM_SIZE)
TARGET_ELF = $(TARGET_NAME).elf
TARGETS = $(TARGET_NAME).bin
TARGET_ELF = $(OBJDIR)/$(TARGET_NAME).elf
TARGETS = $(OBJDIR)/$(TARGET_NAME).bin
all: version $(TARGETS)
debug: version $(TARGETS)
all: $(TARGETS)
locked: version $(TARGETS)
production: version $(TARGETS)
# recompile on any change, because with a small project like this...
$(OBJS): Makefile
$(OBJECTS): Makefile
$(TARGETS): $(TARGET_ELF) Makefile
# link step
$(TARGET_ELF): $(OBJS) $(LINKER_SCRIPT) Makefile
$(CC) $(CFLAGS) -o $(TARGET_ELF) $(LDFLAGS) $(OBJS)
$(TARGET_ELF): $(OBJECTS) $(LINKER_SCRIPT) Makefile
$(CC) $(CFLAGS) $(LDFLAGS) -o $(TARGET_ELF) $(OBJECTS)
$(SIZE) -Ax $@
%.o: %.S
$(OBJDIR)/%.o: %.s
@rm -f $@
@[ -d $(dir $@) ] || mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c -o $@ $<
%.o: %.c
$(OBJDIR)/%.o: %.c
@rm -f $@
@[ -d $(dir $@) ] || mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c -MMD -MP -o $@ $<
# raw binary, forced to right size, pad w/ 0xff
%.bin: $(TARGET_ELF)
$(OBJCOPY) -O binary --pad-to $(BL_FLASH_LAST) --gap-fill 0xff $< $@.tmp
$(OBJDIR)/%.bin: $(TARGET_ELF)
$(OBJCOPY) -O binary --pad-to $$(($(BL_FLASH_LAST) - $(BL_NVROM_SIZE))) --gap-fill 0x00 $< $@.tmp
dd bs=$$(($(BL_FLASH_SIZE) * 1024)) count=1 if=$@.tmp of=$@
@$(RM) $@.tmp
ifneq ($(MAKECMDGOALS),clean)
-include $(OBJS:.o=.d)
-include $(OBJECTS:.o=.d)
endif
# make a 'release' build
release: code-committed check-fontawesome clean all capture
release: CFLAGS += -DRELEASE=1 -Werror
check-fontawesome:
# You must have commerical license for Font Awesome (altho fallback looks ok)
test -f assets/FontAwesome5Pro-Light-300.otf
.PHONY: code-committed
code-committed:
@echo ""
@echo "Are all changes commited already?"
git diff --stat --exit-code .
@echo '... yes'
# these files are what we capture and store for each release.
DELIVERABLES = $(TARGET_NAME).bin
checksums.txt: $(DELIVERABLES)
shasum -a 256 $(DELIVERABLES) > $@
# Track released versions
.PHONY: capture
capture: version.txt version-full.txt $(DELIVERABLES) checksums.txt
V=`cat version.txt` && cat checksums.txt > releases/$$V.txt && cat version-full.txt >> releases/$$V.txt && mkdir -p releases/$$V; cp $(DELIVERABLES) releases/$$V
@echo
@echo " Version: " `cat version.txt`
@echo
V=`cat version.txt` && git tag -am "Bootloader version $$V" "bootloader-"$$V
git add -f releases/*/bootloader.* releases/*.txt
# Pull out the version string from binary object (already linked in) and
# construct a text file (version.txt) with those contents
version.txt version-full.txt: version.o Makefile
$(OBJCOPY) -O binary -j .rodata.version_string version.o version-tmp.txt
cat version-tmp.txt | sed -e 's/ .*//' | sed -e 's/ .*//' > version.txt
cat version-tmp.txt | tr '\0' '\n' > version-full.txt
@echo
@echo "Version string: " `cat version-full.txt`
@echo
$(RM) version-tmp.txt
# nice version numbers.
BUILD_TIME = $(shell date '+%Y%m%d.%H%M%S')
BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
SHA_VERSION = $(shell git rev-parse --short HEAD)
GIT_HASH = "$(BRANCH)@$(SHA_VERSION)"
version.o: CFLAGS += -DBUILD_TIME='"$(BUILD_TIME)"' -DGIT_HASH='$(GIT_HASH)'
version.o: Makefile
clean:
$(RM) $(OBJS)
$(RM) $(OBJS:.o=.d)
@$(RM) -r $(TARGETDIR)
clobber: clean
$(RM) $(TARGETS)
version:
@$(TOP)/boards/Passport/tools/version_info/version_info version_info.c $(BOOTLOADER_VERSION)
@[ -d $(dir $(OBJDIR)/version_info.o) ] || mkdir -p $(dir $(OBJDIR)/version_info.o)
$(CC) $(CFLAGS) -c -MMD -MP -o $(OBJDIR)/version_info.o version_info.c
debug:
@echo CFLAGS = $(CFLAGS)
@echo
@echo OBJS = $(OBJS)
.PHONY: all clean install version
.SECONDARY:

142
ports/stm32/boards/Passport/bootloader/bootloader_graphics.c

@ -0,0 +1,142 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
//
// Autogenerated - Do not edit!
//
#include "bootloader_graphics.h"
uint8_t splash_data[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfe, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfe, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xfe, 0x00, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xfe, 0x00, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xfe, 0x00, 0x0f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xfe, 0x00, 0x0f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xfe, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x0f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x0f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xe0, 0x00, 0x7f, 0xfe, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x3f, 0xfc, 0x00, 0x07, 0xff, 0x80, 0x00, 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x80, 0x0f, 0x80, 0x0e, 0x0e, 0x01, 0xc0, 0x70, 0x1f, 0xe0, 0x00, 0x10, 0x03, 0xff, 0x80, 0x70, 0x00, 0xf8, 0x01, 0xc0, 0x70,
0xff, 0x80, 0x1f, 0xc0, 0x0e, 0x0e, 0x01, 0xc0, 0x70, 0x1f, 0xf0, 0x00, 0x38, 0x03, 0xff, 0x80, 0x70, 0x01, 0xfc, 0x01, 0xc0, 0x70,
0xff, 0x80, 0x3f, 0xe0, 0x0e, 0x0e, 0x01, 0xe0, 0x70, 0x1f, 0xf8, 0x00, 0x38, 0x03, 0xff, 0x80, 0x70, 0x03, 0xfe, 0x01, 0xe0, 0x70,
0xe0, 0x00, 0x78, 0xf0, 0x0e, 0x0e, 0x01, 0xf0, 0x70, 0x1c, 0x3c, 0x00, 0x7c, 0x00, 0x38, 0x00, 0x70, 0x07, 0x8f, 0x01, 0xf0, 0x70,
0xe0, 0x00, 0xf0, 0x78, 0x0e, 0x0e, 0x01, 0xf8, 0x70, 0x1c, 0x1e, 0x00, 0x7c, 0x00, 0x38, 0x00, 0x70, 0x0f, 0x07, 0x81, 0xf8, 0x70,
0xfe, 0x00, 0xe0, 0x38, 0x0e, 0x0e, 0x01, 0xfc, 0x70, 0x1c, 0x0e, 0x00, 0xfe, 0x00, 0x38, 0x00, 0x70, 0x0e, 0x03, 0x81, 0xfc, 0x70,
0xfe, 0x00, 0xe0, 0x38, 0x0e, 0x0e, 0x01, 0xde, 0x70, 0x1c, 0x0e, 0x00, 0xee, 0x00, 0x38, 0x00, 0x70, 0x0e, 0x03, 0x81, 0xde, 0x70,
0xfe, 0x00, 0xe0, 0x38, 0x0e, 0x0e, 0x01, 0xcf, 0x70, 0x1c, 0x0e, 0x01, 0xef, 0x00, 0x38, 0x00, 0x70, 0x0e, 0x03, 0x81, 0xcf, 0x70,
0xe0, 0x00, 0xf0, 0x78, 0x0e, 0x0e, 0x01, 0xc7, 0xf0, 0x1c, 0x1e, 0x01, 0xc7, 0x00, 0x38, 0x00, 0x70, 0x0f, 0x07, 0x81, 0xc7, 0xf0,
0xe0, 0x00, 0x78, 0xf0, 0x0f, 0x1e, 0x01, 0xc3, 0xf0, 0x1c, 0x3c, 0x03, 0xc7, 0x80, 0x38, 0x00, 0x70, 0x07, 0x8f, 0x01, 0xc3, 0xf0,
0xe0, 0x00, 0x3f, 0xe0, 0x07, 0xfc, 0x01, 0xc1, 0xf0, 0x1f, 0xf8, 0x03, 0x83, 0x80, 0x38, 0x00, 0x70, 0x03, 0xfe, 0x01, 0xc1, 0xf0,
0xe0, 0x00, 0x1f, 0xc0, 0x07, 0xfc, 0x01, 0xc0, 0xf0, 0x1f, 0xf0, 0x07, 0x83, 0xc0, 0x38, 0x00, 0x70, 0x01, 0xfc, 0x01, 0xc0, 0xf0,
0xe0, 0x00, 0x0f, 0x80, 0x03, 0xf8, 0x01, 0xc0, 0x70, 0x1f, 0xe0, 0x07, 0x01, 0xc0, 0x38, 0x00, 0x70, 0x00, 0xf8, 0x01, 0xc0, 0x70,
};
Image splash_img = { 172, 129, 22, splash_data };

17
ports/stm32/boards/Passport/bootloader/bootloader_graphics.h

@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
//
// Autogenerated - Do not edit!
//
#include <stdint.h>
typedef struct _Image {
int16_t width;
int16_t height;
int16_t byte_width;
uint8_t* data;
} Image;
extern Image splash_img;

137
ports/stm32/boards/Passport/bootloader/flash.c

@ -1,13 +1,13 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
// (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard <coldcardwallet.com>
// and is covered by GPLv3 license found in COPYING.
//
//
//
// flash.c -- manage flash and its sensitive contents.
//
@ -40,7 +40,7 @@ static inline bool is_pairing_secret_programmed(
return false;
}
static inline bool is_se_programmed(void)
static inline secresult is_se_programmed(void)
{
int rc;
uint8_t config[128] = {0};
@ -50,8 +50,8 @@ static inline bool is_se_programmed(void)
LOCKUP_FOREVER(); /* Can't talk to the SE */
if ((config[86] != 0x55) && (config[87] != 0x55))
return true;
return false;
return SEC_TRUE;
return SEC_FALSE;
}
// See FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE)
@ -113,11 +113,11 @@ void flash_lock(void)
// see HAL_FLASH_Lock();
SET_BIT(FLASH->CR1, FLASH_CR_LOCK);
if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK)) {
return; //INCONSISTENT("failed to lock bank 1");
return;
}
SET_BIT(FLASH->CR2, FLASH_CR_LOCK);
if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK)) {
return; //INCONSISTENT("failed to lock bank 2");
return;
}
}
@ -131,7 +131,7 @@ void flash_unlock(void)
WRITE_REG(FLASH->KEYR1, FLASH_KEY2);
if(READ_BIT(FLASH->CR1, FLASH_CR_LOCK)) {
return; //INCONSISTENT("failed to unlock bank 1");
return;
}
}
if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK)) {
@ -140,11 +140,12 @@ void flash_unlock(void)
WRITE_REG(FLASH->KEYR2, FLASH_KEY2);
if(READ_BIT(FLASH->CR2, FLASH_CR_LOCK)) {
return; //INCONSISTENT("failed to unlock bank 2");
return;
}
}
}
__attribute__((section(".ramfunc")))
int flash_ob_lock(bool lock)
{
if (!lock)
@ -155,7 +156,7 @@ int flash_ob_lock(bool lock)
/* Authorizes the Option Byte registers programming */
WRITE_REG(FLASH->OPTKEYR, FLASH_OPT_KEY1);
WRITE_REG(FLASH->OPTKEYR, FLASH_OPT_KEY2);
/* Verify that the Option Bytes are unlocked */
if (READ_BIT(FLASH->OPTCR, FLASH_OPTCR_OPTLOCK) != 0U)
{
@ -168,7 +169,7 @@ int flash_ob_lock(bool lock)
/* see HAL_FLASH_OB_Lock() */
/* Set the OPTLOCK Bit to lock the FLASH Option Byte Registers access */
SET_BIT(FLASH->OPTCR, FLASH_OPTCR_OPTLOCK);
/* Verify that the Option Bytes are locked */
if (READ_BIT(FLASH->OPTCR, FLASH_OPTCR_OPTLOCK) == 0U)
{
@ -289,18 +290,26 @@ static int flash_rom_secrets(rom_secrets_t *secrets)
{
__IO uint32_t *src_secrets = (__IO uint32_t *)secrets;
__IO uint32_t *flash_secrets = (__IO uint32_t *)(BL_NVROM_BASE);
__IO uint32_t empty[FLASH_NB_32BITWORD_IN_FLASHWORD] = {0};
uint32_t flash_word_len = sizeof(uint32_t) * FLASH_NB_32BITWORD_IN_FLASHWORD;
uint32_t pos = (uint32_t)src_secrets;
uint32_t dest = (uint32_t)flash_secrets;
uint32_t zeros = (uint32_t)empty;
int i;
flash_unlock();
for (i = 0; i < sizeof(rom_secrets_t); i += flash_word_len, pos += flash_word_len, dest += flash_word_len) {
if (flash_burn(dest, pos)) {
for (i = 0; i < sizeof(rom_secrets_t); i += flash_word_len, pos += flash_word_len, dest += flash_word_len)
{
if (flash_burn(dest, pos))
return -1;
}
for (; i < BL_NVROM_SIZE; i += flash_word_len, dest += flash_word_len)
{
if (flash_burn(dest, zeros))
return -1;
}
}
flash_lock();
@ -351,6 +360,24 @@ static int flash_bootloader(rom_secrets_t *secrets)
}
#endif /* JUST_PROGRAM_ROM_SECRETS */
__attribute__((section(".ramfunc")))
void flash_lockdown_hard(void)
{
#ifdef LOCKED
_flash_wait_done(FLASH_BANK_1);
_flash_wait_done(FLASH_BANK_2);
flash_ob_lock(false);
MODIFY_REG(FLASH->OPTSR_PRG, FLASH_OPTSR_RDP, (uint32_t)OB_RDP_LEVEL_2);
_flash_wait_done(FLASH_BANK_1);
_flash_wait_done(FLASH_BANK_2);
SET_BIT(FLASH->OPTCR, FLASH_OPTCR_OPTSTART);
flash_ob_lock(true);
#endif /* LOCKED */
}
static void pick_pairing_secret(rom_secrets_t *local)
{
uint32_t secret[8];
@ -376,11 +403,11 @@ static void pick_pairing_secret(rom_secrets_t *local)
*pos = rng_sample();
}
pos = (uint32_t *)&local->otp_key_long;
len = sizeof(local->otp_key_long);
for (i = 0; i < len; i += sizeof(uint32_t), ++pos) {
*pos = rng_sample();
}
// pos = (uint32_t *)&local->otp_key_long;
// len = sizeof(local->otp_key_long);
// for (i = 0; i < len; i += sizeof(uint32_t), ++pos) {
// *pos = rng_sample();
// }
pos = (uint32_t *)&local->hash_cache_secret;
len = sizeof(local->hash_cache_secret);
@ -389,11 +416,12 @@ static void pick_pairing_secret(rom_secrets_t *local)
}
}
void flash_first_boot(void)
secresult flash_first_boot(void)
{
int rc;
uint8_t fw_hash[HASH_LEN];
uint8_t board_hash[HASH_LEN];
uint8_t fw_hash[HASH_LEN] = {0};
uint8_t board_hash[HASH_LEN] = {0};
uint8_t zeros[HASH_LEN] = {0};
passport_firmware_header_t *fwhdr = (passport_firmware_header_t *)FW_HDR;
uint8_t *fwptr = (uint8_t *)fwhdr + FW_HEADER_SIZE;
bool secrets_already_programmed;
@ -401,17 +429,17 @@ void flash_first_boot(void)
rom_secrets_t local_secrets = {0};
if (sizeof(rom_secrets_t) > 2048)
LOCKUP_FOREVER();
return ERR_ROM_SECRETS_TOO_BIG;
if (!verify_header(fwhdr))
LOCKUP_FOREVER();
if (verify_header(fwhdr) != SEC_TRUE)
return ERR_INVALID_FIRMWARE_HEADER;
hash_fw(&fwhdr->info, fwptr, fwhdr->info.fwlength, fw_hash, sizeof(fw_hash));
if (!verify_signature(fwhdr, fw_hash, sizeof(fw_hash)))
LOCKUP_FOREVER();
if (verify_signature(fwhdr, fw_hash, sizeof(fw_hash)) == SEC_FALSE)
return ERR_INVALID_FIRMWARE_SIGNATURE;
secrets_already_programmed = is_pairing_secret_programmed(rom_secrets->pairing_secret,
secrets_already_programmed = is_pairing_secret_programmed(rom_secrets->pairing_secret,
sizeof(rom_secrets->pairing_secret));
if (secrets_already_programmed)
@ -421,7 +449,7 @@ void flash_first_boot(void)
rc = se_setup_config(&local_secrets);
if (rc != 0)
LOCKUP_FOREVER();
return ERR_UNABLE_TO_CONFIGURE_SE;
if (!secrets_already_programmed)
{
@ -433,41 +461,40 @@ void flash_first_boot(void)
#endif /* JUST_PROGRAM_ROM_SECRETS */
HAL_ResumeTick();
if (rc < 0)
LOCKUP_FOREVER();
}
return ERR_UNABLE_TO_WRITE_ROM_SECRETS;
}
#ifdef DEMO
memset(board_hash, 0, sizeof(board_hash));
#else
// We need to lockdown the flash BEFORE programming the first board_hash into the SE so that the correct
// option bytes from the MCU are included in the hash.
flash_lockdown_hard();
#ifdef PRODUCTION_BUILD
hash_board(fw_hash, sizeof(fw_hash), board_hash, sizeof(board_hash));
#endif /* DEMO */
#else
memset(board_hash, 0, sizeof(board_hash));
#endif /* PRODUCTION_BUILD */
rc = se_program_board_hash(board_hash, sizeof(board_hash));
rc = se_program_board_hash(zeros, board_hash, sizeof(board_hash));
if (rc < 0)
LOCKUP_FOREVER();
return ERR_UNABLE_TO_UPDATE_FIRMWARE_HASH_IN_SE;
flash_lockdown_hard((uint32_t)OB_RDP_LEVEL_2);
return SEC_TRUE;
}
void flash_lockdown_hard(uint32_t rdp_level)
secresult flash_is_programmed(void)
{
#ifndef FIXME /* Enable once we're almost ready to release and don't
* forget to move the secrets back into 0
*/
return;
#else
flash_ob_lock(false);
MODIFY_REG(FLASH->OPTSR_PRG, FLASH_OPTSR_RDP, rdp_level);
if (!is_pairing_secret_programmed(rom_secrets->pairing_secret, sizeof(rom_secrets->pairing_secret)))
return SEC_FALSE;
flash_ob_lock(true);
#endif /* FIXME */
return is_se_programmed();
}
bool flash_is_programmed(void)
#ifdef LOCKED
secresult flash_is_locked(void)
{
if (!is_pairing_secret_programmed(rom_secrets->pairing_secret, sizeof(rom_secrets->pairing_secret)))
return false;
return is_se_programmed();
uint32_t rdp_level = READ_BIT(FLASH->OPTSR_CUR, FLASH_OPTSR_RDP);
if (rdp_level == OB_RDP_LEVEL_2)
return SEC_TRUE;
return SEC_FALSE;
}
#endif /* LOCKED */

16
ports/stm32/boards/Passport/bootloader/flash.h

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
/*
@ -14,10 +14,15 @@
#include "stm32h7xx_hal.h"
#include "secresult.h"
// Details of the OTP area. 64-bit slots.
#define OPT_FLASH_BASE 0x1FFF7000
#define NUM_OPT_SLOTS 128
#define USER_SETTINGS_FLASH_ADDR 0x81E0000
static inline bool flash_is_security_level2(void)
{
return ((FLASH->OPTSR_CUR & FLASH_OPTSR_RDP_Msk) == OB_RDP_LEVEL_2);
@ -29,8 +34,9 @@ extern void flash_unlock(void);
extern int flash_burn(uint32_t flash_address, uint32_t data_address);
extern int flash_sector_erase(uint32_t address);
extern void flash_test(void);
extern void flash_first_boot(void);
extern void flash_lockdown_hard(uint32_t rdp_level_code);
extern bool flash_is_programmed(void);
extern secresult flash_first_boot(void);
extern void flash_lockdown_hard(void);
extern secresult flash_is_programmed(void);
extern secresult flash_is_locked(void);
// EOF

35
ports/stm32/boards/Passport/bootloader/link-script.ld

@ -1,8 +1,8 @@
/*
SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
SPDX-License-Identifier: GPL-3.0-only
*/
@ -26,24 +26,29 @@ SEARCH_DIR(.)
/* Memory Spaces Definitions */
MEMORY
{
rom (rx) : ORIGIN = BL_FLASH_BASE, LENGTH = BL_FLASH_SIZE
ram (rwx) : ORIGIN = BL_SRAM_BASE, LENGTH = BL_SRAM_SIZE
itcm (rwx) : ORIGIN = 0x00000000, LENGTH = 0x10000
rom (rx) : ORIGIN = BL_FLASH_BASE, LENGTH = BL_FLASH_SIZE
ram (rwx) : ORIGIN = BL_SRAM_BASE, LENGTH = BL_SRAM_SIZE
itcm (rwx) : ORIGIN = 0x00000000, LENGTH = 0x10000
}
/* The stack size used by the bootloader. */
STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : DEFINED(__stack_size__) ? __stack_size__ : 0x4000;
STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : DEFINED(__stack_size__) ? __stack_size__ : 0x8000;
/* Section Definitions */
SECTIONS
{
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} > rom
.text :
{
. = ALIGN(4);
_sfixed = .;
KEEP(*(.entry_code))
KEEP(*(.outside_pcrop))
main.o(.text*)
. = ALIGN(256);
/* important: this pulls in library (libgcc) stuff here */
@ -55,7 +60,7 @@ SECTIONS
} > rom
/* .ARM.exidx is sorted, so has to go in its own output section. */
/* .ARM.exidx is sorted, so has to go in its own output section. */
PROVIDE_HIDDEN (__exidx_start = .);
.ARM.exidx :
{
@ -121,18 +126,6 @@ SECTIONS
/* Some very manual linking! I've tried doing it right, and couldn't get it to work well */
addr_rom_secrets = BL_NVROM_BASE;
/* if you initialize a global var to some non-zero value, then that data ends up
in .relocate as read-only data and used briefly at startup (when copied to RAM).
We don't want to support that, so we're checking here that hasn't happened. */
/*
ASSERT(_pdg_hack == _erelocate,
"Sorry, no initialized data support! Set to zero or remove.")
*/
/* ensure binary fits */
/*
ASSERT(_erelocate - BL_CODE_BASE + _etext <= BL_FLASH_BASE + BL_FLASH_SIZE,
"Binary is too big to fit!!!")
*/
. = ALIGN(4);
_end = . ;
}

374
ports/stm32/boards/Passport/bootloader/main.c

@ -1,17 +1,16 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
#include <errno.h>
#include <string.h>
#include <errno.h>
#include "../stm32h7xx_hal_conf.h"
#include "stm32h7xx_ll_cortex.h"
#include "delay.h"
#include "fwheader.h"
#include "pprng.h"
#include "secrets.h"
#include "se.h"
@ -22,11 +21,42 @@
#include "verify.h"
#include "update.h"
#include "backlight.h"
#include "display.h"
#include "lcd-sharp-ls018B7dh02.h"
#ifndef DEBUG
#include "keypad-adp-5587.h"
#endif /* DEBUG */
#include "splash.h"
#include "ui.h"
#include "gpio.h"
#include "version_info.h"
#include "hash.h"
#include "secresult.h"
/*
* This is an empty function to satisfy the linker requirement for init
* when the startup_stm32h753xx.s file was pulled into the bootloader
* build to define the full vector table.
*/
void _init(void)
{
}
void SysTick_Handler(void)
{
HAL_IncTick();
}
#ifndef DEBUG
void EXTI15_10_IRQHandler(void)
{
if (__HAL_GPIO_EXTI_GET_FLAG(1 << 12))
{
__HAL_GPIO_EXTI_CLEAR_FLAG(1 << 12);
keypad_ISR();
}
}
#endif /* DEBUG */
static void SystemClock_Config(void)
{
HAL_StatusTypeDef rc;
@ -42,7 +72,7 @@ static void SystemClock_Config(void)
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI48;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
@ -58,7 +88,7 @@ static void SystemClock_Config(void)
RCC_OscInitStruct.PLL.PLLQ = 120;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1;
rc = HAL_RCC_OscConfig(&RCC_OscInitStruct);
@ -91,10 +121,10 @@ static void SystemClock_Config(void)
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
rc = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
if (rc != HAL_OK)
{
@ -113,7 +143,32 @@ static void SystemClock_Config(void)
__HAL_RCC_D2SRAM3_CLK_ENABLE();
}
void MPU_Config(void)
// Recover from ECC errors during firmware updates
void HardFault_Handler(void)
{
uint32_t cfsr = SCB->CFSR;
if (cfsr & 0x8000) {
uint32_t faultaddr = (uint32_t)SCB->BFAR;
uint32_t fw_sector_start = FW_START;
uint32_t fw_sector_end = FW_END;
if ((faultaddr >= fw_sector_start) && (faultaddr < fw_sector_end)) {
uint32_t faultsector = faultaddr & 0xFFF0000;
flash_unlock();
flash_sector_erase(faultsector);
flash_lock();
/* Reset the board */
passport_reset();
}
}
while (1);
}
static void MPU_Config(void)
{
MPU_Region_InitTypeDef MPU_InitStruct;
@ -180,7 +235,6 @@ void MPU_Config(void)
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
#if 0 /* FIXME...enabling this causes an IACCVIOL! */
/* Configure SRAM4 region as non-executable */
memset(&MPU_InitStruct, 0, sizeof(MPU_InitStruct));
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
@ -195,7 +249,6 @@ void MPU_Config(void)
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
#endif
/* Configure ITCM region as non-executable */
memset(&MPU_InitStruct, 0, sizeof(MPU_InitStruct));
@ -212,23 +265,142 @@ void MPU_Config(void)
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Configure DTCM region as non-executable */
memset(&MPU_InitStruct, 0, sizeof(MPU_InitStruct));
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x20000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_128KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER5;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Configure Backup region as non-executable */
memset(&MPU_InitStruct, 0, sizeof(MPU_InitStruct));
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x38800000;
MPU_InitStruct.Size = MPU_REGION_SIZE_4KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER5;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Enable MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
static void version(void)
{
passport_firmware_header_t *fwhdr = (passport_firmware_header_t *)FW_HDR;
char version[22] = {0};
strcpy(version, "Version ");
strcat(version, (char *)fwhdr->info.fwversion);
show_splash(version);
}
#ifndef DEBUG
static void show_more_info(void)
{
char message[80];
// For the firmware header and hash
uint8_t fw_hash[HASH_LEN];
passport_firmware_header_t *fwhdr = (passport_firmware_header_t *)FW_HDR;
uint8_t page = 0;
while (true) {
switch (page) {
case 0:
strcpy(message, "\nVersion:\n");
strcat(message, build_version);
strcat(message, "\n\nBuild Date:\n");
strcat(message, build_date);
if (ui_show_message("Bootloader Info", message, "SHUTDOWN", "NEXT", true)){
page++;
} else {
display_clean_shutdown();
}
break;
case 1:
strcpy(message, "\nVersion:\n");
strcat(message, (char*)fwhdr->info.fwversion);
strcat(message, "\n\nBuild Date:\n");
strcat(message, (char*)fwhdr->info.fwdate);
if (ui_show_message("Firmware Info", message, "BACK", "NEXT", true)){
page++;
} else {
page--;
}
break;
case 2: {
message[0] = '\n';
message[1] = 0;
hash_fw_user((uint8_t*)fwhdr, FW_HEADER_SIZE + fwhdr->info.fwlength, fw_hash, sizeof(fw_hash), false);
bytes_to_hex_str(fw_hash, 32, &message[1], 8, '\n');
if (ui_show_message("Download Hash", message, "BACK", "NEXT", true)){
page++;
} else {
page--;
}
break;
}
case 3: {
message[0] = '\n';
message[1] = 0;
hash_fw_user((uint8_t*)fwhdr, FW_HEADER_SIZE + fwhdr->info.fwlength, fw_hash, sizeof(fw_hash), true);
bytes_to_hex_str(fw_hash, 32, &message[1], 8, '\n');
if (ui_show_message("Build Hash", message, "BACK", "START", true)){
return;
} else {
page--;
}
break;
}
}
}
}
#endif /* DEBUG */
void random_boot_delay() {
// Random delay to make cold-boot stepping attacks harder: 0 - 100ms
uint32_t ms_to_delay = rng_sample() % 50;
delay_ms(ms_to_delay);
}
int main(void)
{
HAL_StatusTypeDef rc;
#ifndef DEBUG
uint8_t keycount;
uint8_t key;
#endif /* DEBUG */
SystemInit();
rc = HAL_Init();
if (rc != HAL_OK)
{
while(1) { ; }
}
LOCKUP_FOREVER();
#if 0 /* This is interfering with firmware boot after an update. It
* appears that the data cache is getting in the way of the
* reset handler properly copying over the data section into SRAM.
@ -238,27 +410,163 @@ int main(void)
#endif
SystemClock_Config();
// Set Brown-out level early on to reset on glitch attempts
MODIFY_REG(FLASH->OPTSR_PRG, FLASH_OPTSR_BOR_LEV, (uint32_t)OB_BOR_LEVEL2);
#ifdef LOCKED
// Ensure RDP level 2 on every boot in case of shenanigans
if (!flash_is_security_level2()) {
flash_lockdown_hard();
}
#endif /* LOCKED */
rng_setup();
random_boot_delay();
se_setup();
/* Check for first-boot condition */
if (!flash_is_programmed())
flash_first_boot();
// Force LED to red every time we restart for consistency
se_set_gpio(0);
/* Validate our pairing secret */
if (!se_valid_secret(rom_secrets->pairing_secret))
LOCKUP_FOREVER();
// Initialize the LCD driver and clear the display
backlight_init();
backlight_intensity(100);
display_init(true);
/* Validate the internal firmware */
if (!verify_current_firmware())
LOCKUP_FOREVER();
#ifndef DEBUG
keypad_init();
gpio_init();
#endif /* DEBUG */
show_splash("");
random_boot_delay();
// Check for first-boot condition
if (flash_is_programmed() == SEC_FALSE) {
secresult result = flash_first_boot();
switch (result) {
case SEC_TRUE:
// All good!
break;
case ERR_ROM_SECRETS_TOO_BIG:
ui_show_fatal_error("ROM Secrets area is larger than 2048 bytes.");
break;
case ERR_INVALID_FIRMWARE_HEADER:
ui_show_fatal_error("Invalid firmware header found during first boot.");
break;
case ERR_INVALID_FIRMWARE_SIGNATURE:
ui_show_fatal_error("Invalid firmware signature found during first boot.");
break;
/* Check for firmware update */
if (is_firmware_update_present())
case ERR_UNABLE_TO_CONFIGURE_SE:
ui_show_fatal_error("Unable to configure the Secure Element during first boot.");
break;
case ERR_UNABLE_TO_WRITE_ROM_SECRETS:
ui_show_fatal_error("Unable to flash ROM secrets to end of bootloader flash block during first boot.");
break;
case ERR_UNABLE_TO_UPDATE_FIRMWARE_HASH_IN_SE:
ui_show_fatal_error("Unable to program firmware hash into security chip during first boot.");
break;
default:
ui_show_fatal_error("Unexpected error on first boot.");
break;
}
}
// Increment the boot counter
uint32_t counter_result;
if (se_add_counter(&counter_result, 1, 1) != 0) {
ui_show_fatal_error("Unable to increment boot counter in the Secure Element. Device may have been tampered with.\n\nThis Passport is now permanently disabled.");
}
// Validate our pairing secret
if (!se_valid_secret(rom_secrets->pairing_secret)) {
ui_show_fatal_error("Unable to connect to the Secure Element.\n\nThis Passport is now permanently disabled.");
}
// Check for firmware update
if (is_firmware_update_present() == SEC_TRUE) {
update_firmware();
}
// Validate the internal firmware
secresult result = verify_current_firmware(true);
switch (result) {
case SEC_TRUE:
// All good!
break;
case ERR_INVALID_FIRMWARE_HEADER:
ui_show_fatal_error("Invalid firmware header found.\n\nThis Passport is now permanently disabled.");
break;
case ERR_INVALID_FIRMWARE_SIGNATURE:
ui_show_fatal_error("The installed firmware was not signed by a valid key.\n\nThis Passport is now permanently disabled.");
break;
/* Setup MPU */
case ERR_FIRMWARE_HASH_DOES_NOT_MATCH_SE:
ui_show_fatal_error("The installed firmware hash does not match that expected by the Secure Element.\n\nThis Passport is now permanently disabled.");
break;
default:
ui_show_fatal_error("Unexpected error when verifying current firmware.");
break;
}
random_boot_delay();
// Setup MPU
MPU_Config();
/* From here we'll boot to Micropython */
version();
#ifndef DEBUG
/*
* Delay for 3 seconds to allow the user to press a key indicating that
* they would like to see board info or show the self test (in Python).
*/
delay_ms(3000);
// We use the first byte in sram4 to pass a parameter that we check for on the MicroPython side
// to see if user wants to view the self-test.
uint8_t* p_sram4 = (uint8_t*)0x38000000;
*p_sram4 = 0;
keycount = ring_buffer_dequeue(&key);
if (keycount > 0)
{
// The '1' key
if ((key & 0x7f) == 112)
{
show_more_info();
}
// The '7' key
if ((key & 0x7f) == 107)
{
// Setting this byte to 1 signals main.py to show the self-test and serial number
*p_sram4 = 1;
}
}
#endif
// Show a warning message if non-Foundation firmware is loaded on the device
if (is_user_signed_firmware_installed() == SEC_TRUE) {
if (ui_show_message("Firmware Warning", "\nCustom, non-Foundation firmware is loaded on this Passport.\n\nOK to continue?", "NO", "YES", true)){
// Continue booting
} else {
display_clean_shutdown();
}
}
// From here we'll boot to Micropython: see stm32_main() in /ports/stm32/main.c
}

110
ports/stm32/boards/Passport/bootloader/se-atecc608a.c

@ -1,9 +1,10 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
@ -17,14 +18,12 @@
#include "se-config.h"
#include "sha256.h"
#define INCONSISTENT(x) /* FIXME */
static int se_write_data_slot(int slot_num, uint8_t *data, int len, bool lock_it)
{
#ifdef FIXME
ASSERT(len >= 32);
ASSERT(len <= 416);
#endif
if ((len < 32) || (len > 416) || (lock_it && slot_num == 8)) {
return -1;
}
for (int blk = 0, xlen = len; xlen > 0; blk++, xlen -= 32) {
int rc;
@ -38,10 +37,6 @@ static int se_write_data_slot(int slot_num, uint8_t *data, int len, bool lock_it
}
if (lock_it) {
#ifdef FIXME
ASSERT(slot_num != 8); // no support for mega slot 8
ASSERT(len == 32); // probably not a limitation here
#endif
// Assume 36/72-byte long slot, which will be partially written, and rest
// should be ones.
const int slot_len = (slot_num <= 7) ? 36 : 72;
@ -82,34 +77,7 @@ static int se_lock_data_zone(void)
return se_read1();
}
#if 0 /* Not used now */
// Read a 4-byte area from config area, or -1 if fail.
//
static int se_read_config_word(int offset, uint8_t *dest)
{
offset &= 0x7f;
// read 32 bits (aligned)
se_write(OP_Read, 0x00, offset/4, NULL, 0);
int rv = se_read(dest, 4);
if (rv < 0)
return -1;
return 0;
}
// Read a byte from config area.
//
static int se_read_config_byte(int offset)
{
uint8_t tmp[4];
se_read_config_word(offset, tmp);
return tmp[offset % 4];
}
#endif /* 0 */
static int se_config_write(uint8_t *config)
{
// send all 128 bytes, less some that can't be written.
@ -143,10 +111,10 @@ static int se_config_write(uint8_t *config)
// secret in cleartext. They could then restore original chip and access freely.
//
// PASSPORT NOTE: We can eliminate the above by having the factory bootloader
// be different than the normal bootloader. The factory bootloader
// be different than the normal bootloader. The factory bootloader
// will have the one-time setup code only, not the runtime code.
// The normal bootloader will NOT have the one-time setup code,
// but WILL have the main runtime code. So swapping in blank
// but WILL have the main runtime code. So swapping in blank
// SE would not trigger us to write the pairing secret in the clear.
//
int se_setup_config(rom_secrets_t *secrets)
@ -212,7 +180,7 @@ int se_setup_config(rom_secrets_t *secrets)
case 15:
break;
case KEYNUM_pairing:
case KEYNUM_pairing_secret:
if (se_write_data_slot(kn, secrets->pairing_secret, 32, false))
return -4;
break;
@ -226,38 +194,56 @@ int se_setup_config(rom_secrets_t *secrets)
// - stretching pin/words attempts (iterated may times)
// See mathcheck.py for details.
uint8_t tmp[32];
rng_buffer(tmp, sizeof(tmp));
if (se_write_data_slot(kn, tmp, 32, true))
return -5;
}
break;
case KEYNUM_main_pin:
case KEYNUM_pin_hash:
case KEYNUM_lastgood:
case KEYNUM_firmware:
case KEYNUM_firmware_hash:
if (se_write_data_slot(kn, zeros, 32, false))
return -6;
break;
case KEYNUM_secret:
if (se_write_data_slot(kn, zeros, 72, false))
case KEYNUM_supply_chain: {
// SCV key is in user settings flash
uint8_t* supply_chain_key = (uint8_t*)USER_SETTINGS_FLASH_ADDR;
bool is_erased = true;
for (uint32_t i=0; i<32; i++) {
if (supply_chain_key[i] != 0xFF) {
is_erased = false;
}
}
// If the scv key is not set in flash, then don't proceed, else validation will never work!
if (is_erased) {
return -11;
}
int rc = se_write_data_slot(kn, supply_chain_key, 32, false);
// Always erase the supply chain key, even if the write failed
flash_sector_erase(USER_SETTINGS_FLASH_ADDR);
if (rc)
return -7;
}
break;
case KEYNUM_long_secret:
{
uint8_t long_zeros[416] = {0};
if (se_write_data_slot(kn, long_zeros, 416, false))
case KEYNUM_seed:
case KEYNUM_user_fw_pubkey:
if (se_write_data_slot(kn, zeros, 72, false))
return -8;
}
break;
case KEYNUM_match_count:
{
uint32_t buf[32/4] = { 1024, 1024 };
if (se_write_data_slot(KEYNUM_match_count, (uint8_t *)buf,sizeof(buf),false))
if (se_write_data_slot(KEYNUM_match_count, (uint8_t *)buf,sizeof(buf),false))
return -9;
}
break;
@ -323,7 +309,7 @@ int se_set_gpio_secure(uint8_t *digest)
if (rc < 0)
return -1;
rc = se_checkmac(KEYNUM_firmware, digest);
rc = se_checkmac(KEYNUM_firmware_hash, digest);
if (rc < 0)
return -1;
@ -335,25 +321,23 @@ int se_set_gpio_secure(uint8_t *digest)
}
int se_program_board_hash(
uint8_t *board_hash,
uint8_t *previous_hash,
uint8_t *new_hash,
uint8_t hash_len
)
{
#ifdef DEMO
uint8_t zeros[HASH_LEN] = {0};
return se_encrypted_write(KEYNUM_firmware, KEYNUM_main_pin, zeros, board_hash, hash_len);
#ifdef PRODUCTION_BUILD
return se_encrypted_write(KEYNUM_firmware_hash, KEYNUM_firmware_hash, previous_hash, new_hash, hash_len);
#else
/* We don't know how we're going to do this yet */
return 0;
#endif /* DEMO */
#endif /* PRODUCTION_BUILD */
}
bool se_valid_secret(
uint8_t *secret
)
{
int rc = se_checkmac(KEYNUM_pairing, secret);
int rc = se_checkmac(KEYNUM_pairing_secret, secret);
if (rc < 0)
return false;
return true;

6
ports/stm32/boards/Passport/bootloader/se-atecc608a.h

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
// Copyright 2020 - Foundation Devices Inc.
@ -17,7 +17,7 @@ extern int se_setup_config(rom_secrets_t *secrets);
extern uint8_t se_get_gpio(void);
extern int se_set_gpio(int state);
extern int se_set_gpio_secure(uint8_t *digest);
extern int se_program_board_hash(uint8_t *board_hash, uint8_t hash_len);
extern int se_program_board_hash(uint8_t *previous_hash, uint8_t *new_hash, uint8_t hash_len);
extern bool se_valid_secret(uint8_t *secret);
#endif //_SECURE_ELEMENT_ATECC608A_H_

BIN
ports/stm32/boards/Passport/bootloader/secrets

Binary file not shown.

BIN
ports/stm32/boards/Passport/bootloader/secrets-main-dev-se

Binary file not shown.

BIN
ports/stm32/boards/Passport/bootloader/secrets-old

Binary file not shown.

BIN
ports/stm32/boards/Passport/bootloader/secrets.unknown

Binary file not shown.

19
ports/stm32/boards/Passport/bootloader/splash.c

@ -0,0 +1,19 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc.
// <hello@foundationdevices.com> SPDX-License-Identifier: GPL-3.0-or-later
//
// splash.c - Splash screen shown at during initialization
#include "display.h"
#include "bootloader_graphics.h"
void show_splash(char* message)
{
uint16_t x = SCREEN_WIDTH / 2 - splash_img.width / 2;
uint16_t y = SCREEN_HEIGHT / 2 - splash_img.height / 2;
display_clear(0);
display_image(x, y, splash_img.width, splash_img.height, splash_img.data, DRAW_MODE_NORMAL);
display_text(message, CENTER_X, SCREEN_HEIGHT - 68, &FontSmall, false);
display_show();
}

6
ports/stm32/boards/Passport/bootloader/splash.h

@ -0,0 +1,6 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc.
// <hello@foundationdevices.com> SPDX-License-Identifier: GPL-3.0-or-later
//
// splash.h - Splash screen shown at during initialization
extern void show_splash(char* message);

4
ports/stm32/boards/Passport/bootloader/startup.S

@ -1,8 +1,8 @@
/*
SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
SPDX-License-Identifier: GPL-3.0-only
*/
/* starting value for the top of our stack. */

86
ports/stm32/boards/Passport/bootloader/startup.s

@ -0,0 +1,86 @@
/*
SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
SPDX-License-Identifier: GPL-3.0-or-later
SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
SPDX-License-Identifier: GPL-3.0-only
*/
.thumb
.syntax unified
.global Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
/* Load the stack pointer */
ldr sp, =_estack
/* Initialise the data section */
ldr r1, =_sidata
ldr r2, =_sdata
ldr r3, =_edata
b .data_copy_entry
.data_copy_loop:
ldr r0, [r1], #4 /* Should be 4-aligned to be as fast as possible */
str r0, [r2], #4
.data_copy_entry:
cmp r2, r3
bcc .data_copy_loop
/* Zero out the BSS section */
movs r0, #0
ldr r1, =_sbss
ldr r2, =_ebss
b .bss_zero_entry
.bss_zero_loop:
str r0, [r1], #4 /* Should be 4-aligned to be as fast as possible */
.bss_zero_entry:
cmp r1, r2
bcc .bss_zero_loop
/* Initialise the sram section */
ldr r1, =_siram
ldr r2, =_sram
ldr r3, =_eram
b .ram_copy_entry
.ram_copy_loop:
ldr r0, [r1], #4 /* Should be 4-aligned to be as fast as possible */
str r0, [r2], #4
.ram_copy_entry:
cmp r2, r3
bcc .ram_copy_loop
bl main
/*
* get a ptr to real code
* load R1 with 0x08020800 value: start of firmware
*/
movw r1, (0x08020800 >> 12)
lsl r1, 12
orr.w r1, r1, #0x800
/* set stack pointer to their preference */
ldr r0, [r1]
mov sp, r0
/* Disabled
* We cannot change to user mode here because the micropython code
* depends on being in supervisor mode. SystemInit() is invoked
* from the Reset_Handler() and the vector table (along with other
* SCB accesses) is set at the start of stm32_main()...both
* important things in the startup processing.
*/
/* We are in supervisor mode out of reset...drop down to user mode */
/*
mrs r3, CONTROL
orr.w r3, r3, #1
msr CONTROL, r3
*/
/* Read reset vector, and jump to it. */
mov r0, 1 /* set reset_mode arg: 1=normal? */
ldr lr, [r1, 4]
bx lr
.end

243
ports/stm32/boards/Passport/bootloader/ui.c

@ -0,0 +1,243 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc.
// <hello@foundationdevices.com> SPDX-License-Identifier: GPL-3.0-or-later
//
// ui.c - Simple UI elements for the bootloader
#include <string.h>
#include "ui.h"
#include "gpio.h"
#include "delay.h"
#include "utils.h"
#include "display.h"
#include "passport_fonts.h"
#include "ring_buffer.h"
#include "lcd-sharp-ls018B7dh02.h"
#define HEADER_HEIGHT 40
#define FOOTER_HEIGHT 32
#define SIDE_MARGIN 4
#define TOP_MARGIN 4
void ui_draw_header(char* title) {
uint16_t title_y = 10;
// Title
display_text(title, CENTER_X, title_y, &FontSmall, false);
// Divider
display_fill_rect(0, HEADER_HEIGHT-4, SCREEN_WIDTH, 2, 1);
}
void ui_draw_button(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char* label, bool is_pressed) {
if (is_pressed) {
display_fill_rect(x, y, w, h, 1);
} else {
display_rect(x, y, w, h, 1);
}
// Measure text and center it in the button
uint16_t label_width = display_measure_text(label, &FontTiny);
x = x + (w / 2 - label_width / 2);
y = y + (h / 2 - FontTiny.ascent / 2);
display_text(label, x, y - 1, &FontTiny, is_pressed);
}
void ui_draw_footer(char* left_btn, bool is_left_pressed, char* right_btn, bool is_right_pressed) {
uint16_t btn_w = SCREEN_WIDTH / 2;
// Draw left button
ui_draw_button(-1, SCREEN_HEIGHT - FOOTER_HEIGHT + 1, btn_w + 1,
FOOTER_HEIGHT, left_btn, is_left_pressed);
// Draw right button
ui_draw_button(btn_w - 1, SCREEN_HEIGHT - FOOTER_HEIGHT + 1,
btn_w + 2, FOOTER_HEIGHT, right_btn, is_right_pressed);
}
void ui_draw_wrapped_text(uint16_t x, uint16_t y, uint16_t max_width, char* text, bool center) {
// Buffer to hold each wrapped line
char line[80];
uint16_t curr_y = y;
while (*text != 0) {
uint16_t sp = 0;
uint16_t last_space = 0;
uint16_t line_width = 0;
uint16_t first_non_space = 0;
uint16_t text_len = strlen(text);
uint16_t sp_skip = 0;
// Skip leading spaces
while (true) {
if (text[sp] == ' ') {
sp++;
first_non_space = sp;
} else if (text[sp] == '\n') {
sp++;
first_non_space = sp;
curr_y += FontSmall.leading;
} else {
break;
}
}
while (sp < text_len) {
char ch = text[sp];
if (ch == ' ') {
last_space = sp;
}
else if (ch == '\n') {
// Time to break the line - Skip over this character after copying and rendering the line with sp_skip
sp_skip = 1;
break;
}
uint16_t ch_width = display_get_char_width(ch, &FontSmall);
line_width += ch_width;
if (line_width >= max_width) {
// If we found a space, we can break there, but if we didn't
// then just break before we go over.
if (last_space != 0) {
sp = last_space;
}
break;
}
sp++;
}
// Copy to prepare for rendering
strncpy(line, text + first_non_space, sp-first_non_space);
line[sp-first_non_space] = 0;
text = text + sp + sp_skip;
// Draw the line
display_text(line, center ? CENTER_X : SIDE_MARGIN, curr_y, &FontSmall, false);
curr_y += FontSmall.leading;
}
}
#ifndef DEBUG
static bool poll_for_key(uint8_t* p_key, bool* p_is_key_down) {
uint8_t key;
uint8_t count = ring_buffer_dequeue(&key);
if (count == 0) {
return false;
}
*p_key = key & 0x7F;
*p_is_key_down = (key & 0x80) ? true : false;
return true;
}
#endif // DEBUG
// Show message and then delay or wait for button press
bool ui_show_message(char* title, char* message, char* left_btn, char *right_btn, bool center) {
bool exit = false;
bool result = false;
bool is_left_pressed = false;
bool is_right_pressed = false;
do {
display_clear(0);
// Draw the text
ui_draw_wrapped_text(SIDE_MARGIN, HEADER_HEIGHT + TOP_MARGIN, SCREEN_WIDTH - SIDE_MARGIN * 2, message, center);
// Draw the header
ui_draw_header(title);
// Draw the footer
ui_draw_footer(left_btn, is_left_pressed, right_btn, is_right_pressed);
display_show();
#ifdef DEBUG
delay_ms(5000);
result = true;
} while (exit);
#else
// Only poll if we are not exiting
if (!exit) {
// Poll for key
uint8_t key;
bool is_key_down;
bool key_read;
do {
key_read = poll_for_key(&key, &is_key_down);
} while (!key_read);
// Handle key
if (key_read) {
if (is_key_down) {
switch (key) {
case 99: // 'y'
is_right_pressed = true;
break;
case 113: // 'x'
is_left_pressed = true;
break;
}
} else {
switch (key) {
case 99: // 'y'
is_right_pressed = false;
exit = true;
result = true;
continue;
case 113: // 'x'
is_left_pressed = false;
exit = true;
result = false;
continue;
}
}
} else {
delay_ms(50);
}
}
} while (!exit);
#endif // DEBUG
return result;
}
// Show the error message and give user the option to SHUTDOWN, or view
// CONTACT information. Then have option to go BACK to the error.
// NOTE: This function never returns!
void ui_show_fatal_error(char* error) {
bool show_error = true;
while (true) {
if (show_error) {
// Show the error
if (ui_show_message("Fatal Error", error, "CONTACT", "SHUTDOWN", true)) {
display_clean_shutdown();
} else {
show_error = false;
}
} else {
// Show Contact Info
if (ui_show_message("Contact", "\nContact us at:\n\nhello@foundationdevices.com",
"BACK", "SHUTDOWN", true)) {
display_clean_shutdown();
} else {
show_error = true;
}
}
}
}
void ui_show_hex_buffer(char* title, uint8_t* data, uint32_t length) {
char buf[512];
bytes_to_hex_str(data, length, buf, 8, '\n');
ui_show_message(title, buf, "SHUTDOWN", "CONTINUE", true);
}

16
ports/stm32/boards/Passport/bootloader/ui.h

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc.
// <hello@foundationdevices.com> SPDX-License-Identifier: GPL-3.0-or-later
//
// ui.h - Simple UI elements for the bootloader
#include <stdint.h>
#include <stdbool.h>
// UI elements
void ui_draw_header(char* title);
void ui_draw_footer(char* left_btn, bool is_left_pressed, char* right_btn, bool is_right_pressed);
void ui_draw_button(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char* label, bool is_pressed);
void ui_draw_wrapped_text(uint16_t x, uint16_t y, uint16_t max_width, char* text, bool center);
bool ui_show_message(char* title, char* message, char* left_btn, char*right_btn, bool center);
void ui_show_fatal_error(char* message);
void ui_show_hex_buffer(char* title, uint8_t* buf, uint32_t length);

299
ports/stm32/boards/Passport/bootloader/update.c

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
/*
@ -9,15 +9,35 @@
*
*/
#include <string.h>
#include <stdlib.h>
#include "display.h"
#include "fwheader.h"
#include "hash.h"
#include "se-config.h"
#include "sha256.h"
#include "spiflash.h"
#include "splash.h"
#include "utils.h"
#include "se-atecc608a.h"
#include "verify.h"
#include "flash.h"
#include "update.h"
#include "ui.h"
#include "gpio.h"
#include "firmware-keys.h"
// Global so we can compare with it later in do_update()
static uint8_t spi_hdr_hash[HASH_LEN] = {0};
static void clear_update_from_spi_flash()
{
uint8_t zeros[FW_HEADER_SIZE] = {0};
spi_write(0, 256, zeros);
spi_write(256, sizeof(zeros), zeros);
}
static void calculate_spi_hash(
passport_firmware_header_t *hdr,
@ -26,12 +46,12 @@ static void calculate_spi_hash(
)
{
SHA256_CTX ctx;
uint32_t pos = FW_HEADER_SIZE;
uint32_t pos = FW_HEADER_SIZE + 256; // Skip over the update hash page
uint32_t remaining = hdr->info.fwlength;
uint8_t *buf = (uint8_t *)D1_AXISRAM_BASE; /* Working memory */
sha256_init(&ctx);
sha256_update(&ctx, (uint8_t *)&hdr->info, sizeof(fw_info_t));
while (remaining > 0)
@ -62,6 +82,44 @@ out:
return;
}
static void calculate_spi_hdr_hash(
passport_firmware_header_t *hdr,
uint8_t *hash,
uint8_t hashlen
)
{
SHA256_CTX ctx;
sha256_init(&ctx);
sha256_update(&ctx, (uint8_t *)hdr, sizeof(passport_firmware_header_t));
sha256_final(&ctx, hash);
/* double SHA256 */
sha256_init(&ctx);
sha256_update(&ctx, hash, hashlen);
sha256_final(&ctx, hash);
}
// Hash the spi hash with the device hash value -- used to prevent external attacker from beign able to insert a firmware
// update directly in external SPI flash. They won't be able to replicate this hash.
static void calculate_update_hash(
uint8_t *spi_hash,
uint8_t spi_hashlen,
uint8_t *update_hash,
uint8_t update_hashlen
)
{
SHA256_CTX ctx;
uint8_t device_hash[HASH_LEN];
get_device_hash(device_hash);
sha256_init(&ctx);
sha256_update(&ctx, (uint8_t *)spi_hash, spi_hashlen);
sha256_update(&ctx, device_hash, sizeof(device_hash));
sha256_final(&ctx, update_hash);
}
static int do_update(uint32_t size)
{
int rc;
@ -69,17 +127,62 @@ static int do_update(uint32_t size)
uint32_t pos;
uint32_t addr;
uint32_t data[FLASH_NB_32BITWORD_IN_FLASHWORD] __attribute__((aligned(8)));
uint32_t total = FW_END - FW_START;
uint8_t percent_done = 0;
uint8_t last_percent_done = 255;
uint8_t curr_spi_hdr_hash[HASH_LEN] = {0};
uint32_t remaining_bytes_to_hash = sizeof(passport_firmware_header_t);
secresult not_checked = SEC_TRUE;
SHA256_CTX ctx;
sha256_init(&ctx);
flash_unlock();
// Make sure header still fits in one page or this check will be more complex.
if (sizeof(passport_firmware_header_t) > 256) {
clear_update_from_spi_flash();
ui_show_fatal_error("sizeof(passport_firmware_header_t) > 256");
}
for (pos = 0, addr = FW_START; pos < size; pos += flash_word_len, addr += flash_word_len)
{
if (spi_read(pos, sizeof(data), (uint8_t *)data) != HAL_OK)
// We read starting 256 bytes in as the first page holds the update request hash
if (spi_read(pos + 256, sizeof(data), (uint8_t *)data) != HAL_OK)
{
rc = -1;
break;
}
// TOCTOU check by hashing the header again and comparing to the hash we took earlier when we verified it.
if (remaining_bytes_to_hash > 0) {
// Calculate the running hash 32 bytes at a time until we reach sizeof(passport_firmware_header_t)
size_t hash_size = MIN(remaining_bytes_to_hash, flash_word_len);
sha256_update(&ctx, (uint8_t *)data, hash_size);
remaining_bytes_to_hash -= hash_size;
}
if (not_checked == SEC_TRUE && remaining_bytes_to_hash == 0) {
// Finalize the hash and check it
sha256_final(&ctx, curr_spi_hdr_hash);
/* double SHA256 */
sha256_init(&ctx);
sha256_update(&ctx, curr_spi_hdr_hash, HASH_LEN);
sha256_final(&ctx, curr_spi_hdr_hash);
// ui_show_hex_buffer("Prev Hash", spi_hdr_hash, HASH_LEN);
// ui_show_hex_buffer("TOCTOU Hash", curr_spi_hdr_hash, HASH_LEN);
// Compare the hashes
if (memcmp(curr_spi_hdr_hash, spi_hdr_hash, HASH_LEN) != 0) {
// Someone may be hacking on the SPI flash!
clear_update_from_spi_flash();
ui_show_fatal_error("\nSPI flash appears to have been actively modified during firmware update.");
}
not_checked = SEC_FALSE;
}
if (addr % FLASH_SECTOR_SIZE == 0)
{
rc = flash_sector_erase(addr);
@ -90,26 +193,69 @@ static int do_update(uint32_t size)
rc = flash_burn(addr, (uint32_t)data);
if (rc < 0)
break;
/* Update the progress bar only if the percentage changed */
percent_done = (uint8_t)((float)pos/(float)total * 100.0f);
if (percent_done != last_percent_done)
{
display_progress_bar(PROGRESS_BAR_MARGIN, PROGRESS_BAR_Y, SCREEN_WIDTH - (PROGRESS_BAR_MARGIN * 2), PROGRESS_BAR_HEIGHT, percent_done);
/* Showing just the lines that changed is much faster and avoids full-screen flicker */
display_show_lines(PROGRESS_BAR_Y, PROGRESS_BAR_Y + PROGRESS_BAR_HEIGHT);
last_percent_done = percent_done;
}
}
/* Clear the remainder of flash */
memset(data, 0, sizeof(data));
for (; addr < FW_END; pos += flash_word_len, addr += flash_word_len)
{
if (addr % FLASH_SECTOR_SIZE == 0)
{
rc = flash_sector_erase(addr);
if (rc < 0)
break;
}
rc = flash_burn(addr, (uint32_t)data);
if (rc < 0)
break;
/* Update the progress bar only if the percentage changed */
percent_done = (uint8_t)((float)pos/(float)total * 100.0f);
if (percent_done != last_percent_done)
{
display_progress_bar(PROGRESS_BAR_MARGIN, PROGRESS_BAR_Y, SCREEN_WIDTH - (PROGRESS_BAR_MARGIN * 2), PROGRESS_BAR_HEIGHT, percent_done);
/* Showing just the lines that changed is much faster and avoids full-screen flicker */
display_show_lines(PROGRESS_BAR_Y, PROGRESS_BAR_Y + PROGRESS_BAR_HEIGHT);
last_percent_done = percent_done;
}
}
/* Make sure the progress bar goes to 100 */
display_progress_bar(PROGRESS_BAR_MARGIN, PROGRESS_BAR_Y, SCREEN_WIDTH - (PROGRESS_BAR_MARGIN * 2), PROGRESS_BAR_HEIGHT, 100);
display_show_lines(PROGRESS_BAR_Y, PROGRESS_BAR_Y + PROGRESS_BAR_HEIGHT);
flash_lock();
return rc;
}
bool is_firmware_update_present(void)
secresult is_firmware_update_present(void)
{
passport_firmware_header_t hdr = {};
if (spi_setup() != HAL_OK)
return false;
return SEC_FALSE;
if (spi_read(0, sizeof(hdr), (void *)&hdr) != HAL_OK)
return false;
// Skip first page of flash
if (spi_read(256, sizeof(hdr), (void *)&hdr) != HAL_OK)
return SEC_FALSE;
if (!verify_header(&hdr))
return false;
return SEC_FALSE;
return true;
return SEC_TRUE;
}
void update_firmware(void)
@ -117,32 +263,137 @@ void update_firmware(void)
int rc;
passport_firmware_header_t *internalhdr = FW_HDR;
passport_firmware_header_t spihdr = {0};
uint8_t fw_hash[HASH_LEN] = {0};
uint8_t zeros[FW_HEADER_SIZE] = {0};
uint8_t internal_fw_hash[HASH_LEN] = {0};
uint8_t spi_fw_hash[HASH_LEN] = {0};
uint8_t current_board_hash[HASH_LEN] = {0};
uint8_t new_board_hash[HASH_LEN] = {0};
uint8_t actual_update_hash[HASH_LEN] = {0};
uint8_t expected_update_hash[HASH_LEN] = {0};
/*
* If we fail to either setup the SPI bus or read the SPI flash
* then just return...something is wrong in hardware but maybe it's
* temporary.
*/
if (spi_setup() != HAL_OK)
return;
if (spi_read(0, sizeof(spihdr), (void *)&spihdr) != HAL_OK)
// If the update was requested by the user, then there will be a hash in the first 32 bytes that combines
// the firmware hash with the device hash.
if (spi_read(0, HASH_LEN, (void *)&actual_update_hash) != HAL_OK)
return;
// Start reading one page in as there is a 32-byte hash in the first page
if (spi_read(256, sizeof(spihdr), (void *)&spihdr) != HAL_OK)
return;
// ui_show_hex_buffer("SPI Hdr 1", (uint8_t*)&spihdr, 170);
if (!verify_header(&spihdr))
goto out;
calculate_spi_hdr_hash(&spihdr, spi_hdr_hash, HASH_LEN);
/* Don't allow downgrades */
if (spihdr.info.timestamp <= internalhdr->info.timestamp)
goto out;
calculate_spi_hash(&spihdr, fw_hash, sizeof(fw_hash));
// ui_show_hex_buffer("SPI Hdr Hash", spi_hdr_hash, HASH_LEN);
calculate_update_hash(spi_hdr_hash, sizeof(spi_hdr_hash), expected_update_hash, sizeof(expected_update_hash));
if (!verify_signature(&spihdr, fw_hash, sizeof(fw_hash)))
// Ensure that the hashes match!
if (memcmp(expected_update_hash, actual_update_hash, sizeof(expected_update_hash)) != 0) {
// This looks like an unrequested update (i.e., a possible attack)
goto out;
}
/* Verify firmware header in SPI flash and bail if it fails */
if (!verify_header(&spihdr))
{
if (ui_show_message("Update Error", "The firmware update you chose has an invalid header and will not be installed.", "SHUTDOWN", "OK", true)){
goto out;
} else {
display_clean_shutdown();
}
}
/*
* If the current firmeware verification passes then compare
* timestamps and don't allow an earlier version. However, if the
* internal firmware header verification fails then proceed with the
* update...maybe the previous update attempt failed because we lost
* power.
*
* We also allow going back and forth between user-signed firmware and Foundation-signed firmware.
*/
if (verify_current_firmware(true) == SEC_TRUE)
{
if ((spihdr.signature.pubkey1 != FW_USER_KEY && internalhdr->signature.pubkey1 != FW_USER_KEY) &&
(spihdr.info.timestamp < internalhdr->info.timestamp))
{
if (ui_show_message("Update Error", "This firmware update is older than the current firmware and will not be installed.", "SHUTDOWN", "OK", true))
goto out;
else
display_clean_shutdown();
}
// Handle the firmware hash update
uint8_t *fwptr = (uint8_t *)internalhdr + FW_HEADER_SIZE;
hash_fw(&internalhdr->info, fwptr, internalhdr->info.fwlength, internal_fw_hash, sizeof(internal_fw_hash));
hash_board(internal_fw_hash, sizeof(internal_fw_hash), current_board_hash, sizeof(current_board_hash));
calculate_spi_hash(&spihdr, spi_fw_hash, sizeof(spi_fw_hash));
/* Verify the signature and bail if it fails */
if (verify_signature(&spihdr, spi_fw_hash, sizeof(spi_fw_hash)) == SEC_FALSE)
{
if (ui_show_message("Update Error", "The firmware update does not appear to be properly signed and will not be installed.\n\nThis can also occur if you lost power during a firmware update.", "SHUTDOWN", "OK", true))
goto out;
else
display_clean_shutdown();
}
/*
* Calculate a new board hash based on the SPI firmware and then
* reprogram the board hash in the SE. If the update fails it
* will be retried until it succeeds or the board is declared dead.
*/
hash_board(spi_fw_hash, sizeof(spi_fw_hash), new_board_hash, sizeof(new_board_hash));
#ifdef CONVERSION_BUILD
/*
* Conversion build is temporary and used to get current demo
* boards which have 0's programmed for the board hash to be
* properly programmed with a real board hash. Thereafter they
* will only be able to update via SD card.
* Delete this code once this has been done.
*/
memset(current_board_hash, 0, sizeof(current_board_hash));
#endif /* CONVERSION_BUILD */
rc = se_program_board_hash(current_board_hash, new_board_hash, sizeof(new_board_hash));
if (rc < 0) {
if (ui_show_message("Update Error", "Unable to update the firmware hash in the Secure Element. Update will continue, but may not be successful.", "SHUTDOWN", "OK", true)){
// Nothing to do
} else {
display_clean_shutdown();
}
}
}
// Draw the logo and message - progress bar gets drawn and updated periodically in do_update()
show_splash("Updating Firmware...");
rc = do_update(FW_HEADER_SIZE + spihdr.info.fwlength);
if (rc < 0)
return; /* Don't erase SPI...maybe it will work next time */
{
if (ui_show_message("Update Error", "Failed to install the firmware update.", "SHUTDOWN", "RESTART", true))
passport_reset();
else
// TODO: Should we have an option here to clear the SPI flash and restart (we could run a verify_current_firmware() first to make sure it's safe to boot there
display_clean_shutdown();
}
out:
spi_write(0, sizeof(zeros), zeros);
clear_update_from_spi_flash();
}
secresult is_user_signed_firmware_installed(void)
{
passport_firmware_header_t *hdr = FW_HDR;
return (hdr->signature.pubkey1 == FW_USER_KEY && hdr->signature.pubkey2 == 0) ? SEC_TRUE : SEC_FALSE;
}

6
ports/stm32/boards/Passport/bootloader/update.h

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
#pragma once
@ -6,5 +6,5 @@
#include <stdint.h>
extern void update_firmware(void);
extern bool is_firmware_update_present(void);
extern secresult is_firmware_update_present(void);
extern secresult is_user_signed_firmware_installed(void);

123
ports/stm32/boards/Passport/bootloader/verify.c

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
/*
@ -9,40 +9,45 @@
*
*/
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "utils.h"
#include "sha256.h"
#include "delay.h"
#include "firmware-keys.h"
#include "hash.h"
#include "delay.h"
#include "uECC.h"
#include "se.h"
#include "se-atecc608a.h"
#include "se-config.h"
#include "sha256.h"
#include "uECC.h"
#include "utils.h"
#include "update.h"
#include "se-atecc608a.h"
#include "verify.h"
bool verify_header(passport_firmware_header_t *hdr)
secresult verify_header(passport_firmware_header_t *hdr)
{
if (hdr->info.magic != FW_HEADER_MAGIC) goto fail;
if (hdr->info.timestamp == 0) goto fail;
if (hdr->info.fwversion[0] == 0x0) goto fail;
if (hdr->info.fwlength == 0x0) goto fail;
if (hdr->info.fwlength < FW_HEADER_SIZE) goto fail;
#ifdef USE_CRYPTO
if (hdr->signature.pubkey1 == 0) goto fail;
if (hdr->signature.pubkey1 > FW_MAX_PUB_KEYS) goto fail;
if (hdr->signature.pubkey2 == 0) goto fail;
if (hdr->signature.pubkey2 > FW_MAX_PUB_KEYS) goto fail;
// if (hdr->signature.pubkey1 == 0) goto fail;
if ((hdr->signature.pubkey1 != FW_USER_KEY) && (hdr->signature.pubkey1 > FW_MAX_PUB_KEYS)) goto fail;
if (hdr->signature.pubkey1 != FW_USER_KEY)
{
// if (hdr->signature.pubkey2 == 0) goto fail;
if (hdr->signature.pubkey2 > FW_MAX_PUB_KEYS) goto fail;
}
#endif /* USE_CRYPTO */
return true;
return SEC_TRUE;
fail:
return false;
return SEC_FALSE;
}
bool verify_signature(
secresult verify_signature(
passport_firmware_header_t *hdr,
uint8_t *fw_hash,
uint32_t hashlen
@ -51,53 +56,77 @@ bool verify_signature(
#ifdef USE_CRYPTO
int rc;
rc = uECC_verify(approved_pubkeys[hdr->signature.pubkey1],
fw_hash, hashlen,
hdr->signature.signature1, uECC_secp256k1());
if (rc == 0)
return false;
rc = uECC_verify(approved_pubkeys[hdr->signature.pubkey2],
fw_hash, hashlen,
hdr->signature.signature2, uECC_secp256k1());
if (rc == 0)
return false;
return true;
if (hdr->signature.pubkey1 == FW_USER_KEY)
{
uint8_t user_public_key[72] = {0};
/*
* It looks like the user signed this firmware so, in order to
* validate, we need to get the public key from the SE.
*/
se_pair_unlock();
rc = se_read_data_slot(KEYNUM_user_fw_pubkey, user_public_key, sizeof(user_public_key));
if (rc < 0)
return SEC_FALSE;
rc = uECC_verify(user_public_key,
fw_hash, hashlen,
hdr->signature.signature1, uECC_secp256k1());
if (rc == 0)
return SEC_FALSE;
}
else
{
rc = uECC_verify(approved_pubkeys[hdr->signature.pubkey1],
fw_hash, hashlen,
hdr->signature.signature1, uECC_secp256k1());
if (rc == 0)
return SEC_FALSE;
rc = uECC_verify(approved_pubkeys[hdr->signature.pubkey2],
fw_hash, hashlen,
hdr->signature.signature2, uECC_secp256k1());
if (rc == 0)
return SEC_FALSE;
}
return SEC_TRUE;
#else
return true;
return SEC_TRUE;
#endif /* USE_CRYPTO */
}
bool verify_current_firmware(void)
secresult verify_current_firmware(
bool process_led
)
{
int rc;
uint8_t fw_hash[HASH_LEN];
uint8_t board_hash[HASH_LEN];
passport_firmware_header_t *fwhdr = (passport_firmware_header_t *)FW_HDR;
uint8_t *fwptr = (uint8_t *)fwhdr + FW_HEADER_SIZE;
if (!verify_header(fwhdr))
goto fail;
return ERR_INVALID_FIRMWARE_HEADER;
hash_fw(&fwhdr->info, fwptr, fwhdr->info.fwlength, fw_hash, sizeof(fw_hash));
if (!verify_signature(fwhdr, fw_hash, sizeof(fw_hash)))
goto fail;
if (verify_signature(fwhdr, fw_hash, sizeof(fw_hash)) == SEC_FALSE)
return ERR_INVALID_FIRMWARE_SIGNATURE;
#ifdef DEMO
memset(board_hash, 0, sizeof(board_hash));
#else
hash_board(fw_hash, sizeof(fw_hash), board_hash, sizeof(board_hash));
#endif /* DEMO */
rc = se_set_gpio_secure(board_hash);
if (rc < 0)
goto fail;
#ifdef PRODUCTION_BUILD
if (process_led)
{
int rc;
uint8_t board_hash[HASH_LEN];
return true;
hash_board(fw_hash, sizeof(fw_hash), board_hash, sizeof(board_hash));
fail:
return false;
rc = se_set_gpio_secure(board_hash);
if (rc < 0)
return ERR_UNABLE_TO_UPDATE_FIRMWARE_HASH_IN_SE;
}
#endif /* PRODUCTION_BUILD */
return SEC_TRUE;
}
// EOF

11
ports/stm32/boards/Passport/bootloader/verify.h

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
/*
@ -10,9 +10,8 @@
#include <stdbool.h>
#include "fwheader.h"
#include "secresult.h"
extern bool verify_current_firmware(void);
extern bool verify_header(passport_firmware_header_t *hdr);
extern bool verify_signature(passport_firmware_header_t *hdr, uint8_t *fw_hash, uint32_t hashlen);
extern void verify_min_version(uint8_t *min_version);
extern secresult verify_header(passport_firmware_header_t *hdr);
extern secresult verify_current_firmware(bool process_led);
extern secresult verify_signature(passport_firmware_header_t *hdr, uint8_t *fw_hash, uint32_t hashlen);

6
ports/stm32/boards/Passport/bootloader/version_info.h

@ -0,0 +1,6 @@
// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
extern char *build_date;
extern char *build_version;

196
ports/stm32/boards/Passport/busy_bar.c

@ -0,0 +1,196 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc.
// <hello@foundationdevices.com> SPDX-License-Identifier: GPL-3.0-or-later
//
// busy_bar.c - Timer and rendering code for busy bar
#include <string.h>
#include <math.h>
#include "display.h"
#include "firmware_graphics.h"
#define BUSY_BAR_HEIGHT 34
static TIM_HandleTypeDef htim7;
#ifdef SINE_WAVE_BUSY_BAR
#define NUM_BUSY_BAR_FRAMES 24
#define NUM_BUSY_BAR_FRAMES_TO_RENDER 20
static int busy_bar_frames[NUM_BUSY_BAR_FRAMES] = {6,5,4,3,2,1,0,1,2,3,4,5,6,5,4,3,2,1,0,1,2,3,4,5};
#define NUM_BUSY_BAR_IMAGES 7
static Image* busy_bar_images[NUM_BUSY_BAR_IMAGES] = {
&busybar1_img,
&busybar2_img,
&busybar3_img,
&busybar4_img,
&busybar5_img,
&busybar6_img,
&busybar7_img,
};
#define X_OFFSET_PER_IMAGE 20
#define DIRECTION_RIGHT_TO_LEFT 1
#define DIRECTION_LEFT_TO_RIGHT 2
static float sin_offset = 0.0;
static void busy_bar(void)
{
int16_t start_y = SCREEN_HEIGHT - BUSY_BAR_HEIGHT;
uint16_t direction = DIRECTION_LEFT_TO_RIGHT;
// Draw white area for the background since we only draw black pixels below
display_fill_rect(0, start_y, SCREEN_WIDTH, BUSY_BAR_HEIGHT, 0);
for (int16_t i=0; i<NUM_BUSY_BAR_FRAMES_TO_RENDER; i++) {
int16_t x = (X_OFFSET_PER_IMAGE * i) - 10;
uint16_t image_index = 1; //busy_bar_frames[i];
float v = (float)x + sin_offset; // Offset for animation
float s = sin(v);
int16_t scaled = (int16_t)(s * 7.0f);
int16_t y = (int16_t)(scaled + start_y + 8);
display_image(x + ((int16_t)(sin_offset * 2.0) % X_OFFSET_PER_IMAGE), y, busy_bar_images[image_index]->width, busy_bar_images[image_index]->height, busy_bar_images[image_index]->data, DRAW_MODE_WHITE_ONLY);
}
display_show_lines(start_y, start_y + SCREEN_HEIGHT - 1);
sin_offset += 1.0;
// Rotate frame indexes
if (direction == DIRECTION_RIGHT_TO_LEFT) {
int first = busy_bar_frames[0];
for (int16_t i=0; i<NUM_BUSY_BAR_FRAMES - 1; i++) {
busy_bar_frames[i] = busy_bar_frames[i+1];
}
busy_bar_frames[NUM_BUSY_BAR_FRAMES-1] = first;
} else {
int last = busy_bar_frames[NUM_BUSY_BAR_FRAMES-1];
for (int16_t i=NUM_BUSY_BAR_FRAMES - 1; i>0; i--) {
busy_bar_frames[i] = busy_bar_frames[i-1];
}
busy_bar_frames[0] = last;
}
}
#endif
#define KNIGHT_RIDER_BUSY_BAR
#ifdef KNIGHT_RIDER_BUSY_BAR
#define NUM_BUSY_BAR_IMAGES 6
#define X_OFFSET_PER_IMAGE 23
typedef struct _bal_info_t {
Image* image;
int16_t x_pos;
int8_t direction;
} ball_info_t;
ball_info_t ball_info[NUM_BUSY_BAR_IMAGES] = {
// {&busybar7_img, 0, 1},
{&busybar6_img, 0, 1},
{&busybar5_img, 0, 1},
{&busybar4_img, 0, 1},
{&busybar3_img, 0, 1},
{&busybar2_img, 0, 1},
{&busybar1_img, 0, 1},
};
static bool first_activation = true;
static void busy_bar_reset_animation(void) {
for (int16_t i=0; i<NUM_BUSY_BAR_IMAGES; i++) {
ball_info[i].x_pos = -(X_OFFSET_PER_IMAGE*i);
ball_info[i].direction = 1;
}
}
static void busy_bar(void)
{
int16_t start_y = SCREEN_HEIGHT - BUSY_BAR_HEIGHT;
int16_t x_offset = (X_OFFSET_PER_IMAGE - ball_info[0].image->width) / 2;
// Don't draw this the first time we show it on the splash screen -- looks better
if (!first_activation) {
// Draw a black separator line (should be exactly where the footer line is)
display_fill_rect(0, start_y, SCREEN_WIDTH, 1, 1);
}
// Draw white area for the background since we only draw black pixels below
display_fill_rect(0, start_y + 1, SCREEN_WIDTH, BUSY_BAR_HEIGHT - 1, 0);
// Vertical offset to center busy bar
int16_t voffset = (BUSY_BAR_HEIGHT / 2) - (ball_info[0].image->height/2);
for (int16_t i=0; i<NUM_BUSY_BAR_IMAGES; i++) {
display_image(ball_info[i].x_pos + x_offset, start_y + voffset, ball_info[i].image->width, ball_info[i].image->height, ball_info[i].image->data, DRAW_MODE_WHITE_ONLY);
// Move this ball for next time
ball_info[i].x_pos += X_OFFSET_PER_IMAGE * ball_info[i].direction;
if ((ball_info[i].x_pos < 0 && ball_info[i].direction == -1) ||
(ball_info[i].x_pos > SCREEN_WIDTH && ball_info[i].direction == 1)) {
ball_info[i].direction = -ball_info[i].direction;
}
}
int16_t end_y = start_y + BUSY_BAR_HEIGHT - 1;
display_show_lines(start_y, end_y);
}
#endif
void TIM7_IRQHandler(void)
{
if (__HAL_TIM_GET_FLAG(&htim7, TIM_FLAG_UPDATE) != RESET)
{
if (__HAL_TIM_GET_ITSTATUS(&htim7, TIM_IT_UPDATE) != RESET)
{
__HAL_TIM_CLEAR_FLAG(&htim7, TIM_FLAG_UPDATE);
busy_bar();
}
}
return;
}
void busy_bar_start(void)
{
busy_bar_reset_animation();
HAL_NVIC_EnableIRQ(TIM7_IRQn);
HAL_TIM_Base_Start_IT(&htim7);
}
void busy_bar_stop(void)
{
HAL_TIM_Base_Stop_IT(&htim7);
HAL_NVIC_DisableIRQ(TIM7_IRQn);
first_activation = false;
}
void busy_bar_init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
uint16_t prescaler;
uint32_t period;
__TIM7_CLK_ENABLE();
/* Fixed interrupt frequency of 1 Hz */
prescaler = 24000 - 1;
period = 1000 - 1;
htim7.Instance = TIM7;
htim7.Init.Prescaler = prescaler;
htim7.Init.CounterMode = TIM_COUNTERMODE_UP;
htim7.Init.Period = period;
htim7.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim7.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&htim7);
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim7, &sClockSourceConfig);
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim7, &sMasterConfig);
__HAL_TIM_CLEAR_FLAG(&htim7, TIM_SR_UIF);
HAL_NVIC_SetPriority(TIM7_IRQn, 10, 0);
}

9
ports/stm32/boards/Passport/busy_bar.h

@ -0,0 +1,9 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// busy_bar.h - Timer and rendering code for busy bar
#pragma once
extern void busy_bar_init(void);
extern void busy_bar_start(void);
extern void busy_bar_stop(void);

269
ports/stm32/boards/Passport/bytewords_word_info.c

@ -0,0 +1,269 @@
// SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
#include <stdint.h>
typedef struct {
uint32_t keypad_digits;
uint16_t offsets;
} word_info_t;
word_info_t bytewords_word_info[] = {
{2225, 0x4900}, // back
{2243, 0x2800}, // acid
{2253, 0x1900}, // able
{2253, 0x4800}, // bald
{2256, 0x8800}, // calm
{2274, 0x8d00}, // cash
{2276, 0x4900}, // barn
{2287, 0x8300}, // cats
{2358, 0x5800}, // belt
{2382, 0x5000}, // beta
{2427, 0x6300}, // bias
{2433, 0x9600}, // chef
{2489, 0xa200}, // city
{2529, 0xa000}, // claw
{2576, 0x2e00}, // also
{2583, 0x6500}, // blue
{2633, 0xa100}, // code
{2639, 0x6200}, // body
{2652, 0xa800}, // cola
{2665, 0xa900}, // cook
{2678, 0xac00}, // cost
{2724, 0x2900}, // arch
{2724, 0x6000}, // brag
{2739, 0x0500}, // apex
{2739, 0x6400}, // brew
{2782, 0x1400}, // aqua
{2789, 0xa500}, // crux
{2852, 0x5900}, // bulb
{2866, 0x0800}, // atom
{2868, 0x1400}, // aunt
{2875, 0x9a00}, // curl
{2877, 0x9c00}, // cusp
{2899, 0x5f00}, // buzz
{2926, 0xa100}, // cyan
{2929, 0x0200}, // away
{2947, 0x1b00}, // axis
{3224, 0x4900}, // each
{3228, 0x8800}, // fact
{3246, 0x6600}, // echo
{3247, 0x8a00}, // fair
{3275, 0x0900}, // dark
{3279, 0x4e00}, // easy
{3282, 0x0000}, // data
{3297, 0x0b00}, // days
{3343, 0x4100}, // edge
{3354, 0x1a00}, // deli
{3376, 0x9900}, // fern
{3423, 0x2900}, // dice
{3438, 0x2400}, // diet
{3447, 0xa300}, // figs
{3456, 0xa800}, // film
{3474, 0xad00}, // fish
{3499, 0xaf00}, // fizz
{3527, 0xa000}, // flap
{3539, 0xa400}, // flew
{3589, 0xa500}, // flux
{3667, 0x2a00}, // door
{3696, 0x2100}, // down
{3699, 0xa600}, // foxy
{3729, 0x2000}, // draw
{3733, 0xa500}, // free
{3742, 0x4a00}, // epic
{3764, 0xa800}, // frog
{3767, 0x2800}, // drop
{3786, 0x2400}, // drum
{3835, 0x9600}, // fuel
{3836, 0x6500}, // even
{3855, 0x1a00}, // dull
{3863, 0x9400}, // fund
{3889, 0x1200}, // duty
{3926, 0x5000}, // exam
{3937, 0x6700}, // eyes
{3948, 0x5800}, // exit
{4233, 0xa400}, // iced
{4252, 0x0800}, // gala
{4253, 0x4a00}, // half
{4263, 0x0100}, // game
{4264, 0x4400}, // hang
{4273, 0x4800}, // hard
{4295, 0x4100}, // hawk
{4327, 0x1200}, // gear
{4328, 0x5000}, // heat
{4332, 0x8400}, // idea
{4353, 0x8900}, // idle
{4357, 0x5800}, // help
{4367, 0x1300}, // gems
{4438, 0x2800}, // gift
{4444, 0x6100}, // high
{4455, 0x6a00}, // hill
{4475, 0x2a00}, // girl
{4569, 0x2800}, // glow
{4624, 0x9900}, // inch
{4659, 0x6a00}, // holy
{4659, 0x9600}, // inky
{4663, 0x2800}, // good
{4673, 0x6100}, // hope
{4676, 0x6900}, // horn
{4686, 0x9200}, // into
{4729, 0x2200}, // gray
{4746, 0x2800}, // grim
{4747, 0xab00}, // iris
{4766, 0xa900}, // iron
{4836, 0x8400}, // item
{4874, 0x1d00}, // gush
{4878, 0x1900}, // guru
{4887, 0x5300}, // huts
{4976, 0x2a00}, // gyro
{5233, 0x0100}, // jade
{5262, 0x8100}, // lamb
{5282, 0x8800}, // lava
{5299, 0x0f00}, // jazz
{5299, 0x8e00}, // lazy
{5323, 0x9200}, // leaf
{5337, 0x5400}, // keep
{5347, 0x9300}, // legs
{5366, 0x5600}, // keno
{5378, 0x5000}, // kept
{5397, 0x5b00}, // keys
{5425, 0x6900}, // kick
{5427, 0xa200}, // liar
{5456, 0x6900}, // kiln
{5464, 0x6400}, // king
{5466, 0xa900}, // lion
{5467, 0xa000}, // limp
{5478, 0xac00}, // list
{5483, 0x6100}, // kite
{5494, 0x6200}, // kiwi
{5646, 0x2900}, // join
{5646, 0xa200}, // logo
{5658, 0x2800}, // jolt
{5662, 0x5900}, // knob
{5683, 0xa400}, // loud
{5683, 0xa900}, // love
{5695, 0x2200}, // jowl
{5825, 0x9900}, // luck
{5828, 0x9100}, // luau
{5836, 0x1200}, // judo
{5847, 0x1300}, // jugs
{5864, 0x9400}, // lung
{5865, 0x1500}, // junk
{5867, 0x1000}, // jump
{5879, 0x1a00}, // jury
{6239, 0x9600}, // obey
{6245, 0x4a00}, // nail
{6246, 0x0900}, // main
{6263, 0x9900}, // oboe
{6269, 0x0600}, // many
{6284, 0x0100}, // math
{6289, 0x4a00}, // navy
{6293, 0x0d00}, // maze
{6333, 0x5400}, // need
{6366, 0x1200}, // memo
{6368, 0x1500}, // menu
{6369, 0x1800}, // meow
{6397, 0x5300}, // news
{6398, 0x5400}, // next
{6453, 0x2800}, // mild
{6468, 0x2400}, // mint
{6477, 0x2f00}, // miss
{6648, 0x8800}, // omit
{6665, 0x2500}, // monk
{6666, 0x6900}, // noon
{6683, 0x6100}, // note
{6699, 0x9900}, // onyx
{6736, 0x8500}, // open
{6825, 0xa200}, // oval
{6862, 0x5100}, // numb
{6957, 0x8b00}, // owls
{7223, 0x8900}, // race
{7227, 0xe200}, // scar
{7233, 0xc900}, // safe
{7242, 0xc000}, // saga
{7243, 0x0800}, // paid
{7267, 0x8000}, // ramp
{7278, 0x0800}, // part
{7325, 0x1900}, // peck
{7325, 0x9200}, // real
{7336, 0x9200}, // redo
{7387, 0xd300}, // sets
{7424, 0xa900}, // rich
{7455, 0xe900}, // silk
{7529, 0x2200}, // play
{7539, 0xd400}, // skew
{7568, 0xe800}, // slot
{7587, 0x2700}, // plus
{7623, 0xa000}, // road
{7625, 0xa900}, // rock
{7627, 0xe000}, // soap
{7636, 0x2400}, // poem
{7656, 0xea00}, // solo
{7663, 0xaa00}, // roof
{7664, 0xe400}, // song
{7665, 0x2a00}, // pool
{7673, 0x2d00}, // pose
{7823, 0x5000}, // quad
{7829, 0x9600}, // ruby
{7833, 0x1a00}, // puff
{7846, 0x9900}, // ruin
{7849, 0x5b00}, // quiz
{7862, 0x1000}, // puma
{7867, 0x9700}, // runs
{7873, 0xda00}, // surf
{7877, 0x1a00}, // purr
{7878, 0x9c00}, // rust
{7882, 0xc500}, // stub
{7926, 0xc100}, // swan
{8226, 0x0a00}, // taco
{8275, 0x0d00}, // task
{8278, 0x8c00}, // vast
{8294, 0x0600}, // taxi
{8368, 0x1400}, // tent
{8379, 0x9a00}, // very
{8386, 0x9200}, // veto
{8423, 0xa500}, // vibe
{8425, 0xa200}, // vial
{8433, 0x2400}, // tied
{8439, 0xa400}, // view
{8459, 0x4a00}, // ugly
{8463, 0x2100}, // time
{8469, 0x2600}, // tiny
{8472, 0xac00}, // visa
{8636, 0x5200}, // undo
{8643, 0xa800}, // void
{8645, 0x2a00}, // toil
{8648, 0x5800}, // unit
{8662, 0x2100}, // tomb
{8697, 0x2b00}, // toys
{8697, 0xa300}, // vows
{8737, 0x7600}, // user
{8743, 0x6100}, // urge
{8747, 0x2800}, // trip
{8862, 0x1400}, // tuna
{8946, 0x0900}, // twin
{9255, 0x0a00}, // wall
{9263, 0x0400}, // wand
{9265, 0x8500}, // yank
{9276, 0x0800}, // warm
{9277, 0x0c00}, // wasp
{9277, 0xc300}, // zaps
{9283, 0x0900}, // wave
{9296, 0x8100}, // yawn
{9299, 0x0600}, // waxy
{9327, 0x1700}, // webs
{9355, 0x9a00}, // yell
{9376, 0xda00}, // zero
{9378, 0xdc00}, // zest
{9428, 0x1000}, // what
{9436, 0x1500}, // when
{9449, 0x1b00}, // whiz
{9462, 0xe600}, // zinc
{9642, 0xa000}, // yoga
{9653, 0x2a00}, // wolf
{9663, 0xe500}, // zone
{9666, 0xe800}, // zoom
{9675, 0x2900}, // work
{9878, 0x9800} // yurt
};

34
ports/stm32/boards/Passport/camera-ovm7690.c

@ -171,9 +171,9 @@ static CAMERA_REG Camera_RegInit[] = {
{0x14, 0x29}, /* Max AGC 8x */
{0x13, 0xE7}, /* fast AGC/AEC, AEC step unlimited, banding filter, AEC below banding, AGC auto, AWB auto, exp auto */
{0x11, 0x00}, /* external clock or internal clock prescalar */
{0x11, 0x40}, /* external clock or internal clock prescalar */
{0x0E, 0x03}, /* already specified above */
{0x0E, 0x00}, /* already specified above */
{0xC8, 0x02},
{0xC9, 0x40}, /* Input Horiz 576 */
@ -252,7 +252,7 @@ camera_on(void)
int rc;
uint8_t val;
printf("DRIVER: camera_on()\n");
// printf("DRIVER: camera_on()\n");
rc = camera_read(0x0E, &val);
if (rc < 0)
{
@ -279,9 +279,7 @@ camera_off(void)
uint8_t val;
HAL_StatusTypeDef rc;
printf("DRIVER: camera_off() 1\n");
rc = HAL_DCMI_Stop(&hdcmi);
printf("DRIVER: camera_off() 1\n");
if (rc != HAL_OK)
{
printf("[%s] HAL_DCMI_Stop() failed\n", __func__);
@ -289,7 +287,6 @@ printf("DRIVER: camera_off() 1\n");
}
irc = camera_read(0x0E, &val);
printf("DRIVER: camera_off() 2\n");
if (irc < 0)
{
printf("[%s] camera_read() failed\n", __func__);
@ -299,14 +296,12 @@ printf("DRIVER: camera_off() 2\n");
/* Put camera into sleep mode */
irc = camera_write(0x0E, val | (1 << 3));
printf("DRIVER: camera_off() 3\n");
if (irc < 0)
{
printf("[%s] camera_write() failed\n", __func__);
rval = -1;
}
out:
printf("DRIVER: camera_off() - DONE\n");
return rval;
}
@ -335,9 +330,6 @@ int camera_snapshot(void)
// uint32_t total_start = HAL_GetTick();
// uint32_t total_end = 0;
/* Clear the buffer */
memset(camera_frame_buffer, 0, (FRAMEBUF_SIZE * 2));
/* Clear any current interrupts */
hdcmi.Instance->ICR = DCMI_IT_FRAME | DCMI_IT_OVR | DCMI_IT_ERR | DCMI_IT_VSYNC | DCMI_IT_LINE;
@ -366,6 +358,7 @@ int camera_snapshot(void)
}
// printf("[%s] frame complete in %d milliseconds\n", __func__, count);
}
out:
// Need to call this after DMA completes
camera_stop_dcmi();
@ -423,7 +416,7 @@ int camera_init(void)
FrameBufAddr = (uint32_t)camera_frame_buffer;
printf("****************************************************************************\n");
// printf("****************************************************************************\n");
/*
* Per STM Appnote AN5020
@ -498,6 +491,17 @@ int camera_init(void)
GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Configure the BUF1_OE and BUF2_OE */
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_9, 0);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_10, 0);
GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = 0;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/* Configure Timer 3 channel 4 */
__TIM3_CLK_ENABLE();
@ -541,7 +545,8 @@ int camera_init(void)
__HAL_RCC_I2C1_CLK_ENABLE();
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x109095DF;
hi2c1.Init.Timing = 0x00B07FFF; /* 0x00100727 - 300 KHz @ 64 MHz */
/* 0x00B07FFF - 300 KHz @ 480 MHz */
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
@ -586,6 +591,7 @@ int camera_init(void)
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_7, GPIO_PIN_SET);
HAL_Delay(20);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_7, GPIO_PIN_RESET);
HAL_Delay(20);
/* Configure camera size */
camera_setQVGA();
@ -595,7 +601,7 @@ int camera_init(void)
val &= ~(1 << 7);
camera_write(0x6F, val);
printf("CAMERA INIT COMPLETE!\n");
// printf("CAMERA INIT COMPLETE!\n");
return 0;
}

5
ports/stm32/boards/Passport/camera-ovm7690.h

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: BSD-3-Clause
//
@ -44,7 +44,7 @@
#define CAMERA_WIDTH 396
#define CAMERA_HEIGHT 330
#define FRAMEBUF_SIZE (CAMERA_WIDTH * CAMERA_HEIGHT)
#if 0 /* Not used for now */
/* Camera registers */
#define GAIN 0x00
#define BGAIN 0x01
@ -190,6 +190,7 @@
#define REGDF 0xDF
#define REGE0 0xE0
#define REGE1 0xE1
#endif
extern uint16_t *camera_frame_buffer;

4
ports/stm32/boards/Passport/clang-format.txt

@ -1,4 +0,0 @@
---
BreakBeforeBraces: Allman
...

30
ports/stm32/boards/Passport/backlight.c → ports/stm32/boards/Passport/common/backlight.c

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// Backlight driver for LED
@ -23,8 +23,9 @@ void backlight_init(void)
__TIM4_CLK_ENABLE();
backlight_timer_handle.Instance = TIM4;
/* Prescale = 10 gives about 331 Hz 200 - 400Hz ideal */
backlight_timer_handle.Init.Prescaler = 10;
backlight_timer_handle.Init.Prescaler = 10; /* Default for 480 MHz */
backlight_timer_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
backlight_timer_handle.Init.Period = 65535;
backlight_timer_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
@ -49,6 +50,14 @@ void backlight_init(void)
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
// Only initialize what's necessary for the firmware to takeover control of the backlight since the main
// backlight_init() function was already called by the bootloader. If we call the full init again, the backlight
// turns off for a couple of seconds during startup, which is not good UX.
void backlight_minimal_init(void)
{
backlight_timer_handle.Instance = TIM4;
}
/*
* backlight_intensity()
* Adjusts intensity of the backlight when passed a value between 0 and 100.
@ -57,7 +66,9 @@ void backlight_init(void)
* Returns: Nothing
*/
void backlight_intensity(uint16_t intensity)
void backlight_intensity(
uint16_t intensity
)
{
if (intensity == 0) {
/* Turn backlight timer off */
@ -70,3 +81,16 @@ void backlight_intensity(uint16_t intensity)
*BACKLIGHT_PWM_CCR() = intensity * (BACKLIGHT_PWM_TIM_PERIOD - 1) / 100;
}
}
void backlight_adjust(
bool turbo
)
{
HAL_TIM_PWM_Stop(&backlight_timer_handle, TIM_CHANNEL_3);
if (turbo)
backlight_timer_handle.Init.Prescaler = 10;
else
backlight_timer_handle.Init.Prescaler = 1;
TIM_Base_SetConfig(backlight_timer_handle.Instance, &backlight_timer_handle.Init);
HAL_TIM_PWM_Start(&backlight_timer_handle, TIM_CHANNEL_3);
}

4
ports/stm32/boards/Passport/common/delay.c

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
/*

187
ports/stm32/boards/Passport/common/display.c

@ -0,0 +1,187 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc.
// <hello@foundationdevices.com> SPDX-License-Identifier: GPL-3.0-or-later
//
// display.c - Display rendering functions for the Passport bootloader
#include <string.h>
#include "display.h"
#include "keypad-adp-5587.h"
#include "gpio.h"
static uint8_t disp_buf[SCREEN_BYTES_PER_LINE * SCREEN_HEIGHT];
static uint8_t get_image_pixel(int16_t x, int16_t y, uint16_t w, uint16_t h, uint8_t* image, uint8_t default_color)
{
if (x < 0 || x >= w || y < 0 || y >= h) {
return default_color;
}
uint16_t w_bytes = (w + 7) / 8;
uint16_t offset = (y * w_bytes) + x / 8;
uint8_t bit = 1 << (7 - x % 8);
return ((image[offset] & bit) == 0) ? 0 : 1;
}
static void set_pixel(int16_t x, int16_t y, uint8_t c)
{
if (x < 0 || x >= SCREEN_WIDTH || y < 0 || y >= SCREEN_HEIGHT) {
return;
}
uint16_t offset = (y * SCREEN_BYTES_PER_LINE) + x / 8;
uint8_t bit = 1 << (7 - x % 8);
if (c == 1) {
disp_buf[offset] |= bit;
} else {
disp_buf[offset] &= ~bit;
}
}
uint16_t display_measure_text(char* text, Font* font)
{
uint16_t width = 0;
uint16_t slen = strlen(text);
for (int i=0; i<slen; i++){
GlyphInfo glyphInfo;
glyph_lookup(font, text[i], &glyphInfo);
width += glyphInfo.advance;
}
return width;
}
void display_fill_rect(int16_t x, int16_t y, int16_t w, int16_t h, uint8_t color)
{
for (int dy = y; dy < y + h; dy++) {
for (int dx = x; dx < x + w; dx++) {
set_pixel(dx, dy, color);
}
}
}
void display_text(char* text, int16_t x, int16_t y, Font* font, bool invert)
{
if (x == CENTER_X) {
uint16_t text_width = display_measure_text(text, font);
x = SCREEN_WIDTH/2 - text_width/2;
}
uint16_t slen = strlen(text);
for (int i=0; i<slen; i++) {
GlyphInfo glyphInfo;
glyph_lookup(font, text[i], &glyphInfo);
// y + font.ascent - fn.h - fn.y
display_image(x + glyphInfo.x, y + font->ascent - glyphInfo.h - glyphInfo.y, glyphInfo.w, glyphInfo.h, glyphInfo.bitmap,
invert ? DRAW_MODE_WHITE_ONLY | DRAW_MODE_INVERT : DRAW_MODE_WHITE_ONLY);
x += glyphInfo.advance;
}
}
uint16_t display_get_char_width(char ch, Font* font)
{
GlyphInfo glyphInfo;
glyph_lookup(font, ch, &glyphInfo);
return glyphInfo.advance;
}
void display_rect(int16_t x, int16_t y, int16_t w, int16_t h, u_int8_t color)
{
// Draw the top and bottom
int16_t y_bottom = y + h - 1;
for (int dx = x; dx < x + w; dx++) {
set_pixel(dx, y, color);
set_pixel(dx, y_bottom, color);
}
// Draw the sides - repeats the top and bottom pixels to avoid special case
// code for short rectangles
int16_t x_right = x + w - 1;
for (int dy = y; dy < y + w; dy++) {
set_pixel(x, dy, color);
set_pixel(x_right, dy, color);
}
}
// Very simple and inefficient image drawing, but should be fast enough for our
// limited use.
void display_image(uint16_t x, uint16_t y, uint16_t image_w, uint16_t image_h, uint8_t* image, uint8_t mode)
{
// Iterate over the image bounds
for (int dy = 0; dy < image_h; dy++) {
for (int dx = 0; dx < image_w; dx++) {
uint8_t color = get_image_pixel(dx, dy, image_w, image_h, image, 0);
if (((mode & DRAW_MODE_BLACK_ONLY) && color == 1) || ((mode & DRAW_MODE_WHITE_ONLY) && color == 0)) {
// Skip this pixel if we are not supposed to draw it
continue;
}
if (mode & DRAW_MODE_INVERT) {
color = !color;
}
set_pixel(x + dx, y + dy, color);
}
}
}
// Assumes it's the only thing on these lines, so it does not retain any other
// image that might have been rendered there.
void display_progress_bar(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t percent)
{
// Clear whole line first
display_fill_rect(0, y, SCREEN_WIDTH-1, h, 0);
display_fill_rect(x, y, w, h, 1);
display_fill_rect(x + 2, y + 2, w - 4, h - 4, 0);
display_fill_rect(x + 3, y + 3, (w * percent) / 100 - 6, h - 6, 1);
}
void display_show(void)
{
// Disable IRQs so keypad events don't interrupt display drawing
__disable_irq();
lcd_update(disp_buf, true);
__enable_irq();
#ifndef DEBUG
// Clear the keypad interrupt so that it will retrigger if it had any events while
// interrupts were disabled, else it will hang the controller since it's waiting
// for the previous interrupt to be acknowledged.
keypad_write(KBD_ADDR, KBD_REG_INT_STAT, 0xFF);
#endif /* DEBUG */
}
void display_show_lines(uint16_t y_start, uint16_t y_end)
{
if (y_start >= SCREEN_HEIGHT) {
return;
}
if (y_end >= SCREEN_HEIGHT) {
y_end = SCREEN_HEIGHT - 1;
}
for (uint16_t y=y_start; y<=y_end; y++) {
lcd_prebuffer_line(y, &disp_buf[y * SCREEN_BYTES_PER_LINE], true);
}
lcd_update_line_range(y_start, y_end);
}
void display_clear(uint8_t color)
{
memset(disp_buf, color == 0 ? 0x00 : 0xFF, SCREEN_BYTES_PER_LINE * SCREEN_HEIGHT);
}
void display_init(bool clear)
{
lcd_init(clear);
}
// Clear the memory display and then shutdown
void display_clean_shutdown()
{
display_clear(0);
display_show();
passport_shutdown();
}

4
ports/stm32/boards/Passport/gpio.c → ports/stm32/boards/Passport/common/gpio.c

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
@ -30,7 +30,7 @@ void gpio_init(void)
void passport_reset(void)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, 0);
NVIC_SystemReset();
}
void passport_shutdown(void)

100
ports/stm32/boards/Passport/common/hash.c

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
#include <stdint.h>
@ -14,10 +14,33 @@
#include "utils.h"
#include "fwheader.h"
#include "sha256.h"
#ifndef PASSPORT_COSIGN_TOOL
#include "secrets.h"
#endif
#define UID_LEN (96/8) /* 96 bits (Section 61.1 in STMH753 RM) */
void hash_bl(
uint8_t *bl,
size_t bllen,
uint8_t *hash,
uint8_t hashlen
)
{
SHA256_CTX ctx;
sha256_init(&ctx);
/* Checksum the bootloader */
sha256_update(&ctx, bl, bllen);
sha256_final(&ctx, hash);
/* double SHA256 */
sha256_init(&ctx);
sha256_update(&ctx, hash, hashlen);
sha256_final(&ctx, hash);
}
// This hash is used for the integrity check of the firmware and is not user-facing
void hash_fw(
fw_info_t *hdr,
uint8_t *fw,
@ -30,7 +53,7 @@ void hash_fw(
sha256_init(&ctx);
/* Checksum the header */
// Checksum the info block too
sha256_update(&ctx, (uint8_t *)hdr, sizeof(fw_info_t));
/* Checksum the firmware */
@ -43,6 +66,32 @@ void hash_fw(
sha256_final(&ctx, hash);
}
// User-facing hash includes signatures so user can compare to downloaded file.
// When exclude_hdr is true, only the code part of the firmware is hashed, which
// would allow a user to build the code themselves and compare the hash with what
// is in the Passport.
void hash_fw_user(
uint8_t *fw,
size_t fwlen,
uint8_t *hash,
uint8_t hashlen,
bool exclude_hdr
)
{
SHA256_CTX ctx;
// Skip the whole header if requested
if (exclude_hdr) {
fw += FW_HEADER_SIZE;
fwlen -= FW_HEADER_SIZE;
}
sha256_init(&ctx);
sha256_update(&ctx, fw, fwlen);
sha256_final(&ctx, hash);
}
#ifndef PASSPORT_COSIGN_TOOL
void hash_board(
uint8_t *fw_hash,
@ -71,4 +120,47 @@ void hash_board(
sha256_update(&ctx, hash, hashlen);
sha256_final(&ctx, hash);
}
void get_device_hash(uint8_t *hash)
{
SHA256_CTX ctx;
sha256_init(&ctx);
/* Add SE serial number */
sha256_update(&ctx, rom_secrets->se_serial_number, sizeof(rom_secrets->se_serial_number));
/* One-time pad */
sha256_update(&ctx, rom_secrets->otp_key, sizeof(rom_secrets->otp_key));
/* Pairing secret */
sha256_update(&ctx, rom_secrets->pairing_secret, sizeof(rom_secrets->pairing_secret));
/* Add unique device ID from MCU */
sha256_update(&ctx, (uint8_t *)UID_BASE, UID_LEN);
sha256_final(&ctx, hash);
/* double SHA256 */
sha256_init(&ctx);
sha256_update(&ctx, hash, 32);
sha256_final(&ctx, hash);
}
bool get_serial_number(
char *serial_buf,
uint8_t serial_buf_len
)
{
uint8_t hash[32];
if (serial_buf_len < 20) {
return false;
}
get_device_hash(hash);
// Format as serial number
bytes_to_hex_str(hash, 8, serial_buf, 2, '-');
return true;
}
#endif /* PASSPORT_COSIGN_TOOL */

64
ports/stm32/boards/Passport/keypad-adp-5587.c → ports/stm32/boards/Passport/common/keypad-adp-5587.c

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
@ -8,10 +8,12 @@
#include "stm32h7xx_hal.h"
#include "stm32h7xx_hal_i2c_ex.h"
#include "extint.h"
#include "delay.h"
#include "keypad-adp-5587.h"
#include "modfoundation.h"
#ifndef PASSPORT_BOOTLOADER
#include "extint.h"
#endif /* PASSPORT_BOOTLOADER */
static I2C_HandleTypeDef hi2c;
@ -69,29 +71,31 @@ static int keypad_setup(void)
return 0;
}
void keypad_ISR()
void keypad_ISR(void)
{
int rc;
uint8_t key = 0;
uint8_t key_count = 0;
printf("keypad_ISR() 1\n");
uint8_t loop_count = 0;
while (loop_count < 10)
{
rc = keypad_read(KBD_ADDR, KBD_REG_KEY_EVENTA, &key, 1);
if (rc < 0) {
#ifndef PASSPORT_BOOTLOADER
printf("keypad_ISR() read error\n");
#endif /* PASSPORT_BOOTLOADER */
break;
}
if (key == 0) {
printf("keypad_ISR() no key in queue\n");
#ifndef PASSPORT_BOOTLOADER
// printf("keypad_ISR() no key in queue\n");
#endif /* PASSPORT_BOOTLOADER */
break;
}
ring_buffer_enqueue(&keybuf, key);
printf("key=%d\n", key);
ring_buffer_enqueue(key);
key_count++;
loop_count++;
}
@ -101,9 +105,10 @@ void keypad_ISR()
/* Clear the interrrupt on the keypad controller */
rc = keypad_write(KBD_ADDR, KBD_REG_INT_STAT, 0xFF);
if (rc < 0) {
#ifndef PASSPORT_BOOTLOADER
printf("[%s] I2C problem\n", __func__);
#endif /* PASSPORT_BOOTLOADER */
}
printf("keypad_ISR() 5\n");
}
else
{
@ -112,13 +117,9 @@ void keypad_ISR()
* controller is in a strange state. We'll reset it and reconfigure
* it to get it working again.
*/
printf("keypad_ISR() 2\n");
keypad_reset();
printf("keypad_ISR() 3\n");
keypad_setup();
printf("keypad_ISR() 4\n");
}
printf("keypad_ISR() 6======\n");
}
void keypad_init(void)
@ -127,24 +128,18 @@ void keypad_init(void)
HAL_StatusTypeDef rc;
GPIO_InitTypeDef GPIO_InitStruct = { 0 };
printf("keypad_init(): 1\n");
// Need to specify the size of the ring buffer 128 for a test
ring_buffer_init(&keybuf);
ring_buffer_init();
printf("keypad_init(): 2\n");
__HAL_RCC_GPIOE_CLK_ENABLE();
printf("keypad_init(): 3\n");
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
printf("keypad_init(): 4\n");
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
printf("keypad_init(): 5\n");
__HAL_RCC_I2C2_CLK_ENABLE();
printf("keypad_init(): 6\n");
memset(&GPIO_InitStruct, 0, sizeof(GPIO_InitStruct));
GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_11;
@ -152,21 +147,18 @@ printf("keypad_init(): 6\n");
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C2;
printf("keypad_init(): 7\n");
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
printf("keypad_init(): 8\n");
/* Configure GPIO pin : PB12 */
memset(&GPIO_InitStruct, 0, sizeof(GPIO_InitStruct));
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
printf("keypad_init(): 9\n");
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
printf("keypad_init(): 10\n");
hi2c.Instance = I2C2;
hi2c.Init.Timing = 0x109095DF;
hi2c.Init.Timing = 0x00B03FDB; /* 0x0010061A - 400 KHz @ 64 MHz */
/* 0x00B03FDB - 400 KHz @ 480 MHz */
hi2c.Init.OwnAddress1 = 0;
hi2c.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
@ -174,28 +166,28 @@ printf("keypad_init(): 10\n");
hi2c.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
printf("keypad_init(): 11\n");
rc = HAL_I2C_Init(&hi2c);
if (rc != HAL_OK)
#ifdef PASSPORT_BOOTLOADER
;
#else
printf("[%s-%d] HAL_I2C_Init failed\n", __func__, __LINE__);
printf("keypad_init(): 12\n");
#endif /* PASSPORT_BOOTLOADER */
keypad_reset();
printf("keypad_init(): 13\n");
rcc = keypad_setup();
if (rcc < 0)
#ifdef PASSPORT_BOOTLOADER
;
#else
printf("[%s-%d] keypad_setup() failed\n", __func__, __LINE__);
#endif /* PASSPORT_BOOTLOADER */
/* EXTI interrupt init*/
printf("keypad_init(): 14\n");
mp_uint_t irq_state = disable_irq();
printf("keypad_init(): 15\n");
__disable_irq();
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
printf("keypad_init(): 16\n");
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
printf("keypad_init(): 17\n");
enable_irq(irq_state);
printf("keypad_init(): 18\n");
__enable_irq();
}
int keypad_write(

160
ports/stm32/boards/Passport/common/lcd-sharp-ls018B7dh02.c

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// Screen driver for Sharp LS018B7DH02 monochrome display
@ -6,51 +6,16 @@
#include <stdio.h>
#include <string.h>
#include "lcd-sharp-ls018B7dh02.h"
#include "mpconfigboard.h"
#include "spi.h"
#include "stm32h7xx_hal.h"
Screen screen;
static TIM_HandleTypeDef lcd_refresh_timer_handle;
#include "lcd-sharp-ls018B7dh02.h"
uint8_t busy_pattern[34][288] = {
{0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, },
{0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x00, },
{0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x00, },
{0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x00, },
{0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x00, },
{0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x00, },
{0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x00, },
{0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x00, },
{0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, },
{0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, },
{0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, },
{0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, },
{0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, },
{0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, },
{0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, },
{0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, },
{0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, },
{0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, },
{0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, },
{0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, },
{0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, },
{0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, },
{0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, },
{0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, },
{0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, },
{0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, },
{0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x00, },
{0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x00, },
{0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x00, },
{0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x00, },
{0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x00, },
{0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x00, },
{0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x00, 0x00, },
{0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, }
};
#define LCD_NSS_PIN GPIO_PIN_15 // port A
#define LCD_SPI_SCK GPIO_PIN_5 // port A
#define LCD_SPI_MOSI GPIO_PIN_7 // port A
Screen screen;
static TIM_HandleTypeDef lcd_refresh_timer_handle;
uint8_t header_lookup[] = {
0x80, 0x00,
@ -360,35 +325,61 @@ uint8_t header_lookup[] = {
typedef struct
{
mp_obj_base_t base;
const spi_t* spi;
SPI_HandleTypeDef *spi;
int row;
int column;
} lcd_t;
static lcd_t lcd;
static SPI_HandleTypeDef spi_port;
void lcd_clear(
bool invert)
bool invert
)
{
uint8_t invert_mask = invert ? 0x40 : 0x00;
uint8_t clear_msg[2] = { 0x20 | invert_mask, 0x00 };
HAL_SPI_Transmit(lcd.spi->spi, clear_msg, 2, 1000);
HAL_SPI_Transmit(lcd.spi, clear_msg, 2, 1000);
}
void lcd_init(void)
void lcd_init(bool clear)
{
SPI_InitTypeDef* init;
SPI_InitTypeDef *init;
TIM_MasterConfigTypeDef sMasterConfig = { 0 };
TIM_OC_InitTypeDef sConfigOC = { 0 };
GPIO_InitTypeDef GPIO_InitStruct = { 0 };
lcd.spi = &spi_obj[0];
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_SPI1_CLK_ENABLE();
GPIO_InitStruct.Pin = LCD_NSS_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LCD_SPI_SCK;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LCD_SPI_MOSI;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
lcd.spi = &spi_port;
lcd.spi->Instance = SPI1;
init = &lcd.spi->Init;
// init the SPI bus
init = &lcd.spi->spi->Init;
init->Mode = SPI_MODE_MASTER;
//
@ -408,11 +399,7 @@ void lcd_init(void)
// === These are in the cubeIDE init code but not the MP LCD module make_new init code
init->NSSPMode = SPI_NSS_PULSE_ENABLE;
#if defined(MICROPY_PASSPORT_HW_REV1)
init->NSSPolarity = SPI_NSS_POLARITY_LOW;
#elif defined(MICROPY_PASSPORT_HW_REV2)
init->NSSPolarity = SPI_NSS_POLARITY_HIGH;
#endif // MICROPY_PASSPORT_HW_REV1 or MICROPY_PASSPORT_HW_REV2
init->FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
init->TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
init->RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
@ -422,8 +409,7 @@ void lcd_init(void)
init->MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
init->IOSwap = SPI_IO_SWAP_DISABLE;
// Init the SPI bus. Set the enable NSS pin flag.
spi_init(lcd.spi, true);
HAL_SPI_Init(lcd.spi);
// Code to configure Timer 1 using code similar to the MP LED module PWM timer code.
__TIM1_CLK_ENABLE();
@ -459,10 +445,9 @@ void lcd_init(void)
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
lcd_clear(false);
// Enable screen now that it's clear
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_15, 1);
if (clear) {
lcd_clear(false);
}
// Start timer to refresh the SRAM inside the LCD
HAL_TIM_PWM_Start(&lcd_refresh_timer_handle, TIM_CHANNEL_1);
@ -470,12 +455,15 @@ void lcd_init(void)
void lcd_deinit(void)
{
spi_deinit(lcd.spi);
__HAL_RCC_SPI1_FORCE_RESET();
__HAL_RCC_SPI1_RELEASE_RESET();
__HAL_RCC_SPI1_CLK_DISABLE();
}
void lcd_update(
uint8_t* screen_data,
bool invert)
bool invert
)
{
for (int y = 0; y < SCREEN_HEIGHT; y++) {
// Use lookup table to set header bytes
@ -503,33 +491,37 @@ void lcd_update(
// Write the screen data to the screen all at once -- this is much
// faster than separate writes for each line
HAL_SPI_Transmit(lcd.spi->spi, (uint8_t*)&screen, sizeof(screen), 1000);
HAL_SPI_Transmit(lcd.spi, (uint8_t*)&screen, sizeof(screen), 1000);
}
int busy_pos = 5;
#define BUSY_BAR_HEIGHT 34
int cnt = 0;
void lcd_show_busy_bar() {
if (++cnt % 7 != 0) {
// Used to prepare a screen line for updating with lcd_update_line_range()
void lcd_prebuffer_line(uint16_t y, uint8_t* line_data, bool invert) {
if (y >= SCREEN_HEIGHT) {
return;
}
int busy_bar_start_y = SCREEN_HEIGHT - BUSY_BAR_HEIGHT;
int offset = 0;
for (int y = busy_bar_start_y; y < SCREEN_HEIGHT; y++) {
// Use lookup table to set header bytes
screen.lines[y].header[0] = header_lookup[y * 2];
screen.lines[y].header[1] = header_lookup[y * 2 + 1];
screen.lines[y].header[0] = header_lookup[y * 2];
screen.lines[y].header[1] = header_lookup[y * 2 + 1];
// Copy data bytes for this line
memcpy(screen.lines[y].pixels, &busy_pattern[y - busy_bar_start_y][busy_pos], SCREEN_BYTES_PER_LINE);
offset++;
if (invert) {
// Invert pixels 16 bits at a time.
// This works because our screen width in bytes is divisible by 2 (but not by 4)
uint16_t* psrc = (uint16_t*)line_data;
for (int i = 0; i < SCREEN_BYTES_PER_LINE / 2; i++) {
screen.lines[y].pixels_u16[i] = ~psrc[i];
}
} else {
// Copy data bytes for this line
memcpy(screen.lines[y].pixels, line_data, SCREEN_BYTES_PER_LINE);
}
busy_pos -= 1;
if (busy_pos < 0) {
busy_pos = 5;
}
// Update a subset of lines on the LCD
// This is used for updating progress bars and busy bars without need a full screen redraw.
void lcd_update_line_range(uint16_t y_start, uint16_t y_end) {
if (y_start >= SCREEN_HEIGHT || y_end >= SCREEN_HEIGHT) {
return;
}
// Write the busy bar data all at once
HAL_SPI_Transmit(lcd.spi->spi, (uint8_t*)&screen.lines[busy_bar_start_y], sizeof(ScreenLine) * BUSY_BAR_HEIGHT, 1000);
}
HAL_SPI_Transmit(lcd.spi, (uint8_t*)&screen.lines[y_start], sizeof(ScreenLine) * (y_end - y_start + 1), 1000);
}

845
ports/stm32/boards/Passport/common/passport_fonts.c

@ -0,0 +1,845 @@
// Passport wallet font definitions in C
// Autogenerated by bdf-to-passport.py: DO NOT EDIT
#include "passport_fonts.h"
// Lookup GlyphInfo for a single codepoint or return None
bool glyph_lookup(Font* font, uint8_t cp, GlyphInfo* glyph_info) {
for (int i=0; i<font->num_codepoint_ranges; i++) {
Codepoints* cp_entry = &font->codepoints[i];
if (cp < cp_entry->range_start || cp > cp_entry->range_end-1) {
continue;
}
int offset = cp_entry->bitmap_offsets[cp - cp_entry->range_start];
uint8_t bbox_offset = font->bitmaps[offset];
glyph_info->x = font->bboxes[bbox_offset].x;
glyph_info->y = font->bboxes[bbox_offset].y;
glyph_info->w = font->bboxes[bbox_offset].w;
glyph_info->h = font->bboxes[bbox_offset].h;
glyph_info->advance = font->bboxes[bbox_offset].advance;
glyph_info->bitmap = font->bitmaps + offset + 1;
return true;
}
return false;
}
BBox FontTiny_bboxes[] = {
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 4, 1 },
{ 1, 0, 2, 11, 4, 11 },
{ 1, 7, 5, 4, 6, 4 },
{ 0, 0, 10, 10, 11, 20 },
{ 1, -2, 7, 15, 9, 15 },
{ 1, 0, 11, 11, 13, 22 },
{ 1, 0, 9, 11, 11, 22 },
{ 1, 7, 2, 4, 3, 4 },
{ 1, -3, 4, 14, 5, 14 },
{ 0, -3, 4, 14, 5, 14 },
{ 0, 4, 7, 7, 6, 7 },
{ 1, 2, 6, 6, 9, 6 },
{ 1, -2, 2, 5, 4, 5 },
{ 1, 3, 4, 2, 6, 2 },
{ 1, 0, 2, 2, 4, 2 },
{ 0, -1, 7, 14, 6, 14 },
{ 1, 0, 8, 11, 10, 11 },
{ 0, 0, 4, 11, 5, 11 },
{ 0, 0, 8, 11, 9, 11 },
{ 0, 0, 10, 11, 10, 22 },
{ 0, 0, 9, 11, 9, 22 },
{ 1, 0, 2, 8, 4, 8 },
{ 1, -2, 2, 10, 4, 10 },
{ 1, 2, 7, 7, 9, 7 },
{ 1, 2, 7, 6, 9, 6 },
{ 1, 0, 7, 11, 9, 11 },
{ 0, -3, 15, 14, 15, 28 },
{ 2, 0, 8, 11, 10, 11 },
{ 0, 0, 6, 11, 7, 11 },
{ 1, 0, 12, 11, 14, 22 },
{ 1, 0, 11, 11, 12, 22 },
{ 1, -2, 11, 13, 12, 26 },
{ 1, 0, 8, 11, 9, 11 },
{ 0, 0, 11, 11, 11, 22 },
{ 1, 0, 15, 11, 17, 22 },
{ -1, -2, 7, 14, 6, 14 },
{ 0, -1, 7, 1, 7, 1 },
{ 2, 9, 3, 2, 9, 2 },
{ 1, 0, 7, 8, 9, 8 },
{ 1, 0, 9, 11, 10, 22 },
{ 0, 0, 8, 8, 9, 8 },
{ 1, 0, 8, 8, 10, 8 },
{ 0, 0, 6, 11, 6, 11 },
{ 0, -3, 9, 11, 10, 22 },
{ -2, -3, 5, 14, 4, 14 },
{ 1, 0, 14, 8, 15, 16 },
{ 1, -3, 9, 11, 10, 22 },
{ 0, -3, 11, 11, 10, 22 },
{ 1, 0, 6, 8, 8, 8 },
{ 1, 0, 6, 10, 7, 10 },
{ 0, 0, 9, 8, 9, 16 },
{ 0, 0, 13, 8, 14, 16 },
{ 0, -3, 9, 11, 9, 22 },
{ 1, -3, 4, 14, 6, 14 },
{ 1, -3, 2, 14, 5, 14 },
{ 1, 3, 7, 4, 9, 4 },
{ 1, 0, 7, 9, 9, 9 },
{ 1, 5, 5, 6, 6, 6 },
{ 4, 9, 3, 2, 9, 2 },
{ 1, -3, 8, 11, 10, 11 },
{ 2, 2, 5, 6, 9, 6 },
};
uint16_t FontTiny_codepoints_0[] = { 1,3,15,20,41,57,80,103,108,123,138,146,153,159,162,165,180,192,204,216,228,251,263,286,309,321,344,353,364,372,379,387,399,428,451,474,497,520,532,544,567,579,591,603,615,627,650,662,685,697,724,736,748,760,783,806,829,852,875,887,902,917,932,939,941,944,953,976,985,1008,1017,1029,1052,1064,1076,1091,1103,1115,1132,1141,1150,1173,1196,1205,1214,1225,1234,1251,1268,1277,1300,1309,1324,1339,1354, };
uint16_t FontTiny_codepoints_1[] = { 1359,1369,1376,1383,1386, };
uint16_t FontTiny_codepoints_2[] = { 1398, };
Codepoints FontTiny_codepoints[] = {
{ 32, 127, FontTiny_codepoints_0 },
{ 177, 182, FontTiny_codepoints_1 },
{ 215, 216, FontTiny_codepoints_2 },
};
uint8_t FontTiny_bitmaps[] = {
0xAA, // Dummy first entry
0x01, // $0020 offset = 1
0x00,
0x02, // $0021 offset = 3
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0xC0,0xC0,
0x03, // $0022 offset = 15
0xD8,0xD8,0xD8,0xD8,
0x04, // $0023 offset = 20
0x19,0x80,0x19,0x80,0x7F,0xC0,0x7F,0xC0,0x33,0x00,0x33,0x00,0xFF,0x80,0xFF,0x80,0x66,0x00,0x66,0x00,
0x05, // $0024 offset = 41
0x10,0x10,0x7C,0xFE,0xD2,0xD0,0xF0,0x7C,0x1E,0x16,0x96,0xFE,0x7C,0x10,0x10,
0x06, // $0025 offset = 57
0x60,0x80,0x91,0x80,0x93,0x00,0x93,0x00,0x96,0x00,0x64,0xC0,0x0D,0x20,0x19,0x20,0x11,0x20,0x31,0x20,0x60,0xC0,
0x07, // $0026 offset = 80
0x3C,0x00,0x7E,0x00,0x66,0x00,0x66,0x00,0x3C,0x00,0x79,0x00,0xCD,0x80,0xCD,0x80,0xC7,0x00,0xFF,0x80,0x7D,0x80,
0x08, // $0027 offset = 103
0xC0,0xC0,0xC0,0xC0,
0x09, // $0028 offset = 108
0x30,0x60,0x60,0xE0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xE0,0x60,0x60,0x30,
0x0a, // $0029 offset = 123
0xC0,0x60,0x60,0x70,0x30,0x30,0x30,0x30,0x30,0x30,0x70,0x60,0x60,0xC0,
0x0b, // $002A offset = 138
0x10,0x54,0x38,0xFE,0x38,0x54,0x10,
0x0c, // $002B offset = 146
0x30,0x30,0xFC,0xFC,0x30,0x30,
0x0d, // $002C offset = 153
0xC0,0xC0,0xC0,0x80,0x80,
0x0e, // $002D offset = 159
0xF0,0xF0,
0x0f, // $002E offset = 162
0xC0,0xC0,
0x10, // $002F offset = 165
0x06,0x06,0x0C,0x0C,0x18,0x18,0x18,0x30,0x30,0x30,0x60,0x60,0xC0,0xC0,
0x11, // $0030 offset = 180
0x3C,0x7E,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,0xE7,0x7E,0x3C,
0x12, // $0031 offset = 192
0xF0,0xF0,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
0x13, // $0032 offset = 204
0x3C,0xFE,0x47,0x03,0x07,0x0E,0x1C,0x38,0x70,0xFF,0xFF,
0x13, // $0033 offset = 216
0xFF,0xFF,0x0E,0x0C,0x1C,0x1E,0x07,0x03,0x47,0xFF,0x7C,
0x14, // $0034 offset = 228
0x06,0x00,0x0E,0x00,0x0C,0x00,0x18,0x00,0x38,0x00,0x33,0x00,0x73,0x00,0xFF,0xC0,0xFF,0xC0,0x03,0x00,0x03,0x00,
0x13, // $0035 offset = 251
0x7F,0x7F,0x60,0x60,0x7C,0x7F,0x07,0x03,0x43,0xFF,0x7C,
0x15, // $0036 offset = 263
0x1F,0x00,0x3F,0x00,0x70,0x00,0x60,0x00,0xEE,0x00,0xFF,0x00,0xF3,0x80,0xE1,0x80,0x73,0x80,0x3F,0x00,0x1E,0x00,
0x15, // $0037 offset = 286
0xFF,0x80,0xFF,0x80,0xC3,0x00,0x07,0x00,0x06,0x00,0x0E,0x00,0x0E,0x00,0x0C,0x00,0x1C,0x00,0x18,0x00,0x38,0x00,
0x11, // $0038 offset = 309
0x3C,0x7E,0xC3,0xC3,0x7E,0x7E,0xC3,0xC3,0xC3,0x7E,0x3C,
0x15, // $0039 offset = 321
0x3C,0x00,0x7E,0x00,0xE7,0x00,0xC3,0x00,0xE7,0x80,0x7F,0x80,0x3B,0x80,0x03,0x00,0x07,0x00,0x7E,0x00,0x7C,0x00,
0x16, // $003A offset = 344
0xC0,0xC0,0x00,0x00,0x00,0x00,0xC0,0xC0,
0x17, // $003B offset = 353
0xC0,0xC0,0x00,0x00,0x00,0xC0,0xC0,0xC0,0x80,0x80,
0x18, // $003C offset = 364
0x06,0x1E,0x78,0xC0,0x78,0x1E,0x06,
0x19, // $003D offset = 372
0xFE,0xFE,0x00,0x00,0xFE,0xFE,
0x18, // $003E offset = 379
0xC0,0xF0,0x3C,0x06,0x3C,0xF0,0xC0,
0x1a, // $003F offset = 387
0x78,0xFC,0xC6,0x06,0x0C,0x18,0x30,0x30,0x00,0x30,0x30,
0x1b, // $0040 offset = 399
0x0F,0xE0,0x1C,0x70,0x30,0x18,0x63,0x6C,0x67,0xE4,0xCC,0x66,0xCC,0x66,0xCC,0x66,0xCC,0x64,0x6F,0xFC,0x67,0xB8,0x30,0x00,0x1C,0x60,0x0F,0xC0,
0x07, // $0041 offset = 428
0x08,0x00,0x1C,0x00,0x1C,0x00,0x36,0x00,0x36,0x00,0x63,0x00,0x63,0x00,0x7F,0x00,0xE3,0x80,0xC1,0x80,0xC1,0x80,
0x07, // $0042 offset = 451
0xFE,0x00,0xFF,0x00,0xC3,0x00,0xC3,0x00,0xFE,0x00,0xFF,0x00,0xC3,0x00,0xC3,0x80,0xC3,0x80,0xFF,0x00,0xFE,0x00,
0x07, // $0043 offset = 474
0x1F,0x00,0x7F,0x80,0xE1,0x80,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xE1,0x80,0x7F,0x80,0x1F,0x00,
0x07, // $0044 offset = 497
0xFC,0x00,0xFF,0x00,0xC3,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC3,0x80,0xFF,0x00,0xFC,0x00,
0x1a, // $0045 offset = 520
0xFE,0xFE,0xC0,0xC0,0xFC,0xFC,0xC0,0xC0,0xC0,0xFE,0xFE,
0x1a, // $0046 offset = 532
0xFE,0xFE,0xC0,0xC0,0xC0,0xFC,0xFC,0xC0,0xC0,0xC0,0xC0,
0x07, // $0047 offset = 544
0x1F,0x00,0x7F,0x80,0xE1,0x80,0xC0,0x00,0xC0,0x00,0xC3,0x80,0xC3,0x80,0xC1,0x80,0xE1,0x80,0x7F,0x80,0x1F,0x00,
0x1c, // $0048 offset = 567
0xC3,0xC3,0xC3,0xC3,0xFF,0xFF,0xC3,0xC3,0xC3,0xC3,0xC3,
0x02, // $0049 offset = 579
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
0x1d, // $004A offset = 591
0x7C,0x7C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x4C,0xFC,0x78,
0x11, // $004B offset = 603
0xC3,0xC7,0xCE,0xDC,0xF0,0xF0,0xF8,0xDC,0xCE,0xC7,0xC3,
0x1a, // $004C offset = 615
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xFE,0xFE,
0x1e, // $004D offset = 627
0xC0,0x30,0xE0,0x70,0xF0,0xF0,0xF0,0xF0,0xF9,0xF0,0xD9,0xB0,0xCF,0x30,0xCF,0x30,0xC6,0x30,0xC6,0x30,0xC0,0x30,
0x11, // $004E offset = 650
0xC3,0xC3,0xE3,0xF3,0xFB,0xFB,0xDF,0xCF,0xC7,0xC7,0xC3,
0x1f, // $004F offset = 662
0x1F,0x00,0x3F,0x80,0x60,0xC0,0x60,0xC0,0xC0,0x60,0xC0,0x60,0xC0,0x60,0x60,0xC0,0x60,0xC0,0x3F,0x80,0x1F,0x00,
0x11, // $0050 offset = 685
0xFC,0xFE,0xC7,0xC3,0xC3,0xC7,0xFE,0xFC,0xC0,0xC0,0xC0,
0x20, // $0051 offset = 697
0x1F,0x00,0x3F,0x80,0x71,0xC0,0x60,0xC0,0xC0,0x60,0xC0,0x60,0xC0,0x60,0x60,0xC0,0x71,0xC0,0x3F,0x80,0x1E,0x00,0x07,0xE0,0x03,0xC0,
0x11, // $0052 offset = 724
0xFC,0xFE,0xC7,0xC3,0xC3,0xC7,0xFE,0xFC,0xCE,0xC6,0xC7,
0x21, // $0053 offset = 736
0x7C,0xFE,0xC2,0xC0,0xE0,0x7C,0x3E,0x03,0x83,0xFE,0x7C,
0x11, // $0054 offset = 748
0xFF,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
0x07, // $0055 offset = 760
0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xE3,0x80,0x7F,0x00,0x3E,0x00,
0x22, // $0056 offset = 783
0xC0,0x60,0xC0,0x60,0x60,0xC0,0x60,0xC0,0x31,0x80,0x31,0x80,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x0E,0x00,0x0E,0x00,
0x23, // $0057 offset = 806
0xC1,0x06,0xC3,0x86,0xC3,0x86,0xE6,0xCE,0x66,0xCC,0x66,0xCC,0x76,0xDC,0x36,0xD8,0x3C,0x78,0x3C,0x78,0x18,0x30,
0x14, // $0058 offset = 829
0xE1,0xC0,0x73,0x80,0x33,0x00,0x1F,0x00,0x1E,0x00,0x0C,0x00,0x1E,0x00,0x3F,0x00,0x33,0x00,0x73,0x80,0xE1,0xC0,
0x14, // $0059 offset = 852
0xE1,0xC0,0x61,0x80,0x73,0x80,0x33,0x00,0x3F,0x00,0x1E,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,
0x11, // $005A offset = 875
0xFF,0xFF,0x06,0x0E,0x1C,0x18,0x38,0x70,0x60,0xFF,0xFF,
0x09, // $005B offset = 887
0xF0,0xF0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xF0,0xF0,
0x24, // $005C offset = 902
0xC0,0xC0,0x60,0x60,0x30,0x30,0x30,0x18,0x18,0x18,0x0C,0x0C,0x06,0x06,
0x0a, // $005D offset = 917
0xF0,0xF0,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0xF0,0xF0,
0x19, // $005E offset = 932
0x10,0x38,0x6C,0x6C,0xC6,0xC6,
0x25, // $005F offset = 939
0xFE,
0x26, // $0060 offset = 941
0xC0,0x60,
0x27, // $0061 offset = 944
0x7C,0xFE,0x06,0x7E,0xC6,0xC6,0xFE,0x76,
0x28, // $0062 offset = 953
0xC0,0x00,0xC0,0x00,0xC0,0x00,0xDE,0x00,0xFF,0x00,0xE3,0x00,0xC1,0x80,0xC1,0x80,0xE3,0x00,0xFF,0x00,0xDE,0x00,
0x29, // $0063 offset = 976
0x1E,0x7F,0x62,0xC0,0xC0,0x62,0x7F,0x1E,
0x28, // $0064 offset = 985
0x01,0x80,0x01,0x80,0x01,0x80,0x3D,0x80,0x7F,0x80,0x63,0x80,0xC1,0x80,0xC1,0x80,0x63,0x80,0x7F,0x80,0x3D,0x80,
0x2a, // $0065 offset = 1008
0x3C,0x7E,0xC3,0xC3,0xFE,0xC0,0x7F,0x3E,
0x2b, // $0066 offset = 1017
0x3C,0x7C,0x60,0xFC,0xFC,0x60,0x60,0x60,0x60,0x60,0x60,
0x2c, // $0067 offset = 1029
0x3D,0x80,0x7F,0x80,0x63,0x80,0xC1,0x80,0xC1,0x80,0x63,0x80,0x7F,0x80,0x1D,0x80,0x01,0x80,0x7F,0x00,0x3E,0x00,
0x11, // $0068 offset = 1052
0xC0,0xC0,0xC0,0xDC,0xFE,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,
0x02, // $0069 offset = 1064
0xC0,0xC0,0x00,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
0x2d, // $006A offset = 1076
0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x98,0xF8,0x70,
0x11, // $006B offset = 1091
0xC0,0xC0,0xC0,0xC7,0xCE,0xDC,0xF8,0xFC,0xEE,0xC6,0xC7,
0x02, // $006C offset = 1103
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
0x2e, // $006D offset = 1115
0xDC,0xF0,0xFF,0xF8,0xE7,0x9C,0xC3,0x0C,0xC3,0x0C,0xC3,0x0C,0xC3,0x0C,0xC3,0x0C,
0x2a, // $006E offset = 1132
0xDE,0xFF,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,
0x2a, // $006F offset = 1141
0x3C,0x7E,0xE7,0xC3,0xC3,0xE7,0x7E,0x3C,
0x2f, // $0070 offset = 1150
0xDE,0x00,0xFF,0x00,0xE3,0x00,0xC1,0x80,0xC1,0x80,0xE3,0x00,0xFF,0x00,0xDE,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,
0x30, // $0071 offset = 1173
0x3D,0x80,0x7F,0x80,0x63,0x80,0xC1,0x80,0xC1,0x80,0x63,0x80,0x7F,0x80,0x3D,0x80,0x01,0x80,0x01,0xE0,0x01,0xC0,
0x31, // $0072 offset = 1196
0xD8,0xFC,0xE4,0xC0,0xC0,0xC0,0xC0,0xC0,
0x31, // $0073 offset = 1205
0x7C,0xFC,0xC0,0xF0,0x7C,0x0C,0xFC,0xF8,
0x32, // $0074 offset = 1214
0x30,0x30,0xFC,0xFC,0x30,0x30,0x30,0x30,0x3C,0x1C,
0x2a, // $0075 offset = 1225
0xC3,0xC3,0xC3,0xC3,0xC3,0xE7,0xFF,0x7B,
0x33, // $0076 offset = 1234
0xC1,0x80,0xE3,0x80,0x63,0x00,0x77,0x00,0x36,0x00,0x3E,0x00,0x1C,0x00,0x1C,0x00,
0x34, // $0077 offset = 1251
0xC2,0x18,0xC7,0x18,0xC7,0x18,0x67,0x30,0x6D,0xB0,0x3D,0xE0,0x3D,0xE0,0x18,0xC0,
0x27, // $0078 offset = 1268
0xC6,0x6C,0x7C,0x38,0x38,0x7C,0x6C,0xC6,
0x35, // $0079 offset = 1277
0xC1,0x80,0xE3,0x00,0x63,0x00,0x76,0x00,0x36,0x00,0x3E,0x00,0x1C,0x00,0x1C,0x00,0x18,0x00,0xF8,0x00,0xF0,0x00,
0x31, // $007A offset = 1300
0xFC,0xFC,0x18,0x38,0x70,0xE0,0xFC,0xFC,
0x36, // $007B offset = 1309
0x30,0x70,0x60,0x60,0x60,0x60,0xC0,0xC0,0x60,0x60,0x60,0x60,0x70,0x30,
0x37, // $007C offset = 1324
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
0x36, // $007D offset = 1339
0xC0,0xE0,0x60,0x60,0x60,0x60,0x30,0x30,0x60,0x60,0x60,0x60,0xE0,0xC0,
0x38, // $007E offset = 1354
0x60,0xF2,0x9E,0x0C,
0x39, // $00B1 offset = 1359
0x30,0x30,0xFE,0xFE,0x30,0x30,0x00,0xFE,0xFE,
0x3a, // $00B2 offset = 1369
0xF0,0x90,0x10,0x30,0xC0,0xF8,
0x3a, // $00B3 offset = 1376
0xF0,0x30,0x70,0x18,0x98,0xF0,
0x3b, // $00B4 offset = 1383
0x60,0xC0,
0x3c, // $00B5 offset = 1386
0xC3,0xC3,0xC3,0xC3,0xC3,0xE7,0xFF,0xFB,0xC0,0xC0,0xC0,
0x3d, // $00D7 offset = 1398
0x88,0xD8,0x70,0x70,0xD8,0x88,
};
Font FontTiny = {
14,
8,
14,
3,
21,
32,
216,
3,
FontTiny_bboxes,
FontTiny_codepoints,
FontTiny_bitmaps,
};
BBox FontSmall_bboxes[] = {
{ 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 5, 0 },
{ 0, 0, 6, 13, 20, 13 },
{ 1, 8, 6, 5, 7, 5 },
{ 0, 0, 13, 13, 13, 26 },
{ 1, -2, 10, 17, 12, 34 },
{ 1, 0, 14, 13, 16, 26 },
{ 1, 0, 11, 13, 13, 26 },
{ 1, 8, 2, 5, 4, 5 },
{ 2, -4, 3, 18, 6, 18 },
{ 1, -4, 3, 18, 6, 18 },
{ 1, 8, 5, 6, 8, 6 },
{ 1, 2, 9, 9, 11, 18 },
{ 1, -3, 2, 5, 4, 5 },
{ 1, 4, 5, 2, 7, 2 },
{ 1, 0, 2, 2, 4, 2 },
{ 0, -2, 8, 18, 7, 18 },
{ 1, 0, 10, 13, 13, 26 },
{ 0, 0, 5, 13, 7, 13 },
{ 1, 0, 9, 13, 11, 26 },
{ 0, 0, 10, 13, 11, 26 },
{ 1, 0, 10, 13, 12, 26 },
{ 0, 0, 11, 13, 12, 26 },
{ 1, 0, 2, 10, 4, 10 },
{ 1, -3, 2, 13, 4, 13 },
{ 1, 3, 9, 8, 11, 16 },
{ 1, 4, 9, 5, 11, 10 },
{ 1, -4, 17, 17, 19, 51 },
{ 0, 0, 14, 13, 14, 26 },
{ 2, 0, 11, 13, 14, 26 },
{ 1, 0, 11, 13, 14, 26 },
{ 2, 0, 13, 13, 15, 26 },
{ 2, 0, 9, 13, 13, 26 },
{ 2, 0, 9, 13, 12, 26 },
{ 1, 0, 12, 13, 14, 26 },
{ 2, 0, 11, 13, 15, 26 },
{ 2, 0, 2, 13, 6, 13 },
{ -1, 0, 9, 13, 10, 26 },
{ 2, 0, 11, 13, 13, 26 },
{ 2, 0, 9, 13, 11, 26 },
{ 2, 0, 14, 13, 18, 26 },
{ 1, -2, 14, 15, 16, 30 },
{ 1, 0, 10, 13, 11, 26 },
{ 1, 0, 19, 13, 21, 39 },
{ 0, 0, 12, 13, 12, 26 },
{ 1, 0, 11, 13, 12, 26 },
{ 2, -4, 4, 18, 6, 18 },
{ -1, -2, 8, 18, 7, 18 },
{ 0, -4, 4, 18, 6, 18 },
{ 2, 3, 7, 8, 11, 8 },
{ 0, -1, 9, 1, 9, 2 },
{ 3, 12, 4, 2, 11, 2 },
{ 1, 0, 9, 10, 11, 20 },
{ 2, 0, 10, 14, 13, 28 },
{ 1, 0, 10, 14, 13, 28 },
{ 1, 0, 10, 10, 11, 20 },
{ 0, 0, 8, 14, 7, 14 },
{ 1, -4, 10, 14, 13, 28 },
{ 2, 0, 9, 14, 13, 28 },
{ 2, 0, 2, 14, 5, 14 },
{ -3, -4, 7, 18, 5, 18 },
{ 2, 0, 9, 14, 12, 28 },
{ 2, 0, 16, 10, 20, 20 },
{ 2, 0, 9, 10, 13, 20 },
{ 1, 0, 10, 10, 12, 20 },
{ 2, -4, 10, 14, 13, 28 },
{ 1, -4, 13, 14, 13, 28 },
{ 2, 0, 6, 10, 8, 10 },
{ 1, 0, 8, 10, 9, 10 },
{ 0, 0, 7, 12, 8, 12 },
{ 0, 0, 11, 10, 10, 20 },
{ 0, 0, 17, 10, 17, 30 },
{ 1, 0, 9, 10, 10, 20 },
{ 0, -4, 11, 14, 10, 28 },
{ 1, 0, 8, 10, 10, 10 },
{ 1, -4, 6, 18, 7, 18 },
{ 2, -4, 2, 18, 6, 18 },
{ 0, -4, 6, 18, 7, 18 },
{ 1, 5, 9, 3, 11, 6 },
{ 1, 0, 9, 12, 11, 24 },
{ 1, 6, 6, 8, 8, 8 },
{ 5, 12, 3, 2, 11, 2 },
{ 2, -4, 9, 14, 13, 28 },
{ 2, 3, 7, 7, 11, 7 },
};
uint16_t FontSmall_codepoints_0[] = { 1,2,16,22,49,84,111,138,144,163,182,189,208,214,217,220,239,266,280,307,334,361,388,415,442,469,496,507,521,538,549,566,593,645,672,699,726,753,780,807,834,861,875,902,929,956,983,1010,1037,1064,1095,1122,1149,1176,1203,1230,1270,1297,1324,1351,1370,1389,1408,1417,1420,1423,1444,1473,1494,1523,1544,1559,1588,1617,1632,1651,1680,1695,1716,1737,1758,1787,1816,1827,1838,1851,1872,1893,1924,1945,1974,1985,2004,2023,2042, };
uint16_t FontSmall_codepoints_1[] = { 2049,2074,2083,2092,2095, };
uint16_t FontSmall_codepoints_2[] = { 2124, };
Codepoints FontSmall_codepoints[] = {
{ 32, 127, FontSmall_codepoints_0 },
{ 177, 182, FontSmall_codepoints_1 },
{ 215, 216, FontSmall_codepoints_2 },
};
uint8_t FontSmall_bitmaps[] = {
0xAA, // Dummy first entry
0x01, // $0020 offset = 1
0x02, // $0021 offset = 2
0xFC,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x00,0x30,0x30,
0x03, // $0022 offset = 16
0xCC,0xCC,0xCC,0xCC,0xCC,
0x04, // $0023 offset = 22
0x0C,0x60,0x0C,0x60,0x0C,0x60,0x0C,0x60,0xFF,0xF8,0x18,0xC0,0x18,0xC0,0x18,0xC0,0xFF,0xF0,0x31,0x80,0x31,0x80,0x31,0x80,0x31,0x80,
0x05, // $0024 offset = 49
0x0C,0x00,0x0C,0x00,0x3F,0x00,0x7F,0x80,0xCC,0x80,0xCC,0x00,0xCC,0x00,0x7C,0x00,0x3F,0x00,0x0F,0x80,0x0C,0xC0,0x0C,0xC0,0x8C,0xC0,0xFF,0x80,0x7F,0x00,0x0C,0x00,0x0C,0x00,
0x06, // $0025 offset = 84
0x78,0x30,0xCC,0x20,0x84,0x40,0x84,0xC0,0x84,0x80,0xCD,0x00,0x7B,0x78,0x06,0xCC,0x04,0x84,0x0C,0x84,0x18,0x84,0x10,0xCC,0x20,0x78,
0x07, // $0026 offset = 111
0x1E,0x00,0x33,0x00,0x61,0x00,0x63,0x00,0x33,0x00,0x1C,0x00,0x3C,0x00,0x66,0x20,0xC3,0x60,0xC1,0xC0,0xC0,0xC0,0x7F,0xE0,0x3E,0x20,
0x08, // $0027 offset = 138
0xC0,0xC0,0xC0,0xC0,0xC0,
0x09, // $0028 offset = 144
0x20,0x60,0x60,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x60,0x60,0x20,
0x0a, // $0029 offset = 163
0x80,0xC0,0xC0,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0xC0,0xC0,0x80,
0x0b, // $002A offset = 182
0x20,0xA8,0x70,0x70,0xA8,0x20,
0x0c, // $002B offset = 189
0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0xFF,0x80,0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,
0x0d, // $002C offset = 208
0xC0,0xC0,0x40,0xC0,0x80,
0x0e, // $002D offset = 214
0xF8,0xF8,
0x0f, // $002E offset = 217
0xC0,0xC0,
0x10, // $002F offset = 220
0x03,0x03,0x06,0x06,0x06,0x0C,0x0C,0x0C,0x18,0x18,0x18,0x30,0x30,0x60,0x60,0x60,0xC0,0xC0,
0x11, // $0030 offset = 239
0x3F,0x00,0x7F,0x80,0xE1,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xE1,0xC0,0x7F,0x80,0x3F,0x00,
0x12, // $0031 offset = 266
0xF8,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
0x13, // $0032 offset = 280
0x7E,0x00,0xFF,0x00,0xC3,0x80,0x01,0x80,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0xFF,0x80,0xFF,0x80,
0x14, // $0033 offset = 307
0x7F,0x80,0x7F,0x80,0x03,0x00,0x07,0x00,0x06,0x00,0x0C,0x00,0x0F,0x80,0x01,0x80,0x00,0xC0,0x00,0xC0,0xC1,0xC0,0xFF,0x80,0x3F,0x00,
0x07, // $0034 offset = 334
0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x61,0x80,0x61,0x80,0xFF,0xE0,0xFF,0xE0,0x01,0x80,0x01,0x80,0x01,0x80,
0x14, // $0035 offset = 361
0x3F,0x80,0x3F,0x80,0x30,0x00,0x60,0x00,0x60,0x00,0x7F,0x00,0x7F,0x80,0x00,0xC0,0x00,0xC0,0x00,0xC0,0xC0,0xC0,0xFF,0x80,0x3F,0x00,
0x15, // $0036 offset = 388
0x1F,0x80,0x3F,0x80,0x60,0x00,0x40,0x00,0xC0,0x00,0xDF,0x00,0xFF,0x80,0xE1,0xC0,0xC0,0xC0,0xC0,0xC0,0xE1,0xC0,0x7F,0x80,0x1F,0x00,
0x13, // $0037 offset = 415
0xFF,0x80,0xFF,0x80,0x81,0x80,0x81,0x80,0x03,0x00,0x03,0x00,0x06,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x30,0x00,
0x15, // $0038 offset = 442
0x3F,0x00,0x7F,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x61,0x80,0x7F,0x80,0xE1,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x7F,0x80,0x3F,0x00,
0x16, // $0039 offset = 469
0x1F,0x00,0x7F,0x80,0xE1,0xC0,0xC0,0xC0,0xC0,0xC0,0xE1,0xE0,0x7F,0xE0,0x1E,0x60,0x00,0x60,0x00,0xC0,0x01,0xC0,0x3F,0x80,0x3E,0x00,
0x17, // $003A offset = 496
0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,
0x18, // $003B offset = 507
0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0x40,0xC0,0x80,
0x19, // $003C offset = 521
0x01,0x80,0x0F,0x00,0x3C,0x00,0xE0,0x00,0xE0,0x00,0x3C,0x00,0x0F,0x00,0x01,0x80,
0x1a, // $003D offset = 538
0xFF,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x80,
0x19, // $003E offset = 549
0xC0,0x00,0x78,0x00,0x1E,0x00,0x03,0x80,0x03,0x80,0x1E,0x00,0x78,0x00,0xC0,0x00,
0x13, // $003F offset = 566
0x7E,0x00,0xFF,0x00,0xC3,0x80,0x01,0x80,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x18,0x00,0x18,0x00,
0x1b, // $0040 offset = 593
0x07,0xF0,0x00,0x1C,0x1C,0x00,0x30,0x06,0x00,0x60,0x03,0x00,0x43,0xE9,0x80,0xC6,0x38,0x80,0x8C,0x18,0x80,0x88,0x08,0x80,0x88,0x08,0x80,0x88,0x08,0x80,0x8C,0x18,0x80,0xC6,0x3D,0x80,0x43,0xE7,0x00,0x60,0x00,0x00,0x30,0x00,0x00,0x1C,0x18,0x00,0x07,0xF0,0x00,
0x1c, // $0041 offset = 645
0x03,0x00,0x03,0x00,0x07,0x80,0x04,0x80,0x0C,0xC0,0x08,0x40,0x18,0x60,0x18,0x60,0x30,0x30,0x3F,0xF0,0x60,0x18,0x60,0x18,0xC0,0x0C,
0x1d, // $0042 offset = 672
0xFF,0x80,0xFF,0xC0,0xC0,0xC0,0xC0,0x60,0xC0,0xC0,0xFF,0x80,0xFF,0xC0,0xC0,0xE0,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xFF,0xE0,0xFF,0x80,
0x1e, // $0043 offset = 699
0x0F,0xC0,0x3F,0xE0,0x70,0x20,0x60,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0x60,0x00,0x70,0x20,0x3F,0xE0,0x0F,0xC0,
0x1f, // $0044 offset = 726
0xFF,0x00,0xFF,0xC0,0xC0,0xE0,0xC0,0x30,0xC0,0x30,0xC0,0x18,0xC0,0x18,0xC0,0x18,0xC0,0x30,0xC0,0x30,0xC0,0xE0,0xFF,0xC0,0xFF,0x00,
0x20, // $0045 offset = 753
0xFF,0x80,0xFF,0x80,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xFF,0x00,0xFF,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xFF,0x80,0xFF,0x80,
0x21, // $0046 offset = 780
0xFF,0x80,0xFF,0x80,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xFF,0x00,0xFF,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,
0x22, // $0047 offset = 807
0x0F,0xC0,0x3F,0xF0,0x70,0x20,0x60,0x00,0xC0,0x00,0xC0,0x00,0xC0,0xF0,0xC0,0xF0,0xC0,0x30,0x60,0x30,0x70,0x30,0x3F,0xF0,0x0F,0xC0,
0x23, // $0048 offset = 834
0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xFF,0xE0,0xFF,0xE0,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,
0x24, // $0049 offset = 861
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
0x25, // $004A offset = 875
0x3F,0x80,0x3F,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0xC1,0x80,0x7F,0x00,0x3E,0x00,
0x26, // $004B offset = 902
0xC0,0x60,0xC0,0xC0,0xC1,0x80,0xC3,0x00,0xC6,0x00,0xCC,0x00,0xD8,0x00,0xFC,0x00,0xE6,0x00,0xC3,0x00,0xC1,0x80,0xC0,0xC0,0xC0,0x60,
0x27, // $004C offset = 929
0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xFF,0x80,0xFF,0x80,
0x28, // $004D offset = 956
0xC0,0x0C,0xC0,0x0C,0xE0,0x1C,0xF0,0x3C,0xF0,0x3C,0xD8,0x6C,0xC8,0x4C,0xCC,0xCC,0xC7,0x8C,0xC7,0x8C,0xC3,0x0C,0xC0,0x0C,0xC0,0x0C,
0x23, // $004E offset = 983
0xC0,0x60,0xE0,0x60,0xF0,0x60,0xF0,0x60,0xD8,0x60,0xCC,0x60,0xCE,0x60,0xC7,0x60,0xC3,0x60,0xC1,0xE0,0xC0,0xE0,0xC0,0xE0,0xC0,0x60,
0x06, // $004F offset = 1010
0x0F,0xC0,0x3F,0xF0,0x70,0x38,0x60,0x18,0xC0,0x0C,0xC0,0x0C,0xC0,0x0C,0xC0,0x0C,0xC0,0x0C,0x60,0x18,0x70,0x38,0x3F,0xF0,0x0F,0xC0,
0x1d, // $0050 offset = 1037
0xFF,0x00,0xFF,0x80,0xC0,0xC0,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0xC0,0xFF,0x80,0xFF,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,
0x29, // $0051 offset = 1064
0x0F,0xC0,0x3F,0xF0,0x70,0x38,0x60,0x18,0xC0,0x0C,0xC0,0x0C,0xC0,0x0C,0xC0,0x0C,0xC0,0x0C,0x60,0x18,0x70,0x38,0x3F,0xF0,0x0F,0xC0,0x01,0xC4,0x00,0xFC,
0x1d, // $0052 offset = 1095
0xFF,0x00,0xFF,0x80,0xC0,0xC0,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0xC0,0xFF,0x80,0xFF,0x00,0xC3,0x00,0xC1,0x80,0xC0,0xC0,0xC0,0xC0,
0x15, // $0053 offset = 1122
0x3F,0x00,0x7F,0x80,0xC0,0xC0,0xC0,0x00,0xC0,0x00,0x60,0x00,0x3E,0x00,0x0F,0x80,0x01,0xC0,0x00,0xC0,0xC0,0xC0,0xFF,0x80,0x3F,0x00,
0x2a, // $0054 offset = 1149
0xFF,0xC0,0xFF,0xC0,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,
0x23, // $0055 offset = 1176
0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0xC0,0x60,0x60,0xC0,0x7F,0xC0,0x1F,0x00,
0x04, // $0056 offset = 1203
0xC0,0x18,0xC0,0x18,0x60,0x30,0x60,0x30,0x30,0x60,0x30,0x60,0x18,0xC0,0x18,0xC0,0x0D,0x80,0x0D,0x80,0x07,0x00,0x07,0x00,0x02,0x00,
0x2b, // $0057 offset = 1230
0xC0,0x40,0x60,0xC0,0xE0,0x60,0xC0,0xE0,0x60,0x61,0xB0,0xC0,0x61,0xB0,0xC0,0x61,0xB0,0xC0,0x33,0x19,0x80,0x33,0x19,0x80,0x33,0x19,0x80,0x1E,0x0F,0x00,0x1E,0x0F,0x00,0x1E,0x07,0x00,0x0C,0x06,0x00,
0x07, // $0058 offset = 1270
0xC0,0x60,0x60,0xC0,0x31,0x80,0x1B,0x00,0x1B,0x00,0x0E,0x00,0x0E,0x00,0x0E,0x00,0x1B,0x00,0x1B,0x00,0x31,0x80,0x60,0xC0,0xC0,0x60,
0x2c, // $0059 offset = 1297
0xC0,0x30,0x60,0x60,0x60,0x60,0x30,0xC0,0x19,0x80,0x19,0x80,0x0F,0x00,0x07,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,
0x2d, // $005A offset = 1324
0xFF,0xE0,0xFF,0xE0,0x01,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x38,0x00,0x30,0x00,0x60,0x00,0xFF,0xE0,0xFF,0xE0,
0x2e, // $005B offset = 1351
0xF0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xF0,
0x2f, // $005C offset = 1370
0xC0,0xC0,0x60,0x60,0x60,0x30,0x30,0x30,0x18,0x18,0x18,0x0C,0x0C,0x06,0x06,0x06,0x03,0x03,
0x30, // $005D offset = 1389
0xF0,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0xF0,
0x31, // $005E offset = 1408
0x10,0x38,0x28,0x6C,0x44,0xC6,0x82,0x82,
0x32, // $005F offset = 1417
0xFF,0x80,
0x33, // $0060 offset = 1420
0xC0,0x70,
0x34, // $0061 offset = 1423
0x3E,0x00,0xFF,0x00,0x03,0x80,0x01,0x80,0x7F,0x80,0xE3,0x80,0xC1,0x80,0xC3,0x80,0xE7,0x80,0x7D,0x80,
0x35, // $0062 offset = 1444
0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xDE,0x00,0xFF,0x80,0xC1,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC1,0x80,0xFF,0x80,0x9E,0x00,
0x34, // $0063 offset = 1473
0x1E,0x00,0x7F,0x80,0xE1,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xE1,0x00,0x7F,0x80,0x1E,0x00,
0x36, // $0064 offset = 1494
0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x3E,0xC0,0x7F,0xC0,0xE1,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xE1,0xC0,0x7F,0xC0,0x3E,0xC0,
0x37, // $0065 offset = 1523
0x3F,0x00,0x7F,0x80,0xC1,0x80,0xC0,0xC0,0xFF,0xC0,0xC0,0x00,0xC0,0x00,0xE0,0x00,0x7F,0x80,0x1F,0x00,
0x38, // $0066 offset = 1544
0x1E,0x3B,0x30,0x30,0x30,0xFE,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
0x39, // $0067 offset = 1559
0x3E,0xC0,0x7F,0xC0,0xE0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x61,0xC0,0x3F,0xC0,0x1E,0xC0,0x00,0xC0,0x40,0xC0,0xFF,0x80,0x3F,0x00,
0x3a, // $0068 offset = 1588
0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xDE,0x00,0xFF,0x00,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,
0x3b, // $0069 offset = 1617
0xC0,0xC0,0x00,0x00,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
0x3c, // $006A offset = 1632
0x06,0x06,0x00,0x00,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0xC6,0x7C,0x78,
0x3d, // $006B offset = 1651
0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC3,0x00,0xC6,0x00,0xCC,0x00,0xD8,0x00,0xF0,0x00,0xF8,0x00,0xCC,0x00,0xC6,0x00,0xC3,0x00,0xC1,0x80,
0x3b, // $006C offset = 1680
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
0x3e, // $006D offset = 1695
0xDE,0x3C,0xFF,0x7E,0xE1,0xC3,0xC1,0x83,0xC1,0x83,0xC1,0x83,0xC1,0x83,0xC1,0x83,0xC1,0x83,0xC1,0x83,
0x3f, // $006E offset = 1716
0xDE,0x00,0xFF,0x00,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,
0x40, // $006F offset = 1737
0x1E,0x00,0x7F,0x80,0xE1,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xE1,0xC0,0x7F,0x80,0x1E,0x00,
0x41, // $0070 offset = 1758
0xDE,0x00,0xFF,0x80,0xC1,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC1,0x80,0xFF,0x80,0xDE,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,
0x42, // $0071 offset = 1787
0x3E,0xC0,0x7F,0xC0,0xE1,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xE1,0xC0,0x7F,0xC0,0x3E,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xF8,0x00,0xE0,
0x43, // $0072 offset = 1816
0xD8,0xFC,0xE4,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
0x44, // $0073 offset = 1827
0x3E,0x7F,0xC0,0xC0,0x70,0x1E,0x03,0x03,0xFE,0x7C,
0x45, // $0074 offset = 1838
0x30,0x30,0xFE,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3E,0x1E,
0x3f, // $0075 offset = 1851
0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xE3,0x80,0xFF,0x80,0x3D,0x80,
0x46, // $0076 offset = 1872
0xC0,0x60,0x60,0xC0,0x60,0xC0,0x31,0x80,0x31,0x80,0x1B,0x00,0x1B,0x00,0x0E,0x00,0x0E,0x00,0x04,0x00,
0x47, // $0077 offset = 1893
0xC0,0x81,0x80,0x41,0xC1,0x00,0x61,0xC3,0x00,0x63,0x63,0x00,0x23,0x62,0x00,0x32,0x26,0x00,0x16,0x34,0x00,0x1C,0x3C,0x00,0x1C,0x1C,0x00,0x0C,0x18,0x00,
0x48, // $0078 offset = 1924
0xC1,0x80,0x63,0x00,0x36,0x00,0x1C,0x00,0x1C,0x00,0x1C,0x00,0x1C,0x00,0x36,0x00,0x63,0x00,0xC1,0x80,
0x49, // $0079 offset = 1945
0xC0,0x60,0x60,0xC0,0x60,0xC0,0x60,0x80,0x31,0x80,0x33,0x00,0x1B,0x00,0x1A,0x00,0x0E,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0xF8,0x00,0xF0,0x00,
0x4a, // $007A offset = 1974
0xFF,0x03,0x06,0x0C,0x18,0x30,0x30,0x60,0xC0,0xFF,
0x4b, // $007B offset = 1985
0x1C,0x38,0x30,0x30,0x30,0x30,0x30,0x70,0xE0,0x70,0x30,0x30,0x30,0x30,0x30,0x30,0x38,0x1C,
0x4c, // $007C offset = 2004
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
0x4d, // $007D offset = 2023
0xE0,0x70,0x30,0x30,0x30,0x30,0x30,0x38,0x1C,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x70,0xE0,
0x4e, // $007E offset = 2042
0x78,0x80,0xCD,0x80,0x87,0x00,
0x4f, // $00B1 offset = 2049
0x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0xFF,0x80,0x08,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x80,
0x50, // $00B2 offset = 2074
0xF8,0x8C,0x0C,0x08,0x18,0x20,0x40,0xFC,
0x50, // $00B3 offset = 2083
0xFC,0x08,0x10,0x38,0x0C,0x04,0x8C,0xF8,
0x51, // $00B4 offset = 2092
0x60,0xC0,
0x52, // $00B5 offset = 2095
0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC1,0x80,0xC3,0x80,0xFF,0x80,0xFD,0x80,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,
0x53, // $00D7 offset = 2124
0x84,0xCE,0x7C,0x38,0x78,0xEC,0xC4,
};
Font FontSmall = {
18,
10,
18,
4,
28,
32,
216,
3,
FontSmall_bboxes,
FontSmall_codepoints,
FontSmall_bitmaps,
};

4
ports/stm32/boards/Passport/common/pprng.c

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
/*

72
ports/stm32/boards/Passport/common/ring_buffer.c

@ -0,0 +1,72 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
#include <stdio.h>
#include "ring_buffer.h"
static ring_buffer_t keybuf;
/**
* Code adapted from https://github.com/AndersKaloer/Ring-Buffer
*/
int ring_buffer_init(void)
{
keybuf.size = MAX_RING_BUFFER_SIZE;
keybuf.size_plus1 = MAX_RING_BUFFER_SIZE + 1;
keybuf.head_index = 0;
keybuf.tail_index = 0;
return 0;
}
void ring_buffer_enqueue(uint8_t data)
{
if (ring_buffer_is_full()) {
keybuf.tail_index = ((keybuf.tail_index + 1) % keybuf.size_plus1);
}
keybuf.buffer[keybuf.head_index] = data;
keybuf.head_index = ((keybuf.head_index + 1) % keybuf.size_plus1);
}
uint8_t ring_buffer_dequeue(uint8_t* data)
{
if (ring_buffer_is_empty()) {
return 0;
}
*data = keybuf.buffer[keybuf.tail_index];
keybuf.tail_index = ((keybuf.tail_index + 1) % keybuf.size_plus1);
return 1;
}
uint8_t ring_buffer_peek(uint8_t* data, ring_buffer_size_t index)
{
if (index >= ring_buffer_num_items()) {
return 0;
}
ring_buffer_size_t data_index = ((keybuf.tail_index + index) % keybuf.size_plus1);
*data = keybuf.buffer[data_index];
return 1;
}
uint8_t ring_buffer_is_empty(void)
{
uint8_t result = (keybuf.head_index == keybuf.tail_index);
return result;
}
uint8_t ring_buffer_is_full(void)
{
uint8_t num_items = ring_buffer_num_items();
uint8_t result = num_items == keybuf.size;
return result;
}
ring_buffer_size_t ring_buffer_num_items(void)
{
uint8_t result = (keybuf.head_index + keybuf.size_plus1 - keybuf.tail_index) % keybuf.size_plus1;
return result;
}

315
ports/stm32/boards/Passport/common/se.c

@ -1,9 +1,10 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
@ -21,11 +22,11 @@
#include "utils.h"
#ifndef PASSPORT_BOOTLOADER
#include "lcd-sharp-ls018B7dh02.h"
#include "display.h"
#endif /* PASSPORT_BOOTLOADER */
/*
* This bit should be define in the STM32H7 header files but it is not...
* This bit should be defined in the STM32H7 header files but it is not...
* somehow was missed. It is a valid bit in the interrupt status register
* so we'll define it here so as not to mess with the micropython HAL
* installation.
@ -35,8 +36,24 @@
// "one wire" is on PA0 aka. UART4
#define MY_UART UART4
/* SE error codes */
#define SE_SUCCESS 0x00
#define SE_CHECKMAC_MISCOMPARE 0x01
#define SE_PARSE_ERROR 0x03
#define SE_ECC_FAULT 0x05
#define SE_SELF_TEST_ERROR 0x07
#define SE_EXECUTION_ERROR 0x0F
#define SE_WAKE_ACK 0x11
#define SE_WATCHDOG_EXPIRING 0xEE
#define SE_COMMS_ERROR 0xFF
/* SE extended error codes */
#define SE_EX_RETRY_OUT 0xE0
#define STATS(x)
static uint8_t last_error;
uint32_t crc_errors;
uint32_t not_ready_n;
uint32_t short_error;
@ -66,6 +83,38 @@ typedef enum {
IOFLAG_SLEEP = 0xCC,
} ioflag_t;
#ifndef PASSPORT_BOOTLOADER
static char se_error[23];
static char *error_to_str(uint8_t error)
{
switch (error)
{
case SE_SUCCESS: strcpy(se_error, "SE_SUCCESS"); break;
case SE_CHECKMAC_MISCOMPARE: strcpy(se_error, "SE_CHECKMAC_MISCOMPARE"); break;
case SE_PARSE_ERROR: strcpy(se_error, "SE_PARSE_ERROR"); break;
case SE_ECC_FAULT: strcpy(se_error, "SE_ECC_FAULT"); break;
case SE_SELF_TEST_ERROR: strcpy(se_error, "SE_SELF_TEST_ERROR"); break;
case SE_EXECUTION_ERROR: strcpy(se_error, "SE_EXECUTION_ERROR"); break;
case SE_WAKE_ACK: strcpy(se_error, "SE_WAKE_ACK"); break;
case SE_WATCHDOG_EXPIRING: strcpy(se_error, "SE_WATCHDOG_EXPIRING"); break;
case SE_COMMS_ERROR: strcpy(se_error, "SE_COMMS_ERROR"); break;
case SE_EX_RETRY_OUT: strcpy(se_error, "SE_EX_RETRY_OUT"); break;
default: strcpy(se_error, "unknown error"); break;
}
return se_error;
}
#endif /* PASSPORT_BOOTLOADER */
uint8_t se_show_error(void)
{
uint8_t error = last_error;
#ifndef PASSPORT_BOOTLOADER
printf("[%s] last SE error: %s, (%02X)\n", __func__, error_to_str(last_error), last_error);
#endif /* PASSPORT_BOOTLOADER */
last_error = 0;
return error;
}
static inline void _send_byte(uint8_t ch)
{
// reset timeout timer (Systick)
@ -135,11 +184,8 @@ static inline int _read_byte(void)
// "fast" timeout reached, clear flag
++rtof;
MY_UART->ICR = USART_ICR_RTOCF;
return -1;
}
#ifdef FIXME
INCONSISTENT("rxf");
#endif
return -1;
}
@ -271,9 +317,6 @@ void se_write(seopcode_t opcode, uint8_t p1, uint16_t p2, uint8_t *data, uint8_t
.p2_lsb = p2 & 0xff,
.p2_msb = (p2 >> 8) & 0xff,
};
#ifdef FIXME
STATIC_ASSERT(sizeof(known) == 6);
#endif
STATS(last_op = opcode);
STATS(last_p1 = p1);
STATS(last_p2 = p2);
@ -296,16 +339,12 @@ void se_write(seopcode_t opcode, uint8_t p1, uint16_t p2, uint8_t *data, uint8_t
// insert a variable-length body area (sometimes)
if (data_len) {
_send_serialized(data, data_len);
se_crc16_chain(data_len, data, crc);
}
// send final CRC bytes
_send_serialized(crc, 2);
#ifndef PASSPORT_BOOTLOADER
lcd_show_busy_bar();
#endif /* PASSPORT_BOOTLOADER */
}
int se_read(uint8_t *data, uint8_t len)
@ -342,12 +381,14 @@ int se_read(uint8_t *data, uint8_t len)
len_error++;
if (resp_len == 4) {
/* Error code returned */
ERRV(tmp[1], "ae errcode");
ERRV(tmp[1], "se errcode");
len_error_two++;
if (tmp[1] == 0xEE)
wdgtimeout++;
return -1;
last_error = tmp[1];
goto out;
}
ERRV(tmp[0], "wr len");
goto try_again;
@ -356,13 +397,14 @@ int se_read(uint8_t *data, uint8_t len)
if (!check_crc(tmp, actual)) {
ERR("bad crc");
crc_errors++;
last_error = SE_COMMS_ERROR;
goto try_again;
}
}
memcpy(data, tmp + 1, actual - 3);
/*
/*
* Pause the watchdog in case there's more to do
* NOTE: Requires a wake commmand to resume!
*/
@ -374,6 +416,10 @@ try_again:
ln_retry++;
}
retry_out++;
last_error = SE_EX_RETRY_OUT;
out:
se_show_error();
return -1;
}
@ -388,6 +434,51 @@ int se_read1(void)
return data;
}
int se_read_data_slot(int slot_num, uint8_t *data, int len)
{
int rc;
int rval = 0;
#ifdef FIXME
ASSERT((len == 4) || (len == 32) || (len == 72));
#endif
// zone => data
// only reading first block of 32 bytes. ignore the rest
se_write(OP_Read, (len == 4 ? 0x00 : 0x80) | 2, (slot_num<<3), NULL, 0);
rc = se_read(data, (len == 4) ? 4 : 32);
if (rc < 0)
{
rval = -1;
goto out;
}
if (len == 72) {
// read second block
se_write(OP_Read, 0x82, (1<<8) | (slot_num<<3), NULL, 0);
rc = se_read(data+32, 32);
if (rc < 0)
{
rval = -1;
goto out;
}
// read third block, but only using part of it
uint8_t tmp[32];
se_write(OP_Read, 0x82, (2<<8) | (slot_num<<3), NULL, 0);
rc = se_read(tmp, 32);
if (rc < 0)
{
rval = -1;
goto out;
}
memcpy(data+64, tmp, 72-64);
}
out:
se_sleep();
return rval;
}
void se_crc16_chain(uint8_t length, const uint8_t *data, uint8_t crc[2])
{
uint8_t counter;
@ -433,7 +524,7 @@ int se_wake(void)
#ifdef PASSPORT_BOOTLOADER
delay_us(2500);
#else
delay_us(100);
delay_us(1250);
#endif
return 0;
@ -571,7 +662,7 @@ bool se_is_correct_tempkey(
uint8_t resp[32];
int rc;
se_write(OP_MAC, mode, KEYNUM_pairing, NULL, 0);
se_write(OP_MAC, mode, KEYNUM_pairing_secret, NULL, 0);
rc = se_read(resp, 32);
se_sleep();
if (rc < 0)
@ -584,7 +675,7 @@ bool se_is_correct_tempkey(
sha256_update(&ctx, rom_secrets->pairing_secret, 32);
sha256_update(&ctx, expected_tempkey, 32);
const uint8_t fixed[16] = { OP_MAC, mode, KEYNUM_pairing, 0x0,
const uint8_t fixed[16] = { OP_MAC, mode, KEYNUM_pairing_secret, 0x0,
0,0,0,0, 0,0,0,0, // eight zeros
0,0,0, // three zeros
0xEE };
@ -606,7 +697,7 @@ int se_pair_unlock()
int rc;
int attempts = 3;
for (int i = 0; i < attempts; i++) {
rc = se_checkmac(KEYNUM_pairing, rom_secrets->pairing_secret);
rc = se_checkmac(KEYNUM_pairing_secret, rom_secrets->pairing_secret);
if (rc == 0)
return 0;
}
@ -673,7 +764,7 @@ int se_checkmac(
sha256_final(&ctx, req.resp);
memcpy(req.od, od, 13);
// Give our answer to the chip. The 0x01 means that TempKey holds
// Give our answer to the chip. The 0x01 means that TempKey holds
// the second 32 byte value. First 32 byte value is in key slot 1 (pairing secret).
se_write(OP_CheckMac, 0x01, keynum, (uint8_t *)&req, sizeof(req));
rc = se_read1();
@ -715,7 +806,72 @@ int se_checkmac_hard(
return 0;
}
int se_encrypted_write32(
static int se_encrypted_read32(
int data_slot,
int blk,
int read_kn,
const uint8_t *read_key,
uint8_t *data
)
{
int rc;
uint8_t digest[32];
rc = se_pair_unlock();
if (rc < 0)
return -1;
rc = se_gendig_slot(read_kn, read_key, digest);
if (rc < 0)
return -1;
// read nth 32-byte "block"
se_write(OP_Read, 0x82, (blk << 8) | (data_slot<<3), NULL, 0);
rc = se_read(data, 32);
se_sleep();
if (rc < 0)
return -1;
xor_mixin(data, digest, 32);
return 0;
}
int se_encrypted_read(
int data_slot,
int read_kn,
const uint8_t *read_key,
uint8_t *data,
int len
)
{
int rc;
#ifdef FIXME
// not clear if chip supports 4-byte encrypted reads
ASSERT((len == 32) || (len == 72));
#endif
rc = se_encrypted_read32(data_slot, 0, read_kn, read_key, data);
if (rc < 0)
return -1;
if (len == 32)
return 0;
rc = se_encrypted_read32(data_slot, 1, read_kn, read_key, data+32);
if (rc < 0)
return -1;
uint8_t tmp[32];
rc = se_encrypted_read32(data_slot, 2, read_kn, read_key, tmp);
if (rc < 0)
return -1;
memcpy(data+64, tmp, 72-64);
return 0;
}
static int se_encrypted_write32(
int data_slot,
int blk,
int write_kn,
@ -882,3 +1038,112 @@ void se_setup(void)
// finally enable UART
MY_UART->CR1 |= USART_CR1_UE;
}
// Just read a one-way counter.
//
int se_get_counter(uint32_t *result, uint8_t counter_number)
{
int rc;
se_write(OP_Counter, 0x0, counter_number, NULL, 0);
rc = se_read((uint8_t *)result, 4);
se_sleep();
if (rc < 0)
return -1;
// IMPORTANT: Always verify the counter's value because otherwise
// nothing prevents an active MitM changing the value that we think
// we just read.
uint8_t digest[32];
rc = se_gendig_counter(counter_number, *result, digest);
if (rc < 0)
return -1;
if (!se_is_correct_tempkey(digest))
return -1;
return 0;
}
// Add-to and return a one-way counter's value. Have to go up in
// single-unit steps, but can we loop.
//
int se_add_counter(uint32_t *result, uint8_t counter_number, int incr)
{
int rc;
int rval = 0;
for (int i = 0; i < incr; i++) {
se_write(OP_Counter, 0x1, counter_number, NULL, 0);
rc = se_read((uint8_t *)result, 4);
if (rc < 0)
{
rval = -1;
goto out;
}
}
// IMPORTANT: Always verify the counter's value because otherwise
// nothing prevents an active MitM changing the value that we think
// we just read. They could also stop us from incrementing the counter.
uint8_t digest[32];
rc = se_gendig_counter(counter_number, *result, digest);
if (rc < 0)
{
rval = -1;
goto out;
}
if (!se_is_correct_tempkey(digest))
rval = -1;
out:
se_sleep();
return rval;
}
// Construct a digest over one of the two counters. Track what we think
// the digest should be, and ask the chip to do the same. Verify we match
// using MAC command (done elsewhere).
//
int se_gendig_counter(int counter_num, const uint32_t expected_value, uint8_t digest[32])
{
int rc;
uint8_t num_in[20], tempkey[32];
rng_buffer(num_in, sizeof(num_in));
rc = se_pick_nonce(num_in, tempkey);
if (rc < 0)
return -1;
//using Zone=4="Counter" => "KeyID specifies the monotonic counter ID"
se_write(OP_GenDig, 0x4, counter_num, NULL, 0);
rc = se_read1();
se_sleep();
if (rc != 0)
return -1;
// we now have to match the digesting (hashing) that has happened on
// the chip. No feedback at this point if it's right tho.
//
// msg = hkey + b'\x15\x02' + ustruct.pack("<H", slot_num)
// msg += b'\xee\x01\x23' + (b'\0'*25) + challenge
// assert len(msg) == 32+1+1+2+1+2+25+32
//
SHA256_CTX ctx;
sha256_init(&ctx);
uint8_t zeros[32] = { 0 };
uint8_t args[8] = { OP_GenDig, 0x4, counter_num, 0, 0xEE, 0x01, 0x23, 0x0 };
sha256_update(&ctx, zeros, 32);
sha256_update(&ctx, args, sizeof(args));
sha256_update(&ctx, (const uint8_t *)&expected_value, 4);
sha256_update(&ctx, zeros, 20);
sha256_update(&ctx, tempkey, 32);
sha256_final(&ctx, digest);
return 0;
}

4
ports/stm32/boards/Passport/common/spiflash.c

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
/*

96
ports/stm32/boards/Passport/common/utils.c

@ -1,13 +1,14 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
/*
* (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard <coldcardwallet.com>
* and is covered by GPLv3 license found in COPYING.
*/
#include <stdio.h>
#include "utils.h"
// Return T if all bytes are 0xFF
@ -75,3 +76,94 @@ void xor_mixin(uint8_t *acc, uint8_t *more, int len)
*(acc) ^= *(more);
}
}
char hex_map[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F', };
void to_hex(char* buf, uint8_t value) {
buf[0] = hex_map[value >> 4];
buf[1] = hex_map[value & 0xF];
buf[2]=0;
}
// Assumes str is big enough to hold len*2 + 1 bytes
void bytes_to_hex_str(uint8_t* bytes, uint32_t len, char* str, uint32_t split_every, char split_char) {
for (uint32_t i=0; i<len;) {
to_hex((char*)str, bytes[i]);
str += 2;
i++;
if (i % split_every == 0 && i != len) {
str[0] = split_char;
str++;
}
}
*str = 0;
}
#ifndef PASSPORT_BOOTLOADER
void print_hex_buf(char* prefix, uint8_t* buf, int len) {
printf(prefix);
for (int i=0; i<len; i++) {
printf("%02x", buf[i]);
}
putchar('\n');
}
void copy_bytes(uint8_t* dest, int dest_len, uint8_t* src, int src_len) {
for (int i=0; i<src_len; i++) {
if (i < dest_len) {
dest[i] = src[i];
}
}
}
uint32_t getsp(void)
{
register void *sp asm ("sp");
return (uint32_t)sp;
}
void set_stack_sentinel() {
uint32_t* eos = (uint32_t*)MIN_SP + 1;
*eos = EOS_SENTINEL;
}
bool check_stack_sentinel() {
uint32_t* eos = (uint32_t*)MIN_SP + 1;
return *eos == EOS_SENTINEL;
}
int32_t max_diff = 0;
// true if stack is OK, false if not
bool check_stack(char* msg, bool print) {
uint32_t sp = getsp();
int32_t diff = (int32_t)(sp - MIN_SP);
if (diff < 0){
if (-diff > max_diff) {
max_diff = -diff;
}
}
bool sentinel_overwritten = !check_stack_sentinel();
// Only print if there is a problem
if (print) {
printf("%s: (sp=0x%08lx, Diff=%ld, Max Diff=%ld : %s, %s)\n",
msg,
sp,
diff,
max_diff,
sp <= MIN_SP ? "BLOWN!" : "OK",
sentinel_overwritten ? "SENTINEL OVERWRITTEN!" : "OK");
}
return !sentinel_overwritten;
}
#endif /* PASSPORT_BOOTLOADER */

2
ports/stm32/boards/Passport/debug-utils.c

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// Utility functions

2
ports/stm32/boards/Passport/debug-utils.h

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// Utility functions

223
ports/stm32/boards/Passport/dispatch.c

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
/*
@ -44,78 +44,6 @@ static inline void memset4(uint32_t *dest, uint32_t value, uint32_t byte_len)
}
}
// wipe_all_sram()
//
static void wipe_all_sram(void)
{
#ifndef FIXME
return;
#else
const uint32_t noise = 0xdeadbeef;
// wipe all of SRAM (except our own memory, which was already wiped)
memset4((void *)D1_AXISRAM_BASE, noise, D1_AXISRAM_SIZE_MAX);
memset4((void *)SRAM2_BASE, noise, SRAM2_SIZE - BL_SRAM_SIZE);
#endif /* FIXME */
}
// fatal_error(const char *msg)
//
void
fatal_error(const char *msgvoid)
{
#ifdef FIXME
oled_setup();
oled_show(screen_fatal);
#endif
// Maybe should do a reset after a delay, like with
// the watchdog timer or something.
LOCKUP_FOREVER();
}
// fatal_mitm()
//
void fatal_mitm(void)
{
#ifdef FIXME
oled_setup();
oled_show(screen_mitm);
#endif
#ifdef RELEASE
wipe_all_sram();
#endif
printf("====================================!\n");
printf("FATAL MITM ATTACK! LOOPING FOREVER!\n");
printf("====================================!\n");
LOCKUP_FOREVER();
}
static int good_addr(const uint8_t *b, int minlen, int len, bool readonly)
{
uint32_t x = (uint32_t)b;
if (minlen) {
if (!b) return EFAULT; // gave no buffer
if (len < minlen) return ERANGE; // too small
}
if ((x >= D1_AXISRAM_BASE) && ((x - D1_AXISRAM_BASE) < D1_AXISRAM_SIZE_MAX)) {
// inside SRAM1, okay
return 0;
}
if (!readonly) {
return EPERM;
}
#ifdef FIXME
if ((x >= FIRMWARE_START) && (x - FIRMWARE_START) < FW_MAX_LENGTH) {
// inside flash of main firmware (happens for QSTR's)
return 0;
}
#endif /* FIXME */
return EACCES;
}
// se_dispatch()
//
// A C-runtime compatible env. is running, so do some work.
@ -136,7 +64,7 @@ int se_dispatch(
// - range check pointers so we aren't tricked into revealing our secrets
// - check buf_io points to main SRAM, and not into us!
// - range check len_in tightly
// - calling convention only gives me enough for 4 args to this function, so
// - calling convention only gives me enough for 4 args to this function, so
// using read/write in place.
// - use arg2 use when a simple number is needed; never a pointer!
// - mpy may provide a pointer to flash if we give it a qstr or small value, and if
@ -148,149 +76,33 @@ int se_dispatch(
}
// Use these macros
#define REQUIRE_IN_ONLY(x) if ((rv = good_addr(buf_io, (x), len_in, true))) { goto fail; }
#define REQUIRE_OUT(x) if ((rv = good_addr(buf_io, (x), len_in, false))) { goto fail; }
printf("se_dispatch() method_num=%d\n", method_num);
switch(method_num) {
case CMD_GET_BOOTLOADER_VERSION: {
REQUIRE_OUT(64);
// Return my version string
memset(buf_io, 0, len_in);
#ifdef FIXME
strlcpy((char *)buf_io, version_string, len_in);
#else
memcpy(buf_io, version_string, len_in);
#endif
rv = strlen(version_string);
break;
}
#ifdef FIXME
case CMD_GET_FIRMWARE_HASH: {
// Perform SHA256 over ourselves, with 32-bits of salt, to imply we
// haven't stored valid responses.
REQUIRE_OUT(32);
SHA256_CTX ctx;
sha256_init(&ctx);
sha256_update(&ctx, (void *)&arg2, 4);
sha256_update(&ctx, (void *)BL_FLASH_BASE, BL_FLASH_SIZE);
sha256_final(&ctx, buf_io);
break;
}
#endif /* FIXME */
#ifdef FIXME
case CMD_UPGRADE_FIRMWARE: {
const uint8_t *scr;
bool secure = flash_is_security_level2();
// Go into DFU mode. It's a one-way trip.
// Also used to show some "fatal" screens w/ memory wipe.
#define REQUIRE_OUT(x) if (len_in < x) { goto fail; }
switch (arg2) {
default:
case 0: // TODO: define constants once these are understood
// enter DFU for firmware upgrades
if (secure) {
// we cannot support DFU in secure mode anymore
rv = EPERM;
goto fail;
}
scr = screen_dfu;
break;
case 1:
// in case some way for Micropython to detect it.
scr = screen_downgrade;
break;
case 2:
scr = screen_blankish;
break;
case 3:
scr = screen_brick;
secure = true; // no point going into DFU, if even possible
break;
}
// printf("se_dispatch() method_num=%d\n", method_num);
oled_setup();
oled_show(scr);
// Random small delay to make cold-boot stepping attacks harder: 0 - 10,000us
uint32_t us_to_delay = rng_sample() % 10000;
delay_us(us_to_delay);
wipe_all_sram();
if (secure) {
// just die with that message shown; can't start DFU
LOCKUP_FOREVER();
} else {
// Cannot just call enter_dfu() because it doesn't work well
// once Micropython has configured so much stuff in the chip.
// Leave a reminder to ourselves
memcpy(dfu_flag->magic, REBOOT_TO_DFU, sizeof(dfu_flag->magic));
dfu_flag->screen = scr;
// reset system
NVIC_SystemReset();
// NOT-REACHED
}
break;
}
#endif /* FIXME */
case CMD_RESET:
// logout: wipe all of memory and lock up. Must powercycle to recover.
switch (arg2) {
case 0:
case 2:
#ifdef FIXME
oled_show(screen_logout);
#endif /* FIXME */
break;
case 1:
// leave screen untouched
break;
}
wipe_all_sram();
if (arg2 == 2) {
// need some time to show OLED contents
delay_ms(100);
// reboot so we can "login" again
NVIC_SystemReset();
// NOT-REACHED (but ok if it does)
}
// wait for an interrupt which will never happen (ie. sleep)
LOCKUP_FOREVER()
break;
case CMD_IS_BRICKED:
// Are we a brick?
// if the pairing secret doesn't work anymore, that
// means we've been bricked.
// TODO: also report hardware issue, and non-configured states
se_setup();
switch(method_num) {
case CMD_IS_BRICKED:
// If the pairing secret doesn't work anymore, that means we've been bricked.
rv = (se_pair_unlock() != 0);
break;
case CMD_READ_SE_SLOT: {
// Read a dataslot directly. Will fail on
// Read a dataslot directly. Will fail on
// encrypted slots.
if (len_in != 4 && len_in != 32 && len_in != 72) {
rv = ERANGE;
} else {
REQUIRE_OUT(4);
se_setup();
if (se_read_data_slot(arg2 & 0xf, buf_io, len_in)) {
rv = EIO;
}
}
break;
}
@ -339,15 +151,11 @@ int se_dispatch(
case PIN_GET_SECRET:
rv = pin_fetch_secret(args);
break;
case PIN_LONG_SECRET:
rv = pin_long_secret(args);
break;
default:
rv = ENOENT;
break;
}
break;
}
@ -355,11 +163,10 @@ int se_dispatch(
// Read out entire config dataspace
REQUIRE_OUT(128);
se_setup();
rv = se_config_read(buf_io);
if(rv) {
rv = EIO;
}
}
break;
default:
@ -370,11 +177,9 @@ int se_dispatch(
#undef REQUIRE_OUT
fail:
// Precaution: we don't want to leave ATECC508A authorized for any specific keys,
// perhaps due to an error path we didn't see. Always reset the chip.
se_reset_chip();
return rv;
}

29
ports/stm32/boards/Passport/dispatch.h

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
/*
@ -10,47 +10,24 @@
*/
#pragma once
// Go into DFU mode, and certainly clear things.
extern void enter_dfu(void) __attribute__((noreturn));
// Start DFU, or return doing nothing if chip is secure (no DFU possible).
extern void dfu_by_request(void);
/* Temporary declaration for unit-testing */
extern int se_dispatch(int method_num, uint8_t *buf_io, int len_in, uint32_t arg2, uint32_t incoming_sp, uint32_t incoming_lr);
#define CMD_GET_BOOTLOADER_VERSION 0
#define CMD_GET_FIRMWARE_HASH 1
#define CMD_UPGRADE_FIRMWARE 2 // TODO: What is this actually for?
#define CMD_RESET 3
#define CMD_LED_CONTROL 4
#define CMD_IS_BRICKED 5
#define CMD_READ_SE_SLOT 15
#define CMD_GET_ANTI_PHISHING_WORDS 16
#define CMD_GET_RANDOM_BYTES 17
#define CMD_PIN_CONTROL 18
#define CMD_GET_SE_CONFIG 20
#define CMD_FIRMWARE_CONTROL 21
#define CMD_GET_SUPPLY_CHAIN_VALIDATION_WORDS 22
#define CMD_FACTORY_SETUP -1
#define CMD_GET_SUPPLY_CHAIN_VALIDATION_WORDS 21
// Subcommands for CMD_LED_CONTROL
#define LED_READ 0
#define LED_SET_RED 1
#define LED_SET_GREEN 2
#define LED_ATTEMPT_TO_SET_GREEN 3
// Subcommands for CMD_PIN_CONTROL
#define PIN_SETUP 0
#define PIN_ATTEMPT 1
#define PIN_CHANGE 2
#define PIN_GET_SECRET 3
#define PIN_GREENLIGHT_FIRMWARE 4
#define PIN_LONG_SECRET 5
// Subcommands for CMD_FIRMWARE_CONTROL
#define GET_MIN_FIRMWARE_VERSION 0
#define GET_IS_FIRMWARE_DOWNGRADE 1 // May not be used
#define UPDATE_HIGH_WATERMARK 2
#define GET_HIGH_WATERMARK 3 // May not be used

61
ports/stm32/boards/Passport/docs/generic-wallet-export.md

@ -0,0 +1,61 @@
# Export wallet file format (Generic JSON)
Passport can export data intended for various desktop and mobile
wallet systems, but it also supports a file format for general purpose
exports.
It contains master XPUB, XFP for that, and derived values for the top hardened
position of BIP44, BIP84 and BIP49.
# Example JSON file
Here is an example:
```javascript
{
"chain": "XTN",
"xfp": "0F056943",
"xpub": "tpubD6NzVbkrYhZ4XzL5Dhayo67Gorv1YMS7j8pRUvVMd5odC2LBPLAygka9p7748JtSq82FNGPppFEz5xxZUdasBRCqJqXvUHq6xpnsMcYJzeh",
"account": 123,
"bip44": {
"deriv": "m/44'/1'/123'",
"first": "n44vs1Rv7T8SANrg2PFGQhzVkhr5Q6jMMD",
"name": "p2pkh",
"xfp": "B7908B26",
"xpub": "tpubDCiHGUNYdRRGoSH22j8YnruUKgguCK1CC2NFQUf9PApeZh8ewAJJWGMUrhggDNK73iCTanWXv1RN5FYemUH8UrVUBjqDb8WF2VoKmDh9UTo"
},
"bip49": {
"_pub": "upub5DMRSsh6mNak9KbcVjJ7xAgHJvbE3Nx22CBTier5C35kv8j7g2q58ywxskBe6JCcAE2VH86CE2aL4MifJyKbRw8Gj9ay7SWvUBkp2DJ7y52",
"deriv": "m/49'/1'/123'",
"first": "2N87V39riUUCd4vmXfDjMWAu9gUCiBji5jB",
"name": "p2wpkh-p2sh",
"xfp": "CEE1D809",
"xpub": "tpubDCDqt7XXvhAdy1MpSze5nMJA9x8DrdRaKALRRPasfxyHpiqWWEAr9cbDBQ9BcX7cB3up98Pk97U2QQ3xrvQsi5dNPmRYYhdcsKY9wwEY87T"
},
"bip84": {
"_pub": "vpub5Y5a91QvDT45EnXQaKeuvJupVvX8f9BiywDcadSTtaeJ1VgJPPXMitnYsqd9k7GnEqh44FKJ5McJfu6KrihFXhAmvSWgm7BAVVK8Gupu4fL",
"deriv": "m/84'/1'/123'",
"first": "tb1qc58ys2dphtphg6yuugdf3d0kufmk0tye044g3l",
"name": "p2wpkh",
"xfp": "78CF94E5",
"xpub": "tpubDC7jGaaSE66VDB6VhEDFYQSCAyugXmfnMnrMVyHNzW9wryyTxvha7TmfAHd7GRXrr2TaAn2HXn9T8ep4gyNX1bzGiieqcTUNcu2poyntrET"
}
}
```
## Notes
1. The `first` address is formed by added `/0/0` onto the given derivation, and is assumed
to be the first (non-change) receive address for the wallet.
2. The user may specify any value (up to 9999) for the account number, and it's meant to
segregate funds into sub-wallets. Don't assume it's zero.
3. When making your PSBT files to spend these amounts, remember that the XFP of the master
(`0F056943` in this example) is is the root of the subkey paths found in the file, and
you must include the full derivation path from master. So based on this example,
to spend a UTXO on `tb1qc58ys2dphtphg6yuugdf3d0kufmk0tye044g3l`, the input section
of your PSBT would need to specify `(m=0F056943)/84'/1'/123'/0/0`.
4. The `_pub` value is the [SLIP-132](https://github.com/satoshilabs/slips/blob/master/slip-0132.md) style "ypub/zpub/etc" which some systems might want. It implies
a specific address format.

71
ports/stm32/boards/Passport/factory/test_ocd.py

@ -1,71 +0,0 @@
# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
import telnetlib
HOST = "localhost"
tn = telnetlib.Telnet(HOST, 4444)
print("1")
result = tn.expect(['>'], 10)[2]
print("2: result={}".format(result))
tn.write(b"reset halt\r")
print("3")
result = tn.expect(['>'], 10)[2]
print("4: result={}".format(result))
tn.write(b"flash write_image erase build-Passport/firmware0.bin 0x8000000\r")
print("5")
result = tn.expect(['>'], 10)[2]
print("6: result={}".format(result))
tn.write(b"flash write_image erase build-Passport/firmware1.bin 0x8040000\r")
print("7")
result = tn.expect(['>'], 100)[2]
# TODO: This should not need to be here - someone we have to expect the prompt twice.
# TODO: Is it an extra echo character? Or is expect() not consuming the input? Do we also need to read the input?
result = tn.expect(['>'], 100)[2]
print("8: result = {}".format(result))
tn.write(b"reset\r")
print("9")
result = tn.expect(['>'], 10)[2]
result = tn.expect(['>'], 10)[2]
print("10: result = {}".format(result))
tn.write(b"mdb 0x081e0000 20\r")
print("11")
result = tn.expect(["0x081e0000: (.*)\r"])
print("12: result = {}".format(result))
print('Memory at 0x81e0000 = {}'.format(result[1].group(1)))
# In order to readout the public key generated for supply chain validation:
#
# - The initialization code must generate the public key for the device and
# store it at a known address in RAM.
# - The MPU should NOT be configured on initial boot (if SE is blank)
# - The Python script should issue a command like 'mdb 0x01234567 32' and save the
# result somewhere (probably POST to a server with a long cookie for auth).
# At a high level, this script will:
#
# - reset halt
# - Flash the firmware to the device
# - reset
# - Wait x seconds for the basic config to complete
# - Read any necessary information from known SRAM locations
# - Post information to our server
# - reset
#
# Disconnect from telnet
#
# Use some other lib to connect to the GPIO board and start factory test
#
# Numato 32 channel GPIO board over USB serial:
#
# - https://numato.com/product/32-channel-usb-gpio-module-with-analog-inputs/
# - https://github.com/numato/samplecode/blob/master/RelayAndGPIOModules/USBRelayAndGPIOModules/python/usbgpio16_32/gpioread.py
# - https://github.com/numato/samplecode/blob/master/RelayAndGPIOModules/USBRelayAndGPIOModules/python/usbgpio16_32/gpiowrite.py
# - https://github.com/numato/samplecode/blob/master/RelayAndGPIOModules/USBRelayAndGPIOModules/python/usbgpio16_32/analogread.py

142
ports/stm32/boards/Passport/firmware_graphics.c

@ -0,0 +1,142 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
//
// Autogenerated - Do not edit!
//
#include "firmware_graphics.h"
uint8_t busybar1_data[] = {
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x03, 0x80,
0x07, 0xc0,
0x07, 0xc0,
0x07, 0xc0,
0x03, 0x80,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
};
Image busybar1_img = { 15, 15, 2, busybar1_data };
uint8_t busybar2_data[] = {
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x03, 0x80,
0x07, 0xc0,
0x0f, 0xe0,
0x0f, 0xe0,
0x0f, 0xe0,
0x07, 0xc0,
0x03, 0x80,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
};
Image busybar2_img = { 15, 15, 2, busybar2_data };
uint8_t busybar3_data[] = {
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x03, 0x80,
0x07, 0xc0,
0x0f, 0xe0,
0x1f, 0xf0,
0x1f, 0xf0,
0x1f, 0xf0,
0x0f, 0xe0,
0x07, 0xc0,
0x03, 0x80,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
};
Image busybar3_img = { 15, 15, 2, busybar3_data };
uint8_t busybar4_data[] = {
0x00, 0x00,
0x00, 0x00,
0x03, 0x80,
0x0f, 0xe0,
0x1f, 0xf0,
0x1f, 0xf0,
0x3f, 0xf8,
0x3f, 0xf8,
0x3f, 0xf8,
0x1f, 0xf0,
0x1f, 0xf0,
0x0f, 0xe0,
0x03, 0x80,
0x00, 0x00,
0x00, 0x00,
};
Image busybar4_img = { 15, 15, 2, busybar4_data };
uint8_t busybar5_data[] = {
0x00, 0x00,
0x00, 0x00,
0x07, 0xc0,
0x1f, 0xf0,
0x1f, 0xf0,
0x3f, 0xf8,
0x3f, 0xf8,
0x3f, 0xf8,
0x3f, 0xf8,
0x3f, 0xf8,
0x1f, 0xf0,
0x1f, 0xf0,
0x07, 0xc0,
0x00, 0x00,
0x00, 0x00,
};
Image busybar5_img = { 15, 15, 2, busybar5_data };
uint8_t busybar6_data[] = {
0x00, 0x00,
0x0f, 0xe0,
0x1f, 0xf0,
0x3f, 0xf8,
0x7f, 0xfc,
0x7f, 0xfc,
0x7f, 0xfc,
0x7f, 0xfc,
0x7f, 0xfc,
0x7f, 0xfc,
0x7f, 0xfc,
0x3f, 0xf8,
0x1f, 0xf0,
0x0f, 0xe0,
0x00, 0x00,
};
Image busybar6_img = { 15, 15, 2, busybar6_data };
uint8_t busybar7_data[] = {
0x0f, 0xe0,
0x1f, 0xf0,
0x3f, 0xf8,
0x7f, 0xfc,
0xff, 0xfe,
0xff, 0xfe,
0xff, 0xfe,
0xff, 0xfe,
0xff, 0xfe,
0xff, 0xfe,
0xff, 0xfe,
0x7f, 0xfc,
0x3f, 0xf8,
0x1f, 0xf0,
0x0f, 0xe0,
};
Image busybar7_img = { 15, 15, 2, busybar7_data };

23
ports/stm32/boards/Passport/firmware_graphics.h

@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
//
// Autogenerated - Do not edit!
//
#include <stdint.h>
typedef struct _Image {
int16_t width;
int16_t height;
int16_t byte_width;
uint8_t* data;
} Image;
extern Image busybar1_img;
extern Image busybar2_img;
extern Image busybar3_img;
extern Image busybar4_img;
extern Image busybar5_img;
extern Image busybar6_img;
extern Image busybar7_img;

159
ports/stm32/boards/Passport/frequency.c

@ -0,0 +1,159 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
#include <stdio.h>
#include "stm32h7xx_hal.h"
#include "py/mperrno.h"
#include "py/mpstate.h"
#include "py/mphal.h"
#include "uart.h"
#include "backlight.h"
#include "frequency.h"
#include "se.h"
#define LOW_FREQUENCY 64000000
// #define HIGH_FREQUENCY 240000000
#define HIGH_FREQUENCY 480000000
static uint8_t rxbuf[260];
static pyb_uart_obj_t pyb_uart_repl_obj;
void frequency_update_console_uart(void)
{
pyb_uart_repl_obj.base.type = &pyb_uart_type;
pyb_uart_repl_obj.uart_id = MICROPY_HW_UART_REPL;
pyb_uart_repl_obj.is_static = true;
pyb_uart_repl_obj.timeout = 0;
pyb_uart_repl_obj.timeout_char = 2;
uart_init(&pyb_uart_repl_obj, MICROPY_HW_UART_REPL_BAUD, UART_WORDLENGTH_8B, UART_PARITY_NONE, UART_STOPBITS_1, 0);
uart_set_rxbuf(&pyb_uart_repl_obj, sizeof(rxbuf), rxbuf);
MP_STATE_PORT(pyb_stdio_uart) = &pyb_uart_repl_obj;
}
void frequency_turbo(
bool enable
)
{
HAL_StatusTypeDef rc;
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
// printf("[%s] %s\n", __func__, enable ? "true":"false");
// HACK: TEMP - always be in high speed mode
enable = true;
if ((!enable && (SystemCoreClock == LOW_FREQUENCY)) ||
(enable && (SystemCoreClock == HIGH_FREQUENCY)))
return; /* Already at requested frequency...nothing to do */
RCC->CR |= RCC_CR_HSION;
/* Wait till HSI is ready */
while (!(RCC->CR & RCC_CR_HSIRDY));
/* Select HSI clock as main clock */
RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_SW)) | RCC_CFGR_SW_HSI;
/* Reconfigure the clocks based on enable flag:
* 64 MHz core clock if false
* 480 MHz core clock if true
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI48;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
RCC_OscInitStruct.CSIState = RCC_CSI_OFF;
RCC_OscInitStruct.LSEState = RCC_LSE_OFF;
RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.ClockType |= (RCC_CLOCKTYPE_D3PCLK1 | RCC_CLOCKTYPE_D1PCLK1);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC|RCC_PERIPHCLK_USART2
|RCC_PERIPHCLK_RNG|RCC_PERIPHCLK_SPI4
|RCC_PERIPHCLK_SPI1|RCC_PERIPHCLK_SPI2
|RCC_PERIPHCLK_SDMMC|RCC_PERIPHCLK_I2C2
|RCC_PERIPHCLK_ADC|RCC_PERIPHCLK_I2C1
|RCC_PERIPHCLK_I2C4;
PeriphClkInitStruct.PLL2.PLL2M = 1;
PeriphClkInitStruct.PLL2.PLL2N = 18;
PeriphClkInitStruct.PLL2.PLL2P = 1;
PeriphClkInitStruct.PLL2.PLL2Q = 2;
PeriphClkInitStruct.PLL2.PLL2R = 2;
PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_3;
PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOMEDIUM;
PeriphClkInitStruct.PLL2.PLL2FRACN = 6144;
PeriphClkInitStruct.SdmmcClockSelection = RCC_SDMMCCLKSOURCE_PLL;
PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL;
PeriphClkInitStruct.Spi45ClockSelection = RCC_SPI45CLKSOURCE_D2PCLK1;
PeriphClkInitStruct.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_D2PCLK1;
PeriphClkInitStruct.RngClockSelection = RCC_RNGCLKSOURCE_HSI48;
PeriphClkInitStruct.I2c123ClockSelection = RCC_I2C123CLKSOURCE_D2PCLK1;
PeriphClkInitStruct.I2c4ClockSelection = RCC_I2C4CLKSOURCE_D3PCLK1;
PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLL2;
PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
if (!enable)
{
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 32;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 32;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV2;
}
else
{
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 120;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 120;
RCC_OscInitStruct.PLL.PLLR = 2;
// RCC_OscInitStruct.PLL.PLLM = 1;
// RCC_OscInitStruct.PLL.PLLN = 60; // TODO: clock tree
// RCC_OscInitStruct.PLL.PLLP = 2;
// RCC_OscInitStruct.PLL.PLLQ = 60;
// RCC_OscInitStruct.PLL.PLLR = 2;
}
rc = HAL_RCC_OscConfig(&RCC_OscInitStruct);
if (rc != HAL_OK)
printf("[%s] HAL_RCC_OscConfig failed\n", __func__);
rc = HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
if (rc != HAL_OK)
printf("[%s] HAL_RCCEx_PeriphCLKConfig failed\n", __func__);
rc = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
if (rc != HAL_OK)
printf("[%s] HAL_RCC_ClockConfig failed\n", __func__);
/* Adjust the backlight PWM based on the new frequency */
backlight_adjust(enable);
/* Re-initialize the console UART based on the new frequency */
frequency_update_console_uart();
/* Re-initialize the SE UART based on the new frequency */
se_setup();
//printf("%lu, %lu, %lu, %lu, %lu\n", HAL_RCC_GetSysClockFreq(), SystemCoreClock, HAL_RCC_GetHCLKFreq(), HAL_RCC_GetPCLK1Freq(), HAL_RCC_GetPCLK2Freq());
}

13
ports/stm32/boards/Passport/frequency.h

@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
#ifndef __FREQUENCY_H__
#define __FREQUENCY_H__
#include <stdbool.h>
extern void frequency_turbo(bool enable);
extern void frequency_update_console_uart(void);
#endif // __FREQUENCY_H__

5
ports/stm32/boards/Passport/graphics/README

@ -0,0 +1,5 @@
NOTE: The following website is able to convert PNGs to true two-color images:
https://manytools.org/image/colorize-filter/
The py/build.py script requires exactly two color entries or it will fail.

5
ports/stm32/boards/Passport/graphics/c/.gitignore

@ -0,0 +1,5 @@
bootloader_graphics.c
bootloader_graphics.h
firmware_graphics.c
firmware_graphics.h

24
ports/stm32/boards/Passport/graphics/c/Makefile

@ -0,0 +1,24 @@
# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
# SPDX-License-Identifier: GPL-3.0-only
#
# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard <coldcardwallet.com>
# and is covered by GPLv3 license found in COPYING.
all: bootloader_graphics.c firmware_graphics.c
BOOTLOADER_SOURCES = splash.png
bootloader_graphics.c: Makefile $(BOOTLOADER_SOURCES) cbuild.py
python3 cbuild.py bootloader_graphics $(BOOTLOADER_SOURCES)
FIRMWARE_SOURCES = $(wildcard busybar*.png)
firmware_graphics.c: Makefile $(FIRMWARE_SOURCES) cbuild.py
python3 cbuild.py firmware_graphics $(FIRMWARE_SOURCES)
up: all
(cd ../shared; make up)

BIN
ports/stm32/boards/Passport/graphics/c/busybar1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 B

BIN
ports/stm32/boards/Passport/graphics/c/busybar2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 B

BIN
ports/stm32/boards/Passport/graphics/c/busybar3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 B

BIN
ports/stm32/boards/Passport/graphics/c/busybar4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

BIN
ports/stm32/boards/Passport/graphics/c/busybar5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

BIN
ports/stm32/boards/Passport/graphics/c/busybar6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 B

BIN
ports/stm32/boards/Passport/graphics/c/busybar7.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

88
ports/stm32/boards/Passport/graphics/cbuild.py → ports/stm32/boards/Passport/graphics/c/cbuild.py

@ -37,7 +37,7 @@ def read_img(fn):
# fix colour issues: assume minority colour is white (1)
histo = img.histogram()
assert len(histo) == 256, repr(histo)
assert len(set(histo)) == 3, "Too many colours: "+repr(histo)
assert len(set(histo)) == 3, "Too many colors: "+repr(histo)
# if histo[-1] > histo[0]:
img = ImageOps.invert(img)
@ -61,26 +61,56 @@ def crunch(n):
return a[0]
def doit(outfname, fnames):
def gen_header(outfile, fnames):
assert fnames, "need some files"
fp = open(outfname, 'wt')
fp = open('{}.h'.format(outfile_prefix), 'wt')
fp.write("""\
# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
# SPDX-License-Identifier: GPL-3.0-only
#
# autogenerated; don't edit
#
class Graphics:
# (w,h, w_bytes, wbits, data)
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
//
// Autogenerated - Do not edit!
//
#include <stdint.h>
typedef struct _Image {
int16_t width;
int16_t height;
int16_t byte_width;
uint8_t* data;
} Image;
""")
from io import StringIO
for fn in fnames:
varname = fn.split('.')[0].replace('-', '_')
fp.write("extern Image {}_img;\n".format(varname))
def gen_source(outfile_prefix, fnames):
assert fnames, "need some files"
fp = open('{}.c'.format(outfile_prefix), 'wt')
fp.write("""\
// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
//
// Autogenerated - Do not edit!
//
#include "{}.h"
""".format(outfile_prefix))
from io import StringIO
for fn in fnames:
if fn.endswith('.txt'):
@ -100,29 +130,23 @@ class Graphics:
print('w={}, h={} len(raw)={}'.format(w, h, len(raw)))
str.write('{')
str.write(os.linesep)
w_bytes = (w + 7) // 8
for y in range(h):
str.write('{')
for x in range(w//8):
b = raw[(y * w//8) + x]
str.write(' ')
for x in range(w_bytes):
b = raw[(y * w_bytes) + x]
str.write('0x{:02x}{} '.format(b, ',' if x < w-1 else ''))
str.write('},\\n')
str.write('}\\n')
wbits, comp = crunch(raw)
str.write('\n')
str.write('};')
if 0:
# is compression better?
is_comp = len(comp)+8 < len(raw)
else:
# disable; taking too much runtime memory
is_comp = False
print(" %s = (%d, %d, %d, %s, %r)\n" % (varname, w, h, ((w+7)//8),
wbits if is_comp else 0, str.getvalue() if not is_comp else comp), file=fp)
fp.write("uint8_t {}_data[] = {}\n".format(varname, str.getvalue()))
fp.write("Image {}_img = {{ {}, {}, {}, {}_data }};\n\n".format(varname, w, h, (w+7)//8, varname))
print("done: '%s' (%d x %d)" % (varname, w, h))
fp.write("\n# EOF\n")
if 1:
doit('graphics.py', sys.argv[1:])
outfile_prefix = sys.argv[1]
sources = sys.argv[2:].copy()
sources.sort()
gen_header(outfile_prefix, sources)
gen_source(outfile_prefix, sources)

0
ports/stm32/boards/Passport/graphics/splash.png → ports/stm32/boards/Passport/graphics/c/splash.png

Before

Width:  |  Height:  |  Size: 919 B

After

Width:  |  Height:  |  Size: 919 B

67
ports/stm32/boards/Passport/graphics/graphics.py

File diff suppressed because one or more lines are too long

BIN
ports/stm32/boards/Passport/graphics/loading1.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 407 B

6
ports/stm32/boards/Passport/graphics/Makefile → ports/stm32/boards/Passport/graphics/py/Makefile

@ -1,3 +1,9 @@
# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
# SPDX-License-Identifier: GPL-3.0-only
#
# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard <coldcardwallet.com>
# and is covered by GPLv3 license found in COPYING.

0
ports/stm32/boards/Passport/graphics/README.md → ports/stm32/boards/Passport/graphics/py/README.md

0
ports/stm32/boards/Passport/graphics/arrow_down.txt → ports/stm32/boards/Passport/graphics/py/arrow_down.txt

0
ports/stm32/boards/Passport/graphics/arrow_up.txt → ports/stm32/boards/Passport/graphics/py/arrow_up.txt

0
ports/stm32/boards/Passport/graphics/battery_100.png → ports/stm32/boards/Passport/graphics/py/battery_100.png

Before

Width:  |  Height:  |  Size: 115 B

After

Width:  |  Height:  |  Size: 115 B

0
ports/stm32/boards/Passport/graphics/battery_25.png → ports/stm32/boards/Passport/graphics/py/battery_25.png

Before

Width:  |  Height:  |  Size: 120 B

After

Width:  |  Height:  |  Size: 120 B

0
ports/stm32/boards/Passport/graphics/battery_50.png → ports/stm32/boards/Passport/graphics/py/battery_50.png

Before

Width:  |  Height:  |  Size: 117 B

After

Width:  |  Height:  |  Size: 117 B

0
ports/stm32/boards/Passport/graphics/battery_75.png → ports/stm32/boards/Passport/graphics/py/battery_75.png

Before

Width:  |  Height:  |  Size: 117 B

After

Width:  |  Height:  |  Size: 117 B

0
ports/stm32/boards/Passport/graphics/battery_low.png → ports/stm32/boards/Passport/graphics/py/battery_low.png

Before

Width:  |  Height:  |  Size: 119 B

After

Width:  |  Height:  |  Size: 119 B

14
ports/stm32/boards/Passport/graphics/build.py → ports/stm32/boards/Passport/graphics/py/build.py

@ -10,7 +10,7 @@ import zlib
def read_text(fname):
w = 0
rows = []
rows = []
Z = b'\0'
F = b'\xff'
@ -22,7 +22,7 @@ def read_text(fname):
w = max(w, len(r))
rows.append(r)
assert 1 <= w < 220, w
assert 1 <= w < 230, w
raw = b''
for r in rows:
@ -34,13 +34,13 @@ def read_text(fname):
def read_img(fn):
img = Image.open(fn)
w,h = img.size
assert 1 <= w < 220, w
assert 1 <= w < 230, w
img = img.convert('L')
# fix colour issues: assume minority colour is white (1)
histo = img.histogram()
assert len(histo) == 256, repr(histo)
assert len(set(histo)) == 3, "Too many colours: "+repr(histo)
#assert len(set(histo)) == 3, "Too many colors: "+repr(histo)
# if histo[-1] > histo[0]:
img = ImageOps.invert(img)
@ -62,7 +62,7 @@ def crunch(n):
#print(' / '.join("%d => %d" % (wb,len(d)) for wb,d in a))
return a[0]
def doit(outfname, fnames):
@ -71,10 +71,10 @@ def doit(outfname, fnames):
fp = open(outfname, 'wt')
fp.write("""\
# SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
# SPDX-FileCopyrightText: 2021 Foundation Devices, Inc. <hello@foundationdevices.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
# SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
# SPDX-License-Identifier: GPL-3.0-only
#
# autogenerated; don't edit

2
ports/stm32/boards/Passport/graphics/cylon.py → ports/stm32/boards/Passport/graphics/py/cylon.py

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
# SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
# SPDX-License-Identifier: GPL-3.0-only
#
#!/usr/bin/env python3

BIN
ports/stm32/boards/Passport/graphics/py/fcc-ce-logos.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
ports/stm32/boards/Passport/graphics/py/fcc-ce-logos.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

0
ports/stm32/boards/Passport/graphics/fruit.png → ports/stm32/boards/Passport/graphics/py/fruit.png

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

87
ports/stm32/boards/Passport/graphics/py/graphics.py

File diff suppressed because one or more lines are too long

BIN
ports/stm32/boards/Passport/graphics/py/ie_logo.py

Binary file not shown.

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save