|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
. Q6 o2 d6 h1 F( Y: p$ J
" S+ A& r) {. L0 B$ USEC/CEI:
/ m) H h ~: l v! n4 D& J; L UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
- r9 e# A/ g! r8 F6 d7 d在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
" A" ~& n' x) b8 f$ }# ~* U5 @4 h9 {# m: V. b' b- E
PEI: ~& l" z, E2 R& D
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
- f6 P$ c4 U! I z EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。+ q5 j3 }5 N3 j" Q1 e
InitializePPIService函数,将PPI队列清空,这个队列长0x3F.: o* n( d1 n9 Y
InitializeSercurityService函数,将Notify队列清空。& V$ p$ Q1 V& z& C9 I0 y0 X' v2 v
InitializeDispatcherData函数,将Dispatcher队列清空。
9 v1 y8 E* t g" M 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
# B* ~ D& V! h. u, E( F9 k+ h 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:% m* S" H" I$ H' {" z2 X
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
* }" ]: e$ L) p! @9 M8 S {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
8 r# [) P" y5 u {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
1 H) Z* e9 q7 A% o c* r5 e2 |2 E {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
; X1 z J5 E8 _0 f% ` {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
) _9 c1 j' m5 }/ @" S7 v0 p% \1 { {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
+ M8 j; [+ g; C1 X* L {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
0 x; L% d- a% B( t% x, a9 c };
# a$ Y! |" R: p0 S& Y1 I) h 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。# a3 |' @5 O$ ~; W/ y( W
这些PPI会在PEIDispatcher中用到。
' s6 E$ l% Q3 L) o# U 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
% D5 }5 c2 Y9 {+ T2 { 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
" E. Z) ]4 ^5 F SwitchStacks (8 N; E, L/ c4 t) U; z
(VOID *) (UINTN) DxeCoreEntryPoint,
! x# E7 J' V9 ~$ s (UINTN) (HobList.Raw),! y9 S* E- q9 [) d; q' ]2 ^% p
(VOID *) (UINTN) TopOfStack,
# z2 j! l* E: D# Q3 m/ s (VOID *) (UINTN) BspStore- w; ~$ M5 o7 R: x
);
/ N3 S, _/ W Z; @ 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
0 C% p- j5 a+ f2 k# h
% g0 z9 y: b; m6 T n7 Z7 f9 kDXE:
" d W8 }! e+ c: V; d' ` 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。3 |! v. C# d- A! _* P L
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
! h4 `. O- r* C/ j' t, e 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
% J2 x2 y* r+ w中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。6 @- R1 d: U! K( u& [- H
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
, i; o" @& W% _2 }
% f0 X% e l8 eDriver:
* S+ Z7 p) y5 Y 我们的驱动什么为在PEI和DXE等不同阶段执行呢?( i# H& O" ~" ~/ x" D
大家请看一下我们的驱动的makefile.(EDK中的*.inf)
! ?' H$ b% ~% P, L [defines]7 s* e# t: v* s; C
BASE_NAME = OWEN1 m$ S. ^& y" H2 e: c$ X
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110+ d) \- E/ C; V3 x
COMPONENT_TYPE = BS_DRIVER
: I- ~. G! r, s3 z, B0 F3 U$ W7 p; C+ Y' x. l
BASE_NAME告诉编译器最终生成的驱动的名字。
5 }8 j# \2 R) D FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
2 m* a0 z3 W! K1 D: F) Z0 A3 g2 c8 o COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
% _7 B; C, W6 D# x* b 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
; o! x; C5 n8 [. j/ |& s- d+ e* | COMP_TYPE_EXTENSION mCompTypeExtension[] = {- ~7 ^/ V) W4 K/ Y3 s9 W& c% g
{"bs_driver", ".dxe" },
6 K1 J$ f: P# G1 N! C, D: K( d+ s4 a {"rt_driver", ".dxe" },
# _6 G6 D b) ^+ I {"sal_rt_driver", ".dxe"},* ]$ u c4 Z" j
{"security_core", ".sec"},
; \5 ^, B5 g1 D/ s" w8 A" I W {"pei_core", ".pei"},- Z: c Q1 c! r. P! g2 y5 Q7 n
{"pic_peim", ".pei"},
& s6 D( J8 B& M, K+ w {"pe32_peim", ".pei"},
$ f8 K- w- [! V {"relocatable_peim", ".pei"},# R2 G4 w. ` |- J: M
{"binary", ".ffs"},2 W* S- X% i& s0 {% U& y
{"application", ".app"},
4 N" X1 f+ m$ t# W: y {"file", ".ffs"},. \5 v2 b1 W' z
{"fvimagefile", ".fvi"},: s& t3 ~0 Y; S- H% P1 N2 b
{"rawfile", ".raw"},
8 U0 z- e5 s C7 L- O" t N: ] {"apriori", ".ffs"},
5 c9 u0 I0 C; a5 Q0 m2 Y, X7 f {"combined_peim_driver", ".pei"},
5 k8 b7 i% p1 c2 H6 t9 n- b { NULL, NULL }
! H; v" Q% ?& G, C" Z$ X1 W};8 \/ ~) k+ p) p
* k3 H0 g" b. K" S# h6 R, Q
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
; y3 |/ \8 x k/ I ; G" ?$ }5 ~8 X2 m* T! H1 q# G
; E$ ^ l& k& U4 M: l6 S! w |
|