jz2440 kernel 移植(启动代码分析)

来源:互联网 发布:唯一网络王宇杰豪车 编辑:程序博客网 时间:2024/05/14 16:04
1、内核中处理器部分:
************************
内核中要查找处理器相关,通过_lookup_processor_type函数进行查找,其中涉及到重要的结构


proc_lifo_list(include/asm-arm/procinfo.h定义),而对于arm920处理器,在proc-arm920.S


(arch/arm/mm/)中进行在段属性中.proc.info.init赋值。方便在r0读取到CPU ID后与.proc.info.init
段的内容进行查找比对后,确定CPU的型号。
/include/asm-arm/procinfo.h
struct proc_info_list {
unsigned int cpu_val;
unsigned int cpu_mask;
unsigned long __cpu_mm_mmu_flags; /* used by head.S */
unsigned long __cpu_io_mmu_flags; /* used by head.S */
unsigned long __cpu_flush; /* used by head.S */
const char *arch_name;
const char *elf_name;
unsigned int elf_hwcap;
const char *cpu_name;
struct processor*proc;
struct cpu_tlb_fns*tlb;
struct cpu_user_fns*user;
struct cpu_cache_fns*cache;
};
/arch/arm/mm/proc-arm920.S
.section ".proc.info.init", #alloc, #execinstr


.type __arm920_proc_info,#object
__arm920_proc_info:
.long 0x41009200
.long 0xff00fff0
.long   PMD_TYPE_SECT | \
PMD_SECT_BUFFERABLE | \
PMD_SECT_CACHEABLE | \
PMD_BIT4 | \
PMD_SECT_AP_WRITE | \
PMD_SECT_AP_READ
.long   PMD_TYPE_SECT | \
PMD_BIT4 | \
PMD_SECT_AP_WRITE | \
PMD_SECT_AP_READ
b __arm920_setup
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
.long cpu_arm920_name
.long arm920_processor_functions
.long v4wbi_tlb_fns
.long v4wb_user_fns
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
.long arm920_cache_fns
#else
.long v4wt_cache_fns
#endif
.size __arm920_proc_info, . - __arm920_proc_info


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


2、内核中开发板mach部分:
**********************
内核中要查找开发板相关,通过__lookup_machine_type函数查找,其中涉及的重要的结构machine_desc
(include/asm-arm/mach/arch.h定义),而对于SMDK2440开发板,在mach-smdk2440.c(arch/arm/mach-


S3C2440)中对其进行赋值。
/include/asm-arm/mach/arch.h
struct machine_desc {
/*
* Note! The first four elements are used
* by assembler code in head-armv.S
*/
unsigned int nr; /* architecture number*/
unsigned int phys_io; /* start of physical io*/
unsigned int io_pg_offst; /* byte offset for io 
* page tabe entry*/


const char *name; /* architecture name*/
unsigned long boot_params; /* tagged list*/


unsigned int video_start; /* start of video RAM*/
unsigned int video_end; /* end of video RAM*/


unsigned int reserve_lp0 :1; /* never has lp0*/
unsigned int reserve_lp1 :1; /* never has lp1*/
unsigned int reserve_lp2 :1; /* never has lp2*/
unsigned int soft_reboot :1; /* soft reboot*/
void (*fixup)(struct machine_desc *,
struct tag *, char **,
struct meminfo *);
void (*map_io)(void);/* IO mapping function*/
void (*init_irq)(void);
struct sys_timer*timer; /* system tick timer*/
void (*init_machine)(void);
};


#define MACHINE_START(_type,_name) \
static const struct machine_desc __mach_desc_##_type\
 __used \
 __attribute__((__section__(".arch.info.init"))) = {\
.nr = MACH_TYPE_##_type,\
.name = _name,


#define MACHINE_END \
};
/arch/arm/mach-S3C2440/mach-smdk2440.c
MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
   * to SMDK2410 */
/* Maintainer: Jonas Dietsche */
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = smdk2410_map_io,
.init_irq = s3c24xx_init_irq,
.init_machine = smdk2410_init,
.timer = &s3c24xx_timer,
MACHINE_END
**********************


3、c函数是怎样连接到段属性中去的?
**********************
在函数名前面添加__init 或者 __initdata,其中它们的定义如下:
#define __init __attribute__ ((__section__ (".init.text")))
#define __initdata __attribute__ ((__section__ (".init.data")))
#define __exitdata __attribute__ ((__section__(".exit.data")))
#define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))
**********************




4、void parse_tags(tags){}函数分析
**********************
对于不同的tag进行处理,比如其中内存tag、命令tag。分别调用了parse_tag_mem32、parse_tag_commline


函数。
#define ATAG_NONE 0x00000000


struct tag_header {
__u32 size;
__u32 tag;
};
/* The list must start with an ATAG_CORE node */
#define ATAG_CORE 0x54410001


tag的定义:(/include/asm-arm/Setup.h)
struct tag {
struct tag_header hdr;
union {
struct tag_corecore;
struct tag_mem32mem;
struct tag_videotextvideotext;
struct tag_ramdiskramdisk;
struct tag_initrdinitrd;
struct tag_serialnrserialnr;
struct tag_revisionrevision;
struct tag_videolfbvideolfb;
struct tag_cmdlinecmdline;


/*
* Acorn specific
*/
struct tag_acornacorn;


/*
* DC21285 specific
*/
struct tag_memclkmemclk;
} u;
};
   这里要说明一下这里的tags实 际上是一个tag的数组或者说队列,里面有多个tag结构体,每一个结构体


都是一个header加一个参数,具体的结构我们可以看看setup.h。
  对 ATAG参数的解析全部定义在arch/arm/kernel/setup.c里面,首先在setup.c里面定义了一个类似于这样 


__tagtable(ATAG_CORE, parse_tag_core)的宏,这个宏实际上是声明了一个放在__tagtable_begin和


__tagtable_end段之间结构体,这个 结构体定义了这个一个参数类型,和对这个参数类型进行解析的函数。


所有的参数解析我们都可以从setup.c里面找到相对应的函数,比如说对 boot_commad_line的解析,从


config文件得到的default_commad_line就会被ATAG里面获得 commad_line给替换掉;再比如ramdisk,就会


将ATAG里面的ramdisk的信息赋值给rd_image_start, rd_size等系统的全局变量。


__tagtable(ATAG_CORE, parse_tag_core);
其中__tagtalbe(tag,fn)宏定义如下:
#define __tagtable(tag, fn) \
static struct tagtable __tagtable_##fn __tag = { tag, fn }
**********************


meminfo结构体描述内存块的大小、地址信息定义
**********************
struct membank {
unsigned long start;
unsigned long size;
int           node;
};


struct meminfo {
int nr_banks;
struct membank bank[NR_BANKS];
};
**********************


后续内核执行流程:
start_kernel 
        setup_arch      //解析u-boot传入的启动参数
setup_command_line  //解析u-boot传入的命令参数
rest_init
kernel_init
prepare_namespace
   mount_root    //挂接根文件系统
init_post 
   //执行应用程序
(1)重要知识点承接:
内核执行的第一个程序,是挂载根文件系统下程序,所以第一个程序是/sbin/init程序,即去解析由busyx配


置好的文件,然后再去执行重要用户程序。


(2)重要的init配置格式:
inittab格式:
<id>:<runlevels>:<action>:<process>


id =>/dev/id,用作终端:stdin,stdout,stderr: print,scanf,err
<runlevels>:可以忽略
action:指定时机
process:应用程序或脚本


例如:init:ASKFIRST:


ls/cp --> busybox
那么busybox的初始化程序要完成如下工作:
init程序 :1、读取配置文件
  2、解析配置文件
  3、执行(应用程序)
其中配置文件要做的事情:1、指定程序  
2、何时执行
(3)
busybox->init_main
...
parse_inittab(busybox中文件可能缺省)
fopen = (INITTAB,"r");//打开配置文件/etc/initab
new_init_action(..)
  init_action_list //链表 
struct init_action {    
struct init_action *next;
int action;
pid_t pid;
char command[INIT_BUFFS_SIZE];
char terminal[CONSOLE_NAME_SIZE];
};
new_init_action(ASKFIRST,"-/bin/sh","/dev/tty2");
static void new_init_action(int action,const char *command,const char *cons)
执行时机          执行程序            id用作终端
1、创建一个init_action结构,填充
2、把这个结构放入链表init_action_list




源码分析:
从默认new_init_action反推出默认的配置文件:
    new_init_action(CTRLALTDEL, "reboot", "");
/* Umount all filesystems on halt/reboot */
new_init_action(SHUTDOWN, "umount -a -r", "");
/* Swapoff on halt/reboot */
if (ENABLE_SWAPONOFF) new_init_action(SHUTDOWN, "swapoff -a", "");
/* Prepare to restart init when a HUP is received */
new_init_action(RESTART, "init", "");
/* Askfirst shell on tty1-4 */
new_init_action(ASKFIRST, bb_default_login_shell, "");
new_init_action(ASKFIRST, bb_default_login_shell, VC_2);
new_init_action(ASKFIRST, bb_default_login_shell, VC_3);
new_init_action(ASKFIRST, bb_default_login_shell, VC_4);
/* sysinit */
new_init_action(SYSINIT, INIT_SCRIPT, "");
解析结果:(如果没有配置文件!!!)
<id>:<runlevels>:<action>:<process>
::CTRLALTDEL:reboot
::SHUTDOWN:umount -a -r
::RESTART::init
::askfirst:~/bin/sh
tty2::askfirst:~/bin/sh
tty3::askfirst:~/bin/sh
tty4::askfirst:~/bin/sh
::SYSINIT:INIT_SCRIPT
1、创建一个init_action结构,填充
2、把这个结构放入链表init_action_list
busybox->init_main
...
parse_inittab(busybox中文件可能缺省)
fopen = (INITTAB,"r");//打开配置文件/etc/initab
new_init_action(..)             //创建一个init_action结构,填充
  init_action_list //链表 //把这个结构放入


init_action_list链表
run_actions(SYSINIT)
waitfor(a,0);       //执行应用程序,等待它执行完毕
run(a);        //创建process子进程
waitpid(runpid,&status,0)      //等待结束
delete_init_action(a); //在init_action_list链表里删除
run_actions(WAIT)
waitfor(a,0);       //执行应用程序,等待它执行完毕
run(a);        //创建process子进程
waitfor(runpid,&status,0)      //等待结束
delete_init_action(a); //在init_action_list链表里删除
run_actions(ONCE)
run(a);        //创建process子进程
delete_init_action(a); //在init_action_list链表里删除
while(1){
run_action(RESPAWN);
if(a->pid==0){
a->pid = run(a);
}
run_action(ASKFIRST);
if(a->pid==0){
a->pid = run(a)
}
wpid = wait(NULL);//等待子进程退出
while(wpid > 0)
{
a->pid = 0;//退出后,就设置pid=0
}
}
init_main只是busybox其中的一个应用程序,还有ls_main


总结最小的根文件系统所必须的:
|-1、/dev/console  /dev/null 
| 2、init => busybox
| 3、/etc/inittab
| 4、配置文件指定的程序
|-5、C库
0 0
原创粉丝点击