|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。) y* U u# [! m! E1 ^
' B) x; _9 b, d
SEC/CEI:
8 u5 g+ ]/ u4 l. c. C' i; m UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。. i2 M0 p, @2 c) d5 O! l, o- {
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).) w$ L, Q4 {/ @4 p5 B* w# |/ \
* u8 E4 \; j$ t n& A; c: dPEI:
9 Y) P6 A+ P" I 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行" I! @1 j% d* }2 u
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
8 W4 d) M5 D# b InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
6 d* z$ ~2 v1 O. F8 i InitializeSercurityService函数,将Notify队列清空。5 m; p+ T H$ _% @3 z `; _5 b
InitializeDispatcherData函数,将Dispatcher队列清空。. L/ f& G, |' s o# U A4 a2 [
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。% G9 g r8 H; E2 R/ d
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:1 w1 i# X& `; |& y7 b% }1 Y* t9 F
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {$ S8 Y/ x* O; h! p# i
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
. P% A; t+ D$ j" a. w- L4 E" b {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},& g4 U/ z( c* L( w5 u: ] |1 P5 ^
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},/ W x: H8 J1 e4 t
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
) s. ?, l B | {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
0 b' Q# T4 ]; c {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
, I5 q! p5 c6 N1 c3 { };
( X9 v8 v" h: G2 A 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。5 w: O" x+ K, T
这些PPI会在PEIDispatcher中用到。9 B! T% g: N* M( k2 w
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。: N% H$ t' o. u" A4 Y$ O/ J
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
% P; g5 w0 H! t0 [3 V$ u SwitchStacks (. |% M! R9 q& j
(VOID *) (UINTN) DxeCoreEntryPoint,5 T$ q3 \: n. `6 N% `, D! a
(UINTN) (HobList.Raw),
+ t% o: z& \( {/ [2 X0 N (VOID *) (UINTN) TopOfStack,
5 x# J- @0 A0 `3 A6 r (VOID *) (UINTN) BspStore
$ G6 D. U0 b* t: |4 a" V );
) {2 v% R6 v3 v' J6 s+ h1 y3 M, k 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)1 D6 o# q" Z: a6 a2 ]/ T6 \' D
) S, l- p6 |5 B: a4 K) }+ M* l
DXE:
J' u) c2 |, t- H$ e2 k 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
# B, K+ e5 i s% \1 c接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
1 u8 w: g8 Y4 Z/ J, W6 Z6 m. D) D$ ~ 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
* |$ n! B- F) `4 Z中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
7 e- O" C4 Y$ Z1 y3 @ 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
2 x' m' L3 D I4 k: e ' n3 }, M n# Y/ {7 R/ z' V% ~0 A
Driver:
- T0 ~9 X, H8 J* V+ p 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
/ {# z( w' E3 c- N9 {0 o$ B 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
$ ~* a: y, V) D [defines]; [, T* i- }! P: ~% s
BASE_NAME = OWEN
( W6 @3 W8 d. u+ R' G! g( E0 }' D FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110, t+ d/ b5 p r% X% E2 q
COMPONENT_TYPE = BS_DRIVER
+ k5 B( o6 n, A E. Y) |& t r! W3 b: n0 w* Y
BASE_NAME告诉编译器最终生成的驱动的名字。
]9 d% J: k# I: w4 c FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。$ s. W, T) _5 h F% Y
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
% l% E$ L4 K, e 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
2 N; g8 d- ^; T$ e5 ~$ u0 A6 @ COMP_TYPE_EXTENSION mCompTypeExtension[] = {
/ p0 Y) p& H) `7 n. v7 T0 ? {"bs_driver", ".dxe" },- u& z' v. Q+ l4 W; z3 E* u B+ K
{"rt_driver", ".dxe" },, v( N* B$ E) S. _4 Q4 M
{"sal_rt_driver", ".dxe"},( n: X4 c4 U% u. h: I
{"security_core", ".sec"},
: ~7 Y# i6 k7 d* W {"pei_core", ".pei"},' i$ b3 ^" C; X; e
{"pic_peim", ".pei"},( k' E" e6 |7 n/ i; L4 c+ D
{"pe32_peim", ".pei"},
" h9 Y/ R$ }: L {"relocatable_peim", ".pei"},
. P+ e- I# F8 x" X# a {"binary", ".ffs"},- V6 p! x5 L4 j% c" K# @
{"application", ".app"},
5 M1 f& M' |7 ?" V1 Q/ d+ P' D1 R( { {"file", ".ffs"},3 F5 C, I) }- C
{"fvimagefile", ".fvi"},
1 G" ?7 p% Z G% _. P {"rawfile", ".raw"},) m& @/ @" Y3 c# f* ]
{"apriori", ".ffs"},4 D+ q6 g5 `2 i$ W/ V
{"combined_peim_driver", ".pei"},# J* [8 s+ U9 G0 {' R7 l
{ NULL, NULL }: G: F8 A3 h& d4 @- ]
};
) o5 q1 s9 p- D4 y' e
% N! w, z5 o% ? B. h了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
/ L' \) \5 F" _: V5 ]
- }1 I T( S# `4 x * z9 i2 G2 T3 B( e5 c- ]
|
|