intel xscale PXA270 porting :unsupported machine ID大杂烩

时间:2022-03-26 17:23:47

关于这一类的问题,不同的平台可能它的代码出处不一样,但大体结构是一样的。

一、Details

输出现下面的一行打印后,就再也没有输出信息,


Uncompressing Linux... done, booting the kernel.//如果没有打开kernel的DEBUG_LL选项,就会hang在这,没有下面的信息,所以一般在调试阶段我们会打开这个项


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


Available machine support:


ID (hex)        NAME
00000d32        Xilinx Zynq Platform

Please check your kernel config and/or bootloader.



之前也一曾经遇到家过类似的现象,但大多和是由于uart没有配好的原因,这次发现是由于bootloader传给kernel的machine ID不相等的原因。
如代码如下:
arch/arm/boot/compressed/misc.c
ulg
decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p,
 int arch_id)
{
output_data = (uch *)output_start; /* Points to kernel start */
free_mem_ptr = free_mem_ptr_p;
free_mem_ptr_end= free_mem_ptr_end_p;
__machine_arch_type= arch_id;
arch_decomp_setup();
makecrc();
putstr("Uncompressing Linux...");
gunzip();
putstr(" done, booting the kernel.\n");
return output_ptr;
}


在上面的函数解压完kernel后,就会退出,这时是没有问题的。在退回到arch/arm/boot/compressed/head.s后,最终会执行下面的一段汇编:

call_cache_fn: adrr12, proc_types
#ifdef CONFIG_CPU_CP15
mrc p15, 0, r6, c0, c0@ get processor ID //获取CPU的ID号到ARM寄存器R6里面
#else
ldr r6, =CONFIG_PROCESSOR_ID
#endif
1: ldr r1, [r12, #0] @ get value
ldr r2, [r12, #4]@ get mask
eor r1, r1, r6@ (real ^ match)
tst r1, r2@       & mask
addeq pc, r12, r3@ call cache function
add r12, r12, #4*5
b 1b  //不相等则再找下一个。

关于如何修改machine ID在网上很多,在这就不说了。

如果不改uboot,只改kernel,下面的在个文件,只要改动一个就可以了。


include/asm-arm/mach-types.h---------一般是在这个文件中改动,找到相应板子的定义,直接改成uboot转过来的ID值就可以了。在3.X的版本后,它的地址变了是在include/generated/下,不过你也可以用find . -name "mach-types*" -ls来找。

arch/arm/tools/mach-types

arch/arm/kernel/head.s

对于uboot所支持的各种machine_id是定义在arch/arm/include/asm/mach-types.h下。

二、uboot how to pass machine id 

在2014.1版本的uboot,引导linux的函数是int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images),在这里会读取之machine ID,同时传给kernel

如:

static void boot_jump_linux(bootm_headers_t *images, int flag)
{
#ifdef CONFIG_ARM64
	void (*kernel_entry)(void *fdt_addr);
	int fake = (flag & BOOTM_STATE_OS_FAKE_GO);

	kernel_entry = (void (*)(void *fdt_addr))images->ep;

	debug("## Transferring control to Linux (at address %lx)...\n",
		(ulong) kernel_entry);
	bootstage_mark(BOOTSTAGE_ID_RUN_OS);

	announce_and_cleanup(fake);

	if (!fake)
		kernel_entry(images->ft_addr);
#else

unsigned long machid = gd->bd->bi_arch_number;//从gd中读取之前在board_init中初始化过的ID,不同的平台,可能初始化位置不一样。

char *s; void (*kernel_entry)(int zero, int arch, uint params); unsigned long r2; int fake = (flag & BOOTM_STATE_OS_FAKE_GO); kernel_entry = (void (*)(int, int, uint))images->ep;//函数指针指向内核映像的入口地址

s = getenv("machid");//这里设备ID号可以从环境变量中获得!如果环境变量中有,就会覆盖之前赋值过的设备ID(最终通过r1传递给内核)。

if (s) { strict_strtoul(s, 16, &machid); printf("Using machid 0x%lx from environment\n", machid); } debug("## Transferring control to Linux (at address %08lx)" \ "...\n", (ulong) kernel_entry); bootstage_mark(BOOTSTAGE_ID_RUN_OS); announce_and_cleanup(fake); if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) r2 = (unsigned long)images->ft_addr; else r2 = gd->bd->bi_boot_params; if (!fake) kernel_entry(0, machid, r2);//跳入内核入口地址:r1=0、r1=machid、r2=启动参数指针
#endif
}

对于arm平台,gd定义是在global_data.c中完成的:
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r9")

这个声明告诉编译器使用寄存器r8来存储gd_t类型的指针gd,即这个定义声明了一个指针,并且指明了它的存储位置。

register表示变量放在机器的寄存器
volatile用于指定变量的值可以由外部过程异步修改
并且这个指针在start_armboot()(board.c)中被初始化:
    /* Pointer is writable since we allocated a register for it */
    gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
这样,gd就指向的一个可用的内存地址了。

Note:

如果kernel是用go命令来引导,这时转给kernel的参数格式是不对的,从r1中读取到的machine Id是一个argv的地址,对于这种情况,一般是在head.s中加强制给r1赋值。同时要注意,当ID的值大于0x100时,最好用ldr指令,不要用mov,因为对于ARM指令中的立即数是循环右移偶数位的,具体原因可以看一下ARM指令关于立即数的说明。给一个网址,可以看下外外的说法:http://*.com/questions/10261300/invalid-constant-after-fixup

三、kernel how to get ID

waiting .................