mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-23 23:08:14 +00:00
reflash: add new firmware target
Flashes (unlocked) boardloader and bootloader from pre-compiled sdcard image.
This commit is contained in:
parent
09af312789
commit
8b85078730
9
Makefile
9
Makefile
@ -8,6 +8,7 @@ BUILD_DIR = build
|
||||
BOARDLOADER_BUILD_DIR = $(BUILD_DIR)/boardloader
|
||||
BOOTLOADER_BUILD_DIR = $(BUILD_DIR)/bootloader
|
||||
PRODTEST_BUILD_DIR = $(BUILD_DIR)/prodtest
|
||||
REFLASH_BUILD_DIR = $(BUILD_DIR)/reflash
|
||||
FIRMWARE_BUILD_DIR = $(BUILD_DIR)/firmware
|
||||
UNIX_BUILD_DIR = $(BUILD_DIR)/unix
|
||||
|
||||
@ -89,6 +90,11 @@ build_bootloader: ## build bootloader
|
||||
build_prodtest: ## build production test firmware
|
||||
$(SCONS) CFLAGS="$(CFLAGS)" $(PRODTEST_BUILD_DIR)/prodtest.bin
|
||||
|
||||
build_reflash: ## build reflash firmware + reflash image
|
||||
$(SCONS) CFLAGS="$(CFLAGS)" $(REFLASH_BUILD_DIR)/reflash.bin
|
||||
dd if=build/boardloader/boardloader.bin of=$(REFLASH_BUILD_DIR)/sdimage.bin bs=1 seek=0
|
||||
dd if=build/bootloader/bootloader.bin of=$(REFLASH_BUILD_DIR)/sdimage.bin bs=1 seek=49152
|
||||
|
||||
build_firmware: res build_cross ## build firmware with frozen modules
|
||||
$(SCONS) CFLAGS="$(CFLAGS)" $(FIRMWARE_BUILD_DIR)/firmware.bin
|
||||
|
||||
@ -114,6 +120,9 @@ clean_bootloader: ## clean bootloader build
|
||||
clean_prodtest: ## clean prodtest build
|
||||
rm -rf $(PRODTEST_BUILD_DIR)
|
||||
|
||||
clean_reflash: ## clean reflash build
|
||||
rm -rf $(REFLASH_BUILD_DIR)
|
||||
|
||||
clean_firmware: ## clean firmware build
|
||||
rm -rf $(FIRMWARE_BUILD_DIR)
|
||||
|
||||
|
159
SConscript.reflash
Normal file
159
SConscript.reflash
Normal file
@ -0,0 +1,159 @@
|
||||
# pylint: disable=E0602
|
||||
|
||||
import os
|
||||
|
||||
CCFLAGS_MOD = ''
|
||||
CPPPATH_MOD = []
|
||||
CPPDEFINES_MOD = []
|
||||
SOURCE_MOD = []
|
||||
|
||||
# modtrezorui
|
||||
CPPDEFINES_MOD += [
|
||||
'TREZOR_FONT_MONO_DISABLE',
|
||||
'TREZOR_FONT_NORMAL_DISABLE',
|
||||
('QR_MAX_VERSION', '0'),
|
||||
]
|
||||
SOURCE_MOD += [
|
||||
'embed/extmod/modtrezorui/display.c',
|
||||
'embed/extmod/modtrezorui/inflate.c',
|
||||
'embed/extmod/modtrezorui/font_bitmap.c',
|
||||
'embed/extmod/modtrezorui/font_roboto_bold_20.c',
|
||||
'embed/extmod/modtrezorui/trezor-qrenc/qr_encode.c',
|
||||
]
|
||||
|
||||
SOURCE_STMHAL = [
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_can.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dac_ex.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dac.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pcd_ex.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pcd.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rng.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rtc_ex.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rtc.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_sd.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_spi.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_sram.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_fmc.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_sdmmc.c',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c',
|
||||
]
|
||||
|
||||
SOURCE_REFLASH = [
|
||||
'embed/reflash/startup.s',
|
||||
'embed/reflash/header.S',
|
||||
'embed/reflash/main.c',
|
||||
]
|
||||
|
||||
SOURCE_TREZORHAL = [
|
||||
'embed/trezorhal/common.c',
|
||||
'embed/trezorhal/flash.c',
|
||||
'embed/trezorhal/mini_printf.c',
|
||||
'embed/trezorhal/rng.c',
|
||||
'embed/trezorhal/sbu.c',
|
||||
'embed/trezorhal/sdcard.c',
|
||||
'embed/trezorhal/stm32.c',
|
||||
'embed/trezorhal/touch.c',
|
||||
'embed/trezorhal/usb.c',
|
||||
'embed/trezorhal/usbd_conf.c',
|
||||
'embed/trezorhal/usbd_core.c',
|
||||
'embed/trezorhal/usbd_ctlreq.c',
|
||||
'embed/trezorhal/usbd_ioreq.c',
|
||||
'embed/trezorhal/util.s',
|
||||
'embed/trezorhal/vectortable.s',
|
||||
]
|
||||
|
||||
env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')))
|
||||
|
||||
env.Replace(
|
||||
AS='arm-none-eabi-as',
|
||||
AR='arm-none-eabi-ar',
|
||||
CC='arm-none-eabi-gcc',
|
||||
LINK='arm-none-eabi-ld',
|
||||
SIZE='arm-none-eabi-size',
|
||||
STRIP='arm-none-eabi-strip',
|
||||
OBJCOPY='arm-none-eabi-objcopy', )
|
||||
|
||||
env.Replace(
|
||||
CCFLAGS='-Os '
|
||||
'-g3 '
|
||||
'-nostdlib '
|
||||
'-std=gnu99 -Wall -Werror -Wdouble-promotion -Wpointer-arith -fno-common '
|
||||
'-mthumb -mtune=cortex-m4 -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard '
|
||||
'-fsingle-precision-constant -fdata-sections -ffunction-sections '
|
||||
'-fstack-protector-all -ffreestanding '
|
||||
+ CCFLAGS_MOD,
|
||||
CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB',
|
||||
LINKFLAGS='-nostdlib -T embed/reflash/memory.ld --gc-sections -Map=build/reflash/reflash.map --warn-common',
|
||||
CPPPATH=[
|
||||
'embed/reflash',
|
||||
'embed/trezorhal',
|
||||
'embed/extmod/modtrezorui',
|
||||
'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Inc',
|
||||
'vendor/micropython/lib/stm32lib/CMSIS/STM32F4xx/Include',
|
||||
'vendor/micropython/lib/cmsis/inc',
|
||||
'vendor/micropython/ports/stm32',
|
||||
] + CPPPATH_MOD,
|
||||
CPPDEFINES=[
|
||||
'TREZOR_STM32',
|
||||
'MCU_SERIES_F4',
|
||||
'STM32F427xx',
|
||||
('STM32_HAL_H', '"<stm32f4xx_hal.h>"'),
|
||||
] + CPPDEFINES_MOD,
|
||||
ASFLAGS='-mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16',
|
||||
ASPPFLAGS='$CFLAGS $CCFLAGS', )
|
||||
|
||||
env.Replace(
|
||||
BINCTL='tools/binctl',
|
||||
COMBINE_SIGN='tools/combine_sign',
|
||||
)
|
||||
|
||||
#
|
||||
# Program objects
|
||||
#
|
||||
|
||||
obj_program = []
|
||||
obj_program += env.Object(source=SOURCE_MOD)
|
||||
obj_program += env.Object(source=SOURCE_REFLASH)
|
||||
obj_program += env.Object(source=SOURCE_STMHAL)
|
||||
obj_program += env.Object(source=SOURCE_TREZORHAL)
|
||||
|
||||
obj_program.extend(
|
||||
env.Command(
|
||||
target='embed/reflash/vendorheader.o',
|
||||
source='embed/firmware/vendorheader.bin',
|
||||
action='$OBJCOPY -I binary -O elf32-littlearm -B arm'
|
||||
' --rename-section .data=.vendorheader,alloc,load,readonly,contents'
|
||||
' $SOURCE $TARGET', ))
|
||||
|
||||
program_elf = env.Command(
|
||||
target='reflash.elf',
|
||||
source=obj_program,
|
||||
action=
|
||||
'$LINK -o $TARGET $LINKFLAGS $SOURCES `$CC $CFLAGS $CCFLAGS $_CCCOMCOM -print-libgcc-file-name` `$CC $CFLAGS $CCFLAGS $_CCCOMCOM -print-file-name=libc_nano.a`',
|
||||
)
|
||||
|
||||
program_bin = env.Command(
|
||||
target='reflash.bin',
|
||||
source=program_elf,
|
||||
action=[
|
||||
'$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data $SOURCE $TARGET',
|
||||
'$BINCTL $TARGET -h',
|
||||
'dd if=$TARGET of=build/reflash/header.tosign bs=1 count=1024 skip=`wc -c < embed/firmware/vendorheader.bin | tr -d " "`',
|
||||
'$BINCTL $TARGET -s 1:2 `$COMBINE_SIGN firmware build/reflash/header.tosign 4747474747474747474747474747474747474747474747474747474747474747 4848484848484848484848484848484848484848484848484848484848484848`',
|
||||
], )
|
@ -2,6 +2,7 @@
|
||||
|
||||
SConscript('SConscript.boardloader', variant_dir='build/boardloader', duplicate=False)
|
||||
SConscript('SConscript.bootloader', variant_dir='build/bootloader', duplicate=False)
|
||||
SConscript('SConscript.reflash', variant_dir='build/reflash', duplicate=False)
|
||||
SConscript('SConscript.prodtest', variant_dir='build/prodtest', duplicate=False)
|
||||
SConscript('SConscript.firmware', variant_dir='build/firmware', duplicate=False)
|
||||
SConscript('SConscript.unix', variant_dir='build/unix', duplicate=False)
|
||||
|
24
embed/reflash/header.S
Normal file
24
embed/reflash/header.S
Normal file
@ -0,0 +1,24 @@
|
||||
.syntax unified
|
||||
|
||||
#include "version.h"
|
||||
|
||||
.section .header, "a"
|
||||
|
||||
.type g_header, %object
|
||||
.size g_header, .-g_header
|
||||
|
||||
g_header:
|
||||
.byte 'T','R','Z','F' // magic
|
||||
.word g_header_end - g_header // hdrlen
|
||||
.word 0 // expiry
|
||||
.word _codelen // codelen
|
||||
.byte VERSION_MAJOR // vmajor
|
||||
.byte VERSION_MINOR // vminor
|
||||
.byte VERSION_PATCH // vpatch
|
||||
.byte VERSION_BUILD // vbuild
|
||||
. = . + 12 // reserved
|
||||
. = . + 512 // hash1 ... hash16
|
||||
. = . + 415 // reserved
|
||||
.byte 0 // sigmask
|
||||
. = . + 64 // sig
|
||||
g_header_end:
|
100
embed/reflash/main.c
Normal file
100
embed/reflash/main.c
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) Jan Pochyla, SatoshiLabs
|
||||
*
|
||||
* Licensed under TREZOR License
|
||||
* see LICENSE file for details
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "common.h"
|
||||
#include "display.h"
|
||||
#include "flash.h"
|
||||
#include "image.h"
|
||||
#include "rng.h"
|
||||
#include "sbu.h"
|
||||
#include "sdcard.h"
|
||||
#include "secbool.h"
|
||||
#include "touch.h"
|
||||
|
||||
static void progress_callback(int pos, int len)
|
||||
{
|
||||
display_printf(".");
|
||||
}
|
||||
|
||||
static void flash_from_sdcard(uint32_t target, uint32_t source, uint32_t length)
|
||||
{
|
||||
static uint32_t buf[SDCARD_BLOCK_SIZE / sizeof(uint32_t)];
|
||||
|
||||
ensure(
|
||||
sectrue * (source % SDCARD_BLOCK_SIZE == 0),
|
||||
"source not a multiple of block size");
|
||||
ensure(
|
||||
sectrue * (length % SDCARD_BLOCK_SIZE == 0),
|
||||
"length not a multiple of block size");
|
||||
|
||||
for (uint32_t i = 0; i < length / SDCARD_BLOCK_SIZE; i++) {
|
||||
display_printf("read %d\n", (unsigned int)(i + source / SDCARD_BLOCK_SIZE));
|
||||
|
||||
ensure(
|
||||
sdcard_read_blocks(buf, i + source / SDCARD_BLOCK_SIZE, 1),
|
||||
"sdcard_read_blocks");
|
||||
|
||||
for (uint32_t j = 0; j < SDCARD_BLOCK_SIZE / sizeof(uint32_t); j++) {
|
||||
ensure(
|
||||
flash_write_word(target + i * SDCARD_BLOCK_SIZE + j * sizeof(uint32_t), buf[j]),
|
||||
"flash_write_word");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
sdcard_init();
|
||||
touch_init();
|
||||
|
||||
display_orientation(0);
|
||||
display_clear();
|
||||
display_backlight(255);
|
||||
|
||||
ensure(
|
||||
sdcard_is_present(),
|
||||
"sdcard_is_present");
|
||||
|
||||
display_printf("updating boardloader + bootloader\n");
|
||||
|
||||
uint8_t sectors[] = {
|
||||
FLASH_SECTOR_BOARDLOADER_START,
|
||||
1,
|
||||
FLASH_SECTOR_BOARDLOADER_END,
|
||||
FLASH_SECTOR_BOOTLOADER,
|
||||
};
|
||||
display_printf("erasing sectors");
|
||||
ensure(
|
||||
flash_erase_sectors(sectors, sizeof(sectors), progress_callback),
|
||||
"flash_erase_sectors");
|
||||
display_printf("\n");
|
||||
display_printf("erased\n");
|
||||
|
||||
ensure(
|
||||
flash_unlock(),
|
||||
"flash_unlock");
|
||||
|
||||
sdcard_power_on();
|
||||
|
||||
#define BOARDLOADER_SIZE (3 * 16 * 1024)
|
||||
#define BOOTLOADER_SIZE (128 * 1024)
|
||||
|
||||
flash_from_sdcard(BOARDLOADER_START, 0, BOARDLOADER_SIZE);
|
||||
flash_from_sdcard(BOOTLOADER_START, BOARDLOADER_SIZE, BOOTLOADER_SIZE);
|
||||
|
||||
display_printf("done\n");
|
||||
sdcard_power_off();
|
||||
flash_lock();
|
||||
|
||||
return 0;
|
||||
}
|
71
embed/reflash/memory.ld
Normal file
71
embed/reflash/memory.ld
Normal file
@ -0,0 +1,71 @@
|
||||
/* TREZORv2 firmware linker script */
|
||||
|
||||
ENTRY(reset_handler)
|
||||
|
||||
MEMORY {
|
||||
FLASH (rx) : ORIGIN = 0x08040000, LENGTH = 768K
|
||||
CCMRAM (wal) : ORIGIN = 0x10000000, LENGTH = 64K
|
||||
SRAM (wal) : ORIGIN = 0x20000000, LENGTH = 192K
|
||||
}
|
||||
|
||||
main_stack_base = ORIGIN(SRAM) + LENGTH(SRAM); /* 8-byte aligned full descending stack */
|
||||
_estack = main_stack_base;
|
||||
|
||||
/* used by the startup code to populate variables used by the C code */
|
||||
data_lma = LOADADDR(.data);
|
||||
data_vma = ADDR(.data);
|
||||
data_size = SIZEOF(.data);
|
||||
|
||||
/* used by the startup code to wipe memory */
|
||||
ccmram_start = ORIGIN(CCMRAM);
|
||||
ccmram_end = ORIGIN(CCMRAM) + LENGTH(CCMRAM);
|
||||
|
||||
/* used by the startup code to wipe memory */
|
||||
sram_start = ORIGIN(SRAM);
|
||||
sram_end = ORIGIN(SRAM) + LENGTH(SRAM);
|
||||
_ram_start = sram_start;
|
||||
_ram_end = sram_end;
|
||||
|
||||
_codelen = SIZEOF(.flash) + SIZEOF(.data);
|
||||
_flash_start = ORIGIN(FLASH);
|
||||
_flash_end = ORIGIN(FLASH) + LENGTH(FLASH);
|
||||
_heap_start = ADDR(.heap);
|
||||
_heap_end = ADDR(.heap) + SIZEOF(.heap);
|
||||
|
||||
SECTIONS {
|
||||
.vendorheader : ALIGN(4) {
|
||||
KEEP(*(.vendorheader))
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.header : ALIGN(4) {
|
||||
KEEP(*(.header));
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.flash : ALIGN(512) {
|
||||
KEEP(*(.vector_table));
|
||||
. = ALIGN(4);
|
||||
*(.text*);
|
||||
. = ALIGN(4);
|
||||
*(.rodata*);
|
||||
. = ALIGN(512);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.data : ALIGN(4) {
|
||||
*(.data*);
|
||||
. = ALIGN(512);
|
||||
} >SRAM AT>FLASH
|
||||
|
||||
.bss : ALIGN(4) {
|
||||
*(.bss*);
|
||||
. = ALIGN(4);
|
||||
} >SRAM
|
||||
|
||||
.heap : ALIGN(4) {
|
||||
. = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */
|
||||
. = ABSOLUTE(sram_end - 16K); /* this explicitly sets the end of the heap effectively giving the stack at most 16K */
|
||||
} >SRAM
|
||||
|
||||
.stack : ALIGN(8) {
|
||||
. = 4K; /* this acts as a build time assertion that at least this much memory is available for stack use */
|
||||
} >SRAM
|
||||
}
|
41
embed/reflash/startup.s
Normal file
41
embed/reflash/startup.s
Normal file
@ -0,0 +1,41 @@
|
||||
.syntax unified
|
||||
|
||||
.text
|
||||
|
||||
.global reset_handler
|
||||
.type reset_handler, STT_FUNC
|
||||
reset_handler:
|
||||
// setup environment for subsequent stage of code
|
||||
ldr r0, =ccmram_start // r0 - point to beginning of CCMRAM
|
||||
ldr r1, =ccmram_end // r1 - point to byte after the end of CCMRAM
|
||||
ldr r2, =0 // r2 - the word-sized value to be written
|
||||
bl memset_reg
|
||||
|
||||
ldr r0, =sram_start // r0 - point to beginning of SRAM
|
||||
ldr r1, =sram_end // r1 - point to byte after the end of SRAM
|
||||
ldr r2, =0 // r2 - the word-sized value to be written
|
||||
bl memset_reg
|
||||
|
||||
// copy data in from flash
|
||||
ldr r0, =data_vma // dst addr
|
||||
ldr r1, =data_lma // src addr
|
||||
ldr r2, =data_size // size in bytes
|
||||
bl memcpy
|
||||
|
||||
// setup the stack protector (see build script "-fstack-protector-all") with an unpredictable value
|
||||
bl rng_get
|
||||
ldr r1, = __stack_chk_guard
|
||||
str r0, [r1]
|
||||
|
||||
// re-enable exceptions
|
||||
// according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.7:
|
||||
// "If it is not necessary to ensure that a pended interrupt is recognized immediately before
|
||||
// subsequent operations, it is not necessary to insert a memory barrier instruction."
|
||||
cpsie f
|
||||
|
||||
// enter the application code
|
||||
bl main
|
||||
|
||||
b shutdown
|
||||
|
||||
.end
|
4
embed/reflash/version.h
Normal file
4
embed/reflash/version.h
Normal file
@ -0,0 +1,4 @@
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 1
|
||||
#define VERSION_PATCH 0
|
||||
#define VERSION_BUILD 0
|
Loading…
Reference in New Issue
Block a user