|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。/ X$ t+ v0 F# r: s5 F1 Z" W# ~
- w6 Y. I" M3 [2 P+ Y& F, t' CSEC/CEI:
8 q8 t0 D* R; v z$ T8 M, Y- i UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。' x3 y$ c1 C6 |* e/ v$ o+ ^4 F4 {$ k
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).3 t V( A1 `$ K- P9 l
" _ }8 G: x7 |) E5 ~$ d) A$ H' L1 ?. tPEI:" I8 {8 A- h. ?' r+ ]0 i$ G& J! \
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
6 A% y" V% |! b* p' W EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。' F: F& ~! G; ]& G- L2 x' I+ v. _
InitializePPIService函数,将PPI队列清空,这个队列长0x3F.+ b4 E$ T4 k1 L( T+ I3 e
InitializeSercurityService函数,将Notify队列清空。
1 M/ t* {* ?( F, q: i- J InitializeDispatcherData函数,将Dispatcher队列清空。
7 i/ p2 `8 Z' O# I" i 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
- W Z, M# q4 z% c 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:! V9 s3 t1 m% W# J9 {' n* Z$ e m# @
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
+ ?5 t: N4 Z$ I4 k6 t2 i, X {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
% J8 D) w: Y8 Q6 T8 a# { {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
/ S+ a* i3 v; g {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},3 V1 D w- K& K: n% v0 M4 g
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
! b' Y. w$ o, h$ K# K2 N0 Y {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
4 s/ ~/ r2 {. E {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
; i. h% v% y! @ };
+ ^* c8 A" |) z& h6 g 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
1 t, H: J9 y: t5 A0 m* _& [2 s 这些PPI会在PEIDispatcher中用到。, b; g% t- V- z9 i8 |7 o; D
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。0 s8 o% n! h+ E
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
3 p/ B& G' w1 z! v" v* b5 {2 O SwitchStacks (
2 L S, B+ |/ |* K, z2 t (VOID *) (UINTN) DxeCoreEntryPoint,) R% j/ `" l+ J3 z4 ]6 i3 m
(UINTN) (HobList.Raw),
7 \# z, @: w4 m% j" Z+ O (VOID *) (UINTN) TopOfStack,
+ y4 f/ T1 P- T% R! Z# m7 T (VOID *) (UINTN) BspStore0 A; R4 L, c4 H8 v+ U+ P. l9 L$ K% j
);9 }+ [5 x1 d9 p+ E
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
+ ~3 |/ t0 J; S' g/ P* C7 r+ e& w4 X
DXE:$ Q+ z: `0 M; o" \! t
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。1 x) X3 V2 O8 _
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。: R" e: b9 u; k" [# L
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver+ I! e) [% ^" W6 m7 ?& t
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
6 K- z3 c, U- K+ n 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。5 `. j) y1 P# x" b. `8 H8 ?( @
- ]1 i, v( m- T4 I8 t$ s% Q- m+ S
Driver:
" R' a4 [0 X# N4 n: w9 Q 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
' e1 J! P' w, D4 D; {5 f% G Z 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
. G( @8 K. |7 v$ w4 Y4 W [defines]
% N4 M1 d0 @" o; b BASE_NAME = OWEN" E i7 B( L- M7 U
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
' O, k9 n% S$ e: g$ O COMPONENT_TYPE = BS_DRIVER
5 S; b8 A: P+ g! D0 P6 s6 X; G- \0 w: {) `
BASE_NAME告诉编译器最终生成的驱动的名字。, P7 Y( o8 \' l) p/ l! Y& A% ~
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。8 C8 w0 M8 {" Z7 \' X/ ]1 z' {+ I
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
" c' X4 b. _9 h: I 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
% b. A) r Q! f c6 \+ k COMP_TYPE_EXTENSION mCompTypeExtension[] = {
% g' q) K! J% `+ @# A) J) s# {+ Q {"bs_driver", ".dxe" },$ B, d+ ~5 U4 p2 s* P( \, T* {( O
{"rt_driver", ".dxe" },
8 D; R/ G# a# F0 E0 d! `' ` {"sal_rt_driver", ".dxe"},! K: b: B/ ]1 I6 }. P( b( ?1 F
{"security_core", ".sec"},
8 O5 V2 R4 Z( F$ X( S9 i7 A$ @ {"pei_core", ".pei"},6 V8 N' D% S* h2 j
{"pic_peim", ".pei"},; k- z. |; b0 d
{"pe32_peim", ".pei"},7 S8 X$ v2 {4 A" K7 P: W
{"relocatable_peim", ".pei"},
2 Y1 |% A4 L, J" D+ K) V h8 l% N {"binary", ".ffs"},0 t! N" ?; Z/ ?3 s) T) z: Q
{"application", ".app"},8 r7 p) a( e# a; ^/ \
{"file", ".ffs"},
Q3 }7 K. u0 J* R! C& o6 Q {"fvimagefile", ".fvi"},
( ~, a y0 C- s5 F {"rawfile", ".raw"},, \" v# B( F6 o$ H: d
{"apriori", ".ffs"},: _( g0 ^0 I2 X5 L
{"combined_peim_driver", ".pei"},4 @! J0 P. U% D4 D
{ NULL, NULL }
% E8 M. |/ Y+ {1 i0 f};
% P# y; E' K: K0 A# p
# N4 Q4 Y: V% C; S了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)+ ~) G& ]6 f0 R' m5 A
# L( R! d7 u6 ?3 T' D0 n$ F 7 g; |$ H! x' ?
|
|