Uboot源码.docx
- 文档编号:29123389
- 上传时间:2023-07-20
- 格式:DOCX
- 页数:38
- 大小:27.18KB
Uboot源码.docx
《Uboot源码.docx》由会员分享,可在线阅读,更多相关《Uboot源码.docx(38页珍藏版)》请在冰豆网上搜索。
Uboot源码
uboot源码阅读
这篇文章属于转载
cpu/arm920t/start.S
在开始处首先定义了一个全局的标签,
.globl_start
这个是整个uboot程序的入口,可在链接脚本board/s3c2410/u-boot.lds中找到。
这个标签所指的地址处就是一跳转指令
_start:
breset
开始复位。
reset:
/*
*setthecputoSVC32mode
*/
mrsr0,cpsr
bicr0,r0,#0x1f
/*disableIRQandFIQ,ARMinstructset,supervisormode.addedbyBoySKung*/
orrr0,r0,#0xd3
msrcpsr,r0
首先将cpu设置为supervisor模式。
通过设置cpsr的低5位为10011实现,并禁止IRQ、FIQ。
即cpsr的第七第六位设置为11.
接着关闭看门狗定时器
ldrr0,=pWTCON
movr1,#0x0
strr1,[r0]
将看门狗定时器控制寄存器置0。
ldrr0,=CLKDIVN
movr1,#3
strr1,[r0]
设置FCLK:
HCLK:
PCLK为1:
2:
4,通过设置CLKDIVN控制寄存器的HDIVN、PDIVN值实现不同的
比例
00(1:
1:
1)
01(1:
1:
2)
10(1:
2:
2)
11(1:
2:
4)
这些然后开初始化cpu
cpu_init_crit:
/*
*flushv4I/Dcaches
*/
movr0,#0
mcrp15,0,r0,c7,c7,0/*flushv3/v4cache*/
mcrp15,0,r0,c8,c7,0/*flushv4TLB*/
首先关闭ICache和DCache.
/*
*disableMMUstuffandcaches
*/
mrcp15,0,r0,c1,c0,0
bicr0,r0,#0x00002300@clearbits13,9:
8(--V---RS)
bicr0,r0,#0x00000087@clearbits7,2:
0(B----CAM)
orrr0,r0,#0x00000002@setbit2(A)Align
orrr0,r0,#0x00001000@setbit12(I)I-Cache
mcrp15,0,r0,c1,c0,0
关闭MMU,数据存储格式为小端。
开启数据地址对齐错误检测,使能ICACHE。
/*
*beforerelocating,wehavetosetupRAMtiming
*becausememorytimingisboard-dependend,youwill
*findamemsetup.Sinyourboarddirectory.
*/
movip,lr
blmemsetup
movlr,ip
movpc,lr
还要对内存时序进行设置,因为内存时序是依赖于开发板的。
Cpu初始化结束后,开始初始化串口uart
@InitializeUART
@
@r0=numberofUARTport
InitUART:
ldrr1,=0x
movr2,#0x0
strr2,[r1,#0x8]
strr2,[r1,#0xc]
movr2,#0x3
strr2,[r1,#0x0]
ldrr2,=0x245
strr2,[r1,#0x4]
/*=PCLK=202.8/4=50.7whenFCLKat202.8*/
#defineUART_BRD((/(115200*16))-1)
movr2,#UART_BRD
strr2,[r1,#0x28]
这里主要对uart的一些控制寄存器进行了设置,并设置了串口的波特率
movr3,#100
movr2,#0x0
1:
subr3,r3,#0x1
tstr2,r3
bne1b
movpc,lr
这里是一段延时,具体起什么作用还不清楚。
这些初始化都结束后开始代码重定位
relocate:
/*relocateU-BoottoRAM*/
adrr0,_start/*r0<-currentpositionofcode*/
ldrr1,_TEXT_BASE/*testifwerunfromflashorRAM*/
cmpr0,r1/*don'trelocduringdebug*/
beqstack_setup
ldrr2,_armboot_start
ldrr3,_bss_start
subr2,r3,r2/*r2<-sizeofarmboot*/
addr2,r0,r2/*r2<-sourceendaddress*/
copy_loop:
ldmiar0!
{r3-r10}/*copyfromsourceaddress[r0]*/
stmiar1!
{r3-r10}/*copytotargetaddress[r1]*/
cmpr0,r2/*untilsourceendaddreee[r2]*/
blecopy_loop
重定位时,首先检查当前是不是在ram中运行,若是则不需重定位
紧接着设置堆栈
stack_setup:
@ldrr1,=0x
@ldrr0,[r1]
@blPrintHexWord
/*enteransynchronous,whencpuat202.8MHZ,itmustintoasynchronousmode*/
mrcp15,0,r1,c1,c0,0@readctrlregister
orrr1,r1,#0xc0000000@Asynchronous
mcrp15,0,r1,c1,c0,0@writectrlregister
ldrr0,_TEXT_BASE/*upper128KiB:
relocateduboot*/
subr0,r0,#CFG_MALLOC_LEN/*mallocarea*/
subr0,r0,#CFG_GBL_DATA_SIZE/*bdinfo*/
#ifdefCONFIG_USE_IRQ
subr0,r0,#(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
subsp,r0,#12/*leave3wordsforabort-stack*/
清除bss段
clear_bss:
ldrr0,_bss_start/*findstartofbsssegment*/
addr0,r0,#4/*startatfirstbyteofbss*/
ldrr1,_bss_end/*stophere*/
movr2,#0x00000000/*clear*/
clbss_l:
strr2,[r0]/*clearloop...*/
addr0,r0,#4
cmpr0,r1
bneclbss_l
就是将bss段全部置0
最后
ldrpc,_start_armboot
开始进入c的世界,uboot启动的stage2
Lib_arm/board.c
当第一阶段的汇编部分执行完,跳到stage2时,开始执行c函数start_armboot
开头首先声明一个全局指针变量DECLARE_GLOBAL_DATA_PTR;这个宏定义在头文件
include/asm-arm/global_data.h中
#defineDECLARE_GLOBAL_DATA_PTRregistervolatilegd_t*gdasm("r8")
typedefstructglobal_data{
bd_t*bd;
unsignedlongflags;
unsignedlongbaudrate;
unsignedlonghave_console;/*serial_init()wascalled*/
unsignedlongreloc_off;/*RelocationOffset*/
unsignedlongenv_addr;/*AddressofEnvironmentstruct*/
unsignedlongenv_valid;/*ChecksumofEnvironmentvalid?
*/
unsignedlongfb_base;/*baseaddressofframebuffer*/
#ifdefCONFIG_VFD
unsignedcharvfd_type;/*displaytype*/
#endif
#if0
unsignedlongcpu_clk;/*CPUclockinHz!
*/
unsignedlongbus_clk;
unsignedlongram_size;/*RAMsize*/
unsignedlongreset_status;/*resetstatusregisteratboot*/
#endif
void**jt;/*jumptable*/
}gd_t;
在这个结构中存放一些全局数据。
gd=(gd_t*)(_armboot_start-CFG_MALLOC_LEN-sizeof(gd_t));
这行是对指针的初始化。
接下来通过一个循环,执行初始化序列中的一些函数
for(init_fnc_ptr=init_sequence;*init_fnc_ptr;++init_fnc_ptr){
if((*init_fnc_ptr)()!
=0){
hang();
}
}
初始化序列的定义如下:
init_fnc_t*init_sequence[]={
cpu_init,//初始化cpu,主要是设置FIQ和IRQ的堆栈起始地址
board_init,//开发板初始化,设置电源、时钟、I/O端口及全能I/DCache
interrupt_init,//中断初始化,设置PWM时钟
env_init,//环境变量初始化,检测环境变量是否有效,并初始化相全局变
量
init_baudrate,//初始化波特率,设置板子通信时的波特率
serial_init,//初始化串口,设置串口和通信时数据结构,包括起始/停止位等
console_init_f,//控制台初始化,将控制台设置为silent模式
display_banner,//打印板子相关信息
dram_init,//内存初始化,设置内存的起始地址和大小
display_dram_config,//显示内存配置信息
#ifdefined(CONFIG_VCMA9)
checkboard,
#endif
NULL,
};
这些初始化都完成后开始初始化flash
unsignedlongflash_init(void)
{
unsignedlongsize_b0;
inti;
/*Init:
noFLASHesknown*/
for(i=0;i flash_info[i].flash_id=FLASH_UNKNOWN; } /*StaticFLASHBankconfigurationhere-FIXMEXXX*/ #if1 debug("\n##Getflashbank1size@0x%08x\n",CFG_FLASH_BASE); #endif //根据flash的基地址CFG_FLASH_BASE,获得flash的大小, size_b0=flash_get_size((vu_short*)CFG_FLASH_BASE,&flash_info[0]); if(flash_info[0].flash_id==FLASH_UNKNOWN){ printf("##UnknownFLASHonBank0: " "ID0x%lx,Size=0x%08lx=%ldMB\n", flash_info[0].flash_id, size_b0,size_b0<<20); } //获得并保存flash各块的起始地址 flash_get_offsets(CFG_FLASH_BASE,&flash_info[0]); //保存flash的大小 flash_info[0].size=size_b0; //下面是根据配置,对flash中相应块进行保护,以免数据丢失。 #ifCFG_MONITOR_BASE>=CFG_FLASH_BASE /*monitorprotectionONbydefault*/ flash_protect(FLAG_PROTECT_SET, CFG_MONITOR_BASE, CFG_MONITOR_BASE+monitor_flash_len-1, &flash_info[0]); #endif #ifdefCFG_ENV_IS_IN_FLASH /*ENVprotectionONbydefault*/ flash_protect(FLAG_PROTECT_SET, CFG_ENV_ADDR, CFG_ENV_ADDR+CFG_ENV_SECT_SIZE-1, &flash_info[0]); #endif returnsize_b0; } 然后是初始内存堆 static voidmem_malloc_init(ulongdest_addr) { mem_malloc_start=dest_addr; mem_malloc_end=dest_addr+CFG_MALLOC_LEN; mem_malloc_brk=mem_malloc_start; memset((void*)mem_malloc_start,0, mem_malloc_end-mem_malloc_start); } 之后要进行环境变量重定位,把环境变量放到内存当中 env_relocate(); 还要设置网卡的ip地址和mac地址 /*IPAddress*/ gd->bd->bi_ip_addr=getenv_IPaddr("ipaddr"); /*MACAddress*/ { inti; ulongreg; char*s,*e; uchartmp[64]; i=getenv_r("ethaddr",tmp,sizeof(tmp)); s=(i>0)? tmp: NULL; for(reg=0;reg<6;++reg){ gd->bd->bi_enetaddr[reg]=s? simple_strtoul(s,&e,16): 0; if(s) s=(*e)? e+1: e; } } 设备初始化 intdevices_init(void) { char*s; #ifndefCONFIG_ARM/*alreadyrelocatedforcurrentARMimplementation*/ DECLARE_GLOBAL_DATA_PTR; ulongrelocation_offset=gd->reloc_off; inti; /*relocatedevicenamepointers*/ for(i=0;i<(sizeof(stdio_names)/sizeof(char*));++i){ stdio_names[i]=(char*)(((ulong)stdio_names[i])+ relocation_offset); } #endif /*Initializethelist*/ devlist=ListCreate(sizeof(device_t)); if(devlist==NULL){ eputs("Cannotinitializethelistofdevices! \n"); return-1; } #ifdefined(CONFIG_HARD_I2C)||defined(CONFIG_SOFT_I2C) i2c_init(CFG_I2C_SPEED,CFG_I2C_SLAVE); #endif #ifdefCONFIG_LCD drv_lcd_init(); #endif #ifdefined(CONFIG_VIDEO)||defined(CONFIG_CFB_CONSOLE) if((s=getenv("sm501mode"))! =NULL) { sm501mode=simple_strtoul(s,NULL,10); if(! (sm501mode>=1&&sm501mode<=13)) { printf("sm501modeerror,setsm501modeto1! \n"); sm501mode=1; } } if((s=getenv("sm501bpp"))! =NULL) { sm501bpp=simple_strtoul(s,NULL,10); if(sm501mode! =16) { printf("sm501bpperror,only16bppvalid,setsm501bppto16! \n"); sm501bpp=16; } } drv_video_init(); #endif #ifdefCONFIG_KEYBOARD //drv_keyboard_init(); #endif #ifdefCONFIG_LOGBUFFER drv_logbuff_init(); #endif drv_system_init(); return(0); } 这里要创建一个设备列表,把一些设备放入这个表中,初始化i2c总线,设置sm501显卡, 初始化视频设备,初始化并注册个别系统设备。 voidjumptable_init(void) { DECLARE_GLOBAL_DATA_PTR; inti; gd->jt=(void**)malloc(XF_MAX*sizeof(void*)); for(i=0;i gd->jt[i]=(void*)dummy; gd->jt[XF_get_version]=(void*)get_version; gd->jt[XF_malloc]=(void*)malloc; gd->jt[XF_free]=(void*)free; gd->jt[XF_get_timer]=(void*)get_timer; gd->jt[XF_udelay]=(void*)udelay; #ifdefined(CONFIG_I386)||defined(CONFIG_PPC) gd->jt[XF_install_hdlr]=(void*)irq_install_handler; gd->jt[XF_free_hdlr]=(void*)irq_free_handler; #endif/*I386||PPC*/ #if(CONFIG_COMMANDS&CFG_CMD_I2C) gd->jt[XF_i2c_write]=(void*)i2c_write; gd->jt[XF_i2c_read]=(void*)i2c_read; #endif/*CFG_CMD_I2C*/ } 初始化跳转表,主要是保存了一些系统函数的指针。 便于以后引用 然后对控制台进行全面的初始化 console_init_r();/*fullyinitconsoleasadevice*/ 主要是初始化控制台输入输出设备 接下来开中断 /*enableexceptions*/ enable_interrupts(); 初始化网卡设备等 /*Performnetworkcardinitialisationifnecessary*/ #ifdefCONFIG_DRIVER_DM9000 DM9000_get_enetaddr(gd->bd->bi_enetaddr); #endif 最后进入主循环 /*main_loop()canreturntoretryautoboot,ifsojustrunitagain.*/ for(;;){ main_loop(); } 在这个循环中,将检测是自动启动还是命令行起动。 起动后,uboot的stage2也就结束了 Uboot中的每一个命令都由一个宏进行声明,这宏在文件include/command.h中定义 #defineU_BOOT_CMD(name,maxargs,rep,cmd,usage,help)\ cmd_tbl_t__u_boot_cmd_##nameStruct_Section={#name,maxargs,rep,cmd,usage,help} 如i2c设备操作中的某个命令的声明如下 U_BOOT_CMD( imd,4,1,do_i2c_md,\ "imd-i2cmemorydisplay\n",\ "chipaddress[.0,.1,.2][#ofobjects]\n-i2cmemorydisplay\n"\ ); 这个声明里初始化了cmd_tbl_t结构 structcmd_tbl_s{ char*name;/*CommandName*/ intmaxargs;/*maximumnumber
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Uboot 源码