|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
7 \% p6 k+ E( P" S% X6 b6 O `( h, V }7 r6 p/ Y5 O+ O- v
SEC/CEI:+ ]+ O8 P9 \9 w. x) j
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。5 N( H; a- ~. T2 A- \
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
9 V" f6 l2 D8 `% S ? [8 I; T" }7 b
PEI:
! G7 L( O8 M) n8 g# s- b* _ 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行1 k, x, x- b8 q" v
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。: _; C; ?& y: ^1 L7 w1 o9 L
InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
4 ^( E( ?% X. R InitializeSercurityService函数,将Notify队列清空。
5 Y3 j) M' w5 U InitializeDispatcherData函数,将Dispatcher队列清空。. R! p1 W- [) i/ E0 M& z: J
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。& K k6 a% z( D! j% }& ]8 ~' B. s
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
0 ]' s9 w9 W1 L EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {2 S5 \. ?: |% F
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
7 [2 K. P$ D X% x/ w Q7 k, ? {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},1 ]4 o* b/ `9 a9 Z
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
0 S# t8 m- ?/ @( w! M/ k* Y# z {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi}, n8 f: l- x* W# L. I
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},5 Q) v; j' y% M" [$ V9 F
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
) M4 M& n* [& c% L6 T" H };
; N' S, [7 D0 L; | 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。3 n6 R# W* v. M1 p
这些PPI会在PEIDispatcher中用到。
# B F( X! M! Q" r) g, g 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。 F, K7 \( a Y/ W7 v
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
* q% i9 Q3 j) m% O0 q5 ~8 ^ SwitchStacks (7 Y* U* k* r/ d, L
(VOID *) (UINTN) DxeCoreEntryPoint,
9 b3 S) r( }" Q2 a (UINTN) (HobList.Raw),1 ^2 V1 O" p. ]6 s6 ~
(VOID *) (UINTN) TopOfStack,
6 d J! @+ u1 `& h (VOID *) (UINTN) BspStore" W; E3 C7 P0 K, r0 q7 {% p
);' e3 ]) D& s4 A; y8 d5 r" j
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)+ F6 g- _8 a" f, ~, Y8 W4 s
/ q6 q Y% n; [ W# k8 K" ?
DXE:
% k) Z' V# z( u- Z2 N0 q 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。6 ^1 T& L2 k7 u1 Y$ b0 \& F
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
2 V; y& B: P" ~ 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
( R2 g7 f& y9 l! X6 h) F; U中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。: c0 W3 ^: m% p" s' D
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。9 w0 R, s) l8 k
7 L f% L. Q+ U; i
Driver:
, A5 o7 e& ~9 Z/ G7 ?9 ?0 v 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
! @: u/ [5 z# c; C 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
' X% R- C& C5 N3 W) B [defines] O. I7 `, I+ P: M; C
BASE_NAME = OWEN
/ g) L, D8 p$ \* ]2 G FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
3 C8 Z7 Q& {+ U; }$ b+ A) t6 ~ COMPONENT_TYPE = BS_DRIVER% h/ z! X6 H5 p) Z
+ M& u- Q$ ?4 g8 x4 `
BASE_NAME告诉编译器最终生成的驱动的名字。( R$ _# c8 D6 C% Z! L
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。1 }7 t4 M, ^- |: v! R7 J# x
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。/ f X" V n* w% u U! ]) q* O6 Z- A
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名( A7 B: {9 e5 p. _, t) [
COMP_TYPE_EXTENSION mCompTypeExtension[] = {6 v# ?( q/ K& |4 v
{"bs_driver", ".dxe" },7 h9 }2 J! g% i3 J! t
{"rt_driver", ".dxe" },
! {6 o' j- d, \ `4 H, \ {"sal_rt_driver", ".dxe"},
3 ?1 ]7 g, W, p+ s+ C' Y; E9 Q {"security_core", ".sec"},
. d6 ~1 c; Y4 V+ T' ~3 h. n {"pei_core", ".pei"},, ]& o5 ?( y& `5 ]- ^
{"pic_peim", ".pei"},
' P& n% ]( J; z {"pe32_peim", ".pei"},
! m- G4 L7 d0 v; |0 ?& w8 Q5 V {"relocatable_peim", ".pei"},
$ s5 b7 @* F5 `5 O- L3 D {"binary", ".ffs"},
$ P% C: ?' r+ }; @; d5 n {"application", ".app"},
" k$ A! x. v$ ~4 i L# ` {"file", ".ffs"},
3 ]/ i' ~, t6 K% s" G8 {: h4 W {"fvimagefile", ".fvi"},
' o: v$ I# x, ]* x* E {"rawfile", ".raw"},
5 a0 V6 V4 e, T* w% q) \9 z- M {"apriori", ".ffs"},
1 L7 m% l ^. S {"combined_peim_driver", ".pei"},6 s" u! i; l, j# f4 K& h: y# r
{ NULL, NULL }$ |- }, s. x5 o4 E
};9 j. C* f" u# d9 e2 i9 {: N8 G
* X5 {6 W: M, v+ p
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
+ E! W1 X0 Q1 d7 g: `
6 W+ z6 r2 p+ e, R5 s9 x ( y0 y% X. }: [+ {3 u
|
|