|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
% @+ T4 C4 F! L: f5 P+ o a* K6 M. a3 j$ ?; J6 s
SEC/CEI:% H; Z( C, z9 N5 U
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。: D+ Y2 @; a/ j* P0 p6 {* L1 g
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).3 ]* e$ ?! e& ]( l Y) r
/ G' |7 A0 D8 C8 p3 U7 W6 RPEI:9 e4 h! h; c1 F+ V
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行! A3 L {) z, w) J
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
! \2 a+ W; N# P+ r5 S4 z5 n8 u InitializePPIService函数,将PPI队列清空,这个队列长0x3F.2 a3 c5 W' |. o% H
InitializeSercurityService函数,将Notify队列清空。% L* l1 [8 R5 q8 n" J
InitializeDispatcherData函数,将Dispatcher队列清空。# X& u8 v" D( o2 M
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
. @4 X7 O5 W0 m9 p4 ^. ]5 E ? 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:0 X% i8 u$ s5 @( h( f( P
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
1 \% `6 ` F4 q+ u {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
' k9 R6 d, T1 p, ` {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
' r$ x6 ^; {% m/ G( } {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},- g6 D/ C$ ^( E! a, @& ^ X
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
+ W; Z+ k; Z2 j {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
/ e) A( I" |( `6 q {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
$ @' s2 |! K; j3 k+ y. M. V };, {2 k! Q& H0 F8 f( p' q; D% z
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。( }9 T- X# N+ _$ G `
这些PPI会在PEIDispatcher中用到。1 o, L* S( _. Q I* Q9 `
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
' O1 D' b4 E3 z3 g4 Y# X2 N& A 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。% u3 ~2 W$ l8 o- \: Q
SwitchStacks (
& y+ }8 D3 K7 t' [- p (VOID *) (UINTN) DxeCoreEntryPoint,
, R5 A% ~: W+ K7 P# h2 v (UINTN) (HobList.Raw),
& ~$ a5 A) C) P0 K" \! a/ Q" x (VOID *) (UINTN) TopOfStack,; u/ j3 |) S* V1 Z& T; t
(VOID *) (UINTN) BspStore/ @8 H8 @/ i% @' W
);
% Z D5 [ ?4 f* S( K9 M8 h 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)) F3 E5 o- X2 k0 s7 a
+ e- H, J8 {. F" fDXE:
0 g7 ]; X6 I7 h. u Q 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。4 t3 B- Z! n! Y) P& a* ?$ r
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
. B2 o/ y' O4 G% e4 V8 ? 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver+ c6 E1 n& I; D9 _, G1 x& p! C( B m
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
/ @5 W7 ]5 A6 H9 s 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
0 Z3 W4 c3 b7 |0 V% U4 b7 ?1 r$ {
2 n. u7 `! ?6 c+ ~ qDriver:$ F9 P3 r' I( u* @% m
我们的驱动什么为在PEI和DXE等不同阶段执行呢?
$ Q/ `6 a( T5 R2 U! u% J& L6 @5 n" C 大家请看一下我们的驱动的makefile.(EDK中的*.inf)$ L; H( a1 [. K9 n
[defines]
7 l8 |: u& k- e% b BASE_NAME = OWEN
7 {% r/ t3 \# o; q FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
1 w w8 F% `, c g7 w# ^ COMPONENT_TYPE = BS_DRIVER
7 {- e. R9 s, @ o
/ t( m7 y3 I" w) e! H) w BASE_NAME告诉编译器最终生成的驱动的名字。/ x% V3 m& w) q3 K$ P8 Z2 _* A
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。+ O2 X" q; K0 a4 k: Z% H3 e2 i
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。3 L4 c$ b) c/ B; W$ f: `( K
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
! I9 m) ~- L7 }: o5 V y+ _ COMP_TYPE_EXTENSION mCompTypeExtension[] = {
" t3 @6 K5 S0 t( L. u- k' \ {"bs_driver", ".dxe" },
N: o# }. B) }% J, e0 | {"rt_driver", ".dxe" },
" J: P V% s' R6 D# w {"sal_rt_driver", ".dxe"},4 S, W* ]3 E: N3 X
{"security_core", ".sec"},( {3 a/ R) p) u1 L
{"pei_core", ".pei"},. P' C5 A8 c9 M0 d+ v( ?
{"pic_peim", ".pei"},
- k R! u1 Q- {& J! c4 a+ Q& k6 h( p2 w {"pe32_peim", ".pei"},1 |7 h9 V0 `, Z6 ]. j" x; J, s
{"relocatable_peim", ".pei"}, A: y! p2 r7 n
{"binary", ".ffs"},8 q% H5 X) ^7 W0 z- G
{"application", ".app"},! F( a% U5 @* | u7 N
{"file", ".ffs"},
2 r7 G2 }6 k4 { h# Y {"fvimagefile", ".fvi"},+ q3 t' v, I7 P+ p6 k: M; d& N
{"rawfile", ".raw"},
0 S! \9 q/ {0 O6 e {"apriori", ".ffs"},
5 I- F: b) S+ |$ C7 M. Q {"combined_peim_driver", ".pei"},
7 c( F! |; o3 J% S/ p+ p0 n* D' ^ { NULL, NULL }
+ n% a9 t% B5 J/ G9 a7 Z3 ^: g};) a. I2 n' ^) f: O, ?/ J
& t+ x* f5 d8 T8 N& @
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever): a5 ]0 l5 X0 `5 f0 q
$ z3 {5 z$ X9 l7 x: L w
! |- Q1 h3 k/ Z# V* E |
|