原创
关于vivi bootloader的理解
2007-6-7 14:30
4468
6
6
分类:
软件与OS
开机的整个过程
第一步:
@
@ Start VIVI head
@ what head.S does(this is the stage1 of bootloader):
@ 1. disable watch dog timer( watch dog timer is enable when reset)
@ 2. disable all interrupts, using register INTMSK and INTSUBMSK
@ 3. initialise system clocks:
@ FCLK for CPU = 200MHz, HCLK for the AHB bus peripherals = 100MHz, and PCLK for the APB bus peripherals = 50MHz.
@ Asynchronous
@ 4. initialise the static memory---set memory control registers
@ 5. check whether waked up from PWR_OFF mode, if do, call WakeupStart.
@ 6. ALL LED on
@ 7. set GPIO for UART
@ 8. copy vivi to ram(copy_myself):
@ a. set nand flash control registers
@ b. set the stack pointer
@ c. set parameters for C function nand_read_ll(arch/s3c2410/nand_read.c)
@ d. call nand_read_ll to copy vivi from nand flash to ram
@ e. verify the first 4k bytes data, compare between address range 0x00000000-0x00001000 and 0x33f00000-0x33f01000
@ 9. jump to ram(when execute arm-gcc-ld, it uses arch/vivi.lds to define that the base address is 0x33f00000, which is VIVI_RAM_BASE) :
@ a. set the stack pointer
@ b. set the parameters for C function main(init/main.c)
@ c. call main
第二步:
进入main函数:
/*
* Step 1:
*
*/
reset_handler(); /* include/reset_handle.h, do nothing */
/*
* Step 2:
*
*/
ret = board_init(); /*arch/s3c2410/smdk.c*/
/*it calls init_time(at arch/s3c2410/proc.c) and set_gpios(in arch/s3c2410/smdk.c)*/
/*init_time: TCFG0 = 0 | 0xf00 | 0 */
/*
* Step 3:
*
*/
mem_map_init(); /*arch/s3c2410/mmu.c line194*/
/*1. call mem_map_nand_boot in arch/s3c2410/mmu.c
this function call mem_mapping_linear immediately
mem_mapping_linear(arch/s3c2410/mmu.c):
initialize the mmu translation table, Make DRAM section cacheable
2. call cache_clean_invalidate in arch/s3c2410/mmu.c: clean and invalidate all cache lines
3. call tlb_invalidate in arch/s3c2410/mmu.c: invalidate I & D TLBs
*/
mmu_init(); /*arch/s3c2410/mmu.c line120*/
/*call arm920_setup in arch/s3c2410/mmu.c:
1. invalidate I,D caches
2. drain write buffer
3. invalidate I,D TLBs
4. load page table pointer(has been initialized at mmm_mapping_linear upside)
5. set MMU control registers:
a. base location of exception = 0 (exception vectors' start address is 0x00000000)
b. RS=0b00 (RS is not used as AP=0b11 which means all access types permitted
in both supervisor and user mode)
c. set little-endian
d. mmu enable
*/
/*
* Now, vivi is running on the ram. MMU is enabled.
*/
/*
* Step 4:
*
*/
/* initialize the heap area*/
ret = heap_init(); /*lib/heap.c*/
/*heap is a memory from which the function mmalloc require a memory block
it calls mmalloc_init in lib/heap.c to initialize the heap
*/
/* add by thisway.diy */
usb_init();
/* Step 5:
*/
ret = mtd_dev_init(); /*drivers/mtd/mtdcore.c*/
/*it calls the functions mtd_init at drivers/mtd/maps/s3c2410_flash.c:
calls smc_init at the same file:
a. mmalloc memory for strcut mymtd
b. initialize (struct nand_chip *)(&mymtd[1]) for NAND FLASH
c. call smc_insert at the same file:
call the functions smc_scan at drivers/mtd/nand/smc_core.c:
read the ID of NAND FLASH, compare it with the pre-defined infomation of some usually types of NAND FLASH, and then
set the NAND FLASH's data struct (struct nand_chip *)(&mymtd[1]).
*/
/* Step 6:
*
*/
init_priv_data(); /*lib/priv_data/rw.c*/
/*there are two sets of vivi's parameters, one are the default parameters and the other are the saved parameters.
init_priv_data load the default parameters on the memory, and then load the saved parameters and overwrite the corespointing part of the default parameters if the saved parameters is validate. The saved parameters were
stored at the param partion of nand flash.
1. get_default_data(lib/priv_data/rw.c):
a. get_default_param_tlb, defined at struct default_vivi_parameters at arch/s3c2410/smdk.c
b. get_default_linux_cmd, copy linux command "char linux_cmd[] = "noinitrd root=/dev/mtdblock/0
init=/linuxrc console=ttyS0" "(arch/s3c2410/smdk.c)
c. get_default_mtd_partition, defined at struct default_mtd_partitions at arch/s3c2410/smdk.c
2. load_saved_priv_data(lib/priv_data/rw.c):
a. read_saved_priv_data_blk(at the same file), read the saved vivi parameters from the param part of
nand flash to DRAM_BASE
b. copy the saved tlb parameters from DRAM_BASE to overwrite what 1.a stores
c. copy the saved linux command from DRAM_BASE to overwrite what 1.b stores
d. copy the saved part parameters from DRAM_BASE to overwrite what 1.c stores
*/
/* Step 7:
*
*/
misc(); /*arch/s3c2410/smdk.c*/
/*call the function add_command(&cpu_cmd) defined at lib/command.c, to add the cpu command to the command chain
this command is used to change the cpu's clock
*/
init_builtin_cmds(); /*lib/command.c*/
/*1. add_command(&bon_cmd)
2. add_command(&reset_cmd)
3. add_command(¶m_cmd)
4. add_command(&part_cmd)
5. add_command(&mem_cmd)
6. add_command(&load_cmd)
7. add_command(&go_cmd)
8. add_command(&dump_cmd)
9. add_command(&call_cmd)
10.add_command(&boot_cmd)
11.add_command(&help_cmd)
*/
/* Step 8:
*
*/
boot_or_vivi(); /*call vivi_shell() or run_autoboot.
1. run_autoboot:
exec_string("boot") (lib/command.c):
parse the sting "boot", and then call the function execcmd:
use the execcmd's parameter to find the boot_cmd's function and executive it:
the boot_cmd was defined at lib/boot_kernel.c(see follow):
user_command_t boot_cmd = {
"boot",
command_boot,
NULL,
"boot [{cmds}] \t\t\t-- Booting linux kernel"
};
so, we call the function command_boot(lib/boot_kernel.c):
a. media_type = get_param_value("media_type", &ret)
(lib/priv_data/param.c), media_type=3
b. kernel_part = get_mtd_partition("kernel")
(lib/priv_data/mtdpart.c), see also arch/s3c2410/smdk.c
name: "kernel",
offset: 0x00030000,
size: 0x00100000,
flag: 0
c. boot_kernel(from, size, media_type) (lib/boot_kernel.c):
i. copy the kernel image from the kernel partion on nand
flash to ram(boot_mem_base + LINUX_KERNEL_OFFSET,
0x30008000)using the copy_kernel_img.
ii.setup_linux_param, set the linux parameters at
boot_mem_base + LINUX_PARAM_OFFSET(0x30000100),
these parameters were stored as a struct param_struct,
which contains the command line parameter.
iii.call_linux(0, mach_type, to)
(boot_mem_base + LINUX_KERNEL_OFFSET=0x30008000)
(1). cache_clean_invalidate
(2). tlb_invalidate
(3). use the inline asm to jump to linux kernel:
define the p15 corprocessor:
zero PID
invalidate I,D caches
drain write buffer
invalidate I,D TLBs
get control register
disable MMU
write control register
set the PC register as the kernel address:
mov pc, r2
2. vivi_shell:
call the function serial_term at drivers/serial/term.c:
a. printk("%s> ", prompt), display the string "vivi>"
b. getcmd(cmd_buf, MAX_CMDBUF_SIZE) at drivers/serial/getcmd.c, wait for the command send
from serial port by user
c. exec_string(cmd_buf) at lib/command.c:
parseargs
execcmd
*/
/*******************************************************************************************
Now, the DRAM is seperated to these parts;
+-----------------------------------------------+ 0x33ff_ffff = 0x3000_0000+64M-1
+ +
+ +
+ 1M VIVI +
+ +
+ +
+-----------------------------------------------+ 0x33f0_0000 = VIVI_RAM_BASE
+ +
+ +
+ 1M HEAP +
+ +
+ +
+-----------------------------------------------+ 0x33e0_0000 = HEAP_BASE
+ 16k MMU_TABLE +
+-----------------------------------------------+ 0x33df_c000 = MMU_TABLE_BASE (used at the stage2 of bootloader)
+ 16k LINUX_CMD +
+ + LINUX_CMD_OFFSET = 16 k
+ 16k PARAMETER_TLB +
+ + PARAMETER_TLB_OFFSET = 16k
+ 16k PARAMETER_PART +
+-----------------------------------------------+ 0x33df_0000 = VIVI_PRIV_RAM_BASE (PARAMETER_PART_OFFSET = 0)
+ +
+ 32k STACK +
+ +
+-----------------------------------------------+ 0x33de_8000 = STACK_BASE
+ . +
+ . +
+ . +
+ . +
+ . +
+ . +
+-----------------------------------------------+
+ +
+ +
+ 1M LINUX KERNEL +
+ +
+ +
+-----------------------------------------------+ 0x3000_8000 = the kernel image is placed begin this address
+ +
+ LINUX PAREMETER +
+-----------------------------------------------+ LINUX_PARAM_OFFSET = 0x100
+-----------------------------------------------+ 0x3000_0000 = RAM_BASE
*******************************************************************************************/
这样main函数内的boot_or_vivi();进入了死循环。
从boot_or_vivi()进入vivi_shell();
接着进入:serial_term(); /*drivers/serial/term.c*/
for (;;) {
printk("%s> ", prompt); /*prompt is defined upside*/
getcmd(cmd_buf, MAX_CMDBUF_SIZE); /*drivers/serial/getcmd.c*/
/* execute a user command */
if (cmd_buf[0])
exec_string(cmd_buf);
}
这样就不断地得到命令,
然后执行命令。
application的code编写的话,就在每个.c文件内写成
写一个函数实现下面的结构体:
typedef struct user_command {
const char *name;
void (*cmdfunc)(int argc, const char **);
struct user_command *next_cmd;
const char *helpstr;
} user_command_t;
这样通过这个结构体把application和系统联一起了。
例如:
void command_flash(int argc, const char **argv)
{
if (mymtd == NULL) {
printk("Error: Can not find MTD information\n");
return;
}
if (argc == 1) {
printk("invalid 'flash' command: too few arguments\n");
command_help(0, NULL);
return;
}
execsubcmd(flash_cmds, argc-1, argv+1);
}
static user_command_t flash_cmd = {
"flash",
command_flash,
NULL,
"flash [{cmds}] \t\t\t-- Manage Flash memory"
};
文章评论(0条评论)
登录后参与讨论