|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。! ]7 n1 w2 ` I! j
0 X6 x: E) O8 j% `% K6 {& C$ vSEC/CEI:7 m ~) V9 w* U% w' x0 {
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
4 C9 o9 @. Z6 a" U* h在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).( e9 S7 n0 x- y# ]
7 N& Z8 D6 j0 e+ B% `& C3 GPEI:' X) Q) | ~- \) J6 h$ B
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行& s6 [0 u8 k* `! _/ I7 X
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。/ N# f- r z% p. x# o2 X4 Q
InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
$ ?7 Y2 y! o/ z: ?5 e InitializeSercurityService函数,将Notify队列清空。& C' h* r- x" b9 }# x
InitializeDispatcherData函数,将Dispatcher队列清空。$ k2 `# {9 E# h& W* G% a. H
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
! }: Q. `( t! }$ S, Z( G 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西: { m5 C& n2 D3 \: K
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {, D% Y9 K6 z7 C
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},+ Z. c9 O" |& W4 H. |/ x0 x
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
5 }8 o% w' a, _+ B4 a {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
- x& k! f- M/ L% ?' B8 ~ {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},9 b9 f( {$ ^' F0 G: |
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},$ n2 x3 F4 U# K- S
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
; u9 X) P' \* { g' ?2 p# K0 @ };
- j& q- Z7 v- F4 Z3 q, d! \ 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
" ^# q/ W1 N U1 j+ D8 V! C9 [ 这些PPI会在PEIDispatcher中用到。
7 G& s6 j$ d L! X2 X 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。' g8 e. y0 B0 B. L3 G
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
" f5 f. C7 V6 G& _* l SwitchStacks (
6 H- O% i8 x' `: o# s (VOID *) (UINTN) DxeCoreEntryPoint,
0 O: C% v" K1 a* q2 p4 [% { (UINTN) (HobList.Raw),9 t/ I2 i' _3 Q% M
(VOID *) (UINTN) TopOfStack,
/ v* t+ ?1 D7 ?3 P4 R) Y/ a (VOID *) (UINTN) BspStore0 P) ~0 P% J, Z7 l9 R
);
+ N) Q* {5 h4 J- _ 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)& f% Y: R3 G: O5 e, X& Y
& b) v+ K$ B6 b5 F2 ~+ V/ lDXE:
4 m+ C% f3 }1 d& P7 A0 k 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。3 ~/ a; Q; j. I( @3 ~0 C% u
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
- _1 j" L, g! A; `" w" ~. m( e2 C 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver' s$ h1 ~& g9 m# }- ]
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。, f9 i9 W2 E6 B
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
1 X/ x# o$ Z/ [& t5 w # c1 Y; c( ]/ o9 F
Driver:
+ w# J. d1 `3 r, }+ F 我们的驱动什么为在PEI和DXE等不同阶段执行呢?: e# L$ G5 O+ q8 J0 X
大家请看一下我们的驱动的makefile.(EDK中的*.inf)7 E% d7 H% P' |
[defines]
) |' y' k" K1 B BASE_NAME = OWEN! M/ f/ h7 ?0 ?7 r
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
; m/ A/ ^; M8 G$ Y/ e COMPONENT_TYPE = BS_DRIVER% w1 m8 L7 [7 a* \) V0 r) X# K
2 Y2 k# a% L1 } @+ X, i BASE_NAME告诉编译器最终生成的驱动的名字。' g/ X) C) m8 V" R$ [* P
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
$ m& o5 k2 @$ l% z) H" [ COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。0 H7 u g' G, y3 W; f; L5 L* ]
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名6 y9 o$ j' o" K
COMP_TYPE_EXTENSION mCompTypeExtension[] = {
/ T! n8 Y$ U" |$ _ {"bs_driver", ".dxe" },
" \3 z. P) B, S- W) V {"rt_driver", ".dxe" },
6 g0 ~# |( r( M+ }+ E {"sal_rt_driver", ".dxe"},
5 W5 O, f1 f s6 D2 D! ~ {"security_core", ".sec"},5 c; c% F L l
{"pei_core", ".pei"},) g1 d4 \; P( ^+ v* G$ a3 @
{"pic_peim", ".pei"},
0 H- [/ l2 D, M* J/ B- k {"pe32_peim", ".pei"},
! X% ^ B; k* Z6 f, m9 z3 {+ [ {"relocatable_peim", ".pei"},) E1 _7 V! [* B! {7 H$ F+ x
{"binary", ".ffs"},
& [% w% G# u( y {"application", ".app"},. L; _5 p: ^+ V9 U3 R$ |+ x" ~; A
{"file", ".ffs"},
# v3 w' q' J# l3 h8 _& L( e- _ {"fvimagefile", ".fvi"},
6 r: K* ]& [+ [; U* E7 L0 w! H {"rawfile", ".raw"},* Y" z5 D2 F0 x3 @# V! n
{"apriori", ".ffs"},; i2 C" X |* A8 F& c' h
{"combined_peim_driver", ".pei"},
1 V2 j& n7 _( z# d& @9 Q { NULL, NULL }5 o; s6 P* c3 m1 T
};8 K/ r3 c* |2 \ L- ]
7 w8 u' `* M( W7 |了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)- w5 z; f" H V6 Y' m5 o
- O4 s! O( _- u* _7 D! @ |
) r& N M0 H) ~% h0 X |
|