u-boot分析(2)

来源:互联网 发布:网络吞吐率 编辑:程序博客网 时间:2024/06/06 00:11

前面已经准备好了sp指针,而且pc也指向了start_armboot,下面就该运行这个c函数了。

start_armboot()lib_arm/board.c中,我想一行一行的分析,练习基本功。

void start_armboot (void)

首先分析参数和返回值(由于不是计算机专业毕业的,只能做些基础的分析),这个函数的返回值和参数都是空,它对系统的影响只能体现在对全局量的改变上。

    272 {

    273     init_fnc_t **init_fnc_ptr;

    274     char *s;

    275 #if defined(CONFIG_VFD) || defined(CONFIG_LCD)

    276     unsigned long addr;

277 #endif

init_fnc_t类型的定义在前面

233 typedef int (init_fnc_t) (void);

返回值是int,参数是voidint的返回值,应该是标记程序运行的结果状态。

    279    

    280     gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));

    281    

    282     __asm__ __volatile__("": : :"memory");

    284     memset ((void*)gd, 0, sizeof (gd_t));

    285     gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));

    286     memset (gd->bd, 0, sizeof (bd_t));

    288     gd->flags |= GD_FLG_RELOC;

    290     monitor_flash_len = _bss_start - _armboot_start;

结构体gd_t保存了一些全局信息,需要用到的时候才看

typedef    struct       global_data {

         bd_t          *bd;

         unsigned long  flags;

         unsigned long  baudrate;

         unsigned long  have_console;

         unsigned long  env_addr;        

         unsigned long  env_valid;        

         unsigned long  fb_base; 

#ifdef CONFIG_VFD

         unsigned char  vfd_type;

#endif

#ifdef CONFIG_FSL_ESDHC

         unsigned long  sdhc_clk;

#endif

         void           **jt;         

} gd_t;

其中成员bd_t是板子信息

typedef struct bd_info {

    int                       bi_baudrate;   

    unsigned long  bi_ip_addr;      

    struct environment_s             *bi_env;

    ulong                bi_arch_number;    

    ulong                bi_boot_params;    

    struct                                  

    {

         ulong start;

         ulong size;

    }                           bi_dram[CONFIG_NR_DRAM_BANKS];

} bd_t;

从成员名字上就能看出各个的作用,其中有波特率,ip地址,环境参数,板子id,板子参数,内存等信息。

_TEXT_BASE:

         .word        TEXT_BASE

.globl _armboot_start

_armboot_start:

         .word _start

可以看出_armboot_start = _start = TEXT_BASE

Config.mk (board\samsung\smdk2410):TEXT_BASE = 0x33F80000

所以_armboot_start = 0x33F80000

#define CONFIG_SYS_MALLOC_LEN                 (CONFIG_ENV_SIZE + 128*1024)

#define CONFIG_ENV_SIZE               0x10000  

CONFIG_SYS_MALLOC_LEN = 64K + 128K = 192K

其中64K用来放环境变量,另外128K用来作为动态内存(malloc分配),看来u_boot只需要128K内存就可以了。

280行指定gd存放地址

285行指定gd的成员gd->bd存放地址

内存分配的一部分,如下图所示:

 

另外几个暂时不知道意思,用到时候再看

    292     for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {

    293         if ((*init_fnc_ptr)() != 0) {

    294             hang ();

    295         }

    296     }

init_sequence在同一文件的上面一点定义如下:

    237 init_fnc_t *init_sequence[] = {

    238 #if defined(CONFIG_ARCH_CPU_INIT)

    239     arch_cpu_init,     

    240 #endif

    241     board_init,    

    242 #if defined(CONFIG_USE_IRQ)

    243     interrupt_init,    

    244 #endif

    245     timer_init,    

    246 #ifdef CONFIG_FSL_ESDHC

    247     get_clocks,

    248 #endif

    249     env_init,      

    250     init_baudrate,     

    251     serial_init,       

    252     console_init_f,    

    253     display_banner,    

    254 #if defined(CONFIG_DISPLAY_CPUINFO)

    255     print_cpuinfo,     

    256 #endif

    257 #if defined(CONFIG_DISPLAY_BOARDINFO)

    258     checkboard,    

    259 #endif

    260 #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)

    261     init_func_i2c,

    262 #endif

    263     dram_init,     

    264 #if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)

    265     arm_pci_init,

    266 #endif

    267     display_dram_config,

    268     NULL,

    269 };

293 挨个运行其中初始化函数,每个函数都是没有参数的,返回值表示运行结果状态。

这里以文件include/configs/sbc2410x.h为线索。

1. board/sbc2410x/sbc2410x.c

int board_init (void)

没有参数的函数,和前面分析的定义一样。

     72

     76 int board_init (void)

     77 {

     78     struct s3c24x0_clock_power * const clk_power =

     79                     s3c24x0_get_base_clock_power();

     80     struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();

     82    

     83     clk_power->LOCKTIME = 0xFFFFFF;

     85    

     86     clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);

     88    

     89     delay (4000);

     91    

     92     clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);

     94    

     95     delay (8000);

     97    

     98     gpio->GPACON = 0x007FFFFF;

     99     gpio->GPBCON = 0x00044556;

    100     gpio->GPBUP = 0x000007FF;

    101     gpio->GPCCON = 0xAAAAAAAA;

    102     gpio->GPCUP = 0x0000FFFF;

    103     gpio->GPDCON = 0xAAAAAAAA;

    104     gpio->GPDUP = 0x0000FFFF;

    105     gpio->GPECON = 0xAAAAAAAA;

    106     gpio->GPEUP = 0x0000FFFF;

    107     gpio->GPFCON = 0x000055AA;

    108     gpio->GPFUP = 0x000000FF;

    109     gpio->GPGCON = 0xFF95FF3A;

    110     gpio->GPGUP = 0x0000FFFF;

    111     gpio->GPHCON = 0x0016FAAA;

    112     gpio->GPHUP = 0x000007FF;

    114     gpio->EXTINT0=0x22222222;

    115     gpio->EXTINT1=0x22222222;

    116     gpio->EXTINT2=0x22222222;

    118    

    119     gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;

    121    

    122     gd->bd->bi_boot_params = 0x30000100;

    124     icache_enable();

    125     dcache_enable();

    127     return 0;

    128 }

这样子的函数,由于没有参数,返回值也只是反映运行的结果状态,很好懂。

总的来说,设置了时钟、gpiogd->bd->bi_arch_numbergd->bd->bi_boot_params、打开数据和指令cache

1.1 分析一下delay()这个函数

     65 static inline void delay (unsigned long loops)

     66 {

     67     __asm__ volatile ("1:\n"

     68               "subs %0, %1, #1\n"

     69               "bne 1b":"=r" (loops):"0" (loops));

     70 }

是个内联函数,没有返回值,参数是unsigned long,表示延时循环的次数。

内部是嵌入汇编,看不懂的话,看看《linux内核代码情景分析》第一章就没有问题了。

展开为汇编如下(这里假设loops变量存放在寄存器t0中):

1

subs t0, t0, #1          //运行t0 = t0 -1

bne 1b                         //如果t0 == 0结束,否则跳回标号1处,运行

一共运行loops次结束,用这个方式产生延时。如第89行的delay (4000)语句是延时cpu运行4000次上面指令的时间,和现实中我们熟悉的时间单位s,ms,us,ns等没有明确关系。

1.2 分析icache_enable()

<lib_arm/cache-cp15.c>

void icache_enable(void)

{

         cache_enable(CR_I);

}

没有返回值,也没有参数,是个简单函数

 

static void cache_enable(uint32_t cache_bit)

{

         uint32_t reg;

         reg = get_cr();

         cp_delay();

         set_cr(reg | cache_bit);

}

<include/asm-arm/system.h>

static inline unsigned int get_cr(void)

{

         unsigned int val;

         asm("mrc p15, 0, %0, c1, c0, 0        @ get CR" : "=r" (val) : : "cc");

         return val;

}

cp15 register1 bit2 for dcache, bit12 for icache

static void cp_delay (void)

{

         volatile int i;

        

         for (i = 0; i < 100; i++)

                   nop();

}

#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");

相当于mov r0 r0

r0 = r0没啥意义,浪费时间用的

static inline void set_cr(unsigned int val)

{

         asm volatile("mcr p15, 0, %0, c1, c0, 0   @ set CR"

           : : "r" (val) : "cc");

         isb();

}

#define isb() __asm__ __volatile__ ("" : : : "memory")

相当于内存同步

设置cp15 register1  cache相应的位

1.3 void dcache_enable(void)

icache_enable()一样

 

2. < cpu/arm920t/s3c24x0/timer.c>

int timer_init(void)

简单函数

     52 int timer_init(void)

     53 {

     54     struct s3c24x0_timers *timers = s3c24x0_get_base_timers();

     55     ulong tmr;

     56    

     57    

     58    

     59     writel(0x0f00, &timers->TCFG0);

     60     if (timer_load_val == 0) {

     61        

     66         timer_load_val = get_PCLK() / (2 * 16 * 100);

     67         timer_clk = get_PCLK() / (2 * 16);

     68     }  

     69    

     70     lastdec = timer_load_val;

     71     writel(timer_load_val, &timers->TCNTB4);

     72    

     73     tmr = (readl(&timers->TCON) & ~0x0700000) | 0x0600000;

     74     writel(tmr, &timers->TCON);

     75    

     76     tmr = (tmr & ~0x0700000) | 0x0500000;

     77     writel(tmr, &timers->TCON);

     78     timestamp = 0;

     80     return (0);

     81 }

#define writel(v,a)                      __arch_putl(v,a)

#define __arch_putl(v,a)          (*(volatile unsigned int *)(a) = (v))

可见本处理器是ioram统一编制,直接取地址就可以了

本函数就是始终相关的初始化,简单,要结合寄存器手册看

 

3. <common/env_flash.c>

    246 int  env_init(void)

    247 {

    248     if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {

    249         gd->env_addr  = (ulong)&(env_ptr->data);

    250         gd->env_valid = 1;

    251         return(0);

    252     }

    254     gd->env_addr  = (ulong)&default_environment[0];

    255     gd->env_valid = 0;

    256     return (0);

    257 }

简单函数

uint32_t ZEXPORT crc32 (uint32_t crc, const Bytef *p, uInt len)

{

     return crc32_no_comp(crc ^ 0xffffffffL, p, len) ^ 0xffffffffL;

}

算出CRC校验值,比较是否正确。有兴趣的可以看看crc如何算出来的。

env_t *env_ptr = (env_t *)CONFIG_ENV_ADDR;

include/configs/sbc2410x.h中可以算出CONFIG_ENV_ADDR的值

#define CONFIG_ENV_ADDR           (CONFIG_SYS_FLASH_BASE + 0x0F0000)

#define CONFIG_SYS_FLASH_BASE          PHYS_FLASH_1

#define PHYS_FLASH_1             0x00000000

这种情况下是0x0F0000,这个地址是属于flash

0x0F0000处存放结构体env_t

typedef    struct environment_s {

         uint32_t   crc;           

         unsigned char  data[ENV_SIZE];

} env_t;

干啥用的,以后用的时候才能知道,也才需要知道

254行,如果没有定义,就采用默认的。

默认的是default_environment,可以看到里面都是启动配置信息

 

4. <lib_arm/board.c>

    125 static int init_baudrate (void)

    126 {

    127     char tmp[64];  

    128     int i = getenv_r ("baudrate", tmp, sizeof (tmp));

    129     gd->bd->bi_baudrate = gd->baudrate = (i > 0)

    130             ? (int) simple_strtoul (tmp, NULL, 10)

    131             : CONFIG_BAUDRATE;

    133     return (0);

    134 }

128行在上面的环境变量中查找baudrate字符串,看看有没有设置正确的波特率,有的话就设置上。

 

5. <drivers/serial/serial_s3c24x0.c>

    163 int serial_init(void)

    164 {

    165     return serial_init_dev(UART_NR);

166 }

124 static int serial_init_dev(const int dev_index)

    125 {

    126     struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);

    128 #ifdef CONFIG_HWFLOW

    129     hwflow = 0;

    130 #endif

    132    

    133     writel(0x07, &uart->UFCON);

    134     writel(0x0, &uart->UMCON);

    136    

    137     writel(0x3, &uart->ULCON);

    138    

    142     writel(0x245, &uart->UCON);

    144 #ifdef CONFIG_HWFLOW

    145     writel(0x1, &uart->UMCON); 

    146 #endif

    148    

    149 #if defined(CONFIG_ARCH_GTA02_v1) || defined(CONFIG_ARCH_GTA02_v2)

    150    

    151     if (dev_index == 0 || dev_index == 1)

    152         writel(0x10, &uart->UMCON);

    153 #endif

    154     _serial_setbrg(dev_index);

    156     return (0);

    157 }

     94 void _serial_setbrg(const int dev_index)

     95 {

     96     struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);

     97     unsigned int reg = 0;

     98     int i;

     99

    100    

    101     reg = get_PCLK() / (16 * gd->baudrate) - 1;

    102

    103     writel(reg, &uart->UBRDIV);

    104     for (i = 0; i < 100; i++)

    105         ;

106 }

初始化串口寄存器,相应的要看寄存器手册

 

6. <common/console.c>

    522

    523 int console_init_f(void)

    524 {

    525     gd->have_console = 1;

    527 #ifdef CONFIG_SILENT_CONSOLE

    528     if (getenv("silent") != NULL)

    529         gd->flags |= GD_FLG_SILENT;

    530 #endif

    532     return 0;

533 }

设置gd->have_console,表示有console

 

7. <lib_arm/board.c>

    136 static int display_banner (void)

    137 {

    138     printf ("\n\n%s\n\n", version_string);

    139     debug ("U-Boot code: lX -> lX  BSS: -> lX\n",

    140            _armboot_start, _bss_start, _bss_end);

    141 #ifdef CONFIG_MODEM_SUPPORT

    142     debug ("Modem Support enabled\n");

    143 #endif

    144 #ifdef CONFIG_USE_IRQ

    145     debug ("IRQ Stack: lx\n", IRQ_STACK_START);

    146     debug ("FIQ Stack: lx\n", FIQ_STACK_START);

    147 #endif

    148

    149     return (0);

150 }

打印信息

 

8. <board/sbc2410x/sbc2410x.c>

    130 int dram_init (void)

    131 {

    132     gd->bd->bi_dram[0].start = PHYS_SDRAM_1;

    133     gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;

    135     return 0;

    136 }

#define CONFIG_NR_DRAM_BANKS       1         

#define PHYS_SDRAM_1          0x30000000

#define PHYS_SDRAM_1_SIZE         0x04000000

64M内存,在0x30000000

 

9. <lib_arm/board.c>

    159 static int display_dram_config (void)

    160 {

    161     int i;

    171     ulong size = 0;

173     for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) {

    174         size += gd->bd->bi_dram[i].size;

    175     }

    176     puts("DRAM:  ");

    177     print_size(size, "\n");

    180     return (0);

    181 }

打印出内存信息


原文见:http://blog.sina.com.cn/s/blog_559f6ffc0100mgw9.html

原创粉丝点击