|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
, a2 T: p" h/ z" F4 A
& [ ]3 h+ X$ u1 `SEC/CEI:
) z) ~) |; @0 D/ O0 T+ o# `. L# g3 p UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。9 ], f6 b2 y! b( A
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
! i1 }5 @; J$ ]% o X& h/ R* [' b
PEI:8 e! D# D% x% {# j0 q4 {
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行: E. D0 L6 P' ~. E! C- K' Y- {5 @+ u0 c
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
& h* V, d& _! v) V/ Y+ ] InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
* c: U/ [4 I' g+ j' v2 Z InitializeSercurityService函数,将Notify队列清空。
# }8 C. m' n! \& W$ t3 I InitializeDispatcherData函数,将Dispatcher队列清空。
4 [$ u% ? x9 v4 {. q 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。/ _: W% l3 w/ U" I. c: p! g8 `
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
o, H: e w9 J& x5 h EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
9 K" G8 z* [4 { x; w {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},/ g* C' n, i& E! M1 \+ W( M1 _
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},! E2 Z N/ e$ T6 d: l* N
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
6 M: s; h8 l6 I | {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
2 }. E8 r$ G+ } {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},' n7 C9 S* l( ~2 N$ d4 H: H
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}* n# s" a. G0 \" r( N
};+ b$ {9 s" \: V
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。0 d, @" ?. d: |% J3 ^! r' Y' |
这些PPI会在PEIDispatcher中用到。3 ]1 U; l2 V* [& o, x
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
" }6 e9 @6 e; F. M 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
) I, T0 `" k- }2 }- @6 Z SwitchStacks (
7 D2 F5 P& r* ?6 t1 U" l+ Z) R (VOID *) (UINTN) DxeCoreEntryPoint,0 R( u4 R* o5 j z4 ]2 S
(UINTN) (HobList.Raw),
/ K9 t( q8 h! z (VOID *) (UINTN) TopOfStack,# X S. v, Y6 q$ c
(VOID *) (UINTN) BspStore
+ B6 ?1 V5 u1 k9 d5 L2 t );
* `4 O$ L: m3 v" m" f6 H 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
) B2 I. y/ h8 h5 e; I- h5 `+ w' j3 H) q0 z
DXE:' L6 m7 H' m8 V) T& I' m+ B
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。$ @$ q, k2 u+ A2 m6 |5 d
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。& o- y, E8 v) k2 i0 L: F# a
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
" i& u1 C+ _# b0 A: P9 b1 {中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
1 j+ e% ?, t& Y8 ] M) s' k 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
/ G! X5 M. j- v3 b* x" O, C; ^ / E: ]. d( r& D) c4 T* X0 y
Driver:7 j( p: \" e; o l' S0 ~
我们的驱动什么为在PEI和DXE等不同阶段执行呢?
# k- z7 C( B' e M 大家请看一下我们的驱动的makefile.(EDK中的*.inf). [% q( J4 K, q7 K5 ^& j
[defines]
t4 K" j1 Y7 \2 ` BASE_NAME = OWEN: |+ t" B8 Y% v0 r$ ^
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
1 ^+ P" e; K, W1 H6 I COMPONENT_TYPE = BS_DRIVER e" @( [8 o, m* t! ]) P
( w3 a X$ `' f2 r) C/ f4 O7 d
BASE_NAME告诉编译器最终生成的驱动的名字。6 u7 k2 M: A$ I" T3 }1 W; M" c6 x
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。 Z6 O* \" k& i$ d0 _/ v
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
/ H C# S! K' m( ] ]3 E$ }7 { 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名6 H* H' r, M6 {) H1 S, Q9 g
COMP_TYPE_EXTENSION mCompTypeExtension[] = {) W+ i/ E8 p+ }2 t# f" W1 |
{"bs_driver", ".dxe" },
3 u5 b6 C) E& \* @" }3 ?! w1 W {"rt_driver", ".dxe" },0 e* Q) S' x/ M& X. A( m
{"sal_rt_driver", ".dxe"},' U6 W( n6 f# ?$ G1 Y0 @
{"security_core", ".sec"},3 n/ M! {8 X* A& e1 r
{"pei_core", ".pei"},
& E, Q% y% h, G; U8 B {"pic_peim", ".pei"},6 s# |# y, L- E. `0 A
{"pe32_peim", ".pei"},; y. y- T. U2 w1 x% `/ c
{"relocatable_peim", ".pei"}," C1 t4 |& U1 f
{"binary", ".ffs"},6 J2 ?* B u! \! E' W
{"application", ".app"},
' |. M4 q8 C, k( g {"file", ".ffs"},3 `- q7 @. D* }
{"fvimagefile", ".fvi"},
$ W4 ?' r7 ^8 y3 H {"rawfile", ".raw"},# z, A9 C$ q* Y7 g5 j: L
{"apriori", ".ffs"},
/ j: M$ N, n2 t* N( H6 H8 a {"combined_peim_driver", ".pei"},: G+ e& @+ R; Z4 `& r! b
{ NULL, NULL }
0 Z1 e; @7 E( i: N9 m/ X6 B& d};
' O1 I/ v! N) {$ N
: b9 d+ k# z6 J6 x- l& T了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)% R) ^( [; V- ^; B9 e
7 }4 L! a% i3 H; n
! E8 L. i1 I% m6 Q' Y
|
|