U-boot代碼層次
uboot需要支持眾多的硬件,并且具有良好的可擴展性、可移植性和可維護性,因此必須要有一個設計良好的代碼架構。代碼架構的設計總是與軟硬件架構密不可分的,在硬件層面嵌入式系統的核心一般包括以下層次:
(1)目標板:它包含了系統運行所需的所有組件,如SOC芯片、DDR、flash/emmc存儲器、各種外設以及時鐘源、電源管理芯片等
(2)SOC:它包含了cpu、總線控制器、集成在片內的rom、sram、dma控制器、硬件加速器、異構核,以及片內時鐘、電源控制模塊等
(3)處理器架構:它一般指處理器體系結構的大版本,不同的體系結構之間可能存在不同的指令集、異常模型以及內存模型等。例如對于arm系列架構,armv8和armv7就屬于不同的處理器架構
(4)cpu型號:它是指處理器的具體型號,如cortex-a53或cortex-a72等
一般cpu型號和處理器架構數量相對較少,如對于arm架構來說一般就是arm官方發布的這些型號。而soc型號就要多一些,它主要是各芯片公司基于特定cpu架構以及其它ip模塊,設計的專用或通用芯片,如高通或海思設計的手機芯片。最后就是以soc芯片為核心設計的目標板了,在目標板上基本上集成了一款產品所需的所有組件,如一款手機的電路板。它們之間的簡單關系如下圖:
Uboot的代碼設計也遵循以上層次,arch目錄包含了處理器架構相關代碼,arch/cpu目錄包含了特定cpu代碼,而board目錄則包含了特定目標板的代碼。因此當我們新增加一款目標板時,主要的工作就可以集中在board相關的代碼,只要不是太新的cpu型號,arch和cpu相關代碼在uboot官方版本中都已經被支持。因此可以直接復用這部分實現,我們唯一要做的就是選擇正確的配置選項。
如何添加board
添加board的基本步驟
當我們開始一個全新的項目時,總是希望能先讓系統能運行起來,然后再在此基礎上為其添加更多的feature,這個只包含能讓系統運行所需模塊的系統,叫做最小系統。cpu能正常運行包含以下幾個條件:
(1)具有合適的電源和時鐘
(2)程序代碼被加載到合適的位置,cpu能夠正常獲取指令
(3)具有cpu用于數據操作的可讀寫內存
(4)cpu被release reset 當然對于需要支持中斷的系統,則還需要包含中斷控制器,而對于像操作系統這種需要通過定時器驅動進程切換的系統,則顯然還需要timer定時器。為了達到以上目的,我們添加board的基本步驟大概如下: (1)在board目錄下為新board添加一個目錄,用于存放board特定的代碼
(2)為新目錄添加Kconfig配置選項和Makefile編譯選項,將其添加到編譯系統中
(3)在Kconfig中為該board定義一個配置項,并為該配置項添加其所支持的特性,如cpu架構、cpu型號等
(4)為新board增加一個配置相關的頭文件和編譯所需的defconfig文件,用于該board相關的選項配置
(5)在board目錄下添加適當的文件,并實現必要的接口
test board添加示例
添加target配置選項
- 在arch/arm/Kconfig的board select菜單下新增如下的TARGET_TESTBOARD配置選項:
config TARGET_TESTBOARD
bool "Qemu test board"
select ARM64
select DM
select DM_SERIAL
select PL01X_SERIAL
select SUPPORT_SPL
select SPL if SUPPORT_SPL
select SPL_FRAMEWORK_BOARD_INIT_F if SPL
select SPL_SERIAL_SUPPORT
select PL011_SERIAL if SPL
select SPL_LIBGENERIC_SUPPORT if SPL
select SPL_LIBCOMMON_SUPPORT if SPL
它將在后面的configs/testboard_defconfig中通過CONFIG_ TARGET_TESTBOARD =y選擇
- 在arch/arm/Kconfig文件中添加以下內容,以包含board的Kconfig文件
source "board/mars/test/Kconfig"
添加config頭文件
在include/configs目錄下添加config頭文件testboard.h,并添加以下內容:
#ifndef __CONFIG_H
#define __CONFIG_H
#include
#define CONFIG_SYS_SDRAM_BASE 0x40000000
/* The DTB generated by QEMU is placed at start of RAM, stay away from there */
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + SZ_2M)
#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + SZ_2M)
#define CONFIG_SYS_MALLOC_LEN SZ_16M
#define CONFIG_SYS_BOOTM_LEN SZ_64M
#define CONFIG_SYS_HZ 1000
#define CONFIG_PL01x_PORTS {(void *)(0x9000000)}
#define CONFIG_PL011_CLOCK 1
#define CONFIG_SYS_UBOOT_START 0x40300000
#define BOOT_TARGET_DEVICES(func) \\
func(VIRTIO, virtio, 0)
#define CONFIG_EXTRA_ENV_SETTINGS \\
"fdt_addr=0x43000000\\0" \\
"kernel_addr_r=0x40000000\\0" \\
"bootargs=earlycon root=/dev/vda\\0" \\
"bootcmd=smhload /home/lgj/work/linux/arch/arm64/boot/Image ${kernel_addr_r};" \\
"smhload /home/lgj/work/linux/arch/arm64/boot/dts/qemu/test-board-smc.dtb ${fdt_addr};" \\
"booti ${kernel_addr_r} - ${fdt_addr}\\0"
#define CONFIG_SYS_CBSIZE 512
#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE
#define CONFIG_SYS_MAX_FLASH_BANKS_DETECT 2
#define CONFIG_SYS_MAX_FLASH_SECT 256 /* Sector: 256K, Bank: 64M */
#define CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS
#define CONFIG_SPL_MAX_SIZE 0x25000
#define CONFIG_SPL_STACK (CONFIG_SYS_SDRAM_BASE + SZ_1M)
#define CONFIG_SPL_BSS_START_ADDR (CONFIG_SYS_SDRAM_BASE + SZ_1M)
#define CONFIG_SPL_BSS_MAX_SIZE 0x1000
#endif
添加dtb文件
使用qemu模擬器啟動uboot時,模擬器會提供一個默認的dtb文件,但是我們也可以使用自己自定義的dtb文件,以下是自定義dtb文件的方法:
- 在arch/arm/dts/目錄下添加dts文件test-board-minimal.dts,并在目錄的Makefile中添加以下編譯選項
dtb-$(CONFIG_TARGET_TESTBOARD) += test-board-minimal.dtb
- 在配置文件configs/testboard_defconfig中指定該dtb為默認dtb文件,并使能uboot的設備樹支持
CONFIG_DEFAULT_DEVICE_TREE="test-board-minimal"
CONFIG_OF_CONTROL=y
CONFIG_OF_SEPARATE=y
添加board文件
- 在board目錄下創建mars/test目錄
- 在board/mars/test目錄下創建Kconfig文件,并添加如下內容
if TARGET_TESTBOARD
config SYS_VENDOR
default "mars"
config SYS_BOARD
default "test"
config SYS_CONFIG_NAME
default "testboard"
endif
其中:
SYS_VENDOR:用于指定該board的vendor名,它與SYS_BOARD一起確定會被編譯的board代碼路徑。即board/< SYS_VENDOR >/common和board/< SYS_VENDOR >/< SYS_BOARD >的路徑下的Makefile會被執行,在我們的例子中該目錄為board/mars/common/和board/mars/test/SYS_BOARD:用于指定在board/< SYS_VENDOR >下需要編譯的board路徑,如當前配置下該目錄為board/mars/test/
SYS_CONFIG_NAME用于指定include/configs目錄下的頭文件名,如當前配置該文件即為include/configs/testboard.h
- 在board/mars/test目錄下創建MAINTAINERS文件,并添加如下內容
QEMU QEMU TEST BOARD
M: xxx@yyy.com
S: Maintained
F: board/mars/test
F: include/configs/testboard.h
F: configs/testboard.h
- 在board/mars/test目錄下創建Makefile文件,并添加如下內容
obj-y += testboard.o
- 創建board/mars/test目錄下創建testboard.c文件,并添加如下內容
include
#include
#include
#include
#include
#ifdef CONFIG_ARM64
#include
static struct mm_region testboard_mem_map[] = {
{
/* Flash */
.virt = 0x00000000UL,
.phys = 0x00000000UL,
.size = 0x08000000UL,
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
PTE_BLOCK_INNER_SHARE
}, {
/* Lowmem peripherals */
.virt = 0x08000000UL,
.phys = 0x08000000UL,
.size = 0x38000000,
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
PTE_BLOCK_NON_SHARE |
PTE_BLOCK_PXN | PTE_BLOCK_UXN
}, {
/* RAM */
.virt = 0x40000000UL,
.phys = 0x40000000UL,
.size = 255UL * SZ_1G,
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
PTE_BLOCK_INNER_SHARE
}, {
/* Highmem PCI-E ECAM memory area */
.virt = 0x4010000000ULL,
.phys = 0x4010000000ULL,
.size = 0x10000000,
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
PTE_BLOCK_NON_SHARE |
PTE_BLOCK_PXN | PTE_BLOCK_UXN
}, {
/* Highmem PCI-E MMIO memory area */
.virt = 0x8000000000ULL,
.phys = 0x8000000000ULL,
.size = 0x8000000000ULL,
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
PTE_BLOCK_NON_SHARE |
PTE_BLOCK_PXN | PTE_BLOCK_UXN
}, {
/* List terminator */
0,
}
};
struct mm_region *mem_map = testboard_mem_map;
#endif
int board_init(void)
{
return 0;
}
int dram_init(void)
{
if (fdtdec_setup_mem_size_base() != 0)
return -EINVAL;
return 0;
}
int dram_init_banksize(void)
{
fdtdec_setup_memory_banksize();
return 0;
}
void *board_fdt_blob_setup(void)
{
/* QEMU loads a generated DTB for us at the start of RAM. */
return (void *)CONFIG_SYS_SDRAM_BASE;
}
void enable_caches(void)
{
icache_enable();
dcache_enable();
}
#ifdef CONFIG_SPL
u32 spl_boot_device(void)
{
return BOOT_DEVICE_SEMIHOSTING;
}
#endif
創建defconfig配置文件
在configs目錄下為testboard創建配置文件testboard_defconfig,并添加如下內容
CONFIG_ARM=y
CONFIG_TARGET_TESTBOARD=y
CONFIG_POSITION_INDEPENDENT=y
CONFIG_NR_DRAM_BANKS=1
CONFIG_ENV_SIZE=0x40000
CONFIG_ENV_SECT_SIZE=0x40000
CONFIG_DEFAULT_DEVICE_TREE="test-board-minimal"
CONFIG_ENV_ADDR=0x4000000
CONFIG_OF_CONTROL=y
CONFIG_OF_SEPARATE=y
CONFIG_DM_SERIAL=y
CONFIG_DM_ETH=y
CONFIG_SYSRESET=y
CONFIG_SEMIHOSTING=y
# add boot stage info to fdt
CONFIG_OF_FDT=y
CONFIG_SPL_SYS_MALLOC_F_LEN=0x1000
CONFIG_SPL_TEXT_BASE=0x40000000
CONFIG_CONS_INDEX=0
CONFIG_SYS_TEXT_BASE=0x40300000
# CONFIG_DISPLAY_CPUINFO is not set
spl支持semihost啟動
- 將arch/arm/lib/semihosting.c中smh_load_file導出,即去掉下面定義中的static
static int smh_load_file(const char * const name, ulong load_addr, ulong *end_addr)
{
…
}
- 將arch/arm/lib/semihosting.c中的do_smhload文件修改為只有uboot編譯,即將其修改為:
#ifndef CONFIG_SPL_BUILD
static int do_smhload(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]) {
}
#endif
- 在arch/arm/include/asm/spl.h的BOOT DEVICE枚舉中添加對semihosting的支持
enum {
…
BOOT_DEVICE_SEMIHOSTING,
BOOT_DEVICE_NONE
};
- 在common/spl/目錄下添加文件spl_semihosting.c,并添加以下內容:
#include
#include
extern int smh_load_file(const char * const name, ulong load_addr,
ulong *end_addr);
static int spl_sh_load_image(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev)
{
int rc;
ulong uboot_load_addr = 0x40300000, uboot_end_addr;
rc = smh_load_file("u-boot.bin", uboot_load_addr,
&uboot_end_addr);
if (rc < 0) {
if (CONFIG_IS_ENABLED(SHOW_ERRORS) &&
CONFIG_IS_ENABLED(LIBCOMMON_SUPPORT))
printf(SPL_TPL_PROMPT "load file u-boot.bin failed (err=%d)\\n",
rc);
else
puts(SPL_TPL_PROMPT "load file u-boot.bin failed\\n");
return -1;
}
spl_image->load_addr = uboot_load_addr;
spl_image->entry_point = uboot_load_addr;
spl_image->os = IH_OS_U_BOOT;
return 0;
}
SPL_LOAD_IMAGE_METHOD("SEMIHOSTING", 0, BOOT_DEVICE_SEMIHOSTING, spl_sh_load_image);
-
soc
+關注
關注
38文章
4204瀏覽量
219099 -
u-boot
+關注
關注
0文章
121瀏覽量
38315 -
代碼
+關注
關注
30文章
4827瀏覽量
69054 -
board
+關注
關注
0文章
37瀏覽量
19804
發布評論請先 登錄
相關推薦
U-boot的基本介紹
![<b class='flag-5'>U-boot</b>的基本介紹](https://file1.elecfans.com/web2/M00/8C/C4/wKgaomSxDC-AIi1QAACKegMzhAU876.png)
U-Boot的啟動及移植分析
Porting U-Boot to the Control
u-boot的Makefile分析
u-boot簡介
U-Boot架構淺析
![<b class='flag-5'>U-Boot</b>架構淺析](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
評論