VELT-0.1.5開發:使用kgdb調試Linux核心,velt-0.1.5kgdb
VELT的全稱是Visual EmbedLinuxTools,它是一個與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進行嵌入式開發:外掛程式安裝》。下面是它的準系統:
支援x86 Linux,海思hi3516/hi3520,MinGW這幾個平台,提供這幾個平台的項目模板。
完成UBOOT的編譯,並根據編譯的錯誤資訊自動定位到相應的檔案位置。
完成LINUX核心的編譯,並根據編譯的錯誤資訊自動定位到相應的檔案位置。
在VS下完成Linux核心的配置。
不使用Makefile進行Linux應用程式的編譯。
使用Makefile進行Linux應用程式的開發。
使用SSH串連目標機器並用gdb進行應用程式的調試。
使用Telnet串連目標機器並用gdb進行應用程式的調試。
在VS中整合Linux終端(Poderosa),支援SSH/Telnet/Com,在開啟終端時自動將VS的變數匯出為bash裡的變數,如ProjectDir等。
接下來嘗試通過串口調試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兩個參數,前一個參數指明要使用的串口參數,後一個參數讓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 修改核心代碼
檢查了一下核心的代碼,在等待串連時核心停在了下面的位置:
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寄存器時總是返回無資料的結果。
進一步的檢查發現這個時候串口的接收使能是關閉的,而發送使能則是開啟的!因此串口當然只能發送資料不能接收了!
不太想追究為什麼會這樣,直接在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();}}
修改了這一行:
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,這樣我們就可以在目標機器上執行一些簡單的調試命令了,也不需要依賴於主機上的gdb。
但由於我們希望通過gdb結合源碼進行調試,因此不選擇kdb,僅僅用kgdb。