[feat] add fw_header
This commit is contained in:
parent
6afed2f349
commit
38dec013f8
@ -3,7 +3,11 @@
|
||||
|
||||
#include "reg.h"
|
||||
|
||||
#define FW_ADDRESS (64 * 1024)
|
||||
#define MAGIC_HEAD (0x64616568) /* ASCII of "head" */
|
||||
|
||||
struct fw_header_s {
|
||||
uint32_t magic;
|
||||
uint32_t size;
|
||||
uint32_t jump_address;
|
||||
/* syspll config */
|
||||
@ -18,10 +22,10 @@ struct fw_header_s {
|
||||
uint8_t usbpll_postdiv2; /* must be in 1~7 */
|
||||
/* system clock div */
|
||||
uint32_t sysclk_div; /* 1~2^24-1 is available */
|
||||
uint8_t regulator_voltage; /* 5~15 is available, Voltage = 0.05 * regulator_voltage + 0.55V */
|
||||
uint8_t resv;
|
||||
/* flash config */
|
||||
uint16_t flash_div; /* 0 is for disable, 2~65534 is available, must be even value */
|
||||
uint16_t flash_resv;
|
||||
uint32_t resv;
|
||||
/* checksum */
|
||||
uint32_t checksum;
|
||||
};
|
||||
|
||||
@ -1 +1,25 @@
|
||||
#include "common.h"
|
||||
|
||||
__attribute__((section(".fw_header"))) struct fw_header_s fw_header = {
|
||||
.magic = MAGIC_HEAD,
|
||||
.size = sizeof(struct fw_header_s),
|
||||
.jump_address = 0x10010000 + sizeof(struct fw_header_s),
|
||||
/* syspll config */
|
||||
.syspll_refdiv = 1, /* must be in 1~63, fref/refdiv must >= 5MHz */
|
||||
.syspll_feedback = 125, /* must be in 16~320, fvco must be in 750MHz~1600MHz */
|
||||
.syspll_postdiv1 = 6, /* must be in 1~7 */
|
||||
.syspll_postdiv2 = 1, /* must be in 1~7 */
|
||||
/* usbpll config */
|
||||
.usbpll_refdiv = 1, /* must be in 1~63, fref/refdiv must >= 5MHz */
|
||||
.usbpll_feedback = 96, /* must be in 16~320, fvco must be in 750MHz~1600MHz */
|
||||
.usbpll_postdiv1 = 4, /* must be in 1~7 */
|
||||
.usbpll_postdiv2 = 2, /* must be in 1~7 */
|
||||
/* system clock div */
|
||||
.sysclk_div = 1, /* 1~2^24-1 is available */
|
||||
.regulator_voltage = 15, /* 5~15 is available, Voltage = 0.05 * regulator_voltage + 0.55V */
|
||||
.resv = 0,
|
||||
/* flash config */
|
||||
.flash_div = 4, /* 0 is for disable, 2~65534 is available, must be even value */
|
||||
/* checksum */
|
||||
.checksum = 0,
|
||||
};
|
||||
|
||||
@ -52,19 +52,20 @@ void __attribute__((section(".text.boot2_pre"))) boot2_copy_self(void)
|
||||
ioqspi_hw->io[1].ctrl = GPIO_OVER_OUT_HIGH;
|
||||
}
|
||||
|
||||
#include "common.h"
|
||||
#include "resets.h"
|
||||
#include "clock.h"
|
||||
#include "uart.h"
|
||||
#include "flash.h"
|
||||
#include "watchdog.h"
|
||||
#include "timer.h"
|
||||
#include "stdio.h"
|
||||
#include "jump.h"
|
||||
|
||||
uint8_t uart_tx_buffer[512];
|
||||
uint8_t uart_rx_buffer[512];
|
||||
uint8_t tx_buffer[512] __attribute__((aligned(4)));
|
||||
uint8_t rx_buffer[512] __attribute__((aligned(4)));
|
||||
|
||||
struct uart_cfg_s uart_cfg = {
|
||||
.baudrate = 2 * 1000 * 1000,
|
||||
.baudrate = 750 * 1000,
|
||||
.mode = UART_MODE_TX_RX,
|
||||
.data_bits = UART_DATABITS_8,
|
||||
.parity = UART_PARITY_NONE,
|
||||
@ -141,7 +142,7 @@ void uart_process(uint16_t code, uint16_t length)
|
||||
uint16_t i;
|
||||
uint32_t v1, v2;
|
||||
|
||||
p = uart_rx_buffer + 8;
|
||||
p = rx_buffer + 8;
|
||||
if ((length > 0) && (length <= 4)) {
|
||||
return;
|
||||
}
|
||||
@ -168,7 +169,7 @@ void uart_process(uint16_t code, uint16_t length)
|
||||
process_return_ok();
|
||||
} else if (code == 0x0003) {
|
||||
process_return_ok();
|
||||
process_flash_read(v1, uart_tx_buffer, v2);
|
||||
process_flash_read(v1, tx_buffer, v2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,10 +188,10 @@ void uart_state_machine(uint8_t id)
|
||||
uart_rx_length = 0;
|
||||
return;
|
||||
}
|
||||
code = ((uint16_t)uart_rx_buffer[0] << 8) | (uint16_t)uart_rx_buffer[1];
|
||||
code_inv = ((uint16_t)uart_rx_buffer[2] << 8) | (uint16_t)uart_rx_buffer[3];
|
||||
length = ((uint16_t)uart_rx_buffer[4] << 8) | (uint16_t)uart_rx_buffer[5];
|
||||
length_inv = ((uint16_t)uart_rx_buffer[6] << 8) | (uint16_t)uart_rx_buffer[7];
|
||||
code = ((uint16_t)rx_buffer[0] << 8) | (uint16_t)rx_buffer[1];
|
||||
code_inv = ((uint16_t)rx_buffer[2] << 8) | (uint16_t)rx_buffer[3];
|
||||
length = ((uint16_t)rx_buffer[4] << 8) | (uint16_t)rx_buffer[5];
|
||||
length_inv = ((uint16_t)rx_buffer[6] << 8) | (uint16_t)rx_buffer[7];
|
||||
if ((code != (uint16_t)~code_inv) || (length != (uint16_t)~length_inv)) {
|
||||
uart_rx_length = 0;
|
||||
return;
|
||||
@ -198,28 +199,23 @@ void uart_state_machine(uint8_t id)
|
||||
uart_process(code, length);
|
||||
uart_rx_length = 0;
|
||||
} else {
|
||||
uart_rx_buffer[uart_rx_length++] = uart0_hw->dr & 0xFF;
|
||||
rx_buffer[uart_rx_length++] = uart0_hw->dr & 0xFF;
|
||||
time_fifo_empty = timer_count_read();
|
||||
if (uart_rx_length >= sizeof(uart_rx_buffer)) {
|
||||
if (uart_rx_length >= sizeof(rx_buffer)) {
|
||||
uart_rx_length = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((naked)) void jump_to_address(uint32_t address) {
|
||||
__asm volatile (
|
||||
"bx %0\n"
|
||||
:
|
||||
: "r" (address)
|
||||
);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
uint32_t boot_pin_low, boot_pin_high;
|
||||
struct fw_header_s *header;
|
||||
|
||||
system_clock_config(SYSTEM_CLOCK_FREQ_120MHZ);
|
||||
clock_ref_set(CLOCK_REF_SRC_XOSC_GLITCHLESS, 1);
|
||||
clock_sys_set(CLOCK_SYS_SRC_REF_GLITCHLESS, 1);
|
||||
clock_peri_set(ENABLE, CLOCK_PERI_SRC_XOSC);
|
||||
|
||||
reset_unreset_blocks_wait(RESETS_BLOCK_IO_BANK0 | RESETS_BLOCK_PADS_BANK0 | RESETS_BLOCK_UART0 | RESETS_BLOCK_TIMER);
|
||||
gpio_init(0, GPIO_FUNC_UART | GPIO_PULL_UP | GPIO_DRIVE_4MA); /* UART_TX pin */
|
||||
@ -239,12 +235,23 @@ int main(void)
|
||||
}
|
||||
}
|
||||
if (boot_pin_high > boot_pin_low) {
|
||||
for (uint32_t i = 0; i < 4; i++) {
|
||||
tx_buffer[i] = 0x55;
|
||||
}
|
||||
uart_write_block(UART_ID_0, tx_buffer, 4);
|
||||
while (1) {
|
||||
uart_state_machine(UART_ID_0);
|
||||
}
|
||||
} else {
|
||||
flash_enter_quad_xip(6);
|
||||
jump_to_address(0x10010000 | 1);
|
||||
flash_read(FW_ADDRESS, rx_buffer, FLASH_READ_SIZE);
|
||||
header = (struct fw_header_s *)rx_buffer;
|
||||
if (jump_check_is_failed(header)) {
|
||||
flash_enter_quad_xip(6);
|
||||
jump_to_address((uint32_t)(uintptr_t *)(FW_ADDRESS | XIP_BASE | 1));
|
||||
} else {
|
||||
jump_pre_config(header);
|
||||
jump_to_address(((struct fw_header_s *)header)->jump_address | 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
file(GLOB FILELIST
|
||||
flash.c
|
||||
jump.c
|
||||
)
|
||||
|
||||
set(TARGET src)
|
||||
|
||||
56
example/boot2/src/jump.c
Normal file
56
example/boot2/src/jump.c
Normal file
@ -0,0 +1,56 @@
|
||||
#include "jump.h"
|
||||
#include "common.h"
|
||||
#include "system.h"
|
||||
#include "clock.h"
|
||||
#include "flash.h"
|
||||
|
||||
int jump_check_is_failed(void *addr)
|
||||
{
|
||||
uint32_t size, sum;
|
||||
uint32_t *p;
|
||||
struct fw_header_s *header;
|
||||
|
||||
header = (struct fw_header_s *)addr;
|
||||
if (header->magic != MAGIC_HEAD) {
|
||||
return -1;
|
||||
}
|
||||
if (header->size != sizeof(struct fw_header_s)) {
|
||||
return -2;
|
||||
}
|
||||
sum = 0;
|
||||
size = header->size;
|
||||
p = (uint32_t *)header;
|
||||
for (uint32_t i = 0; i < size / 4; i++) {
|
||||
sum += p[i];
|
||||
}
|
||||
if (sum != 0xFFFFFFFF) {
|
||||
return -3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void jump_pre_config(void *addr)
|
||||
{
|
||||
struct fw_header_s *header;
|
||||
|
||||
header = (struct fw_header_s *)addr;
|
||||
clock_ref_set(CLOCK_REF_SRC_XOSC_GLITCHLESS, 1);
|
||||
clock_sys_set(CLOCK_SYS_SRC_REF_GLITCHLESS, 1);
|
||||
system_regulator_set(header->regulator_voltage);
|
||||
clock_syspll_init(header->syspll_refdiv, \
|
||||
header->syspll_feedback, \
|
||||
header->syspll_postdiv1, \
|
||||
header->syspll_postdiv2);
|
||||
clock_usbpll_init(header->usbpll_refdiv, \
|
||||
header->usbpll_feedback, \
|
||||
header->usbpll_postdiv1, \
|
||||
header->usbpll_postdiv2);
|
||||
clock_sys_set(CLOCK_SYS_SRC_SYSPLL, header->sysclk_div);
|
||||
clock_peri_set(ENABLE, CLOCK_PERI_SRC_SYSPLL);
|
||||
flash_enter_quad_xip(header->flash_div);
|
||||
}
|
||||
|
||||
void jump_to_address(uint32_t addr)
|
||||
{
|
||||
((void (*)(void))(addr | 1))();
|
||||
}
|
||||
18
example/boot2/src/jump.h
Normal file
18
example/boot2/src/jump.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef __JUMP_H__
|
||||
#define __JUMP_H__
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int jump_check_is_failed(void *addr);
|
||||
void jump_pre_config(void *addr);
|
||||
void jump_to_address(uint32_t addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __JUMP_H__ */
|
||||
11
flash.ld
11
flash.ld
@ -11,7 +11,8 @@ _stack_top_core1 = 0x20041000 + 4 * 1024;
|
||||
|
||||
PHDRS
|
||||
{
|
||||
fw_header PT_LOAD FLAGS(5); /* R + X */
|
||||
fw_header PT_LOAD FLAGS(6); /* R + X */
|
||||
isr_reset PT_LOAD FLAGS(6); /* R + X */
|
||||
text PT_LOAD FLAGS(5); /* R + X */
|
||||
rodata PT_LOAD FLAGS(6); /* R + W */
|
||||
data PT_LOAD FLAGS(6); /* R + W */
|
||||
@ -24,10 +25,16 @@ SECTIONS
|
||||
{
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.fw_header))
|
||||
KEEP(*(.text.isr_reset))
|
||||
. = ALIGN(4);
|
||||
} >FLASH :fw_header
|
||||
|
||||
.isr_reset :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.text.isr_reset))
|
||||
. = ALIGN(4);
|
||||
} >FLASH :isr_reset
|
||||
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
|
||||
@ -23,6 +23,9 @@ LDFLAGS += -Wl,--gc-sections
|
||||
LDFLAGS += -nostartfiles
|
||||
LDFLAGS += -Wl,-Map=$(EXAMPLE_NAME).map
|
||||
LDFLAGS += -Wl,--print-memory-usage
|
||||
ifndef BOOT2_PRE_CRC
|
||||
LDFLAGS += -ufw_header
|
||||
endif
|
||||
|
||||
CMAKE := cmake
|
||||
ELF2UF2 := $(SDK_BASE_DIR)/tools/elf2uf2
|
||||
@ -54,12 +57,19 @@ cmake_definition+= -DEXAMPLE_BASE_DIR=$(EXAMPLE_BASE_DIR)
|
||||
|
||||
FINAL_NAME_PRE := $(EXAMPLE_BASE_DIR)/build/$(EXAMPLE_NAME)
|
||||
|
||||
FW_HEADER_CHECKSUM ?= fw_header_checksum.bin
|
||||
|
||||
post:build
|
||||
ifdef BOOT2_PRE_CRC
|
||||
@$(CROSS_COMPILE)objcopy -O binary --only-section=.boot2_pre $(FINAL_NAME_PRE).elf $(BOOT2_PRE_CRC)
|
||||
@python3 $(SDK_BASE_DIR)/tools/boot2_pre_crc.py $(BOOT2_PRE_CRC)
|
||||
@$(CROSS_COMPILE)objcopy --update-section .boot2_pre=$(BOOT2_PRE_CRC) $(FINAL_NAME_PRE).elf
|
||||
@rm $(BOOT2_PRE_CRC)
|
||||
else
|
||||
@$(CROSS_COMPILE)objcopy -O binary --only-section=.fw_header $(FINAL_NAME_PRE).elf $(FW_HEADER_CHECKSUM)
|
||||
@python3 $(SDK_BASE_DIR)/tools/checksum.py $(FW_HEADER_CHECKSUM)
|
||||
@$(CROSS_COMPILE)objcopy --update-section .fw_header=$(FW_HEADER_CHECKSUM) $(FINAL_NAME_PRE).elf
|
||||
@rm $(FW_HEADER_CHECKSUM)
|
||||
endif
|
||||
@$(CROSS_COMPILE)objcopy -O binary $(FINAL_NAME_PRE).elf $(FINAL_NAME_PRE).bin
|
||||
@$(CROSS_COMPILE)objdump -d -S $(FINAL_NAME_PRE).elf > $(FINAL_NAME_PRE).asm
|
||||
|
||||
73
tools/checksum.py
Normal file
73
tools/checksum.py
Normal file
@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
|
||||
def calculate_checksum(data):
|
||||
"""计算小端序校验和:每4字节相加后取反(32位无符号)"""
|
||||
if len(data) % 4 != 0:
|
||||
raise ValueError("Data length must be multiple of 4")
|
||||
|
||||
sum_val = 0
|
||||
# 遍历所有4字节块(最后4字节除外)
|
||||
for i in range(0, len(data)-4, 4):
|
||||
chunk = data[i:i+4]
|
||||
value = struct.unpack('<I', chunk)[0] # 小端序解析
|
||||
sum_val = (sum_val + value) & 0xFFFFFFFF # 32位溢出保护
|
||||
|
||||
return (~sum_val) & 0xFFFFFFFF # 取反并保持32位
|
||||
|
||||
def process_file(filename):
|
||||
"""处理文件的主函数"""
|
||||
try:
|
||||
# 读取文件内容(二进制模式)
|
||||
with open(filename, 'rb+') as f:
|
||||
original_data = f.read()
|
||||
data_len = len(original_data)
|
||||
|
||||
# ========== 验证阶段 ==========
|
||||
# 1. 检查文件长度是否为4的倍数
|
||||
if data_len % 4 != 0:
|
||||
raise ValueError(f"文件长度 {data_len} 不是4的倍数")
|
||||
|
||||
# 2. 检查第二个4字节是否等于文件长度
|
||||
if data_len >= 8:
|
||||
declared_length = struct.unpack('<I', original_data[4:8])[0]
|
||||
if declared_length != data_len:
|
||||
raise ValueError(
|
||||
f"长度声明不匹配:文件头声明={declared_length},实际={data_len}"
|
||||
)
|
||||
|
||||
# ========== 计算校验和 ==========
|
||||
checksum = calculate_checksum(original_data)
|
||||
|
||||
# ========== 写入校验和 ==========
|
||||
# 定位到文件最后4字节
|
||||
f.seek(-4, os.SEEK_END)
|
||||
f.write(struct.pack('<I', checksum)) # 小端序写入
|
||||
|
||||
print(f"[成功] 文件 {filename} 已更新校验码:0x{checksum:08X}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"[错误] 处理文件 {filename} 失败:{str(e)}")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 参数检查
|
||||
if len(sys.argv) != 2:
|
||||
print("用法: python checksum.py <文件名>")
|
||||
sys.exit(1)
|
||||
|
||||
input_file = sys.argv[1]
|
||||
|
||||
# 文件存在性检查
|
||||
if not os.path.isfile(input_file):
|
||||
print(f"[错误] 文件不存在: {input_file}")
|
||||
sys.exit(1)
|
||||
|
||||
# 执行处理
|
||||
if not process_file(input_file):
|
||||
sys.exit(1)
|
||||
Loading…
Reference in New Issue
Block a user