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库
************************
内核中要查找处理器相关,通过_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
- jz2440 kernel 移植(启动代码分析)
- jz2440 uboot 移植(顶层Makefile分析)
- 移植u-boot-2012.04.01到jz2440开发板之修改代码支持NAND启动
- 关于linux kernel及文件系统在jz2440的移植
- 学习嵌入式Linux-JZ2440-启动过程分析
- JZ2440 Uboot 启动过程分析续
- ucOS_II移植:Stm32启动代码分析
- jz2440 uboot移植(norflash部分)
- jz2440 uboot移植(nand部分)
- 移植u-boot12.04到jz2440 -->支持nandflash启动
- JZ2440 编译 kernel
- kernel的启动流程分析(未完)
- 嵌入式Linux之Kernel(裁减移植)启动调试技术
- linux kernel 启动分析
- uboot配置分析(jz2440开发板)
- JZ2440 start.S 分析1(arm920t)
- 嵌入式 Linux开发Kernel移植(三)——Kernel工程Makefile分析
- kernel移植之linux stage2:启动内核
- Debugg工程的时候出现Unable to Start program 。。。 .dll
- [Win32] Windows Sockets 2笔记(1)在开始之前
- 存储过程批量更新
- c语言代码运行时的内存分布结构
- 50个Sql语句
- jz2440 kernel 移植(启动代码分析)
- MyEclipse 中各种 libraries 的含义
- 如何自己动手实现 KVO
- 网络环境渗透测试简述 & 点评
- 求字符串中数字字符转换成数字之后的总和
- poj 2249/1942 求组合数
- android 自定义Button,满足你对Button呈现样式的一系列要求
- hdu 5389 Zero Escape
- Ubuntu-15.04-64位配置安卓开发环境