|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。5 u$ w. o; W; m( h" O6 }# w
) B: k- k( S" I
SEC/CEI:
# q% i0 a8 l% D5 P UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。3 h X4 Q0 f( [/ f. d# |, W" B& [% r
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
0 A3 r! S1 D7 ?1 a- a. f; Q3 l% a0 y1 T! k6 m3 \
PEI:
$ R4 ~( u3 F% X- J( f1 R 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行; I& J3 }: l2 X! Z: n$ f0 U" Y
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。5 ^5 R: O( k% i2 M. [7 O! m _
InitializePPIService函数,将PPI队列清空,这个队列长0x3F.) K7 M' R& E- Q6 z* O
InitializeSercurityService函数,将Notify队列清空。: o8 l0 I' Q1 L; l) I" k: G
InitializeDispatcherData函数,将Dispatcher队列清空。
/ Z, F" ~3 X, K' x$ _% ^ 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。9 E; I0 ~, Y4 `5 |
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
* {1 U f A* c9 | F EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {( @6 S* d) F+ J6 d4 {6 t; }' q- h6 d
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},$ w2 t: l. Q" _" u w# t* i+ c
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
! \$ E5 ?9 J+ M* k$ `' ? {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},2 i, h/ S4 J" f# I
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},/ O2 u, Z) Q! g, X" o/ p& R
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
3 u. P: r* _5 a' ^ {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
( {- j6 i/ I" o: q6 a# F. u# R3 { };
) ~7 Y& X9 e: |1 q, [/ p& m5 h 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
5 G0 A# b9 d* |% j 这些PPI会在PEIDispatcher中用到。$ I3 `' S0 W$ g# ~( k
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
8 p; f, @/ Y+ y1 }% e9 j' e# g7 w, k 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
" R7 l- R, @5 C6 w1 U" R0 S SwitchStacks (/ e4 x6 @/ n% ?1 S* R" A1 W
(VOID *) (UINTN) DxeCoreEntryPoint,
! R4 p0 r9 O8 B (UINTN) (HobList.Raw)," R1 U: K6 N+ X$ O3 W3 {" S
(VOID *) (UINTN) TopOfStack,
+ x, U2 ^) B3 S, ` (VOID *) (UINTN) BspStore
5 @: n: z( N3 ~ V, K );8 ^: Z3 |3 e: l9 R; w
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)5 V+ [% P0 N! x8 N; ], ~9 n
' i' [9 e5 q. m9 j8 ~
DXE:% }6 n" M4 ?. i. `$ b! C9 g6 P, J4 z
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。6 {: _# b. z& |* ]
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。 i: n: U) U9 Z/ b6 K; j1 ~ ?
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
+ T! `0 W5 G! f5 x- v中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。: S' z" M7 @5 ~6 n* |2 M
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。1 e3 x' T( E: c/ {6 v) i
l) _) ^. V6 P; |, k9 q) k3 L- _
Driver:
% `! m/ s/ u3 J q 我们的驱动什么为在PEI和DXE等不同阶段执行呢?+ ~; v- `6 \: F3 W
大家请看一下我们的驱动的makefile.(EDK中的*.inf)
1 u2 y; y# ?) C2 G+ r1 i* e [defines]
( X6 C5 Y/ ]9 `( p- g) a* L BASE_NAME = OWEN8 B; O [- N. T4 ~
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110+ p( V9 i* p$ a0 c; X, k
COMPONENT_TYPE = BS_DRIVER9 Q: d5 }- N% L% x' t& j* _" G
% ^6 k$ \1 I! _9 d8 o BASE_NAME告诉编译器最终生成的驱动的名字。& f- q4 k' X' E4 _+ [, R
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
y) V. k3 o# ] COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。5 G M8 x2 ^4 X1 s7 F
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名5 C% Q [* |* K( }& i+ z1 k
COMP_TYPE_EXTENSION mCompTypeExtension[] = {
. L$ I! J! k; C1 d5 R' Z8 H4 g9 ]: a1 _ {"bs_driver", ".dxe" },4 F: Z5 A6 a# b5 M' ~" s! F9 f
{"rt_driver", ".dxe" },
. C9 G7 t9 y& z- t' E0 C {"sal_rt_driver", ".dxe"},2 c) w0 K0 l8 I9 l( v4 u" o
{"security_core", ".sec"},
7 U) L& U: G3 J- }) h {"pei_core", ".pei"},) U3 t+ y- W6 T" o, e
{"pic_peim", ".pei"},% a! ^2 g9 g# G3 {6 w
{"pe32_peim", ".pei"},
4 B" q+ Y( A0 R1 @$ I# ~4 Q {"relocatable_peim", ".pei"},
2 {/ e3 b9 @. a' ]$ F {"binary", ".ffs"},
# e& Y+ B: Y. n( m1 N( B. e {"application", ".app"},
0 F$ e4 L2 b- c. ?- X2 Z {"file", ".ffs"},
: y' [5 |) C, ~, m) L/ R' v! {1 S# Y {"fvimagefile", ".fvi"},5 c1 J$ P8 i3 J8 G8 O; f' }+ V
{"rawfile", ".raw"},
3 U, J2 A3 t6 ~; i! q4 ` {"apriori", ".ffs"},& ~# l4 Q9 N% s2 z/ |, G
{"combined_peim_driver", ".pei"},/ `# P5 x7 R' c6 l1 P
{ NULL, NULL }: e0 e8 W' E) N( H6 n
};
W( R6 }! Q& k9 j" K0 P. o
; F4 C9 P& Q- |$ {7 M了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
4 [8 ]$ u7 W7 O Q& ]
& T* }1 J$ a d/ J
8 c8 w( g& N' @7 C) x0 r, S |
|