uboot如何调用驱动接口

uboot如何调用驱动接口,第1张

u-boot是一种普遍用于嵌入式系统中的Bootloader,Bootloader是在 *** 作系统运行之前执行的一小段程序,通过它,我们可以初始化硬件设备、建立内存空间的映射表,从而建立适当的软硬件环境,为最终调用 *** 作系统内核做好准备。Boot Loader的主要运行任务就是将内核映象从硬盘上读到RAM中,然后跳转到内核的入口点去运行,即开始配孝启动 *** 作系统。系统在上电或复位时通常都从地址0x00000000处开始执行,而在这个地址处安排的通常就是系统的Boot Loader程序。u-boot目录结构:1、board中存放于开发板相关的配置文件,每一个开发板都以子文件夹的形式出现;2、Commom文件夹实现u-boot行下支持的命令,每一个命令对应一个文件;3、cpu中存放特定cpu架构相关的目录,每一款cpu架构都对应了一个子目录;4、Doc是文档目录,有u-boot非常完善的文档;5、Drivers中是u-boot支持的各种设备的驱动程序;6、Fs是支持的文件系统,其中最常用的是JFFS2文件系统;7、Include文件夹是u-boot使用的头文件,还有各种硬件平台支持的汇编文件,系统配置文件和文件系统支持的文件;8、Net是与网络协议相关的代码,bootp协议、TFTP协议、NFS文件系统得实现;9、Tooles是生成U-boot的工具。其中比较重要的目录就是/board、/cpu、/drivers和 /include目录,如果想实现u-boot在一个平台上的移植,就要对这些目录进行深入的分析。u-boot的启动过程:系统启动的入口点。既然我们现在要分析u-boot的启动过程,就必须先找到u-boot最先实现的是哪些代码,最先完成的是哪些任务。另一方面一个可执行的image必须有一个入口点,并且只能有一个全局入口点,所以要通知编译器这个入口在哪里。由此我们可以找到程序的入口点是在/board /lpc2210/u-boot.lds中指定的,其中ENTRY(_start)说明程序从_start开始运行,而他指向的是cpu /arm7tdmi/start.o文件。因为如闭我们用的是ARM7TDMI的cpu架构,在复位后从地址0x00000000取它的第一条指令,所以我们将Flash映射到这个地址上,这样培橡稿在系统加电后,cpu将首先执行u-boot程序。u-boot的启动过程是多阶段实现的,分了两个阶段:第一阶段是用汇编写的,主要任务是:1、CPU 自身初始化:包括MMU,Cache,时钟系统,SDRAM 控制器等的初始化;2、重定位:把自己从非易失性存储器搬移到 RAM 中;3、分配堆栈空间,设置堆栈指针;4、清零 BSS 数据段;5、跳转到第二阶段入口函数 start_armboot();第二阶段是用C写的,主要任务是:1、为 U-boot 内部私有数据分配存储空间,并清零;2、依次调用函数指针数组 init_sequence 中定义的函数进行一系列的初始化;3、如果系统支持 NOR Flash,调用flash_init ()和display_flash_config ()初始化并显示检测到的器件信息;4、如果系统支持 LCD 或VFD,调用lcd_setmem()或vfd_setmem()计算帧缓(Framebuffer)大小,然后在BSS 数据段之后为Framebuffer 分配空间,初始化gd->fb_base 为Framebuffer 的起始地址;5、调用 mem_malloc_init()进行存储分配系统(类似于C 语言中的堆)的初始化和空间分配;6、如果系统支持 NAND Flash,调用nand_init ()进行初始化;7、如果系统支持 DataFlash,调用AT91F_DataflashInit()和dataflash_print_info()进行初始化并显示检测到的器件信息;8、调用 env_relocate ()进行环境变量的重定位,即从Flash 中搬移到RAM 中;9、如果系统支持 VFD,调用drv_vfd_init()进行VFD 设备初始化;10、从 环 境 变 量 中 读 取 IP 地址和MAC 地址, 初始化gd->bd->bi_ip_addr 和gd->bd->bi_enetaddr;11、调用 jumptable_init ()进行跳转表初始化,跳转表在global_data 中,具体用途尚不清楚;12、调用 console_init_r()进行控制台初始化;13、如果需要,调用 misc_init_r ()进行杂项初始化;14、调用 enable_interrupts ()打开中断;15、如果需要,调用board_late_init()进行单板后期初始化,对于AT91SAM9260EK,主要是以太网初始化;16、进入主循环:根据用户的选择启动 linux,或者进入命令循环执行用户输入的命令;这部分是一些相对变化不大的部分,我们针对不同的板子改变它调用的一些初始化函数,并且通过设置一些宏定义来改变初始化的流程,所以这些代码在移植的过程中并不需要修改,也是错误相对较少出现的文件。在文件的开始先是定义了一个函数指针数组,通过这个数组,程序通过一个循环来按顺序进行常规的初始化,并在其后通过一些宏定义来初始化一些特定的设备。在最后程序进入一个循环,main_loop。这个循环接收用户输入的命令,以设置参数或者进行启动引导。

U_BOOT_CMD宏定义是在文件include/command.h中,添加自己的命令时一般是在common/目录下新建一个C文件,C文件中包含的头文件可以从该目录下其他厅答命令文件(如cmd_nand.c)复制过来,新建的C文件中一扮槐慧般使用宏U_BOOT_CMD进行声明,例如U_BOOT_CMD(

lcdmenu, CFG_MAXARGS, 0, do_lcd_menu,

"menu - display the myown menu!\n",

"menu - long help for the menu command!\n"

)

然后再在本文件中定义一个函数do_lcd_menu作为该命令的具体实现函数。

为了让新建的C文件参与编译,在common/makefile文件中找到

COBJS = 许多的 .o目标文件

在其它.o文件的后面添加上 lcd_cmd.o(新建的C文件明肆名为lcd_cmd.c)即可。最后重新编译。

那u-boot的那些个关于命令的结构体到底从何而来呢?在include/command.h里定义了这样的宏:

#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))

... ... ... ...

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \

cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}

二个宏展开便定义了一个代表u-boot命碧瞎穗令的结构体。也就是说定义了一个变量,并赋与其初值。关键在于Struc_Section,它被展开后成了

__attribute__

((unused,section(".u_boot_cmd")))。也就是说,每个变量(占内存!)都放在.u_boot_cmd段悔卜里。它们还被加上

了unused的属性,应该是为了平息编译器的警告。确实,没有任何代码引用过它们!!如果这些变量被放在一个显示声明的数组里,那么,每增加一个命令都

得去更改数组的定义神祥。然后,通过这种方法,各人想要增加新的命令时,只需用上面的这个宏即可。这些表示命令的结构体被统一放在.u_boot_cmd段

里,链接脚本里又有:

__u_boot_cmd_start = .

.u_boot_cmd : { *(.u_boot_cmd) }

__u_boot_cmd_end = .

即,

把所有待链接文件里u_boot_cmd段合并在一起生成一个大的.u_boot_cmd段,并且用__u_boot_cmd_start与

__u_boot_cmd_end两个符号标识这块内存的首尾边界。这样,不用大家去修改某一文件的代码(为了改变数组的定义),而是像数据库一样,各个

提供自己的信息。借由编译器与链接器生成这个“数据库”, *** 作数据时对“数据库”进行查询即可。正是一个月前看《计算机程序构造与解释》时看到的

“Data Direct”(好像是这么说)。在Grub及内核里也用了这样机制。

参考:http://blog.163.com/lijiji_1515/blog/static/12687744620114522449739/


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/tougao/12302737.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-24
下一篇 2023-05-24

发表评论

登录后才能评论

评论列表(0条)

保存