NVMe-eMMC Bridge 芯片固件开发(二):Bootloader 启动流程

1. Bootloader 概述

Bootloader 是芯片上电后执行的第一段代码,负责完成以下核心任务:

  1. CPU 寄存器初始化:设置 PSR、TBR、WIM、堆栈指针
  2. Cache 使能:开启指令和数据 Cache
  3. 固件加载:从 SPI Flash 或 eMMC Boot 分区加载 Firmware
  4. 安全验证:Parity Check 和 Checksum 校验
  5. 跳转执行:跳转到 RAM 中的 Firmware 入口

1.1 启动模式

BayBridge 支持多种启动模式:

模式 Bootloader 位置 Firmware 位置 典型场景
ROM + SPI Flash 芯片 ROM 固化 SPI Flash 省成本方案
SPI Flash Only SPI Flash Base SPI Flash Middle 外挂 Flash
eMMC Boot ROM 或 SPI eMMC Boot Partition 无外挂 Flash
FW Download ROM 或 SPI 主机下载 工厂烧录/救砖

2. 汇编启动代码分析

2.1 boot.S 入口代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/* boot.S - SPARC LEON2 启动汇编 */

#include "cpu.h"
#include "config.h"

.seg "text"
PUBLIC(start)
.global start

SYM(start):
start:
/* 硬件复位入口 */
PUBLIC(hard_reset)
SYM(hard_reset):

common_init:
/* 1. 初始化 PSR (Processor State Register) */
rd %psr, %g1
or %g1, 0xFA0, %g1 ! supervisor mode, disable interrupt, enable trap
wr %g0, %g1, %psr
nop ! PSR 写入需要 3 个延迟槽
nop
nop

/* 2. 初始化 TBR (Trap Base Register) */
set 0x40000000, %g1 ! Trap 表放在 RAM 起始位置
mov %g1, %tbr

/* 3. 初始化 WIM (Window Invalid Mask) */
set WIM_INIT, %g1 ! WIM_INIT = 2
mov %g1, %wim
nop
nop
nop

/* 4. 初始化堆栈指针 */
set STACK_BASE, %g3 ! STACK_BASE = 0x40000000 + 160KB
sub %g3, 1024, %g3 ! 预留 1KB 存储 FW Header 参数
sub %g3, 128, %g3 ! 预留输入参数空间
mov %g3, %fp ! 设置 Frame Pointer
sub %g3, 96, %sp ! 设置 Stack Pointer (SPARC ABI 要求)
andn %sp, 0x0f, %sp ! 16 字节对齐

/* 5. 使能 Cache */
set 0x80000014, %l1 ! Cache Control Register 地址
ld [%l1], %l2
set 0x81000F, %l3 ! 使能 I-Cache 和 D-Cache
or %l3, %l2, %l2
st %l2, [%l1]
flush ! 刷新 Pipeline
nop
nop
nop

/* 6. 跳转到 C 代码 */
set SYM(boot_route), %g2
jmp %g2
nop

2.2 关键寄存器说明

寄存器 作用 初始值
PSR 处理器状态 0xFA0 (S=1, ET=1, PIL=15)
TBR Trap 基地址 0x40000000
WIM 窗口无效掩码 0x02
%fp Frame Pointer RAM_TOP - 1KB - 128
%sp Stack Pointer %fp - 96

2.3 堆栈布局

1
2
3
4
5
6
7
8
9
10
11
12
13
0x40028000 (160KB RAM Top)
|
+------------------------+ <- RAM_TOP
| FW Header (1KB) | <- 存储从 SPI Flash 拷贝的参数
+------------------------+ <- 0x40027C00
| Input Args (128B) | <- 函数调用参数区
+------------------------+ <- 0x40027B80 (%fp)
| Local Vars (96B) | <- 当前栈帧
+------------------------+ <- %sp (16字节对齐)
| |
| Stack Growth ↓ |
| |
+------------------------+

3. 启动路由逻辑 (boot_route.c)

3.1 启动流程状态机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
void boot_route()
{
card_info_struct card_info;
u32 dump_info_buf[20] = {0};
u32 fw_head_base = 0;
u32 fw_body_base;
fw_sect_t fw_sect;
spi_cfg_t spi_cfg;
u32 rst_slot;

// Step 1: 设置默认 PLL 和 AHB 时钟
// PLL 200MHz, AHB 100MHz (ASIC)
set_pll_ahb_clock();

// Step 2: 初始化 UART (调试模式)
#ifdef BOOTLOADER_DEBUG
InitUARTPrint();
#endif

// Step 3: 检查强制下载标志
if (get_fw_download_flag() == 0x2) {
goto fw_download_entry; // 进入固件下载模式
}

// Step 4: 检查 SPI Flash 是否存在
if (!check_spi_exist()) {
goto emmc_boot_entry; // 无 SPI Flash,尝试 eMMC Boot
}

// Step 5: 检查复位时激活的 Slot
rst_slot = get_reset_activate_slot();
if (rst_slot != 0 && rst_slot != 3) {
goto emmc_boot_entry; // 目标不是 SPI,尝试 eMMC
}

// === SPI Boot Flow ===

// Step 6: 验证 SPI Flash 中的固件有效性
int valid = firmware_valid_check(SPI_FLASH_BASE, BOOT_MAX_SIZE);
if (valid == 0) {
// Firmware 在 SPI Flash 起始位置 (Bootloader 在 ROM)
fw_head_base = SPI_FLASH_BASE;
} else if (valid == 1) {
// Firmware 在 SPI Flash 中部 (Bootloader 也在 SPI Flash)
fw_head_base = SPI_FLASH_BASE + BOOT_MAX_SIZE; // 跳过 16KB Bootloader
} else {
goto emmc_boot_entry; // SPI 固件无效,尝试 eMMC
}

// Step 7: 解析 Firmware Header,获取段信息
fw_body_base = fw_head_base + FW_HEAD_SIZE; // FW_HEAD_SIZE = 1KB
firmware_head_parse(fw_head_base, &fw_sect, &spi_cfg);

// Step 8: 拷贝 Firmware 到 RAM
firmware_copy(fw_body_base, &fw_sect, &spi_cfg);

// Step 9: 设置当前激活 Slot 为 SPI
set_current_activate_slot_spi();

// Step 10: 跳转到 Firmware
boot_exit(); // 永不返回

emmc_boot_entry:
// eMMC Boot 流程...
clear_current_activate_slot_spi();
read_boot_part(&fw_sect, ...);

fw_download_entry:
// 固件下载模式
bootload_firmware_downloader(&card_info, dump_info_buf);
}

3.2 固件有效性校验

采用奇偶校验 (Parity Check) 验证固件 Header:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int parity_check(int parity_mode, u32 dword_addr)
{
u8 byte[4];
int check_result;
u32 *p_dword = (u32 *)dword_addr;
u8 *p_byte = (u8 *)dword_addr;

byte[0] = *p_byte;
byte[1] = *(p_byte + 1);
byte[2] = *(p_byte + 2);
byte[3] = *(p_byte + 3);

// 检查全 0 或全 1(无效固件)
if (*p_dword == 0xffffffff || *p_dword == 0) {
return -1;
}

// 计算奇偶校验
check_result = byte[0] ^ byte[1] ^ byte[2] ^ byte[3];

if (parity_mode == 1 && check_result == 0xff) // 奇校验通过
return 0;
else if (parity_mode == 0 && check_result == 0) // 偶校验通过
return 0;
else
return -1;
}

3.3 Firmware Header 结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
* Firmware Header Layout (1KB = 2 Blocks)
*
* Block 1 (512 Bytes):
* DWORD[0]: Parity Byte + Firmware Size (24-bit)
* DWORD[1]: .text Section Address
* DWORD[2]: .text Section Size
* DWORD[3]: .data Section Address
* DWORD[4]: .data Section Size
* DWORD[5]: .bss Section Address
* DWORD[6]: .bss Section Size
* DWORD[8-19]: SPI Flash Configuration
* DWORD[31]: Firmware Checksum
* DWORD[32-127]: Customer Parameters (VID/PID, Serial Number, etc.)
*
* Block 2 (512 Bytes):
* Reserved / Additional Parameters
*/

typedef struct {
u32 text_addr;
u32 text_size;
u32 data_addr;
u32 data_size;
u32 bss_addr;
u32 bss_size;
} fw_sect_t;

typedef struct {
u32 spi_frq_div; // SPI 时钟分频
u32 spi_timing_dly; // SPI 相位配置
} spi_cfg_t;

4. 固件拷贝流程

4.1 firmware_copy 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
static void firmware_copy(u32 base, fw_sect_p fw_sect, spi_cfg_p spi_cfg)
{
u32 *copy_start, *copy_end, *bss_start, *bss_end;
u32 *dest, *src;
u32 copy_offset;

// Step 1: 配置 SPI Flash 访问参数
if (SPI_WR_CFG == 0) {
SPI_FRQ_DIV = spi_cfg->spi_frq_div;
SPI_CTRL &= ~PHASE_ADJUST_FIELD_MASK;
SPI_CTRL |= spi_cfg->spi_timing_dly;
SPI_WR_CFG = 1; // 生效配置(100 CPU cycles 后自动清零)
}

// Step 2: 拷贝 Firmware Header 到 RAM Top 1KB
dest = (u32 *)(BAYBRIDGE_WORKRAM_BASE + BB_RAM_SIZE - FW_HEAD_SIZE);
src = (u32 *)(base - FW_HEAD_SIZE);
copy_end = (u32 *)(BAYBRIDGE_WORKRAM_BASE + BB_RAM_SIZE);
while (dest < copy_end) {
*dest++ = *src++;
}

// Step 3: 设置设备 VID/PID 寄存器
dev_vend_id_register();

// Step 4: 判断是否为 Fastboot(仅拷贝 .data 段)
if (is_reset_fastboot()) {
copy_start = (u32 *)fw_sect->data_addr;
copy_offset = fw_sect->data_addr - fw_sect->text_addr;
} else {
// 正常启动:拷贝 .text + .data
copy_start = (u32 *)fw_sect->text_addr;
copy_offset = 0;
}
copy_end = (u32 *)(fw_sect->data_addr + fw_sect->data_size);

// Step 5: 拷贝 .text 和 .data 段
dest = copy_start;
src = (u32 *)(base + copy_offset);
while (dest < copy_end) {
*dest++ = *src++;
}

// Step 6: 清零 .bss 段
bss_start = (u32 *)fw_sect->bss_addr;
bss_end = (u32 *)(fw_sect->bss_addr + fw_sect->bss_size);
dest = bss_start;
while (dest < bss_end) {
*dest++ = 0;
}

// Step 7: 恢复 SPI 频率为安全值
if (SPI_WR_CFG == 0) {
SPI_FRQ_DIV = 8; // DIV4,保证 SPI Write 稳定
SPI_WR_CFG = 1;
}
}

4.2 Fastboot 机制

Fastboot 是一种快速启动优化:

  • 触发条件:热复位(非断电重启)且 Fastboot 标志有效
  • 优化效果:跳过 .text 段拷贝,直接复用 RAM 中的代码
  • 限制:RAM 内容必须保持不变
1
2
3
4
5
6
7
8
9
static u32 is_reset_fastboot()
{
// Slot 复位时禁止 Fastboot
if (get_reset_activate_slot())
return 0;

// 检查 Fastboot 指示标志
return ((BAYBRIDGE_RESET_FAST_BOOT_INDICATOR >> 4) == 0x5a);
}

5. 跳转到 Firmware

5.1 boot_exit 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void boot_exit()
{
Key_Info_Print_BL("boot_exit...\n");

/* 跳转到 RAM 入口执行 Firmware
* RAM 起始位置是 Trap Table,不是代码
* 需要通过 Trap Table 中的二次跳转到达真正的入口
*/
asm(
"set 0x40000000, %g2\n"
"jmp %g2\n"
"nop"
);
}

5.2 Trap Table 结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* trap_table.S - RAM 起始的 Trap 表 */

.section ".text"
.global trap_table_start

trap_table_start:
/* Trap 0: Reset - 跳转到 InitSystem */
ba SYM(InitSystem)
nop
nop
nop

/* Trap 1-255: 其他中断/异常处理 */
...

5.3 InitSystem 入口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// init_sys.c
void InitSystem(void)
{
// 1. 执行 Firmware Checksum 校验
// do_fw_checksum();

// 2. 初始化 BSP 模块
InitBSP();

// 3. 初始化中断控制器
interrupt_init();

// 4. 进入 NVMe 主流程
main();
}

6. 固件构建工具

6.1 bin_attach 工具

bin_attach 是一个多功能二进制处理工具,支持三种模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*
* 模式 0: 生成 Firmware Header
* - 输入: fw_sys_raw.bin, fw_sys_size.txt, boot.cfg, customer.cfg
* - 输出: fw_head.bin (1KB)
*
* 模式 1: 扩展 Bootloader 到固定大小
* - 输入: boot_flash.bin
* - 输出: boot_flash_extended.bin (16KB)
*
* 模式 2: 合并两个二进制文件
* - 输入: head.bin, tail.bin
* - 输出: merged.bin
*/

// Parity 生成算法
static u32 parity_generate(u32 dword, u32 mode)
{
u8 byte[4];
byte[1] = (dword & 0x00ff0000) >> 16;
byte[2] = (dword & 0x0000ff00) >> 8;
byte[3] = (dword & 0x000000ff);

if (mode == 1) // 奇校验
byte[0] = ~(byte[1] ^ byte[2] ^ byte[3]);
else // 偶校验
byte[0] = (byte[1] ^ byte[2] ^ byte[3]);

dword &= 0x00ffffff; // 清除最高字节
dword |= ((u32)byte[0]) << 24; // 填入校验字节
return dword;
}

6.2 fw_checksum 工具

计算 Firmware 的 XOR Checksum:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// fw_checksum.c
int main(u8 argc, u8 *argv[])
{
FILE *fp_fwbin = fopen(argv[1], "rb");

u32 fw_size = get_file_len(fp_fwbin);
u32 fw_size_raw = fw_size - 1024; // 排除 Header
u32 fw_dword_cnt = fw_size_raw / 4;

u8 *buffer = create_buf(fw_size);
fread(buffer, sizeof(u8), fw_size, fp_fwbin);

// XOR Checksum 计算
u32 *dword_buf = (u32 *)buffer;
u32 checksum = dword_buf[256]; // 从 offset 1K 开始
for (int i = 1; i < fw_dword_cnt; i++) {
checksum ^= dword_buf[256 + i];
}

printf("firmware raw size: %u, dword checksum: 0x%X\n",
fw_size_raw, checksum);

// 写入 Header 的 DWORD[31] 位置
*((u32 *)(buffer + FW_CHECKSUM_DWORD_OFFSET * 4)) = checksum;

FILE *fp_fwbin_out = fopen(argv[2], "wb");
fwrite(buffer, sizeof(u8), fw_size, fp_fwbin_out);

return 0;
}

7. 启动时序分析

7.1 典型启动时序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
+-------+------------------+------------------+------------------+
| 阶段 | SPI Boot | eMMC Boot | FW Download |
+-------+------------------+------------------+------------------+
| T0 | Power On | Power On | Power On |
| T1 | CPU Reset | CPU Reset | CPU Reset |
| T2 | boot.S (ASM) | boot.S (ASM) | boot.S (ASM) |
| T3 | boot_route() | boot_route() | boot_route() |
| T4 | SPI Check OK | SPI Check Fail | Force Download |
| T5 | FW Valid Check | eMMC Boot Check | Wait Host CMD |
| T6 | FW Copy to RAM | FW Copy to RAM | Receive FW Data |
| T7 | boot_exit() | boot_exit() | boot_exit() |
| T8 | Trap Table | Trap Table | Trap Table |
| T9 | InitSystem() | InitSystem() | InitSystem() |
| T10 | main() | main() | main() |
+-------+------------------+------------------+------------------+
| Time | ~10-20 ms | ~50-100 ms | Variable |
+-------+------------------+------------------+------------------+

7.2 启动时间优化技术

  1. Fastboot:热复位跳过 .text 拷贝
  2. SPI 频率优化:动态调整 SPI 时钟分频
  3. 并行初始化:减少串行依赖

8. 总结

BayBridge Bootloader 的设计体现了嵌入式系统启动代码的典型特征:

  1. 精简高效:汇编代码控制在 100 行以内
  2. 多路启动:支持 ROM/SPI/eMMC 多种启动介质
  3. 安全校验:Parity + Checksum 双重保护
  4. 容错机制:启动失败自动切换到 FW Download 模式
  5. 快速启动:Fastboot 减少热复位时间

下一篇文章将详细介绍 Firmware 主流程和 NVMe 协议栈的实现。


附录:关键宏定义

1
2
3
4
5
6
7
8
9
// config.h
#define BB_RAM_SIZE (160*1024) // 160KB RAM
#define BB_ROM_BASE 0x50000000 // ROM 基地址

// boot.h
#define SPI_FLASH_BASE 0x50000000 // SPI Flash 映射地址
#define BOOT_MAX_SIZE 16384 // Bootloader 最大 16KB
#define FW_HEAD_SIZE 1024 // Firmware Header 1KB
#define PARITY_MODE 1 // 1: 奇校验, 0: 偶校验