|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。" R" A t" A5 J% M9 @
* m5 {) u% p' D* j" \3 r/ h" MSEC/CEI:; U. H0 Z% U9 T0 H
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。% m0 a2 I, a f# g) t
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).7 H" r1 k0 T6 c) S g: s
6 _' s1 N1 A3 M+ w' K+ @& q; O- \
PEI:5 V. S9 A0 ~* q# o$ [* U( s! T
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行8 _! A/ L4 z/ f2 \2 Q7 \( ]
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
1 @: Y+ L D8 R5 r, j+ W InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
2 ]% a0 V3 _& V9 Q% p2 R InitializeSercurityService函数,将Notify队列清空。4 t- L2 a, U. ^( y# _! X8 n0 S
InitializeDispatcherData函数,将Dispatcher队列清空。
$ E5 f( G, R1 O; n; @ 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
0 X6 W4 D& F R' | 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:2 I8 n j; D* A( J! K" w8 _1 J
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {4 [2 L4 e2 u- j9 T, t
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
/ \8 ]& T# X, J! Y4 E# i9 r& b {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
; _# m( J0 @$ b {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
3 _4 H# A" u: d {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
" |) z: b0 M% l( l6 y {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
: O" x6 G, [) S4 A {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}" g+ w% _* R" X) S) g" F o
};
; Y* O4 q9 _. }9 ] 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
- |7 N4 S. T5 n# W6 p, j7 _ 这些PPI会在PEIDispatcher中用到。
) m5 H% ]: p+ M 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。/ ], L1 t! p* ~9 I9 ^- C
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
9 X( |$ L1 B8 B/ s SwitchStacks (% p _( I% n, n6 Y) q% |
(VOID *) (UINTN) DxeCoreEntryPoint,
0 C2 G# }& h4 ], y: A' X( H5 h (UINTN) (HobList.Raw),
0 K! _* Z; n* B0 p7 w (VOID *) (UINTN) TopOfStack,; A- |1 g/ ?8 v( h" T' I9 n' Y
(VOID *) (UINTN) BspStore# ^' E: v5 {$ o3 D/ z, Q: G8 c
);% [+ R( Q$ h: q! [
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。): u' O% a3 j$ c/ i
( I/ B0 O& i/ R& q# FDXE:
. E! W" _0 S+ \2 D- R- z 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
7 w" ^% ]$ Y" d3 b接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
& Q3 _2 G, t" u9 x 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver8 M' m1 T _' X/ K. K
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
' @6 X# T' b8 \% e: u, _" E# U 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。4 F: H% u3 c( o; j0 n, S
, t$ W3 i* m- k0 G3 g
Driver:
8 x2 f% u+ R' R. b2 _; g$ Y 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
. T3 V" J# q- O 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
) C# Z) Q! o( a! o* h [defines] a4 h4 j7 ]) j; ^( ?- U
BASE_NAME = OWEN0 {, G+ c- A1 [
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
6 H; V1 } A& ^2 e( |( ` COMPONENT_TYPE = BS_DRIVER
8 [" V# [7 O6 i! ]& R
4 _5 l- f! K+ c8 j BASE_NAME告诉编译器最终生成的驱动的名字。% p" z- _; O/ S7 y
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。 H1 ^" m0 d) \9 ]1 w- m
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。( B: u! q9 ^" |; i/ l/ @2 j7 _
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名( q% t8 \+ W8 G/ p/ D
COMP_TYPE_EXTENSION mCompTypeExtension[] = {
( Y% h1 a! |5 N% x {"bs_driver", ".dxe" }," d# h8 T2 W7 q8 `' J, }# e* G
{"rt_driver", ".dxe" },
+ [" T$ Y/ L4 u4 G {"sal_rt_driver", ".dxe"},
2 C6 E: t4 |. L9 f( S2 K {"security_core", ".sec"},% R$ |' u4 q! C9 Y5 g
{"pei_core", ".pei"},
7 M J5 B; }8 L& \7 G, y {"pic_peim", ".pei"},4 R- F. c4 i) r h
{"pe32_peim", ".pei"},* o `# t f5 O& ~# s( U
{"relocatable_peim", ".pei"},
4 S2 U& c, A2 ]* N0 T/ y {"binary", ".ffs"},- @* V( V: ]0 u' e/ h
{"application", ".app"},* ?2 d& O3 z- q M* ^- w; u; R: V
{"file", ".ffs"},! ~7 W8 @3 w- G$ n- ^
{"fvimagefile", ".fvi"},
6 m* {4 f) H! a, c; I6 o {"rawfile", ".raw"},
* c6 z& P4 R3 j% o$ \9 b {"apriori", ".ffs"},
0 L6 N) Q% A, f {"combined_peim_driver", ".pei"},
1 Q7 I0 A! A: ^7 s7 r { NULL, NULL }
5 a E4 y T+ B8 m$ Z! k};
4 V* U* a* } x" c% Q/ Z8 z ]/ |0 O: F: L# m
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
, W- I/ A1 S" x( Q- a( e ; l& T: O9 A. }+ I5 d. h
* M* I1 f; o0 U. \$ d4 t |
|