完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
` 中奖名单见: https://bbs.elecfans.com/jishu_422412_1_1.html 感谢大家的热情支持,更加要感谢作者朱兆祺(@zzq宁静致远 )的大力支持,慷慨拿出20本《嵌入式Linux开发实用教程》送给大家。 嵌入式Linux开发实用教程 如何让这本充满情怀的书到你碗里去? 规则一: 致亲爱的发烧友们: ★你是不是常常看到单片机“裸奔”,想给MCU/处理器穿上一层“衣服(操作系统)” ★你是不是正在寻找嵌入式Linux修炼秘诀? ★你是不是期待着到自己在嵌入式linux领域有更大的进步? 期待着自己能从Linux的野战军变成正规军甚至王牌军吗? 我们,等你来! 征集时间 2014-02.19 至 2014-03-16 参与规则 下载附件《嵌入式linux开发实用教程》 嵌入式Linux开发实用教程(试用).pdf (705.32 KB, 下载次数: 0) ,阅读《嵌入式linux开发实用教程》试读文章,在本帖中回答3个小问题或者在嵌入式板块单独开帖分析问题,就有机会获得《嵌入式linux开发实用教程》赠书1本,越详细能得到书本的机会越大。 3个问题 2.DDR的内存是如何分配? 3.Main_loop()函数的作用是什么? 规则二: 以“我与linux XXX的段子”为题,在本板块[Linux论坛]里发表新帖,分享你在linux开发过程中的逸闻趣事,或者开发过程中遇到的大大小小问题,又或者分享你是如何开始你的linux之旅的,也许还因为linux结下某段不解之缘,又可能因为linux成功卖身,还可能忘linux于身后,入他行而谋生。数之不尽,道之不截,总之是你与linux的故事,大小均可,重在分享,任你发挥,引发讨论火热的同学将获得赠书喔! PS:“XXX”可以是最囧,最坑,最惊悚,最开心,最浪漫,最可爱,最蛋疼、...... 公布获奖名单的时间: 3月3日、3月17日,每次公布10人,一共20本送出! 想获得特别赠言的朋友还可以再此回帖留下你的赠言! 另外朱兆祺正在开展 新年学生大礼包,凭借学生证购买开发板可免费领取书本、蓝牙模块:
嵌入式linux开发实用教程 目录.doc
(22.5 KB, 下载次数: 177
)
` |
|
相关推荐
83 个讨论
|
|
首先感谢朱老师的奉献精神,我记得朱老师说过:“馒头人生”。我们需要的是失败时候的雪中送炭,而不是成功时的锦上添花。感谢你在我们觉得最黑暗的帮我们看到一丝曙光。
1.lowlevel_init函数作用: lowlevel_init函数的工作是进行与单板相关的初始化工作,故名思议,这个初始化仅仅是最低限(lowlevel)的,包括led灯配置(便于观察现象)、关闭看门狗、设置中断、配置系统时钟、初始化串口、初始化内存和初始化唤醒复位。 1) 配置led ldr r0, =ELFIN_GPIO_BASE ldr r1, =0x55540000 str r1, [r0, #GPNCON_OFFSET] ldr r1, =0x55555555 str r1, [r0, #GPNPUD_OFFSET] ldr r1, =0xf000 str r1, [r0, #GPNDAT_OFFSET] 这里应该改成与s3c6410相适应的配置,单板使用GPM0-GPM3管脚驱动led。根据 s3c6410用户手册中的端口M控制寄存器章节可以对程序作出如下修改。 /* LED on only #8 */ ldr r0, =ELFIN_GPIO_BASE ldr r1, =0x00111111 str r1, [r0, #GPMCON_OFFSET] ldr r1, =0x00000555 str r1, [r0, #GPMPUD_OFFSET] /* all of LEDs are power on */ ldr r1, =0x000f str r1, [r0, #GPMDAT_OFFSET] 根据需要,LED测试自行修改: /* LED test */ ldr r0, =ELFIN_GPIO_BASE ldr r1, =0x0003 str r1, [r0, #GPMDAT_OFFSET] 2) 关闭看门狗 ldr r0, =0x7e000000 @0x7e004000 orr r0, r0, #0x4000 mov r1, #0 str r1, [r0] 大多数微处理器都带有看门狗,当看门狗没有被定时清零(喂狗)时,将引起复位,这 可防止程序跑飞,也可以防止程序运行时候出现死循环。设计者必须清楚看门狗的溢出时间 以决定在合适的时候清除看门狗。在内核中通常用于防止出现死循环,U-Boot直接关闭看 门狗。 3) 设置中断 /* External interrupt pending clear */ ldr r0, =(ELFIN_GPIO_BASE+EINTPEND_OFFSET) /*EINTPEND*/ ldr r1, [r0] str r1, [r0] ldr r0, =ELFIN_VIC0_BASE_ADDR @0x71200000 ldr r1, =ELFIN_VIC1_BASE_ADDR @0x71300000 /* Disable all interrupts (VIC0 and VIC1) */ mvn r3, #0x0 str r3, [r0, #oINTMSK] str r3, [r1, #oINTMSK] /* Set all interrupts as IRQ */ mov r3, #0x0 str r3, [r0, #oINTMOD] str r3, [r1, #oINTMOD] /* Pending Interrupt Clear */ mov r3, #0x0 str r3, [r0, #oVECTADDR] str r3, [r1, #oVECTADDR] 4) 配置系统时钟 S3C6410有三个PLL(锁相环),分别为APLL、MPLL和EPLL。其中APLL产生ACLK, 给CPU使用,MPLL产生HCLKX2、HCLK和PCLK,HCLKX2主要提供时钟给DDR使用, 最大可以到266MHz。HCLK用作AXIAHB总线时钟,PCLK用作APB总线时钟。接AXI和 AHB总线的外设最大时钟为133MHz,接APB总线的外设最大时钟为66MHz。UART的时 钟可以由MPLL或者EPLL提供。 系统时钟初始化起始于: system_clock_init: ldr r0, =ELFIN_CLOCK_POWER_BASE /* 0x7e00f000 */ S3C6400的时钟系统与S3C6410有所差异,其中将 /* FOUT of EPLL is 96MHz */ ldr r1, =0x200203 修改成: ldr r1, =0x80200203 5) 串口初始化 uart_asm_init: /* set GPIO to enable UART */ ldr r0, =ELFIN_GPIO_BASE ldr r1, =0x220022 str r1, [r0, #GPACON_OFFSET] mov pc, lr 6) NAND Flash控制器初始化 nand_asm_init: ldr r0, =ELFIN_NAND_BASE ldr r1, [r0, #NFCONF_OFFSET] orr r1, r1, #0x70 orr r1, r1, #0x7700 str r1, [r0, #NFCONF_OFFSET] ldr r1, [r0, #NFCONT_OFFSET] orr r1, r1, #0x07 str r1, [r0, #NFCONT_OFFSET] mov pc, lr 简单地对NAND Flash主机控制器的时间参数初始化。 7) 内存初始化 调用mem_ctrl_asm_init函数,跳入到arch/arm/cpu/arm1176/s3c64xx/ mem_ctrl_asm_init.s 中。系统上电,在利用内存控制器访问外部内存之前,需要进行一系列初始化工作,如图2. 3。主要做两件事情:配置内存控制器和初始化外部内存设备。配置内存控制器包括时间参数、位宽、片选和ID配置等。初始化外部内存设备,通过操P1DIRECTCMD寄存器,发出初始化系列:“nop”命令,Prechargeall命令,Autorefresh命令,Autorefresh命令,EMRS 命令,MRS命令。 S3C6410的DRAM控制器是基于 ARM PrimeCell CP003 AXI DMC(PL340),S3C6410的存储器端口0并不支持DRAM,所以只能选用存储器端口1(DMC1)。S3C6410的DMC1基址ELFIN_DMC1_BASE的值为0x7e00_1000。当DMC1使用32位数据线DRAM时,需要配置MEM_SYS_CFG寄存器,将芯片管脚Xm1DATA[31:16]设置为DMC1的数据域。单板利用两块64M×16的DDR SDRAM芯片K4X1G163PC组合成一块大小为64M×32的芯片,此时,MEM_SYS_CFG[7]必须清零。 DDR时间参数根据K4X1G163PC手册得到,并定义在s3c6410.h头文件中,利用宏NS_TO_CLK(t)将时间参数转化成时钟周期,再写入相应的寄存器中。一块K4X1G163PC行地址为A0 - A13,列地址为A0 - A9,BANK地址为B0-B1。寻址范围为128Mb。特别注意的是,片选寄存器DMC1_CHIP0_CFG的值:P1_chip_0_cfg[16] = 1,选择Bank-Row-Column组织结构。地址匹配值为0x50,地址屏蔽位0xF0,屏蔽了总线的高八位。因此寻址范围0x5xxxx_xxxx(0x5000_0000~0x5ff_ffff ). 8) 唤醒复位初始化 /* Wakeup support. Don't know if it's going to be used, untested. */ ldr r0, =(ELFIN_CLOCK_POWER_BASE + RST_STAT_OFFSET) ldr r1, [r0] bic r1, r1, #0xfffffff7 cmp r1, #0x8 beq wakeup_reset 2.8) 唤醒复位初始化 /* Wakeup support. Don't know if it's going to be used, untested. */ ldr r0, =(ELFIN_CLOCK_POWER_BASE + RST_STAT_OFFSET) ldr r1, [r0] bic r1, r1, #0xfffffff7 cmp r1, #0x8 beq wakeup_reset 2.DDR的内存分配过程: 这行代码告诉我们SDRAM的末位物理地址为0x5800 0000,即SDRAM的空间分布为 0x5000 0000~0x57FF FFFF。说明SDRAM一共256MB的空间。 接下来的代码程序就是对这256MB内存进行划分。 #ifdef CONFIG_PRAM /* * reserve protected RAM */ reg = getenv_ulong("pram", 10, CONFIG_PRAM); addr -= (reg << 10); /* size is in kB */ debug("Reserving %ldk for protected RAM at %08lxn", reg, addr); #endif /* CONFIG_PRAM */ #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) /* reserve TLB table */ addr -= (4096 * 4); /* round down to next 64 kB limit */ addr &= ~(0x10000 - 1); gd->tlb_addr = addr; debug("TLB table at: %08lxn", addr); #endif /* round down to next 4 kB limit */ addr &= ~(4096 - 1); debug("Top of RAM usable for U-Boot at: %08lxn", addr); 这里告诉我们是将SDRAM的最后64K(addr &= ~(0x10000 - 1))分配给TLB,所分配 的地址为:0x57FF 0000~0x57FF FFFF。 #ifdef CONFIG_LCD #ifdef CONFIG_FB_ADDR gd->fb_base = CONFIG_FB_ADDR; #else /* reserve memory for LCD display (always full pages) */ addr = lcd_setmem(addr); gd->fb_base = addr; #endif /* CONFIG_FB_ADDR */ #endif /* CONFIG_LCD */ /* * reserve memory for U-Boot code, data & bss * round down to next 4 kB limit */ addr -= gd->mon_len; addr &= ~(4096 - 1); debug("Reserving %ldk for U-Boot at: %08lxn", gd->mon_len >> 10, addr); 这段代码是在SDRAM中从后往前给u-boot分配BSS、数据段、代码段,分配地址为: 0x57F7 5000~0x57FE FFFF。 /* * reserve memory for malloc() arena */ addr_sp = addr - TOTAL_MALLOC_LEN; debug("Reserving %dk for malloc() at: %08lxn", TOTAL_MALLOC_LEN >> 10, addr_sp); 从后往前紧挨着代码段开辟一块了malloc空间,给予的地址为:0x57E6 D000~0x57E7 4FFF。 /* * (permanently) allocate a Board Info struct * and a permanent copy of the "global" data */ addr_sp -= sizeof (bd_t); bd = (bd_t *) addr_sp; gd->bd = bd; debug("Reserving %zu Bytes for Board Info at: %08lxn", sizeof (bd_t), addr_sp); 为bd结构体分配空间,地址为:0x57E6 CFD8~0x57E6 CFFF。 addr_sp -= sizeof (gd_t); id = (gd_t *) addr_sp; debug("Reserving %zu Bytes for Global Data at: %08lxn", sizeof (gd_t), addr_sp); 这是给gd结构体分配空间,地址为:0x57E6 CF60~0x57E6 CFD7。 /* setup stackpointer for exeptions */ gd->irq_sp = addr_sp; #ifdef CONFIG_USE_IRQ addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ); debug("Reserving %zu Bytes for IRQ stack at: %08lxn", CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp); #endif /* leave 3 words for abort-stack */ addr_sp -= 12; /* 8-byte alignment for ABI compliance */ addr_sp &= ~0x07; #else addr_sp += 128; /* leave 32 words for abort-stack */ gd->irq_sp = addr_sp; #endif debug("New Stack Pointer is: %08lxn", addr_sp); 分配异常中断空间,地址:0x57E6 CF50~0x57E6 CF5F。 3.main_loop()函数的作用: main_loop()函数位于/commom目录下的main.c文件中。如下: void main_loop (void) main_loop()函数既无入口参数也无返回值。Main_loop()函数的主要实现作用是: 1) HUSH的相关初始化 #ifndef CONFIG_SYS_HUSH_PARSER static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, }; int len; int rc = 1; int flag; #endif …… #ifdef CONFIG_SYS_HUSH_PARSER u_boot_hush_start (); #endif #if defined(CONFIG_HUSH_INIT_VAR) hush_init_var (); #endif 2) bootdelay的初始化 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) char *s; int bootdelay; #endif 3) 启动次数 #ifdef CONFIG_BOOTCOUNT_LIMIT bootcount = bootcount_load(); 上面这行代码的作用是加载保存的启动次数。 bootcount++; 启动次数加1。 bootcount_store(bootcount); 更新启动次数。 sprintf (bcs_set, "%lu", bootcount); 将启动次数通过串口输出。 setenv ("bootcount", bcs_set); bcs = getenv ("bootlimit"); bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0; #endif /* CONFIG_BOOTCOUNT_LIMIT */ 这段代码蕴含的东西较多。启动次数限制功能,启动次数限制可以被用户设置一个启动次数,然后保存在Flash存储器的特定位置,当到达启动次数后,U-Boot无法启动。该功能适合一些商业产品,通过配置不同的License限制用户重新启动系统。 4) Modem功能 #ifdef CONFIG_MODEM_SUPPORT debug ("DEBUG: main_loop: do_mdm_init=%dn", do_mdm_init); if (do_mdm_init) { char *str = strdup(getenv("mdm_cmd")); setenv ("preboot", str); /* set or delete definition */ if (str != NULL) free (str); mdm_init(); /* wait for modem connection */ } #endif /* CONFIG_MODEM_SUPPORT */ 如果系统中有Modem功能,打开其功能可以接受其他用户通过电话网络的拨号请求。Modem功能通常供一些远程控制的系统使用 5) 设置U-Boot版本号 #ifdef CONFIG_VERSION_VARIABLE { setenv ("ver", version_string); /* set version variable */ } #endif /* CONFIG_VERSION_VARIABLE */ 打开动态版本支持功能后,u-boot在启动的时候会显示最新的版本号。 6) 启动tftp功能 #if defined(CONFIG_UPDATE_TFTP) update_tftp (0UL); #endif /* CONFIG_UPDATE_TFTP */ 7) 打印启动菜单 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) s = getenv ("bootdelay"); bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; debug ("### main_loop entered: bootdelay=%dnn", bootdelay); 在进入主循环之前,如果配置了启动延迟功能,需要等待用户从串口或者网络接口输入。如果用户按下任意键打断,启动流程,会向终端打印出一个启动菜单。 #if defined(CONFIG_MENU_SHOW) bootdelay = menu_show(bootdelay); #endif 向终端打印出一个启动菜单。 # ifdef CONFIG_BOOT_RETRY_TIME init_cmd_timeout (); # endif /* CONFIG_BOOT_RETRY_TIME */ 初始化命令行超时机制。 #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"); 获取启动命令参数。 main_loop()的主要作用即是U-Boot启动管理。 |
|
|
|
|
|
1.lowlevel_init函数完成了哪些初始化?
函数的工作是进行与单板相关的初始化工作这个初始化仅仅是最低限度(lowlevel)的,包括led灯配置(便于观察现象)、关闭看门狗、设置中断、配置系统时钟、初始化串口、初始化内存和初始化唤醒复位。 2.DDR的内存是如何分配? SDRAM的末位物理地址为0x5800 0000,即SDRAM的空间分布为0x5000 0000~0x57FF FFFF SDRAM的最后64K(addr &= ~(0x10000 - 1))分配给TLB,所分配的地址为:0x57FF 0000~0x57FF FFFF。SDRAM中从后往前给u-boot分配BSS、数据段、代码段,分配地址为:0x57F7 5000~0x57FE FFFF。一块了malloc空间,给予的地址为:0x57E6 D000~0x57E7 4FFF。为bd结构体分配空间,地址为:0x57E6 CFD8~0x57E6 CFFF。gd结构体分配空间,地址为:0x57E6 CF60~0x57E6 CFD7。分配异常中断空间,地址:0x57E6 CF50~0x57E6 CF5F。说明SDRAM的起始地址是:0x5000 0000。 3.Main_loop()函数的作用是什么? 1) HUSH的相关初始化 2) bootdelay的初始化 3) 启动次数 4) Modem功能 5) 设置U-Boot版本号 6) 启动tftp功能 7) 打印启动菜单 main_loop()的主要作用即是U-Boot启动管理。 |
|
|
|
|
|
1.lowlevel_init函数完成了哪些初始化?
函数的工作是进行与单板相关的初始化工作这个初始化仅仅是最低限度(lowlevel)的,包括led灯配置(便于观察现象)、关闭看门狗、设置中断、配置系统时钟、初始化串口、初始化内存和初始化唤醒复位。 2.DDR的内存是如何分配? SDRAM的末位物理地址为0x5800 0000,即SDRAM的空间分布为0x5000 0000~0x57FF FFFF SDRAM的最后64K(addr &= ~(0x10000 - 1))分配给TLB,所分配的地址为:0x57FF 0000~0x57FF FFFF。SDRAM中从后往前给u-boot分配BSS、数据段、代码段,分配地址为:0x57F7 5000~0x57FE FFFF。一块了malloc空间,给予的地址为:0x57E6 D000~0x57E7 4FFF。为bd结构体分配空间,地址为:0x57E6 CFD8~0x57E6 CFFF。gd结构体分配空间,地址为:0x57E6 CF60~0x57E6 CFD7。分配异常中断空间,地址:0x57E6 CF50~0x57E6 CF5F。说明SDRAM的起始地址是:0x5000 0000。 3.Main_loop()函数的作用是什么? 答:Main_loop()函数的作用: 1.HUSH的相关初始化 2.bootdelay的初始化 3.启动次数 4.Modem功能 5.设置U-Boot版本号 6.启动tftp功能 7.打印启动菜单 |
|
|
|
|
|
1.lowlevel_init函数完成了哪些初始化? lowleve_init,名字得知,完成低级别的初始化,程序跳到board.c中。关看门狗、串口、内存、flash等的初始化,为搬运代码到ram做准备 2.DDR的内存是如何分配? SDRAM的最后64K分配给TLB,所分配的地址为:0x57FF 0000~0x57FF FFFF。 给u-boot分配BSS、数据段、代码段,分配地址为:0x57F7 5000~0x57FE FFFF。 malloc空间,分配的地址为:0x57E6 D000~0x57E7 4FFF。 bd结构体分配空间,地址为:0x57E6 CFD8~0x57E6 CFFF。 gd结构体分配空间,地址为:0x57E6 CF60~0x57E6 CFD7. 分配异常中断空间,地址:0x57E6 CF50~0x57E6 CF5F。 3.Main_loop()函数的作用是什么? 等待命令输入,如果倒数计数到则boot kernel. |
|
|
|
|
|
本帖最后由 aaa1350 于 2014-3-14 22:31 编辑 1.lowlevel_init函数完成了哪些初始化? 与单板相关的初始化工作, 这个初始化仅仅是最低限度(lowlevel)的,包括led灯配置(便于观察现象)、关闭看门狗、设置中断、配置系统时钟、初始化串口、初始化内存和初始化唤醒复位。 2.DDR的内存是如何分配? SDRAM的末位物理地址为0x5800 0000,即SDRAM的空间分布为0x5000 0000~0x57FF FFFF SDRAM的最后64K(addr &= ~(0x10000 - 1))分配给TLB, 所分配的地址为:0x57FF 0000~0x57FF FFFF。 SDRAM中从后往前给u-boot分配BSS、数据段、代码段, 分配地址为:0x57F7 5000~0x57FE FFFF。 一块了malloc空间,给予的地址为:0x57E6 D000~0x57E7 4FFF。 为bd结构体分配空间,地址为:0x57E6 CFD8~0x57E6 CFFF。 gd结构体分配空间,地址为:0x57E6 CF60~0x57E6 CFD7。 分配异常中断空间,地址:0x57E6 CF50~0x57E6 CF5F。 说明SDRAM的起始地址是:0x5000 0000。 3.Main_loop()函数的作用是什么? 1) HUSH的相关初始化 2) bootdelay的初始化 3) 启动次数 4) Modem功能 5) 设置U-Boot版本号 6) 启动tftp功能 7) 打印启动菜单 main_loop()的主要作用即是U-Boot启动管理。 main_loop()函数做的都是与具体平台无关的工作,主要包括初始化启动次数限制机制、设置软件版本号、打印启动信息、解析命令等。 (1)设置启动次数有关参数。在进入main_loop()函数后,首先是根据配置加载已经保留的启动次数,并且根据配置判断是否超过启动次数。代码如下: 295 void main_loop (void) 296 { 297 #ifndef CFG_HUSH_PARSER 298 static char lastcommand[CFG_CBSIZE] = { 0, }; 299 int len; 300 int rc = 1; 301 int flag; 302 #endif 303 304 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) 305 char *s; 306 int bootdelay; 307 #endif 308 #ifdef CONFIG_PREBOOT 309 char *p; 310 #endif 311 #ifdef CONFIG_BOOTCOUNT_LIMIT 312 unsigned long bootcount = 0; 313 unsigned long bootlimit = 0; 314 char *bcs; 315 char bcs_set[16]; 316 #endif /* CONFIG_BOOTCOUNT_LIMIT */ 317 318 #if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO) 319 ulong bmp = 0; /* default bitmap */ 320 extern int trab_vfd (ulong bitmap); 321 322 #ifdef CONFIG_MODEM_SUPPORT 323 if (do_mdm_init) 324 bmp = 1; /* alternate bitmap */ 325 #endif 326 trab_vfd (bmp); 327 #endif /* CONFIG_VFD && VFD_TEST_LOGO */ 328 329 #ifdef CONFIG_BOOTCOUNT_LIMIT 330 bootcount = bootcount_load(); // 加载保存的启动次数 331 bootcount++; // 启动次数加1 332 bootcount_store (bootcount); // 更新启动次数 333 sprintf (bcs_set, "%lu", bootcount); // 打印启动次数 334 setenv ("bootcount", bcs_set); 335 bcs = getenv ("bootlimit"); 336 bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0; // 转换启动次数字符串为UINT类型 337 #endif /* CONFIG_BOOTCOUNT_LIMIT */ 第329~337行是启动次数限制功能,启动次数限制可以被用户设置一个启动次数,然后保存在Flash存储器的特定位置,当到达启动次数后,U-Boot无法启动。该功能适合一些商业产品,通过配置不同的License限制用户重新启动系统。 (2)程序第339~348行是Modem功能。如果系统中有Modem,打开该功能可以接受其他用户通过电话网络的拨号请求。Modem功能通常供一些远程控制的系统使用,代码如下: 339 #ifdef CONFIG_MODEM_SUPPORT 340 debug ("DEBUG: main_loop: do_mdm_init=%dn", do_mdm_init); 341 if (do_mdm_init) { // 判断是否需要初始化Modem 342 char *str = strdup(getenv("mdm_cmd")); // 获取Modem参数 343 setenv ("preboot", str); /* set or delete definition */ 344 if (str != NULL) 345 free (str); 346 mdm_init(); /* wait for modem connection */ // 初始化Modem 347 } 348 #endif /* CONFIG_MODEM_SUPPORT */ (3)接下来设置U-Boot的版本号,初始化命令自动完成功能等。代码如下: 350 #ifdef CONFIG_VERSION_VARIABLE 351 { 352 extern char version_string[]; 353 354 setenv ("ver", version_string); /* set version variable */ // 设置版本号 355 } 356 #endif /* CONFIG_VERSION_VARIABLE */ 357 358 #ifdef CFG_HUSH_PARSER 359 u_boot_hush_start (); // 初始化Hash功能 360 #endif 361 362 #ifdef CONFIG_AUTO_COMPLETE 363 install_auto_complete(); // 初始化命令自动完成功能 364 #endif 365 366 #ifdef CONFIG_PREBOOT 367 if ((p = getenv ("preboot")) != NULL) { 368 # ifdef CONFIG_AUTOBOOT_KEYED 369 int prev = disable_ctrlc(1); /* disable Control C checking */ // 关闭Crtl+C组合键 370 # endif 371 372 # ifndef CFG_HUSH_PARSER 373 run_command (p, 0); // 运行Boot参数 374 # else 375 parse_string_outer(p, FLAG_PARSE_SEMICOLON | 376 FLAG_EXIT_FROM_LOOP); 377 # endif 378 379 # ifdef CONFIG_AUTOBOOT_KEYED 380 disable_ctrlc(prev); /* restore Control C checking */ // 恢复Ctrl+C组合键 381 # endif 382 } 383 #endif /* CONFIG_PREBOOT */ 程序第350~356行是动态版本号功能支持代码,version_string变量是在其他文件定义的一个字符串变量,当用户改变U-Boot版本的时候会更新该变量。打开动态版本支持功能后,U-Boot在启动的时候会显示最新的版本号。 程序第363行设置命令行自动完成功能,该功能与Linux的shell类似,当用户输入一部分命令后,可以通过按下键盘上的Tab键补全命令的剩余部分。main_loop()函数不同的功能使用宏开关控制不仅能提高代码模块化,更主要的是针对嵌入式系统Flash存储器大小设计的。在嵌入式系统上,不同的系统Flash存储空间不同。对于一些Flash空间比较紧张的设备来说,通过宏开关关闭一些不是特别必要的功能如命令行自动完成,可以减小U-Boot编译后的文件大小。 (4)在进入主循环之前,如果配置了启动延迟功能,需要等待用户从串口或者网络接口输入。如果用户按下任意键打断,启动流程,会向终端打印出一个启动菜单。代码如下: 385 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) 386 s = getenv ("bootdelay"); 387 bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; // 启动延迟 388 389 debug ("### main_loop entered: bootdelay=%dnn", bootdelay); 390 391 # ifdef CONFIG_BOOT_RETRY_TIME 392 init_cmd_timeout (); // 初始化命令行超时机制 393 # endif /* CONFIG_BOOT_RETRY_TIME */ 394 395 #ifdef CONFIG_BOOTCOUNT_LIMIT 396 if (bootlimit && (bootcount > bootlimit)) { // 检查是否超出启动次数限制 397 printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.n", 398 (unsigned)bootlimit); 399 s = getenv ("altbootcmd"); 400 } 401 else 402 #endif /* CONFIG_BOOTCOUNT_LIMIT */ 403 s = getenv ("bootcmd"); // 获取启动命令参数 404 405 debug ("### main_loop: bootcmd="%s"n", s ? s : " 406 407 if (bootdelay >= 0 && s && !abortboot (bootdelay)) { //检查是否支持启动延迟功能 408 # ifdef CONFIG_AUTOBOOT_KEYED 409 int prev = disable_ctrlc(1); /* disable Control C checking */ // 关闭Ctrl+C组合键 410 # endif 411 412 # ifndef CFG_HUSH_PARSER 413 run_command (s, 0); // 运行启动命令行 414 # else 415 parse_string_outer(s, FLAG_PARSE_SEMICOLON | 416 FLAG_EXIT_FROM_LOOP); 417 # endif 418 419 # ifdef CONFIG_AUTOBOOT_KEYED 420 disable_ctrlc(prev); /* restore Control C checking */ // 打开Ctrl+C组合键 421 # endif 422 } 423 424 # ifdef CONFIG_MENUKEY 425 if (menukey == CONFIG_MENUKEY) { // 检查是否支持菜单键 426 s = getenv("menucmd"); 427 if (s) { 428 # ifndef CFG_HUSH_PARSER 429 run_command (s, 0); 430 # else 431 parse_string_outer(s, FLAG_PARSE_SEMICOLON | 432 FLAG_EXIT_FROM_LOOP); 433 # endif 434 } 435 } 436 #endif /* CONFIG_MENUKEY */ 437 #endif /* CONFIG_BOOTDELAY */ 438 439 #ifdef CONFIG_AMIGAONEG3SE 440 { 441 extern void video_banner(void); 442 video_banner(); // 打印启动图标 443 } 444 #endif (5)在各功能设置完毕后,程序第454行进入一个for死循环,该循环不断使用readline()函数(第463行)从控制台(一般是串口)读取用户的输入,然后解析。有关如何解析命令请参考U-Boot代码中run_command()函数的定义,本书不再赘述。代码如下: 446 /* 447 * Main Loop for Monitor Command Processing 448 */ 449 #ifdef CFG_HUSH_PARSER 450 parse_file_outer(); 451 /* This point is never reached */ 452 for (;;); 453 #else 454 for (;;) { // 进入命令行循环 455 #ifdef CONFIG_BOOT_RETRY_TIME 456 if (rc >= 0) { 457 /* Saw enough of a valid command to 458 * restart the timeout. 459 */ 460 reset_cmd_timeout(); // 设置命令行超时 461 } 462 #endif 463 len = readline (CFG_PROMPT); // 读取命令 464 465 flag = 0; /* assume no special flags for now */ 466 if (len > 0) 467 strcpy (lastcommand, console_buffer); 468 else if (len == 0) 469 flag |= CMD_FLAG_REPEAT; 470 #ifdef CONFIG_BOOT_RETRY_TIME 471 else if (len == -2) { 472 /* -2 means timed out, retry autoboot 473 */ 474 puts ("nTimed out waiting for commandn"); 475 # ifdef CONFIG_RESET_TO_RETRY 476 /* Reinit board to run initialization code again */ 477 do_reset (NULL, 0, 0, NULL); 478 # else 479 return; /* retry autoboot */ 480 # endif 481 } 482 #endif 483 484 if (len == -1) 485 puts (" 486 else 487 rc = run_command (lastcommand, flag); // 运行命令 488 489 if (rc <= 0) { 490 /* invalid command or not repeatable, forget it */ 491 lastcommand[0] = 0; 492 } 493 } 494 #endif /*CFG_HUSH_PARSER*/ 495 } |
|
|
|
|
|
本帖最后由 aaa1350 于 2014-3-14 22:47 编辑
1.lowlevel_init函数完成了哪些初始化? 函数的工作是进行与单板相关的初始化工作这个初始化仅仅是最低限度(lowlevel)的,包括led灯配置(便于观察现象)、关闭看门狗、设置中断、配置系统时钟、初始化串口、初始化内存和初始化唤醒复位。 #include #include /* some parameters for the board */ /* * * Taken from linux/arch/arm/boot/compressed/head-s3c2410.S * * Copyright (C) 2002 Samsung Electronics SW.LEE <hitchcar@sec.samsung.com> * */ @我的开发板上的SDRAM为:HY57V561620FTP-H,4Mx16bitx4Banks,两片接成32bit,64MB,接在BANK6上,地址范围为:[0x30000000-0x33ffffff] @(还没搞清楚SDRAM的结构,为什么要分成Banks,改天看下相关的文档研究一下) @对于SDRAM的初始化是要配置13个寄存器,好像多采用循环方式。 #define BWSCON 0x48000000 @BWSCON寄存器地址,控制每个总线 /* BWSCON */ #define DW8 (0x0) #define DW16 (0x1) #define DW32 (0x2) @将用来设置位宽的三个宏 #define WAIT (0x1<<2) #define UBLB (0x1<<3) @将用来设置wait和ublb的宏 #define B1_BWSCON (DW32) #define B2_BWSCON (DW16) #define B3_BWSCON (DW16 + WAIT + UBLB) #define B4_BWSCON (DW16) #define B5_BWSCON (DW16) @BANK2、BANK3、BANK4、BANK5为什么配成16bit总线宽度,而且BANK3还要加上WAIT和UBLB属性没有搞明白,感觉如果没用到的话可以配成默认值的吧? #define B6_BWSCON (DW32) #define B7_BWSCON (DW32) @我板子的SDRAM接在BANK6,所以配成32bit位宽,BANK7按datasheet的要求配置的和BANK6相同 @分别配置每个BANK的BANKCON寄存器,这里应该根据SRAM的手册来配置相应的BANK,BANK0~5主要是配置一些时序参数 /* BANK0CON */ #define B0_Tacs 0x0 /* 0clk */ #define B0_Tcos 0x0 /* 0clk */ #define B0_Tacc 0x7 /* 14clk */ #define B0_Tcoh 0x0 /* 0clk */ #define B0_Tah 0x0 /* 0clk */ #define B0_Tacp 0x0 #define B0_PMC 0x0 /* normal */ /* BANK1CON */ #define B1_Tacs 0x0 /* 0clk */ #define B1_Tcos 0x0 /* 0clk */ #define B1_Tacc 0x7 /* 14clk */ #define B1_Tcoh 0x0 /* 0clk */ #define B1_Tah 0x0 /* 0clk */ #define B1_Tacp 0x0 #define B1_PMC 0x0 #define B2_Tacs 0x0 #define B2_Tcos 0x0 #define B2_Tacc 0x7 #define B2_Tcoh 0x0 #define B2_Tah 0x0 #define B2_Tacp 0x0 #define B2_PMC 0x0 @这里BANK3CON不为默认值,是因为在SMDK2410上BANK3上应该接了ROM @根据我自己的板子,我把这里换成了默认值(根据vivi上的默认值修改的),不过要不是默认值的话应该也没有影响的吧?我的板子这里接了DM9000A #define B3_Tacs 0x0 /* 0clk */ #define B3_Tcos 0x3 /* 4clk */ #define B3_Tacc 0x7 /* 14clk */ #define B3_Tcoh 0x1 /* 1clk */ #define B3_Tah 0x0 /* 0clk */ #define B3_Tacp 0x3 /* 6clk */ #define B3_PMC 0x0 /* normal */ #define B4_Tacs 0x0 /* 0clk */ #define B4_Tcos 0x0 /* 0clk */ #define B4_Tacc 0x7 /* 14clk */ #define B4_Tcoh 0x0 /* 0clk */ #define B4_Tah 0x0 /* 0clk */ #define B4_Tacp 0x0 #define B4_PMC 0x0 /* normal */ #define B5_Tacs 0x0 /* 0clk */ #define B5_Tcos 0x0 /* 0clk */ #define B5_Tacc 0x7 /* 14clk */ #define B5_Tcoh 0x0 /* 0clk */ #define B5_Tah 0x0 /* 0clk */ #define B5_Tacp 0x0 #define B5_PMC 0x0 /* normal */
2.DDR的内存是如何分配? SDRAM的末位物理地址为0x5800 0000,即SDRAM的空间分布为0x5000 0000~0x57FF FFFF SDRAM的最后64K(addr &= ~(0x10000 - 1))分配给TLB,所分配的地址为:0x57FF 0000~0x57FF FFFF。SDRAM中从后往前给u-boot分配BSS、数据段、代码段,分配地址为:0x57F7 5000~0x57FE FFFF。一块了malloc空间,给予的地址为:0x57E6 D000~0x57E7 4FFF。为bd结构体分配空间,地址为:0x57E6 CFD8~0x57E6 CFFF。gd结构体分配空间,地址为:0x57E6 CF60~0x57E6 CFD7。分配异常中断空间,地址:0x57E6 CF50~0x57E6 CF5F。说明SDRAM的起始地址是:0x5000 0000。 3.Main_loop()函数的作用是什么? 答:Main_loop()函数的作用: 1.HUSH的相关初始化 2.bootdelay的初始化 3.启动次数 4.Modem功能 5.设置U-Boot版本号 6.启动tftp功能 7.打印启动菜单 具体分析 void main_loop (void) { #ifndef CFG_HUSH_PARSER static char lastcommand[CFG_CBSIZE] = { 0, }; int len; int rc = 1; int flag; #endif #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) char *s; int bootdelay; #endif #ifdef CONFIG_PREBOOT char *p; #endif (1)启动次数限制功能,启动次数限制可以被用户设置一个启动次数,然后保存在Flash存储器的特定位置,当到达启动次数后,U-Boot无法启动。该功能适合一些商业产品,通过配置不同的License限制用户重新启动系统。 #ifdef CONFIG_BOOTCOUNT_LIMIT //使能启动次数限制功能,主要用于产品的限次使用 unsigned long bootcount = 0; unsigned long bootlimit = 0; char *bcs; char bcs_set[16]; #endif /* CONFIG_BOOTCOUNT_LIMIT */ #if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO) ulong bmp = 0; /* default bitmap */ extern int trab_vfd (ulong bitmap); #ifdef CONFIG_MODEM_SUPPORT if (do_mdm_init) bmp = 1; /* alternate bitmap */ #endif trab_vfd (bmp); #endif /* CONFIG_VFD && VFD_TEST_LOGO */ #ifdef CONFIG_BOOTCOUNT_LIMIT bootcount = bootcount_load(); //加载启动次数 bootcount++;//启动次数加一 bootcount_store (bootcount); //存储修改后的启动次数 sprintf (bcs_set, "%lu", bootcount); setenv ("bootcount", bcs_set);//设置环境变量bootcount bcs = getenv ("bootlimit");//获得启动次数的上限 bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0; #endif /* CONFIG_BOOTCOUNT_LIMIT */ (2)Modem功能。如果系统中有Modem,打开该功能可以接受其他用户通过电话网络的拨号请求。Modem功能通常供一些远程控制的系统使用。 #ifdef CONFIG_MODEM_SUPPORT debug ("DEBUG: main_loop: do_mdm_init=%dn", do_mdm_init); if (do_mdm_init) { char *str = strdup(getenv("mdm_cmd")); setenv ("preboot", str); /* set or delete definition */ if (str != NULL) free (str); mdm_init(); /* wait for modem connection */ } #endif /* CONFIG_MODEM_SUPPORT */ (3)设置U-Boot的版本号,初始化命令自动完成功能等。动态版本号功能支持代码,version_string变量是在其他文件定义的一个字符串变量,当用户改变U-Boot版本的时候会更新该变量。打开动态版本支持功能后,U-Boot在启动的时候会显示最新的版本号。 #ifdef CONFIG_VERSION_VARIABLE { extern char version_string[]; //在lib_arm/board.c中定义有此字符串 setenv ("ver", version_string); /* set version variable */ //将版本号写入flash } #endif /* CONFIG_VERSION_VARIABLE */ #ifdef CFG_HUSH_PARSER u_boot_hush_start (); #endif #ifdef CONFIG_AUTO_COMPLETE /// 初始化命令自动完成功能 install_auto_complete(); #endif //设置命令行自动完成功能,该功能与Linux的shell类似,当用户输入一部分命令后,可以通过按下键盘上的Tab键 //补全命令的剩余部分。main_loop()函数不同的功能使用宏开关控制不仅能提高代码模块化,更主要的是针对嵌入 //式系统Flash存储器大小设计的。在嵌入式系统上,不同的系统Flash存储空间不同。对于一些Flash空间比较紧张 //的设备来说,通过宏开关关闭一些不是特别必要的功能如命令行自动完成,可以减小U-Boot编译后的文件大小。 #ifdef CONFIG_PREBOOT if ((p = getenv ("preboot")) != NULL) { # ifdef CONFIG_AUTOBOOT_KEYED int prev = disable_ctrlc(1); /* disable Control C checking */ // 关闭Crtl+C组合键 # endif # ifndef CFG_HUSH_PARSER run_command (p, 0); # else parse_string_outer(p, FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP); # endif # ifdef CONFIG_AUTOBOOT_KEYED disable_ctrlc(prev); /* restore Control C checking */ // 恢复Ctrl+C组合键 # endif } #endif /* CONFIG_PREBOOT */ (4)启动延迟功能,需要等待用户从串口或者网络接口输入。如果用户按下任意键打断,启动流程,会向终端打印出一个启动菜单。 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) s = getenv ("bootdelay");//获得启动延时时间环境变量 bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; debug ("### main_loop entered: bootdelay=%dnn", bootdelay); # ifdef CONFIG_BOOT_RETRY_TIME init_cmd_timeout ();// 初始化命令行超时机制 # endif /* CONFIG_BOOT_RETRY_TIME */ #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"); // 获取启动命令参数 debug ("### main_loop: bootcmd="%s"n", s ? s : " //在启动命令非0(有启动命令)的情况下,如果在启动延时时间到之前按下键终止了,abortboot返回1,否则如果一 //直没有键按下,直到启动延时时间到,那么函数返回0。所以,如果按下键了,就可以跳过启动操作系统;如果没 //按就直接启动操作系统了。 if (bootdelay >= 0 && s && !abortboot (bootdelay)) { # ifdef CONFIG_AUTOBOOT_KEYED int prev = disable_ctrlc(1); /* disable Control C checking *///关闭control+c组合键 # endif # ifndef CFG_HUSH_PARSER run_command (s, 0); //运行启动命令,启动操作系统 # else parse_string_outer(s, FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP); # endif # ifdef CONFIG_AUTOBOOT_KEYED disable_ctrlc(prev); /* restore Control C checking *///恢复control+c组合键功能 # endif } # ifdef CONFIG_MENUKEY if (menukey == CONFIG_MENUKEY) {//检查是否支持菜单键 s = getenv("menucmd"); if (s) { # ifndef CFG_HUSH_PARSER run_command (s, 0); # else parse_string_outer(s, FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP); # endif } } #endif /* CONFIG_MENUKEY */ #endif /* CONFIG_BOOTDELAY */ #ifdef CONFIG_AMIGAONEG3SE { extern void video_banner(void); video_banner(); // 打印启动图标 } #endif (5)读取命令,解析命令。这是一个for死循环,该循环不断使用readline()函数(第463行)从控制台(一般是串口)读取用户的输入,然后解析。有关如何解析命令请参考U-Boot代码中run_command()函数的定义。 /* * Main Loop for Monitor Command Processing */ #ifdef CFG_HUSH_PARSER parse_file_outer(); /* This point is never reached */ for (;;); #else for (;;) { #ifdef CONFIG_BOOT_RETRY_TIME if (rc >= 0) { /* Saw enough of a valid command to * restart the timeout. */ reset_cmd_timeout();// 设置命令行超时 } #endif len = readline (CFG_PROMPT);// 读取命令,读取到的命令存储在全局变量console_buffer 中 flag = 0; /* assume no special flags for now */ if (len > 0) //命令长度大于0 strcpy (lastcommand, console_buffer);//将读取到的命令copy到lastcommand中 else if (len == 0) flag |= CMD_FLAG_REPEAT; #ifdef CONFIG_BOOT_RETRY_TIME else if (len == -2) { /* -2 means timed out, retry autoboot */ puts ("nTimed out waiting for commandn"); # ifdef CONFIG_RESET_TO_RETRY /* Reinit board to run initialization code again */ do_reset (NULL, 0, 0, NULL); # else return; /* retry autoboot */ # endif } #endif if (len == -1) puts (" else rc = run_command (lastcommand, flag);//解析并运行命令 if (rc <= 0) { /* invalid command or not repeatable, forget it */ lastcommand[0] = 0; } } #endif /*CFG_HUSH_PARSER*/ } |
|
|
|
|
|
1.lowlevel_init函数完成了哪些初始化?
函数的工作是进行与单板相关的初始化工作这个初始化仅仅是最低限度(lowlevel)的,包括led灯配置(便于观察现象)、关闭看门狗、设置中断、配置系统时钟、初始化串口、初始化内存和初始化唤醒复位。 2.DDR的内存是如何分配? SDRAM的末位物理地址为0x5800 0000,即SDRAM的空间分布为0x5000 0000~0x57FF FFFF SDRAM的最后64K(addr &= ~(0x10000 - 1))分配给TLB, 所分配的地址为:0x57FF 0000~0x57FF FFFF。 SDRAM中从后往前给u-boot分配BSS、数据段、代码段,分配地址为:0x57F7 5000~0x57FE FFFF。 一块了malloc空间,给予的地址为:0x57E6 D000~0x57E7 4FFF。 为bd结构体分配空间,地址为:0x57E6 CFD8~0x57E6 CFFF。 gd结构体分配空间,地址为:0x57E6 CF60~0x57E6 CFD7。 分配异常中断空间,地址:0x57E6 CF50~0x57E6 CF5F。 说明SDRAM的起始地址是:0x5000 0000。 3.Main_loop()函数的作用是什么? 1) HUSH的相关初始化 2) bootdelay的初始化 3) 启动次数 4) Modem功能 5) 设置U-Boot版本号 6) 启动tftp功能 7) 打印启动菜单 main_loop()的主要作用即是U-Boot启动管理。 3.Main_loop()函数的作用是什么? 答:Main_loop()函数的作用: 1.HUSH的相关初始化 2.bootdelay的初始化 3.启动次数 4.Modem功能 5.设置U-Boot版本号 6.启动tftp功能 7.打印启动菜单 |
|
|
|
|
|
具体分析
void main_loop (void) { #ifndef CFG_HUSH_PARSER static char lastcommand[CFG_CBSIZE] = { 0, }; int len; int rc = 1; int flag; #endif #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) char *s; int bootdelay; #endif #ifdef CONFIG_PREBOOT char *p; #endif (1)启动次数限制功能,启动次数限制可以被用户设置一个启动次数,然后保存在Flash存储器的特定位置,当到达启动次数后,U-Boot无法启动。该功能适合一些商业产品,通过配置不同的License限制用户重新启动系统。 #ifdef CONFIG_BOOTCOUNT_LIMIT //使能启动次数限制功能,主要用于产品的限次使用 unsigned long bootcount = 0; unsigned long bootlimit = 0; char *bcs; char bcs_set[16]; #endif /* CONFIG_BOOTCOUNT_LIMIT */ #if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO) ulong bmp = 0; /* default bitmap */ extern int trab_vfd (ulong bitmap); #ifdef CONFIG_MODEM_SUPPORT if (do_mdm_init) bmp = 1; /* alternate bitmap */ #endif trab_vfd (bmp); #endif /* CONFIG_VFD && VFD_TEST_LOGO */ #ifdef CONFIG_BOOTCOUNT_LIMIT bootcount = bootcount_load(); //加载启动次数 bootcount++;//启动次数加一 bootcount_store (bootcount); //存储修改后的启动次数 sprintf (bcs_set, "%lu", bootcount); setenv ("bootcount", bcs_set);//设置环境变量bootcount bcs = getenv ("bootlimit");//获得启动次数的上限 bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0; #endif /* CONFIG_BOOTCOUNT_LIMIT */ (2)Modem功能。如果系统中有Modem,打开该功能可以接受其他用户通过电话网络的拨号请求。Modem功能通常供一些远程控制的系统使用。 #ifdef CONFIG_MODEM_SUPPORT debug ("DEBUG: main_loop: do_mdm_init=%dn", do_mdm_init); if (do_mdm_init) { char *str = strdup(getenv("mdm_cmd")); setenv ("preboot", str); /* set or delete definition */ if (str != NULL) free (str); mdm_init(); /* wait for modem connection */ } #endif /* CONFIG_MODEM_SUPPORT */ (3)设置U-Boot的版本号,初始化命令自动完成功能等。动态版本号功能支持代码,version_string变量是在其他文件定义的一个字符串变量,当用户改变U-Boot版本的时候会更新该变量。打开动态版本支持功能后,U-Boot在启动的时候会显示最新的版本号。 #ifdef CONFIG_VERSION_VARIABLE { extern char version_string[]; //在lib_arm/board.c中定义有此字符串 setenv ("ver", version_string); /* set version variable */ //将版本号写入flash } #endif /* CONFIG_VERSION_VARIABLE */ #ifdef CFG_HUSH_PARSER u_boot_hush_start (); #endif #ifdef CONFIG_AUTO_COMPLETE /// 初始化命令自动完成功能 install_auto_complete(); #endif //设置命令行自动完成功能,该功能与Linux的shell类似,当用户输入一部分命令后,可以通过按下键盘上的Tab键 //补全命令的剩余部分。main_loop()函数不同的功能使用宏开关控制不仅能提高代码模块化,更主要的是针对嵌入 //式系统Flash存储器大小设计的。在嵌入式系统上,不同的系统Flash存储空间不同。对于一些Flash空间比较紧张 //的设备来说,通过宏开关关闭一些不是特别必要的功能如命令行自动完成,可以减小U-Boot编译后的文件大小。 #ifdef CONFIG_PREBOOT if ((p = getenv ("preboot")) != NULL) { # ifdef CONFIG_AUTOBOOT_KEYED int prev = disable_ctrlc(1); /* disable Control C checking */ // 关闭Crtl+C组合键 # endif # ifndef CFG_HUSH_PARSER run_command (p, 0); # else parse_string_outer(p, FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP); # endif # ifdef CONFIG_AUTOBOOT_KEYED disable_ctrlc(prev); /* restore Control C checking */ // 恢复Ctrl+C组合键 # endif } #endif /* CONFIG_PREBOOT */ (4)启动延迟功能,需要等待用户从串口或者网络接口输入。如果用户按下任意键打断,启动流程,会向终端打印出一个启动菜单。 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0) s = getenv ("bootdelay");//获得启动延时时间环境变量 bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; debug ("### main_loop entered: bootdelay=%dnn", bootdelay); # ifdef CONFIG_BOOT_RETRY_TIME init_cmd_timeout ();// 初始化命令行超时机制 # endif /* CONFIG_BOOT_RETRY_TIME */ #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"); // 获取启动命令参数 debug ("### main_loop: bootcmd="%s"n", s ? s : " //在启动命令非0(有启动命令)的情况下,如果在启动延时时间到之前按下键终止了,abortboot返回1,否则如果一 //直没有键按下,直到启动延时时间到,那么函数返回0。所以,如果按下键了,就可以跳过启动操作系统;如果没 //按就直接启动操作系统了。 if (bootdelay >= 0 && s && !abortboot (bootdelay)) { # ifdef CONFIG_AUTOBOOT_KEYED int prev = disable_ctrlc(1); /* disable Control C checking *///关闭control+c组合键 # endif # ifndef CFG_HUSH_PARSER run_command (s, 0); //运行启动命令,启动操作系统 # else parse_string_outer(s, FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP); # endif # ifdef CONFIG_AUTOBOOT_KEYED disable_ctrlc(prev); /* restore Control C checking *///恢复control+c组合键功能 # endif } # ifdef CONFIG_MENUKEY if (menukey == CONFIG_MENUKEY) {//检查是否支持菜单键 s = getenv("menucmd"); if (s) { # ifndef CFG_HUSH_PARSER run_command (s, 0); # else parse_string_outer(s, FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP); # endif } } #endif /* CONFIG_MENUKEY */ #endif /* CONFIG_BOOTDELAY */ #ifdef CONFIG_AMIGAONEG3SE { extern void video_banner(void); video_banner(); // 打印启动图标 } #endif (5)读取命令,解析命令。这是一个for死循环,该循环不断使用readline()函数(第463行)从控制台(一般是串口)读取用户的输入,然后解析。有关如何解析命令请参考U-Boot代码中run_command()函数的定义。 /* * Main Loop for Monitor Command Processing */ #ifdef CFG_HUSH_PARSER parse_file_outer(); /* This point is never reached */ for (;;); #else for (;;) { #ifdef CONFIG_BOOT_RETRY_TIME if (rc >= 0) { /* Saw enough of a valid command to * restart the timeout. */ reset_cmd_timeout();// 设置命令行超时 } #endif len = readline (CFG_PROMPT);// 读取命令,读取到的命令存储在全局变量console_buffer 中 flag = 0; /* assume no special flags for now */ if (len > 0) //命令长度大于0 strcpy (lastcommand, console_buffer);//将读取到的命令copy到lastcommand中 else if (len == 0) flag |= CMD_FLAG_REPEAT; #ifdef CONFIG_BOOT_RETRY_TIME else if (len == -2) { /* -2 means timed out, retry autoboot */ puts ("nTimed out waiting for commandn"); # ifdef CONFIG_RESET_TO_RETRY /* Reinit board to run initialization code again */ do_reset (NULL, 0, 0, NULL); # else return; /* retry autoboot */ # endif } #endif if (len == -1) puts (" else rc = run_command (lastcommand, flag);//解析并运行命令 if (rc <= 0) { /* invalid command or not repeatable, forget it */ lastcommand[0] = 0; } } #endif /*CFG_HUSH_PARSER*/ } |
|
|
|
|
|
最后一天了,我还赶上了。
我最近在看的是鸟哥linux基础篇. 顺便回答问题。。。。 1.lowlevel_init函数完成了哪些初始化? 答:lowlevel_init函数主要是进行与开发板相关的初始化工作,如看门狗、中断设置、配置系统时钟,初始化串口、初始化内存和初始化唤醒复位等等。 2.DDR的内存是如何分配? 答: SDRAM的末位物理地址为0x5800 0000,即SDRAM的空间分布为0x5000 0000~0x57FF FFFF SDRAM的最后64K(addr &= ~(0x10000 - 1))分配给TLB,所分配的地址为:0x57FF 0000~0x57FF FFFF SDRAM中从后往前给u-boot分配BSS、数据段、代码段,分配地址为:0x57F7 5000~0x57FE FFFF 从后往前紧挨着代码段开辟一块了malloc空间,给予的地址为:0x57E6 D000~0x57E7 4FFF 为bd结构体分配空间,地址为:0x57E6 CFD8~0x57E6 CFFF 给gd结构体分配空间,地址为:0x57E6 CF60~0x57E6 CFD7 分配异常中断空间,地址:0x57E6 CF50~0x57E6 CF5F 3.Main_loop()函数的作用是什么? 答:Main_loop()函数的主要作用即是U-Boot启动管理,其他如: 1、 HUSH的相关初始化 2、 bootdelay的初始化 3、 启动次数 4、 Modem功能 5、 设置U-Boot版本号 6、 启动tftp功能 7、 打印启动菜单 |
|
|
|
|
|
《具身智能机器人系统》第1-6章阅读心得之具身智能机器人系统背景知识与基础模块
1103 浏览 0 评论
1098 浏览 12 评论
904 浏览 0 评论
【「嵌入式系统设计与实现」阅读体验】“基于车牌识别的自动地锁”案例学习
931 浏览 0 评论
【「HarmonyOS NEXT启程:零基础构建纯血鸿蒙应用」阅读体验】+ 8-10章有感
638 浏览 0 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-24 04:43 , Processed in 1.108973 second(s), Total 94, Slave 78 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号