您的位置:首页 > 编程语言

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

2015-08-26 09:13 411 查看
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_core
core;

struct tag_mem32
mem;

struct tag_videotext
videotext;

struct tag_ramdisk
ramdisk;

struct tag_initrd
initrd;

struct tag_serialnr
serialnr;

struct tag_revision
revision;

struct tag_videolfb
videolfb;

struct tag_cmdline
cmdline;

/*

* Acorn specific

*/

struct tag_acorn
acorn;

/*

* DC21285 specific

*/

struct tag_memclk
memclk;

} 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库
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: