- QEMU/KVM源碼解析與應用
- 李強編著
- 1143字
- 2021-08-24 11:53:39
2.3 QEMU參數解析
本節對QEMU參數解析進行簡要介紹,幫助讀者將QEMU命令行參數與其代碼中的實現聯系起來,方便閱讀代碼,但是由于參數解析并非本書重點,因此不會對具體的細節進行深入講解。本節使用的QEMU命令如下。

QEMU使用QEMUOption來表示QEMU程序的參數選項,其定義如下。

其中,name表示參數選項的名字;flags表示選項中一些參數選項的屬性,比如是否有子參數;arch_mask表示參數支持的體系結構。
vl.c在全局范圍定義了一個qemu_options,存儲了所有的可用選項,main函數中會調lookup_opt來解析QEMU命令行參數,不在qemu_options中的參數是不合法的。

qemu_options的生成使用QEMU_OPTIONS_GENERATE_OPTIONS編譯控制選項以及一個文件qemu-options-wrapper.h填充。在qemu-options-wrapper.h中,根據是否定義QEMU_OPTIONS_GENERATE_ENUM,QEMU_OPTIONS_GENERATE_HELP,QEMU_OPTIONS_GENERATE_OPTIONS以及qemu-options.def文件可以生成不同的內容。qemu-options.def是在Makefile中利用scripts/hxtool腳本根據qemu-options.hx文件生成的。
在這里只需要理解qemu_options中包括了所有可能的參數選項,如上面的-enable-kvm、-smp、-realtime、-device等即可。圖2-13顯示了gdb中部分qemu_options的值。

圖2-13 QEMU參數選項
QEMUOption提供了參數的基本信息情況。實際參數的保存是由3個數據結構完成的。
QEMU將所有參數分成了幾個大選項,如-eanble-kvm和-kernel都屬于machine相關的,每一個大選項使用結構體QemuOptsList表示,QEMU在qemu-config.c中定義了vm_config_groups。

這表示可以支持48個大選項。在main函數中用qemu_add_opts將各個QemuOptsList添加到vm_config_groups中。

每個QemuOptsList存儲了大選項支持的所有小選項,如-realtime大選項定義如下。

-realtime只支持一個值為bool的子選項,即只能有-realtime mlock=on/off。但是像-device這種選項就沒有這么死板了,-device并沒有規定必需的選項,因為設備有無數多種,不可能全部進行規定,解析就是按照“,”或者“=”來進行的。每個子選項由一個QemuOpt結構表示,定義如下。


name表示子選項的字符串表示;str表示對應的值。
QemuOptsList并不和QemuOpt直接聯系,中間還需要有一層QemuOpts,這是因為QEMU命令行可以指定創建兩個相同的設備,此時這類設備都在QemuOptsList的鏈表上,這是兩個獨立QemuOpts,每個QemuOpts有自己的QemuOpt鏈表。QemuOpts結構如下。

head是QemuOpts下的QemuOpt鏈表頭;next用來連接相同QemuOptsList下同一種Qemu Opts。
QemuOptsList、QemuOpts與QemuOpt三者的關系如圖2-14所示。

圖2-14 QemuOptsList、QemuOpts與QemuOpt三者關系
這里以-device參數項為例簡單分析參數的處理過程,vl.c中的main函數中有一個很長的for循環來解析參數,當解析到"-device"時,下面是對QEMU_OPTION_device的分支處理。

qemu_find_opts函數從全局變量vm_config_groups中找到剛才插入的device QemuOptsList并返回。qemu_opts_parse_noisily函數只是簡單調用了opts_parse,后者解析出一個QemuOpts,每一個大類的參數(如-device edu)都會在相應的QemuOptsList下面構造處理一個Opts。


opts_parse函數調用的最重要的兩個函數是qemu_opts_create和opts_do_parse,前者用來創建opts并且將它插入到QemuOptsList上,后者則開始解析出一個一個的QemuOpt。opts_do_parse的作用就是解析參數的值,如本節開始的命令行參數ivshmem,shm=ivshmem,size=1。QEMU的參數可以有多種情況,比如foo,bar中foo表示開啟一個flag,也有可能類似于foo=bar,對此opts_do_parse需要處理各種情況,并對每一個值生成一個QemuOpt。關鍵代碼如下。


該函數首先根據各種情況(foo,bar或者foo=bar,more)解析出option以及value,然后調用opt_set,在該函數中會分配一個QemuOpt結構,并且進行初始化。例子中的ivshmem,shm=ivshmem, size=1會解析出3個QemuOpt,name=str分別是driver=ivshmem、shm=ivshmem、size=1。所以對于兩個device的參數解析會形成圖2-15所示的鏈表。

圖2-15 QEMU參數解析結果