android 4.0板卡接收视频源,Android 4.0启动流程分析

在分析SPRD启动流程之前,第一步:先来分析一下嵌入式系统一般的启动流程,也就是从uboot开始在到启动kernel模块。第二部:再来分析一下SPRD android系统的启动与一般启动有和不同,启动过程分析道android init进程起来为止。至于init后的启动过程应该是地球人都知道的。

第一部分:关于uboot分析有些摘自网络,

http://blog.chinaunix.net/uid-24951403-id-2212589.html

bootloader 除了依赖CPU,还依赖板级设备的配置,例如板卡的硬件地址分配,外设硬件芯片的类型。不同的板子需修改bootloader。阶段1:硬件初始化,为加载bootloader的二阶段准备RAM空间,拷贝2阶段代码到内存,设置好堆栈,跳到2阶段,初始化本阶段要的设备,将内核和根文件从flash中拷贝到RAM中,最后调用内核。

1、Stage1 start.S代码结构 u-boot的stage1代码通常放在start.S文件中,他用汇编语言写成,其主要代码部分如下

(1)定义入口。:

该工作通过修改连接器脚本来完成。

(2)设置异常向量(Exception Vector)。

(3)设置CPU的速度、时钟频率及终端控制寄存器。

(4)初始化内存控制器。

(5)将ROM中的程序复制到RAM中。

(6)初始化堆栈。

(7)转到RAM中执行,该工作可使用指令ldr pc来完成。

2、Stage2

C语言代码部分lib_arm/board.c中的start arm boot是C语言开始的函数也是整个启动代码中C语言的主函数,同时还是整个u-boot(armboot)的主函数,该函数只要完成如下操作:

(1)调用一系列的初始化函数。

(2)初始化Flash设备。

(3)初始化系统内存分配函数。

(4)如果目标系统拥有NAND设备,则初始化NAND设备。

(5)如果目标系统有显示设备,则初始化该类设备。

(6)初始化相关网络设备,填写IP、MAC地址等。

(7)进去命令循环(即整个boot的工作循环),接受用户从串口输入的命令,然后进行相应的工作。

3、U-Boot的启动顺序 发板上电后,执行U-Boot的第一条指令,然后顺序执行U-Boot启动函数。看一下u-boot\board\spreadtrum\sp6825ga/u-boot.lds这个链接脚本,可以知道目标程序的各部分链接顺序。第一个要链接的是arch/arm/cpu/arm926ejs/start.o,那么U-Boot的入口指令一定位于这个程序中。下面分两阶段介绍启动流程:

如下:u-boot\board\spreadtrum\sp6825ga\start.s

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")

OUTPUT_ARCH(arm)

ENTRY(_start)

SECTIONS

{

. = 0x00000000;

. = ALIGN(4);

.text :

{

arch/arm/cpu/arm926ejs/start.o(.text)

*(.text)

}

. = ALIGN(4);

.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }

. = ALIGN(4);

.data : { *(.data) }

. = ALIGN(4);

.got : { *(.got) }

. = .;

__u_boot_cmd_start = .;

.u_boot_cmd : { *(.u_boot_cmd) }

__u_boot_cmd_end = .;

. = ALIGN(4);

__bss_start = .;

.bss (NOLOAD) : { *(.bss) . = ALIGN(4); }

_end = .;

}

第一阶段

1.  start.S  这个汇编程序是U-Boot的入口程序,开头就是复位向量的代码。

.globl _start

_start: breset //复位向量

… …

ldrpc, _undefined_instruction

ldrpc, _software_interrupt

ldrpc, _prefetch_abort

ldrpc, _data_abort

ldrpc, _not_used

ldrpc, _irq //中断向量

ldrpc, _fiq //

… …

/*

* the actual reset code

*/

reset://复位启动子程序

/*

* set the cpu to SVC32 mode

*/

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

#ifdef SPRD_EVM_TAG_ON

ldr r0,=SPRD_EVM_ADDR_START

ldr r1,=0x87003004

ldr r2,[r1]

str r2,[r0]

#endif /*?设置CPU为SVC32模式?*/

mrsr0, cpsr

bicr0, r0, #0x1f

orrr0, r0, #0xd3

msrcpsr,r0

#endif

… …

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

blcpu_init_crit

mov r10, #0

/*set up temp stack*///设置堆栈

LDR sp, =SVC_STACK_TEMP

STMDB sp!,{lr}

bl lowlevel_init//初始化CPU

@bl MMU_Init //初始化MMU内存管理单元

/*Re-set up stack

The sp here must be in the reserved region

*///重新设置堆栈 sp必须指向此区域

LDMIA sp!, {lr}

LDR sp, =SPL_STACK

#endif

/* Set stackpointer in internal RAM to call board_init_f */

//设置堆栈指针 指向 RAM 调用board_init_f

call_board_init_f:

ldrsp, =(CONFIG_SYS_INIT_SP_ADDR)

bicsp, sp, #7 /* 8-byte alignment for ABI compliance */

#ifndef CONFIG_NAND_SPL

ldrr0,=0x00000000

blboard_init_f

#else

ldr r0, =(CONFIG_SYS_INIT_SP_ADDR)

ldr r1, =0x00000000

ldr r2, =(CONFIG_SYS_TEXT_BASE)

bl relocate_code

#endif

… …

/*

* We are done. Do not return, instead branch to second part of board

* initialization, now running from RAM.

*/

jump_2_ram:

#ifdef CONFIG_NAND_SPL

ldr r0, _nand_boot_ofs

movpc, r0

_nand_boot_ofs:

.word nand_boot

#else

ldrr0, _board_init_r_ofs

adrr1, _start

addlr, r0, r1

addlr, lr, r9

/* setup parameters for board_init_r */

movr0, r5/* gd_t */

movr1, r6/* dest_addr */

/* jump to it ... */

movpc, lr

_board_init_r_ofs:

.word board_init_r - _start

#endif

第二阶段:跳转到u-boot\arch\arm\lib

start_armboot是U-Boot执行的第一个C语言函数,完成系统初始化工作,进入主循环,处理用户输入的命令。

在board_init_f函数中有init_sequence[]

init_sequence[]数组保存着基本的初始化函数指针。

init_fnc_t *init_sequence[] = {

cpu_init,  /* 基本的处理器相关配置 -- arch\arm\cpu\armv7 */

board_init,/* 基本的板级相关配置 -- board\spreadtrum\sp6825ga*/

interrupt_init,  /* 初始化中断处理 -- arch\arm\lib/interrupt.c */

env_init,      /* 初始化环境变量 --common/cmd_flash.c */

init_baudrate,  /* 初始化波特率设置 --lib_arm/board.c */

serial_init,  /* 串口通讯设置 -- common /serial.c*/

console_init_f,       /* 控制台初始化阶段1 --common/console.c */

display_banner,       /* 打印u-boot信息 --lib_arm/board.c */

dram_init,     /* 配置可用的RAM -- board/ spreadtrum/ openphone.c */

display_dram_config,  /* 显示RAM的配置大小 --lib_arm/board.c */

NULL,

};

void board_init_f (ulong bootflag)

{

bd_t *bd;

init_fnc_t **init_fnc_ptr;

gd_t *id;

ulong addr, addr_sp;

/* Pointer is writable since we allocated a register for it */

gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);

/* compiler optimization barrier needed for GCC >= 3.4 */

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

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

gd->mon_len = _bss_end_ofs;

/* 顺序执行init_sequence数组中的初始化函数 */

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

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

hang ();

}

}

debug ("monitor len: %08lX\n", gd->mon_len);

/*

* Ram is setup, size stored in gd !!

*/

debug ("ramsize: %08lX\n", gd->ram_size);

#if defined(CONFIG_SYS_MEM_TOP_HIDE)

/*

* Subtract specified amount of memory to hide so that it won't

* get "touched" at all by U-Boot. By fixing up gd->ram_size

* the Linux kernel should now get passed the now "corrected"

* memory size and won't touch it either. This should work

* for arch/ppc and arch/powerpc. Only Linux board ports in

* arch/powerpc with bootwrapper support, that recalculate the

* memory size from the SDRAM controller setup will have to

* get fixed.

*/

gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;

#endif

addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;

#ifdef CONFIG_LOGBUFFER

#ifndef CONFIG_ALT_LB_ADDR

/* reserve kernel log buffer */

addr -= (LOGBUFF_RESERVE);

debug ("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN, addr);

#endif

#endif

#ifdef CONFIG_PRAM

/*

* reserve protected RAM

*/

i = getenv_r ("pram", (char *)tmp, sizeof (tmp));

reg = (i > 0) ? simple_strtoul ((const char *)tmp, NULL, 10) : CONFIG_PRAM;

addr -= (reg << 10);/* size is in kB */

debug ("Reserving %ldk for protected RAM at %08lx\n", reg, addr);

#endif /* CONFIG_PRAM */

#if !(defined(CONFIG_SYS_NO_ICACHE) && defined(CONFIG_SYS_NO_DCACHE))

/* reserve TLB table */

addr -= (4096 * 4);

/* round down to next 64 kB limit */

addr &= ~(0x10000 - 1);

gd->tlb_addr = addr;

debug ("TLB table at: %08lx\n", addr);

#endif

/* round down to next 4 kB limit */

addr &= ~(4096 - 1);

debug ("Top of RAM usable for U-Boot at: %08lx\n", addr);

#ifdef CONFIG_VFD

#ifndef PAGE_SIZE

# define PAGE_SIZE 4096

#endif

/*

* reserve memory for VFD display (always full pages)

*/

addr -= vfd_setmem (addr);

gd->fb_base = addr;

#endif /* CONFIG_VFD */

#ifdef CONFIG_LCD

/* reserve memory for LCD display (always full pages) */

addr = lcd_setmem (addr);

gd->fb_base = addr;

#endif /* CONFIG_LCD */

/*

* reserve memory for U-Boot code, data & bss

* round down to next 4 kB limit

*/

addr -= gd->mon_len;

addr &= ~(4096 - 1);

debug ("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);

#ifndef CONFIG_PRELOADER

/*

* reserve memory for malloc() arena

*/

addr_sp = addr - TOTAL_MALLOC_LEN;

debug ("Reserving %dk for malloc() at: %08lx\n",

TOTAL_MALLOC_LEN >> 10, addr_sp);

/*

* (permanently) allocate a Board Info struct

* and a permanent copy of the "global" data

*/

addr_sp -= sizeof (bd_t);

bd = (bd_t *) addr_sp;

gd->bd = bd;

debug ("Reserving %zu Bytes for Board Info at: %08lx\n",

sizeof (bd_t), addr_sp);

addr_sp -= sizeof (gd_t);

id = (gd_t *) addr_sp;

debug ("Reserving %zu Bytes for Global Data at: %08lx\n",

sizeof (gd_t), addr_sp);

/* setup stackpointer for exeptions */

gd->irq_sp = addr_sp;

#ifdef CONFIG_USE_IRQ

addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);

debug ("Reserving %zu Bytes for IRQ stack at: %08lx\n",

CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp);

#endif

/* leave 3 words for abort-stack */

addr_sp -= 3;

/* 8-byte alignment for ABI compliance */

addr_sp &= ~0x07;

#else

addr_sp += 128;/* leave 32 words for abort-stack */

gd->irq_sp = addr_sp;

#endif

debug ("New Stack Pointer is: %08lx\n", addr_sp);

#ifdef CONFIG_POST

post_bootmode_init();

post_run (NULL, POST_ROM | post_bootmode_get(0));

#endif

gd->bd->bi_baudrate = gd->baudrate;

/* Ram ist board specific, so move it to board code ... */

dram_init_banksize();

display_dram_config();/* and display it */

gd->relocaddr = addr;

gd->start_addr_sp = addr_sp;

gd->reloc_off = addr - _TEXT_BASE;

debug ("relocation Offset is: %08lx\n", gd->reloc_off);

memcpy (id, (void *)gd, sizeof (gd_t));

/* 配置环境变量*/

relocate_code (addr_sp, id, addr);

/* NOTREACHED - relocate_code() does not return */

}

然后还会调用此函数

在start.s中

/*

* We are done. Do not return, instead branch to second part of board

* initialization, now running from RAM.

*/

jump_2_ram:

#ifdef CONFIG_NAND_SPL

ldr r0, _nand_boot_ofs

movpc, r0

_nand_boot_ofs:

.word nand_boot

#else

ldrr0, _board_init_r_ofs

adrr1, _start

addlr, r0, r1

addlr, lr, r9

/* setup parameters for board_init_r */

movr0, r5/* gd_t */

movr1, r6/* dest_addr */

/* jump to it ... */

movpc, lr

_board_init_r_ofs:

.word board_init_r - _start

#endif

将调用board.c中的board_init_r

/************************************************************************

*

* This is the next part if the initialization sequence: we are now

* running from RAM and have a "normal" C environment, i. e. global

* data can be written, BSS has been cleared, the stack size in not

* that critical any more, etc.

*

************************************************************************

*/

void board_init_r (gd_t *id, ulong dest_addr)

{

char *s;

bd_t *bd;

ulong malloc_start;

#if !defined(CONFIG_SYS_NO_FLASH)

ulong flash_size;

#endif

gd = id;

bd = gd->bd;

gd->flags |= GD_FLG_RELOC;/* tell others: relocation done */

monitor_flash_len = _bss_start_ofs;

debug ("monitor flash len: %08lX\n", monitor_flash_len);

board_init();/* Setup chipselects */

boot_pwr_check();

#ifdef CONFIG_SERIAL_MULTI

serial_initialize();

#endif

debug ("Now running in RAM - U-Boot at: %08lx\n", dest_addr);

#ifdef CONFIG_LOGBUFFER

logbuff_init_ptrs ();

#endif

#ifdef CONFIG_POST

post_output_backlog ();

#endif

/* The Malloc area is immediately below the monitor copy in DRAM */

malloc_start = dest_addr - TOTAL_MALLOC_LEN;

#ifdef SPRD_EVM_TAG_ON

SPRD_EVM_TAG(4);

#endif

/* _armboot_start在u-boot.lds链接脚本中定义*/

mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);

#ifdef SPRD_EVM_TAG_ON

SPRD_EVM_TAG(5);

#endif

boot_pwr_check();

#if !defined(CONFIG_SYS_NO_FLASH)

puts ("FLASH: ");

/*配置可用的Flash */

if ((flash_size = flash_init ()) > 0) {

# ifdef CONFIG_SYS_FLASH_CHECKSUM

print_size (flash_size, "");

/*

* Compute and print flash CRC if flashchecksum is set to 'y'

*

* NOTE: Maybe we should add some WATCHDOG_RESET()? XXX

*/

s = getenv ("flashchecksum");

if (s && (*s == 'y')) {

printf (" CRC: %08X",

crc32 (0, (const unsigned char *) CONFIG_SYS_FLASH_BASE, flash_size)

);

}

putc ('\n');

# else/* !CONFIG_SYS_FLASH_CHECKSUM */

print_size (flash_size, "\n");

# endif /* CONFIG_SYS_FLASH_CHECKSUM */

} else {

puts (failed);

hang ();

}

#endif

boot_pwr_check();

#if !defined(CONFIG_EMMC_BOOT)

#if defined(CONFIG_CMD_NAND)

puts ("NAND: ");

nand_init();/* go init the NAND */

#endif

#endif

boot_pwr_check();

#ifdef SPRD_EVM_TAG_ON

SPRD_EVM_TAG(6);

#endif

#if defined(CONFIG_CMD_ONENAND)

#if !(defined CONFIG_TIGER && defined CONFIG_EMMC_BOOT)

onenand_init();

#endif

#endif

#ifdef CONFIG_GENERIC_MMC

puts("MMC: ");

mmc_initialize(bd);

#endif

#ifdef CONFIG_HAS_DATAFLASH

AT91F_DataflashInit();

dataflash_print_info();

#endif

#ifdef CONFIG_EMMC_BOOT

mmc_legacy_init(1);

#endif

/* initialize environment */

env_relocate ();

boot_pwr_check();

#ifdef CONFIG_VFD

/* must do this after the framebuffer is allocated */

drv_vfd_init();

#endif /* CONFIG_VFD */

/*tempaily use for tiger to avoid died as refreshing LCD*/

/* IP Address */ /* 从环境变量中获取IP地址 */

gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

stdio_init ();/* get the devices list going. */

boot_pwr_check();

jumptable_init ();

boot_pwr_check();

#if defined(CONFIG_API)

/* Initialize API */

api_init ();

#endif

char fake[4]="fak";

setenv("splashimage", fake);

/* 完整地初始化控制台设备 */

console_init_r ();/* fully init console as a device */

boot_pwr_check();

#if defined(CONFIG_ARCH_MISC_INIT)

/* miscellaneous arch dependent initialisations */

arch_misc_init ();

#endif

#if defined(CONFIG_MISC_INIT_R)

/* miscellaneous platform dependent initialisations */

misc_init_r ();

#endif

/* set up exceptions */

interrupt_init ();

/* enable exceptions */

enable_interrupts ();/* 使能中断处理 */

boot_pwr_check();

/* Perform network card initialisation if necessary */

#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)

/* XXX: this needs to be moved to board init */

if (getenv ("ethaddr")) {

uchar enetaddr[6];

eth_getenv_enetaddr("ethaddr", enetaddr);

smc_set_mac_addr(enetaddr);

}

#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */

/* Initialize from environment */ /* 通过环境变量初始化 */

if ((s = getenv ("loadaddr")) != NULL) {

load_addr = simple_strtoul (s, NULL, 16);

}

#if defined(CONFIG_CMD_NET)

if ((s = getenv ("bootfile")) != NULL) {

copy_filename (BootFile, s, sizeof (BootFile));

}

#endif

boot_pwr_check();

//usb_eth_initialize(NULL);

#ifdef BOARD_LATE_INIT

board_late_init ();

#endif

#ifdef CONFIG_BITBANGMII

bb_miiphy_init();

#endif

#if defined(CONFIG_CMD_NET)

#if defined(CONFIG_NET_MULTI)

puts ("Net: ");

#endif

//eth_initialize(gd->bd);

#if defined(CONFIG_RESET_PHY_R)

debug ("Reset Ethernet PHY\n");

reset_phy();

#endif

#endif

#ifdef CONFIG_POST

post_run (NULL, POST_RAM | post_bootmode_get(0));

#endif

boot_pwr_check();

#if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)

/*

* Export available size of memory for Linux,

* taking into account the protected RAM at top of memory

*/

{

ulong pram;

uchar memsz[32];

#ifdef CONFIG_PRAM

char *s;

if ((s = getenv ("pram")) != NULL) {

pram = simple_strtoul (s, NULL, 10);

} else {

pram = CONFIG_PRAM;

}

#else

pram=0;

#endif

#ifdef CONFIG_LOGBUFFER

#ifndef CONFIG_ALT_LB_ADDR

/* Also take the logbuffer into account (pram is in kB) */

pram += (LOGBUFF_LEN+LOGBUFF_OVERHEAD)/1024;

#endif

#endif

sprintf ((char *)memsz, "%ldk", (bd->bi_memsize / 1024) - pram);

setenv ("mem", (char *)memsz);

}

#endif

#ifdef SPRD_EVM_TAG_ON

SPRD_EVM_TAG(11);

#endif

extern int do_cboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);

boot_pwr_check();

do_cboot(NULL, 0, 1, NULL);

/* main_loop() can return to retry autoboot, if so just run it again. */

for (;;) {

main_loop ();/* 主循环函数处理执行用户命令 -- common/main.c */

}

/* NOTREACHED - no way out of command loop except booting */

}

命令实现

U-Boot作为Bootloader,具备多种引导内核启动的方式。常用的do命令可以直接引导内核映像启动。U-Boot与内核的关系主要是内核启动过程中参数的传递。

1.  do命令的实现:

查看参数:do_cboot(NULL, 0, 1, NULL);

u-boot\property

U_BOOT_CMD(

cboot, CONFIG_SYS_MAXARGS, 1, do_cboot,

"choose boot mode",

"mode: \nrecovery, fastboot, dloader, charge, normal, vlx, caliberation.\n"

"cboot could enter a mode specified by the mode descriptor.\n"

"it also could enter a proper mode automatically depending on "

"the environment\n"

);

int do_cboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])

{

… …

boot_pwr_check();//检查是否有power按键

… …

CHG_Init();//充电模块初始化

… …

boot_pwr_check();//再次检查是否有power按键

board_keypad_init();//初始化按键选项

boot_pwr_check();//再次检查是否有power按键

int recovery_init(void);//恢复出厂设置初始化

int ret =0;

ret = recovery_init();

if(ret == 1){

DBG("func: %s line: %d\n", __func__, __LINE__);

recovery_mode_without_update();

}else if(ret == 2){

try_update_modem(); //update img from mmc

normal_mode();

}

… …

//检查重启模式

unsigned check_reboot_mode(void);

unsigned rst_mode= check_reboot_mode();

if(rst_mode == RECOVERY_MODE){

DBG("func: %s line: %d\n", __func__, __LINE__);

recovery_mode();

}

else if(rst_mode == FASTBOOT_MODE){

DBG("func: %s line: %d\n", __func__, __LINE__);

fastboot_mode();

}else if(rst_mode == NORMAL_MODE){

normal_mode();

}else if(rst_mode == WATCHDOG_REBOOT){

watchdog_mode();

}else if(rst_mode == UNKNOW_REBOOT_MODE){

unknow_reboot_mode();

}else if(rst_mode == PANIC_REBOOT){

panic_reboot_mode();

}else if(rst_mode == ALARM_MODE){

int flag =alarm_flag_check();

if(flag == 1)

alarm_mode();

else if(flag == 2)

normal_mode();

}else if(rst_mode == SLEEP_MODE){

sleep_mode();

}else if(rst_mode == SPECIAL_MODE){

special_mode();

}

… …

//充电连接,充电模式

if(charger_connected()){

DBG("%s: charger connected\n", __FUNCTION__);

charge_mode();

}

//find the power up trigger //检查是否有power按键,是否是组合按键

else if(boot_pwr_check() >= get_pwr_key_cnt()){

DBG("%s: power button press\n", __FUNCTION__);

DBG("boot_pwr_check=%d,get_pwr_key_cnt=%d\n",boot_pwr_check(),get_pwr_key_cnt());

//go on to check other keys

mdelay(50);

for(i=0; i<10;i++){

key_code = board_key_scan();

if(key_code != KEY_RESERVED)

break;

}

DBG("key_code %d\n", key_code);

key_mode = check_key_boot(key_code);

switch(key_mode){

case BOOT_FASTBOOT:

fastboot_mode();

break;

case BOOT_RECOVERY:

recovery_mode();

break;

case BOOT_CALIBRATE:

engtest_mode();

return 0; //back to normal boot

break;

case BOOT_DLOADER:

dloader_mode();

break;

default:

break;

}

}

else if(alarm_triggered() && alarm_flag_check()){//alarm模式

DBG("%s: alarm triggered\n", __FUNCTION__);

int flag =alarm_flag_check();

if(flag == 1)

alarm_mode();

else if(flag == 2)

normal_mode();

}else{

#if BOOT_NATIVE_LINUX_MODEM

*(volatile u32*)CALIBRATION_FLAG = 0xca;

#endif

calibration_detect(0);

//if calibrate success, it will here

DBG("%s: power done again\n", __FUNCTION__);

power_down_devices();

while(1)

;

}

//主要为1个参数,正常模式启动

if(argc == 1){

DBG("func: %s line: %d\n", __func__, __LINE__);

normal_mode();

return 1;

}

… …

}

将会进入此函数normal_mode(normal_mode.c)

void normal_mode(void)

{

#if defined (CONFIG_SC8810) || defined (CONFIG_SC8825)

//MMU_Init(CONFIG_MMU_TABLE_ADDR);

vibrator_hw_init();

#endif

set_vibrator(1);//按开机按键震动设置

#if BOOT_NATIVE_LINUX

vlx_nand_boot(BOOT_PART, CONFIG_BOOTARGS, BACKLIGHT_ON);

#else

vlx_nand_boot(BOOT_PART, NULL, BACKLIGHT_ON);//从这里启动

#endif

}

将进入vlx_nand_boot(normal_nand_mode.c)

void vlx_nand_boot(char * kernel_pname, char * cmdline, int backlight_set)

{

boot_img_hdr *hdr = (void *)raw_header;

struct mtd_info *nand;

struct mtd_device *dev;

struct part_info *part;

u8 pnum;

int ret;

size_t size;

loff_t off = 0;

char *fixnvpoint = "/fixnv";

char *fixnvfilename = "/fixnv/fixnv.bin";

char *fixnvfilename2 = "/fixnv/fixnvchange.bin";

char *backupfixnvpoint = "/backupfixnv";

char *backupfixnvfilename = "/backupfixnv/fixnv.bin";

char *runtimenvpoint = "/runtimenv";

char *runtimenvfilename = "/runtimenv/runtimenv.bin";

char *runtimenvfilename2 = "/runtimenv/runtimenvbkup.bin";

char *productinfopoint = "/productinfo";

char *productinfofilename = "/productinfo/productinfo.bin";

char *productinfofilename2 = "/productinfo/productinfobkup.bin";

int orginal_right, backupfile_right;

unsigned long orginal_index, backupfile_index;

nand_erase_options_t opts;

char * mtdpart_def = NULL;

#if (defined CONFIG_SC8810) || (defined CONFIG_SC8825)

MMU_Init(CONFIG_MMU_TABLE_ADDR);//初始化MMU内存管理单元

#endif

ret = mtdparts_init();//flash 区域初始化

if (ret != 0){

printf("mtdparts init error %d\n", ret);

return;

}

#ifdef CONFIG_SPLASH_SCREEN

#define SPLASH_PART "boot_logo"

ret = find_dev_and_part(SPLASH_PART, &dev, &pnum, &part);//查找开机logo

if(ret){

printf("No partition named %s\n", SPLASH_PART);

return;

}else if(dev->id->type != MTD_DEV_TYPE_NAND){

printf("Partition %s not a NAND device\n", SPLASH_PART);

return;

}

off=part->offset;

nand = &nand_info[dev->id->num];

//read boot image header

size = 1<<19;//where the size come from????

char * bmp_img = malloc(size);

if(!bmp_img){

printf("not enough memory for splash image\n");

return;

}

ret = nand_read_offset_ret(nand, off, &size, (void *)bmp_img, &off);

if(ret != 0){

printf("function: %s nand read error %d\n", __FUNCTION__, ret);

return;

}

//显示开机logo

lcd_display_logo(backlight_set,(ulong)bmp_img,size);

#endif

#if !(BOOT_NATIVE_LINUX)

/*int good_blknum, bad_blknum;

nand_block_info(nand, &good_blknum, &bad_blknum);

printf("good is %d bad is %d\n", good_blknum, bad_blknum);*/

///

/* recovery damaged fixnv or backupfixnv */

/* FIXNV_PART */

printf("Reading fixnv to 0x%08x\n", FIXNV_ADR);

//try "/fixnv/fixnvchange.bin" first,if fail,

//try /fixnv/fixnv.bin instead

ret = load_sector_to_memory(fixnvpoint,

fixnvfilename2,

fixnvfilename,

(unsigned char *)FIXNV_ADR,

(unsigned char *)MODEM_ADR,

FIXNV_SIZE + 4);

if(ret == -1){

//fixnvpoint's files are not correct

//the "/backupfixnv/fixnv.bin" must be correct!

ret = load_sector_to_memory(backupfixnvpoint,

backupfixnvfilename,

0,

(unsigned char *)FIXNV_ADR,

(unsigned char *)MODEM_ADR,//we just test if it's correct.

FIXNV_SIZE + 4);

if(ret ==1){

//we got a right file in backupfixnvpoint,

//use it to recovery fixnvpoint's files.

recovery_sector(fixnvpoint,

fixnvfilename,

fixnvfilename2,

(unsigned char *)FIXNV_ADR,

FIXNV_SIZE + 4);

}else{

//backupfixnvpoint's files are still uncorrect.

//then we can do nothing to get it right!!!!

//there is an fatal error has occured.

printf("\n\nfixnv and backupfixnv are all wrong!\n\n");

return -1;

//clear memory

//memset(FIXNV_ADR, 0xff,FIXNV_SIZE + 4);

}

}else{

//everything is right!!

//we can chose to do it or not.

ret = load_sector_to_memory(backupfixnvpoint,

backupfixnvfilename,

0,

(unsigned char *)RUNTIMENV_ADR,//we just test if it's correct.

(unsigned char *)MODEM_ADR,//we just test if it's correct.

FIXNV_SIZE + 4);

if(ret == -1){

recovery_sector(backupfixnvpoint,

backupfixnvfilename,

0,

(unsigned char *)FIXNV_ADR,

FIXNV_SIZE + 4);

}

}

//finally we check the fixnv structure,if fail,then u-boot will hung up!!!

if(check_fixnv_struct(FIXNV_ADR,FIXNV_SIZE) == -1){

printf("check fixnv structer error ............\r\n");

return -1;

}

///

/* PRODUCTINFO_PART */

ret = load_sector_to_memory(productinfopoint,

productinfofilename2,

productinfofilename,

(unsigned char *)PRODUCTINFO_ADR,

(unsigned char *)MODEM_ADR,//we just test if it's correct.

PRODUCTINFO_SIZE + 4);

if(ret == -1){

printf("don't need read productinfo to 0x%08x!\n", PRODUCTINFO_ADR);

}

eng_phasechecktest((unsigned char *)PRODUCTINFO_ADR, SP09_MAX_PHASE_BUFF_SIZE);

///

///

/* RUNTIMEVN_PART */

ret = load_sector_to_memory(runtimenvpoint,

runtimenvfilename2,

runtimenvfilename,

(unsigned char *)RUNTIMENV_ADR,

(unsigned char *)MODEM_ADR,//we just test if it's correct.

RUNTIMENV_SIZE + 4);

if(ret == -1){

//clear memory

memset(RUNTIMENV_ADR, 0xff,RUNTIMENV_SIZE + 4);

}

//array_value((unsigned char *)RUNTIMENV_ADR, RUNTIMENV_SIZE);

/* DSP_PART */

printf("Reading dsp to 0x%08x\n", DSP_ADR);

ret = find_dev_and_part(DSP_PART, &dev, &pnum, &part);

if (ret) {

printf("No partition named %s\n", DSP_PART);

return;

} else if (dev->id->type != MTD_DEV_TYPE_NAND) {

printf("Partition %s not a NAND device\n", DSP_PART);

return;

}

off = part->offset;

nand = &nand_info[dev->id->num];

flash_page_size = nand->writesize;

size = (DSP_SIZE + (flash_page_size - 1)) & (~(flash_page_size - 1));

if(size <= 0) {

printf("dsp image should not be zero\n");

return;

}

ret = nand_read_offset_ret(nand, off, &size, (void*)DSP_ADR, &off);

if(ret != 0) {

printf("dsp nand read error %d\n", ret);

return;

}

secure_check(DSP_ADR, 0, DSP_ADR + DSP_SIZE - VLR_INFO_OFF, CONFIG_SYS_NAND_U_BOOT_DST + CONFIG_SYS_NAND_U_BOOT_SIZE - KEY_INFO_SIZ - VLR_INFO_OFF);

#elif defined(CONFIG_CALIBRATION_MODE_NEW)

#if defined(CONFIG_SP7702) || defined(CONFIG_SP8810W)

/*

force dsp sleep in native 8810 verson to reduce power consumption

*/

extern void DSP_ForceSleep(void);

DSP_ForceSleep();

printf("dsp nand read ok1 %d\n", ret);

#endif

//开机校准

if(poweron_by_calibration())

{

/* recovery damaged fixnv or backupfixnv */

orginal_right = 0;

memset((unsigned char *)FIXNV_ADR, 0xff, 0x20000);

cmd_yaffs_mount(fixnvpoint);

ret = cmd_yaffs_ls_chk(fixnvfilename);

if (ret == (FIXNV_SIZE + 4)) {

cmd_yaffs_mread_file(fixnvfilename, (unsigned char *)FIXNV_ADR);

//should do something here

}

cmd_yaffs_umount(fixnvpoint);

printf("Reading fixnv to 0x%08x \n", FIXNV_ADR);

/* DSP_PART */

printf("Reading dsp to 0x%08x\n", DSP_ADR);

ret = find_dev_and_part(DSP_PART, &dev, &pnum, &part);

if (ret) {

printf("No partition named %s\n", DSP_PART);

return;

} else if (dev->id->type != MTD_DEV_TYPE_NAND) {

printf("Partition %s not a NAND device\n", DSP_PART);

return;

}

off = part->offset;

nand = &nand_info[dev->id->num];

flash_page_size = nand->writesize;

size = (DSP_SIZE + (flash_page_size - 1)) & (~(flash_page_size - 1));

if(size <= 0) {

printf("dsp image should not be zero\n");

return;

}

ret = nand_read_offset_ret(nand, off, &size, (void*)DSP_ADR, &off);

if(ret != 0) {

printf("dsp nand read error %d\n", ret);

return;

}

printf("Reading firmware to 0x%08x\n", FIRMWARE_ADR);

ret = find_dev_and_part(FIRMWARE_PART, &dev, &pnum, &part);

if (ret) {

printf("No partition named %s\n", FIRMWARE_PART);

return;

} else if (dev->id->type != MTD_DEV_TYPE_NAND) {

printf("Partition %s not a NAND device\n", FIRMWARE_PART);

return;

}

off = part->offset;

nand = &nand_info[dev->id->num];

size = (FIRMWARE_SIZE +(flash_page_size - 1)) & (~(flash_page_size - 1));

if(size <= 0) {

printf("firmware image should not be zero\n");

return;

}

ret = nand_read_offset_ret(nand, off, &size, (void*)FIRMWARE_ADR, &off);

if(ret != 0) {

printf("firmware nand read error %d\n", ret);

return;

}

printf("Reading vmjaluna to 0x%08x\n", VMJALUNA_ADR);

ret = find_dev_and_part(VMJALUNA_PART, &dev, &pnum, &part);

if (ret) {

printf("No partition named %s\n", VMJALUNA_PART);

return;

} else if (dev->id->type != MTD_DEV_TYPE_NAND) {

printf("Partition %s not a NAND device\n", VMJALUNA_PART);

return;

}

off = part->offset;

nand = &nand_info[dev->id->num];

size = (VMJALUNA_SIZE +(flash_page_size - 1)) & (~(flash_page_size - 1));

if(size <= 0) {

printf("modem image should not be zero\n");

return;

}

ret = nand_read_offset_ret(nand, off, &size, (void*)VMJALUNA_ADR, &off);

if(ret != 0) {

printf("modem nand read error %d\n", ret);

return;

}

printf("call bootup modem in vlx_nand_boot,0x%x 0x%x\n",FIXNV_ADR, FIXNV_SIZE);

bootup_modem((char *)VMJALUNA_ADR,0x3000);

calibration_mode(cmdline, 10);

memset(VMJALUNA_ADR,0,VMJALUNA_SIZE);

memset(FIXNV_ADR,0,FIXNV_SIZE+4);

memset(MODEM_ADR,0,MODEM_SIZE);

memset(DSP_ADR,0,DSP_SIZE);

memset(RUNTIMENV_ADR,0,RUNTIMENV_SIZE+4);

}

#endif

set_vibrator(0);

/* KERNEL_PART */

printf("Reading kernel to 0x%08x\n", KERNEL_ADR);

ret = find_dev_and_part(kernel_pname, &dev, &pnum, &part);

if(ret){

printf("No partition named %s\n", kernel_pname);

return;

}else if(dev->id->type != MTD_DEV_TYPE_NAND){

printf("Partition %s not a NAND device\n", kernel_pname);

return;

}

off=part->offset;

nand = &nand_info[dev->id->num];

//read boot image header

//加载内核

ret = load_kernel_and_layout(nand,

(unsigned int)off,

(char *)raw_header,

(char *) KERNEL_ADR,

(char *) RAMDISK_ADR,

2048,

nand->writesize);

if (ret != 0) {

printf("ramdisk nand read error %d\n", ret);

return;

}

#if !(BOOT_NATIVE_LINUX)

/* MODEM_PART */

printf("Reading modem to 0x%08x\n", MODEM_ADR);

ret = find_dev_and_part(MODEM_PART, &dev, &pnum, &part);

if (ret) {

printf("No partition named %s\n", MODEM_PART);

return;

} else if (dev->id->type != MTD_DEV_TYPE_NAND) {

printf("Partition %s not a NAND device\n", MODEM_PART);

return;

}

off = part->offset;

nand = &nand_info[dev->id->num];

flash_page_size = nand->writesize;

size = (MODEM_SIZE +(flash_page_size - 1)) & (~(flash_page_size - 1));

if(size <= 0) {

printf("modem image should not be zero\n");

return;

}

ret = nand_read_offset_ret(nand, off, &size, (void*)MODEM_ADR, &off);

if(ret != 0) {

printf("modem nand read error %d\n", ret);

return;

}

secure_check(MODEM_ADR, 0, MODEM_ADR + MODEM_SIZE - VLR_INFO_OFF, CONFIG_SYS_NAND_U_BOOT_DST + CONFIG_SYS_NAND_U_BOOT_SIZE - KEY_INFO_SIZ - VLR_INFO_OFF);

//array_value((unsigned char *)MODEM_ADR, MODEM_SIZE);

/* VMJALUNA_PART */

printf("Reading vmjaluna to 0x%08x\n", VMJALUNA_ADR);

ret = find_dev_and_part(VMJALUNA_PART, &dev, &pnum, &part);

if (ret) {

printf("No partition named %s\n", VMJALUNA_PART);

return;

} else if (dev->id->type != MTD_DEV_TYPE_NAND) {

printf("Partition %s not a NAND device\n", VMJALUNA_PART);

return;

}

off = part->offset;

nand = &nand_info[dev->id->num];

size = (VMJALUNA_SIZE +(flash_page_size - 1)) & (~(flash_page_size - 1));

if(size <= 0) {

printf("VMJALUNA image should not be zero\n");

return;

}

ret = nand_read_offset_ret(nand, off, &size, (void*)VMJALUNA_ADR, &off);

if(ret != 0) {

printf("VMJALUNA nand read error %d\n", ret);

return;

}

secure_check(VMJALUNA_ADR, 0, VMJALUNA_ADR + VMJALUNA_SIZE - VLR_INFO_OFF, CONFIG_SYS_NAND_U_BOOT_DST + CONFIG_SYS_NAND_U_BOOT_SIZE - KEY_INFO_SIZ - VLR_INFO_OFF);

#endif

creat_cmdline(cmdline,hdr);//

vlx_entry();//启动内核模块

}

加载linux kernel函数

static int load_kernel_and_layout(struct mtd_info *nand,

unsigned int phystart,

char *header,

char *kernel,

char *ramdisk,

unsigned int virtual_page_size,

unsigned int real_page_size

) {

int ret = -1;

boot_img_hdr *hdr = (boot_img_hdr*)header;

unsigned int off = phystart;

int size = real_page_size;

printf("virtual_page_size : %x\n",virtual_page_size);

printf("real_page_size : %x\n",real_page_size);

//read boot image header

ret = nand_read_offset_ret(nand, off, &size, (void *)hdr, &off);

if(ret != 0){

printf("function: %s nand read error %d\n", __FUNCTION__, ret);

return -1;

}

if(memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)){

printf("bad boot image header, give up read!!!!\n");

return -1;

}

else

{

char* prev_page_addr = header;

//we asume that the header takes only one page.

//read kernel image prepare

unsigned int used_size = 1*virtual_page_size;

unsigned int spare_size = 0;

unsigned int next_file_size = hdr->kernel_size;

if(used_size > 0){

spare_size = real_page_size - used_size;

}else{

spare_size = 0;

}

//read kernel image

printf("file size: %x\n",hdr->kernel_size);

printf("use size: %x\n",used_size);

printf("spare size: %x\n",spare_size);

if(spare_size) {

memcpy(kernel,&prev_page_addr[used_size],spare_size);

next_file_size -= spare_size;

}

size = (next_file_size+(real_page_size - 1)) & (~(real_page_size - 1));

ret = nand_read_offset_ret(nand, off, &size, (void *)(kernel+spare_size), &off);

if(ret != 0){

printf("reading kernel error!\n");

printf("try reading to %x\n",kernel+spare_size);

}

//read ramdisk image prepare

prev_page_addr = (char*)(kernel+spare_size+size-real_page_size);

used_size = (next_file_size%real_page_size+virtual_page_size-1)&(~(virtual_page_size-1));

if(used_size > 0){

spare_size = real_page_size - used_size;

}else{

spare_size = 0;

}

next_file_size = hdr->ramdisk_size;

printf("file size: %x\n",hdr->ramdisk_size);

printf("use size: %x\n",used_size);

printf("spare size: %x\n",spare_size);

//read ramdisk image

if(spare_size){

memcpy(ramdisk,&prev_page_addr[used_size],spare_size);

next_file_size -= spare_size;

}

size = (next_file_size+(real_page_size - 1)) & (~(real_page_size - 1));

ret = nand_read_offset_ret(nand, off, &size, (void *)(ramdisk+spare_size), &off);

if(ret != 0){

printf("reading ramdisk error!\n");

printf("try reading to %x\n",ramdisk+spare_size);

}

}

return ret;

}

void vlx_entry()

{

void (*entry)(void) = (void*) VMJALUNA_ADR;

#ifndef CONFIG_SC8810

#ifndef CONFIG_TIGER

MMU_InvalideICACHEALL();

#endif

#endif

#if (defined CONFIG_SC8810) || (defined CONFIG_SC8825)

MMU_DisableIDCM();

#endif

#ifdef REBOOT_FUNCTION_INUBOOT

reboot_func();

#endif

#if BOOT_NATIVE_LINUX

start_linux();

#else

entry();

#endif

}

static int start_linux()

{

void (*theKernel)(int zero, int arch, u32 params);

u32 exec_at = (u32)-1;

u32 parm_at = (u32)-1;

u32 machine_type;

machine_type = machine_arch_type; /* get machine type */

theKernel = (void (*)(int, int, u32))KERNEL_ADR; /* set the kernel address */

*(volatile u32*)0x84001000 = 'j';

*(volatile u32*)0x84001000 = 'm';

*(volatile u32*)0x84001000 = 'p';

theKernel(0, machine_type, VLX_TAG_ADDR); /* jump to kernel with register set */

while(1);

return 0;

}

引导linux内核并启动。

遗留问题:

1、  传递参数到linux内核。

2、  Uboot到底做了什么?分别问那些部分?如:背光如何亮的,如何显示开机logo的。

3、  Nand flash如何启动并且初始化的?

4、  其他涉及到的模块初始化问题?

5、  Watchdog如何开始工作?

6、  总结回顾。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值