VELT-0.1.5开发:使用kgdb调试Linux内核
VELT的全称是Visual EmbedLinuxTools,它是1个与visual gdb类似的visual studio插件,用以辅助完成Linux开发。利用这个插件,将可以在visual studio的IDE中进行Linux利用程序的开发(包括编译和调试),也能够进行uboot和linux内核的编译,并根据编译时的毛病信息正肯定位到源码。目前的版本是0.1.4,仅支持vs2013。此插件可以在CSDN下载频道下载(http://download.csdn.net/detail/lights_joy/8429771),安装进程参见《用vs2013+velt-0.1.4进行嵌入式开发:插件安装》。下面是它的基本功能:
接下来尝试通过串口调试Linux内核。 以hi3520的内核为实验对象。 1.1 打开内核的调试开关首先打开内核的调试开关: 加上内核的调试信息: 打开kgdb 1.2 引导参数配置在UBOOT下配置传递给内核的参数: Kernel command line: mem=127m console=ttyAMA0,115200ip=192.168.110.10:::255.255.255.0::eth0: root=mtd:work02 init=/sbin/initmtdparts=hi_sfc:256K(uboot01),64K(env01),64K(sysinfo01),3712k(configs01),8M(boot01),20M(work01),256K(uboot02),64K(env02),64K(sysinfo02),3712k(configs02),8M(boot02),20M(work02)kgdboc=ttyAMA0,115200 kgdbwait 这里最重要的是kgdboc和kgdbwait两个参数,前1个参数指明要使用的串口参数,后1个参数让kgdb在内核启动的时候进行等待。 加载内核: kgdb: Registered I/O driver kgdboc. kgdb: Waiting for connection from remote gdb... 然后系统开始等待。 1.3 用MinGW gdb连接内核直接用MinGW gdb打开编译内核时生成的vmlinux文件, 然后用 target remote COM1 连接串口,很遗憾,超时!
1.3 修改内核代码检查了1下内核的代码,在等待连接时内核停在了下面的位置: static int gdbstub_read_wait(void)
{
int ret = dbg_io_ops->read_char();
while (ret == NO_POLL_CHAR)
ret = dbg_io_ops->read_char();
return ret;
}
它将不停地查询串口上是不是有数据,刚开始时怀疑是串口参数配置不正确致使读取不到数据,但跟踪进去后发现这里的read_char可以正确地调用串口驱动(amba-pl011.c)中的查询函数: static int pl010_get_poll_char(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int status,ena_status;
status = readw(uap->port.membase + UART01x_FR);
ena_status = readw(uap->port.membase + UART011_CR);
if (status & UART01x_FR_RXFE)
return NO_POLL_CHAR;
return readw(uap->port.membase + UART01x_DR);
}
只不过在读取UART01x_FR寄存器时总是返回无数据的结果。 进1步的检查发现这个时候串口的接收使能是关闭的,而发送使能则是打开的!因此串口固然只能发送数据不能接收了! 不太想追究为何会这样,直接在shutdown函数中打开接收使能: static void pl011_shutdown(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
/*
* disable all interrupts
*/
spin_lock_irq(&uap->port.lock);
uap->im = 0;
writew(uap->im,uap->port.membase + UART011_IMSC);
writew(0xffff,uap->port.membase + UART011_ICR);
spin_unlock_irq(&uap->port.lock);
pl011_dma_shutdown(uap);
/*
* Free the interrupt
*/
free_irq(uap->port.irq,uap);
/*
* disable the port
*/
uap->autorts = false;
writew(UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_RXE,uap->port.membase + UART011_CR);
/*
* disable break condition and fifos
*/
pl011_shutdown_channel(uap,uap->lcrh_rx);
if (uap->lcrh_rx != uap->lcrh_tx)
pl011_shutdown_channel(uap,uap->lcrh_tx);
/*
* Shut down the clock producer
*/
clk_disable(uap->clk);
if (uap->port.dev->platform_data) {
struct amba_pl011_data *plat;
plat = uap->port.dev->platform_data;
if (plat->exit)
plat->exit();
}
}
修改了这1行: writew(UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_RXE,uap->port.membase + UART011_CR); 原来的代码是这样的: writew(UART01x_CR_UARTEN | UART011_CR_TXE,uap->port.membase + UART011_CR); 直接给上加上使能标记! 再履行gdb的target remote COM1命令,可以正常连接了!!
1.5 kdb在HI3520的内核中已带了kdb的支持: 当选上最下面的那个选项时将启用kdb,这样我们就能够在目标机器上履行1些简单的调试命令了,也不需要依赖于主机上的gdb。 但由于我们希望通过gdb结合源码进行调试,因此不选择kdb,仅仅用kgdb。 ?? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |