|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。% U1 c/ g/ _- |- U; t% t
( H G0 _& e( @! ]' i1 k
SEC/CEI:
6 u* t' b" ?! y' g' I6 q+ J UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。, T5 \% D5 d! X7 ~# N8 }( u# q( v% m! K
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
: x1 L2 I* u3 L4 E6 [. }. i3 \1 C; P/ ]
PEI:
; P0 b# w9 [: E7 i1 p% e b 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行. u. W) D; R/ L- y
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。! C, Q! U6 t$ d5 A$ P0 d
InitializePPIService函数,将PPI队列清空,这个队列长0x3F.2 m- a0 c6 z* ~% z% x* I! X
InitializeSercurityService函数,将Notify队列清空。' [) O1 Y! `1 F+ U/ q& u0 y+ e" Q$ @
InitializeDispatcherData函数,将Dispatcher队列清空。
- z7 p3 H2 Z; E# o6 }: p4 b 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
* c; ?7 g& ?& Z 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:% C! `% y/ q7 }7 Y
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
0 F4 Z5 r# d8 ~; l) t; _ {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},6 R$ `5 g, `, X0 L
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},) D1 E, z/ a% w# Y) u4 ]' [
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
& w3 ]! @1 J" K. a( E% ~ {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},; R" T: p9 K. y V4 l$ _
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
$ I; l* f4 a( o Y$ ]6 F) _$ g" Y6 C6 Q {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}+ @2 J8 D4 M7 J A
};. l. F' M' B! Z
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
6 k$ f. q* F' b+ d# h0 m 这些PPI会在PEIDispatcher中用到。7 y+ ^ B4 a/ T' N8 C8 p4 t: {
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。: b" \) B% o$ s
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
7 T- P o9 C Y" Z SwitchStacks (4 ^7 K5 l) h" [7 B# w" @; D
(VOID *) (UINTN) DxeCoreEntryPoint,
4 y y! g3 R+ w: o% H) g) ] (UINTN) (HobList.Raw),
9 Y' K' ~+ {/ \& m/ p (VOID *) (UINTN) TopOfStack,! Q. m" d- I- V7 O% z# v- f
(VOID *) (UINTN) BspStore) r1 q$ ^$ K; k
); Z* q4 a# ^4 J1 n: a$ e ]) y
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)0 H" }0 }/ h/ e' k+ a; t, `( U
6 `7 |0 F$ i) e" i U
DXE:
; L% @6 m( v3 [4 ? 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
5 p1 y* |, q% j接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。1 F. L4 m/ W5 v3 M/ C9 g
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver. o& ^( \2 M0 h0 {' r8 [& L; {( q# s
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。# k' e6 O6 j- ~& U0 H8 U+ M$ x
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。% Q& d* d. q3 z, S4 T! n. \
/ M& z- i, [5 i; o
Driver:
4 q. {, y, o9 q0 n, k2 } 我们的驱动什么为在PEI和DXE等不同阶段执行呢?9 }- e( j3 N( f+ D5 D1 ]
大家请看一下我们的驱动的makefile.(EDK中的*.inf)
* _' ~! X; W2 P [defines]
$ @2 S. @0 u7 D% P2 {9 Q BASE_NAME = OWEN
6 y4 ?3 A- W$ V- R/ \: x FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
5 N7 o' {& y9 d( \4 f5 E COMPONENT_TYPE = BS_DRIVER
7 b7 f: ^3 X0 N# u* i2 T" t" X# ^1 E8 [6 V
BASE_NAME告诉编译器最终生成的驱动的名字。# N2 K0 ?: H2 e- Y" N
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
' Z' q3 s- E% Y4 N0 |& z+ s+ @/ y. N COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
A$ Q- H/ P2 ^- G* w& e% i 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
5 N8 [, o2 b( e' z, T& b COMP_TYPE_EXTENSION mCompTypeExtension[] = {
. ]% U w& I0 {& q {"bs_driver", ".dxe" },
& p2 L$ x6 H8 u7 Q% g {"rt_driver", ".dxe" },
6 w9 T" c- h: C2 a* Z$ _. Z {"sal_rt_driver", ".dxe"},+ u* _1 g: ~) ]; J4 h
{"security_core", ".sec"},
% h( Z& l4 ?6 L {"pei_core", ".pei"},9 t T# F$ E) E. k5 f) J
{"pic_peim", ".pei"},
6 ]5 B0 L' v8 b }- Y {"pe32_peim", ".pei"},) \2 b- L& l) ?) f0 E$ N, l# ^
{"relocatable_peim", ".pei"},9 ]6 A, s% y; i3 ~+ L0 U
{"binary", ".ffs"},
0 ~6 M' A z6 d+ R' ? {"application", ".app"},
7 t& T# A; o* r {"file", ".ffs"},
M* b0 t+ t# U2 W {"fvimagefile", ".fvi"},* S- w/ C) q; b) X( \, F
{"rawfile", ".raw"},
# Z. t5 |/ ?! M6 O) x6 @3 ? {"apriori", ".ffs"},* U' _' I9 w% @& \9 [
{"combined_peim_driver", ".pei"},
5 S1 d5 C; w, O0 \# v c( { { NULL, NULL }- @6 r! f& W/ b# h8 d/ A
};2 q2 A/ s' @: H! v6 ^
0 U; N6 o* u0 d6 m/ j
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)5 _4 ~9 _: }( z
& b% f+ L( R/ T- R( z+ P
8 _4 g4 C8 M z c |
|