天天看點

嵌入式程式設計中使用qemu能夠做什麼?嵌入式程式設計中使用qemu能夠做什麼?

嵌入式程式設計中使用qemu能夠做什麼?

  • 1.前言
  • 2.嵌入式的裸機或RTOS程式設計
  • 3.利用qemu網絡程式設計研究
  • 4.嵌入式圖形開發
  • 5.進行嵌入式Linux的開發
  • 6.小結

1.前言

嵌入式開發的過程中,很多時間都是要和硬體裝置打交道,通過程式控制硬體的具體行為,這些往往是單片機延續下來的開發模式,在目前複雜的嵌入式系統中,很多都需要借助設計模式來進行開發,比如檔案系統,網絡,圖形,算法等等,這些如果能夠利用軟體模拟器進行開發,可以大大的減少上闆調試的時間。減少硬體連接配接的煩惱,在家也能随時分析軟體代碼。

嵌入式程式設計中使用qemu能夠做什麼?嵌入式程式設計中使用qemu能夠做什麼?

在實際項目的開發過程中,qemu也非常的有用,例如當進行網絡程式設計時,往往都會直接使用socket程式設計,其上層接口符合POSIX接口,這樣上層應用的開發和底層驅動便可以很簡單的分離出來,将工作細節進行合理的劃分。而當進行嵌入式GUI程式設計設計時,也可以通過framebuffer,來進行各種界面的設計。同時,如果想新學習一款嵌入式程式設計語言,或者深入了解一些處理器的架構方面的知識,通過裸機程式設計,直接到qemu上運作也能夠非常友善的進行探究工作。

嵌入式程式設計中使用qemu能夠做什麼?嵌入式程式設計中使用qemu能夠做什麼?

下面舉出一些qemu實際好用的應用來進行詳細的描述。

2.嵌入式的裸機或RTOS程式設計

qemu的是指令翻譯進行的,是以可以根據實際的需求進行相應的裸機開發和學習,比如語言學習,嵌入式C語言,嵌入式RUST語言,等等項目。一些github上的好用學習型的項目也會對qemu進行支援,用RUST語言在arm上的程式設計,即使手上沒有很好的硬體的條件,也能夠去學習RUST語言在嵌入式程式設計上的使用。

針對arm的程式設計,qemu也可以模拟出許多的架構出來,通過對這些架構的學習和掌握,可以加快對架構程式設計的了解。

./qemu-system-arm -M virt -cpu ?
Available CPUs:
  arm1026
  arm1136
  arm1136-r2
  arm1176
  arm11mpcore
  arm926
  arm946
  cortex-a15
  cortex-a7
  cortex-a8
  cortex-a9
  cortex-m0
  cortex-m3
  cortex-m33
  cortex-m4
  cortex-m55
  cortex-m7
  cortex-r5
  cortex-r5f
  max
  pxa250
  pxa255
  pxa260
  pxa261
  pxa262
  pxa270-a0
  pxa270-a1
  pxa270
  pxa270-b0
  pxa270-b1
  pxa270-c0
  pxa270-c5
  sa1100
  sa1110
  ti925t
           

複制

然而嵌入式開發往往會和硬體打交道,qemu也提供了不同類别的硬體,比如flash,網卡,sd卡,中斷,序列槽等等,這些對于學習不同的體系架構,也有着非常關鍵的作用。

比如學習cortex-m3或者aarch64程式設計,采用qemu,運作自己寫的裸機代碼,能夠非常友善的進行各種實驗。

在進行rtos的開發過程中,經常會采用qemu作為調試工具,進行龍芯、樹莓派、riscv相關的開發和驗證工作。在rtos中,比較關鍵的是上下文的切換,通過對寄存器資訊的儲存和恢複,另外就是中斷的處理,能夠很好的了解架構的底層程式設計方式。

以前的時候,也做過aarch64上的qemu程式設計,也是最開始基于qemu,然後慢慢的移植到樹莓派上面,因為外設一緻,代碼層面不用改變,直接可以将qemu運作通過的固件放到樹莓派的sd卡中也一樣能夠正常的運作。

嵌入式程式設計中使用qemu能夠做什麼?嵌入式程式設計中使用qemu能夠做什麼?

上圖是在qemu的

rt-thread/bsp/raspberry-pi/raspi3-64

中編譯的固件在qemu上的運作效果,基本上完成對aarch64體系架構中的棧幀、中斷、mmu的支援,以及外設部分SD卡、圖形、序列槽、mbox的支援。該固件也可以直接放到樹莓派硬體的sd卡中運作,其效果和在qemu效果一樣。

除此之外,我也在qemu的支援上做了一些擴充開發,比如在riscv的生态支援上對gd32的rv-star在中科院軟體研究所的基礎上做了一些研究,同時對nuclei的各種處理器系列做了适配。這樣對于軟體層面的驗證更加有用,比如去運作一下nuclei-sdk,或者對于RISCV的V擴充的支援的nmsis的支援。

qemu-system-riscv64 -M nuclei_n,download=ilm -cpu nuclei-nx600fdp -nodefaults -nographic -serial stdio -kernel CMSIS/nmsis_release/NMSIS/DSP/Examples/RISCV/riscv_matrix_example/dsp_example.elf
           

複制

這樣可以進行相關的dsp的驗證工作。因為

nmsis

是基于arm的

cmsis

在riscv上的一份移植,其中實作了許多的加速運算的demo,比如矩陣運算,卷積,圖像處理等等,這些指令同樣也可以在nuclei qemu中計算出正确的結果。

嵌入式程式設計中使用qemu能夠做什麼?嵌入式程式設計中使用qemu能夠做什麼?

由于對riscv的p擴充和v擴充的支援,使得其行為和實際硬體闆子無差異。在qemu做算法優化和研究也是非常值得去嘗試的。雖然qemu是用軟體去模拟真實計算結果,但是從指令集的優化層面上來說,當功能邏輯實作正确後再移植到闆子上做性能測試,這才是高效的處理方法。

在支援baremetal程式設計和rtos程式設計方面,nuclei-sdk也做了一些工作,可以更加好的觀察分析軟體的具體行為。

qemu-system-riscv32 -M nuclei_n,download=ilm -cpu nuclei-n201 -nodefaults -nographic -serial stdio -kernel application/rtthread/msh/msh.elf
Nuclei SDK Build Time: May 31 2021, 11:48:18
Download Mode: ILM
CPU Frequency 168290222 Hz

 \ | /
- RT -     Thread Operating System
 / | \     3.1.3 build May 31 2021
 2006 - 2019 Copyright by rt-thread team
Hello RT-Thread!
msh >
msh >ps
thread   pri  status      sp     stack size max used left tick  error
-------- ---  ------- ---------- ----------  ------  ---------- ---
tshell     6  ready   0x000000d8 0x00001000    10%   0x0000000a 000
tidle      7  ready   0x00000078 0x00000200    23%   0x00000020 000
main       2  suspend 0x000000b8 0x00000400    17%   0x00000013 000
msh >
           

複制

也可以支援其他的rtos,例如下面的ucosii和freertos等等。

ucosii的運作效果如下:

qemu-system-riscv32 -M nuclei_n,download=ilm -cpu nuclei-n201 -nodefaults -nographic -serial stdio -kernel application/ucosii/demo/demo.elf
Nuclei SDK Build Time: May 31 2021, 11:49:45
Download Mode: ILM
CPU Frequency 182521692 Hz
Start ucosii...
create start task success
start all task...
task3 is running... 1
task2 is running... 1
task1 is running... 1
task3 is running... 2
task2 is running... 2
task3 is running... 3
task2 is running... 3
task1 is running... 2
task3 is running... 4
task2 is running... 4
task3 is running... 5
task2 is running... 5
           

複制

freertos的運作效果如下:

qemu-system-riscv32 -M nuclei_n,download=ilm -cpu nuclei-n201 -nodefaults -nographic -serial stdio -kernel application/freertos/demo/demo.elf
Nuclei SDK Build Time: May 31 2021, 11:49:45
Download Mode: ILM
CPU Frequency 232205516 Hz
Before StartScheduler
Enter to task_1
task1 is running 0.....
Enter to task_2
task2 is running 0.....
timers Callback 0
timers Callback 1
task1 is running 1.....
task2 is running 1.....
timers Callback 2
timers Callback 3
task1 is running 2.....
task2 is running 2.....
           

複制

利用qemu作為底層研究将會非常的高效。同時,善于借助gdb等調試工具,将能夠非常容易的找到問題出現的點。

3.利用qemu網絡程式設計研究

由于qemu的網絡可以直接連接配接主機的網絡,對這方面的研究可以從網絡協定棧,網絡的上層應用程式設計等等進行研究。例如去研究lwip協定棧的實作等等。

我寫過一個qemu上的e1000網卡裝置的驅動,針對于qemu riscv64的virt版本。

https://github.com/bigmagic123/rt-thread/tree/riscv_virt_network
           

複制

針對rt-thread的qemu riscv的virt64版本,可以進行如下的設定。

嵌入式程式設計中使用qemu能夠做什麼?嵌入式程式設計中使用qemu能夠做什麼?

其中其底層的驅動為e1000,為qemu提供了網絡資料的收發、以及網絡資料包的接收中斷服務。

借助rt-thread上适配的lwip驅動程式,可以非常容易的實作上層網絡程式設計應用。

比如借助rt-thread的IOT軟體包

嵌入式程式設計中使用qemu能夠做什麼?嵌入式程式設計中使用qemu能夠做什麼?

使能一些例子

嵌入式程式設計中使用qemu能夠做什麼?嵌入式程式設計中使用qemu能夠做什麼?

最後可以測試一下web的通信情況。

嵌入式程式設計中使用qemu能夠做什麼?嵌入式程式設計中使用qemu能夠做什麼?

當然,上述這個例子隻是一個非常簡單網絡程式設計的示範,其中socket的程式設計部分實際上是通用的,無論是arm架構、mips架構或者riscv架構,借助qemu的好處在于可以采用一個架構平台,進行協定棧或者上層開發後,可以無縫的移植到自己的真實的闆子上,非常友善進行整體業務的聯調。

對于qemu riscv64 virt平台,整個系統從底層的virtio或者e1000的網卡裝置提供資料的收發、中斷消息機制之外,rt-thread也通過提供lwip協定棧的支援,這樣整個網絡鍊路才是比較合理的。開發起來也比較的友善。

在物聯網子產品的開發方面,采用qemu,也可以不用rt-thread,直接裸機驅動virt上的e1000網卡驅動,然後借助對寄存器的讀寫操作,移植其他的網絡協定棧,進而實作網絡資料的收發工作,網絡程式設計的上層對接阿裡雲、騰訊雲等雲伺服器,非常容易的實作業務的程式設計,同時調試方面,qemu的gdb調試功能也是非常的強大,也可以dump出記憶體進行ram parse分析。

4.嵌入式圖形開發

因為嵌入式程式設計的實作,也會多少涉及到圖形程式設計,當接上LCD屏後,其中的顯示驅動對上層應用暴露出來的實際上是一塊顯存,通過對顯存的讀寫,flush進行lcd的圖像更新。

在圖像程式設計方面,qemu也提供了顯示視窗。這種顯示視窗可以為gui相關的開發工作帶來很多便捷。

關于嵌入式圖像程式設計,可以參考

rt-thread\bsp\raspberry-pi\raspi3-64
           

複制

相關的bsp,隻需要完善顯示程式即可。

可以尋找一張bmp的圖檔,圖檔大小為800x480的圖檔。

嵌入式程式設計中使用qemu能夠做什麼?嵌入式程式設計中使用qemu能夠做什麼?

利用Image2Lcd的工具進行圖像轉換成數組。

嵌入式程式設計中使用qemu能夠做什麼?嵌入式程式設計中使用qemu能夠做什麼?

最後将數組程式編譯到程式代碼中,将該數組放到顯存中即可。

嵌入式程式設計中使用qemu能夠做什麼?嵌入式程式設計中使用qemu能夠做什麼?

一切準備就緒後,就能夠進行顯示器的開發了。

#define LCD_BUF_SIZE  (800 * 480)
extern unsigned char gImage_1[];

void lcd_test()
{
    struct rt_device *lcd;
    struct rt_device_graphic_info *test_lcd_info;

    test_lcd_info = rt_malloc(sizeof( struct rt_device_graphic_info));
    //找到lcd    lcd = (struct rt_device *)rt_device_find("lcd");
    rt_kprintf("lcd get info:\n");
    rt_device_control(lcd, RTGRAPHIC_CTRL_GET_INFO, test_lcd_info);
    rt_kprintf("lcd width is %d\n", test_lcd_info->width);
    rt_kprintf("lcd height is %d\n", test_lcd_info->height);
    rt_kprintf("lcd bpp is %d\n", test_lcd_info->bits_per_pixel);

    rt_memcpy(test_lcd_info->framebuffer, &gImage_1[0], LCD_BUF_SIZE*4);
    //重新整理圖檔
    rt_device_control(lcd, RTGRAPHIC_CTRL_RECT_UPDATE, NULL);
    rt_thread_delay(20);
}
           

複制

如果要進行觸摸操作,qemu也進行了基本的支援,隻需移植相關的底層驅動即可進行開發工作,非常的高效和友善。

5.進行嵌入式Linux的開發

進行Linux開發工作,如果深入去學習某一個裝置的開發,當然少不了不斷的對Linux的核心部分進行編譯和下載下傳,這是一個十分耗時的工作,如果隻是進行應用程式的開發,可能感覺不到許多的差别,但是一旦涉及到Linux核心的分析,頻繁的下載下傳也會浪費大量的時間。

當使用qemu後,這種問題将會得到很好的解決,采用qemu進行核心層面的裁剪,進行核心層面子產品化的驗證工作後,再進行移植,讓其變得更加通用,不僅僅針對這個項目有效,而且也為自己積累了很多經驗。

嵌入式程式設計中使用qemu能夠做什麼?嵌入式程式設計中使用qemu能夠做什麼?

從分析linux的loader,分析Linux的驅動架構,記憶體管理,多核管理等等,都能夠非常友善進行調試工作。

在實際硬體裝置沒有穩定之前,對軟體項目進行評估,qemu是非常好用的工具。

6.小結

接觸很多軟體開發工作中,使用qemu确實能夠在一定程度上節省時間,提高軟體調試與分析的效率。

用軟體模拟硬體的操作行為,本質上來說和實際的硬體操作差別不大,因為在嵌入式程式設計中,最底層的指令集的行為已經在qemu中實作的很好了,硬體模拟方面,qemu也大緻能夠模拟操作寄存器後,處理器的行為,這些在對qemu的底層支援和學習的過程中已經進行了大量的實驗和研究。

了解qemu的使用,會對嵌入式軟體原理有着更加深刻的了解,從更大的層面上來說,虛拟化的行為本來就是一種很好的解決方案,去設計一個嵌入式軟體方案,去示範一個底層軟體,或者節約下載下傳調試時間,開發嵌入式上層業務系統軟體的功能層面來說,qemu都是值得去研究和使用的工具。