返回列表 发帖

[站长原创] 移植内核必备知识-关于processor id和machine type id的匹配

[站长原创] 移植内核必备知识-关于processor id和machine type id的匹配

移植内核必备知识-关于processor id和machine type id的匹配


嵌入式开发联盟

www.mcuos.com

Osboy 站长原创

QQ:82475491

Mcuos.com@gmail.com


Q:移植内核的时候发现是不是经常看到串口输出“Uncompressing Linux...done, booting the kernel.”然后就什么都没有啦?


遇到这种问题在linux2.6的做法是:


(1)有条件的可以用ICE去调试下看看程序有没有执行到start_kernel函数?
(2)没有条件的只能确保自己的串口移植没有任何问题,然后start_kernel加打印信息。


以上两种做法是确保程序到底有没有执行到Linux内核的第一个c函数start_kernel函数中,如果没有那么多半是processor id和machine type id的匹配的问题。

(1)processor id的匹配,我们在2.3章讲解过,就不在累述,一般出现这个的问题是,在移植的时候没有选择正确的proc-xxx.S架构支持文件。请检查文件:

arch/arm/kconfig文件中:

  1. config ARCH_S3C64XX
  2.         bool "Samsung S3C64XX"
  3.         select PLAT_SAMSUNG
  4.         select CPU_V6
  5.         select ARM_VIC
  6.         select HAVE_CLK
  7.         select NO_IOPORT
  8.         select ARCH_USES_GETTIMEOFFSET
  9.         select ARCH_HAS_CPUFREQ
复制代码

针对你的CPU有选择正确的

select CPU_V6架构。


(2)machine type id的匹配


在linux2.6的内核中,machine id的匹配是通过uboot中传参数到linux内核中,然后和自己在

mach-types文件中指定的machine id相匹配,这个版本的内核做这个匹配工作是在head.S中,但是在linux3.0以后的内核则从head.S中移除。具体原因:
* We're trying to keep crap to a minimum; DO NOT add any machine specific * crap here - that's what the boot loader (or in extreme, well justified * circumstances, zImage) is for.这个是head.S中一段注释,看看不要加太多的crap在这个文件中,大侠们认为在head.S中添加machine specific的东西是crap :)
那么linux3.0如何做这个匹配的呢?似乎在这个版本中对这个id的匹配要求的不是那么严格了。
  1.         mdesc = setup_machine_fdt(__atags_pointer);
  2.         early_printk("------------setup_machine_fdt return %d------------\n", mdesc);
  3.         if (!mdesc)
  4.                 mdesc = setup_machine_tags(machine_arch_type);
  5.         machine_desc = mdesc;
  6.         machine_name = mdesc->name;
复制代码

setup_machine_fdt,是和uboot传给linux的machine id做匹配,如果找不到匹配的id的话,可以通过setup_machine_tags函数来找到mdesc指针,这个函数似乎永远能够找到machine id号,只要你在mach-types文件中定义了自己的machine-id,我测试过随便修改个machine id,程序总能够找到正确的mdesc,这点不像是linux2.6,linux2.6的内核如果匹配不到的话程序都走不下去,产生错误了。
下面对这个函数具体的研究下:
首先我们必须知道,在mach-type.h中,有定义如下:
  1. #ifdef CONFIG_MACH_MCUOS6410
  2. # ifdef machine_arch_type
  3. #  undef machine_arch_type
  4. #  define machine_arch_type        __machine_arch_type
  5. # else
  6. #  define machine_arch_type        MACH_TYPE_MCUOS6410
  7. # endif
  8. # define machine_is_mcuos6410()        (machine_arch_type == MACH_TYPE_MCUOS6410)
  9. #else
  10. # define machine_is_mcuos6410()        (0)
  11. #endif
复制代码


而我们在调用setup_machine_tags 函数的时候形式为:

  1. mdesc = setup_machine_tags(machine_arch_type);
复制代码


所以此时传进去的machine_arch_type 就等于我的板子的machine ID。下面我们来看具体的这个函数:


static struct machine_desc * __init setup_machine_tags(unsigned int nr)
{

struct tag *tags = (struct tag *)&init_tags;

struct machine_desc *mdesc = NULL, *p;

char *from = default_command_line;


init_tags.mem.start = PHYS_OFFSET;


/*

* locate machine in the list of supported machines.

*/

for_each_machine_desc(p)

if (nr == p->nr) {

printk("Machine: %s\n", p->name);

mdesc = p;

break;

}


  1. #define for_each_machine_desc(p)                        \
  2.         for (p = __arch_info_begin; p < __arch_info_end; p++)
复制代码


根据
for_each_machine_desc(p) 的定义,我们知道在__arch_info_begin__arch_info_end之间是.arch.info.init段,而我们的驱动中是把__mach_desc_MCUOS6410结构体放在这个段中,p也就是__mach_desc_MCUOS6410 结构体的指针,所以从p->nr == MACH_TYPE_MCUOS6410 ,由上面的定义define machine_arch_type        MACH_TYPE_MCUOS6410 可以知道,似乎是100%能够匹配的到machine id在3.0的内核中。

if (!mdesc) {

early_print("\nError: unrecognized/unsupported machine ID"

" (r1 = 0x%08x).\n\n", nr);

dump_machine_table(); /* does not return */

}


if (__atags_pointer)

tags = phys_to_virt(__atags_pointer);

else if (mdesc->boot_params) {//我们其实已经定义了.boot_params= S3C64XX_PA_SDRAM + 0x100,#define S3C64XX_PA_SDRAM (0x50000000),我们知道ok6410的起始物理地址为:
0x50000000 ,所以我们是在起始地址的0x100便宜处存放的是boot参数。
#ifdef CONFIG_MMU

/*

* We still are executing with a minimal MMU mapping created

* with the presumption that the machine default for this

* is located in the first MB of RAM.  Anything else will

* fault and silently hang the kernel at this point.

*/

if (mdesc->boot_params < PHYS_OFFSET ||

    mdesc->boot_params >= PHYS_OFFSET + SZ_1M) {//在这里
PHYS_OFFSET = 0x50000000

printk(KERN_WARNING

       "Default boot params at physical 0x%08lx out of reach\n",

       mdesc->boot_params);

} else
#endif

{

tags = phys_to_virt(mdesc->boot_params);//把
0x50000100物理地址转化成虚拟地址。

}

}

#if defined(CONFIG_DEPRECATED_PARAM_STRUCT)

/*

* If we have the old style parameters, convert them to

* a tag list.

*/

if (tags->hdr.tag != ATAG_CORE)

convert_to_tag_list(tags);
#endif


if (tags->hdr.tag != ATAG_CORE) {
#if defined(CONFIG_OF)

/*

* If CONFIG_OF is set, then assume this is a reasonably

* modern system that should pass boot parameters

*/

early_print("Warning: Neither atags nor dtb found\n");
#endif

tags = (struct tag *)&init_tags;

}


if (mdesc->fixup)

mdesc->fixup(mdesc, tags, &from, &meminfo);


if (tags->hdr.tag == ATAG_CORE) {

if (meminfo.nr_banks != 0)

squash_mem_tags(tags);

save_atags(tags);

parse_tags(tags);

}

//上面的代码就是读出一些boot参数。
/* parse_early_param needs a boot_command_line */

strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);


return mdesc;
}

分享到: QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友

返回列表
网页右侧QQ悬浮滚动在线客服
网页右侧QQ悬浮滚动在线客服