|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
, A0 f7 P4 i$ o3 L4 X7 k/ i
4 Q7 W( e( Q! H) i) S+ bSEC/CEI:
+ s( D! S$ g# j8 |3 n UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
! b/ F3 K' o7 {在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
8 E/ J8 [; d( f2 T: V- b* z" I2 r
% P; Z- ^! n& dPEI:
" d, e/ y9 u+ b) F% f/ |% G6 A 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行+ g. h% e7 I, C" U# c. ] O6 j) V
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
8 N9 B5 o1 o, i# U/ J. z InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
) B( `) P7 [/ p2 P( ^* l InitializeSercurityService函数,将Notify队列清空。
# ^8 L+ m. a: w) B; s9 K InitializeDispatcherData函数,将Dispatcher队列清空。# u6 o% g3 H" V: G4 c
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。8 n: o4 w5 _" v7 M. J) p
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:( _. E' E/ Z! ~6 n
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
: r* K% j& P& M( F. U! |$ i5 E {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
& Q& d6 o/ z1 x# A' K" _: Q5 k {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi}," J, D1 I% v* ]
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
# O S- p7 ~4 ~; ~# u9 l {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi}, V; Z" `1 `4 B9 T& Y
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
2 i+ |3 ]) t5 S1 E3 @/ l {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
) _0 O+ u |& D' \' T+ _$ N };! s9 U6 ^# m7 M. ?) P5 n
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。* n4 _, ~5 e; t/ D7 Y' W1 X8 i0 v
这些PPI会在PEIDispatcher中用到。! [: w7 |" k) r" F) u0 \
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
- a/ x* [" I" |4 V% f 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。, _) W% v# c* j! {8 J
SwitchStacks (: N& a) e# }" A {
(VOID *) (UINTN) DxeCoreEntryPoint,$ f: d3 `6 v- N* W3 N, W, C+ h
(UINTN) (HobList.Raw),3 [, B/ {/ j5 Y. i
(VOID *) (UINTN) TopOfStack,. E+ G: d% I" `8 \. i! H8 z+ O5 l0 Y; z
(VOID *) (UINTN) BspStore1 ]% t- d. ^+ R3 G8 P
);
& H! r9 q) J4 s, r5 W 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
1 Y: n9 s, k; i/ O/ }. Y# h) X/ G1 ?
% F; F5 h5 W, n: i' o# r1 e1 @5 WDXE:/ G, F, F1 T8 }* T. y1 `
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
1 w2 K3 b( E. F4 u接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。; U' P8 e3 m" ?+ P
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver, f3 p! @* J* ~- m3 j1 i$ F1 k1 Y1 J
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
. w. f( o- t) X 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
8 x- i( \: e; q7 O( p
/ E, m e9 w6 o0 TDriver:" X6 p9 u' a6 u# m0 ]0 `4 |9 F
我们的驱动什么为在PEI和DXE等不同阶段执行呢?" _+ m. W6 O/ L; s! d
大家请看一下我们的驱动的makefile.(EDK中的*.inf)& q* r% r$ U2 F. }' P- o
[defines]
) s% u- Y* `" B; }+ j; c BASE_NAME = OWEN1 ~, N8 R6 Z4 {0 I* }
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
) y) _6 L0 W3 S/ k COMPONENT_TYPE = BS_DRIVER: X$ q1 h0 o0 X) F( o5 v( ]$ }
( Q2 F( A7 F0 B+ k6 r
BASE_NAME告诉编译器最终生成的驱动的名字。
8 W1 D l/ {, Q q FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。: ]4 E4 [! c) ~& a$ n1 K S
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。, l( [4 d$ t3 T3 A) P
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
) O! E; N) Z( {( ~4 U) x2 T5 W COMP_TYPE_EXTENSION mCompTypeExtension[] = {
! A, z1 w; m. V) S {"bs_driver", ".dxe" },
5 P8 i; m# N4 p! v! k( h l {"rt_driver", ".dxe" },# Q1 x+ V& K$ U; c- H
{"sal_rt_driver", ".dxe"},
; @6 b1 K% }/ U" |8 a, s {"security_core", ".sec"},/ o! c G7 V- h& @
{"pei_core", ".pei"},9 G% h' G1 r8 \ \8 k2 P, v7 \
{"pic_peim", ".pei"}," E) a$ z' A. J* |. G8 G: d+ y
{"pe32_peim", ".pei"},* P2 n, O& x+ J0 ~2 I0 I; q g
{"relocatable_peim", ".pei"},
! d" s8 V7 I! x# u6 X- ] {"binary", ".ffs"},/ s2 V6 Y' K: p+ U+ V6 U8 X
{"application", ".app"},
) q6 G5 j- y3 F0 V. X8 N {"file", ".ffs"},5 u2 ?. v' c2 u& d7 E, c: q
{"fvimagefile", ".fvi"},
! A& w/ `/ C2 `7 C5 q {"rawfile", ".raw"},2 @; s+ f% Q. A6 |( r# E0 ~+ _
{"apriori", ".ffs"},
% ~0 c1 j6 _. g6 {- u {"combined_peim_driver", ".pei"},5 m2 W5 E% o6 M7 \% f
{ NULL, NULL }
& m2 Y. S" _, L/ R0 @. _7 D};' [3 z" @" Y0 d4 G4 m$ u
4 N( t4 G' O3 {. P了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)0 H( V5 t6 q+ _& q' B2 I
/ V0 F4 X1 A" j( v; o2 [
0 M& C; a# F; ^6 \( z |
|