STM32F103 ucLinux开发之四(内核启动后的调试)

Stm32-uclinux启动后的调试

1、  修改__pfn_to_page使得能够启动

根据STM32F103 ucLinux开发之三(内核启动后不正常)的描述,内核无法启动是选择了平板内存模式后,下面两个宏定义,导致计算错误,从而Backtrace的。

#define __pfn_to_page(pfn)     (mem_map + ((pfn) - ARCH_PFN_OFFSET))

#define __page_to_pfn(page)  ((unsigned long)((page) - mem_map) + \

ARCH_PFN_OFFSET)

以上两个宏中用到的ARCH_PFN_OFFSET ->

#define ARCH_PFN_OFFSET              PHYS_PFN_OFFSET ->

#define PHYS_PFN_OFFSET      (PHYS_OFFSET >> PAGE_SHIFT) ->

#define PAGE_SHIFT                  12,

#define PHYS_OFFSET     (CONFIG_DRAM_BASE)

#define CONFIG_DRAM_BASE 0x20000000

经过这样一番推算,确实是0x2000 0

根据内存的分配,我修改这里,改为下面的:

#define __pfn_to_page(pfn)    (mem_map + ((pfn) - 0x68000))

#define __page_to_pfn(page)          ((unsigned long)((page) - mem_map) + \

0x68000)

这样,运行在片内FLASH的内核,运行在片外NorFlash的内核都可以正常启动了。

2、  微内核制作文件initramfs

微内核运行在片内的FLASH中,其中编译好的xipImage,里面包含一个压缩的cpio格式的initrd,这个initrd占据了一段空间,这样内核不能添加其它模块,而initrd也限制了大小,有必要将内核和initrd分离。

initramfs_data.cpio.gz与内核分离,放在片外的norflash,在populate_rootfs函数,解压initramfs_data.cpio.gz,实际是解压initrd_start开头的内容,挂载根文件,这样与Android的启动非常类似。需要做的修改:

修改1:\init\initramfs.c

//if (err)

//panic(err);

此处解压会出错,err返回一个大于0的数值,所以先注释掉。

修改2:原来编译busybox后,生成的 initramfs-filelist 文件,每次编译都会重新生成。将这个文件减少为4行,创建/   /dev   /rooot   /dev/console四个;

在vendors/STMicroelectronics/STM3210E-EVAL-MCU_Flash/gen-initramfs-filelist.sh文件中,除了第一行外,用if [0]; then限制,这样每次整个编译的时候,就不会修改内核目录linux-2.6.x下面的initramfs-filelist文件了

修改3:boot中的参数添加initrd=0x64200000,128K(暂定起始地址是0x6420 0000,大小是128K)。

initramfs_data.cpio.gz的解压与制作

解压缩:

gunzip   initramfs_data.cpio.gz

mkdir    temp

cd       temp

cpio    -i   -F  ../initramfs_data.cpio.gz --no-absolute-filename               //千万要加后面的--no-absolute-filename,不然虚拟机会处问题

重新压缩打包:

cd   romfs/

find . | cpio -o -H newc | gzip > ../initramfs_data.cpio.gz

3、  Busybox单独编译

原始编译过程中,busybox跟着一起编译,但是提供的命令非常有限,要添加命令,就需要单独编译busybox。需要做的修改:

修改1:编译命令为:

Make ARCH=arm CROSS_COMPILE=/root/CodeSourcery/Sourcery_G++_Lite/bin/arm-uclinuxeabi- ROOTDIR=/opt/stm32uclinux/uClinux-dist/

修改2:Makefile中修改CC等,加入CPUFLAG

CPUFLAGS := -march=armv7-m -mthumb

CC        = $(CROSS_COMPILE)gcc $(CPUFLAGS)

AS        = $(CROSS_COMPILE)as $(CPUFLAGS)

CXX       = $(CROSS_COMPILE)g++ $(CPUFLAGS)

AR        = $(CROSS_COMPILE)ar

LD        = $(CROSS_COMPILE)ld $(CPULDFLAGS)

OBJCOPY   = $(CROSS_COMPILE)objcopy

RANLIB    = $(CROSS_COMPILE)ranlib

ELF2FLT   = elf2flt

STRIPTOOL = $(CROSS_COMPILE)strip

STRIP     = $(STRIPTOOL)

4、  jfss2文件系统制作

运行在片外NorFlash的内核,挂载了jfss2格式的文件系统,而这个文件系统是只读的,调试应用程序的时候,就需要重新生成这样的文件系统,然后下载到norflash中。

假设当前目录下,包含romfs、原始的device.tab,则执行下面的命令,会生成rootfs.img.bin

/opt/stm32uclinux/uClinux-dist/user/mtd-utils/build/mkfs.jffs2 -D device.tab -o rootfs.img.bin -q -x rtime -x zlib -d romfs/

5、  如何调试,在片外SRAM运行,省去每次写Flash操作

无论是运行在片内、还是片外,每次少些内核都需要擦除和写入FLASH,这个时间比较长,不利于调试程序。而开发板有网口,可以在boot支持tftp下载,将内核下载到片外的SRAM中,然后boot跳转到SRAM中执行内核。

5.1 修改内核编译启动地址,让其在SRAM内运行

如下图所示,修改内核启动后的执行地址为0x6800 1000,让出前面4K的空间,用于存放boot参数信息等。

还要修改arch\arm\kernel\vmlinux.lds.S文件中,原来如下面所示,这样将数据段编译到了0x2000 0000开头的地方。

_etext = .;                           /* End of text and rodata section */

#ifdef CONFIG_XIP_KERNEL

__data_loc = ALIGN(4);            /* location in binary */

. = PAGE_OFFSET + TEXT_OFFSET;

#else

. = ALIGN(THREAD_SIZE);

__data_loc = .;

#endif

修改为下面这样的,这样数据段,就会更在内核代码段的后面,所有的内容都编译了片外SRAM。

_etext = .;                           /* End of text and rodata section */

#ifdef CONFIG_XIP_KERNEL

. = ALIGN(THREAD_SIZE);

__data_loc = .;

#else

. = ALIGN(THREAD_SIZE);

__data_loc = .;

#endif

5.2 无法运行时,修改中断向量位置

按照5.1那样,编译出来的中断向量也防止到片外。在arch\arm\mm\proc-v7m.S的__v7m_setup段,原来是下面所示,将中断向量的位置写入向量表基址寄存器,而内核编译到片外以后,这个地址vector_table也在片外。Stm32f103的中断向量不能防止到片外,这里需要修改。

@ Configure the vector table base address

ldr    r0, =0xe000ed08               @ vector table base address

ldr    r12, =vector_table

str    r12, [r0]

修改为下面这样,将编译好的中断向量表的内容复制到0x20008000开始的地方,然后将0x20008000设置到向量表基址寄存器

ldr    r0, =vector_table

ldr   r5, =0x20008000

Add  r6, r0, #0x120

1:      ldr    r12, [r0], #4

str    r12, [r5], #4

cmp r0, r6

bne  1b

@ Configure the vector table base address

ldr    r0, =0xe000ed08               @ vector table base address

ldr    r12, =0x20008000

str    r12, [r0]

5.3 修改norFlash文件系统分区,使得自行编译过的busybox文件系统可以运行

在drivers\mtd\maps\stm3210e_eval_mtd_map.c文件中,调整分区,如下所示。

static struct mtd_partition stm3210e_eval_flash_partitions [] = {

{

.name = "Kernel raw data",

.offset = 0,

.size = 0x00100000,

.mask_flags     = MTD_WRITEABLE, /* force read-only */

},

{

.name = "rootfs",

.offset = 0x00100000,

.size = 0x00C00000,

},

{

.name = "rawdata",

.offset = 0x00D00000,

.size = 0x30000,/* MTDPART_SIZ_FULL will expand to the end of the flash */

},

{

.name = "cramfs_partition",

.offset = 0x00D30000,

.size = 0x30000,/* MTDPART_SIZ_FULL will expand to the end of the flash */

},

};

将文件系统的大小由原来的384K,调整为12M,其它分区大小不变,位置需要跟着调整。

6、  三种方式运行速率

采用第5部分调试后,内核运行在了片外SRAM中。跟运行在片内Flash,片外的norflash中相比,速率有明显的差异,以BogoMIPS为比较,如下面所示。

片内:                           164864     32.97                 基本准确,时钟是72M

片外SRAM:                   9280         1.85

片外norflash:                4096         0.81

系统时钟是72M,所以运行在片内FLASH是正常的,而其它两个位置,速率都非常的慢,系统变得异常了。考虑到应用程序最终要运行在片外的SRAM中,而系统运行这么慢,所以这种方式不适合ucLinux开发,不再尝试了。下面给出一个异常的例子。

7、  串口的过载

微内核运行在片内的Flash中,initramfs启动后,在超级终端上输入命令,可以看到输出,然后点击PC键盘上的向上箭头,可以看到上一条输入的命令。

而无论运行在片外SRAM,还是norflash,挂载文件系统后,点击PC键盘上的向上箭头,都会打印出ttySA0 input overrun(s),意思就是传开口过载了。

跟踪程序发现,就是串口收到的字符没有来得及读取完毕,下一个字符有到来了,这样就会出现过载。而点击PC键盘上的向上箭头,串口会连续收到0x1B 5B 41 ,3个字节的数据。运行在片外SRM或者norflash中,系统缓慢到,连串口的3个字节数据都处理不了,其它的外设也许也会出现异常。

时间: 2025-01-05 17:25:03

STM32F103 ucLinux开发之四(内核启动后的调试)的相关文章

通过JTAG对比内核启动后text/rodata段内容

关键词:vmlinux.strip.dump._text.__end_rodata等等. 在日常的调试中,可能会在某些情况下踩到内核重要的数据,比如代码段或者rodata之类. 这种情况下,需要确认这些数据是否异常. 所谓的异常就是从DDR中读出的数据能否和vmlinux对上. 1. 准备vmlinux数据 原始的vmlinux文件,需要strip: strip vmlinux -o vmlinux_stripped 然后去掉vmlinux的0x1000头部. dd if=vmlinux_str

linux、内核源码、内核编译与配置、内核模块开发、内核启动流程(转)

linux是如何组成的?答:linux是由用户空间和内核空间组成的为什么要划分用户空间和内核空间?答:有关CPU体系结构,各处理器可以有多种模式,而LInux这样的划分是考虑到系统的安全性,比如X86可以有4种模式RING0~RING3  RING0特权模式给LINUX内核空间RING3给用户空间linux内核是如何组成的?答:linux内核由SCI(System Call Interface)系统调用接口.PM(Process Management)进程管理.MM(Memory Managem

自定义内核启动后的Logo

1.使用图像GIMP工具 2.详细步骤如下: A.将800x480的图片导入到GIMP工具. B.选中GIMP菜单栏进行以下操作 图像 -->模式 -->索引 .在弹出的窗口当中,选中调色板,最大颜色值修改为224. .点击[转换]按钮,退出. C.将文件"Export As"文件类型为ppm格式,并且文件名为:logo_linux_clut224.ppm,输出格式为ASCII,最后进行保存. D.将logo_linux_clut224.ppm拷贝到内核目录当中的drive

内核启动后,lcd显示logo失败

针对-s5pv210,但对其他平台也使用 lcd显示logo失败,若显示成功默认的logo是一只企鹅,但是串口打印"Start display and show logo",但是LCD屏没有显示 [ 0.833071] s3cfb s3cfb: [fb2] dma: 0x465ab000, cpu: 0xe1000000, size: 0x005dc000 [ 0.845112] FIMD src sclk = 166750000 [ 0.965701] s3cfb s3cfb: re

Linux内核启动及根文件系统载入过程

上接博文<u-boot之u-boot-2009.11启动过程分析> Linux内核启动及文件系统载入过程 当u-boot開始运行bootcmd命令,就进入Linux内核启动阶段.与u-boot类似,普通Linux内核的启动过程也能够分为两个阶段,但针对压缩了的内核如uImage就要包含内核自解压过程了.本文以linux-2.6.37版源代码为例分三个阶段来描写叙述内核启动全过程.第一阶段为内核自解压过程,第二阶段主要工作是设置ARM处理器工作模式.使能MMU.设置一级页表等,而第三阶段则主要为

Linux内核启动及文件系统加载过程

上接博文<u-boot之u-boot-2009.11启动过程分析> 当u-boot开始执行bootcmd命令,就进入Linux内核启动阶段,与u-boot类似,普通Linux内核的启动过程也可以分为两个阶段,但针对压缩了的内核如uImage就要包括内核自解压过程了.本文以项目中使用的linux-2.6.37版源码为例分三个阶段来描述内核启动全过程.第一阶段为内核自解压过程,第二阶段主要工作是设置ARM处理器工作模式.使能MMU.设置一级页表等,而第三阶段则主要为C代码,包括内核初始化的全部工作

I.MX6Q(TQIMX6Q/TQE9)学习笔记——内核启动与文件系统挂载

经过前面的移植,u-boot已经有能力启动内核了,本文主要来看下如何通过之前移植的u-boot来启动内核.如果按照前面的文章完成了LTIB 的编译,那么,Linux的内核应该就会出现rpm/BUILD/目录下,接下来,我们就开始移植这个3.0.35版本的内核到TQIMX6Q. 内核的编译 为了简化内核编译的过程,可以在内核目录下创建编译脚本,命名为build.sh,内容如下: [cpp] view plaincopy #!/bin/sh export ARCH=arm export CROSS_

Linux内核启动及加载根文件系统

</pre></h1><p><span style="font-family:KaiTi_GB2312;font-size:18px;">上接博文<<a target=_blank href="http://blog.csdn.net/gqb_driver/article/details/8931775" style="text-decoration: none; font-family: 'Mi

第3阶段——内核启动分析之创建si工程和启动内核分析(3)

目标: (1)创建Source Insight 工程,方便后面分析如何启动内核的 (2)分析uboot传递参数,链接脚本如何进入stext的 (3) 分析stext函数如何启动内核 1 创建内核source sight 工程 1.1 点击 "add all" 添加所有文件,后面再慢慢删去Arch目录和Include目录中与2440芯片没用的文件. 1.2 点击Remove Tree 删除Arch文件夹,再添加与2440相关的硬件核心代码以及其它公用的代码 Arch:包含了平台,处理器相