内核的移植-从三星官方内核开始移植

一、内核移植初体验

1、三星官方移植版内核获取
三星的SMDKV210开发板附带的光盘资料
android_kernel_2.6.35_smdkv210.tar资源链接:https://www.aliyundrive.com/s/LcCuuGvdjkP

2、构建移植环境
(1)Windows下建立SI工程
(2)ubuntu下解压

3、配置编译下载尝试
(1)检查Makefile中ARCH和CROSS_COMPILE (vi查看搜索:/ARCH)

ARCH		?= arm
CROSS_COMPILE	?= /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-

(2)make xx_defconfig (ls arch/arm/configs 去查看,找一个合适的make smdkv210_android_defconfig)

(3)make menuconfig

(4)make -j4
默认情况下直接make则会直接单线程编译。但是如果make -j4则会4线程编译从而加快编译的速度。

4、后续要做的事情:
(1)编译得到的zImage去烧录运行,看结果
(2)根据结果去分析问题原因,然后去尝试解决这些问题。

二、初步移植以看到启动信息

1、分析问题
(1)根据开发板运行结果,分析串口打印信息发现:linux内核的自解压代码都没有运行(因为没有看到:Uncompressing Linux… done, booting the kernel.)

(2)说明zImage根本没有被解压成功,内核代码根本就没有被运行,当然没有输出信息了。所以问题出在解压相关的部分。

(3)问题出在内核配置的解压后代码放置的内存地址处。

(4)内核配置的解压地址应该等于链接地址,否则自解压之后内核无法运行。现在问题变成:第一,内核的链接地址等于多少?第二,内核中配置的解压地址是多少?

(5)这里面还有个问题:内核的链接地址是一个虚拟地址,而自解压代码解压内核时需要物理地址,因此上面说的等于,链接地址对应的物理地址等于自解压地址。

(6)链接地址和他对应的物理地址在head.S中可以查到,分别是0xC0008000和0x30008000(uboot中的内存配到了30000000-4fffffff, uboot中的分区表要与内核中的相同)。那么自解压代码配置的解压地址应该是30008000.

//head.S
#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)
#define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET)

(7)自解压代码对应的自解压地址在mach-s5pv210/Makefile.boot文件中。在其中修改,加入两行:

#override for SMDKV210
zreladdr-$(CONFIG_MACH_SMDKV210)	:= 0x30008000     //自解压代码地址
params_phys-$(CONFIG_MACH_SMDKV210)	:= 0x30000100     //传的参数的地址

(8)将windows修改后的代码同步到ubuntu中,并且编译,得到zImage,然后在uboot通过tftp重新下载运行查看结果。

(9)结果就是:还是没运行,但是有效果。自解压代码解压打印信息已经出来了。但是内核还没运行

2、问题分析
(1)定义的物理地址不对,从20000000改到30000000即可
android-kernel-samsung-dev\arch\arm\mach-s5pv210\include\mach\memory.h

可通过head.S开头的

#define KERNEL_RAM_VADDR	(PAGE_OFFSET + TEXT_OFFSET)
#define KERNEL_RAM_PADDR	(PHYS_OFFSET + TEXT_OFFSET)

借助sourceinsight软件查找得到,然后进行修改。

三、内核中机器码的确定

android-kernel-samsung-dev\arch\arm\mach-s5pv210\mach-smdkc110.c的末尾

android-kernel-samsung-dev\arch\arm\mach-s5pv210\mach-smdkv210.c的末尾

1、MACHINE_START宏
(1)这个宏用来定义一个机器码的数据结构的。这个宏的使用其实是用来定义一个结构体类型为machine_desc类型的结构体变量,名为__mach_desc_SMDKV210。这个结构体变量会被定义到一个特定段.arch.info.init,因此这个结构体变量将来会被链接器链接到这个.arch.info.init段中。

static const struct machine_desc __mach_desc_SMDKV210	\
 __used							\
 __attribute__((__section__(".arch.info.init"))) = {	\
	.nr		= MACH_TYPE_SMDKV210,		\
	.name		= "SMDKV210",
	.phys_io	= S3C_PA_UART & 0xfff00000,
	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
	.boot_params	= S5P_PA_SDRAM + 0x100,
	.init_irq	= s5pv210_init_irq,
	.map_io		= smdkv210_map_io,
	.init_machine	= smdkv210_machine_init,
	.timer		= &s5p_systimer,
};

(2)经过分析,发现一个mach-xxx.c文件中定义了一个机器码的开发板的machine_desc结构体变量,这个结构体变量放到.arch.info.init段中后,那么就表示当前内核可以支持这个机器码的开发板。

(3)落实到当前开发板和当前内核中来分析,当前我们移植的目标开发板使用S5PV210的CPU,开发板名字叫X210.我们在三星官方版本的内核中是找不到mach-x210.c的,所以我们又不想从零开始去移植,因此我们的思路是在三星移植的mach-s5pv210目录下找一个mach-xx.c,这个开发板和我们的X210开发板最为接近,然后以此为基础来移植。

(4)经过查看,发现mach-s5pc110.c和mach-s5pv210.c和我们的X210开发板最为接近。我们一般确定的一个原则是:看我们的开发板和三星官方的哪个开发板最为相似。我们的X210开发板抄的是三星的SMDKV210,因此要找这个对应的那个文件。

(5)结合mach-s5pv210目录下的Makefile来分析,得知.config中定义了CONFIG_MACH_SMDKV210后,实际绑定的是mach-smdkc110.c这个文件。所以实际上mach-smdkv210.c这个文件根本没用到。从这里我们可以得到的经验就是不要光看名字,要实际去分析。

2、硬件驱动的加载和初始化函数执行(mach-smdkc110.c)
(1).init_machine = smdkc110_machine_init,

(2)这个元素定义了一个机器硬件初始化函数,这个函数非常重要,这个函数中绑定了我们这个开发板linux内核启动过程中会初始化的各种硬件的信息。

static void __init smdkc110_machine_init(void)
{
	arm_pm_restart = smdkc110_pm_restart;

	s3c_usb_set_serial();
	platform_add_devices(smdkc110_devices, ARRAY_SIZE(smdkc110_devices));
#ifdef CONFIG_ANDROID_PMEM
	platform_device_register(&pmem_gpu1_device);
#endif
	pm_power_off = smdkc110_power_off ;

#ifdef CONFIG_ANDROID_PMEM
	android_pmem_set_platdata();
#endif
	/* i2c */
	s3c_i2c0_set_platdata(NULL);
	s3c_i2c1_set_platdata(NULL);
	s3c_i2c2_set_platdata(NULL);

	sound_init();

	i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
	i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
	i2c_register_board_info(2, i2c_devs2, ARRAY_SIZE(i2c_devs2));

#ifdef CONFIG_DM9000
	smdkc110_dm9000_set();
#endif

#ifdef CONFIG_FB_S3C_LTE480WV
	s3cfb_set_platdata(&lte480wv_fb_data);
#endif

	/* spi */
#ifdef CONFIG_S3C64XX_DEV_SPI
	if (!gpio_request(S5PV210_GPB(1), "SPI_CS0")) {
		gpio_direction_output(S5PV210_GPB(1), 1);
		s3c_gpio_cfgpin(S5PV210_GPB(1), S3C_GPIO_SFN(1));
		s3c_gpio_setpull(S5PV210_GPB(1), S3C_GPIO_PULL_UP);
		s5pv210_spi_set_info(0, S5PV210_SPI_SRCCLK_PCLK,
			ARRAY_SIZE(smdk_spi0_csi));
	}
	if (!gpio_request(S5PV210_GPB(5), "SPI_CS1")) {
		gpio_direction_output(S5PV210_GPB(5), 1);
		s3c_gpio_cfgpin(S5PV210_GPB(5), S3C_GPIO_SFN(1));
		s3c_gpio_setpull(S5PV210_GPB(5), S3C_GPIO_PULL_UP);
		s5pv210_spi_set_info(1, S5PV210_SPI_SRCCLK_PCLK,
			ARRAY_SIZE(smdk_spi1_csi));
	}
	spi_register_board_info(s3c_spi_devs, ARRAY_SIZE(s3c_spi_devs));
#endif

#if defined(CONFIG_TOUCHSCREEN_S3C)
	s3c_ts_set_platdata(&s3c_ts_platform);
#endif

#if defined(CONFIG_S5P_ADC)
	s3c_adc_set_platdata(&s3c_adc_platform);
#endif

#if defined(CONFIG_PM)
	s3c_pm_init();
#endif

#ifdef CONFIG_VIDEO_FIMC
	/* fimc */
	s3c_fimc0_set_platdata(&fimc_plat_lsi);
	s3c_fimc1_set_platdata(&fimc_plat_lsi);
	s3c_fimc2_set_platdata(&fimc_plat_lsi);
	/* external camera */
	/* smdkv210_cam0_power(1); */
	/* smdkv210_cam1_power(1); */
#endif

#ifdef CONFIG_VIDEO_FIMC_MIPI
	s3c_csis_set_platdata(NULL);
#endif

#ifdef CONFIG_VIDEO_JPEG_V2
	s3c_jpeg_set_platdata(&jpeg_plat);
#endif

#ifdef CONFIG_VIDEO_MFC50
	/* mfc */
	s3c_mfc_set_platdata(NULL);
#endif

#ifdef CONFIG_VIDEO_TV20
	s3c_set_qos();
#endif

#ifdef CONFIG_S3C_DEV_HSMMC
	s5pv210_default_sdhci0();
#endif
#ifdef CONFIG_S3C_DEV_HSMMC1
	s5pv210_default_sdhci1();
#endif
#ifdef CONFIG_S3C_DEV_HSMMC2
	s5pv210_default_sdhci2();
#endif
#ifdef CONFIG_S3C_DEV_HSMMC3
	s5pv210_default_sdhci3();
#endif
#ifdef CONFIG_S5PV210_SETUP_SDHCI
	s3c_sdhci_set_platdata();
#endif

#ifdef CONFIG_BACKLIGHT_PWM
	smdk_backlight_register();
#endif

	regulator_has_full_constraints();

	smdkc110_setup_clocks();
}
	/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
	.phys_io	= S3C_PA_UART & 0xfff00000,
	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
	.boot_params	= S5P_PA_SDRAM + 0x100,
	.init_irq	= s5pv210_init_irq,
	.map_io		= smdkc110_map_io,
	.init_machine	= smdkc110_machine_init,
	.timer		= &s5p_systimer,
MACHINE_END

四、解决内核启动中的错误

“Oops 这个单词含义为“惊讶”。 在linux中,当内核出错时(比如访问非法地址)打印出来的信息被称为 Oops 信息: 当某些比较致命的问题出现时,我们的Linux内核也会抱歉的对我们说:“哎呦(Oops),对不起,我把事情搞砸了

Linux内核在发生kernel panic时会打印出Oops信息,把目前的寄存器状态、堆栈内容、以及完整的Call trace都show给我们看,这样就可以帮助我们定位错误。

1、认识内核启动OOPS
(1)内核启动后会有打印信息,打印信息中隐藏了问题所在。认真的去分析这个打印信息,从中找到对的或者错误的一些信息片段,才能帮助我们找到问题,从而解决问题。

(2)内核启动中的错误信息有一些特征:

Unable to handle kernel NULL pointer dereference at virtual address 00000060使用了野指针导致的错误
Internal error: Oops: 5 [#1] PREEMPT  看到Oops,表明问题就出现在附近,内核已经死了,之后打印的信息都是调试信息
PC is at dev_driver_string+0xc/0x44      PC寄存器,通过其知道正在执行那个指令
LR is at max8698_pmic_probe+0x150/0x32c

3)从以上错误信息中的PC和LR的值可以看出,程序是执行到dev_driver_string或者max8698_pmic_probe(这两个是函数或者汇编中的标号)符号部分的时候出错了。我们就从这两个符号出发去寻找、思考可能出错的地方然后试图去解决。

2、错误追溯及问题解决
(1)max8698_pmic_probe看名字是max8698这个电源管理IC的驱动安装函数部分出错了,应该是我们的开发板系统中配置了支持这个电源管理IC,于是乎启动时去加载他的驱动,结果驱动在加载执行的过程中出错了OOPS了。

(2)我们为什么要配置支持这个驱动?这个驱动加载为什么要出错?

(3)结合我们X210开发板的硬件实际情况来分析:我们X210开发板上根本就没有max8698这个电源管理IC,既然硬件都没有驱动执行了肯定会出错。

(4)回忆当时从三星版本的uboot移植的时候,在uboot的lowlevel_init.S中也有调用个电源管理IC初始化函数(PMIC_init),后来解决的办法就是屏蔽掉了这个函数的调用,uboot就成功运行下去了。

(5)为什么我们的uboot和内核中默认都调用了这个电源管理IC的初始化代码?原因就是三星的SMDKV210开发板中是用了max8698这个电源管理IC的,所以三星的uboot和kernel中都有默认支持这个。但是九鼎科技的X210中是没用的,因此都需要去掉。

(6)怎么解决?在uboot中是直接改源代码屏蔽掉那个初始化函数解决的;在内核中不能这么干?因为linux kernel是高度模块化高度可配置的,内核中每一个模块都是被配置项条件编译了的,因此要去掉某个模块的支持,只需要重新配置去掉选项即可,不用改源代码。所以我们的关键就是要找它对应的配置项。

(7)我们做法:make menuconfig,然后/搜索"MAX8698"这几个关键字,然后看到这个配置项的路径,然后到路径下去按N键去掉这个模块的支持,保存,重新编译即可。

(8)实践证明问题被解决了,而且内核再次启动后直接运行到挂载rootfs才出错。

3、分析及总结
(1)分析:问题究竟是怎么被解决的?涉及哪几个方面

根本原因在于CONFIG_MFD_MAX8698这个配置宏。这个配置宏决定了很多东西
第一:这个配置宏决定了drivers目录下的max8698对应的驱动程序源代码是否被编译(查看Makefile可知)

obj-$(CONFIG_MFD_MAX8698) += max8698.o

android-kernel-samsung-dev\drivers\mfd\max8698.c

第二:这个配置宏决定了kernel启动过程中是否会调用一些max8698的相关的代码
在smdkc110.c中包含了该文件,进行PMIC的初始化

(2)总结:kernel是高度模块化和可配置化的,所以在内核中做任何事情(添加一个模块、更改一个模块、去掉一个模块)都必须按照内核设定的方案和流程来走。一般不允许进行低级的改代码

五、iNand的问题和安排

[    1.663479] VFS: Cannot open root device "mmcblk0p2" or unknown-block(0,0)
[    1.670081] Please append a correct "root=" boot option; here are the available partitions:
[    1.678418] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
[    1.686635] Backtrace: 
[    1.689067] [<c0031fb8>] (dump_backtrace+0x0/0x110) from [<c0394240>] (dump_stack+0x18/0x1c)
[    1.697469]  r6:00008000 r5:dfdc9000 r4:c051f084 r3:00000002
[    1.703089] [<c0394228>] (dump_stack+0x0/0x1c) from [<c03942bc>] (panic+0x78/0xf8)
[    1.710646] [<c0394244>] (panic+0x0/0xf8) from [<c000904c>] (mount_block_root+0x25c/0x2ac)
[    1.718871]  r3:00000000 r2:00000001 r1:dfc2ff60 r0:c049ce95
[    1.724493] [<c0008df0>] (mount_block_root+0x0/0x2ac) from [<c00090f0>] (mount_root+0x54/0x68)
[    1.733090] [<c000909c>] (mount_root+0x0/0x68) from [<c0009274>] (prepare_namespace+0x170/0x1c8)
[    1.741836]  r5:c0027a39 r4:c054d200
[    1.745377] [<c0009104>] (prepare_namespace+0x0/0x1c8) from [<c00084fc>] (kernel_init+0x128/0x170)
[    1.754315]  r5:c00083d4 r4:c054cfc0
[    1.757861] [<c00083d4>] (kernel_init+0x0/0x170) from [<c0054b10>] (do_exit+0x0/0x5f0)

从这块的打印信息中可以看出函数调用的顺序和包含关系

1、错误分析
(1)得到的内核错误信息:

Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

从错误信息字面意思来分析,就是内核试图挂载根文件系统时失败,失败的原因是unknown-block(不能识别的块设备)

(2)backstrace分析,可以得知错误信息的来源,再结合之前的内核启动流程分析,就更加确定了出错的地方。

(3)下一个问题:分析这个错误出现的原因。unknown-block(0,0)。在kernel启动时uboot会传给内核一个cmdline,其中用root=xx来指定了rootfs在哪个设备上,内核就会到相应的地方去挂载rootfs。譬如我们传参中:root=/dev/mmcblk0p2,这里的/dev/mmcblk0p2就是rootfs的设备地址,这个设备文件编号的含义就是mmc设备0的第2个分区(设备0就是在SD0通道上的设备,也就是iNand),这里的问题就是没找到mmc设备0的第2分区。

(4)下一步问题:为什么没找到mmc设备0的第2分区。一定是因为kernel启动过程中加载mmc驱动的时候有问题,驱动没有发现mmc设备0.问题定位在MMC相关的驱动方面。

(5)对比九鼎版本提供的内核打印的启动信息,即可发现我们的内核启动并没有找到MMC设备(内置的iNand和外置的SD卡都没找到),没找到肯定是驱动的问题,这就要去移植MMC驱动了。

2、问题阐述
(1)SD/iNand本身都是由一个一个的扇区组成的,210启动时,BL1在SD卡的1扇区开始往后存放,SD卡的0扇区是不用的。SD卡的0扇区是用来放置MBR的。

(2)MBR就是用来描述块设备的分区信息的,事先定义了一个通用的数据结构来描述块设备的分区,我们只要按照这个标准将分区信息写入MBR中即可对该设备完成分区。MBR默认就是在块设备的第0个扇区上存放的。

下载一些软件修改SD卡的分区其实就是在写MBR

(3)我们内核中读到iNand分4个分区,我们哪里分区的?
uboot中有一个命令fdisk -c 0时就对iNand进行了分区。uboot的fdisk命令内部已经写死了iNand的分区表,到内核中时内核直接读取MBR就知道了分区。所以在uboot和内核之间iNand设备的分区信息是靠iNand自己传递的,所以uboot不用给内核传参时传递分区表信息。

(4)如果开发板用的是nandFlash的话,分区表一般是在内核中自己用代码构建的。所以nand版本的内核移植的时候一般都需要去移植更改nand分区表。

3、解决安排
(1)暂时解决不了这个问题。MMC驱动问题

由于版本号的问题导致的;android-kernel-samsung-dev\drivers\mmc\core\mmc.c 224行

六、网卡驱动的移植和添加实验

1、移植标准
(1)网卡驱动移植ok时,启动信息为:

[1.452008] dm9000 Ethernet Driver, V1.31
[1.455870] eth0: dm9000c at e08f4300,e08f8304 IRQ 42 MAC: 00:09:c0:ff:ec:48 (platform data)

(2)当前内核中网卡驱动尚未移植,因此内核启动时有错误的打印信息:

[    1.130308] dm9000 Ethernet Driver, V1.31
[    1.133113] ERROR : resetting 
[    1.135700] dm9000 dm9000.0: read wrong id 0x2b2a2928
[    1.140915] dm9000 dm9000.0: read wrong id 0x2b2a2928
[    1.145941] dm9000 dm9000.0: read wrong id 0x2b2a2928
[    1.150963] dm9000 dm9000.0: read wrong id 0x2b2a2928
[    1.155992] dm9000 dm9000.0: read wrong id 0x2b2a2928
[    1.161018] dm9000 dm9000.0: read wrong id 0x2b2a2928
[    1.166041] dm9000 dm9000.0: read wrong id 0x2b2a2928
[    1.171070] dm9000 dm9000.0: read wrong id 0x2b2a2928
[    1.176092] dm9000 dm9000.0: wrong id: 0x2b2a2928
[    1.180774] dm9000 dm9000.0: not found (-19).

(3)移植的目标就是让我们的版本的内核可以打印出正确情况下的启动信息,那我们就相信内核启动后网卡是可以工作的。

2、make menuconfig中添加DM9000支持
(1)menuconfig中选择Y

(2)其实这一步本来就是Y,所以在我们这里是不用管的。但是你自己遇到的一个内核可能默认不是Y,因此要设置。

3、mach-smdkc110.c中逻辑分析
(1)mach-smdkc110.c中的smdkc110_machine_init是整个开发板的所有硬件的初始化函数,在这里加载了的硬件将来启动时就会被初始化,在这里没有的将来启动时就不管。

android-kernel-samsung-dev\arch\arm\mach-s5pv210\mach-smdkc110.c smdkc110_machine_init函数

platform_add_devices(smdkc110_devices, ARRAY_SIZE(smdkc110_devices));

#ifdef CONFIG_DM9000        //1545行附近
	smdkc110_dm9000_set();
#endif

(2)smdkc110_devices[]数组和smdkc110_dm9000_set()函数这两个地方是和DM9000有关的,要分别去做移植。

static struct platform_device *smdkc110_devices[] __initdata = {
#ifdef CONFIG_FIQ_DEBUGGER
	&s5pv210_device_fiqdbg_uart2,
#endif
#ifdef CONFIG_MTD_ONENAND
	&s5pc110_device_onenand,
#endif
#ifdef CONFIG_MTD_NAND
	&s3c_device_nand,
#endif
	&s5p_device_rtc,
#ifdef CONFIG_SND_S3C64XX_SOC_I2S_V4
	&s5pv210_device_iis0,
#endif
#ifdef CONFIG_SND_S3C_SOC_AC97
	&s5pv210_device_ac97,
#endif
#ifdef CONFIG_SND_S3C_SOC_PCM
	&s5pv210_device_pcm0,
#endif
#ifdef CONFIG_SND_SOC_SPDIF
	&s5pv210_device_spdif,
#endif
	&s3c_device_wdt,

#ifdef CONFIG_FB_S3C
	&s3c_device_fb,
#endif
#ifdef CONFIG_DM9000
	&s5p_device_dm9000,
#endif

#ifdef CONFIG_VIDEO_MFC50
	&s3c_device_mfc,
#endif
#ifdef CONFIG_TOUCHSCREEN_S3C
	&s3c_device_ts,
#endif
	&s3c_device_keypad,
#ifdef CONFIG_S5P_ADC
	&s3c_device_adc,
#endif
#ifdef CONFIG_VIDEO_FIMC
	&s3c_device_fimc0,
	&s3c_device_fimc1,
	&s3c_device_fimc2,
#endif
#ifdef CONFIG_VIDEO_FIMC_MIPI
	&s3c_device_csis,
#endif
#ifdef CONFIG_VIDEO_JPEG_V2
	&s3c_device_jpeg,
#endif
#ifdef CONFIG_VIDEO_G2D
	&s3c_device_g2d,
#endif
#ifdef CONFIG_VIDEO_TV20
	&s5p_device_tvout,
	&s5p_device_cec,
	&s5p_device_hpd,
#endif

	&s3c_device_g3d,
	&s3c_device_lcd,

	&s3c_device_i2c0,
#ifdef CONFIG_S3C_DEV_I2C1
	&s3c_device_i2c1,
#endif
#ifdef CONFIG_S3C_DEV_I2C2
	&s3c_device_i2c2,
#endif

#ifdef CONFIG_USB_EHCI_HCD
	&s3c_device_usb_ehci,
#endif
#ifdef CONFIG_USB_OHCI_HCD
	&s3c_device_usb_ohci,
#endif

#ifdef CONFIG_USB_GADGET
	&s3c_device_usbgadget,
#endif
#ifdef CONFIG_USB_ANDROID
	&s3c_device_android_usb,
#ifdef CONFIG_USB_ANDROID_MASS_STORAGE
	&s3c_device_usb_mass_storage,
#endif
#ifdef CONFIG_USB_ANDROID_RNDIS
	&s3c_device_rndis,
#endif
#endif
#ifdef CONFIG_BATTERY_S3C
	&sec_device_battery,
#endif
#ifdef CONFIG_S3C_DEV_HSMMC
	&s3c_device_hsmmc0,
#endif
#ifdef CONFIG_S3C_DEV_HSMMC1
	&s3c_device_hsmmc1,
#endif
#ifdef CONFIG_S3C_DEV_HSMMC2
	&s3c_device_hsmmc2,
#endif
#ifdef CONFIG_S3C_DEV_HSMMC3
	&s3c_device_hsmmc3,
#endif

#ifdef CONFIG_S3C64XX_DEV_SPI
	&s5pv210_device_spi0,
	&s5pv210_device_spi1,
#endif
#ifdef CONFIG_S5PV210_POWER_DOMAIN
	&s5pv210_pd_audio,
	&s5pv210_pd_cam,
	&s5pv210_pd_tv,
	&s5pv210_pd_lcd,
	&s5pv210_pd_g3d,
	&s5pv210_pd_mfc,
#endif

#ifdef CONFIG_HAVE_PWM
	&s3c_device_timer[0],
	&s3c_device_timer[1],
	&s3c_device_timer[2],
	&s3c_device_timer[3],
#endif
};

(3)smdkc110_dm9000_set这个函数就是DM9000相关的SROM bank的寄存器设置,相当于在uboot中dm9000移植时的dm9000_pre_init函数。只是读写寄存器的函数名称不同了。

4、修改相应的配置参数

android-kernel-samsung-dev\arch\arm\mach-s5pv210\mach-smdkc110.c 1363#ifdef CONFIG_DM9000
	&s5p_device_dm9000,
#endif

android-kernel-samsung-dev\arch\arm\plat-s5p\devs.c 233struct platform_device s5p_device_dm9000 = {
	.name		= "dm9000",
	.id		=  0,
	.num_resources	= ARRAY_SIZE(s5p_dm9000_resources),
	.resource	= s5p_dm9000_resources,          
	.dev		= {
		.platform_data = &s5p_dm9000_platdata,  
	}
};

(1)DM9000相关的数据配置在arch/arm/plat-s5p/devs.c中更改
修改s5p_dm9000_resources\

android-kernel-samsung-dev\arch\arm\mach-s5pv210\include\mach\map.h
#define S5PV210_PA_DM9000       (0x88000300)   DM9000与SROMBANK连接的地址

(2)在arch/arm/mach-s5pv210/include/mach/map.h中定义了DM9000的IO基地址,和DM9000接在哪个bank有关。

(3)还有+2改成+4,IRQ_EINT9改成10即可。

5、代码实践
(1)同步代码、编译生成zImage
(2)下载启动后看启动信息。

七、内核启动第一阶段的调试方法

**内核移植其实我们很大程度上做的都是驱动移植,**像内存管理,调度系统等都是好的可以用的,一般不会出问题,出了问题也不是我们可以解决的。

1、问题点描述
(1)内核启动在head.S中首先进行了三个校验(CPU id的校验、机器码的校验、tag的校验),然后创建页表,然后做了一些不太会出错的事情,然后b start_kernel。基本上能运行到start_kernel内核移植就不太会出问题了。

(2)有时候移植的内核启动后的现象是:根本没有启动信息出来。这时候有可能是内核启动运行了但是运行出错了没启动起来所以没有打印信息;也有可能是内核根本没得以运行。都有可能但是没法确定。我们希望能有一种调试手段来确定问题所在。

2、调试方法和原理
(1)调试方法就是在内核启动的第一阶段添加汇编操作led点亮/熄灭的方法来标明代码运行的轨迹。

(2)将裸机中汇编操作led点亮/熄灭的代码进行移植,复制粘贴到head.S中合适位置。然后内核启动后根据led的表现来标明代码有无运行。

//led全部熄灭的函数
led:
	ldr r0, =0x11111111
	ldr r1, = 0xE0200240
	str r0, [r1]
	
	ldr r0, =0xff
	ldr r1, =0xE0200244
	str r0, [r1]

这个代码是不可以直接放到head.S中使用的,因为该文件开头使用了r0、r1寄存器进行数据传输,做一些初始化的设置,要进行一定的改造才可以使用

led:
	ldr r3, =0x11111111
	ldr r4, = 0xE0200240
	str r3, [r4]
	
	ldr r3, =0xff
	ldr r4, =0xE0200244
	str r3, [r4]

	mov pc, lr

3、动手测试
(1)整理好led操作的代码段,在head.S中合适的地方添加led这个函数,然后在head.S的内核起始运行阶段添加调用led函数,然后重新编译内核,运行内核看这段代码有无被运行。

(2)如果被运行了,证明在这个调用led的步骤之前的部分都是没问题的,那么如果有错肯定错误在后边;如果没有被运行则证明错误在之前,那么就要去之前的部分debug。

summary:经过这里的移植,内核虽然可以工作一部分,但还是无法正常启动,之前那个MMC驱动问题修改了版本号还是没有解决,由于初学内核驱动水平有限,不得不暂且搁置,等自己功力提升后再解决,如果有哪位同学解决了,请不吝赐教!

至此《初窥Linux内核》专栏的文章也结束了,本专栏遗留的一些问题欢迎各位在评论区交流,一起学习。我后续也会抽时间再整理有关内核的文章,分析学习更高版本的涉及到使用设备树的内核源码。

参考文章:http://t.csdnimg.cn/8esIo

  • 19
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值