|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
6 f l5 Y# u% E4 S& G4 \" G$ ~( n8 C+ F8 e* P x9 q8 C
SEC/CEI:# O: R' L* e. n6 @4 l
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
2 Z, t7 d3 i8 I J3 F在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数). \: I p+ ?; i
3 I$ K1 z7 H& O6 Z, k2 dPEI:
8 J/ u& X2 n; X# x; x 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
6 `; p/ b9 Y; ?$ Z& A- z EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。& a: O+ `# N1 k X& F. q
InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
9 o2 m/ a. d% p+ C/ F9 Y4 H InitializeSercurityService函数,将Notify队列清空。
+ r8 z. ~" }( D. } _ InitializeDispatcherData函数,将Dispatcher队列清空。" G. ~, M1 O# l' E/ E: J5 q/ B
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
: c# d" Q7 V' i8 F$ c" |% N2 x. P 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西: d3 m |9 h# J9 r$ v0 \4 e+ k
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {7 j1 h, _) R4 ]) _- l3 t" j
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},% c2 L* o6 `* f0 G F4 i! D* D# f8 ?2 N
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},0 S5 n2 b5 {; x
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
( P3 g5 _; T2 {" H+ R" R {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},3 M+ n5 G+ W( z1 D
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
2 Z2 P+ w& |+ o% @0 C/ k {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
0 D8 Y& u3 F1 h( e! V; Q* Y };' u! a; r5 S. z
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。) B" s) q% I' j: z
这些PPI会在PEIDispatcher中用到。0 ?, p1 E$ H4 D1 O" ?+ J9 A& r
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。$ T" m0 n D/ J0 F1 C2 z
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
& M% A/ D* V* A7 J4 n. a" Z: m' M$ l SwitchStacks (
3 u$ L5 s8 d- Z U+ @$ d (VOID *) (UINTN) DxeCoreEntryPoint,
3 j" D+ n' F, S! t9 U4 R (UINTN) (HobList.Raw),0 B9 M7 S; _6 a5 ^
(VOID *) (UINTN) TopOfStack,
/ k- d# i$ \! f! } (VOID *) (UINTN) BspStore, e/ M: i/ l9 u" V
);& e5 C% \: a' H' L) ~) C
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
. {$ t( L, V' r6 l; D1 @, L$ g4 X% N$ e6 Z8 {9 g! P3 |
DXE:* M1 h6 f: n! ]% z. z3 V
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
/ `& d2 Q* Z2 m$ ^. S r+ |接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。) f% v9 ?, T& \) B
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver s# J2 |% g4 t3 Z% L4 }! c
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
6 P% x) \/ a: V5 \ 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
2 Q: y4 F5 }& V/ }# I$ ?( o / {& Q0 c' S9 [+ t5 M
Driver:
# {% E0 q# m. f: B! P5 y 我们的驱动什么为在PEI和DXE等不同阶段执行呢?+ o9 y( v6 a6 S8 ?6 y! m
大家请看一下我们的驱动的makefile.(EDK中的*.inf)* Y+ g. m I: i; H8 O/ F; g$ b5 k
[defines]* y. b" Y J: |& G- j; { C9 \: ~& g
BASE_NAME = OWEN3 r; L" z0 x8 w& \$ ?: P; S" q
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
" A$ K9 c0 b6 s5 U9 u( t2 H COMPONENT_TYPE = BS_DRIVER) u6 @8 s) K q8 T
. X, X1 s' ~# l# o" h) C7 X
BASE_NAME告诉编译器最终生成的驱动的名字。/ z3 W0 e4 \2 N& r* }
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
7 A' y, w) g) X1 T COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
]- L+ j2 d) ]# o3 Z) Y) P 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
1 A" ^! f+ h! e! q5 B3 w COMP_TYPE_EXTENSION mCompTypeExtension[] = {; {" q5 x! V! g
{"bs_driver", ".dxe" },) P3 e( c) `( A Q
{"rt_driver", ".dxe" },! o3 C. R, Y7 b% n% N5 V: ~" ]
{"sal_rt_driver", ".dxe"},
3 {9 S- P" D2 w/ ]' ^1 m9 @ {"security_core", ".sec"}, L: e" E$ E. m8 X4 @
{"pei_core", ".pei"},
7 ~9 v. y+ K' _: ]* f" m: t! ]! G7 c7 @ {"pic_peim", ".pei"},' ^4 e* p9 p; s2 t
{"pe32_peim", ".pei"},; l2 v/ Y3 N5 }7 t' |5 `" P$ h: \( T- Z
{"relocatable_peim", ".pei"},
! T6 o, X) m8 A) C7 D$ e {"binary", ".ffs"},
$ k8 y5 Q/ W% ~5 @! }6 r- y {"application", ".app"},; i4 b" o9 L( {, X6 B1 t" L
{"file", ".ffs"}," N" F$ q q' I; D/ U1 T
{"fvimagefile", ".fvi"},
! k6 Y( H! I' t" g4 X {"rawfile", ".raw"},
9 N! \; ?( B: d) K" U6 Z" w {"apriori", ".ffs"},
" _9 q7 _4 O& J4 ]9 k {"combined_peim_driver", ".pei"},! x( d! Z/ X& B5 T! [0 E
{ NULL, NULL }- b' y1 C9 k2 \' x, S6 Y
};- t; l8 K# ?. k; d. B! I
( `2 J0 [! B! T$ M
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)8 p, B3 b' O' k: z- I ^
; r. x- V/ X! ?8 u% X
9 r$ e \; A0 K7 c9 R. E( ~ _ |
|