IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> imx6ul开发板移植主线u-boot -> 正文阅读

[系统运维]imx6ul开发板移植主线u-boot

首先下载U-Boot源码,然后查看有的配置文件,我们这里使用configs/imx6ul_isiot_nand_defconfig文件作为配置文件使用,然后使用如下命令进行编译,

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx6ul_isiot_emmc_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j8

编译完成后u-boot-with-spl.imx即为我们的文件

在这里插入图片描述
然后通过烧录工具mfgtools进行烧录,完蛋,发现NAND版本的根本就无法启动。EMMC正常启动到U-Boot。在这里插入图片描述
然后打开debug打印,打开方式如下。

diff --git a/u-boot/include/log.h b/u-boot/include/log.h
index e0e12ce19..8c6f98af7 100644
--- a/u-boot/include/log.h
+++ b/u-boot/include/log.h
@@ -240,7 +240,7 @@ int _log_buffer(enum log_category_t cat, enum log_level_t level,
        _log_nop((enum log_category_t)(_cat), _l, __FILE__, __LINE__, \
                      __func__, pr_fmt(_fmt), ##_args); \
 })
-
+#define DEBUG
 #ifdef DEBUG
 #define _DEBUG 1
 #else

重新运行,可以看到,应该是没有正确读取到对应的U-Boot镜像,对比EMMC启动,相差点打印信息。

oobsize=64
chipsize=d
in func nand_spl_load_image : offset:0x00200000 len:64 page:400
else start spl_parse_image_header
mkimage signature not found - ih_magic = ffffffff
in last do nand_spl_load_image
in func nand_spl_load_image : offset:0x00200000 len:204800 page:400
in func is_badblock: offs=0x00220000 block:17 page:1088
zxy Jumping to U-Boot...
in func board_init_r do start spl_board_prepare_for_boot
in __weak void spl_board_prepare_for_boot
zxy image entry point: 0x87800000

然后就开始追踪看下代码处理过程,主要执行的函数如下所示,在文件common/spl/spl.c中执行。

void board_init_r(gd_t *dummy1, ulong dummy2)
{
        u32 spl_boot_list[] = {
                BOOT_DEVICE_NONE,
                BOOT_DEVICE_NONE,
                BOOT_DEVICE_NONE,
                BOOT_DEVICE_NONE,
                BOOT_DEVICE_NONE,
        };
        struct spl_image_info spl_image;
        int ret;

        debug("zxy >>" SPL_TPL_PROMPT "board_init_r()\n");

        spl_set_bd();

#if defined(CONFIG_SYS_SPL_MALLOC_START)
        mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
                        CONFIG_SYS_SPL_MALLOC_SIZE);
        gd->flags |= GD_FLG_FULL_MALLOC_INIT;
#endif
        if (!(gd->flags & GD_FLG_SPL_INIT)) {
                if (spl_init())
                        hang();
        }
#if !defined(CONFIG_PPC) && !defined(CONFIG_ARCH_MX6)
        /*
         * timer_init() does not exist on PPC systems. The timer is initialized
         * and enabled (decrementer) in interrupt_init() here.
         */
        timer_init();
#endif
        if (CONFIG_IS_ENABLED(BLOBLIST)) {
                ret = bloblist_init();
                if (ret) {
                        debug("%s: Failed to set up bloblist: ret=%d\n",
                              __func__, ret);
                        puts(SPL_TPL_PROMPT "Cannot set up bloblist\n");
                        hang();
                }
        }
        if (CONFIG_IS_ENABLED(HANDOFF)) {
                int ret;

                ret = setup_spl_handoff();
                if (ret) {
                        puts(SPL_TPL_PROMPT "Cannot set up SPL handoff\n");
                        hang();
                }
        }

#if CONFIG_IS_ENABLED(BOARD_INIT)
        spl_board_init();
#endif

#if defined(CONFIG_SPL_WATCHDOG) && CONFIG_IS_ENABLED(WDT)
        initr_watchdog();
#endif

        if (IS_ENABLED(CONFIG_SPL_OS_BOOT) || CONFIG_IS_ENABLED(HANDOFF) ||
            IS_ENABLED(CONFIG_SPL_ATF))
                dram_init_banksize();

        bootcount_inc();

        memset(&spl_image, '\0', sizeof(spl_image));
#ifdef CONFIG_SYS_SPL_ARGS_ADDR
        spl_image.arg = (void *)CONFIG_SYS_SPL_ARGS_ADDR;
        printf("spl_image.arg  = 0x%08x",spl_image.arg);
#endif
        spl_image.boot_device = BOOT_DEVICE_NONE;
        board_boot_order(spl_boot_list);

        ret = boot_from_devices(&spl_image, spl_boot_list,
                                ARRAY_SIZE(spl_boot_list));
        if (ret) {
                if (CONFIG_IS_ENABLED(SHOW_ERRORS) &&
                    CONFIG_IS_ENABLED(LIBCOMMON_SUPPORT))
                        printf(SPL_TPL_PROMPT "failed to boot from all boot devices (err=%d)\n",
                               ret);
                else
                        puts(SPL_TPL_PROMPT "failed to boot from all boot devices\n");
                hang();
        }
         spl_perform_fixups(&spl_image);
        if (CONFIG_IS_ENABLED(HANDOFF)) {
                ret = write_spl_handoff();
                if (ret)
                        printf(SPL_TPL_PROMPT
                               "SPL hand-off write failed (err=%d)\n", ret);
        }
        if (CONFIG_IS_ENABLED(BLOBLIST)) {
                ret = bloblist_finish();
                if (ret)
                        printf("Warning: Failed to finish bloblist (ret=%d)\n",
                               ret);
        }

#ifdef CONFIG_CPU_V7M
        spl_image.entry_point |= 0x1;
#endif
        switch (spl_image.os) {
        case IH_OS_U_BOOT:
                debug("zxy Jumping to %s...\n", spl_phase_name(spl_next_phase()));
                break;
#if CONFIG_IS_ENABLED(ATF)
        case IH_OS_ARM_TRUSTED_FIRMWARE:
                debug("Jumping to U-Boot via ARM Trusted Firmware\n");
                spl_fixup_fdt(spl_image.fdt_addr);
                spl_invoke_atf(&spl_image);
                break;
#endif
#if CONFIG_IS_ENABLED(OPTEE_IMAGE)
        case IH_OS_TEE:
                debug("Jumping to U-Boot via OP-TEE\n");
                spl_board_prepare_for_optee(spl_image.fdt_addr);
                jump_to_image_optee(&spl_image);
                break;
#endif
#if CONFIG_IS_ENABLED(OPENSBI)
        case IH_OS_OPENSBI:
                debug("Jumping to U-Boot via RISC-V OpenSBI\n");
                spl_invoke_opensbi(&spl_image);
                break;
#endif
#if CONFIG_IS_ENABLED(OS_BOOT)
        case IH_OS_LINUX:
                debug("Jumping to Linux\n");
#if defined(CONFIG_SYS_SPL_ARGS_ADDR)
                spl_fixup_fdt((void *)CONFIG_SYS_SPL_ARGS_ADDR);
#endif
                spl_board_prepare_for_linux();
                jump_to_image_linux(&spl_image);
#endif
        default:
                debug("Unsupported OS image.. Jumping nevertheless..\n");
        }
        #if CONFIG_VAL(SYS_MALLOC_F_LEN) && !defined(CONFIG_SYS_SPL_MALLOC_SIZE)
        debug("SPL malloc() used 0x%lx bytes (%ld KB)\n", gd->malloc_ptr,
              gd->malloc_ptr / 1024);
#endif
        bootstage_mark_name(get_bootstage_id(false), "end phase");
#ifdef CONFIG_BOOTSTAGE_STASH
        ret = bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH_ADDR,
                              CONFIG_BOOTSTAGE_STASH_SIZE);
        if (ret)
                debug("Failed to stash bootstage: err=%d\n", ret);
#endif

        printf("in func %s do start spl_board_prepare_for_boot\n",__func__);
        spl_board_prepare_for_boot();
        jump_to_image_no_args(&spl_image);
}

针对以上,梳理下执行流程,因为我们是无法跳转到U-Boot执行,所以我们重点是去看SPL阶段,是如何去加载NAND中的U-Boot镜像文件的。
最重要的数据就是结构体变量struct spl_image_info spl_image;,所以我们只需要追踪下这个数据的来源,以及赋值即可。

结构体定义如下
struct spl_image_info {
        const char *name;
        u8 os;
        uintptr_t load_addr;
        uintptr_t entry_point;
#if CONFIG_IS_ENABLED(LOAD_FIT) || CONFIG_IS_ENABLED(LOAD_FIT_FULL)
        void *fdt_addr;
#endif
        u32 boot_device;
        u32 offset;
        u32 size;
        u32 flags;
        void *arg;
#ifdef CONFIG_SPL_LEGACY_IMAGE_CRC_CHECK
        ulong dcrc_data;
        ulong dcrc_length;
        ulong dcrc;
#endif
};
memset(&spl_image, '\0', sizeof(spl_image));  //首先清空结构体变量
spl_image.boot_device = BOOT_DEVICE_NONE; //然后给启动设备赋空值
board_boot_order(spl_boot_list); //主要是对spl_boot_list数组第一个元素赋值。展开如下
__weak void board_boot_order(u32 *spl_boot_list)
{
        spl_boot_list[0] = spl_boot_device();
} //这里我们不深究,到时候直接把结果打印出来即可
ret = boot_from_devices(&spl_image, spl_boot_list,
                                ARRAY_SIZE(spl_boot_list)); //这里展开为如下内容

static int boot_from_devices(struct spl_image_info *spl_image,
                             u32 spl_boot_list[], int count)
{
        int ret = -ENODEV;
        int i;

        for (i = 0; i < count && spl_boot_list[i] != BOOT_DEVICE_NONE; i++) { //这里因为我们只有修改过第一个数组元素,
                struct spl_image_loader *loader;                                                     //所以这里只会循环一次
                int bootdev = spl_boot_list[i];
                loader = spl_ll_find_loader(bootdev); //重点执行函数
                if (CONFIG_IS_ENABLED(SERIAL) &&
                    CONFIG_IS_ENABLED(LIBCOMMON_SUPPORT) &&
                    !IS_ENABLED(CONFIG_SILENT_CONSOLE)) {
                        if (loader)
                                printf("Trying to boot from %s\n",
                                       spl_loader_name(loader));
                        else if (CONFIG_IS_ENABLED(SHOW_ERRORS))
                                printf(SPL_TPL_PROMPT
                                       "Unsupported Boot Device %d\n", bootdev);
                        else
                                puts(SPL_TPL_PROMPT "Unsupported Boot Device!\n");
                }
                if (loader && !spl_load_image(spl_image, loader)) {
                        spl_image->boot_device = bootdev;
                        return 0;
                }
        }

        return ret;
}

我们接着看一下函数spl_ll_find_loader

static struct spl_image_loader *spl_ll_find_loader(uint boot_device)
{
        struct spl_image_loader *drv =
                ll_entry_start(struct spl_image_loader, spl_image_loader);
        const int n_ents =
                ll_entry_count(struct spl_image_loader, spl_image_loader);
        struct spl_image_loader *entry;

        for (entry = drv; entry != drv + n_ents; entry++) {
                if (boot_device == entry->boot_device)
                        return entry;
        }

        /* Not found */
        return NULL;
}
//其中ll_entry_start展开如下,其实就是找到u_boot_list_2_spl_image_loader_1这个段的起始,定义在include/linker_lists.h文件中
static char start[0] __aligned(CONFIG_LINKER_LIST_ALIGN)__attribute__((unused))__section(".u_boot_list_2_spl_image_loader_1");                 
        (spl_image_loader *)&start;
可以通过查看u-boot-spl.map文件查找到对应的段内容

在这里插入图片描述

其实就是找到两个值的变化值,
#define ll_entry_count(_type, _list)                                    \
        ({                                                              \
                _type *start = ll_entry_start(_type, _list);            \
                _type *end = ll_entry_end(_type, _list);                \
                unsigned int _ll_result = end - start;                  \
                _ll_result;                                             \
        })

所以再来看如下的函数,其实就好分析了。

//通过进一步的分析,我们可以知道,实际上定义这个section并进行添加的是SPL_LOAD_IMAGE_METHOD
//vim 宏定义在文件include/spl.h中
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
#define SPL_LOAD_IMAGE_METHOD(_name, _priority, _boot_device, _method) \
        SPL_LOAD_IMAGE(_boot_device ## _priority ## _method) = { \
                .name = _name, \
                .boot_device = _boot_device, \
                .load_image = _method, \
        }
那么我们在common/spl/spl_nand.c中定义的宏SPL_LOAD_IMAGE_METHOD("NAND", 1, BOOT_DEVICE_NAND, spl_nand_load_image);,展开后就是

#define SPL_LOAD_IMAGE(__name)                                  \
        ll_entry_declare(struct spl_image_loader, __name, spl_image_loader)
		
		#define ll_entry_declare(_type, _name, _list)                           \
        _type _u_boot_list_2_##_list##_2_##_name __aligned(4)           \
                        __attribute__((unused))                         \
                        __section(".u_boot_list_2_"#_list"_2_"#_name)

static struct spl_image_loader *spl_ll_find_loader(uint boot_device)
{
        struct spl_image_loader *drv =
                ll_entry_start(struct spl_image_loader, spl_image_loader);
        const int n_ents =
                ll_entry_count(struct spl_image_loader, spl_image_loader); //得到和,只有一个
        struct spl_image_loader *entry;

        for (entry = drv; entry != drv + n_ents; entry++) {
                if (boot_device == entry->boot_device)
                        return entry; 
        }
//所以这里找到的对应的文件就是
SPL_LOAD_IMAGE_METHOD("NAND", 1, BOOT_DEVICE_NAND, spl_nand_load_image);
entry->name = "NAND"
entry->boot_device = BOOT_DEVICE_NAND
entry->load_image = spl_nand_load_image;后面就是操作这个函数。
        /* Not found */
        return NULL;
}

//结构体定义如下
struct spl_image_loader {
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
        const char *name;
#endif
        uint boot_device;
        int (*load_image)(struct spl_image_info *spl_image,
                          struct spl_boot_device *bootdev);
};

然后执行函数

static inline const char *spl_loader_name(const struct spl_image_loader *loader)
{
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
        return loader->name;
#else
        return NULL;
#endif
}

其实就是返回一个字符串

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-04-15 00:46:32  更:2022-04-15 00:47:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 21:49:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码