|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。& ]4 o8 V2 Y9 Y; o/ b
5 K3 Z% C/ n4 m, Y1 r! Y
SEC/CEI:2 E) t O4 P# f6 c1 l1 V
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
7 I' Y9 D G) D$ V" Z- c6 _在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).3 h2 W% X7 t0 J5 F$ V5 \* }
|9 ?- C, t$ F3 U ePEI:, c; E2 ^( C6 L# }5 [* P
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行/ c! h1 m& t2 V; S
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
( ~% {; X- _! A1 y InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
# s& ] Z2 p2 O2 ?1 c* a2 h0 V InitializeSercurityService函数,将Notify队列清空。
* n% w4 }7 C8 W8 s0 f P! \ InitializeDispatcherData函数,将Dispatcher队列清空。% `$ H4 x, P" P9 }9 `7 }
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
% x+ j2 B3 w6 Y# `8 h) O 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:! z( E/ j2 V$ i6 L4 j7 z9 k
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {% j* ^+ A" q: L- v: I9 B' G
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
( E7 R# o" E( @ {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
1 g/ s( X1 E. {( Y) H3 x. g {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
3 `( U" |! n6 E. |) }8 q$ a {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
; x) B* u1 s+ o$ I0 t3 X7 Q {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},& F. C% R5 E( d( v4 W9 }1 q- [
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
0 i2 a$ s; Y' ^8 X9 G };
4 j6 [/ z; | `( x, t2 E 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。1 ?# G, ^1 M" f {$ H/ I
这些PPI会在PEIDispatcher中用到。
2 t6 ^- U# P9 e. ^& L% U 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
! x" B# q* y9 Z' d2 g* _ 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。( d, }# g/ E" E% _* @: L. Q
SwitchStacks (
% Y; J# U8 X7 t6 V (VOID *) (UINTN) DxeCoreEntryPoint,
6 T& _: G y E (UINTN) (HobList.Raw),; v- M8 m! u- @/ j$ q& Q% y( i1 G# j
(VOID *) (UINTN) TopOfStack,$ `# W/ m+ A& J8 l
(VOID *) (UINTN) BspStore
1 o( u. n" m& M8 `6 n% a ); l4 v) M. Z6 N6 K
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。). q. e" ^( ^1 S! m! N' n
6 @3 p% ^" m( j; x: _+ ^. lDXE:* n# B) _4 j! F d# r3 k
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
2 ^" p H3 C; |1 m接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
$ a, n5 l5 r# C5 o 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
- t& c+ \& ^9 I, J! ?6 A中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
5 L* y1 F3 ?2 _, }$ } 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
% I: @2 t. U- }; Q$ h+ ]
4 {- \6 ]0 k6 n6 v: BDriver:5 O+ p3 v1 a0 p( M
我们的驱动什么为在PEI和DXE等不同阶段执行呢?
$ K/ v' c$ X& k8 ]/ [1 [ 大家请看一下我们的驱动的makefile.(EDK中的*.inf)! C3 n6 N$ A0 [" v, A
[defines]8 S" W+ G9 ?% B4 B) A
BASE_NAME = OWEN
+ K! J% G8 @% p1 r FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D08301102 w B1 Q, b4 j- M; G) k
COMPONENT_TYPE = BS_DRIVER1 Y" p0 @7 @9 R, v& C0 u; h
- {3 U& c3 j1 Q- [3 Z' O3 \- h
BASE_NAME告诉编译器最终生成的驱动的名字。, t8 i' k" p2 k/ B7 T& s6 z
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。+ z/ x; w- N/ b d
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。4 W. p" K$ O! j" P G5 _ v& x
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名6 W9 V1 o- ^4 u% z: q
COMP_TYPE_EXTENSION mCompTypeExtension[] = {3 }: G- J' q5 ~
{"bs_driver", ".dxe" },, Z: c# C9 E5 B
{"rt_driver", ".dxe" },* o* m. D8 s: q9 @" M. ?) L
{"sal_rt_driver", ".dxe"},: T+ p( L0 j5 V( a$ K5 c a
{"security_core", ".sec"},7 v7 u; O( ]8 o. T E9 u1 F
{"pei_core", ".pei"},3 N; y' \! y% e) O
{"pic_peim", ".pei"},
5 C. G: k" o# X7 J# }& k9 O {"pe32_peim", ".pei"},- L. v( \4 A: G( v% ~
{"relocatable_peim", ".pei"},
! Q7 S ?5 u: C9 l' z, u3 J6 w {"binary", ".ffs"},3 d) P% ^( r* J _ e
{"application", ".app"},; S; V' j/ O$ l) \" h
{"file", ".ffs"},+ E# m9 x! \# t0 K
{"fvimagefile", ".fvi"},
% R: w) W+ j* \! W {"rawfile", ".raw"},# J5 H4 f0 ?9 R2 f$ g O
{"apriori", ".ffs"},
) z4 H! E/ C4 H& u/ o; \ {"combined_peim_driver", ".pei"},# f* \0 D; Y4 J, W" H' t
{ NULL, NULL }* E n# m. ?: t3 P
};
! {9 L' ~! w! Q" f4 s+ ^! A; ?3 J' v
4 p2 r1 ?% Y7 p) y' |了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)2 i: c7 O0 x5 B. A# R# L5 `* j, ?
# S0 ^$ C2 Q# P, [) p- x1 o % F% c# `0 T9 f, R5 g0 g
|
|