linux内核机器码不一致,uboot和linux机器码分析

在u-boot和kernel中都会有一个机器码(即:MACH_TYPE),只有这两个机器码一致时才能引导内核,否则就会出现如下mach的错误信息:

Error: unrecognized/unsupported machine ID (r1 = 0x0000270f).

Available machine support:

ID (hex)   NAME

0000016a SMDK2440

Please check your kernel config and/or bootloader.

这是因为在uboot中的机器码是0x0000270f,即9999,跟linux内核机器码不一致造成的。下面我们来查看一下uboot的机器码:

a.打开uboot目录下的board/GT2440/GT2440.c文件,找到如下语句:

gd->bd->bi_arch_number = MACH_TYPE_GT2440;

这里的MACH_TYPE_GT2440就是uboot的机器码,我们查看一下这个码值。

b.打开uboot目录下的include/asm-arm/mach_types.h文件,在头文件里面找到:

#define MACH_TYPE_GT2440  9999

下面我们对uboot和linux内核的机器码作更改使其保持一致。

1.打开uboot目录下的board/GT2440/GT2440.c文件,将“gd->bd->bi_arch_number = MACH_TYPE_GT2440;”更改为“gd->bd->bi_arch_number = MACH_TYPE_S3C2440;”,此处的机器码值为362;

2.打开linux内核目录下的arch/arm/mach-s3c2440/mach_smdk2440.c文件,将其“MACHINE_START(S3C2440, "SMDK2440")”中的第一项改为与uboot码值对应的宏,在这里是S3C2440。

经过上述更改,重新编译后运行就不再出现机器码不匹配的问题了。

玩过或者移植过arm-linux的都应该知道在/arch/arm目录下有许多与具体处理器相关的目录,当然对于s3c2440的话所对应的目录就是 arch/arm/mach-s3c2440/,在里面找到与具体板子相关的文件mach-mini2440.c,这个文件大部分内容是对平台设备(例如串口,LCD,Nand falsh等)的结构体初始化,在这个文件的最后有一个非常重要的宏:

MACHINE_START(MINI2440, "MINI2440")

/* Maintainer: Michel Pollet  */

.atag_offset = 0x100,

.map_io = mini2440_map_io,

.init_machine = mini2440_init,

.init_irq = s3c24xx_init_irq,

.timer = &s3c24xx_timer,

.restart = s3c244x_restart,

MACHINE_END

MINI2440这个宏在/arch/arm/tools/mach-types文件里定义:

mini2440 MACH_MINI2440 MINI2440 1999

MACHINE_START 的定义在arch/arm/include/asm/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 \

};

就是定义了一个struct machine_desc类型结构体变量,这个结构体还定义了其他一些成员,接下来着重关注.init_machine这个成员,它是一个函数指针,值为mini2440_init,这个函数也在mach-mini2440.c中定义。内这个结构体变量在哪里被调用,从而调用它里面的成员和成员函数呢?先来看 arch/arm/kernel/setup.c 里面的setup_arch()函数:

void __init setup_arch(char **cmdline_p)

{

struct machine_desc *mdesc;

setup_processor();

mdesc = setup_machine_fdt(__atags_pointer);

if (!mdesc)

mdesc = setup_machine_tags(machine_arch_type);

machine_desc = mdesc;

machine_name = mdesc->name

...........

...........

这个函数在 init/main.c 的start_kernel()函数里被调用。看到第10行, 这里的setup_machine()函数的作用就是找到我们想要的struct machine_desc类型的变量,也就是在mach-mini2440.c里定义那个变量。函数的参数machine_arch_type的值是什么呢?继续看:include/generated/mach-types.h

#ifdef CONFIG_ARCH_S3C2440

# ifdef machine_arch_type

# undef machine_arch_type

# define machine_arch_type __machine_arch_type

# else

# define machine_arch_type MACH_TYPE_S3C2440

# endif

# define machine_is_s3c2440() (machine_arch_type == MACH_TYPE_S3C2440)

#else

# define machine_is_s3c2440() (0)

#endif

#define MACH_TYPE_S3C2440              362

也就是说参数 machine_arch_type的值为362。在setup_machine()函数里主要调用了lookup_machine_type()函数来查找对应的type,应该是出于效率的原因,这个函数是通过汇编实现的,在此就不给出具体代码了。

到这里,知道了在/init/main.c的start_kernel()函数里调用了setup_arch(),在setup_arch()里找到了具体的struct machine_desc类型的变量,但是在哪里通过这个变量调用里面的成员或成员函数的呢?继续找。还是在setup.c里,看到了这样一个函数:

static int __init customize_machine(void)

{

/* customizes platform devices, or adds new ones */

if (machine_desc->init_machine)

machine_desc->init_machine();

return 0;

}

arch_initcall(customize_machine);

#define arch_initcall(fn) __define_initcall("3",fn,3)

__initcall_start = .;

*(.initcallearly.init) __early_initcall_end = .;

*(.initcall0.init) *(.initcall0s.init)

*(.initcall1.init) *(.initcall1s.init)

*(.initcall2.init) *(.initcall2s.init)

*(.initcall3.init) *(.initcall3s.init)

*(.initcall4.init) *(.initcall4s.init)

*(.initcall5.init) *(.initcall5s.init)

*(.initcallrootfs.init)

*(.initcall6.init) *(.initcall6s.init)

*(.initcall7.init) *(.initcall7s.init)

__initcall_end = .;

成员函数init_machine就是在这里被调用的。但是它没有被显式调用,而是放在了arch_initcall这个宏里,它被链接到了.initcall段里,现在简单看看 arch/arm/kernel/vmlinux.lds这个链接脚本里关于initcall的定义:可以看到customize_machine()被放到了.initcall3.init里。说了那么多定义,究竟它在哪里被调用啊?好吧,它是在/init/main.c里一个叫do_initcalls()的函数里被调用,去看看呗:

extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];

static void __init do_initcalls(void)

{

initcall_t *fn;

for (fn = __early_initcall_end; fn 

do_one_initcall(*fn);

}

看到第1行,很熟悉吧。在for循环里依次调用了从__early_initcall_end开始到__initcall_end结束的所有函数。customize_machine()也是在其间被调用。

好了,到这里差不多该结束了,最后总结一下这些函数调用顺序:

start_kernel()--->setup_arch()--->do_initcalls()--->customize_machine()--->mini2440_init()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值