|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
/ K5 M" s; w1 }! w H( Z3 V/ u8 X
% x8 l' F/ G, i/ kSEC/CEI:* k8 Q% h' D# ^( x8 F
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。, A2 e2 {. c' \" w$ i
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
# p3 r# k l' ~7 a. ~/ Y5 n2 G7 Q r) t- F; _0 p
PEI:" Z2 U6 x* T4 h0 a+ j$ c
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
; X) W/ @+ P ~! z EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。) P3 N" J- x- p# L( P- z* ?
InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
" w2 E0 r) ? v9 t* |3 q. ~ s; V InitializeSercurityService函数,将Notify队列清空。
. ?% Y- C( y2 T6 W InitializeDispatcherData函数,将Dispatcher队列清空。
$ X! x4 M# W- s# C8 @9 I; \ 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
4 i) Z0 U Z' C: P0 d' \! ^' c; i 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:4 g5 L; U: l: R! L9 C
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
% R- \5 Y: O( w6 Y {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
, a" B, j2 J* U3 X5 \0 O: ~9 g {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
! z0 U' u% n- \' y; w {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
7 @. P& T& L; f! | h7 F8 Q7 ^5 ? {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
; m+ J* L) L; P+ z0 x {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
' L t# n* F3 `, T# I {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
% w9 X& I9 { y, r };
; R. @3 T8 n6 }: y 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
. Q1 u( e U& O5 t- X- d* v+ U& _7 P 这些PPI会在PEIDispatcher中用到。
$ o4 [1 s4 h- D1 J' q( g9 O 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。3 G6 _$ D P7 v( z- Q0 I
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。" f* l! X$ ?+ v7 J
SwitchStacks (
7 K0 X7 h% N1 P4 `# F! E (VOID *) (UINTN) DxeCoreEntryPoint,
# W2 P- e" d, @% P0 q (UINTN) (HobList.Raw),- U( _ ^- Y* o
(VOID *) (UINTN) TopOfStack,
! T3 d$ u8 W0 w2 m1 u4 C k, K (VOID *) (UINTN) BspStore
5 Z- Y2 `, _1 J8 x; @5 V );
, a0 S1 Y, }8 Q' {6 H8 n$ b 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
' d0 z0 {$ \9 ?, T! T C3 A$ N7 g
8 N7 O, a( r. j$ f* jDXE:9 n* ^) }/ @" i# b2 W( `& J' `7 i
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。' Z) h5 z& A% F) Q
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。3 y8 K# v( H5 z0 r6 r
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver3 \! b' t8 F, ~- E5 h; {$ {
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
9 Y6 Y4 B2 x, K8 w, G8 Z 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。: O+ {8 V# M# x! h
* ~( c8 [, V; z- E8 M+ H. V* lDriver:$ A0 r: P5 J' s5 L1 ?9 ~* ^0 n
我们的驱动什么为在PEI和DXE等不同阶段执行呢?3 s! M6 R! X5 z1 @0 a# W
大家请看一下我们的驱动的makefile.(EDK中的*.inf)
( M; d5 A: K& X# z [defines]
6 q) t- @0 H. z | BASE_NAME = OWEN7 T1 ?( C' x% s7 F/ \; Y
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
; h3 s, ], \: }# T( W% A* T3 R; _/ } COMPONENT_TYPE = BS_DRIVER
7 O# u) |3 \7 \6 X4 X
0 _' @, i q, F. j2 l+ ?& C# j BASE_NAME告诉编译器最终生成的驱动的名字。
1 Y, {, g/ \' |8 k FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
- w; E G$ o! L, ` L3 X+ n COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
h3 T; P) l! Q1 N, r) p. Z) q7 ~# r 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
* c( J% I( Y" l# b- Y- Y$ i5 | COMP_TYPE_EXTENSION mCompTypeExtension[] = {( K% r/ Z7 |) O; X; T' @( i
{"bs_driver", ".dxe" },6 U/ _+ X1 Y7 V W# ^; o( I
{"rt_driver", ".dxe" },
) x: l/ V$ [4 e) a {"sal_rt_driver", ".dxe"}, G: g$ p3 o% Q0 h, \% j4 ?. o( s
{"security_core", ".sec"},( w! J8 ?% i5 i7 A4 o& f
{"pei_core", ".pei"},* L9 P$ s7 ]" c( z( ?/ V6 _6 F
{"pic_peim", ".pei"},% h3 S5 H0 p6 @4 S% B5 \5 t- V
{"pe32_peim", ".pei"},
2 G2 s/ |; V, d {"relocatable_peim", ".pei"},
4 u4 _6 E* H. K, t$ B4 S! B% T {"binary", ".ffs"},7 w; ~: d2 i( ~
{"application", ".app"},5 p- y. h" m, J; U+ I/ f
{"file", ".ffs"},# s' ~! t) K* \/ X0 M" x
{"fvimagefile", ".fvi"},' Y- Y/ Q! \# y
{"rawfile", ".raw"},! @% t. ?! i% b! o' u! u) B& K
{"apriori", ".ffs"},
& z& s) {- k1 b* e# b% W! v; j {"combined_peim_driver", ".pei"},
' l# |2 o' B1 Q& b' l { NULL, NULL }
: ^/ V3 N3 ~8 o9 D};
, Z% l$ o& G$ D, b8 \+ ^% C( _- d3 z9 i2 C
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)' K) K$ y: j* C) D; L$ z
6 j" w! r3 t3 \
' V4 R3 P: q) w9 b4 B% ^6 s |
|