|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
3 C& e* F) _6 C8 U" _& e6 V" @5 E8 k7 G- N/ o: p
SEC/CEI:" Y. A& z8 }; I' v, S
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
5 Z. [* w8 \# A, H# W! o在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).+ ]3 ?0 p! J5 |1 R! S4 H9 H
4 g' O9 ~6 s9 j0 W
PEI:
0 F3 k5 E* l6 P |0 M 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行% d. _* S- E6 y* Q4 T
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
1 n) N& [# y7 B* b+ m9 U2 u InitializePPIService函数,将PPI队列清空,这个队列长0x3F./ k; [9 C5 q. R! |& w% E* L
InitializeSercurityService函数,将Notify队列清空。% Y2 l! i" N" n3 V7 n
InitializeDispatcherData函数,将Dispatcher队列清空。$ b5 v; M# a- c5 g
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
3 n# g" d+ c6 r. U$ ? 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
1 E4 ?' O7 J* ]: D EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
# g$ T8 k) v1 ]6 U. E) m- ] {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},7 g2 E9 ^8 `4 O" ]) P4 C5 X/ o- e2 c$ v
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
. k! A1 U/ K- k- `8 W% } {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},$ u n9 o8 x6 E6 K
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},5 S& F& v& O: X7 Y' J( E
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},) `; }. t# j M' U( J% i. _& V& u, Z
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}) W; J; l& c, ~1 ?4 A5 D$ X
};
' B, }1 i" L, C1 }8 A 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。- O& S. O. y" s1 u T
这些PPI会在PEIDispatcher中用到。! m! |' E" h8 I$ R. p3 y) Y' C6 X
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
8 p0 x5 _3 x+ t- P% t# T 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
! K. `. F3 w' A4 g$ r' O SwitchStacks (
' i4 `: P" c% y) d; X+ } (VOID *) (UINTN) DxeCoreEntryPoint,
7 v; m) L: {, N _ (UINTN) (HobList.Raw),
1 R# q" K. X6 D' X0 m. Y (VOID *) (UINTN) TopOfStack,
* m+ H, z8 A' j (VOID *) (UINTN) BspStore# u7 z( W& k/ y! e
);- Y( ?! o; y+ k/ ?& }, M' l
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)( z! c; v% A7 l8 g
3 q) V. j& I. @# W' F, N: cDXE:
; C" T( {- P" w- e' |/ `3 Y 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
% {4 ]6 h; u3 i, A, a接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。& |4 |: d, q# ]5 z: X9 s/ ]+ N
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
$ ^( ] I- x6 o+ x中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
/ {8 z* a: {* z+ M( n. e 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。+ O/ ?' ?5 m8 ] f. I
( s2 M$ V( r7 f% SDriver:
: b+ Q( {. L5 Z5 B' x9 W* @ 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
9 ^- N1 g! f' Z2 S 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
9 }/ R& V" @$ p+ D' K h' E4 u% y [defines]" i& {) Q) [$ W% z& f9 f
BASE_NAME = OWEN
& _; F' B( M# g& x FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
X Y2 c% |/ F! Y- m% F. v( P% I2 I COMPONENT_TYPE = BS_DRIVER# K8 n- n5 S) T! F
! ~1 r, o- p! N0 [ BASE_NAME告诉编译器最终生成的驱动的名字。: i# f( E5 X E$ s" c+ D& ]
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
: [4 @' I1 o- m# s* p COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
. u6 }4 c0 V8 D9 H+ ]4 E 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
2 u' o, C& J- [/ o1 m COMP_TYPE_EXTENSION mCompTypeExtension[] = {
4 q1 a( k w2 | {"bs_driver", ".dxe" },
1 }* A& Y( e S1 ?: v5 o0 g {"rt_driver", ".dxe" },
- I* M' }! B1 V% x0 C) Y; m {"sal_rt_driver", ".dxe"},- V U9 |; b! j9 W
{"security_core", ".sec"},
; E5 Z \- C3 u* z; F: t {"pei_core", ".pei"},
: m j: X L( g9 U! F0 @9 ~& p {"pic_peim", ".pei"},- K5 m+ U. H# K3 p* h( }
{"pe32_peim", ".pei"},
6 n2 z$ o! T, `) y. ]2 Y& j {"relocatable_peim", ".pei"},$ z* a' e7 ]7 f. h) s4 q
{"binary", ".ffs"},
# ^0 t% [- }3 R5 U {"application", ".app"},$ U/ ?* o8 o6 _& b
{"file", ".ffs"}," N% z2 r$ h. O) n0 F7 _6 M
{"fvimagefile", ".fvi"},* Y5 ?4 o9 i$ D2 s, d& P
{"rawfile", ".raw"},4 L( x) p" x0 Z1 f! \! b" @
{"apriori", ".ffs"},
5 m7 w" q9 Z8 h {"combined_peim_driver", ".pei"},7 J( K! a# s3 N9 I6 d4 C8 `
{ NULL, NULL }9 \( ?3 W( W4 V& C* u/ H4 r% j
};
5 G$ k6 V% T5 k7 \6 b
; G4 B5 V7 x5 X3 F! E5 f/ A( e了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
4 k/ X( L2 R7 a0 W! B1 r ! O( J$ }* W0 c3 d6 W; V4 Y3 A2 D
* T; _! y6 @& O, l% c; I |
|