七、uboot 代码流程分析---C环境建立

7.1 start.S 修改

  在上一节中的流程中,发现初始化的过程并没由设置看门狗,也未进行中断屏蔽

  如果看门狗不禁用,会导致系统反复重启,因此需要在初始化的时候禁用看门狗;中断屏蔽保证启动过程中不出现异常现象

  时钟不需要初始化,直接由外部晶振提供初始化,在第二阶段 C 部分再进行初始化。

  代码主要在 start.S 中进行修改。修改后的代码如下:

  1 /* 头文件包含 */
  2 #include <asm-offsets.h>
  3 #include <common.h>
  4 #include <config.h>
  5 
  6 /*
  7  *************************************************************************
  8  *
  9  * Startup Code (called from the ARM reset exception vector)
 10  *
 11  * do important init only if we don't start from memory!
 12  * relocate armboot to ram
 13  * setup stack
 14  * jump to second stage
 15  *
 16  *************************************************************************
 17  */
 18 
 19     .globl    reset
 20 
 21 reset:
 22     /*
 23      * set the cpu to SVC32 mode
 24      * 将 CPU 设置为管理员(SVC)模式
 25      */
 26     mrs    r0, cpsr        /* 将状态寄存器的内容传送至通用寄存器,将CPSR中的内容传送至R0 */
 27     bic    r0, r0, #0x1f   /* 位清除指令 将R0最低5位清零,其余位不变 工作模式位清零 */
 28     orr    r0, r0, #0xd3   /* 工作模式位设置为“10011”(管理模式),并将中断禁止位和快中断禁止位置1 "1101 0011" 指令用于在两个操作数上进行逻辑或运算,并把结果放置到目的寄存器中 */
 29     msr    cpsr, r0        /* 将通用寄存器的内容传送至状态寄存器,将中的内容R0传送至CPSR */
 30 
 31 #if    defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)
 32     /*
 33      * relocate exception table
 34      */
 35     ldr    r0, =_start
 36     ldr    r1, =0x0
 37     mov    r2, #16
 38 copyex:
 39     subs    r2, r2, #1
 40     ldr    r3, [r0], #4
 41     str    r3, [r1], #4
 42     bne    copyex
 43 #endif
 44 
 45 #ifdef CONFIG_S3C24X0    /* turn off the watchdog */
 46 /* JZ2440中未定义 */
 47 #if defined(CONFIG_S3C2400)
 48 #define pWTCON    0x15300000  /* 看门狗寄存器 */
 49 #define INTMSK    0x14400008    /* Interrupt-Controller base addresses */
 50 #define CLKDIVN    0x14800014    /* clock divisor register */
 51 #else    /* 定义控制寄存器地址 */
 52 #define pWTCON    0x53000000    /* 看门狗地寄存器地址 */
 53 #define INTMSK    0x4A000008    /* Interrupt-Controller base addresses */
 54 #define INTSUBMSK    0x4A00001C    /* 中断掩码 */
 55 #define CLKDIVN    0x4C000014    /* clock divisor register */
 56 #define S3C2440_MPLL_400MHZ    ((0x5c<<12)|(0x01<<4)|(0x01))
 57 #endif  /* end CONFIG_S3C2440 */
 58 
 59     /* 关闭看门狗 */    
 60     ldr    r0, =pWTCON                
 61     /* r0中存放看门狗寄存器地址 */    
 62     mov    r1, #0x0                /* 将立即数0存放到r1中,r1 = 0x0 */    
 63     str    r1, [r0]                /* 将r1中的值存放到以r0中的值为地址的存储单元中,即 pwTCON = 0 */
 64     
 65     /*     
 66      * mask all IRQs by setting all bits in the INTMR - default     
 67      * 屏蔽中断     */    
 68     mov    r1, #0xffffffff            /* 将立即数 0xffffffff 存放到r1中*/    
 69     ldr    r0, =INTMSK             /* r0中存放中断控制寄存器基地址 */    
 70     str    r1, [r0]                /* 将r1中的值存放到以r0中的值为地址的存储单元中,即 INTMSK = 0xffffffff */
 71 #if defined(CONFIG_S3C2440)    
 72     ldr    r1, =0x7fff    
 73     ldr    r0, =INTSUBMSK    
 74     str    r1, [r0]
 75 #endif  /* end CONFIG_S3C2440 */
 76 #endif    /* end CONFIG_S3C24X0 */
 77 
 78 
 79     /*
 80      * we do sys-critical inits only at reboot,
 81      * not when booting from ram!
 82      * 未从 ram 启动的时候,所做的CPU 关键初始化工作
 83      */
 84 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
 85     bl    cpu_init_crit       /* CPU 关键初始化 */
 86 #endif
 87 
 88     bl    _main           /* 跳转到 _main 开始执行,进行初始化C环境 和进行第二阶段 */
 89 
 90 /*------------------------------------------------------------------------------*/
 91 
 92     .globl    c_runtime_cpu_setup
 93 c_runtime_cpu_setup:
 94 
 95     mov    pc, lr
 96 
 97 /*
 98  *************************************************************************
 99  *
100  * CPU_init_critical registers
101  *
102  * setup important registers
103  * setup memory timing
104  *
105  *************************************************************************
106  */
107 
108 
109 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
110 cpu_init_crit:
111     /*
112      * flush v4 I/D caches
113      * 刷新L1 cache的icache和dcache
114      */
115     mov    r0, #0                  /* 置零r0通用寄存器 */
116     mcr    p15, 0, r0, c7, c7, 0    /* flush v3/v4 cache 向c7写入0将使ICache与DCache无效 "0"表示省略opcode_2 MCR{<cond>} p15, 0, <Rd>, <CRn>, <CRm>{,<opcode_2>}*/
117     mcr    p15, 0, r0, c8, c7, 0    /* flush v4 TLB MCR{条件} 协处理器编码,协处理器操作码1,源寄存器,目的寄存器1,目的寄存器2,协处理器操作码2 */
118 
119     /*
120      * disable MMU stuff and caches
121      * 关闭 MMU 及其 caches
122      */
123     mrc    p15, 0, r0, c1, c0, 0
124     bic    r0, r0, #0x00002300    @ clear bits 13, 9:8 (--V- --RS)
125     bic    r0, r0, #0x00000087    @ clear bits 7, 2:0 (B--- -CAM)
126     orr    r0, r0, #0x00000002    @ set bit 1 (A) Align
127     orr    r0, r0, #0x00001000    @ set bit 12 (I) I-Cache
128     mcr    p15, 0, r0, c1, c0, 0
129 
130 #ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
131     /*
132      * before relocating, we have to setup RAM timing
133      * because memory timing is board-dependend, you will
134      * find a lowlevel_init.S in your board directory.
135      */
136     mov    ip, lr          /* 保存当前程序地址到 ip  寄存器 */
137 
138     bl    lowlevel_init   /* 执行 SDRAM 初始化 */
139     mov    lr, ip
140 #endif
141     mov    pc, lr          /* 返回 */
142 #endif /* CONFIG_SKIP_LOWLEVEL_INIT */

7.2 _main --- C环境

  执行完一系列初始化后,开始跳转到 _main 中执行进行C环境初始化和第二阶段的代码  

  crt0.S (arch\arm\lib) 

  _main 执行过程如下:

  1. 建立调用 board_init_f() 的环境,此环境只是提供一个用来保存全局变量 GD 结构体的栈和空间,栈和空间都位于 SRAM 中。在调用board_init_f()前,GD 需要被清 0。
  2. 调用 board_init_f(),该函数从系统RAM(DRAM,DDR ...)准备将要执行的硬件。由于系统RAM可能还不可用,因此board_init_f()必须使用当前的GD来存储必须传递到后面阶段的任何数据。 这些数据包括重定位目标,未来堆栈和未来的GD位置。
  3. 设置中间环境,其中堆栈和GD是由系统RAM中的board_init_f()分配的,但BSS和初始化的 non-const 数据仍然不可用。
  4. 对于U-Boot本身(不是SPL),调用relocate_code()。 该函数将U-Boot从其当前位置重定位到由board_init_f()计算的重定位地址。
  5. 设置调用board_init_r()的最终环境。 这个环境具有BSS(初始化为0),初始化的 non-const 数据(初始化为其预期值),和系统RAM中的堆栈(用于SPL将堆栈和GD移入RAM是可选的 - 参见CONFIG_SPL_STACK_R)。 GD保留由board_init_f()设置的值。
  6. 对于U-Boot(不是SPL),有些CPU在内存方面还有一些工作要做,所以调用c_runtime_cpu_setup。
  7. 最后 跳到 board_init_r() 去执行

7.2.1 设置栈并初始化GD 和全局数据

 1 /*
 2  * Set up initial C runtime environment and call board_init_f(0).
 3  */
 4     /* CONFIG_SYS_INIT_SP_ADDR = 0x30000000 + 0x1000 - 0xE0 = 0x3000 0F20 */
 5     ldr    r0, =(CONFIG_SYS_INIT_SP_ADDR)
 6     bic    r0, r0, #7    /* 8-byte alignment for ABI compliance */
 7     mov    sp, r0        /* 栈指向 0x3000 0F20 */
 8     bl    board_init_f_alloc_reserve    /* 分配global_data的空间*/
 9     mov    sp, r0        /* 栈指向 GD 地址的起始位置 */
10     /* set up gd here, outside any C code */
11     mov    r9, r0        /* GD 的起始位置放入 R9 中,并作为入参传入给 board_init_f_init_reserve */
12     bl    board_init_f_init_reserve    /* 初始化global_data区域的代码 */
13 
14     mov    r0, #0            /* r0 = 0, 作为board_init_f的入参 */
15     bl    board_init_f    /* 板子初次初始化 */

7.2.2 board_init_f_alloc_reserve 

 1 /*  从'顶部'地址分配保留空间作为'全局'顶地址,并返回分配空间的'底部'地址
 2     分配global data所需的空间 
 3     如果定义了CONFIG_SYS_MALLOC_F_LEN,则会先预留出early malloc所需的空间。
 4     CONFIG_SYS_MALLOC_F_LEN = 0x400 */
 5 ulong board_init_f_alloc_reserve(ulong top)
 6 {
 7     /* Reserve early malloc arena */
 8 #if CONFIG_VAL(SYS_MALLOC_F_LEN)
 9     /* 从顶部向下分配一块CONFIG_SYS_MALLOC_F_LEN大小的空间给early malloc使用 */
10     /* 这块内存是用于在relocation前用于给malloc函数提供内存池。 */
11     top -= CONFIG_VAL(SYS_MALLOC_F_LEN);
12 #endif
13     /* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
14     /* 分配sizeof(struct global_data)大小的内存给global_data使用,向下16byte对齐 */
15     top = rounddown(top-sizeof(struct global_data), 16);
16 
17     return top; /* 将top,也就是global_data的地址返回 */
18 }

7.2.4 board_init_f_init_reserve

 1 /* 这个函数用于对global_data区域进行初始化,也就是清空global_data区域 */
 2 /* 传入的参数就是global_data的基地址 */
 3 void board_init_f_init_reserve(ulong base)
 4 {
 5     struct global_data *gd_ptr;
 6 
 7     /*
 8      * clear GD entirely and set it up.
 9      * Use gd_ptr, as gd may not be properly set yet.
10      */
11 
12     gd_ptr = (struct global_data *)base;
13     /* zero the area,贤ü齧emset函数对global_data数据结构进行清零 */
14     memset(gd_ptr, '\0', sizeof(*gd));
15     /* set GD unless architecture did it already */
16 #if !defined(CONFIG_ARM)
17     arch_setup_gd(gd_ptr);
18 #endif
19     /* next alloc will be higher by one GD plus 16-byte alignment */
20     /* global_data区域是16Byte对齐的,对齐后,后面的地址就是early malloc的内存池的地址 */
21     /* 这里就获取了early malloc的内存池的地址 */
22     base += roundup(sizeof(struct global_data), 16);
23 
24     /*
25      * record early malloc arena start.
26      * Use gd as it is now properly set for all architectures.
27      */
28 
29 #if CONFIG_VAL(SYS_MALLOC_F_LEN)
30     /* go down one 'early malloc arena', 内存池的地址写入到gd->malloc_base中 */
31     gd->malloc_base = base;
32     /* next alloc will be higher by one 'early malloc arena' size */
33     /* 加上CONFIG_SYS_MALLOC_F_LEN,获取early malloc的内存池的末尾地址,这里并没有什么作用,
34         是为了以后在early malloc的内存池后面多加一个区域时的修改方便。 */
35     base += CONFIG_VAL(SYS_MALLOC_F_LEN);
36 #endif
37 }

7.2.5 global_data内存分布

  

7.3 global data 结构体

  global_data的地址存放在r9中,当我们需要global_data的时候,直接从r9寄存器中获取其地址即可。

  uboot中定义了一个宏DECLARE_GLOBAL_DATA_PTR,使我们可以更加简单地获取global_data。

  定义如下: arch/arm/include/asm/global_data.h

扫描二维码关注公众号,回复: 107032 查看本文章
1 #ifdef CONFIG_ARM64
2 #define DECLARE_GLOBAL_DATA_PTR        register volatile gd_t *gd asm ("x18")
3 #else
4 #define DECLARE_GLOBAL_DATA_PTR        register volatile gd_t *gd asm ("r9")
5 #endif
6 #endif

  DECLARE_GLOBAL_DATA_PTR定义了gd_t *gd,并且其地址是r9中的值。 一旦使用了DECLARE_GLOBAL_DATA_PTR声明之后,后续就可以直接使用gd变量,也就是global_data了。

  Global_data.h (include\asm-generic)中定义了 global_data 的结构体

 1 typedef struct global_data {
 2     bd_t *bd;           /* board info数据结构定义,位于文件 include/asm-arm/u-boot.h定义,主要是保存开发板的相关参数。 */
 3     unsigned long flags; 
 4     unsigned int baudrate;
 5     unsigned long cpu_clk;        /* CPU clock in Hz!        */
 6     unsigned long bus_clk;
 7     /* We cannot bracket this with CONFIG_PCI due to mpc5xxx */
 8     unsigned long pci_clk;
 9     unsigned long mem_clk;
10 #if defined(CONFIG_LCD) || defined(CONFIG_VIDEO)
11     unsigned long fb_base;        /* Base address of framebuffer mem */
12 #endif
13 #if defined(CONFIG_POST)
14     unsigned long post_log_word;    /* Record POST activities */
15     unsigned long post_log_res;    /* success of POST test */
16     unsigned long post_init_f_time;    /* When post_init_f started */
17 #endif
18 #ifdef CONFIG_BOARD_TYPES
19     unsigned long board_type;
20 #endif
21     unsigned long have_console;    /* serial_init() was called */
22 #if CONFIG_IS_ENABLED(PRE_CONSOLE_BUFFER)
23     unsigned long precon_buf_idx;    /* Pre-Console buffer index */
24 #endif
25     unsigned long env_addr;        /* Address  of Environment struct,环境变量的地址*/
26     unsigned long env_valid;    /* Environment valid? enum env_valid */
27     unsigned long env_has_init;    /* Bitmask of boolean of struct env_location offsets */
28     int env_load_location;
29 
30     unsigned long ram_top;        /* Top address of RAM used by U-Boot,RAM空间的顶端地址 */
31     unsigned long relocaddr;    /* Start address of U-Boot in RAM,UBOOT重定向后地址 */
32     phys_size_t ram_size;        /* RAM size, 物理ram的size */
33     unsigned long mon_len;        /* monitor len */
34     unsigned long irq_sp;        /* irq stack pointer,中断的堆栈地址 */
35     unsigned long start_addr_sp;    /* start_addr_stackpointer,堆栈地址 */
36     unsigned long reloc_off;        /* uboot的relocation的偏移 */
37     struct global_data *new_gd;    /* relocated global data, 重定向后的struct global_data结构体 */
38 
39 #ifdef CONFIG_DM
40     struct udevice    *dm_root;    /* Root instance for Driver Model */
41     struct udevice    *dm_root_f;    /* Pre-relocation root instance */
42     struct list_head uclass_root;    /* Head of core tree */
43 #endif
44 #ifdef CONFIG_TIMER
45     struct udevice    *timer;        /* Timer instance for Driver Model */
46 #endif
47 
48     const void *fdt_blob;        /* Our device tree, NULL if none,我们设备的dtb地址 */
49     void *new_fdt;            /* Relocated FDT, relocation之后的dtb地址 */
50     unsigned long fdt_size;        /* Space reserved for relocated FDT, dtb的长度 */
51 #ifdef CONFIG_OF_LIVE
52     struct device_node *of_root;
53 #endif
54     struct jt_funcs *jt;        /* jump table */
55     char env_buf[32];        /* buffer for env_get() before reloc. */
56 #ifdef CONFIG_TRACE
57     void        *trace_buff;    /* The trace buffer */
58 #endif
59 #if defined(CONFIG_SYS_I2C)
60     int        cur_i2c_bus;    /* current used i2c bus */
61 #endif
62 #ifdef CONFIG_SYS_I2C_MXC
63     void *srdata[10];
64 #endif
65     unsigned int timebase_h;
66     unsigned int timebase_l;
67 #if CONFIG_VAL(SYS_MALLOC_F_LEN)
68     unsigned long malloc_base;    /* base address of early malloc() */
69     unsigned long malloc_limit;    /* limit address */
70     unsigned long malloc_ptr;    /* current address */
71 #endif
72 #ifdef CONFIG_PCI
73     struct pci_controller *hose;    /* PCI hose for early use */
74     phys_addr_t pci_ram_top;    /* top of region accessible to PCI */
75 #endif
76 #ifdef CONFIG_PCI_BOOTDELAY
77     int pcidelay_done;
78 #endif
79     struct udevice *cur_serial_dev;    /* current serial device, 当前使用的串口设备 */
80     struct arch_global_data arch;    /* architecture-specific data */
81 #ifdef CONFIG_CONSOLE_RECORD
82     struct membuff console_out;    /* console output */
83     struct membuff console_in;    /* console input */
84 #endif
85 #ifdef CONFIG_DM_VIDEO
86     ulong video_top;        /* Top of video frame buffer area */
87     ulong video_bottom;        /* Bottom of video frame buffer area */
88 #endif
89 #ifdef CONFIG_BOOTSTAGE
90     struct bootstage_data *bootstage;    /* Bootstage information */
91     struct bootstage_data *new_bootstage;    /* Relocated bootstage info */
92 #endif
93 #ifdef CONFIG_LOG
94     int log_drop_count;        /* Number of dropped log messages */
95     int default_log_level;        /* For devices with no filters */
96     struct list_head log_head;    /* List of struct log_device */
97     int log_fmt;            /* Mask containing log format info */
98 #endif
99 } gd_t;

  

  

  

猜你喜欢

转载自www.cnblogs.com/kele-dad/p/8987461.html