|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
; g! E: V/ H+ I6 h
% @4 c' D4 @* j0 M" XSEC/CEI:
# y2 c; w5 O0 j9 L0 v, J UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
) n8 N: E% g6 A; T0 ~: A在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).6 f' y% c2 N6 J7 G1 K7 V* V( m' W
) ]2 T( Y. J/ b, J! d: K
PEI:
6 h' x8 |' E% P" D) Z7 D" B 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行+ O& ` K4 I- { k. I
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
' F. E& O& h4 e% e InitializePPIService函数,将PPI队列清空,这个队列长0x3F.- i3 u/ H; a+ N2 A# z8 J
InitializeSercurityService函数,将Notify队列清空。
7 H( J% l( g+ E# b# `' Y InitializeDispatcherData函数,将Dispatcher队列清空。8 \: V/ d: M) J8 O& j( x# d- d
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
1 Z4 O0 L5 d( v# y% q 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:0 y5 D" T& m' U g- ^; a: r* _
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {9 \6 l9 t6 E6 F! s
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},( `5 n k5 ~7 B9 N4 Q$ R2 J+ X1 G
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi}," G& B* {" h9 Q; I
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},! l w2 P; G+ U
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
. ]1 K x9 O9 M5 j0 v! t/ ]$ U! R {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
- f, {% Y, Y0 h; r8 Y* J {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
, D o9 m! M6 f3 t9 S };
% m, X4 u" i8 E5 _ 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。$ o2 k5 ?' T \: H3 |0 l7 ]2 b" e' [
这些PPI会在PEIDispatcher中用到。% P# u) s1 N* ?7 `( U* M5 y3 t
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
d" _ d. _/ Z. |" B! Q 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
0 L- n6 I* T3 J0 y! s2 I SwitchStacks (
, i2 i5 M; B, s; q, `* m4 u5 F (VOID *) (UINTN) DxeCoreEntryPoint,
/ T6 K$ f. G- J: O" ` (UINTN) (HobList.Raw),
& E: Z5 j0 S- ?2 q* z (VOID *) (UINTN) TopOfStack,
( U8 {, ]! P. r3 F& S! r/ v% j (VOID *) (UINTN) BspStore; u( s) O/ ]+ X+ i$ o
);' h2 R, k' }- |$ X0 C
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
1 \7 g( _( k& W
& R! _3 `% H$ K5 _DXE:& b; e1 g4 k$ R2 G, A3 ?
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
5 y' Q: I! S+ I- R* l% g接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
' v/ o& V! i( Z: J+ \! B3 a3 @ 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
; a- V! _! |: q5 c& l中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。 B! ~( r* x! n9 g+ L- f
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。4 L5 P/ q$ [. [: W3 W3 u' ^
U6 L- ~, `! Q& i, M4 ]
Driver:- z3 P2 s* p* U. ]' ^
我们的驱动什么为在PEI和DXE等不同阶段执行呢?
" d3 _5 t8 ?! ?% b 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
7 ] @- q, W1 s" [. f U [defines]2 o7 N8 Q5 n9 ~% s
BASE_NAME = OWEN1 w) r& H) }8 G% P. r. ^
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110( X7 D' k: M* A" N) O
COMPONENT_TYPE = BS_DRIVER# V+ ?) R% A& v. g5 e- {/ }' r$ E
6 l2 o( n% S; N! h7 w
BASE_NAME告诉编译器最终生成的驱动的名字。6 g1 Z- m& X, F+ M J8 \& v
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
9 ^) w! f- l4 i3 R COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
, d8 o# z) e4 j5 I5 N 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名2 m2 L9 N; v% G7 D
COMP_TYPE_EXTENSION mCompTypeExtension[] = { H. Y* @2 n- l8 o
{"bs_driver", ".dxe" },
! P: T# g7 R7 C# |2 T: L {"rt_driver", ".dxe" },
2 b! x8 n0 K& [ {"sal_rt_driver", ".dxe"},
- m' ]4 J% h; F% o; G0 j$ f {"security_core", ".sec"},
6 a, A+ b; P; v; _3 `# a* E1 x* E# b& ] {"pei_core", ".pei"},) C, a" w) x& x6 Q& k' ]1 I* R
{"pic_peim", ".pei"},, V3 E) s- E. z7 e. k2 ~" j( M
{"pe32_peim", ".pei"},9 A) s& b: Y1 N \8 \
{"relocatable_peim", ".pei"},7 y+ @4 H7 i! s0 ?8 O [$ u
{"binary", ".ffs"},
! Q- ^5 o; h4 \4 ~ {"application", ".app"},( h r W* m. B, d/ A0 Y8 v
{"file", ".ffs"},
) ?6 ~3 b$ D% F8 { {"fvimagefile", ".fvi"},
/ \- w5 k4 ~ [% A' v9 F& P {"rawfile", ".raw"},
5 [5 N8 J% o Z" T3 e0 { {"apriori", ".ffs"},
3 x6 Y5 s% g0 ]% \3 B" c {"combined_peim_driver", ".pei"},
# \; a+ P5 |) x { NULL, NULL }
( D+ [1 [3 w7 }2 G$ |};$ A/ R1 n: k, ~2 O1 S
; @+ S' s- m5 s- W- y/ s D* u3 u
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
! j# g: o/ I0 S" |* ^0 C' H' M& {/ U7 G
) S0 W' b x) B. h- }
- g1 a& @( d9 d$ |$ {& O! j! t* T |
|