|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。9 u/ E. p' l* j
! k- i' a, q$ D# X! o+ K |
SEC/CEI:& k2 u O: m! P% G Z
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
! w: O4 O$ H; E- v在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).9 ?! l7 r6 c( |% N" h+ `+ r& _! ]* c
$ n, U- ]: s7 b9 ^- [4 {
PEI:0 ?3 v$ H% Z6 ]$ G! b! M
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行+ s; Z; L3 o+ K1 P
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
3 w/ s4 Q, U: g# p$ g1 ^9 ]) V' S InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
( s9 h& f" W) s6 v: f2 i$ h, S( }6 N InitializeSercurityService函数,将Notify队列清空。
7 T {, H2 A8 U. \ InitializeDispatcherData函数,将Dispatcher队列清空。 t/ O1 C9 a' p: c Z r% v# W
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。8 Q$ ~2 K5 g: Z7 n( _
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
. w! c0 H7 A- V9 g EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
( p5 @: b1 X% ^1 h {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},$ _/ E9 u4 n: ?" H* j1 n
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
+ f6 ] C7 r; _* x {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},' N9 h& p; f. J$ E6 s% S
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},, V- e. F1 `3 ~+ [: k
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},' l9 k! d+ p( M9 y! F
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}1 a- x: \0 V3 c- h2 t9 r i- Y# j
};
& T7 S$ B% [6 [ 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。5 Y* m8 U4 Z$ q" M
这些PPI会在PEIDispatcher中用到。
9 m5 [7 Z2 V/ A+ { y* X7 f! W( b) q 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
) n/ T+ r. {% [/ E: B' w6 ? 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。 B& {6 ?4 f6 F) @0 D [. y5 \9 P/ E
SwitchStacks (
4 }+ H4 R2 c/ q (VOID *) (UINTN) DxeCoreEntryPoint,# J+ h' z* h. i! y
(UINTN) (HobList.Raw),- Q6 H7 G. g% r" V
(VOID *) (UINTN) TopOfStack,5 i% W/ V% R7 \
(VOID *) (UINTN) BspStore
@6 N. A0 F* ^1 E );- e" ~; Q: [5 G! Q
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
% z, ?" Q0 h# v0 K$ j+ e) |9 _
& N. @. N# F) {7 Y$ g% {% {) W8 @DXE:. U/ l* \8 C. |
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
% G% B, p* C( h2 u m接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
6 F" [0 i+ C. i! I 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
, u3 ?# l- z- H7 j0 X$ I$ w中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
: M; q! X( H I3 m& l 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
; \( I# ~5 N& \9 ]- E5 s 8 ~; O7 @0 `' a; E: t" ]( J
Driver:
9 ^5 C9 \2 B5 d& w$ q 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
/ p' H% @' \" U1 e4 p 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
, P, d, @! p$ Z8 H [defines]
+ d# n/ f* k* \9 @+ D3 O BASE_NAME = OWEN! \& B+ F* e: y
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
: j* q( i0 P0 D4 B2 a8 T, M COMPONENT_TYPE = BS_DRIVER
0 a' J( E8 r, W, h3 o ^" q. s! V# q
BASE_NAME告诉编译器最终生成的驱动的名字。0 O2 j, V" J3 F! p6 u5 G
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
" `" L, R5 L8 o( Q COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。0 g) u7 }) j- {% G: Z' E4 g
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名% b. s! q" m: f! z, R
COMP_TYPE_EXTENSION mCompTypeExtension[] = {1 g5 X; S5 z/ p" W4 l0 n! ?
{"bs_driver", ".dxe" },
# K ^0 d# U: t) m) G {"rt_driver", ".dxe" },
$ C4 [% g& O) @ {"sal_rt_driver", ".dxe"}, J2 s2 F) v9 t' Z) @( E
{"security_core", ".sec"},8 U0 a& K X: Q+ }8 @( l
{"pei_core", ".pei"},& @- V0 ~6 r# K+ @3 }
{"pic_peim", ".pei"},
3 B- D3 f, P# O {"pe32_peim", ".pei"}, N6 m% d7 E4 W9 U3 ]/ J! f
{"relocatable_peim", ".pei"},
7 L' I G; r3 D6 H. T( N {"binary", ".ffs"},
3 L& Y Q; i$ j' h- B" z+ | {"application", ".app"},7 D9 W# ?0 X( S
{"file", ".ffs"},* D# E7 M3 M4 j: }4 {
{"fvimagefile", ".fvi"},
$ M0 V2 J- Z- S; s Q4 U5 j {"rawfile", ".raw"},
0 B r2 ?, A, g: C5 X7 F {"apriori", ".ffs"},
% X2 a: |5 u' Y" ~6 F; I$ r w {"combined_peim_driver", ".pei"}, u G) A3 d1 I9 o2 U
{ NULL, NULL }9 [$ {4 }2 ]5 z, V! U$ d d! _( m. @
};
3 u& E. J1 d, Y+ ~; R/ j$ H( r! o( L1 S4 {! s) ^# z
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)" V, ^- n* D; c- p5 H. X6 Q
9 Y' d9 e; {, X& a; D
l' G* {" d: e. L: Q
|
|