本文分析Zephyr的配置文件和设备树在存储区域上配置生效机制。
通过Zephyr镜像存储区域配置-基于RT1062的实例知道通过配置文件和设备树可以指定Zephyr镜像的存储区域。而我们知道存储区域是在分散加载文件中指定生效,本文分析配置文件和设备树在分散加载文件中生效机制。最后的分析示例还是基于mm_feater(SOC是RT1062)进行。
存储区域
RT1062的存储区域对应于include/arch/arm/aarch32/cortex_m/scripts/linker.ld
中以MEMORY指令指定的region。1
2
3
4
5
6MEMORY
{
FLASH (rx) : ORIGIN = ROM_ADDR, LENGTH = ROM_SIZE
SRAM (wx) : ORIGIN = RAM_ADDR, LENGTH = RAM_SIZE
...
}
Zephyr将可执行程序运行时使用存储区域分为FLASH和SRAM两部分:
- FLASH:只读、执行区域。代码和只读数据放在其中。
- SRAM:读写,执行区域,读写数据放在其中,也可以将可执行代码放入其中执行。
这两片区域的地址ROM_ADDR
,ROM_SIZE
,RAM_ADDR
,RAM_SIZE
通过Zephyr的配置项指定
从include/arch/arm/aarch32/cortex_m/scripts/linker.ld
中可以看到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
(CONFIG_SRAM_SIZE * 1K - RAM_SIZE))
根据CONFIG_XIP
,CONFIG_IS_BOOTLOADER
的不同ROM/RAM的ADDR和SIZE将由下面几个配置项组合和而成
- CONFIG_FLASH_BASE_ADDRESS
- CONFIG_FLASH_SIZE
- CONFIG_FLASH_LOAD_OFFSET
- CONFIG_FLASH_LOAD_SIZE
- CONFIG_SRAM_BASE_ADDRESS
- CONFIG_SRAM_SIZE
- CONFIG_BOOTLOADER_SRAM_SIZE
这些配置项的来源和物理意义如下图CONFIG_FLASH_BASE_ADDRESS/CONFIG_FLASH_SIZE
定义了FLASH的区域范围CONFIG_FLASH_LOAD_OFFSET/CONFIG_FLASH_LOAD_SIZE
在XIP的情况可以指定ROM使用FLASH的区域,Zephyr将被链接到CONFIG_FLASH_LOAD_OFFSET的地址CONFIG_SRAM_BASE_ADDRESS/CONFIG_SRAM_SIZE 定义了SDRAM的区域范围
CONFIG_BOOTLOADER_SRAM_SIZE` zephyr被bootloader引导时,运行通过配置在RAM中留出bootloader使用的保留部分
配置项默认来源
在arch/Kconfig
中定义了FLASH和SRAM地址和大小的默认来源:
- FLASH是从设备树的
zephyr,flash
节点读取 - SDRAM是从设备树的
zephyr,sram
节点读取
1 | DT_CHOSEN_Z_FLASH := zephyr,flash |
FLASH和SRAM都不建议使用配置文件直接配置。
在Kconfig.zephyr
中定义了FLASH LOAD的地址和大小的默认来源,在配置了CONFIG_USE_DT_CODE_PARTITION
后默认会从设备树的zephyr,code-partition
节点读取。也可以不使用设备树在配置文件中直接配置CONFIG_FLASH_LOAD_OFFSET/CONFIG_FLASH_LOAD_SIZE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20if HAS_FLASH_LOAD_OFFSET
config USE_DT_CODE_PARTITION
bool "Link application into /chosen/zephyr,code-partition from devicetree"
DT_CHOSEN_Z_CODE_PARTITION := zephyr,code-partition
config FLASH_LOAD_OFFSET
# Only user-configurable when USE_DT_CODE_PARTITION is disabled
hex "Kernel load offset" if !USE_DT_CODE_PARTITION
default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) if USE_DT_CODE_PARTITION
default 0
config FLASH_LOAD_SIZE
# Only user-configurable when USE_DT_CODE_PARTITION is disabled
hex "Kernel load size" if !USE_DT_CODE_PARTITION
default $(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) if USE_DT_CODE_PARTITION
default 0
endif # HAS_FLASH_LOAD_OFFSET
在Kconfig.zephyr
中定义了BOOTLOADER_SRAM_SIZE
的默认值为16K, 只要使用了zephyr bootloader,无论是bootloader运行期还是app运行期,都为bootloader保留了这段空间。1
2
3
4
5config BOOTLOADER_SRAM_SIZE
int "SRAM reserved for bootloader"
default 16
depends on !XIP || IS_BOOTLOADER
depends on ARM || XTENSA
可以在配置文件中通过CONFIG_BOOTLOADER_SRAM_SIZE
来配置该区域大小,单位为K,如果不需要可以不配置。
mm_feather示例分析
mm_feather使用RT1062,其board综合soc提供的设备树摘录如下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
60flexram: flexram@400b0000 {
compatible = "nxp,imx-flexram";
reg = <0x400b0000 0x4000>;
interrupts = <38 0>;
#address-cells = <1>;
#size-cells = <1>;
itcm: itcm@0 {
compatible = "zephyr,memory-region", "nxp,imx-itcm";
reg = <0x00000000 DT_SIZE_K(128)>;
zephyr,memory-region = "ITCM";
};
dtcm: dtcm@20000000 {
compatible = "zephyr,memory-region", "nxp,imx-dtcm";
reg = <0x20000000 DT_SIZE_K(128)>;
zephyr,memory-region = "DTCM";
};
ocram: ocram@20200000 {
compatible = "mmio-sram";
reg = <0x20200000 DT_SIZE_K(768)>;
};
};
flexspi: spi@402a8000 {
compatible = "nxp,imx-flexspi";
reg = <0x402a8000 0x4000>;
interrupts = <108 0>;
label = "FLEXSPI";
#address-cells = <1>;
#size-cells = <0>;
ahb-bufferable;
ahb-cacheable;
status = "disabled";
};
sdram0: memory@80000000 {
/* Micron MT48LC16M16A2B4-6AIT:G */
device_type = "memory";
reg = <0x80000000 DT_SIZE_M(32)>;
};
&flexspi {
reg = <0x402a8000 0x4000>, <0x60000000 DT_SIZE_M(8)>;
is25wp064: is25wp064@0 {
compatible = "nxp,imx-flexspi-nor";
size = <67108864>;
label = "IS25WP064";
reg = <0>;
spi-max-frequency = <133000000>;
status = "okay";
jedec-id = [9d 70 17];
};
};
chosen {
zephyr,sram = &sdram0;
};
1. XIP直接从0地址运行镜像
配置选项&设备树
1 | CONFIG_XIP=y |
分析
FLASH
没有定义zephyr,flash
节点,对于rt1062来说在soc/arm/nxp_imx/rt/Kconfig.defconfig.series
下会对FLASH_BASE_ADDRESS
和FLASH_SIZE
进行覆盖,不使用zephyr,flash
而是1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19if CODE_FLEXSPI
config FLASH_SIZE
default $(dt_node_reg_size_int,/soc/spi@402a8000,1,K)
config FLASH_BASE_ADDRESS
default $(dt_node_reg_addr_hex,/soc/spi@402a8000,1)
endif # CODE_FLEXSPI
if CODE_FLEXSPI2
config FLASH_SIZE
default $(dt_node_reg_size_int,/soc/spi@402a4000,1,K)
config FLASH_BASE_ADDRESS
default $(dt_node_reg_addr_hex,/soc/spi@402a4000,1)
endif # CODE_FLEXSPI2
这里我们配置了CONFIG_CODE_FLEXSPI=y
,因此会从spi@402a8000
第一个寄存器中读取,spi@402a8000
的别名为flexspi
,其寄存器组为1
reg = <0x402a8000 0x4000>, <0x60000000 DT_SIZE_M(8)>;
第一个寄存器是<0x60000000 DT_SIZE_M(8)>
, 因此读出CONFIG_FLASH_BASE_ADDRESS=0x60000000
, CONFIG_FLASH_SIZE=8M
FLASH LOAD
没有进行相关配置CONFIG_FLASH_LOAD_OFFSET/CONFIG_FLASH_LOAD_SIZE
均为0
SRAM
设备树中指定使用zephyr,sram = &sdram0;
读出sdram0的寄存器<0x80000000 DT_SIZE_M(32)>
,CONFIG_SRAM_BASE_ADDRESS=0x80000000,CONFIG_SRAM_SIZE=32M
BOOTLOAD RAM
不会被配置
最后存储区域如下图
2. XIP从非0地址运行镜像
配置选项&设备树
配置选项1
2
3CONFIG_XIP=y
CONFIG_CODE_FLEXSPI=y
CONFIG_USE_DT_CODE_PARTITION=y
设备树覆盖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/ {
chosen {
zephyr,code-partition = &app_partition;
zephyr,sram = &ocram;
};
}
&flexspi {
reg = <0x402a8000 0x4000>, <0x60000000 DT_SIZE_M(8)>;
is25wp064: is25wp064@0 {
compatible = "nxp,imx-flexspi-nor";
size = <67108864>;
label = "IS25WP064";
reg = <0>;
spi-max-frequency = <133000000>;
status = "okay";
jedec-id = [9d 70 17];
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
boot_partition: partition@0 {
label = "bootloader";
reg = <0x00000000 DT_SIZE_K(128)>;
};
app_partition: partition@40000 {
label = "app";
reg = <0x00040000 DT_SIZE_M(6)>;
};
};
};
};
分析
FLASH
同前分析会从设备树节点flexspi读寄存器得到CONFIG_FLASH_BASE_ADDRESS=0x60000000, CONFIG_FLASH_SIZE=8M
FLASH LOAD
配置了CONFIG_USE_DT_CODE_PARTITION
,会从设备树节点zephyr,code-partition
读出,zephyr,code-partition
使用了app_partition
,也就是读出寄存器<0x00040000 DT_SIZE_M(6)>
,CONFIG_FLASH_LOAD_OFFSET=0x40000,CONFIG_FLASH_LOAD_SIZE=6M
SRAM
设备树中指定使用zephyr,sram = &ocram;
读出ocram的寄存器<0x20200000 DT_SIZE_K(768)>
,CONFIG_SRAM_BASE_ADDRESS=0x20200000,CONFIG_SRAM_SIZE=768K
BOOTLOAD RAM
不会被配置
最后存储区域如下图
3. 非XIP运行
配置选项&设备树
1 | CONFIG_XIP=n |
分析
FLASH
对于rt1062在soc/arm/nxp_imx/rt/Kconfig.defconfig.series
下会对其进行覆盖CONFIG_CODE_SEMC=y
配置了代码在SDRAM内,则从sdram的节点读取地址和大小:1
2
3
4
5
6
7
8
9if CODE_SEMC
config FLASH_SIZE
default $(dt_node_reg_size_int,/memory@80000000,0,K)
config FLASH_BASE_ADDRESS
default $(dt_node_reg_addr_hex,/memory@80000000)
endif # CODE_SEMC
可以从sdram0节点中读出CONFIG_FLASH_BASE_ADDRESS=0x80000000, CONFIG_FLASH_SIZE=32M
FLASH LOAD
没有进行相关配置CONFIG_FLASH_LOAD_OFFSET/CONFIG_FLASH_LOAD_SIZE
均为0
SRAM
设备树中指定使用zephyr,sram = &sdram0;
读出sdram0的寄存器<0x80000000 DT_SIZE_M(32)>
,CONFIG_SRAM_BASE_ADDRESS=0x80000000,CONFIG_SRAM_SIZE=32M
BOOTLOAD RAM
不会被配置
最后存储区域如下图
4. Bootloader+App 非XIP运行
Bootloader在Flash上XIP运行,将ocram作为SRAM
APP在ocram上运行,将ocram作为SRAM
bootload启动将Flash上的APP拷贝到ocram上运行
bootloader
配置为1
2
3
4
5CONFIG_XIP=y
CONFIG_CODE_FLEXSPI=y
CONFIG_USE_DT_CODE_PARTITION=y
CONFIG_BOOTLOADER_SRAM_SIZE=4
CONFIG_IS_BOOTLOADER=y
设备树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/ {
chosen {
zephyr,code-partition = &boot_partition;
zephyr,sram = &ocram;
};
}
&flexspi {
reg = <0x402a8000 0x4000>, <0x60000000 DT_SIZE_M(8)>;
is25wp064: is25wp064@0 {
compatible = "nxp,imx-flexspi-nor";
size = <67108864>;
label = "IS25WP064";
reg = <0>;
spi-max-frequency = <133000000>;
status = "okay";
jedec-id = [9d 70 17];
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
boot_partition: partition@0 {
label = "bootloader";
reg = <0x00000000 DT_SIZE_K(128)>;
};
app_partition: partition@20000 {
label = "app";
reg = <0x00040000 DT_SIZE_K(256)>;
};
};
};
};
按照前面的分析可以得到bootloader的信息
FLASH CONFIG_FLASH_BASE_ADDRESS=0x60000000, CONFIG_FLASH_SIZE=32M
FLASH LOADCONFIG_FLASH_LOAD_OFFSET=0, CONFIG_FLASH_LOAD_SIZE=128K
SRAM
设备树中指定使用zephyr,sram = &ocram;
读出dtcm的寄存器<0x20200000 DT_SIZE_K(768)>
,CONFIG_SRAM_BASE_ADDRESS=0x20200000,CONFIG_SRAM_SIZE=768K
BOOTLOAD RAMCONFIG_BOOTLOADER_SRAM_SIZE=4
为4K
App
配置为1
2
3CONFIG_XIP=n
CONFIG_CODE_FLEXSPI=n
CONFIG_BOOTLOADER_SRAM_SIZE=4
设备树1
2
3
4
5
6/ {
chosen {
zephyr,sram = &ocram;
zephyr,flash = &ocram;
};
}
参照前面的分析可以得到app的信息
FLASH
设备树中指定使用zephyr,sram = &ocram;
读出dtcm的寄存器<0x20200000 DT_SIZE_K(768)>
,CONFIG_FLASH_BASE_ADDRESS=0x20200000, CONFIG_FLASH_SIZE=768K
FLASH LOAD
没有进行相关配置CONFIG_FLASH_LOAD_OFFSET/CONFIG_FLASH_LOAD_SIZE
均为0
SRAM
设备树中指定使用zephyr,sram = &ocram;
读出dtcm的寄存器<0x20200000 DT_SIZE_K(768)>
,CONFIG_SRAM_BASE_ADDRESS=0x20200000,CONFIG_SRAM_SIZE=768K
BOOTLOAD RAM
CONFIG_BOOTLOADER_SRAM_SIZE=4
最后存储区域如下图