|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。5 s9 e, e/ Q) ^( R3 x
" p" a) a( S9 y& I$ YSEC/CEI:- R4 J2 Q* }* F0 o
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。/ o5 {% e4 l* D0 i8 {; O6 x; ]
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
1 f5 o+ @% J+ i( m4 S4 D: W+ f) G" b+ F
PEI:
5 }% K" S4 Y% N' z( ]& h/ r1 K8 v) T 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
2 R$ k) c+ \ j' p6 x EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
$ a$ M1 }! p1 n. a3 T, [ InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
$ b$ C( @5 Q, S( A8 ^0 C InitializeSercurityService函数,将Notify队列清空。# |( t/ F/ u- m& |: O E
InitializeDispatcherData函数,将Dispatcher队列清空。
$ f, [5 ^5 Z% M/ D9 B: ]" C" B# x: \ 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
- W. \! N! W1 D; E8 V 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
6 b6 o! @6 p+ R EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
9 S$ ], K/ J' o) c P {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},) @2 X f2 @: r5 m+ M0 n
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},! B! K& N! t1 b
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},& v' G6 m- d/ I$ V
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},3 k: ~. ~2 x: S
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
" R- ], L- ~! |& g0 A6 K( A {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
) f' B- L3 a) W" l: e/ d* w: `/ H };
& T5 `0 Z8 ^7 v8 ?' Y. a 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。/ x6 p1 R3 c; I$ V
这些PPI会在PEIDispatcher中用到。
" Z3 a' i) o7 U, o4 \1 r. v 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
/ ^" v$ e. A' G& _& l 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
Y) g v' P! P: B- E; C9 Y- S SwitchStacks (8 c( ^# f% D7 F+ [- ~5 t
(VOID *) (UINTN) DxeCoreEntryPoint,; ~% o% |4 K% C1 b1 J9 n P: k
(UINTN) (HobList.Raw),2 I1 P" v$ v! K) V, d K+ B6 e5 j F
(VOID *) (UINTN) TopOfStack,
$ u) @) {. E3 j8 E, O4 U (VOID *) (UINTN) BspStore
. V3 j- X, g* Q1 l4 R; H7 a );9 n, Q6 U& ~5 x8 p% [
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)( |, m E1 W5 Z4 m( _9 `
$ E4 d6 r" ~$ ^1 m( sDXE:% L% p2 {2 n8 ~# y# F8 h
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。- m" u( _: @: V
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。: k8 O7 H% P& h$ }
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver" j; S) u/ ^- |! @; d: _, R
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。& }% A7 K2 _0 R7 T1 B y" W( A
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
- J) E2 C1 z" |( N
& n5 g+ g- f6 V: [9 s! j$ u2 X4 S9 A' hDriver:
6 M* \' q. C) }+ _ 我们的驱动什么为在PEI和DXE等不同阶段执行呢?$ H8 H% D& B& R* B. S+ V# z& V- G
大家请看一下我们的驱动的makefile.(EDK中的*.inf)9 M8 f& N! `! _7 J- F9 ], q
[defines]
* h2 I; [; m2 O9 S+ Q+ J0 v3 t& ] BASE_NAME = OWEN* `3 ^' S5 w4 d$ h* ]5 n- c
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
7 m# A4 M$ o% L( d1 l COMPONENT_TYPE = BS_DRIVER: b1 I) G* o! C+ v2 E; p7 T* d' V
! A; N1 I- X/ H; J$ s/ j( H BASE_NAME告诉编译器最终生成的驱动的名字。+ {: L: z: V1 E& }* n4 q8 J, v
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。; L, g( v: |" C' h: ~, J
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。; l. x" o; M" e) Q' ?1 o
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名 o# H' y* [$ {
COMP_TYPE_EXTENSION mCompTypeExtension[] = {4 A& ~$ s/ C5 G4 A
{"bs_driver", ".dxe" },
! g8 B+ B- v. B6 j: w3 t9 p/ y {"rt_driver", ".dxe" },5 L" x4 i5 \1 |. J4 @
{"sal_rt_driver", ".dxe"},
. L. V6 w3 \, M( M {"security_core", ".sec"},
}) \" T9 ?- m, L: L3 T* z7 ` {"pei_core", ".pei"},' o$ O3 W3 @% t+ q7 _
{"pic_peim", ".pei"},& s" e8 G# S; e) W, K
{"pe32_peim", ".pei"},2 ?$ U' t) x1 M8 ]" o* \7 j
{"relocatable_peim", ".pei"},
+ q6 q& b5 J/ i9 q6 ^# u {"binary", ".ffs"},0 y" f1 _3 Q$ [' U
{"application", ".app"},/ h. j/ |- {5 f, M1 C4 B
{"file", ".ffs"},
% ~# u0 I. O' A" b* k {"fvimagefile", ".fvi"},
' Q( S/ f& `$ { {"rawfile", ".raw"},! \, p5 X, c# j0 y
{"apriori", ".ffs"},
2 d3 R- t7 g+ n) p5 J8 G- R. ]. d {"combined_peim_driver", ".pei"},
$ Y/ |" M- f# e, f- \3 x { NULL, NULL }
" N1 M; m* z& W! k \};
: w D8 C# q4 b6 ~: [% p8 z: S/ _ _7 y
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
M5 d# X& L+ k8 W$ D/ L% K
# @. I. Z. t3 @' d( X [) Q$ H
4 ~/ S% W5 m) Q6 q( ~& ~ |
|