|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
3 g5 `: Y( t2 ?% C2 O- s3 W: J! V1 N2 o9 w s' ~
SEC/CEI:# Y# R4 d$ ^3 C t6 z
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。; t X7 E) \! p2 X+ K, R
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
3 ?7 f' M/ E' ~/ `/ c. D" M5 S+ z) R# w6 K) U% I; V) l
PEI:% {/ ]/ \: l! l' ^
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行% h3 V6 ]2 i9 D& M0 H& v
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。" m" ^4 j+ T! y9 V, b! k
InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
0 s6 }+ n0 e( h3 |, F0 @6 G InitializeSercurityService函数,将Notify队列清空。/ m( E* V5 Y7 c9 m
InitializeDispatcherData函数,将Dispatcher队列清空。
7 V' ?" ^ z/ @2 a$ |0 j$ c6 v 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。' q+ v! d1 g9 O$ T6 ~( c2 [
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
3 M- ~' d1 o/ c1 ^ EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
+ z5 I D4 n5 [3 \ {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
- J/ c( [4 T1 y) _7 a! x {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
* p$ K, g/ r5 @" G7 b6 a {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},6 X2 f4 I, S& L5 R' J: E- F
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
/ J* a: r/ B& D {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
& s8 t5 I' ^0 Q1 J {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
8 T7 q$ E$ }1 r4 K2 V% I };
' l7 l: W" A5 R5 G7 \ 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
0 x2 d3 c' i* X( } 这些PPI会在PEIDispatcher中用到。9 i5 q/ P x. B. V6 }4 b
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。+ p. W$ _& ?* D
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
T i2 B+ | C2 H. N$ U& p SwitchStacks (
0 r ]. Y$ O; h, z1 s (VOID *) (UINTN) DxeCoreEntryPoint,
* j% N7 W/ m; l9 p8 w9 ` ?& t9 ` (UINTN) (HobList.Raw),/ z J. ?3 n1 ^ v4 ?4 |
(VOID *) (UINTN) TopOfStack," G2 Y# w) A' s
(VOID *) (UINTN) BspStore
$ n @2 N. N5 _. E" k5 e );: B/ X# f7 ~6 T
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
( i" h6 d! K% g* y& w' [
. o4 W$ M' W% F D! UDXE:# ?& l6 r* b: J9 d4 x H% Q9 m
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
( P: k4 @ f) S8 ]- b接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
* j, R3 ^, Z/ m" x8 o 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver b6 |* G4 ~( m& ?- @0 x. b
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
5 G& n7 T8 [! ^7 M4 n( X2 T' Z 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
7 V% C1 Y6 G& c" b
: e2 N, i Z1 l$ `$ v( g% k8 v6 q1 tDriver:
% q7 _. G8 N* J6 e3 y. L 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
, ?: r) W4 E) ~ 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
3 Z9 C/ g) ]- e [defines]2 s; Y2 E) ~ o: D
BASE_NAME = OWEN) o! I R; _3 L+ |
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D08301103 {" {- C2 v& [ T; k
COMPONENT_TYPE = BS_DRIVER
' c' o# [7 q% V& T1 \% ?- n" y
) I2 f/ a$ H/ \* r% M: o' Y3 F BASE_NAME告诉编译器最终生成的驱动的名字。
* O; m+ _3 C2 r5 A4 N FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。. A' N6 j/ s/ J( u% l
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。- r9 ]9 {6 Z# Z' j
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名' E9 y9 h( J# f `: ` X, h
COMP_TYPE_EXTENSION mCompTypeExtension[] = {- D. v9 [$ e8 s/ ] L0 {/ s
{"bs_driver", ".dxe" },
: v+ X) k7 O* k$ n1 Z, m! [3 e {"rt_driver", ".dxe" },, _' p4 ]2 ~& E/ z
{"sal_rt_driver", ".dxe"},3 k3 z p! ?. V1 E
{"security_core", ".sec"},
0 `8 x# ~0 R& f) k( R# Q6 A {"pei_core", ".pei"},8 ` `/ K# ^# E
{"pic_peim", ".pei"},0 L. q1 ~6 ]) _6 r- [4 v
{"pe32_peim", ".pei"},
% o; |" M4 d% K; g4 [ {"relocatable_peim", ".pei"},9 z; C1 c) G$ V( }
{"binary", ".ffs"},
* v! V4 ~2 c- d, L* _: H: S, y {"application", ".app"},
% h' P- P5 p, G4 D5 _" N {"file", ".ffs"},
/ y4 z- K; }* s5 p+ t) x% G2 k {"fvimagefile", ".fvi"},
9 t1 z- M4 O+ F* o3 x5 [ {"rawfile", ".raw"},0 Y( p- G9 x: ^' r4 S7 e! |. G
{"apriori", ".ffs"},) h! {, G! E5 z; Y- d: c% a
{"combined_peim_driver", ".pei"},
9 C2 [9 M9 W/ @; N2 B { NULL, NULL }
, F1 M- ^0 d5 [ N/ H8 | b: `5 ]) t};. H) P, M0 ]0 `/ e" |
- T/ S; N7 y- I2 j6 E了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
$ t3 g7 W: J2 u" Z, t+ J/ P 5 M6 \; s' q6 c3 b
* a" A2 E9 E- k( X" {
|
|