|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
3 l/ x J# v7 Z2 Z
- {& ~6 Z6 L: P- H# L3 wSEC/CEI:! K) x9 P) E% U
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。. |! ^; x0 t8 u" }3 o @
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).- a- [: p& C: n+ q: Q
3 P/ l/ w) u) [# k! Q( d7 f$ I6 {
PEI:# S( }* q# ^; s( z e
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行, b' Y3 L/ w, n) }9 L0 r
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。. M& ~: }) o$ W1 y0 V) q+ ?' r5 `
InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
$ A+ J4 p" N4 G InitializeSercurityService函数,将Notify队列清空。
7 E% v0 ]* \. R InitializeDispatcherData函数,将Dispatcher队列清空。
& a8 @+ b7 ^6 ?5 d; Z7 k 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
1 B) `! L7 X9 C& l8 ^9 I+ e 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
3 F5 K" P7 a% L, Y2 B. P' e EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
/ k! o' C0 t3 P* N2 x3 a {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},$ a* V9 Z; O# U1 s9 B8 U* o s" S
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},. T7 Y# }3 `! P7 B$ H
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
* u: S1 l" r D* v9 Q" q- J( n7 R6 w {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
+ i2 Z( k' i3 U& g5 W2 e5 N {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
1 J2 J/ U/ S z- E1 u( Q/ w* b {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}5 J. `6 j: h& Q/ X
};% ^9 W" D# I' I4 } B" ]5 S! P8 h
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
- p$ C0 U6 u3 T 这些PPI会在PEIDispatcher中用到。
, P: ^2 m$ H- ^. O# T/ u; P3 f 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。0 L9 F" x# u9 ?- i1 T
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。% p8 e- _6 Q1 E' r, o {: ]6 d
SwitchStacks (
& e1 C9 m6 p, u# x# p3 } (VOID *) (UINTN) DxeCoreEntryPoint,# W4 A: _+ P% a" x, p Z
(UINTN) (HobList.Raw),
* n& b& i Y! H; V7 w( w8 f" L) B" c (VOID *) (UINTN) TopOfStack,$ d$ H8 |& Z# U6 ]9 ]
(VOID *) (UINTN) BspStore! ]' t1 I5 w9 q( e$ C
);1 F& z( s7 Q8 c8 k+ i9 w
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
5 M6 Y/ ^, B0 Y7 I& k. U7 ~* `1 k' i$ i; @0 i) ~+ w
DXE:# t, g9 e& q& E7 I
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。- T7 h2 g5 h, W: C5 Z. [) N
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。0 t5 e- b3 ^1 d: j/ u6 b+ H4 \
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
. }( ~, j2 y! v5 ]1 e* g/ E中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
3 T( U) ^' W( D9 x% k4 V" p 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。( C7 P" z" D9 ~ n5 k+ o
6 |* ]- z0 r$ o1 ?( j
Driver:
5 y, F+ O8 O0 J# m 我们的驱动什么为在PEI和DXE等不同阶段执行呢?' C/ U1 o9 F" f: l; r
大家请看一下我们的驱动的makefile.(EDK中的*.inf)
y1 i- A2 o2 d1 o" U: [1 b [defines]' c Y# V' w, V+ P5 d- J
BASE_NAME = OWEN6 T; g# r2 H+ e2 Q
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
' U( V3 l9 S6 e+ |& w COMPONENT_TYPE = BS_DRIVER
1 u# j( A5 D2 { C5 h: |7 I( m3 H+ l! K8 ?! W
BASE_NAME告诉编译器最终生成的驱动的名字。! v4 k$ W: }/ H v7 P8 P# z: R5 V
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
( e1 M" b P4 d% m COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
, J" d0 _# N6 K: k3 ~ 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名( [% E: w2 v; \: x0 F( z8 @9 Q
COMP_TYPE_EXTENSION mCompTypeExtension[] = {
, L- q) u+ T# h {"bs_driver", ".dxe" },
2 l" e3 W' o: P- p {"rt_driver", ".dxe" },; @2 r; [( q% W; p" [
{"sal_rt_driver", ".dxe"},
: C7 ?# v: u8 X3 C/ t6 @9 G {"security_core", ".sec"},
& a7 R8 M: H3 l$ W+ L' |, z {"pei_core", ".pei"},% L; w/ j0 s. ~* G' q# T
{"pic_peim", ".pei"},
. v! w% A! g3 f {"pe32_peim", ".pei"},' Y7 N9 A# X. T( @# n2 z" y
{"relocatable_peim", ".pei"},4 s+ {$ i f0 A8 c6 e& a i+ N
{"binary", ".ffs"},/ r+ X! y. _- y1 e& c4 O
{"application", ".app"},8 b; i0 K- e% y" W% t$ B p
{"file", ".ffs"},1 ]6 S/ ?* [9 Y( H, _8 J& M$ m
{"fvimagefile", ".fvi"},4 n. l& Q' d V7 u; }1 x6 h# a+ e
{"rawfile", ".raw"},
% g2 D4 v+ ?1 i, W$ a: U {"apriori", ".ffs"},
8 T$ F3 ^6 D( z {"combined_peim_driver", ".pei"},
3 W% H/ x# G$ e+ W- m { NULL, NULL }4 g! {# b8 c% E2 q) Z# C1 X
};
- P. Y- [5 N4 m% f& ?& m* `( L. M) q2 ]
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
" x( Z: \3 }. B; g ( i1 }7 Y" R& {) _
+ b" U% R1 X8 z- ^2 R8 j+ X |
|