Arm linux 内核移植及系统初始化过程分析

发布时间:2024-11-21

第四届云计算大会门票抢购:史上最低价,每日限5张! 【分享季1】:网友推荐130个经典资源,分享再赠分!

Arm linux 内核移植及系统初始化过程分析

分类: Linux2011-03-25 14:48282人阅读评论(0)收藏举报

================================================================ 浅谈分析Arm linux 内核移植及系统初始化的过程(一)

================================================================

学习嵌入式ARM linux,主要想必三个方向发展:

1、嵌入式linux应用软件开发

2、linux内核的剪裁和移植

3、嵌入式linux底层驱动的开发

本文就Arm linux 内核移植及系统初始化过程进行分析:咨询QQ:313807838

主要介绍内核移植过程中涉及文件的分布及其用途,以及简单介绍系统的初始化过程。整个arm linux内核的启动可分为三个阶段:第一阶段主要是进行cpu和体系结构的检查、cpu本身的初始化以及页表的建立等;第二阶段主要是对系统中的一些基础设施进行初始化;最后则是更高层次的初始化,如根设备和外部设备的初始化。了解系统的初始化过程,有益于更好地移植内核。

1. 内核移植

2. 涉及文件分布介绍

2.1. 内核移植

2.2. 涉及的头文件

/linux-2.6.18.8/include

[root@localhost include]# tree -L 1

.

|-- Kbuild

|-- acpi

|-- asm -> asm-arm

|-- asm-arm ------------------------------->(1)

|-- asm-sparc

|-- asm-sparc64

|-- config

|-- keys

|-- linux ------------------------------->(2)

|-- math-emu

|-- media

|-- mtd

|-- net

|-- pcmcia

|-- rdma

|-- rxrpc

|-- scsi

|-- sound

`-- video

内核移植过程中涉及到的头文件包括处理器相关的头文件(1)和处理器无关的头文件(2)。

2.3. 内核移植2.4. 涉及的源文件

/linux-2.6.18.8/arch/arm

[root@localhost arm]# tree -L 1

.

|-- Kconfig

|-- Kconfig-nommu

|-- Kconfig.debug

|-- Makefile

|-- boot ------------------------------->(2)

|-- common

|-- configs

|-- kernel ------------------------------->(3)

|-- lib

|-- mach-at91rm9200

……

|-- mach-omap2

|-- mach-realview

|-- mach-rpc

|-- mach-s3c2410 ------------------------------->(4)

|-- mach-sa1100

|-- mach-versatile

|-- mm ------------------------------->(5)

|-- nwfpe

|-- oprofile

|-- plat-omap

|-- tools ------------------------------->(1)

`-- vfp

(1)

/linux-2.6.18.8/arch/arm/tools

[root@localhost tools]# tree -L 1

.

|-- Makefile

|-- gen-mach-types

`-- mach-types

Mach-types 文件定义了不同系统平台的系统平台号。移植linux内核到新的平台上需要对新的平台登记系统平台号。

Mach-types文件格式如下:

# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number

s3c2410 ARCH_S3C2410 S3C2410 182

smdk2410 ARCH_SMDK2410 SMDK2410 193

之所以需要这些信息,是因为脚本文件linux/arch/arm/tools/gen-mach-types需要

linux/arch/tools/mach-types来产生linux/include/asm-arm/mach-types.h文件,该文件中设置了一些宏定义,需要这些宏定义来为目标系统选择合适的代码。

(2)

linux-2.6.18.8/arch/arm/boot/compressed

[root@localhost compressed]# tree -L 1

.

|-- Makefile

|-- Makefile.debug

|-- big-endian.S

|-- head-at91rm9200.S

2 浅谈分析Arm linux 内核移植及系统初始化的过程

|-- head.S

|-- ll_char_wr.S

|-- misc.c

|-- ofw-shark.c

|-- piggy.S

`-- vmlinux.lds.in

Head.s 是内核映像的入口代码,是自引导程序。自引导程序包含一些初始化程序,这些程序都是体系结构相关的。在对系统作完初始化设置工作后,调用misc.c文件中的

decompress_kernel()函数解压缩内核映像到指定的位置,然后跳转到kernel的入口地址。

Vmlinux.lds.in用来生成内核映像的内存配置文件。

(3)

linux-2.6.18.8/arch/arm/kernel

[root@localhost kernel]# tree -L 1

.

|-- Makefile

|-- apm.c

|-- armksyms.c

|-- arthur.c

|-- asm-offsets.c

|-- bios32.c

|-- calls.S

|-- dma.c

|-- ecard.c

|-- entry-armv.S

|-- entry-common.S

|-- entry-header.S

|-- fiq.c

|-- head-common.S

|-- head-nommu.S

|-- head.S

|-- init_task.c

|-- io.c

|-- irq.c

|-- isa.c

|-- module.c

|-- process.c

|-- ptrace.c

|-- ptrace.h

|-- semaphore.c

|-- setup.c

|-- smp.c

|-- sys_arm.c

|-- time.c

|-- traps.c

`-- vmlinux.lds.S

内核入口处也是由一段汇编语言实现的,由head.s和head-common.s两个文件组成。 Head.s 是内核的入口文件, 在head.s的末尾处 #i nclude "head-common.S"。 经过一系列的初始化后,跳转到linux-2.6.18.8/init/main.c中的start_kernel()函数中,开始内核的基本初始化过程。

/linux-2.6.18.8/init

[root@localhost init]# tree

.

|-- Kconfig

|-- Makefile

|-- calibrate.c

|-- do_mounts.c

|-- do_mounts_initrd.c

|-- do_mounts_md.c

|-- do_mounts_rd.c

|-- initramfs.c

|-- main.c

`-- version.c

(4)

/linux-2.6.18.8/arch/arm/mach-s3c2410

[root@localhost mach-s3c2410]# tree -L 1

.

|-- Kconfig

|-- Makefile

|-- Makefile.boot

|-- bast-irq.c

|-- bast.h

|-- clock.c

|-- clock.h

|-- common-smdk.c

|-- common-smdk.h

|-- cpu.c

|-- cpu.h

|-- devs.c

|-- devs.h

|-- dma.c

|-- gpio.c

|-- irq.c

|-- irq.h

|-- mach-anubis.c

|-- mach-smdk2410.c

|-- pm-simtec.c

|-- pm.c

|-- pm.h

|-- s3c2400-gpio.c

|-- s3c2410-clock.c

|-- s3c2410-gpio.c

|-- s3c2410.c

|-- s3c2410.h

|-- sleep.S

|-- time.c

|-- usb-simtec.c

`-- usb-simtec.h

这个目录中的文件都是板级相关的,其中比较重要是如下几个:

linux/arch/arm/mach-s3c2410/cpu.c

linux/arch/arm/mach-s3c2410/common-smdk.c

linux/arch/arm/mach-s3c2410/devs.c

linux/arch/arm/mach-s3c2410/mach-smdk2410.c

linux/arch/arm/mach-s3c2410/Makefile.boot

linux/arch/arm/mach-s3c2410/s3c2410.c

3. 处理器和设备4.

这里主要介绍处理器和设备的描述和操作过程。设备描述在

linux/arch/arm/mach-s3c2410/devs.c和linux/arch/arm/mach-s3c2410/common-smdk.c中实现。最后以nand flash为例具体介绍。

================================================================ 浅谈分析Arm linux 内核移植及系统初始化的过程(二)

================================================================ 3 浅谈分析Arm linux 内核移植及系统初始化的过程。咨询QQ:313807838

4.1. 处理器、设备4.2. 描述

设备描述主要两个结构体完成:struct resource和struct platform_device。

先来看看着两个结构体的定义:

struct resource {

resource_size_t start;

resource_size_t end;

const char *name;

unsigned long flags;

struct resource *parent, *sibling, *child;

};

Resource结构体主要是描述了设备在系统中的起止地址、名称、标志以及为了链式描述方便指向本结构体类型的指针。Resource定义的实例将被添加到platform_device结构体对象中去。

struct platform_device {

const char * name;

u32 id;

struct device dev;

u32 num_resources;

struct resource * resource;

};

Platform_device结构体包括结构体的名称、ID号、平台相关的信息、设备的数目以及上面定义的resource信息。Platform_device结构对象将被直接通过设备操作函数注册导系统中去。具体注册和注销过程在下一节介绍。

4.3. 处理器、设备4.4. 操作

(1) int platform_device_register(struct platform_device * pdev); 注册设备

(2) void platform_device_unregister(struct platform_device * pdev); 注销设备

(3) int platform_add_devices(struct platform_device **devs, int num);添加设备,通过调用上面两个函数实现。

4.5. 添加Nand flash设备4.6.

下面以nand flash 设备的描述为例,具体介绍下设备的描述和注册过程。

// resource结构体实例s3c_nand_resource 对nand flash 控制器描述,包括控制器的起止地址和标志。

static struct resource s3c_nand_resource[] = {

[0] = {

.start = S3C2410_PA_NAND,

.end = S3C2410_PA_NAND + S3C24XX_SZ_NAND - 1,

.flags = IORESOURCE_MEM,

}

};

//platform_device结构体实例s3c_device_nand定义了设备的名称、ID号并把resource对象作为其成员之一。

struct platform_device s3c_device_nand = {

.name = "s3c2410-nand",

.id = -1,

.num_resources = ARRAY_SIZE(s3c_nand_resource),

.resource = s3c_nand_resource,

};

// nand flash 的分区情况,由mtd_partition结构体定义。

static struct mtd_partition smdk_default_nand_part[] = {

[0] = {

.name = "Boot Agent",

.size = SZ_16K,

.offset = 0,

},

[1] = {

.name = "S3C2410 flash partition 1",

.offset = 0,

.size = SZ_2M,

},

[2] = {

.name = "S3C2410 flash partition 2",

.offset = SZ_4M,

.size = SZ_4M,

},

[3] = {

.name = "S3C2410 flash partition 3",

.offset = SZ_8M,

.size = SZ_2M,

},

[4] = {

.name = "S3C2410 flash partition 4",

================================================================

浅谈分析Arm linux 内核移植及系统初始化的过程(三)

================================================================

4、浅谈分析Arm linux 内核移植及系统初始化的过程 QQ:313807838

.offset = SZ_1M * 10,

.size = SZ_4M,

},

[5] = {

.name = "S3C2410 flash partition 5",

.offset = SZ_1M * 14,

.size = SZ_1M * 10,

},

[6] = {

.name = "S3C2410 flash partition 6",

.offset = SZ_1M * 24,

.size = SZ_1M * 24,

},

[7] = {

.name = "S3C2410 flash partition 7",

.offset = SZ_1M * 48,

.size = SZ_16M,

}

};

static struct s3c2410_nand_set smdk_nand_sets[] = {

[0] = {

.name = "NAND",

.nr_chips = 1,

.nr_partitions = ARRAY_SIZE(smdk_default_nand_part),

.partitions = smdk_default_nand_part,

},

};

/* choose a set of timings which should suit most 512Mbit

* chips and beyond.

*/

static struct s3c2410_platform_nand smdk_nand_info = {

.tacls = 20,

.twrph0 = 60,

.twrph1 = 20,

.nr_sets = ARRAY_SIZE(smdk_nand_sets),

.sets = smdk_nand_sets,

};

/* devices we initialise */

// 最后将nand flash 设备加入到系统即将注册的设备集合中。

static struct platform_device __initdata *smdk_devs[] = {

&s3c_device_nand,

&smdk_led4,

&smdk_led5,

&smdk_led6,

&smdk_led7,

};

然后通过smdk_machine_init()函数,调用设备添加函数platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs)) 完成设备的注册。具体过程参见系统初始化的相关部分。

5. 系统初始化

5.1. 系统初始化的主干线

Start_kernel() èsetup_arch() èreset_init() è kernel_thread(init …) è init() è

do_basic_setup() èdriver_init() è do_initcall()

Start_kernel()函数负责初始化内核各个子系统,最后调用reset_init(),启动一个叫做init的内核线程,继续初始化。Start_kernel()函数在init/main.c中实现。

asmlinkage void __init start_kernel(void)

{

char * command_line;

extern struct kernel_param __start___param[], __stop___param[];

smp_setup_processor_id();

/*

* Need to run as early as possible, to initialize the

* lockdep hash:

*/

lockdep_init();

local_irq_disable();

early_boot_irqs_off();

early_init_irq_lock_class();

/*

* Interrupts are still disabled. Do necessary setups, then

* enable them

*/

lock_kernel();

boot_cpu_init();

page_address_init();

printk(KERN_NOTICE);

printk(linux_banner);

setup_arch(&command_line);

//setup processor and machine and destinate some pointers for do_initcalls() s

5、浅谈分析Arm linux 内核移植及系统初始化的过程 咨询QQ:313807838

// for example init_machine pointer is initialized with smdk_machine_init() , and

//init_machine() is called by customize_machine(), and the is processed by

//arch_initcall(fn). Therefore smdk_machine_init() is issured. by edwin

setup_per_cpu_areas();

smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */

/*

* Set up the scheduler prior starting any interrupts (such as the

* timer interrupt). Full topology setup happens at smp_init()

* time - but meanwhile we still have a ing scheduler.

*/

sched_init();

/*

* Disable preemption - early bootup scheduling is extremely

* fragile until we cpu_idle() for the first time.

*/

preempt_disable();

build_all_zonelists();

page_alloc_init();

printk(KERN_NOTICE "Kernel command line: %s/n", saved_command_line);

parse_early_param();

parse_args("Booting kernel", command_line, __start___param,

__stop___param - __start___param,

&unknown_bootoption);

sort_main_extable();

unwind_init();

trap_init();

rcu_init();

init_IRQ();

pidhash_init();

init_timers();

hrtimers_init();

softirq_init();

timekeeping_init();

time_init();

profile_init();

if (!irqs_disabled())

printk("start_kernel(): bug: interrupts were enabled early/n");

early_boot_irqs_on();

local_irq_enable();

/*

* HACK ALERT! This is early. We're enabling the console before

* we've done PCI setups etc, and console_init() must be aware of

* this. But we do want output early, in case something goes wrong.

*/

console_init();

if (panic_later)

panic(panic_later, panic_param);

lockdep_info();

/*

* Need to run this when irqs are enabled, because it wants

* to self-test [hard/soft]-irqs on/off lock inversion bugs

* too:

*/

locking_selftest();

#ifdef CONFIG_BLK_DEV_INITRD

if (initrd_start && !initrd_below_start_ok &&

initrd_start < min_low_pfn << PAGE_SHIFT) {

printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "

6、浅谈分析Arm linux 内核移植及系统初始化的过程 咨询QQ:313807838

"disabling it./n",initrd_start,min_low_pfn << PAGE_SHIFT);

initrd_start = 0;

}

#endif

vfs_caches_init_early();

cpuset_init_early();

mem_init();

kmem_cache_init();

setup_per_cpu_pageset();

numa_policy_init();

if (late_time_init)

late_time_init();

calibrate_delay();

pidmap_init();

pgtable_cache_init();

prio_tree_init();

anon_vma_init();

#ifdef CONFIG_X86

if (efi_enabled)

efi_enter_virtual_mode();

#endif

fork_init(num_physpages);

proc_caches_init();

buffer_init();

unnamed_dev_init();

key_init();

security_init();

vfs_caches_init(num_physpages);

radix_tree_init();

signals_init();

/* rootfs populating might need page-writeback */

page_writeback_init();

#ifdef CONFIG_PROC_FS

proc_root_init();

#endif

cpuset_init();

taskstats_init_early();

delayacct_init();

check_bugs();

acpi_early_init(); /* before LAPIC and SMP init */

/* Do the rest non-__init'ed, we're now alive */

rest_init();

}

分析start_kernel()源码, 其中setup_arch() 和 reset_init()是两个比较关键的函数。下面将具体分析这两个函数。

5.2. setup_arch()函数分析

首先我们来分析下setup_arch()函数。

Setup_arch()函数主要工作是安装cpu和machine,并为start_kernel()后面的初始化函数指针指定值。

其中setup_processor()函数调用linux/arch/arm/kernel/head_common.S 中的

lookup_processor_type函数查询处理器的型号并安装。

Setup_machine()函数调用inux/arch/arm/kernel/head_common.S 中的

lookup_machine_type(__machine_arch_type)函数根据体系结构号__machine_arch_type,在__arch_info_begin和__arch_info_end段空间查询体系结构。问题是

__machine_arch_type是在什么时候赋的初值?__arch_info_begin和__arch_info_end段空间到底放的是什么内容?

__machine_arch_type是一个全局变量,在linux/boot/decompress/misc.c的解压缩函数中得以赋值。

decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p, int arch_id)

{

__machine_arch_type = arch_id;

}

__arch_info_begin和__arch_info_end段空间到底放的内容由链接器决定,存放

是http://.init段的内容。这个段是通过段属性__attribute__指定的。Grep一

下http://.init 得到./include/asm/mach/arch.h:53:

__attribute__((__section__("http://.init"))) = { / 在linux/include/asm-arm/mach/arch.h

Arm linux 内核移植及系统初始化过程分析.doc 将本文的Word文档下载到电脑

    精彩图片

    热门精选

    大家正在看

    × 游客快捷下载通道(下载后可以自由复制和排版)

    限时特价:7 元/份 原价:20元

    支付方式:

    开通VIP包月会员 特价:29元/月

    注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
    微信:fanwen365 QQ:370150219