|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。5 e7 F, a7 H; A" Z6 @! K: ?
) ^9 l7 c5 T V" O& {& iSEC/CEI:
7 M& p) `) p; r# \ UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。0 H% M/ \. L7 K8 w7 M2 p
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
5 ~. r. ?% z, a, a" |$ z8 \
% F& u/ ~2 g: D0 F7 iPEI:
) `3 v9 u: X( T# M1 k- K1 p- M 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行: ^2 c8 J+ e5 e; ^7 i4 W% s
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。$ f5 ^& H' V7 P- G6 B
InitializePPIService函数,将PPI队列清空,这个队列长0x3F., q5 O8 k* J0 }& z/ g" F
InitializeSercurityService函数,将Notify队列清空。
' I: M: Q8 D7 J4 Z i/ n0 _ InitializeDispatcherData函数,将Dispatcher队列清空。
0 p- ]. J: `" ~- e0 L \ 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
0 ~9 b* \4 I) K7 [ 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
" m, j, U# S' P# O. o EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {: b0 `, {" C0 M* P5 `/ s
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},* o0 X% v8 k w3 s2 s5 v
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},3 J: }: n! X; U, p3 P0 V; o" t
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
& S! g" v$ @* b* _ {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
5 J9 i' |) z: d! c' j3 _: h1 ^ {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},+ Z- U& R) J5 Y8 t' `& A
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}5 k; `5 m+ Y v8 d" r3 o" g: x2 P, ^
};
! t2 c& ~+ ^3 V 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。1 r% @; x. A( S* t" @# j; b
这些PPI会在PEIDispatcher中用到。: B, ~3 y. z' O4 O, Y( e
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。1 y3 N- _1 E, x* @. l& D- M
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
* {) O/ t; j0 G/ u SwitchStacks (
: j% `% s( z0 k! d0 N (VOID *) (UINTN) DxeCoreEntryPoint,; v1 J* M5 |8 g
(UINTN) (HobList.Raw),
: @% Q: j& H/ t6 D8 ~ (VOID *) (UINTN) TopOfStack,/ d1 G; j% q/ ~5 n9 v
(VOID *) (UINTN) BspStore
$ {: r5 U5 p* p4 k );% m7 M5 Z# a/ j; W! F
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)0 P; }% \; a- e0 n L: @; r1 M
1 d# ?) N# O# _% @4 k0 \DXE:
$ U7 g& i/ j% }; P/ V 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
0 J" r0 r1 g# _6 @' G) g; Q接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。% ^" R9 m) P6 ^" V
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver: i0 }8 R: [7 E/ }. Y( x
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
1 l2 J0 g5 r) ^6 q/ n7 j 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。' K" a ]5 [. b
1 g0 u8 E4 W' r9 ]( }6 e; A
Driver:
6 r( b: X& G1 G- W( q 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
* E2 V+ E, K/ d8 y# Q% n1 y 大家请看一下我们的驱动的makefile.(EDK中的*.inf)8 m" ]# s0 X& H/ P
[defines]- A5 z. f8 m( n2 B
BASE_NAME = OWEN
& C0 T3 p- F% S2 ^) V5 _; e! L% y FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110 b5 B) ~4 S; J+ ?5 R) R' s
COMPONENT_TYPE = BS_DRIVER# S* T9 i: }- {
# q! Q* [! a3 Q) T BASE_NAME告诉编译器最终生成的驱动的名字。
; T) a' c0 p: A+ u9 y5 [. W; I FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
2 o0 I5 K# T' {- s% Z2 J- i+ c COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。8 l; z2 A# I" x
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
& c2 D+ s3 K6 {+ h COMP_TYPE_EXTENSION mCompTypeExtension[] = {
n/ Y- \$ }& ]; Y2 S {"bs_driver", ".dxe" },
; d% T; Y& a' P6 A; Q {"rt_driver", ".dxe" },
5 O, J6 V- G) d$ p7 z, Q {"sal_rt_driver", ".dxe"},/ G/ T/ h, O; K. [4 @
{"security_core", ".sec"},' v5 _ x D. b1 u; ^. O$ w
{"pei_core", ".pei"},
7 `$ d+ l& I5 X' b$ Q7 ~, t9 ] {"pic_peim", ".pei"},
0 M5 _4 w2 _- K# e* S# F" o {"pe32_peim", ".pei"},/ D5 U" I5 v8 Y
{"relocatable_peim", ".pei"}, U( L8 f, T3 b1 n' }
{"binary", ".ffs"},/ q/ _! C9 V8 G, g3 w: q' z
{"application", ".app"},
+ i$ W# E" f$ ]: l {"file", ".ffs"},
9 ~: ]5 W# P3 L8 u9 C+ y) X6 k {"fvimagefile", ".fvi"},
! B' j; r4 W5 t2 r, U6 _- g7 M {"rawfile", ".raw"}," W3 {. e/ J+ ]7 A7 [$ s+ F
{"apriori", ".ffs"},
7 k( P5 A s8 a- v {"combined_peim_driver", ".pei"},
9 l; b& c. F7 d6 s) G( e7 J$ F. q { NULL, NULL }5 j7 b6 [7 m$ D! d5 I( r" A
};
, K. c4 ~& V' l: f0 @% J0 F0 G* ~! q- i! `
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)+ H& C7 ]0 f0 V0 y) F
- v9 @6 m7 I0 m6 b' [3 R) K
+ M0 h: j3 j; w3 \
|
|