|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
4 m& A0 R( b6 I" j5 X
# _- B- p" b2 j8 m9 r7 B' |SEC/CEI:- |5 e% X% ~7 _) R# b
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
: v9 P# Z9 Q2 _在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).4 Y. {' g8 |0 R `
2 x" i; t9 ]$ a6 r3 o9 \* r
PEI:
. L( a) Q* ?3 V* q. s 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
' R% V5 M8 g& F( R7 N/ ? EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。5 U# n/ o. _) ]6 q7 d' P6 q
InitializePPIService函数,将PPI队列清空,这个队列长0x3F." P5 N0 Q3 H' s+ w4 I
InitializeSercurityService函数,将Notify队列清空。
6 {8 A- s q, ?# s u InitializeDispatcherData函数,将Dispatcher队列清空。
?$ ]3 C2 s8 e0 T& v$ l 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
' h4 y5 M% n( v: }) @ 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:! D& [5 e2 i& C! Q: p# i
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
9 u1 B. R- d" j5 w( @. y: X5 L; H" d {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},$ q Z5 p' K5 ^, L8 v( W" ~
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
8 [$ j4 f) R: m0 u+ o {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
/ r& \7 m2 L% ]$ Q8 y- M, @+ } {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
3 ]6 `% p/ s, S% j) V p+ N' J! f {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
U1 A: W* r8 ?$ F3 O- C' Q" V U {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
! ]1 p" J, c& P% ]+ m/ ~, w };
% C# _! P+ c7 X1 } 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。3 s8 X, j) t# [; L# C* W* ^
这些PPI会在PEIDispatcher中用到。5 s0 m9 a; W' m9 i1 Z! y
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
+ B# m1 O8 F$ A+ {6 D$ y7 o% [ 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
! R; Z R# o* O! M$ ^% O( n SwitchStacks (# j( d7 n5 ]8 X# d; w
(VOID *) (UINTN) DxeCoreEntryPoint,
' z5 e4 {: X/ C- E) ?* c R) U3 c( ] (UINTN) (HobList.Raw),
+ e: p; V8 w/ G+ a1 c (VOID *) (UINTN) TopOfStack,
& s- k/ z) S7 K" F2 U5 T (VOID *) (UINTN) BspStore& }1 w; R- ~ H
);
/ ^3 u+ E: x% f0 N 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)# w* ^% z0 t$ O+ g5 L
# I# a! {( b1 z% L- O- V& g1 e
DXE:
: l; \+ }$ k1 B0 }' ? 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
: b; j- W7 w1 K# u V Q5 G+ {接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
* @ `& N A9 b2 q% r 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
+ x- w) B: }# z* X- P中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
$ x; v. Q- J$ [, h" k' y* { 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。4 X* R& l$ P% i7 @4 a: A! O
/ [1 l: H6 o" u; h* S/ G( i" X9 H: A
Driver:. x. N% M9 m, u' ~. s4 |% u
我们的驱动什么为在PEI和DXE等不同阶段执行呢?+ m1 Q1 E, m9 O. ?
大家请看一下我们的驱动的makefile.(EDK中的*.inf): @2 H" B8 E3 {6 t) p
[defines]# J2 _% Z, d4 w0 G! u
BASE_NAME = OWEN
( R% C% V/ [+ P, I FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
5 y: J) N# x/ ?; v$ \7 }2 B5 x8 L COMPONENT_TYPE = BS_DRIVER8 P; d W: H! k& p% ?
- I/ \) A4 X$ G% A
BASE_NAME告诉编译器最终生成的驱动的名字。
' Z# R4 R7 T4 c FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。5 J8 R& r" d8 O/ c n
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
0 X6 i+ y( f" K b( g 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
& y6 `5 d* D# n! ] COMP_TYPE_EXTENSION mCompTypeExtension[] = {
" U* Z0 t( b8 ?! J- D; R {"bs_driver", ".dxe" },
! [; G+ p, c0 p; v+ o+ N {"rt_driver", ".dxe" },
8 j( w% k# b6 `: H: _ {"sal_rt_driver", ".dxe"},
4 c. R/ h6 N% o7 O6 X {"security_core", ".sec"},
) i- b# T/ H' f {"pei_core", ".pei"},# N2 |: t* V: ^5 K% I# P
{"pic_peim", ".pei"},
1 n- L1 y. Y0 z, z) s {"pe32_peim", ".pei"},0 c- R0 p' b) U5 K' p& H- D
{"relocatable_peim", ".pei"},$ A2 s) x0 k7 ?- V i2 n
{"binary", ".ffs"},( }1 ~/ w5 G4 o4 V* `$ ]- c
{"application", ".app"},; S7 \# M+ [& Q* f3 X" ?7 C* J
{"file", ".ffs"},
4 y! w' O+ s9 x# V- y {"fvimagefile", ".fvi"},
$ x, B% t5 O" k' d {"rawfile", ".raw"},+ r, z$ }6 H; `
{"apriori", ".ffs"},
) s! d* t( ]' M9 t) |% Q# \ {"combined_peim_driver", ".pei"},
; u# h& l$ N# Q( E- C% Y { NULL, NULL }" y& k/ F3 ^. p' ~
};
7 ?- ]4 `( d3 T! { H' b# W
2 k8 U6 G' v K; v- D$ p了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
2 O# T$ h0 U% u5 _ : f3 Y4 G Q2 `* u R, U% p0 u2 V/ L+ k
( H/ r' \ u: b
|
|