linux内核移植s3c2410,移植正式开始1

在前面的准备工作完成之后,先实验一下,谈不上真正的移植 ,因为代码都没有改的。

首先修改顶层的Makefile,修改ARCH,CROSS_COMPLIE变量。

#ARCH        ?= $(SUBARCH)
ARCH        ?= arm
CROSS_COMPILE    ?= arm-linux-

执行make smdk2410_defconfig

make

然后执行make uImage,注意需要含有mkimage工具,这个工具是在编译uboot时产生的,同时需要将mkimage拷贝到path

环境变量中。

最终在arch/arm/boot/目录下生成uImage文件,下载该文件到开发板中,既可以观察结果,当然此时是没有文件系统的支持,

内核肯定是启动不起来的。

为了开始内核代码的移植,首先必须得了解内核的启动过程。

内核最先执行的代码是在arch/arm/kernel/head.S文件,该文件只需要关注下面的一段代码:

.section ".text.head", "ax"
    .type    stext, %function
ENTRY(stext)
    msr    cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
                        @ and irqs disabled
    mrc    p15, 0, r9, c0, c0        @ get processor id
    bl    __lookup_processor_type        @ r5=procinfo r9=cpuid
    movs    r10, r5                @ invalid processor (r5=0)?
    beq    __error_p            @ yes, error 'p'
    bl    __lookup_machine_type        @ r5=machinfo
    movs    r8, r5                @ invalid machine (r5=0)?
    beq    __error_a            @ yes, error 'a'
    bl    __create_page_tables
上面的代码首先设置特权模式,然后关闭中断,读取cpu的id,然后调用函数lookup_processor_typ来产看内核是否支持当前的

cpu,接着调用函数lookup_machine_type来查看内核是否支持当前的开发板,如果上面的两个函数调用中有一个函数返回0,

那么内核无法启动。

函数__lookup_processor_type和函数 __lookup_machine_type都是在文件arch/arm/kernel/head-common.S中定义:

__lookup_processor_type:

/*
 * Read processor ID register (CP#15, CR0), and look up in the linker-built
 * supported processor list.  Note that we can't use the absolute addresses
 * for the __proc_info lists since we aren't running with the MMU on
 * (and therefore, we are not in the correct address space).  We have to
 * calculate the offset.
 *
 *    r9 = cpuid
 * Returns:
 *    r3, r4, r6 corrupted
 *    r5 = proc_info pointer in physical address space
 *    r9 = cpuid (preserved)
 */
    .type    __lookup_processor_type, %function
__lookup_processor_type:
    adr    r3, 3f
    ldmda    r3, {r5 - r7}
    sub    r3, r3, r7            @ get offset between virt&phys
    add    r5, r5, r3            @ convert virt addresses to
    add    r6, r6, r3            @ physical address space
1:    ldmia    r5, {r3, r4}            @ value, mask
    and    r4, r4, r9            @ mask wanted bits
    teq    r3, r4
    beq    2f
    add    r5, r5, #PROC_INFO_SZ        @ sizeof(proc_info_list)
    cmp    r5, r6
    blo    1b
    mov    r5, #0                @ unknown processor
2:    mov    pc, lr

这个函数在kernel支持的processor list处理器链表中查找当前的处理器类型,如果找不到的话,函数返回0。上面的函数使用

了结构体proc_info_list,该结构题定义在include/asm-arm/procinfo.c文件中,定义如下:

/*
 * Note!  struct processor is always defined if we're
 * using MULTI_CPU, otherwise this entry is unused,
 * but still exists.
 * 如果是使用的MULTI_CPU,才使用这个结构体,否则是不使用这个结构体的
 * NOTE! The following structure is defined by assembly
 * language, NOT C code.  For more information, check:
 *  arch/arm/mm/proc-*.S and arch/arm/kernel/head.S
 */

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:

__arm920_proc_info:
    .long    0x41009200
    .long    0xff00fff0

不同的proc_info_list被用来支持不同的cpu,最后在arch/arm/kernel/vmlinux.lds连接脚本中:

 __proc_info_begin = .;
   *(.proc.info.init)
  __proc_info_end = .;

不同的proc_info_list结构被用来支持不同的cpu,他们是定义在proc.info.init中,最终自己俄些结构体被组织起来,开始地址是

 __proc_info_begin,结束地址是 __proc_info_end。

在看函数 __lookup_machine_type,函数定义:

/*
 * Lookup machine architecture in the linker-build list of architectures.
 * Note that we can't use the absolute addresses for the __arch_info
 * lists since we aren't running with the MMU on (and therefore, we are
 * not in the correct address space).  We have to calculate the offset.
 *
 *  r1 = machine architecture number
 * Returns:
 *  r3, r4, r6 corrupted
 *  r5 = mach_info pointer in physical address space
 */
    .type    __lookup_machine_type, %function
__lookup_machine_type:
    adr    r3, 3b
    ldmia    r3, {r4, r5, r6}
    sub    r3, r3, r4            @ get offset between virt&phys
    add    r5, r5, r3            @ convert virt addresses to
    add    r6, r6, r3            @ physical address space
1:    ldr    r3, [r5, #MACHINFO_TYPE]    @ get machine type
    teq    r3, r1                @ matches loader number?
    beq    2f                @ found
    add    r5, r5, #SIZEOF_MACHINE_DESC    @ next machine_desc
    cmp    r5, r6
    blo    1b
    mov    r5, #0                @ unknown machine
2:    mov    pc, lr
上面的函数使用到了结构体machine_desc,那么该结构定义在那里呢?

被和中对于每种支持的开发板都会使用宏来定义一个上面的结构machine_desc,在其中定义了有一些于开发板相关的属性和

函数。在arch/arm/mach-s3c2410/mach-smdk2410.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

上面的MACHINE_START和MACHINE_END是两个宏定义在include/asm-arm/mach/arch.h中:

/*
 * Set of macros to define architecture features.  This is built into
 * a table by the linker.
 */
#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/kernel/vmlinux.lds:

  __arch_info_begin = .;
   *(.arch.info.init)
  __arch_info_end = .;

通过上面的连接文件最终将上面的信息连接到vmlinux中。

内核太庞大了,好像偏离了内核启动很长时间了,下面继续开始启动内核:

如果上面的两个函数都能够成功的启动的话,那么接下来内核开始建立页表:

    bl    __create_page_tables

MMU有效:

    adr    lr, __enable_mmu        @ return (PIC) address

最终调用函数start_kernel经如kernel启动的跌入个阶段。

你可能感兴趣的:(linux)