|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。: Q9 I/ r7 X( Q) N. Z: \, {
0 Q2 g7 ]/ s2 U/ H: _, Z5 u
SEC/CEI:
& D0 A! Q% _9 w* ^$ M0 F+ E UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
! p: m% c0 K: S( X在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
1 [. A- w& V! Z. C& J" ]! r
4 |! V; G, H. x; aPEI:/ P2 S5 K/ ?: B9 A2 V5 a0 p* O
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
3 ?8 a2 f C X- p1 M6 Y8 B; z EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。6 s- b' v6 ^3 ~7 K( }2 j, B0 {
InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
y% ~4 H5 | ?% _; d* L% k) }: U InitializeSercurityService函数,将Notify队列清空。' s& F" {+ Y2 a9 E5 O! h
InitializeDispatcherData函数,将Dispatcher队列清空。: C+ Z3 Z9 Z" T, u8 E! [7 k4 p# o& V/ o
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。# g& A" W- c5 R: y: @7 G
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
3 o7 \0 P3 d4 v" |# |* S EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {. U! u' e0 I8 |" a* e, _0 t& Y. Q
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},4 x6 ?+ [* n* N1 n5 c8 C
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},, Y6 O+ T' n4 k2 [" K \# x
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},; V4 q6 S! m( v6 Y5 @: D3 X
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
I! A& o+ V: l8 E. G$ } {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
( B& W s0 |: e# D1 D, m% `) _ {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
6 i3 K5 P: J6 A- \& j$ G };; k8 i% Q/ w" x: N) ]8 V& p
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
$ D7 |. E! _: {* }" R: B* @6 \ 这些PPI会在PEIDispatcher中用到。! L# z) g2 \3 I1 X8 u
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
- x. _2 A! L4 G, q 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
0 M6 x! b; |4 f# k! S# m SwitchStacks (/ O- {' Z! ^$ \# d" j' Y: _) [8 P
(VOID *) (UINTN) DxeCoreEntryPoint,( ^; v$ c1 u% Q$ J
(UINTN) (HobList.Raw),
& b i" C0 _9 u( X0 N) J: \ c (VOID *) (UINTN) TopOfStack,( C6 D4 [# }( O- x! y! {
(VOID *) (UINTN) BspStore
2 ~) S2 A2 y( ?4 p; x* F );
+ U/ I! @% Q( c/ @2 G! q 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)( S) V/ B8 A3 Z
8 W" {9 C- S7 W6 zDXE:! ?, }2 `* m0 {& Y7 L" {
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
& m6 g- q, y. W! w+ Y4 r接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
+ _, R- }3 e0 k) x8 W 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
; g2 @ b) a0 B! T x1 `中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。8 ^4 d; L! X8 |
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
9 E9 b' E" x5 e
: m" x# v6 Z% N [Driver:
1 ~) _9 m9 x7 G( a1 s& ^ 我们的驱动什么为在PEI和DXE等不同阶段执行呢?" D- A! } w+ _, x
大家请看一下我们的驱动的makefile.(EDK中的*.inf), p9 Z% |8 v3 |2 ]5 X5 M
[defines], E3 B$ @# Y, Z& k( X1 c
BASE_NAME = OWEN
8 U# V6 H- n0 A7 s FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
7 T& z+ z k' T0 Z9 v: O COMPONENT_TYPE = BS_DRIVER, u3 u: }; C8 H4 k: K |
1 C/ c9 I, T9 j- ^- S- _, C: ? BASE_NAME告诉编译器最终生成的驱动的名字。
4 D0 ^8 E! w" V. S% ? FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
( V8 q- p6 D# h COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。5 k4 n4 P0 i1 u$ J" k
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名: @* _3 |, d4 b* _+ }, s
COMP_TYPE_EXTENSION mCompTypeExtension[] = {# `" A7 w8 w& g' A! w
{"bs_driver", ".dxe" },1 h2 o5 Z6 p3 t- b. v* ?
{"rt_driver", ".dxe" },
" R3 g4 K4 y6 s# K {"sal_rt_driver", ".dxe"},
- P8 ^5 O, A3 o, }' |; i3 i7 ?! T {"security_core", ".sec"},
+ g% \, F' j' T5 j9 B {"pei_core", ".pei"},' a+ r* ?- ~' r3 w/ y& p9 q2 V+ f7 k
{"pic_peim", ".pei"},+ Z1 F- [+ k. r: W
{"pe32_peim", ".pei"},
& q }9 p: V" B( p1 O5 o7 w' B {"relocatable_peim", ".pei"},; m! g, F# N3 x3 l* R
{"binary", ".ffs"},* k g9 ^( s2 H" J7 I) c1 ?
{"application", ".app"},! k. z* s/ ^* n4 }
{"file", ".ffs"},
" Z8 i S* i1 V. B) {$ v! c) ] {"fvimagefile", ".fvi"},
S2 q- d+ \; } {"rawfile", ".raw"},
& ^2 y( [ B- q E5 B {"apriori", ".ffs"},
4 Y+ Q3 R* b% U$ Q$ e- G {"combined_peim_driver", ".pei"},7 } I( `0 D) P6 P% B% ^. ^9 \
{ NULL, NULL }: j' F6 j/ C5 Y+ \' z8 j5 ?
};
6 x, |- _! D9 _3 m7 _% t7 s* w) ]3 }4 S/ V
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)! x1 O) T2 Y; o
& H4 K- l% x9 A
$ q# r+ t8 }" u% c
|
|