|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。& E, j& U' A* [+ d: O: E
+ p) i7 y' z6 N$ q3 |; `3 {SEC/CEI:
; b& G5 \2 U6 U' I8 n2 K+ ^: d. t UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
4 z) b7 F% i0 h7 m在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
: [2 u1 j# E( B* f7 r$ U1 c, D! U& _5 p% B4 R* p5 b7 o- [
PEI:) H" _$ Q& S& i R3 j8 Y
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
4 N% Y9 K4 N/ i: G% y4 _ EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
2 P8 M/ h2 Y6 y; T6 d InitializePPIService函数,将PPI队列清空,这个队列长0x3F. ?0 w8 b. |# W0 k4 B8 ~
InitializeSercurityService函数,将Notify队列清空。
) z+ s* L6 C/ C2 R. f InitializeDispatcherData函数,将Dispatcher队列清空。
9 Z4 z n7 f9 _# u9 _ 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。) V2 Z9 L6 x2 M7 ^
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
" O% q9 T; E( D1 R u2 z6 c$ _ EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
; ~' a+ G- ]1 T; K {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},: G8 F1 h6 i/ b
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
R3 c, u9 S; C7 E+ f1 x* r5 z {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},: g) | E" n. g2 J
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
1 U* o4 J% q4 [' n0 P {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
& I; t$ r& u4 l {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}3 q7 i/ ], a. E* D- L2 P/ l' ~1 {
};9 }# q% U2 a. S5 y
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
K! e, L5 `; G. R4 {, n 这些PPI会在PEIDispatcher中用到。* c/ _. X( @( W2 k) T. h* h! {$ A. Z
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。8 p7 J0 T# Z* j4 }& v1 }( H
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。, T* u6 l) A4 i% q2 n1 N# R* o
SwitchStacks (6 I5 ]+ `" t+ T l4 ~8 p# v
(VOID *) (UINTN) DxeCoreEntryPoint,
, ?: N3 D: C. j; ^8 S' o8 e" ] (UINTN) (HobList.Raw),
* i X1 O% X7 W. J7 w (VOID *) (UINTN) TopOfStack,
* w* [: m8 Q W( f w( x* M (VOID *) (UINTN) BspStore
, g" z2 o) ~, b" `& _$ t. k) i );
1 C( L- d0 P( l 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
4 x7 \8 w) q8 ~/ W6 }8 u
6 W7 l' {2 E9 x- WDXE:
" j& e! f* |7 _, {3 F 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。1 [. }; S5 Z6 |6 l' }
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
: x4 M! h( G) w3 w+ w, ]' M 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver' L8 ^* K7 r' w" Y8 `
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。 I7 o: B" Y* L/ E! g7 z2 f
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
) C* |: B8 `$ v F 7 ]5 b) |/ w9 o8 s* H0 }1 R
Driver:
. w' P: d l y) g0 ?: a3 F2 U 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
( j3 a" U. h+ | 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
# {* R9 R0 s) z [defines]
, l3 L/ z+ m# s8 A& F2 j BASE_NAME = OWEN
# B) T2 X* V4 c7 g FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
3 O: ~2 c K: `( I7 Q COMPONENT_TYPE = BS_DRIVER
+ o, `. D0 {' p3 y1 _1 i4 ?" E; ]5 z. P6 M
BASE_NAME告诉编译器最终生成的驱动的名字。% I9 t& q7 n6 V$ e" g
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
4 y+ W4 [ V& q, E5 y8 ^ COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。3 e% u* e) G8 Y* j) {) T
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名+ Y$ D8 Z5 n, G) \
COMP_TYPE_EXTENSION mCompTypeExtension[] = {0 [- o0 N% \6 n9 H- Y8 C1 x( t% }
{"bs_driver", ".dxe" },1 T) r0 J2 W/ z M1 w
{"rt_driver", ".dxe" },
8 ^* F8 R, ~& X% @. ]( a4 U v {"sal_rt_driver", ".dxe"},; L" A L: U: {( k. |
{"security_core", ".sec"},$ K" i' f T/ d, N# l, S
{"pei_core", ".pei"},
! e, {2 [& R- Z+ d P5 P {"pic_peim", ".pei"},
; j5 c( l, c7 L& h; Q7 o! J7 L) D {"pe32_peim", ".pei"},
- Q; h% w$ Z- F6 {% Q, }" W; } i {"relocatable_peim", ".pei"},: |2 r3 e7 Y" {* U
{"binary", ".ffs"},# P% H' Y- p7 y' c% d( r
{"application", ".app"},
/ a( S$ a+ r0 c3 \& c/ i: I8 n {"file", ".ffs"},
: o+ |* d7 Z2 _6 }" I& g {"fvimagefile", ".fvi"},
: }( @5 G% b5 z- f7 c+ A' Q0 N4 i; | {"rawfile", ".raw"},4 K1 j, R+ P$ \# e
{"apriori", ".ffs"},, C, Q& }. O4 f7 _
{"combined_peim_driver", ".pei"},! p' u: j: B+ j
{ NULL, NULL }5 Q) N: R s x% u
};
v# a- h0 B1 ]" r o `. q; g+ r5 M# j7 S5 K0 N
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
# ~5 `% C4 s. o2 b
0 r% z* |% [) V$ S
" G; Z/ b% E, A8 T2 Q |
|