[转载]U-boot分析

u-boot分析(2)

前面已经准备好了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,参数是void。int的返回值,应该是标记程序运行的结果状态。

   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

#ifdefCONFIG_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(boardsamsungsmdk2410):TEXT_BASE = 0x33F80000

所以_armboot_start =0x33F80000

#define CONFIG_SYS_MALLOC_LEN                (CONFIG_ENV_SIZE + 128*1024)

#defineCONFIG_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 }

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

总的来说,设置了时钟、gpio、gd->bd->bi_arch_number、gd->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, #1n"

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

    70 }

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

内部是嵌入汇编,看不懂的话,看看《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>

voidicache_enable(void)

{

        cache_enable(CR_I);

}

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

 

static voidcache_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 intget_cr(void)

{

        unsigned int val;

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

        return val;

}

cp15 register1 bit2 fordcache, bit12 for icache

static void cp_delay(void)

{

        volatile int i;

        

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

                  nop();

}

#define nop() __asm____volatile__("movtr0,r0t@ nopnt");

相当于mov r0 r0

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

static inline voidset_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 voiddcache_enable(void)

和icache_enable()一样

 

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

inttimer_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 }

#definewritel(v,a)                     __arch_putl(v,a)

#define__arch_putl(v,a)         (*(volatile unsigned int *)(a) = (v))

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

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

 

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的值

#defineCONFIG_ENV_ADDR          (CONFIG_SYS_FLASH_BASE + 0x0F0000)

#defineCONFIG_SYS_FLASH_BASE         PHYS_FLASH_1

#definePHYS_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 intdev_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 ("nn%snn", version_string);

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

   140           _armboot_start, _bss_start, _bss_end);

   141 #ifdef CONFIG_MODEM_SUPPORT

   142    debug ("Modem Support enabledn");

   143 #endif

   144 #ifdef CONFIG_USE_IRQ

   145    debug ("IRQ Stack: lxn", IRQ_STACK_START);

   146    debug ("FIQ Stack: lxn", 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 }

#defineCONFIG_NR_DRAM_BANKS             

#definePHYS_SDRAM_1         0x30000000

#definePHYS_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 }

打印出内存信息

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值