BIOS知识枝桠——PCD
PCD
- PCD Overview
- PCD TYPES
- PCD LIBRARY
- PCD instrument
- FixAtBuild PCD SYNTAX
- PCD SOFTWARE
- Fixed PCD AutoGen Code
- DYNAMIC PCD
- Special PCD
PCD Overview
PCD的主要目的就是把代碼里面的可配置選項(xiàng)抽取出來,抽取出來的好處是倘若平臺真的需要一些配置的時(shí)候,不需要修改源碼,通過修改dsc把這些東西影響到,是最好的。這個(gè)PCD不止是要在編譯過程中可以配置,還可以在運(yùn)行時(shí)配置。
配置PCD有幾種方式,目的是讓platform時(shí)候更為容易進(jìn)行定制化,減少effect
1:在build time時(shí)候,通過編譯選項(xiàng)或者dsc的值進(jìn)行設(shè)置從而影響源碼;
2:在Boot過程中,通過某個(gè)Driver生成某種狀態(tài)更改PCD的某些值;
3:作為BIOS,release出來的binary image也要提供可配置性。
PCD數(shù)據(jù)庫保存所有動(dòng)態(tài)類型的PCD信息。 PEI PCD數(shù)據(jù)庫的結(jié)構(gòu)是由構(gòu)建工具根據(jù)指定平臺的動(dòng)態(tài)PCD使用情況生成的。 動(dòng)態(tài)PCD,主要用作boot過程中相互進(jìn)行交互溝通的一種方式,初始值肯定也是在build時(shí)候就設(shè)置好了。動(dòng)態(tài)類型PCD用于動(dòng)態(tài)確定值的配置/設(shè)置。 相反,靜態(tài)類型PCD (FeatureFlag, FixedPcd, PatchablePcd)的值在構(gòu)建時(shí)固定在最終生成的FD映像中。
PCD TYPES
FixedAtBuild PCD:值是在build time 時(shí)候就定好了的,在binary階段是不可以改的,整個(gè)boot level也是不可以改的,可以認(rèn)為就是一個(gè)宏,const 全局變量。這個(gè)PCD有一個(gè)好處,是一個(gè)module level的,非系統(tǒng)級別的,即是說不同模塊可以配置不同PCD的值,典型的例子就是DEBUG Message 是否要輸出Message的問題,這是由一個(gè)PCD來control的,由于是模塊級別的,所以可以控制一個(gè)模塊輸出一個(gè)模塊不輸出。
FeatureFlag(control feature Boolean類型) 和FixAtBuild 是一類,可以認(rèn)為是BOOLEAN類型的FixedAtBuild,只是支持靜態(tài)build time的設(shè)置,而且是module level的。
PatchableInModule:module level,它可以patch(binary level 的patch),在boot time 也可以修改,但是能影響的也只是一個(gè)模塊,一個(gè)Driver,在這個(gè)模塊的修改不會影響到其他模塊,相當(dāng)于一個(gè)inf文件的source范圍,但是和FixAtBuild不同的是,這只是一個(gè)全局變量,并不是const類型的,binary level可以修改的。
Dynamic/DynamicEx:動(dòng)態(tài)的PCD,在整個(gè)boot過程中,有人set有人read,是可以一直修改的,作用域是system,system level,意思就是在整個(gè)BIOS,所有的模塊訪問Dynamic的PCD,都是共享的同一個(gè)值,某模塊的修改會導(dǎo)致其他模塊獲取到的值也發(fā)生變化。Dynamic 又有三個(gè)子類:DynamicHII、DynamicVpd、DynamicEx
Dynamic與DynamicEx的區(qū)別:如果只是做source 的build就是說platform是從源碼build出來的,沒有binary在里面的時(shí)候,PCD用的都是Dynamic這種類型,如果在BIOS里面有一些模塊是binary方式集成進(jìn)來的而這些binary又需要用到PCD,那么這些Binary集成的要用到的PCD就必須要設(shè)置為Dynamic類型,這就是Dynamic與DynamicEx之間的區(qū)別。
Dynamic:PCD的值可以認(rèn)為存在于hob或者memory中,會導(dǎo)致在下次啟動(dòng)時(shí)丟失上一次的值,獲取到的是新define的值。
DynamicHII的關(guān)于PCD的值存在于EFI Variable中,可能對應(yīng)的是一個(gè)NV的,non-volatile 的,即在某次PCD的值發(fā)生set之后,下次啟動(dòng)仍然是本次set的值。
DynamicVpd是屬于另一種,ReadOnly,這個(gè)PCD的值存在VPD空間的,VPD是放在FLASH上的只讀的,通常來說是一些系統(tǒng)的Default Section,工廠出廠的一些配置存放在這里,屬于必不會被修改的。
PCD LIBRARY
為了方便code的編寫,對PCD的使用引入PCDlib,這里面包含了常用的PCD接口,故而不用去可以學(xué)習(xí)內(nèi)部實(shí)現(xiàn)是調(diào)用PPI 、Protocol或是直接映射,這些都被LIb隱藏了,所以在使用過程中,只需要關(guān)注PCD Protocol 和PCD PPI FUNCTION:PcdGetXX()、PcdSetXX()、 PcdGetExXX()、 PcdSetEx()、 PcdToken()、 PcdSetSku()、 PcdGetNextToken() 、PcdGetNextTokenSpace()、 CallBackOnSet() 、CancelCallBack() 。【“XX" = 8 16 32 Size Ptr Boolean】
PCDgetXX()和PCDSetXX()是用得最多的,屬于統(tǒng)一化的API接口,無論哪一種Type都可以使用這兩個(gè),使用時(shí)會根據(jù)你具體Type類型,把這個(gè)Function map in到具體的PCDType所對應(yīng)的值的上面。
PCD instrument
FixAtBuild PCD SYNTAX
Define : PCD 在.DEC文件中進(jìn)行聲明,就涉及到了Package,所以說PCD是一個(gè)Package的interface,就是說PCD是Package對外提供的接口之一。在定義過程中有兩個(gè)需要注意的information,TokenSpaceGuid(PCD GUID說明到底在哪個(gè)Space 空間里)和TokenName(PCD 名字),這兩個(gè)決定了PCD的唯一性,不可以重復(fù),也不可以輕易改變。
Value為Default Value,Datum Type描述的是數(shù)據(jù)類型 UINT 8 16 等,倘若是VOID * 還得在[MaxSize]中填入這塊Buffer的最大值128 256等,最后一個(gè)為Token number UINT32的。
[Guids.common] PcdTokenSpaceGuidName = { 0xXXXXXXXX, 0xXXXX, 0xXXXX, { 0xXX, . . .}} . . . [Pcds...] PcdTokenSpaceGuidName.PcdTokenName|Value[|DatumType[|MaxSize]]|TokenReference:PCD在.inf文件中進(jìn)行使用。在inf里一般來說有個(gè)Pcd Section,只要把這個(gè)PCD列上去就行了,通常也不會寫值
[…Pcd…] PcdTokenSpaceGuidName.PcdTokenName|[Value]Modify:PCD在.DSC文件中進(jìn)行配置,在這里會決定PCD的值和類型,若PCD在.DEC文件中進(jìn)行了定義,在inf文件中使用,但在DSC中并沒有重新set,這時(shí)候PCD就會使用默認(rèn)值(.DEC的Value),類型則是支持的最初的類型,類型也是有一個(gè)優(yōu)先級,優(yōu)先考慮FixAtBuild,其次PatchInModule,然后Dynamic,DynamicEx。
[Pcds...] PcdTokenSpaceGuidName.PcdTokenName|Value[|DatumType[|MaximumDatumSize]]For Example:
Defined:(.dec) [PcdsFixedAtBuild, PcdsPatchableInModule]->支持的兩種類型 gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x400|UINT32|0x30000003Referenced:(.inf) MdeModulePkg\Universal\Variable\RuntimeDxe\VariableRuntimeDxe.inf [Pcd]gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize ## CONSUMESModified:(.dsc) [PcdsFixedAtBuild] gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x00840 ->將0x400改為0x8400Use:(.c) MdeModulePkg\Universal\Variable\RuntimeDxe\VariableNonVolatile.c // max NV variable size mVariableModuleGlobal->MaxVariableSize = PcdGet32 (PcdMaxVariableSize)->UINT32 使用PcdGet32()PCD SOFTWARE
PCD起作用并不是簡簡單單通過上述步驟就可以實(shí)現(xiàn)的, 在文件中描述完畢后通過Parsing Tool(實(shí)際就是Build Tool)進(jìn)行parse,生成對應(yīng)的AutoGen code,在code里面可以以PCD類型生成不同的PCD原型,然后被PCD Lib里的PCDGet32()、PCDGet16()等不同的function進(jìn)行引用,而Driver Source Code里面,調(diào)用函數(shù)所用到的就是AutoGen中通過Build Tool生成的值,或是訪問的方法。
關(guān)于動(dòng)態(tài)的PCD,通過 build后parse,拿到所有的動(dòng)態(tài)PCD,然后生成到Database里面,Compiler到一起,最后生成Driver Binary。存儲在PE32 space,通過隔離Database,使得PCD的值可以進(jìn)行修改替換,達(dá)到動(dòng)態(tài)目的。
Fixed PCD AutoGen Code
For Example:
Example : MdeModulePkg\Universal\Variable\RuntimeDxe\VariableRuntimeDxe
Autogen.h
Autogen.c
// Definition of PCDs used in this module ? ? ? GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaxVariableSize = _PCD_VALUE_PcdMaxVariableSize;--->生成的GLobal Variable呼應(yīng).h中的宏DYNAMIC PCD
For Example:
Defined:(.dec) [PcdsDynamic]->支持類型 gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|0xffff|UINT16|0x30000001Modified:(.dsc) [PcdsDynamicDefault]->在Dynamic Default這種Section下 gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|03Setting:(.c) OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c PcdStatus = PcdSet16S (PcdPlatformBootTimeOut,GetFrontPageTimeoutFromQemu ());Use:(.c) OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c Timeout = PcdGet16 (PcdPlatformBootTimeOut);Example Module: (OvmfPkg\Library\PlatformBootManagerLib)
Autogen.h ? ? ? #define _PCD_SET_MODE_16_PcdPlatformBootTimeOut(Value) LibPcdSet16(_PCD_TOKEN_PcdPlatformBootTimeOut, ( Value )) #define _PCD_SET_MODE_16_S_PcdPlatformBootTimeOut(Value) LibPcdSet16S(_PCD_TOKEN_PcdPlatformBootTimeOut, ( Value )) DYNAMIC PCD AUTOGEN FILESAutogen.c:Example Module: (MdeModulePkg/Universal/PCD/Dxe/Pcd)
DXE_PCD_DATABASE_INIT gDXEPcdDbInit = { ? ? ? /* LocalTokenNumberTable */ ? ? ? offsetof(DXE_PCD_DATABASE, Init.PcdPlatformBootTimeOut_*1) | PCD_TYPE_DATA | PCD_DATUM_TYPE_UINT16, ? ? ? { 0x3U } /* PcdPlatformBootTimeOut_*1 { 0x3U } [1] */*1 GUID of PCD Variable PcdPlatformBootTimeOutSpecial PCD
PCD的高級用法,確實(shí)能解決platform porting1過程中的一些問題,但相對來說比較復(fù)雜,所以并沒有大范圍推廣。
Multi-Structure PCD:C data structure and assign the value to each sub-field directly
這個(gè)PCD解決的問題是當(dāng)一個(gè)PCD和一個(gè)EFI Variable進(jìn)行關(guān)聯(lián)的時(shí)候,通常一個(gè)EFI Variable里面是一個(gè)C的Structure,就有可能關(guān)聯(lián)到這個(gè)C Structure的某一個(gè)field,這時(shí)候就需要知道這個(gè)Struct的offset在哪里,這個(gè)對于維護(hù)和開發(fā)會帶來難度,由于并不知道Struct的offset是多少,且當(dāng)Struct改動(dòng)之后關(guān)于PCD 的dsc也要進(jìn)行修改,倘若有很多field需要使用,則需要定義更多的PCD,加大code的復(fù)雜度,故而引入MUlti—Structure PCD。本身而言,只是一個(gè)VOID * 的PCD,這個(gè)PCD mapping 到一個(gè)Structure,以后訪問該P(yáng)CD就相當(dāng)于訪問Structure,訪問Structure中的每個(gè)field就相當(dāng)于訪問PCD然后通過PCD引用相應(yīng)的field。
為了更容易使用Structure PCD,需要DSC能夠支持對每個(gè)field的賦值,在C code能直接引用PCD,然后再把PCD mapping成一個(gè)structure,按照structure layout去訪問每個(gè)field,總的來說,為了使單個(gè)域在dsc里面能夠賦值,而且整個(gè)PCD在DSC里面也能賦值,這樣就把所有的Structure賦值挪到DSC里面,就不需要在C source里面做。同時(shí)即便Structure修改了 DSC也不需要做任何改動(dòng),
Multi-Sku PCD:Multiple configurations generated at build time & set @ run time, (PI Spec Vol 3 chap. 8)
倘若有一個(gè)很大的Structure,如Platform 的setup的structure,這個(gè)Structure可能在一個(gè)平臺有不同版本的board,每個(gè)board里面可能有一些細(xì)微的差別,可能會導(dǎo)致這個(gè)Setup的structure可能有些不同,這種情況下按照原來的配置方法可能要?jiǎng)?chuàng)建好幾個(gè)DSC,每個(gè)DSC里面對PCD設(shè)置不同的值,相對來說比較復(fù)雜。那么這個(gè)PCD相當(dāng)于有一個(gè)base,根據(jù)board的差異繼承base數(shù)據(jù)然后只改差異的地方,支撐整個(gè)Structure。
DefaultStoresPCD:Support the default stores concept in UEFI specification, (UEFI, HII Chap. 32)
HII在啟動(dòng)起來之后有Reset to default等選項(xiàng),用戶可能在對setup選項(xiàng)進(jìn)行修改之后,發(fā)現(xiàn)系統(tǒng)出現(xiàn)了各種各樣的問題,這時(shí)候可能需要恢復(fù)到初始狀態(tài),選擇reset to default標(biāo)準(zhǔn)的,相當(dāng)于重置設(shè)置,另外一種manufaction default,相當(dāng)于恢復(fù)出廠設(shè)置,那么這個(gè)值用StructPCD描述出來,根據(jù)對象為標(biāo)準(zhǔn)default還是manu default寫入DSC里面,倘若需要使用,則進(jìn)行配置使用即可。
For Example:聲明一個(gè)structurePCD然后對每個(gè)Field進(jìn)行賦值,Structure為:SMBIOS_TABLE_TYPE0。
gAdvancedFeaturePkgTokenSpaceGuid.PcdSmbiosType0BiosInformation| \{0x0}|SMBIOS_TABLE_TYPE0|0x80010000 { <HeaderFiles>IndustryStandard/SmBios.h <Packages>MdePkg/MdePkg.decAdvancedFeaturePkg/AdvancedFeaturePkg.dec }gAdvancedFeaturePkgTokenSpaceGuid.PcdSmbiosType0BiosInformation.Vendor|0x1 gAdvancedFeaturePkgTokenSpaceGuid.PcdSmbiosType0BiosInformation.BiosVersion|0x2 gAdvancedFeaturePkgTokenSpaceGuid.PcdSmbiosType0BiosInformation.BiosSegment|0xF000 gAdvancedFeaturePkgTokenSpaceGuid.PcdSmbiosType0BiosInformation.BiosReleaseDate|0x3 gAdvancedFeaturePkgTokenSpaceGuid.PcdSmbiosType0BiosInformation.BiosSize|0xFF gAdvancedFeaturePkgTokenSpaceGuid.PcdSmbiosType0BiosInformation.BiosCharacteristics.\ PciIsSupported|1 gAdvancedFeaturePkgTokenSpaceGuid.PcdSmbiosType0BiosInformation.BiosCharacteristics.\ PlugAndPlayIsSupported|1總結(jié)
以上是生活随笔為你收集整理的BIOS知识枝桠——PCD的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python正整数平方根_Python3
- 下一篇: 谈谈web打印快递单及经验