|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
4 h2 _) U! J) m: w' n! u) t( B6 U6 l, e$ v$ S
SEC/CEI:' v' e; r+ f, G# v& J
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
, Y, K7 l+ p5 H# k$ P在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数)./ N# ~5 e" c( Q* f+ n9 L
; P P6 K6 G, }! o& O; F
PEI:3 [. N; G3 Z7 D G- m
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行9 q! \) o+ F8 f
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
0 }7 g( n1 f' _( Z InitializePPIService函数,将PPI队列清空,这个队列长0x3F.$ q' {; A% M0 F S
InitializeSercurityService函数,将Notify队列清空。# L( U& j6 N! U, c1 W
InitializeDispatcherData函数,将Dispatcher队列清空。
$ f9 w! \3 F+ M3 B8 E 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
5 U$ g; |. n. t& ]7 Q+ J 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:9 G/ [% j' f M5 e
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {1 y9 v8 E) u1 S. }( O
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},1 X" E9 E6 F2 k' b$ U
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},- K% ?6 ?- P% `2 W s* q
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
0 P2 x8 h" F+ S0 h: }7 [ {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},: c) K. m* g* ?- A) D+ p" T0 M
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},! s- B# L s, i8 ^% C0 H2 j/ \! I
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
* k6 R6 K! L" U. P0 t };* {/ o4 ~9 u9 T3 ]1 ]
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
/ k# L% x7 U l) z( c8 j0 X8 a 这些PPI会在PEIDispatcher中用到。
( e: ^) U4 W% b/ H) D$ f! ] 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。- ^: l H7 ]: x+ L, |$ ]; I7 W
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。1 }9 A) P; l1 Q( i
SwitchStacks (5 r: w! s n: D8 |
(VOID *) (UINTN) DxeCoreEntryPoint,
$ f; G6 ^" J7 J- V5 H (UINTN) (HobList.Raw),
% Q# U4 L* o( D (VOID *) (UINTN) TopOfStack," J( I$ m8 _) [: o1 d# r0 r: i6 }
(VOID *) (UINTN) BspStore6 H2 O1 c; C C" X0 A
);5 {- A- ^, \1 d" c5 J
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)$ _! B, r' b! z- k0 r9 w
! ?3 Y! A& Z KDXE:5 W! p/ G J- l: I+ l; |) b
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
5 Q. R+ q9 p) o) G- S/ E7 {接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。5 M( J4 u* f. Q* u
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver T6 |5 t# G& J8 m3 B
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。% d$ w* f% O/ a( U; k
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。: f; ? y% n' X1 ], O3 @9 ?7 l
! j9 f2 U3 A! c& WDriver:$ t& N, q! H2 B
我们的驱动什么为在PEI和DXE等不同阶段执行呢?
& |0 z7 a, B$ e/ r9 u9 ` 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
3 A& M8 o( Y* F9 V8 L8 q- \, k [defines]6 { n/ }% S% U i% h' |# s* T/ D
BASE_NAME = OWEN
3 E0 }; J& A7 ^7 w: Z) [ z FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110/ D* ^0 p6 s, v
COMPONENT_TYPE = BS_DRIVER6 Y9 G* P. I1 w1 p$ A7 E
% n2 ~5 x! l" U" y) q7 l8 N
BASE_NAME告诉编译器最终生成的驱动的名字。
2 S2 q" b3 g7 P, Q. ` FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
* h% h. L& A% H% m/ n( F COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
" [& B( R# ~' a# p! S* }. E 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
5 ]5 s, \3 O+ t* v. y* E$ p* p# | COMP_TYPE_EXTENSION mCompTypeExtension[] = {
$ H- A0 ]2 p8 k. \: }" c {"bs_driver", ".dxe" },
* ~' S+ o) i' b {"rt_driver", ".dxe" },& d; @8 V; z" {3 P! B+ F1 i
{"sal_rt_driver", ".dxe"},
* ^' @1 Y& s1 x$ c1 ^ {"security_core", ".sec"},
& p" m$ L; {; M& a0 m {"pei_core", ".pei"},; H- E2 M3 C0 O' _9 ]0 v
{"pic_peim", ".pei"},, h4 F, m q: z6 W/ H
{"pe32_peim", ".pei"},
, p5 ]( ]0 O+ C# [/ K {"relocatable_peim", ".pei"},) q4 @5 C8 h8 Q7 M
{"binary", ".ffs"},. H( F/ ~; E4 g `" w
{"application", ".app"},
5 }. T( F3 k2 s' Q- `3 Y {"file", ".ffs"},7 X2 _, _ o$ `1 |$ D9 N( ^
{"fvimagefile", ".fvi"},- _& p( {( D$ X1 w( u
{"rawfile", ".raw"},
7 U! D) ^8 ]$ \5 M, G U {"apriori", ".ffs"},) I2 d; B$ g* O% g
{"combined_peim_driver", ".pei"},
# B* i' q+ e9 @) O$ V { NULL, NULL }; S) V5 M* R! c& a3 e! y& }
};" k- j' x+ T2 L
, e9 f# ?6 \' _/ @6 e了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
4 g( `$ @( P+ y/ `( J( \5 l
( _3 R. } Q, @! ?0 {0 H 0 o4 l! |7 d9 R- [$ u& C
|
|