嵌入式Linux之Kernel(裁减移植)启动调试、打印技术 printascii(补充)、内核调试

合集下载

linux内核的裁剪与移植

linux内核的裁剪与移植

1,获得源码,解压,进入解压后的目录;命令;2,修改makefile;为了能让此目录被执行所以在顶级目录的makefile中同时也进行修改;3,得到.config文件;命令;编译内核时对.config文件的依赖比较大,我们需要一个自己的.config文件,又因为我们的板子和smdk2410的很像,仅需将smdk2410的.config 文件复制到顶级目录即可不用修改;4;修改nandflash 分区;此系统启动时从nandflash 中启动而我们的板子不是的所以对其进行必要的修改;5,添加网卡驱动;arch/arm/mach-s3c2410/mach-smdk2410.c开发板上已经配置要的相应的网卡,并且内核中也有相应的实现代码我们只需做一下简单的修改;6添加yaffz文件系统支持将yaffz 源码包考到和linux-2.6.24 同一级目录下解压;在给内核打上补丁;命令是;7、配置和编译内核到现在,一个简单的内核就准备好了,我们还需要做一些配置,然后编译,内核才能正常使用。

在内核源代码的根目录下运行make menuconfig命令,进入配置界面:8,用u-boot启动内核;编译U-Boot时在源代码的tools目录下会生成一个mkimage可执行文件,用这个工具可以对前面编译内核时生成的zImage进行处理,以供U-Boot启动。

cd linux-2.6.24.4/arch/arm/bootcp /up-Star2410/kernel/linux-2.6.24.4/mkimage . 获取mkimage工具./mkimage -A arm -T kernel -C none -O linux -a 0x30008000 -e 0x30008040 -d zImage -n 'Linux-2.6.24' uImage9,最后把生成的uimage 放到主机tftp同目录下,启动开发板;用u-boot的tftp命令下载到sdram;。

07_嵌入式Linux内核裁减移植

07_嵌入式Linux内核裁减移植

什么是Linux内核?
内核架构
内核配置与编译
Linux内核具有可定制的优点 ,具体步骤如下:
1. 清除临时文件、中间文件和配置文件 .
• make clean:remove most generated files but keep the config • make mrproper:remove all generated files + config files • make distclean:mrproper + remove editor backup and patch files
怎样编译文件
(4)obj-m,定义文件编译成可加载模块 obj-m中定义的.o文件由当前目录下的.c或.S文件编译生成,但不会编进 build-in.o中,而是编译成可加载模块.ko 当某个模块(m)需要多个文件编译制作而成: obj-m = a.o a-objs:= b.o, c.o, d.o 由b.o,c.o,d.o组合生成a.o,a.o最后制作成a.ko模块 (5)、obj-m、obj-y变量中增加子目录名则进入该子目录执行Makefile (6)、 lib-y,定义文件被编译成库文件 lib-y中定义的.o文件由当前目录下的.c或.S文件编译生成,并且被打包成当前目 录下的一个库文件lib.a 要把lib.a编译进内核,需要在顶层Makefile中libs-y中列出该目录 要编译成库的代码一般在lib/、arch/$(ARCH)/lib/这两个目录下

内核配置与编译
4、编译内核: • 编译内核映像 – make zImage – make bzImage
区别:在X86平台, zImage只能用于小于 512K的内
生成带Uboot文件头的的内核:make uImage 注意需要uboot的mkimage工具支持,但本开发板uboot支持直接引导zImage 参见:cmd_bootm.c:#ifdef CONFIG_ZIMAGE_BOOT • 如需获取详细编译过程信息,可使用: – make zImage V=1 – make bzImage V=1 编译出错时,可以通过查看编译过程信息定位错误,例如缺 少某些编译选项时 可以到相应目录下的Makefile去修改 编译好的内核位于arch/<cpu>/boot/目录下

嵌入式 linux 裁剪 编译

嵌入式 linux 裁剪 编译

嵌入式linux 裁剪编译摘要:一、嵌入式Linux 简介1.嵌入式系统的概念2.嵌入式Linux 的发展和应用二、嵌入式Linux 裁剪的重要性1.裁剪的定义和目的2.裁剪对系统性能和资源的影响三、嵌入式Linux 裁剪和编译的步骤1.准备工作a.下载Linux 内核源码b.安装开发工具和环境2.内核配置a.选择需要的配置选项b.配置编译器3.编译内核a.生成Makefileb.编译内核4.安装内核a.烧写内核到目标板b.启动嵌入式系统四、裁剪和编译过程中遇到的问题及解决方法1.编译错误a.检查Makefileb.修复依赖关系c.更新软件包2.烧写失败a.检查烧写工具和文件b.更新目标板驱动c.更换烧写方式正文:嵌入式Linux 是一种适用于嵌入式系统的轻量级操作系统,通过裁剪和编译可以使其更好地适应特定应用场景的需求。

本文将详细介绍嵌入式Linux 裁剪和编译的步骤以及过程中可能遇到的问题和解决方法。

首先,我们需要了解嵌入式系统的概念。

嵌入式系统是指被嵌入到其他设备或系统中的计算机系统,具有特定功能和性能要求。

嵌入式Linux 作为一种开源、可定制的操作系统,得到了广泛的应用。

裁剪是嵌入式Linux 开发中的重要环节,可以去除不必要的功能和代码,从而减小系统体积、降低资源占用和提高运行效率。

裁剪过程中需要选择合适的配置选项,以满足系统性能和资源的要求。

嵌入式Linux 裁剪和编译的步骤如下:1.准备工作:首先,需要下载Linux 内核源码,并安装相应的开发工具和环境。

2.内核配置:在配置阶段,需要选择需要的配置选项,例如去除不用的模块、调整编译器参数等。

此外,还需要配置编译器,以满足嵌入式系统的开发需求。

3.编译内核:在编译内核阶段,需要生成Makefile,然后使用编译器编译内核。

这一过程可能需要较长时间,需要耐心等待。

4.安装内核:最后,将编译好的内核烧写至目标板,并启动嵌入式系统。

在烧写过程中,可能会遇到一些问题,如烧写失败等。

Linux内核裁剪的具体过程和方法

Linux内核裁剪的具体过程和方法

Linux内核裁剪的具体过程和方法根据部分网摘资料和实际烧录结果进行整理:内核功能:在能够实现AT91SAM9260开发板基本功能的基础上,通过串口连接上读卡器后能进行一系列的操作和控制功能等,将读卡器的相应数据进行存储或者通过网络传输到远程的PC 机上。

远程PC机能够通过网络方式在开发板上对所连接的读卡器参数进行更新配置,如设置天线接口、设置读卡方式等。

(待与读卡器配套使用后再对内核的功能描述进行补充和完善。

)编译环境:源代码解压完成后,进入linux 2.6.19目录下,使用VI命令编辑Makefile。

确定编译环境为arm交叉编译工具与本机的安装路径一致ARCH = armCROSS_COMPILE = /opt/timesys/toolchains/armv5l-linux/bin/armv5l-linux-内核版本是linux 2.6.19 ,开发板的版本是AT91SAM9260 BOARD V1.01 ,主机系统是ubuntu11.10内核配置:内核配置的方法很多,make config、make xconfig、make menuconfig、make oldconfig 等等,它们的功能都是一样的,区别应该从名字上就能看出来,只有make oldconfig是指用系统当前的设置(./.config)作为缺省值。

这里用的是make menuconfig。

需要牢记:不必要的驱动越多,内核就越大,不仅运行速度慢、占用内存多,在少数情况下、还会引发其他问题。

具体步骤如下:首先确定shell是bash。

然后$make menuconfig。

有一些默认的符号其含义如下:"[ ]"表示该选项有两种选择方式;[*] 直接编译进内核;[] 不编译;"<>"表示该选项有三种选择方式; <*>直接编译进内核; <M>编译成模块形式,但不编译进内核;<> 不编译。

关于嵌入式Linux操作系统的内核调试技术详解

关于嵌入式Linux操作系统的内核调试技术详解

关于嵌入式Linux操作系统的内核调试技术详解近年处理器技术发展速度加快,嵌入式领域发生了翻天覆地的变化。

特别是网络的普及,消费电子异军突起,嵌入式与互联网成为最热门的技术。

在所有操作系统中,Linux是发展很快、应用很广泛的一种操作系统。

Linux的开放性以及其他优秀特性使其成为嵌入式系统开发的首选。

总的来说,嵌入式开发所面临的问题主要表现在以下几个方面。

涉及多种CPU 及多种OS嵌入式的CPU或处理器包括MIPS、PPC、ARM,XScale等不同的架构,这些处理器上运行的操作系统也有VxWorks、Linux、C/OS、WinCE等多种。

在一个企业之内,可能会同时使用好几种处理器,甚至几种嵌入式操作系统。

如果需要同时调试多种类型的电路板,那复杂性是可想而知的。

这也是我们选用瑞士Abatron公司的BDI2000的原因之一,它是一款功能强大的JTAG/BDM通用仿真器。

它支持:PPC/MIPS/ARM/XSCALE/ CPU12/CPU32/M-CORE/ColdFire等多种处理器,支持Windows/Linux系统平台,以及多种第三方调试器,并且对Flash的烧写也很简单方便。

开发工具种类繁多通常各种操作系统有各自的开发工具,在同一系统下开发的不同阶段也会应用不同的开发工具。

如在用户的目标板开发初期,需要硬件仿真器来调试硬件系统和基本的引导程序,然后进行操作系统及驱动程序的开发调试。

在调试应用程序阶段可以使用交互式的开发环境进行软件调试,在测试阶段需要一些专门的测试工具软件进行功能和性能的测试。

在生产阶段需要固化程序及出厂检测等等。

BDI2000可以适应开发的各个阶段,节约企业的支出和简化管理难度。

对目标系统的观察和控制由于嵌入式硬件系统千差万别,软件模块和系统资源也多种多样,要使系统能正常工作,软件开发者必须要对目标系统具有完全的观察和控制能力,例如硬件的各种寄存器、内存空间、操作系统的信号量、消息队列、任务、堆栈等。

linux2.6内核裁剪说明

linux2.6内核裁剪说明

Linux内核裁剪与移植内核,即操作系统。

它为底层的可编程部件提供服务,为上层应用程序提供执行环境。

内核裁剪就是对这些功能进行裁剪,选取满足特定平台和需求的功能。

不同的硬件平台对内核要求也不同,因此从一个平台到另一个平台需要对内核进行重新配置和编译。

操作系统从一个平台过渡到另一个平台称为移植。

Linux是一款平台适应性且容易裁剪的操作系统,因此Linux在嵌入式系统得到了广泛的应用。

本章将详细讲解内核裁剪与移植的各项技术。

4.1 Linux内核结构Linux内核采用模块化设计,并且各个模块源码以文件目录的形式存放,在对内核的裁剪和编译时非常方便。

下面介绍内核的主要部分及其文件目录。

4.1.1 内核的主要组成部分在第1章中已经介绍了Linux内核主要的5个部分:进程调度、内存管理、虚拟文件系统、网络接口、进程通信。

在系统移植的时候,它们是内核的基本元素,这5个部分之间的关系,如图4.1所示。

图4.1 Linux内核子系统及其之间的关系进程调度部分负责控制进程对CPU的访问。

内存管理允许多个进程安全地共享主内存区域。

内存管理从逻辑上分为硬件无关部分和硬件相关部分。

硬件无关部分提供了进程的映射和逻辑内存的对换;硬件相关部分为内存管理硬件提供了虚拟接口。

虚拟文件系统隐藏了不同类型硬件的具体细节,为所有的硬件设备提供了一个标准的接口,VFS提供了十多种不同类型的文件系统。

网络接口提供了对各种网络标准的存取和各种网络硬件的支持。

进程通信部分用于支持进程间各种不同的通信机制。

进程调度处于核心位置,内核的其他子系统都要依赖它,因为每个子系统都存在进程挂起或恢复过程。

* 进程调度与内存管理之间的关系:这两个子系统为互相依赖关系。

在多道程序环境下,程序要运行必须为之创建进程,而创建进程首先就是要将程序和数据装入内存。

另外,内存管理子系统也存在进程的挂起和恢复过程。

* 进程间通信与内存管理之间的关系:进程间通信子系统要依赖内存管理支持共享内存通信机制,通过对共同的内存区域进行操作来达到通信的目的。

linux内核printascii详解

linux内核printascii详解

linux内核printascii详解printasccii的实现在arch/arm/kernel/debug.S中,其中涉及到的文件还有arch/arm/plat-s3c/include/plat/debug-macro.S,arch/arm/mach-s3c2410/include/mach/debug-marco.SENTRY(printascii)addruart r3 /* 选择UARTn的第一个寄存器地址,一般默认选择UART0则r3=0x5000_0000 */b 2f1: waituart r2, r3senduart r1, r3busyuart r2, r3teq r1, #'\n'moveq r1, #'\r'beq 1b2: teq r0, #0 /* 在调用printascii时,r0一般指向要输出的buffer */ldrneb r1, [r0], #1teqne r1, #0 /* 判断是否到了字符串末尾 */bne 1bmov pc, lrENDPROC(printascii)ENTRY(printch) //这里是现实打印一个字符addruart r3mov r1, r0mov r0, #0b 1bENDPROC(printch)下面分别介绍addruart,waituart,senduart,busyuartaddruart的定义在arch/arm/plat-s3c/include/plat/debug-macro.S,主要用来选择uart。

#define S3C2410_UART1_OFF (0x4000)#define SHIFT_2440TXF (14-9).macro addruart, rxmrc p15, 0, \rx, c1, c0 /* 读c1控制寄存器 */tst \rx, #1 /* 测试MMU是否开启 */ldreq \rx, = S3C24XX_PA_UART //直接使用物理地址访问UART 的寄存器ldrne \rx, = S3C24XX_VA_UART //使用虚拟地址访问UART的寄存器,那么就一定要位UART的寄存器建立页表映射在head.S中#if CONFIG_DEBUG_S3C_UART != 0/* 默认使用UART0来显示,如果CONFIG_DEBUG_S3C_UART不等于0则选择相应UART */add \rx, \rx, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)#endif这个三个宏的定义在arch/arm/plat-s3c/include/plat/debug-macro.S中 waituart,senduart,busyuart,waituart是等待Tx FIFO为empty,而busyuart则是判断Tx FIFO是否full,如果full那么就忙循环等待,知道fifo不满为止。

嵌入式Linux2.6内核启动流程)

嵌入式Linux2.6内核启动流程)

Linux内核构成(国嵌)Linux/arch/arm/boot/compressed/head.s1.解压缩2.初始化3.启动应用程序1 arch/arm/boot/compressed/Makefile arch/arm/boot/compressed/vmlinux.lds2. arch/arm/kernel/vmlinux.ldsLinux内核启动流程(国嵌)arch/arm/boot/compressed/start.S(head.s—负责解压缩)Start:.type start,#function.rept 8mov r0, r0.endrb 1f.word 0x016f2818 @ Magic numbers to help the loader.word start @ absolute load/run zImage address.word _edata @ zImage end address1: mov r7, r1 @ save architecture IDmov r8, r2 @ save atags pointer这也标志着u-boot将系统完全的交给了OS,bootloader生命终止。

之后代码在133行会读取cpsr并判断是否处理器处于supervisor模式——从u-boot进入kernel,系统已经处于SVC32模式;而利用angel进入则处于user模式,还需要额外两条指令。

之后是再次确认中断关闭,并完成cpsr写入mrs r2, cpsr @ get current modetst r2, #3 @ not user?bne not_angelmov r0, #0x17 @ angel_SWIreason_EnterSVCswi 0x @ angel_SWI_ARMnot_angel:mrs r2, cpsr @ turn off interrupts toorr r2, r2, #0xc0 @ prevent angel from runningmsr cpsr_c, r2然后在LC0地址处将分段信息导入r0-r6、ip、sp等寄存器,并检查代码是否运行在与链接时相同的目标地址,以决定是否进行处理。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

嵌入式系统搭建过程中,对于系统平台搭建工程师在完成Bootloader 的调试之后就进入Kernel 裁减移植的阶段,其中最重要的一步是Kernel 启动的调试,在调试Kernel 过程中通常遇到最常见的问题是启动异常:
Uncompressing Linux............................................................
........................... done, booting the kernel.( 挂死在此处)
注意:这里是arch/arm/boot/compressed/head.S的解压过程,调用了decompress_kernel()(同目录下的misc.c)->include/asm-arm/arch-xxx/uncompress.h的putc()实现。

这是在uboot中初始化的,用的是物理地址,因为此时内核还没有起来。

而printascii则是调用了汇编。

printascii()位于arch/arm/kernel/debug.S,他需要调用虚拟地址,此虚拟地址通过machine_start提供,而相关的宏在include/asm/arch-xxx/debug-macro.S实现,这下明白了。

10-05-14添加:debug.s里面需要判断一下当前是否打开了mmu,然后指定uart的基址。

在解压阶段的head.s,mmu是1:1映射,目的是加快速度。

到了内核的head.s,就是真正的mmu了,此时就是虚拟地址了。

导致驱动异常(启动挂死)的原因有很多,如基于EVM 板的硬件做了修改(如更改了FLASH 空间大小、地址和型号,更改了SDRAM 、DDR SDRAM 空间大小、地址和型号,更改了晶振频率等),板卡ID号不支持等。

那么如何进行调试那,其实有两种调试技术比较有效。

Kernel 启动调试技术- 使用printascii() 函数跟踪start_kernel() 有没运行,在booting the kernel 之后Kernel 最先执行的是start_kernel() 函数,确认start_kernel() 有否执行就是在其开始代码段添加printascii("start_kernel …") ,如果串口没有打印出start_kernel …,说明start_kernel() 没有运行,那么可能的原因有Bootloader 配置的启动参数错误、 Kernel 加载到(DDR) SDRAM 的地址不正确, Kernel 编译时指定的(DDR) SDRAM 运行地址不正确等。

这样就需要一项一项排查错误,当错误被排查完毕,通常打印出start_kernel …是种必然,如果打印出这仪信息说明 Kernel已进入到start_kernel() 执行,如果此时有串口启动打印就比较成功了,如果仍然没有打印启动信息,就需要另外一种调试技术。

附代码修改:init/main.c <<-

extern void printascii(const char*); // Modify
asmlinkage void __init start_kernel(void)
{
char * command_line;
extern struct kernel_param __start___param[], __stop___param[];
printascii("start_kernel …"); // Modify
smp_setup_processor_id();

->>
Kernel 启动调试技术- 使用printascii() 函数打印printk() 缓存信息,如果Kernel已进入到start_kernel() 执行,仍然没有启动信息打印出来,说明串口波特率出问题的可能性比较大,启动信息是暂时缓存到临时buffer--printk_buf 中的,进入start_kernel() 中会对串口波特率重新初始化,当初始化完成后,缓存的系统启动信息便打印出来,不能打印说明用于串口波特率初始化的系统时钟源没有初始化正确,通常是系统时钟源和实际的晶振频率不一致导致的,通常排查和解决这个问题后,系统启动信息是能正确打印的。

为了帮助解决问题,可以使用 printascii() 打印printk_buf 内容。

这样就能把printascii ()打印的系统信息和预想的系统信息进行比较,从而加快解决问题的进度。

附代码修改:kernel/printk.c <<-

extern void printascii(const char*); // Modify
static char printk_buf[1024]; // Modify
asmlinkage int printk(const char *fmt, ...)
{
va_list args;
int r;
va_start(args, fmt);
r = vprintk(fmt, args);
va_end(args);
printascii(printk_buf); // Modify
return r;
}

static int recursion_bug;
static int new_text_line = 1;
//static char printk_buf[1024]; // Modify

->>
如上是Kernel 裁减移植过程中最重要的两个启动调试技术,灵活使用将带来工作效率的提升,不管硬件平台是那种ARM 或者其它类型的CPU ,也不管是哪个 Kernel 版本(如Linux-2.6.24 、
Linux-2.6.30 等都可以采用这两个启动调试技术解决实际问题。

为了支持 printascii() 函数,需要在 Kernel 裁减中(make menuconfig )添加Kernel hacking ->
Kernel low - level debugging functions 的支持。

我的补充:
1/ 可以在/kernel/head.s里添加打印看是否跑到mmu开启前:
__turn_mmu_on:
//打印一个字符a
mov r9,r0
mov r0,'a'
bl printascii //该函数位于arch/arm/kernel/debug.s,调用了 include/mach/debug-macro.S
mov r0,r9
//现在开启mmu
mov r0, r0
mcr p15, 0, r0, c1, c0, 0 @ write control reg
mrc p15, 0, r3, c0, c0, 0 @ read id reg
mov r3, r3
mov r3, r3
mov pc, r13 /*实际调用了__switch_data,在head-common.s*/
2/ 一般按楼上方法,在startkernel就可以打印出来,如果:在第一步可以打印,而开启mmu后不能打印,那绝对是虚拟地址映射问题,这个问题我搞了2天了....
3/ 如果还没有反应,就要检查串口打印那段 debug-macro.S 是否有问题了。

总结一下:
/compressed/head.s和/kernel/head.s基本上不用改,看文件头,2001年写的,就知道了.呵呵.。

相关文档
最新文档