|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
* `) }; f) [# P$ T4 ^: p
' N" g- l/ f# {0 _+ {SEC/CEI:# g3 o6 A: Y# J5 o5 O& K H
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。7 ?3 x4 P t" Y, I
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
1 p( U& I2 O" H! x! i5 c1 J3 O7 D$ o0 E; L; d. F2 c
PEI:
# I8 x* y' {4 \' A 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行+ x! W! r0 S8 r4 ^ e
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。- }& |4 t+ {( ~. P& L
InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
" S' `, Q/ d# h3 l. p- B! c InitializeSercurityService函数,将Notify队列清空。
% D8 W4 Q/ i/ c* x1 Z1 C& W. r7 Z InitializeDispatcherData函数,将Dispatcher队列清空。
" q9 Q$ _5 H; h/ Q# ? 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
- \, q! h4 w, ^ D6 k- O7 D 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:& t8 Z, {. s/ y v' D0 r, ~$ G
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
) W- e' ~4 k& j1 }) r( H" h {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},6 j L2 _& q8 U$ D m# F j! S1 i
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
" K/ e2 d7 |4 ^5 L9 _3 I {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
, D+ B7 |6 S; A9 m6 C/ F {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},* |% G# N; }" Z9 S
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
! ^+ B$ I1 N5 |/ C( D& M" M) d {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
* D5 m. w, Y. i6 W: ? };
% \& N B2 T8 Y7 o+ {2 Z. a: Y 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。) G" b- i- E. d. e3 R
这些PPI会在PEIDispatcher中用到。) C; v4 R% k6 i. F
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。5 d- H2 o$ _, O! l W
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
# o& g+ u9 y" J @5 r. U/ | SwitchStacks (3 s5 K' d4 h. Y" g! t" m7 f
(VOID *) (UINTN) DxeCoreEntryPoint,
$ g" q0 w9 e( c' U, [' i (UINTN) (HobList.Raw),3 u A: H& |7 @; d% |+ j/ w& u
(VOID *) (UINTN) TopOfStack,5 d# }6 l# X4 f6 @$ e3 o. J
(VOID *) (UINTN) BspStore
. {' e% ]+ W6 \+ E( J" L8 P/ ~ );0 v, i$ R) g2 M# B, B6 d- T+ A7 q
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)& ~& c: Z. N9 r
- A( W. J: j/ P& r5 rDXE:
2 E& ^: n) v+ Z9 ] 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
$ D+ F9 o+ `1 Y& Z' E3 ?& z接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。2 o! W4 |# N( K& m
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
* u/ u4 a5 g5 D; j中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
0 b* s' P. f6 T6 i) u- O 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
- j, e7 S( G- W2 C# v$ x
) h- F/ i, [& e; v) x Y+ YDriver:
( ~4 M" o" b# u& ?6 Q8 N 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
5 }- {4 l" f* F; O8 {& j 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
/ t5 \' S U- E/ C9 N, Q) V [defines]# f4 }4 a6 K5 S _
BASE_NAME = OWEN
4 z+ Q, r9 n; ~5 G$ G FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110) I9 @7 l1 U; B% Z( S5 Q8 e9 W; V
COMPONENT_TYPE = BS_DRIVER% S+ Z4 i- J: n; K U, m
" w: A R7 a& s% `/ p) V2 e5 Z
BASE_NAME告诉编译器最终生成的驱动的名字。
h3 d2 i8 `5 {/ f% K FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。4 q9 a3 l# K) k' S8 Y7 @
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。: X' H; d: g/ p* ~
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名 U K( }! X& x) ^; |
COMP_TYPE_EXTENSION mCompTypeExtension[] = {0 N' ?6 T4 G, E; `! J, E
{"bs_driver", ".dxe" }," R. T5 V5 e" W4 o( W! s" i3 n
{"rt_driver", ".dxe" },
& ^9 }- H- c* Z; [+ l {"sal_rt_driver", ".dxe"},% g& L' f/ }5 ~+ N* \% v5 Q# p5 t
{"security_core", ".sec"},( b# c `: q* ~% l+ l% f
{"pei_core", ".pei"},% G/ V" Q5 n; D8 H1 Y6 b- M/ g: [
{"pic_peim", ".pei"},) N0 A+ z3 h) E D* X4 }) p
{"pe32_peim", ".pei"},; ?+ _: {2 W5 s% h
{"relocatable_peim", ".pei"},
' ?: U8 }( O" A* |3 z* m {"binary", ".ffs"},1 d6 U4 E5 A; Q8 i; y) Q
{"application", ".app"},! V' j! k7 _ ]0 Q9 _4 S
{"file", ".ffs"},
% b6 L: Z' n6 @/ d& K: U {"fvimagefile", ".fvi"},' e5 E" U" ]7 a6 m& U7 b+ p9 n# y
{"rawfile", ".raw"},
T8 B6 c' G4 f* d# f. V3 ] {"apriori", ".ffs"},
6 K1 @6 C* U: M1 R {"combined_peim_driver", ".pei"},
' L4 O* M; ^$ F B( { { NULL, NULL }
( M- x# k4 j9 l% z- W};- z4 D% ^0 L2 x; K! b. r
! \2 m" W6 l$ C6 h- |! c
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
1 }5 B) g" l; Q7 T" A1 B# B 6 m' |% L. r0 L" P
4 |1 X8 J8 C( b% k$ _* G3 u9 I' | |
|