NVMe-eMMC-Bridge芯片固件(十):PRP 和 PRP_List 深度解析
日期: 2026-03-21
系列: NVMe-eMMC-Bridge 芯片固件
适用: 固件工程师、存储系统开发者、NVMe 协议开发者
1. 概述
1.1 什么是 PRP?
PRP (Physical Region Page) 是 NVMe 协议中用于描述主机内存中数据区域的 64 位物理地址结构。在 NVMe 命令中,PRP 告诉控制器从哪里读取或写入数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ┌─────────────────────────────────────────────────────────────────────┐ │ PRP (Physical Region Page) │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ 64-bit Physical Address │ │ │ │ │ │ │ │ ┌───────────────────────┬───────────────────────┐ │ │ │ │ │ Bits [63:12] │ Bits [11:0] │ │ │ │ │ │ Page Frame Address │ Offset in Page │ │ │ │ │ │ (物理页基地址) │ (页内偏移) │ │ │ │ │ └───────────────────────┴───────────────────────┘ │ │ │ │ │ │ │ │ 页大小由 CAP.MPSMAX 决定,通常为 4KB │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘
|
1.2 BayBridge 系统中的内存布局
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
| ┌─────────────────────────────────────────────────────────────────────┐ │ BayBridge 控制器内存布局 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ 控制器寄存器空间 │ │ │ │ (PCIe BAR0) │ │ │ ├─────────────────────────────────────────────────────────────┤ │ │ │ │ │ │ │ ┌─────────────────┐ ┌─────────────────┐ │ │ │ │ │ CMD_BUFFER │ │ DATA_BUFFER │ │ │ │ │ │ (1KB) │ │ (4KB) │ │ │ │ │ │ │ │ │ │ │ │ │ │ NVMe 命令 │ │ DMA 数据缓冲 │ │ │ │ │ │ 存放地址 │ │ │ │ │ │ │ └─────────────────┘ └─────────────────┘ │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ 外部 SPI Flash / eMMC │ │ │ │ 固件存储空间 │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ 主机系统内存 (Host Memory) │ │ │ │ │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ │ │ PRP / PRP List │ │ │ │ │ │ ┌─────────────────────────────────────────────────┐ │ │ │ │ │ │ │ PRP Entry 0: 物理地址 + 偏移 │ │ │ │ │ │ │ │ PRP Entry 1: 物理地址 + 偏移 │ │ │ │ │ │ │ │ ... │ │ │ │ │ │ │ └─────────────────────────────────────────────────┘ │ │ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ │ │ 数据缓冲区 │ │ │ │ │ │ 实际的固件数据存放在这里 │ │ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘
|
2. NVMe 规范中的 PRP 定义
2.1 NVMe Submission Queue 命令格式
根据 NVMe 1.4 规范,命令结构包含两个 PRP 字段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| typedef struct { UINT8 Opc; UINT8 Fuse : 2; UINT8 Rsvd1 : 5; UINT8 Psdt : 1; UINT16 Cid;
UINT32 Nsid; UINT64 Rsvd2; UINT64 Mptr;
UINT64 Prp[2];
UINT64 Payload; } NVME_SQ;
|
2.2 PRP 字段说明
| 字段 |
说明 |
| PRP1 |
第一个物理区域页,作为数据传输的首选位置 |
| PRP2 |
第二个物理区域页,可以是: • 另一个 PRP (指向数据) • PRP List (指向多个 PRP) |
2.3 PRP 数据结构
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
| ┌─────────────────────────────────────────────────────────────────────┐ │ PRP Entry 结构 (64-bit) │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ Byte 7 Byte 6 Byte 5 Byte 4 │ │ ┌─────────┬─────────┬─────────┬─────────┐ │ │ │ [63:56] │ [55:48] │ [47:40] │ [39:32] │ │ │ └─────────┴─────────┴─────────┴─────────┘ │ │ │ │ Byte 3 Byte 2 Byte 1 Byte 0 │ │ ┌─────────┬─────────┬─────────┬─────────┐ │ │ │ [31:24] │ [23:16] │ [15:8] │ [7:0] │ │ │ └─────────┴─────────┴─────────┴─────────┘ │ │ │ │ ───────────────────────────────────────────────────────────────── │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ PRP Entry 解析: │ │ │ │ │ │ │ │ Bits [63:12]: Page Frame Address (物理页基地址) │ │ │ │ 必须按 4KB (或 MPS 指定的页大小) 对齐 │ │ │ │ │ │ │ │ Bits [11:0]: Offset in Page (页内偏移) │ │ │ │ 指示数据在页内的起始位置 │ │ │ │ │ │ │ │ 注意: 如果偏移为 0,PRP 指向整个页面 │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘
|
3. PRP_List 机制
3.1 为什么需要 PRP_List?
当传输的数据量超过一个内存页时,PRP1 无法容纳所有数据。此时:
- PRP1: 指向第一个页的数据
- PRP2: 指向一个 PRP_List (PRP 页)
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
| ┌─────────────────────────────────────────────────────────────────────┐ │ PRP_List 工作原理 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ 场景: 传输 12KB 数据 │ │ ──────────────────────────────── │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ NVMe 命令中的 PRP 字段 │ │ │ │ │ │ │ │ PRP1 ──► ┌─────────────────────────────────────────────┐ │ │ │ │ │ Host Memory Page 0 │ │ │ │ │ │ ┌─────────────────────────────────────┐ │ │ │ │ │ │ │ 数据区域 (4KB) │ │ │ │ │ │ │ └─────────────────────────────────────┘ │ │ │ │ │ └─────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ PRP2 ──► ┌─────────────────────────────────────────────┐ │ │ │ │ │ PRP_List (也是一页,4KB) │ │ │ │ │ │ ┌─────────────────────────────────────┐ │ │ │ │ │ │ │ PRP Entry 0 ──► Page 1 │ │ │ │ │ │ │ │ PRP Entry 1 ──► Page 2 │ │ │ │ │ │ │ │ PRP Entry 2 ──► Page 3 │ │ │ │ │ │ │ │ (每个 4KB,共 8KB) │ │ │ │ │ │ │ └─────────────────────────────────────┘ │ │ │ │ │ └─────────────────────────────────────────────┘ │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ 总传输: 4KB (PRP1) + 4KB (PRP_List[0]) + 4KB (PRP_List[1]) = 12KB │ │ │ └─────────────────────────────────────────────────────────────────────┘
|
3.2 PRP_List 条目规则
根据 NVMe 规范,PRP_List 中的条目必须满足:
| 规则 |
说明 |
| 页对齐 |
每个 PRP Entry 的地址必须按页大小 (4KB) 对齐 |
| 偏移为 0 |
PRP_List 中的条目偏移必须为 0 |
| 页大小 |
除最后一个条目外,每个条目代表一个完整的页 |
3.3 BayBridge 中的 PRP_List 实现
1 2 3 4 5 6
| #define FW_HEAD_LEN_BYTE 1024 #define DATA_BUFFER_SIZE (4*1024) #define PRP_SIZE (4*1024) #define PRP_LIST_SIZE (4*512) #define DATA_BLOCK_SIZE 512
|
1 2 3 4 5 6 7 8 9 10
| typedef struct { u32 *buffer; u32 *prp_list;
u8 prp_list_flag; u16 offset_in_page; u32 size; u32 offset; } firmware_update_data_t;
|
4. DMA 数据传输核心实现
4.1 dma_data_transfer 函数架构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| int dma_data_transfer( u64 prp_entry1, u64 prp_entry2, u32 size, u8 clear_data_buffer_flag, u8 is_write_to_system_memory ) { u32 offset_in_page = prp_entry1 & 0xfff;
}
|
4.2 三种 DMA 场景详解
场景 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
| ┌─────────────────────────────────────────────────────────────────────┐ │ 场景 1: 单页数据传输 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ 数据大小 ≤ 4KB 且不跨页 │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ NVMe 命令: │ │ │ │ │ │ │ │ PRP1 = 0x1000_0000 (含 offset) │ │ │ │ PRP2 = 0 │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ DMA 操作: │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ 主机内存 ──DMA──► BayBridge DATA_BUFFER (4KB) │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ 代码: │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ ret = start_DMA1(prp_entry1, size, offset, ...); │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘
|
场景 2: 两页数据传输 (跨一页)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| ┌─────────────────────────────────────────────────────────────────────┐ │ 场景 2: 两页数据传输 (跨一页) │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ 4KB < 数据大小 ≤ 8KB │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ NVMe 命令: │ │ │ │ │ │ │ │ PRP1 = 0x1000_0000 (Page 0) │ │ │ │ PRP2 = 0x2000_0000 (Page 1 基地址) │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ DMA 操作: │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ Page 0 ──DMA0──► DATA_BUFFER ──DMA1──► Page 1 │ │ │ │ │ │ │ │ 1. start_DMA0(prp_entry1, ...) DMA 读 │ │ │ │ 2. start_DMA1(prp_entry2, ...) DMA 写 │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘
|
场景 3: 多页数据传输 (使用 PRP_List)
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
| ┌─────────────────────────────────────────────────────────────────────┐ │ 场景 3: 多页数据传输 (使用 PRP_List) │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ 数据大小 > 8KB │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ NVMe 命令: │ │ │ │ │ │ │ │ PRP1 = 0x1000_0000 (数据页 0) │ │ │ │ PRP2 = 0x3000_0000 (PRP_List 页面) │ │ │ │ │ │ │ │ PRP_List 内容: │ │ │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ │ │ Entry 0: 0x4000_0000 (数据页 1) │ │ │ │ │ │ Entry 1: 0x5000_0000 (数据页 2) │ │ │ │ │ │ ... │ │ │ │ │ └────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ DMA 操作: │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ │ │ │ │ 1. DMA PRP1 ──► DATA_BUFFER │ │ │ │ 2. DMA PRP_List[0] ──► DATA_BUFFER │ │ │ │ 3. DMA PRP_List[1] ──► DATA_BUFFER │ │ │ │ ... │ │ │ │ │ │ │ │ 每页数据都需要单独的 DMA 操作 │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘
|
4.3 start_DMA1 函数实现
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
| int start_DMA1( u64 prp, u32 size, u16 data_buf_addr, u8 is_write_to_system_memory, u32 timeout ) { BAYBRIDGE_DMA1_CTRL_4 = prp >> 32; BAYBRIDGE_DMA1_CTRL_3 = prp;
BAYBRIDGE_DMA1_CTRL_2 = data_buf_addr & 0xfff;
if(is_write_to_system_memory) { BAYBRIDGE_DMA1_CTRL_1 = START_DMA_BIT | (DMA_DIRECTION_WRITE_TO << DMA_DIRECTION_SHIFT) | (size & DMA_TRANSFER_SIZE_IN_BYTE_MASK_BIT); } else { BAYBRIDGE_DMA1_CTRL_1 = START_DMA_BIT | (DMA_DIRECTION_READ_FROM << DMA_DIRECTION_SHIFT) | (size & DMA_TRANSFER_SIZE_IN_BYTE_MASK_BIT); }
while(!(BAYBRIDGE_INTERNAL_INTERRUPT_STATUS & DMA1_INTERRUPT_STATUS_BIT) && timeout > 0) { timeout--; }
BAYBRIDGE_INTERNAL_INTERRUPT_STATUS = DMA1_INTERRUPT_STATUS_BIT;
return 0; }
|
5. PRP_List 解析实现
5.1 PRP_List 解析核心代码
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
| for(i = 0; i < prp_total_cnt; ++i) { prp_entry = ((u64)leon2_cpu_32bits_swap(global_fw_update_data.prp_list[2*i+1])) << 32 | leon2_cpu_32bits_swap(global_fw_update_data.prp_list[2*i]);
LOG_TEST(TEST_FW_DOWNLOAD, "prp_entry[%d]: 0x%llx\n", i, prp_entry);
if((prp_entry & 0xfff) == 0) {
if(i != prp_total_cnt - 1) { prp_data_size = PRP_SIZE; } else { data_size = (size + global_fw_update_data.offset_in_page) % PRP_SIZE; prp_data_size = data_size ? data_size : PRP_SIZE; }
dma_data_transfer(prp_entry, 0, prp_data_size, 0, 0);
} else { LOG_TEST(TEST_FW_DOWNLOAD, "PRP list's entry offset non zero!\n"); } }
|
5.2 PRP 条目数计算
1 2 3 4 5 6 7 8 9 10 11
| u32 data_size = total_size + offset_in_page; u32 prp_total_cnt = data_size / PRP_SIZE;
if(data_size % PRP_SIZE != 0) { prp_total_cnt++; }
prp_total_cnt--;
|
5.3 大小端转换问题
1 2 3 4 5 6 7 8 9 10 11 12
|
prp_entry = ((u64)leon2_cpu_32bits_swap(prp_list[2*i+1])) << 32 | leon2_cpu_32bits_swap(prp_list[2*i]);
|
6. 固件下载场景分析
6.1 BayBridge 支持的固件下载场景
| 场景 |
说明 |
PRP 处理 |
| SPI Flash 下载 |
下载到外部 SPI Flash |
DMA → RAM Buffer → SPI |
| eMMC Boot 分区 |
下载到 eMMC 启动分区 |
DMA → RAM Buffer → eMMC |
| eMMC FFU |
在线升级 eMMC 固件 |
DMA → eMMC (直接) |
| PowerShell FFU |
Windows PowerShell FFU |
PRP List → 多 DMA |
6.2 SPI Flash 下载流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| ┌─────────────────────────────────────────────────────────────────────┐ │ SPI Flash 下载流程 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ 1. NVMe 命令解析 │ │ └─► PRP1/PRP2 提取 │ │ │ │ 2. DMA 传输 (主机内存 → DATA_BUFFER) │ │ └─► start_DMA1(prp_entry, ...) │ │ │ │ 3. 拷贝到固件缓冲区 │ │ └─► fn_memcpy_4bytes(buffer, DATA_BUFFER, 4KB) │ │ │ │ 4. 写入 SPI Flash │ │ └─► spi_flash_block_safe_write(spi_addr, buffer, size) │ │ │ │ 5. 重复步骤 2-4 直到所有 PRP_List 处理完成 │ │ │ └─────────────────────────────────────────────────────────────────────┘
|
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
| static void do_download_spi_flash(u32 size, u32 offset) { u32 *spi_addr = (u32 *)BAYBRIDGE_EEPROM_BASE; u32 prp_total_cnt; u64 prp_entry;
set_pinshare_mode(MODE_SPI);
if(prp_list_flag == 1) { data_size = size + offset_in_page; prp_total_cnt = data_size / PRP_SIZE + (data_size % PRP_SIZE == 0 ? 0 : 1); prp_total_cnt--;
for(i = 0; i < prp_total_cnt; i++) { prp_entry = ((u64)swap(prp_list[2*i+1])) << 32 | swap(prp_list[2*i]);
dma_data_transfer(prp_entry, 0, prp_data_size, 0, 0);
fn_memcpy_4bytes(buffer, DATA_BUFFER, DATA_BUFFER_SIZE);
spi_flash_block_safe_write(spi_addr, buffer, prp_data_size); spi_addr += (prp_data_size >> 2); } } }
|
6.3 eMMC FFU 下载流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ┌─────────────────────────────────────────────────────────────────────┐ │ eMMC FFU 下载流程 (PowerShell) │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ 与 SPI Flash 下载的主要区别: │ │ ───────────────────────────────────────────────────── │ │ • 不需要中间的固件缓冲区拷贝 │ │ • 每个 PRP DMA 后直接调用 FFU │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ │ │ │ │ PRP DMA ──► DATA_BUFFER ──► eMMC DMA (ffu_download) │ │ │ │ │ │ │ │ │ └── 不需要缓冲区拷贝,直接传输 │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘
|
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
| static void do_ffu_process(u32 size, u32 offset) { u32 prp_total_cnt; u64 prp_entry;
if(prp_list_flag == 1) { data_size = size + offset_in_page; prp_total_cnt = data_size / PRP_SIZE + (data_size % PRP_SIZE == 0 ? 0 : 1); prp_total_cnt--;
if(is_ffu_case == FFU_DEFAULT) { data_size = DATA_BUFFER_SIZE - offset_in_page - FW_HEAD_LEN_BYTE; fn_memcpy_4bytes(DATA_BUFFER, &buffer[FW_HEAD_LEN_BYTE >> 2], data_size);
ffu_download(emmc_id, 1, data_size); }
for(i = 0; i < prp_total_cnt; i++) { prp_entry = ((u64)swap(prp_list[2*i+1])) << 32 | swap(prp_list[2*i]);
dma_data_transfer(prp_entry, 0, prp_data_size, 0, 0);
ffu_download(emmc_id, 0, prp_data_size); } } }
|
6.4 关键区别对比
| 特性 |
SPI Flash 下载 |
eMMC FFU |
| 中间缓冲 |
需要固件缓冲区 |
不需要 |
| 数据传输 |
DMA → Buffer → Flash |
DMA → eMMC |
| 缓冲区拷贝 |
fn_memcpy_4bytes() |
无 |
| 写入方式 |
spi_flash_block_safe_write() |
ffu_download() |
| 性能 |
较慢 (多一步) |
较快 (直接) |
7. 双 DMA 通道架构
7.1 DMA 通道说明
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
| ┌─────────────────────────────────────────────────────────────────────┐ │ BayBridge 双 DMA 通道架构 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ PCIe DMA 通道 │ │ │ │ │ │ │ │ DMA0: 主机内存 ──► DATA_BUFFER (读) │ │ │ │ DMA1: DATA_BUFFER ──► 主机内存 (写) │ │ │ │ │ │ │ │ 寄存器: │ │ │ │ • DMA0_CTRL_1~4: DMA0 控制 │ │ │ │ • DMA1_CTRL_1~4: DMA1 控制 │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ DATA_BUFFER (4KB FIFO) │ │ │ │ │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ │ │ DMA 读/写共享的缓冲区 │ │ │ │ │ │ • NVMe 命令数据 │ │ │ │ │ │ • eMMC/SPI 传输数据 │ │ │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌───────────────┴───────────────┐ │ │ ▼ ▼ │ │ ┌───────────────────────┐ ┌───────────────────────┐ │ │ │ eMMC DMA 通道 │ │ SPI Flash 控制器 │ │ │ │ │ │ │ │ │ │ • 固件升级 (FFU) │ │ • 固件存储 │ │ │ │ • 读/写数据 │ │ • 配置存储 │ │ │ └───────────────────────┘ └───────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘
|
7.2 双 DMA 协同工作
1 2 3 4 5 6 7 8 9
|
start_DMA0(prp_entry, DATA_BUFFER_SIZE, 0, DMA_DIRECTION_READ_FROM, timeout);
ffu_download(emmc_id, 0, DATA_BUFFER_SIZE);
|
8. 实际案例分析
8.1 PowerShell FFU 下载解析
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
| ┌─────────────────────────────────────────────────────────────────────┐ │ PowerShell FFU PRP_List 解析示例 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ 场景: 下载 160KB eMMC 固件 │ │ │ │ 假设: │ │ • offset_in_page = 1024 (PRP1 偏移 1KB) │ │ • total_size = 160KB │ │ │ │ ───────────────────────────────────────────────────────────────── │ │ │ │ 数据大小计算: │ │ data_size = 160KB + 1KB = 161KB │ │ │ │ PRP 条目数计算: │ │ prp_total_cnt = 161KB / 4KB = 40.25 → 41 │ │ prp_total_cnt-- = 40 (减去 PRP1) │ │ │ │ ───────────────────────────────────────────────────────────────── │ │ │ │ 传输顺序: │ │ │ │ 1. PRP1 (已在之前 DMA) → eMMC (跳过 1KB 头) │ │ │ │ 2-41. PRP_List[0-39] → DATA_BUFFER → eMMC │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ PRP_List[0]: 4KB ──► DATA_BUFFER ──► eMMC │ │ │ │ PRP_List[1]: 4KB ──► DATA_BUFFER ──► eMMC │ │ │ │ ... │ │ │ │ PRP_List[39]: 4KB ──► DATA_BUFFER ──► eMMC │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘
|
8.2 关键代码注释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
|
9. 总结
9.1 PRP 机制要点
| 要点 |
说明 |
| PRP 结构 |
64 位物理地址 = 页基址 + 页内偏移 |
| PRP1 |
第一个数据页 (或 PRP_List 指针) |
| PRP2 |
第二个 PRP 或 PRP_List |
| PRP_List |
当数据 > 1 页时使用,存放多个 PRP 条目 |
| 页对齐 |
所有 PRP 地址按 4KB 对齐 |
9.2 BayBridge 实现要点
| 要点 |
说明 |
| DATA_BUFFER |
4KB 共享缓冲区,DMA 中转 |
| 双 DMA |
DMA0 (读) + DMA1 (写) 通道 |
| 大端转换 |
PCIe 传输使用大端,CPU 使用小端 |
| FFU 优化 |
直接 DMA 到 eMMC,无需缓冲区拷贝 |
9.3 调试检查清单
参考资料
- NVMe Specification 1.4 - NVM Express, Inc.
- PCI Express Base Specification - PCI-SIG
- JEDEC eMMC Specification JESD84-B51 - JEDEC
- BayBridge 固件代码:
C:\gitlab-bht\baybridge\src\nvme\firmware_image_download.c
相关文档
| 文档 |
说明 |
NVMe-eMMC-Bridge芯片固件_01_硬件和软件架构.md |
BayBridge 芯片整体架构 |
| 本文档 |
PRP/PRP_List 深度解析 |
文档生成日期: 2026-03-21
固件版本: BayBridge v1.0+