ARM Fast Model下 u-boot调试(四)---加载调试

目录

关闭u-boot编译优化

在FVP上加载u-boot

FVP加载u-boot失败的问题

u-boot运行调试

找不到telnet的问题

autoboot的问题

找不到smc911x的问题

总结

附录


        这篇文章记录u-boot加载调试的过程,包括ds的使用方法,fvp的使用方法,以及u-boot的修改点等。

关闭u-boot编译优化

        代码编译的过程中如果开了优化选项,则编译出来的程序在加载之后,关联源码,就会出现在C源代码单步的时候出现乱跳,而不是一行一行的单步运行。为了方便我们后面单步调试,观察代码的运行情况,需要关闭u-boot的编译优化选项。

        在u-boot源码根目录下的Makefile文件搜索“-O‘”,搜索到下面的代码:将下面的-Os和-O2都修改成-O0。

ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS   += -Os
else
KBUILD_CFLAGS   += -O2
endif

        重新编译:Make V=1(V=1,有了这个参数,make的时候就会将编译的所有细节,包括所有文件的编译选项,能让我们了解到编译的详细细节)。

        编译出现错误:

  arm-linux-gnueabi-gcc -Wp,-MD,cmd/.bootefi.o.d  -nostdinc -isystem /home/ubuntu/u-boot/code/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabi/bin/../lib/gcc/arm-linux-gnueabi/6.2.1/include -Iinclude   -I./arch/arm/include -include ./include/linux/kconfig.h -D__KERNEL__ -D__UBOOT__ -Wall -Wstrict-prototypes -Wno-format-security -fno-builtin -ffreestanding -O0 -fno-stack-protector -fno-delete-null-pointer-checks -g -fstack-usage -Wno-format-nonliteral -Werror=date-time -D__ARM__ -marm -mno-thumb-interwork -mabi=aapcs-linux -mword-relocations -fno-pic -mno-unaligned-access -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -msoft-float -pipe -march=armv7-a -D__LINUX_ARM_ARCH__=7    -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(bootefi)"  -D"KBUILD_MODNAME=KBUILD_STR(bootefi)" -c -o cmd/bootefi.o cmd/bootefi.c
cmd/bootefi.c: In function 'do_bootefi_exec':
cmd/bootefi.c:230:1: error: fp cannot be used in asm here

        为了解决这个问题,需要修改Makefile,如下所示:增加了编译选项-fomit-frame-pointer,修改之后u-boot编译成功。

ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS   += -O0
KBUILD_CFLAGS   += -fomit-frame-pointer
else
KBUILD_CFLAGS   += -O0
KBUILD_CFLAGS   += -fomit-frame-pointer
endif

在FVP上加载u-boot

        按照前面文章的介绍,使能multipass下的mount功能(虚拟机关机之后重启,需要重新配置),然后重新mount一下共享目录,将u-boot根目录下的文件:u-boot(这是elf格式的编译产物,包含了debug调试信息)拷贝到windows下,并将u-boot的源码解压一份,用来单步调试的时候关联源码。

        按照下图所示,指定加载文件,以及FVP连接之后pc寄存器的初值:

        

FVP加载u-boot失败的问题

 连接FVP之后出现错误,如下图所示:

 分析一下u-boot的section信息,看看加载段都有哪些:

ubuntu@vm01:~/u-boot/code/u-boot-2016.11$ arm-linux-gnueabi-objdump -h u-boot

u-boot:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0005bcbc  60800000  60800000  00010000  2**5
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .rodata       0000dab6  6085bcc0  6085bcc0  0006bcc0  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .hash         00000018  60869778  60869778  00079778  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .data         00001c78  60869790  60869790  00079790  2**3
                  CONTENTS, ALLOC, LOAD, DATA
  4 .got.plt      0000000c  6086b408  6086b408  0007b408  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  5 .u_boot_list  00000774  6086b414  6086b414  0007b414  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  6 .efi_runtime  00000130  6086bb88  6086bb88  0007bb88  2**3
                  CONTENTS, ALLOC, LOAD, CODE
  7 .dynsym       00000030  60874200  60874200  00084200  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .efi_runtime_rel 00000090  6086bcb8  6086bcb8  0007bcb8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rel.dyn      000084b8  6086bd48  6086bd48  0007bd48  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .bss_start    00000000  6086bd48  6086bd48  000842d0  2**2
                  CONTENTS
 11 .bss          0003775c  6086bd48  6086bd48  00000000  2**6
                  ALLOC
 12 .bss_end      00000000  608a34a4  608a34a4  000842d0  2**2
                  CONTENTS
 13 .dynstr       00000001  60874230  60874230  00084230  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

        从上面可以看出,.text段的加载地址是0x60800000,那我们看看FVP手册里的memory map,看看0x60800000这个地址对应的是什么设备的内存:可以看出0x60800000对应的设备是Ext AXI,这个不是DDR或者其他存储设备,真正的DDR空间是从蓝色方框标注的0x80000000开始的。

        接下来我们走查一下u-boot的代码,看看u-boot的.text的地址是怎么指定的:可以看出在vexpress_ca9x4.h文件中定义了宏CONFIG_VEXPRESS_ORIGINAL_MEMORY_MAP,导致在vexpress_common.h文件中V2M_PA_CS0的基地址是0x40000000,而实际上我们使用的FVP模型VE Cortext-A9x1的memory map显示DDR基地址是0x80000000;

        所以应该将vexpress_ca9x4.h中的宏定义修改成:CONFIG_VEXPRESS_EXTENDED_MEMORY_MAP

u-boot-2016.11\include\configs\vexpress_ca9x4.h

/*
 * (C) Copyright 2011 Linaro
 * Ryan Harkin, <ryan.harkin@linaro.org>
 *
 * Configuration for Versatile Express. Parts were derived from other ARM
 *   configurations.
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#ifndef __VEXPRESS_CA9X4_H
#define __VEXPRESS_CA9X4_H

#define CONFIG_VEXPRESS_ORIGINAL_MEMORY_MAP
#include "vexpress_common.h"

#endif /* VEXPRESS_CA9X4_H */

 u-boot-2016.11\include\configs\vexpress_common.h

/*
 * Definitions copied from linux kernel:
 * arch/arm/mach-vexpress/include/mach/motherboard.h
 */
#ifdef CONFIG_VEXPRESS_ORIGINAL_MEMORY_MAP
/* CS register bases for the original memory map. */
#define V2M_PA_CS0		0x40000000
#define V2M_PA_CS1		0x44000000
#define V2M_PA_CS2		0x48000000
#define V2M_PA_CS3		0x4c000000
#define V2M_PA_CS7		0x10000000

#define V2M_PERIPH_OFFSET(x)	(x << 12)
#define V2M_SYSREGS		(V2M_PA_CS7 + V2M_PERIPH_OFFSET(0))
#define V2M_SYSCTL		(V2M_PA_CS7 + V2M_PERIPH_OFFSET(1))
#define V2M_SERIAL_BUS_PCI	(V2M_PA_CS7 + V2M_PERIPH_OFFSET(2))

#define V2M_BASE		0x60000000
#define CONFIG_SYS_TEXT_BASE	0x60800000
#elif defined(CONFIG_VEXPRESS_EXTENDED_MEMORY_MAP)
/* CS register bases for the extended memory map. */
#define V2M_PA_CS0		0x08000000
#define V2M_PA_CS1		0x0c000000
#define V2M_PA_CS2		0x14000000
#define V2M_PA_CS3		0x18000000
#define V2M_PA_CS7		0x1c000000

        按照下面的方法进行修改之后,再重新编译:

#ifndef __VEXPRESS_CA9X4_H
#define __VEXPRESS_CA9X4_H

/*#define CONFIG_VEXPRESS_ORIGINAL_MEMORY_MAP*/
#define CONFIG_VEXPRESS_EXTENDED_MEMORY_MAP
#include "vexpress_common.h"

#endif /* VEXPRESS_CA9X4_H */

        使用重新编译之后的产物进行加载:可以看到加载成功,pc指向了elf文件的entry point,且自动关联了u-boot的源码;

        能自动关联,一是因为我将编译产物u-boot和解压后的源码放在了同一个目录下,另外一个是因为我在指定加载文件的时候,将符号加载的选项也打了勾,二者缺一不可。

        如果加载文件与源码没有放在同一个目录下,汇编不能自动关联源码的话,需要你在汇编视图中右键单击,选择show in source,它会弹出窗口让你选择源码的实际路径(前提是要你加载了符号表)。

u-boot运行调试

找不到telnet的问题

        点击运行之后出现弹出窗口,提示有错误:这是因为FVP下的串口是模拟出来的,模拟的串口实际上需要通过telnet去登录对应的port(模型上有多个串口,每个串口对应一个port),这里出错是因为win10下默认没有打开telnet服务。

        使用win+R键打开运行程序,在输入框里输入:OptionalFeatures点击确定;

        勾选上Telnet客户端并点击确定,就会开始安装telnet客户端;

autoboot的问题

        下面运行之后在telnet窗口(实际上是模拟的串口),可以看到没有倒计时就直接autoboot了;   


U-Boot 2016.11 (May 09 2022 - 22:50:00 +0800)

DRAM:  1 GiB
WARNING: Caches not enabled
Flash: 128 MiB
MMC:   MMC: 0
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   smc911x: Invalid chip endian 0x00000000
No ethernet found.
Hit any key to stop autoboot:  0
MMC Device 1 not found
no mmc device at slot 1
Card did not respond to voltage select!
No ethernet found.
missing environment variable: pxeuuid
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/00000000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/0000000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/000000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/00000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/0000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/000
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/00
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/0
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/default-arm
No ethernet found.
missing environment variable: bootfile
Retrieving file: pxelinux.cfg/default
No ethernet found.
Config file not found
No ethernet found.
No ethernet found.
Wrong Image Format for bootm command
ERROR: can't get kernel image!
=>

        接下来要走查u-boot的代码,看看怎么设置一下等待时间,设置成5-10秒:

 u-boot-2016.11\common\main.c

/* We come here after U-Boot is initialised and ready to process commands */
void main_loop(void)
{
	const char *s;

	bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");

#ifdef CONFIG_VERSION_VARIABLE
	setenv("ver", version_string);  /* set version variable */
#endif /* CONFIG_VERSION_VARIABLE */

	cli_init();

	run_preboot_environment_command();

#if defined(CONFIG_UPDATE_TFTP)
	update_tftp(0UL, NULL, NULL);
#endif /* CONFIG_UPDATE_TFTP */

	s = bootdelay_process();
	if (cli_process_fdt(&s))
		cli_secure_boot_cmd(s);

	autoboot_command(s);

	cli_loop();
	panic("No CLI available");
}

 u-boot-2016.11\common\autoboot.c

const char *bootdelay_process(void)
{
	char *s;
	int bootdelay;
#ifdef CONFIG_BOOTCOUNT_LIMIT
	unsigned long bootcount = 0;
	unsigned long bootlimit = 0;
#endif /* CONFIG_BOOTCOUNT_LIMIT */

#ifdef CONFIG_BOOTCOUNT_LIMIT
	bootcount = bootcount_load();
	bootcount++;
	bootcount_store(bootcount);
	setenv_ulong("bootcount", bootcount);
	bootlimit = getenv_ulong("bootlimit", 10, 0);
#endif /* CONFIG_BOOTCOUNT_LIMIT */

	s = getenv("bootdelay");
	bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;

#ifdef CONFIG_OF_CONTROL
	bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay",
			bootdelay);
#endif

	debug("### main_loop entered: bootdelay=%d\n\n", bootdelay);

#if defined(CONFIG_MENU_SHOW)
	bootdelay = menu_show(bootdelay);
#endif
	bootretry_init_cmd_timeout();

#ifdef CONFIG_POST
	if (gd->flags & GD_FLG_POSTFAIL) {
		s = getenv("failbootcmd");
	} else
#endif /* CONFIG_POST */
#ifdef CONFIG_BOOTCOUNT_LIMIT
	if (bootlimit && (bootcount > bootlimit)) {
		printf("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
		       (unsigned)bootlimit);
		s = getenv("altbootcmd");
	} else
#endif /* CONFIG_BOOTCOUNT_LIMIT */
		s = getenv("bootcmd");

	process_fdt_options(gd->fdt_blob);
	/* stored_bootdelay = bootdelay; */
	stored_bootdelay = 10;

	return s;
}

        可以看出,最终从环境变量里面提取出delayboot的启动参数,存储在变量stroed_bootdelay中,直接将该变量修改成10(正式方法应该是去修改环境变量,这会不想去研究环境变量了,先这么修改用着吧);

        修改之后重新编译,使用新的编译产物进行加载调试:可以看到倒计时开启,在倒计时之前按下键盘任意键,进入shell,停止了自启动;

        从打印来看,出现了找不到smc911x网口的错误信息,接下来继续解决这个问题



U-Boot 2016.11 (May 09 2022 - 23:21:51 +0800)

DRAM:  1 GiB
WARNING: Caches not enabled
Flash: 128 MiB
MMC:   MMC: 0
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   smc911x: Invalid chip endian 0x00000000
No ethernet found.
Hit any key to stop autoboot:  0
=>
=>

找不到smc911x的问题

        从FVP手册可以看出,VE Cortex-A9模型里面的网口型号是SMSC 91C111,而上面串口打印的网口型号是smc911x,这两者的驱动程序是兼容的吗? 

u-boot-2016.11/driver/net

-rw-rw-r--  1 ubuntu ubuntu  32578 Nov 15  2016 smc91111.c
-rw-rw-r--  1 ubuntu ubuntu  26443 Nov 15  2016 smc91111.h
-rw-rw-r--  1 ubuntu ubuntu   6931 Nov 15  2016 smc911x.c
-rw-rw-r--  1 ubuntu ubuntu  17053 Nov 15  2016 smc911x.h
-rw-rw-r--  1 ubuntu ubuntu  26884 May  9 22:50 smc911x.o
-rw-rw-r--  1 ubuntu ubuntu    852 May  9 22:50 smc911x.su

        从上面可以看出,smsc911c和smc9111是分开的两个文件,且当前编译的是smc911x.c(因为生成了编译的中间产物smc911x.o);

u-boot-2016.11/driver/net/Makefile

obj-$(CONFIG_SMC91111) += smc91111.o
obj-$(CONFIG_SMC911X) += smc911x.o

        从这个驱动目录下的Makefile文件可以看出,2个宏定义控制着编译使用哪种型号的网口,在u-boot的代码中搜索CONFIG_SMC911X:

(1)u-boot-2016.11/board/armltd/vexpress/vexpress_common.c

int board_eth_init(bd_t *bis)
{
	int rc = 0;
#ifdef CONFIG_SMC911X
	rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
#endif
	return rc;
}

(2)u-boot-2016.11/include/configs/vexpress_common.h

/* SMSC9115 Ethernet from SMSC9118 family */
#define CONFIG_SMC911X			1
#define CONFIG_SMC911X_32_BIT		1
#define CONFIG_SMC911X_BASE		V2M_LAN9118

        针对上述2处进行修改:

(1)u-boot-2016.11/board/armltd/vexpress/vexpress_common.c

int board_eth_init(bd_t *bis)
{
        int rc = 0;
#ifdef CONFIG_SMC911X
        rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
#endif

#ifdef CONFIG_SMC91111
        rc = smc91111_initialize(0, CONFIG_SMC91111_BASE);
#endif
        return rc;
}

(2)u-boot-2016.11/include/configs/vexpress_common.h

/* SMSC9115 Ethernet from SMSC9118 family */
/*
#define CONFIG_SMC911X                  1
#define CONFIG_SMC911X_32_BIT           1
#define CONFIG_SMC911X_BASE             V2M_LAN9118
*/

#define CONFIG_SMC91111                 1
#define CONFIG_SMC91111_BASE            V2M_LAN9118

        按照上述修改之后重新编译,是用新的编译产物加载测试:测试成功,网口初始化正常。

U-Boot 2016.11 (May 10 2022 - 23:20:34 +0800)

DRAM:  1 GiB
WARNING: Caches not enabled
Flash: 128 MiB
MMC:   MMC: 0
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   SMC91111-0
Error: SMC91111-0 address not set.

Hit any key to stop autoboot:  0
=>
=>
=>

        至此,u-boot能正常启动,解决了启动过程中的错误打印。后续还会围绕u-boot进行一些其它的测试,边测试边学习。

总结

(1)上面只是展示了问题的解决方法,要解决这些问题,还是需要阅读FVP的手册,对FVP模型有一定的了解,或者去arm的网站去找相关的文档进行学习;

(2)我也使用ds对u-boot的启动过程进行了单步跟踪,所以对开始的启动流程比较熟悉了,熟悉之后也能帮助定位问题;

(3)

附录

(1)加载符号表:elf文件中包含了debug调试信息,而debug调试信息里又包含了汇编代码与源代码的行数的关系,加载符号表就是告诉DS软件,如果将汇编代码与源文件进行关联,当然debug信息还远不止这些,有兴趣的同学可以去了解一下elf文件的格式

(2)关于FVP模拟串口的原理,大家可以参考FVP的pdf手册,里面有介绍,包括网络smsc-91c111的模拟原理

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值