|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。; d: z9 j. m- u& @ D+ j: k) r0 Z
" |; r ~1 C) Q: m
SEC/CEI:
8 C. g8 q6 P$ h: a% E( o; ]" [: d; D UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
& `9 M6 V. e/ [) `2 h9 T9 n$ ]在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).+ }, `" t' Y# Z! r
% m6 i) R. w B* g0 g
PEI:
2 }$ v2 w- K: K' C8 q 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行/ q4 j) A8 j! t; J5 }4 ?
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
1 Q7 r4 s+ h7 ^ InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
$ @5 X2 O* [# B c InitializeSercurityService函数,将Notify队列清空。) g F0 y& N9 j( C- J
InitializeDispatcherData函数,将Dispatcher队列清空。; k# `+ \: L% T9 l! u8 T+ y+ F
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。9 w. z9 z: @: e( ?9 [
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
/ t' h- u9 y4 `# R EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {* g* @( P8 _3 ]( a
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},9 @9 d; B/ f: ~9 U) O; B' _' G: E* X
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
+ n# W* U, H- {6 I- x9 Y {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
1 f- r/ [3 d. M5 g- m" v {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},$ p- s" m& ^ A) Z1 ~' Y H0 D
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},8 z0 B( b3 A7 C1 D, Z
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}1 C0 y5 b: o3 J6 U9 `
};
i( h* Y* d: y% ] 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。* l! ?2 ^7 q% w
这些PPI会在PEIDispatcher中用到。3 z. n! K# i; P+ ?0 m& D
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。3 [8 y( w8 K% G* ]# {
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。4 t5 V: k+ B3 W) U: u: J
SwitchStacks (
9 m# u* L* c8 b7 G/ A. m4 f (VOID *) (UINTN) DxeCoreEntryPoint,# E. @: M$ o+ b4 L! d, n
(UINTN) (HobList.Raw),
) b8 V0 r7 H) ^3 ]# F (VOID *) (UINTN) TopOfStack, E; ~( o. ~, K" I, w
(VOID *) (UINTN) BspStore
/ l, Q; E' T; j5 q2 z );# u6 Q! }8 m u1 k, {
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
* D0 g3 b- ^1 c/ q# a7 O7 V g# N$ w3 q% S6 C9 q7 R; }2 x* C
DXE:5 M' A0 g0 A& X1 ?
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
- I+ s t& _3 I- N6 [接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
/ O8 ^+ ^0 B y. r# A 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver5 Y+ b2 A6 }; f% v4 j. w, {$ R
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
. E7 F: F7 n, B3 K" X; S 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。. f9 n- Z7 r% p; m0 i
$ n$ C# Y+ w6 a8 ]Driver:
; C, e8 b( v( L! Z K 我们的驱动什么为在PEI和DXE等不同阶段执行呢?, U/ l0 H/ j3 k9 v" n. p/ o# h
大家请看一下我们的驱动的makefile.(EDK中的*.inf)
; g/ N: M7 r' H [defines]
8 c! `6 ]4 F8 G BASE_NAME = OWEN, U& y3 Y. {. h5 o
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110! @, N: F/ g t
COMPONENT_TYPE = BS_DRIVER
9 Q# q& S3 j% J8 ^0 ]+ h! J! X& u8 L
BASE_NAME告诉编译器最终生成的驱动的名字。4 G& r" u; F. Z, p
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。) Q6 Q0 t3 X0 b# @& B: t) b( j
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。! Q/ \9 \ E" _! i* C/ A9 ~
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名: c: Q- [9 {, f. w& f' K/ M
COMP_TYPE_EXTENSION mCompTypeExtension[] = {
' h0 P1 Q1 D' b- V" ~ {"bs_driver", ".dxe" },) R( T% Z7 |, I# S7 }- L' m
{"rt_driver", ".dxe" },
; e, K; P+ U9 c; }- F {"sal_rt_driver", ".dxe"},3 L; y( d$ a+ Z( K L
{"security_core", ".sec"},
! G E1 i3 _: ~) B+ n {"pei_core", ".pei"},, I& D- l0 c9 t8 n4 z3 y* k5 y
{"pic_peim", ".pei"},0 s( w E( d' I3 e
{"pe32_peim", ".pei"},
# f& W' z0 Z$ _3 Z' j0 C: C {"relocatable_peim", ".pei"},
8 [# J, F+ U! Z. H B% N; I {"binary", ".ffs"},9 o. x! ?0 C1 S. Z
{"application", ".app"},4 L+ n2 K: O) o# Q' l! V) V- t
{"file", ".ffs"},
1 T. G0 g& L; i: B. e4 q6 S {"fvimagefile", ".fvi"},
" L. i( s4 `" r$ ` {"rawfile", ".raw"},' M$ I; c. }# C, n& o" J1 e# ^
{"apriori", ".ffs"},
# G. N2 ^( C" q- Q' C- M {"combined_peim_driver", ".pei"},
" a/ D6 F5 O% b) p- y { NULL, NULL }; H* k. L& A! @" }2 a; o- d
};
: p, b7 G( O1 Y" i# z9 J
- u3 c) G5 J$ c了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
/ \, x/ d8 V/ P5 G: q2 @ D1 l0 U
% N( |3 V; k* n7 R! Z
% y' M1 S5 H3 Y% J |
|