决定从头开始分析u-boot-1.1.4源码(三)
来源:互联网 发布:2017新开淘宝卖什么好 编辑:程序博客网 时间:2024/06/01 08:37
init_fnc_t *init_sequence[] = {
cpu_init,
board_init,
interrupt_init,
env_init,
init_baudrate,
serial_init,
console_init_f,
display_banner,
dram_init,
display_dram_config,
#if defined(CONFIG_VCMA9) || defined (CONFIG_CMC_PU2)
checkboard,
#endif
NULL,
};
谭浩强的书上写着,一维指针数组的定义形式为: 类型名 * 数组名[数组长度];
可见,这里的init_sequence也是指针数组,数组名为init_sequence,数组的每一个元素都为指针类型,在这里每个元素是指向函数的指针。init_fnc_ptr即为指向init_sequence指针数组的指针,结合起这里来就可以理解了.
#if defined(CONFIG_VCMA9) || defined (CONFIG_CMC_PU2)
#endif
};
谭浩强的书上写着,一维指针数组的定义形式为: 类型名
可见,这里的init_sequence也是指针数组,数组名为init_sequence,数组的每一个元素都为指针类型,在这里每个元素是指向函数的指针。init_fnc_ptr即为指向init_sequence指针数组的指针,结合起这里来就可以理解了.
下面就跳到数组的第一个函数cpu_init去执行:
int cpu_init (void)
{
int cpu_init (void)
{
#ifdef CONFIG_USE_IRQ
DECLARE_GLOBAL_DATA_PTR;
#endif
}
实际上这里只是什么都不干,因为在u-boot-1.1.4\include\configs\smdk2410.h里没有定义CONFIG_USE_IRQ
#undef CONFIG_USE_IRQ
接下来是board_init函数,先贴出代码稍后再分析:
int board_init (void)
{
DECLARE_GLOBAL_DATA_PTR;
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
int board_init (void)
{
}
首先这里有S3C24X0_CLOCK_POWER结构体类型,搜索到它是在u-boot-1.1.4\include\s3c24x0.h中定义的
typedef struct {
} S3C24X0_CLOCK_POWER;
其中S3C24X0_REG32在同一个文件中有定义:
typedef volatile u32S3C24X0_REG32;
typedef volatile u32
S3C24X0_GetBase_CLOCK_POWER在u-boot-1.1.4\include\s3c2410.h中定义如下:
static inline S3C24X0_CLOCK_POWER * const S3C24X0_GetBase_CLOCK_POWER(void)
{
return (S3C24X0_CLOCK_POWER * const)S3C24X0_CLOCK_POWER_BASE;
}
static inline S3C24X0_CLOCK_POWER * const S3C24X0_GetBase_CLOCK_POWER(void)
{
}
S3C24X0_CLOCK_POWER_BASE也在同一个文件中定义:
#define S3C24X0_CLOCK_POWER_BASE0x4C000000
这里的意思是所有寄存器都通过结构体变量来存取,而不像我们裸机编程是各个寄存器一个个的定义。S3C24X0_GPIO结构体同S3C24X0_CLOCK_POWER,这里不再详述.
接着设置时钟频率,设置I/O口,接下来,
#define S3C24X0_CLOCK_POWER_BASE
这里的意思是所有寄存器都通过结构体变量来存取,而不像我们裸机编程是各个寄存器一个个的定义。S3C24X0_GPIO结构体同S3C24X0_CLOCK_POWER,这里不再详述.
接着设置时钟频率,设置I/O口,接下来,
这里回到我们的bd_t中,那里有个成员:bi_arch_number;
定义是这样的的:ulong
这里给它赋值.在u-boot-1.1.4\include\asm-arm\mach-types.h中#define MACH_TYPE_SMDK2410
这里的MACH_TYPE_SMDK2410应该到时传递给内核以用来识别开发板类型的.
bi_boot_params为传递给内核的参数的地址.
接着设置指令cache,数据cache:
icache_enable();
dcache_enable();
这两个函数定义在u-boot-1.1.4\cpu\arm920t\cpu.c中
void icache_enable (void)
{
ulong reg;
这两个函数定义在u-boot-1.1.4\cpu\arm920t\cpu.c中
void icache_enable (void)
{
}
void dcache_enable (void)
{
}
其中read_p15_c1在同一个文件中定义,mrc指令用英文这样记:mov cp to reg,这里是把cp15的寄存器1读到%0(不太清楚这个内嵌语法).
static unsigned long read_p15_c1 (void)
{
#ifdef MMU_DEBUG
printf ("p15/c1 is = lx\n", value);
#endif
return value;
}
#endif
}
write_p15_c1 (reg | C1_IC);是设置指令cache,其中C1_IC在同一文件中定义#define C1_IC (1<<12)
write_p15_c1 (reg | C1_DC);是设置数据cache,其中C1_DC在同一文件中定义#define C1_DC (1<<2)
static void write_p15_c1 (unsigned long value)
{
#ifdef MMU_DEBUG
printf ("write lx to p15/c1\n", value);
#endif
__asm__ __volatile__(
"mcr p15, 0, %0, c1, c0, 0 @ write it back\n"
:
: "r" (value)
: "memory");
write_p15_c1 (reg | C1_DC);是设置数据cache,其中C1_DC在同一文件中定义#define C1_DC
static void write_p15_c1 (unsigned long value)
{
#ifdef MMU_DEBUG
#endif
}
board_init函数到这里就分析完了,实际上就是设置了一些寄存器,如时钟,IO口,串口,机器类型,启动参数,指令cache,数据cache.
然后到interrupt_init了,
int interrupt_init (void)
{
S3C24X0_TIMERS * const timers = S3C24X0_GetBase_TIMERS();
{
}
结构体S3C24X0_TIMERS同前面的S3C24X0_CLOCK_POWER一样,也在u-boot-1.1.4\include\s3c24x0.h中定义
typedef struct {
} S3C24X0_TIMERS;
这里的寄存器没什么,对照2410数据手册就知道怎么设置了.其中的S3C24X0_GetBase_TIMERS函数在u-boot-1.1.4\include\s3c2410.h中定义
static inline S3C24X0_TIMERS * const S3C24X0_GetBase_TIMERS(void)
{
}
S3C24X0_TIMER_BASE也在同一个文件中定义:
#define S3C24X0_TIMER_BASE 0x51000000
#define S3C24X0_TIMER_BASE
timers->TCFG0 = 0x0f00; 这里用到timer4,只用到预分频器1,这里设置TCFG0[15:8]=0x0f,[7:0]=0(没用到).
在u-boot-1.1.4\cpu\arm920t\s3c24x0\interrupts.c中定义了int timer_load_val = 0;
在u-boot-1.1.4\cpu\arm920t\s3c24x0\interrupts.c中定义了int timer_load_val = 0;
timer_load_val = get_PCLK()/(2 * 16 * 100);
get_PCLK这个函数在u-boot-1.1.4\cpu\arm920t\s3c24x0\speed.c中:
ulong get_PCLK(void)
{
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
ulong get_PCLK(void)
{
}
这里又从PCLK根据分频设置又从get_HCLK()/2或get_HCLK()中得到:
ulong get_HCLK(void)
{
}
而这里HCLK又根据分频设置get_FCLK/2或get_FCLK中得到:
ulong get_FCLK(void)
{
}
static ulong get_PLLCLK(int pllreg)
{
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
ulong r, m, p, s;
{
}
在u-boot-1.1.4\include\configs\smdk2410.h中定义有:
#define CONFIG_SYS_CLK_FREQ12000000
我们的板子也是这个频率,所以很多和时钟有关的参数都不用修改.
#define CONFIG_SYS_CLK_FREQ
我们的板子也是这个频率,所以很多和时钟有关的参数都不用修改.
接着设置timer4定时器的计数值,手动加载,设置自动重载,开启定时器,具体设置就不详细分析了.
lastdec = timers->TCNTB4 = timer_load_val;
timers->TCON = (timers->TCON & ~0x0700000) | 0x600000;
timers->TCON = (timers->TCON & ~0x0700000) | 0x500000;
到这里interrupt_init分析结束
下面到env_init函数,搜索到u-boot有很多个env_init,在u-boot-1.1.4\common\env_flash.c中有这么一句:
#if defined(CFG_ENV_IS_IN_FLASH)
正是因为在u-boot-1.1.4\include\configs\smdk2410.h中定义了CFG_ENV_IS_IN_FLASH,而其他的CFG_ENV_IS_IN_NAND等没有被定义,所以只有env_flash.c被编译
#defineCFG_ENV_IS_IN_FLASH 1
#define
下面就跳到env_flash.c中的env_init去分析,这个文件里也有两个env_init函数,第一个是在CFG_ENV_ADDR_REDUND有定义的情况才去编译的,而u-boot-1.1.4\include\configs\smdk2410.h没有定义这个宏,所以只有第二个env_init会实际被执行:
int env_init(void)
{
DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_OMAP2420H4
int flash_probe(void);
{
#ifdef CONFIG_OMAP2420H4
#endif
#ifdef CONFIG_OMAP2420H4
bad_flash:
#endif
}
对于smdk2410开发板,CONFIG_OMAP2420H4这个宏没有被定义,所以中间那段跳过.
这里是设置了gd_t类型的指针变量gd,这里是用env_addr变量来存放default_environment数组的地址.
env_valid为CRD校验标志,这里设置为无效.default_environment在u-boot-1.1.4\common\env_common.c中定义:
这里是设置了gd_t类型的指针变量gd,这里是用env_addr变量来存放default_environment数组的地址.
env_valid为CRD校验标志,这里设置为无效.default_environment在u-boot-1.1.4\common\env_common.c中定义:
uchar default_environment[] = {
#ifdefCONFIG_BOOTARGS
"bootargs=" CONFIG_BOOTARGS "\0"
#endif
#ifdefCONFIG_BOOTCOMMAND
"bootcmd=" CONFIG_BOOTCOMMAND "\0"
#endif
#ifdefCONFIG_RAMBOOTCOMMAND
"ramboot=" CONFIG_RAMBOOTCOMMAND "\0"
#endif
#ifdefCONFIG_NFSBOOTCOMMAND
"nfsboot=" CONFIG_NFSBOOTCOMMAND "\0"
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
"bootdelay=" MK_STR(CONFIG_BOOTDELAY) "\0"
#endif
#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
"baudrate=" MK_STR(CONFIG_BAUDRATE) "\0"
#endif
#ifdefCONFIG_LOADS_ECHO
"loads_echo=" MK_STR(CONFIG_LOADS_ECHO) "\0"
#endif
#ifdefCONFIG_ETHADDR
"ethaddr=" MK_STR(CONFIG_ETHADDR) "\0"
#endif
#ifdefCONFIG_ETH1ADDR
"eth1addr=" MK_STR(CONFIG_ETH1ADDR) "\0"
#endif
#ifdefCONFIG_ETH2ADDR
"eth2addr=" MK_STR(CONFIG_ETH2ADDR) "\0"
#endif
#ifdefCONFIG_ETH3ADDR
"eth3addr=" MK_STR(CONFIG_ETH3ADDR) "\0"
#endif
#ifdefCONFIG_IPADDR
"ipaddr=" MK_STR(CONFIG_IPADDR) "\0"
#endif
#ifdefCONFIG_SERVERIP
"serverip=" MK_STR(CONFIG_SERVERIP) "\0"
#endif
#ifdefCFG_AUTOLOAD
"\0"
#endif
#ifdefCONFIG_PREBOOT
"preboot=" CONFIG_PREBOOT "\0"
#endif
#ifdefCONFIG_ROOTPATH
"rootpath=" MK_STR(CONFIG_ROOTPATH) "\0"
#endif
#ifdefCONFIG_GATEWAYIP
"gatewayip=" MK_STR(CONFIG_GATEWAYIP) "\0"
#endif
#ifdefCONFIG_NETMASK
"netmask=" MK_STR(CONFIG_NETMASK) "\0"
#endif
#ifdefCONFIG_HOSTNAME
"hostname=" MK_STR(CONFIG_HOSTNAME) "\0"
#endif
#ifdefCONFIG_BOOTFILE
"bootfile=" MK_STR(CONFIG_BOOTFILE) "\0"
#endif
#ifdefCONFIG_LOADADDR
"loadaddr=" MK_STR(CONFIG_LOADADDR) "\0"
#endif
#ifdef CONFIG_CLOCKS_IN_MHZ
"clocks_in_mhz=1\0"
#endif
#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
"pcidelay=" MK_STR(CONFIG_PCI_BOOTDELAY) "\0"
#endif
#ifdef CONFIG_EXTRA_ENV_SETTINGS
CONFIG_EXTRA_ENV_SETTINGS
#endif
"\0"
};
#ifdef
#endif
#ifdef
#endif
#ifdef
#endif
#ifdef
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
#endif
#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
#endif
#ifdef
#endif
#ifdef
#endif
#ifdef
#endif
#ifdef
#endif
#ifdef
#endif
#ifdef
#endif
#ifdef
#endif
#ifdef
#endif
#ifdef
#endif
#ifdef
#endif
#ifdef
#endif
#ifdef
#endif
#ifdef
#endif
#ifdef
#endif
#ifdef
#endif
#ifdef
#endif
#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
#endif
#ifdef
#endif
};
MK_STR宏的作用是将一个字符串转化为一个值,这个宏在其他文件中也有定义,但ENV_IS_EMBEDDED没有被定义,所以Environment.c中MK_STR宏也就没有定义.只有在u-boot-1.1.4\common\env_common.c里定义了.
env_init分析完,接下来到init_baudrate了:
static int init_baudrate (void)
{
DECLARE_GLOBAL_DATA_PTR;
static int init_baudrate (void)
{
}
getenv_r在u-boot-1.1.4\common\cmd_nvedit.c里面,这个函数有一点点复杂,大概意思是取出和name匹配的参数的值,存放到tmp里去
int getenv_r (char *name, char *buf, unsigned len)
{
}
env_get_char在u-boot-1.1.4\common\env_common.c中定义如下:
uchar (*env_get_char)(int) = env_get_char_init;
uchar (*env_get_char)(int) = env_get_char_init;
继续搜索env_get_char_init,也在同一文件中:
static uchar env_get_char_init (int index)
{
DECLARE_GLOBAL_DATA_PTR;
uchar c;
static uchar env_get_char_init (int index)
{
}
envmatch((uchar *)name, i)在u-boot-1.1.4\common\cmd_nvedit.c中定义,表示从i位置开始查找和name匹配的字符串
static int envmatch (uchar *s1, int i2)
{
while (*s1 == env_get_char(i2++))
if (*s1++ == '=')
return(i2);
if (*s1 == '\0' && env_get_char(i2-1) == '=')
return(i2);
return(-1);
}
static int envmatch (uchar *s1, int i2)
{
}
继续执行init_baudrate,这里如果参数值不为0则设置为对应值,为0则采用默认值.
gd->bd->bi_baudrate = gd->baudrate = (i > 0)
? (int) simple_strtoul (tmp, NULL, 10)
: CONFIG_BAUDRATE;
simple_strtoul 这个函数在u-boot-1.1.4\lib_generic\vsprintf.c下面定义,从字面上看,这个函数的意思是str to ul(unsigned long),但它的实现有点复杂,就不去分析了.
接下来到u-boot-1.1.4\cpu\arm920t\s3c24x0\serial.c看下serial_init,这个函数很简单,就是调用了serial_setbrg();
int serial_init (void)
{
serial_setbrg ();
int serial_init (void)
{
}
在同一个文件中定义了serial_setbrg,主要是设置串口控制寄存器,模块时钟,波特率等
void serial_setbrg (void)
{
#ifdef CONFIG_HWFLOW
uart->UMCON = 0x1;
#endif
for (i = 0; i < 100; i++);
}
#endif
}
接下来分析console_init_f,这个函数也比较简单
int console_init_f (void)
{
DECLARE_GLOBAL_DATA_PTR;
int console_init_f (void)
{
#ifdef CONFIG_SILENT_CONSOLE
if (getenv("silent") != NULL)
gd->flags |= GD_FLG_SILENT;
#endif
#endif
}
接下来继续看display_banner这个函数,printf不是从标准C库里调用的,这里是重复定义了这个函数,它的调用顺序是printf->vsprintf->puts->serial_puts.最后是把一些信息直接输出到串口上.
static int display_banner (void)
{
printf ("\n\n%s\n\n", version_string);
printf ("U-Boot code: lX -> lX BSS: -> lX\n",
_armboot_start, _bss_start, _bss_end);
#ifdef CONFIG_MODEM_SUPPORT
puts ("Modem Support enabled\n");
#endif
#ifdef CONFIG_USE_IRQ
printf ("IRQ Stack: lx\n", IRQ_STACK_START);
printf ("FIQ Stack: lx\n", FIQ_STACK_START);
#endif
static int display_banner (void)
{
#ifdef CONFIG_MODEM_SUPPORT
#endif
#ifdef CONFIG_USE_IRQ
#endif
}
搜索到version_string的定义,其中U_BOOT_VERSION定义为"U-Boot 1.1.4",即把这个字符串打印到串口上.
const char version_string[] =
然后输出_armboot_start, _bss_start, _bss_end等地址信息.
按照顺序下来,下面是dram_init,这个函数比较简单,就是初始化板子的sdram起始地址及容量大小.
int dram_init (void)
{
DECLARE_GLOBAL_DATA_PTR;
int dram_init (void)
{
}
在smdk2410.h中定义了下面两个宏
#define PHYS_SDRAM_1
#define PHYS_SDRAM_1_SIZE
回到之前的bd_t结构体里,其成员里有个bi_dram结构体数组,其中CONFIG_NR_DRAM_BANKS表示板子的dram的数目,这里我们只用到了一个sdram,所以只初始化了bi_dram[0].
struct
{
ulong start;
ulong size;
} bi_dram[CONFIG_NR_DRAM_BANKS];
struct
初始化完dram,下面就打印dram有关的信息:
static int display_dram_config (void)
{
DECLARE_GLOBAL_DATA_PTR;
int i;
static int display_dram_config (void)
{
}
回到之前的循环,执行完之后继续运行下去,下面是flash_init().
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
这里的flash_init是在u-boot-1.1.4\board\smdk2410\flash.c里面的,对于smdk2410,它只实现了AMD_LV400/AMD_LV800的flash操作,对于我们板子的SST39VF1601,在移植的时候这个需要改写,这里先分析smdk2410是怎么实现的.
ulong flash_init (void)
{
#if defined(CONFIG_AMD_LV400)
#elif defined(CONFIG_AMD_LV800)
#else
#error "Unknown flash configured"
#endif
}
这里有个FLASH Info,搜索到它的定义在u-boot-1.1.4\include\flash.h中
* FLASH Info: contains chip specific data, per FLASH bank
*/
typedef struct {
ulong size;
ushort sector_count;
ulong flash_id;
ulong start[CFG_MAX_FLASH_SECT];
uchar protect[CFG_MAX_FLASH_SECT];
#ifdef CFG_FLASH_CFI
uchar portwidth;
uchar chipwidth;
ushort buffer_size;
ulong erase_blk_tout;
ulong write_tout;
ulong buffer_write_tout;
ushort vendor;
ushort cmd_reset;
ushort interface;
#endif
} flash_info_t;
#ifdef CFG_FLASH_CFI
#endif
} flash_info_t;
而在smdk2410.h中有如下定义:
flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
#define FLASH_BANK_SIZE PHYS_FLASH_SIZE
PHYS_FLASH_SIZE在u-boot-1.1.4\include\configs\smdk2410.h中定义了为512K大小.而SST39VF1601为2M大小的,CFG_MAX_FLASH_SECT为flash的总扇区数,
#define PHYS_FLASH_SIZE 0x00080000
#define CFG_MAX_FLASH_SECT(11)
#define PHYS_FLASH_SIZE
#define CFG_MAX_FLASH_SECT
对于SST39VF1601,可以采用sector的方法也可以采用block的方法,其中
1 sector=2k word=4k byte,
1 block=32k word=64k byte,
所以共有2048k/64k个block,即32个block,这些移植的时候需要修改.
1 sector=2k word=4k byte,
1 block=32k word=64k byte,
所以共有2048k/64k个block,即32个block,这些移植的时候需要修改.
上面flash_init()里面有个flash_protect(),把它找出来了,看看它都干了些什么
void flash_protect (int flag, ulong from, ulong to, flash_info_t *info)
{
ulong b_end = info->start[0] + info->size - 1;
short s_end = info->sector_count - 1;
int i;
debug ("flash_protect %s: from 0xlX to 0xlX\n",
(flag & FLAG_PROTECT_SET) ? "ON" :
(flag & FLAG_PROTECT_CLEAR) ? "OFF" : "???",
from, to);
if (info->sector_count == 0 || info->size == 0 || to < from) {
return;
}
void flash_protect (int flag, ulong from, ulong to, flash_info_t *info)
{
#if defined(CFG_FLASH_PROTECTION)
#else
#endif
#if defined(CFG_FLASH_PROTECTION)
#else
#endif
}
原来实际上在smdk2410中它等于什么都不干,看来白费我工夫了.
继续分析flash_init后面的display_flash_config,size为所有flash的总大小,这里只有一个flash,所以size=flash_info[0]
static void display_flash_config (ulong size)
{
puts ("Flash: ");
print_size (size, "\n");
}
static void display_flash_config (ulong size)
{
}
继续回到start_armboot(),
#ifdef CONFIG_VFD
#ifndef PAGE_SIZE
# define PAGE_SIZE 4096
#endif
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
size = vfd_setmem (addr);
gd->fb_base = addr;
#endif
#ifdef CONFIG_VFD
#
#
#
#endif
#ifdef CONFIG_LCD
#ifndef PAGE_SIZE
# define PAGE_SIZE 4096
#endif
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
size = lcd_setmem (addr);
gd->fb_base = addr;
#endif
#
#
#
#endif
这两段没有被定义,跳过.
其中mem_malloc_init的定义如下,主要是清除内存区域.
static void mem_malloc_init (ulong dest_addr)
{
mem_malloc_start = dest_addr;
mem_malloc_end = dest_addr + CFG_MALLOC_LEN;
mem_malloc_brk = mem_malloc_start;
static void mem_malloc_init (ulong dest_addr)
{
}
接着继续回到start_armboot(),
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
puts ("NAND:");
nand_init();
#endif
从下面可以看到,u-boot-1.1.4\include\configs\smdk2410.h中没有定义CFG_CMD_NAND,所以这段也跳过
#define CONFIG_COMMANDS \
(CONFIG_CMD_DFL | \
CFG_CMD_CACHE | \
\
\
\
\
CFG_CMD_REGINFO | \
CFG_CMD_DATE | \
CFG_CMD_ELF)
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
#endif
从下面可以看到,u-boot-1.1.4\include\configs\smdk2410.h中没有定义CFG_CMD_NAND,所以这段也跳过
#define CONFIG_COMMANDS \
#ifdef CONFIG_HAS_DATAFLASH
AT91F_DataflashInit();
dataflash_print_info();
#endif
#endif
看看这个env_relocate:
void env_relocate (void)
{
DECLARE_GLOBAL_DATA_PTR;
DEBUGF ("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__,
gd->reloc_off);
#ifdef CONFIG_AMIGAONEG3SE
enable_nvram();
#endif
void env_relocate (void)
{
#ifdef CONFIG_AMIGAONEG3SE
#endif
#ifdef ENV_IS_EMBEDDED
env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off);
DEBUGF ("%s[%d] embedded ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#else
env_ptr = (env_t *)malloc (CFG_ENV_SIZE);
DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#endif
#else
#endif
#if defined(CONFIG_GTH)
#else
#endif
#ifdef CFG_REDUNDAND_ENVIRONMENT
#endif
#ifdef CONFIG_AMIGAONEG3SE
disable_nvram();
#endif
}
#endif
}
env_ptr = (env_t *)malloc (CFG_ENV_SIZE);这里有个env_t,它在include\environment.h中定义:
typedef struct environment_s {
unsigned long crc;
#ifdef CFG_REDUNDAND_ENVIRONMENT
unsigned char flags;
#endif
unsigned char data[ENV_SIZE];
} env_t;
#ifdef CFG_REDUNDAND_ENVIRONMENT
#endif
} env_t;
#define ENV_SIZE (CFG_ENV_SIZE - ENV_HEADER_SIZE)
#define CFG_ENV_SIZE 0x10000
# define ENV_HEADER_SIZE(sizeof(unsigned long))
所以ENV_SIZE=64k-(sizeof(unsigned long))
#define CFG_ENV_SIZE
# define ENV_HEADER_SIZE
所以ENV_SIZE=64k-(sizeof(unsigned long))
uchar env_get_char_memory (int index)
{
}
void env_crc_update (void)
{
env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE);
}
{
}
void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED) || defined(CFG_ENV_ADDR_REDUND)
#ifdef CFG_ENV_ADDR_REDUND
DECLARE_GLOBAL_DATA_PTR;
{
#if !defined(ENV_IS_EMBEDDED) || defined(CFG_ENV_ADDR_REDUND)
#ifdef CFG_ENV_ADDR_REDUND
#endif
#endif
}
这里flash_addr其实就是CFG_ENV_ADDR,也就是在0x0F0000处.
static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x0F0000)
static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
#define CFG_ENV_ADDR
到这里为止,我们了解了env操作的流程大概是这样的,第一次启动是分配一段内存来存放env的信息,然后把内存的指针赋给env_ptr,第二次启动的时候就把存放在flash上的env的地址赋给了env_ptr.
继续回到start_armboot()中:
#ifdef CONFIG_VFD
drv_vfd_init();
#endif
#endif
这里有几层调用,
IPaddr_t getenv_IPaddr (char *var)
{
return (string_to_ip(getenv(var)));
}
IPaddr_t getenv_IPaddr (char *var)
{
}
IPaddr_t string_to_ip(char *s)
{
IPaddr_t addr;
char *e;
int i;
{
}
继续分析start_armboot(),
int devices_init (void)
{
#ifndef CONFIG_ARM
DECLARE_GLOBAL_DATA_PTR;
{
#ifndef CONFIG_ARM
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
#endif
#ifdef CONFIG_LCD
#endif
#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
#endif
#ifdef CONFIG_KEYBOARD
#endif
#ifdef CONFIG_LOGBUFFER
#endif
#ifdef CONFIG_SERIAL_MULTI
#endif
#ifdef CONFIG_USB_TTY
#endif
#ifdef CONFIG_NETCONSOLE
#endif
}
下面列出这里会调用到的结构体和函数:
typedef struct {
list_t ListCreate (int elementSize)
{
list_t list;
{
}
Handle NewHandle (unsigned int numBytes)
{
void *memPtr;
HandleRecord *hanPtr;
{
}
typedef struct ListStructTag
{
int signature;
int percentIncrease;
int minNumItemsIncrease;
int listSize;
int itemSize;
int numItems;
unsigned char itemList[1];
} ListStruct;
#ifdef CONFIG_CMC_PU2
#endif
void jumptable_init (void)
{
DECLARE_GLOBAL_DATA_PTR;
int i;
{
#if defined(CONFIG_I386) || defined(CONFIG_PPC)
#endif
#if (CONFIG_COMMANDS & CFG_CMD_I2C)
#endif
}
int console_init_r (void)
{
#ifdef CONFIG_SPLASH_SCREEN
#endif
#ifdef CONFIG_SILENT_CONSOLE
#endif
#ifndef CFG_CONSOLE_INFO_QUIET
#endif
#if 0
if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
return (0);
#endif
#endif
}
console_init_r ();后期控制台初始化
为什么要使用devlist,std_device[]?
为了更灵活地实现标准IO重定向,任何可以作为标准IO的设备,如USB键盘,LCD屏,串口等都可以对应一个device_t的结构体变量,只需要实现getc和putc等函数,就能加入到devlist列表中去,也就可以被assign为标准IO设备std_device中去。如函数
int console_assign (int file, char *devname);
这个函数功能就是把名为devname的设备重定向为标准IO文件file(stdin,stdout,stderr)。其执行过程是在devlist中查找devname的设备,返回这个设备的device_t指针,并把指针值赋给std_device[file]。
#if defined(CONFIG_MISC_INIT_R)
#endif
#ifdef CONFIG_USE_IRQ
void enable_interrupts (void)
{
unsigned long temp;
__asm__ __volatile__("mrs %0, cpsr\n"
"bic %0, %0, #0x80\n"
"msr cpsr_c, %0"
: "=r" (temp)
:
: "memory");
}
void enable_interrupts (void)
{
}
#ifdef CONFIG_DRIVER_CS8900
#endif
网络部分不懂,暂时不看,等看完cs8900的datasheet再看
void cs8900_get_enetaddr (uchar * addr)
{
}
#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
#endif
#if (CONFIG_COMMANDS & CFG_CMD_NET)
#endif
#ifdef BOARD_LATE_INIT
board_late_init ();
#endif
#if (CONFIG_COMMANDS & CFG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
puts ("Net: ");
#endif
eth_initialize(gd->bd);
#endif
#if (CONFIG_COMMANDS & CFG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
#endif
eth_initialize()有两个,第二个没有被编译,只用到第一个
#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI)
int eth_initialize(bd_t *bis)
#elif (CONFIG_COMMANDS & CFG_CMD_NET) && !defined(CONFIG_NET_MULTI)
int eth_initialize(bd_t *bis)
#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI)
#elif (CONFIG_COMMANDS & CFG_CMD_NET) && !defined(CONFIG_NET_MULTI)
终于到main_loop了,真是开心
for (;;) {
main_loop ();
}
}
这个函数也非常长,这里讲有效代码贴出来:
void main_loop (void)
{
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
char *s;
int bootdelay;
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
s = getenv ("bootdelay");
bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
void main_loop (void)
{
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
#endif
#ifdef CFG_HUSH_PARSER
#else
#ifdef CONFIG_BOOT_RETRY_TIME
#endif
#ifdef CONFIG_BOOT_RETRY_TIME
# ifdef CONFIG_RESET_TO_RETRY
# else
# endif
#endif
#endif
}
阅读全文
0 0
- 决定从头开始分析u-boot-1.1.4源码(三)
- 决定从头开始分析u-boot-1.1.4源码(三)
- 决定从头开始分析u-boot-1.1.4源码(一)
- 决定从头开始分析u-boot-1.1.4源码(二)
- u-boot学习(三):u-boot源码分析
- u-boot源码分析
- u-boot源码分析
- u-boot源码分析
- u-boot源码分析
- u-boot源码分析
- u-boot源码分析
- 三星U-Boot-1.1.6源码分析
- U-boot-1.1.6第一阶段源码分析
- u-boot-1.1.6源码分析
- Tiny210(S5PV210) U-BOOT(三)----配置时钟频率源码分析
- Tiny210 U-BOOT(三)----配置时钟频率源码分析
- u-boot 学习记录 (三) 源码分析(start.S)
- Tiny210(S5PV210) U-BOOT(三)----配置时钟频率源码分析
- session没有过期,其保存的数据无故丢失的原因
- vue.js学习笔记
- 人工智能(AI)期末复习
- LeetCode 455. Assign Cookies(数组,排序)
- 新概念4-6
- 决定从头开始分析u-boot-1.1.4源码(三)
- 2134-->数据结构实验之栈四:括号匹配
- 用ng-repeat循环出一个不规则的表格遇到了问题
- Hi3518E V200R001C05SPC050使用笔记
- Javascript关键字,条件语句,循环语句,函数
- python中列表 字典 元祖 enumerate()函数
- U-Boot启动过程完全分析
- Hystrix 工作流程解析
- Activity的四种启动模式