|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
+ X& d+ {' A( |3 ~
% a9 D" c/ K7 H1 ~0 Q/ KSEC/CEI:
0 |) ^) [# @# ~: N3 W | UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
! l: t; e4 w$ k& c) R! t* `在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).4 Q$ m( G5 ~2 F6 L: V( x
/ e1 j% G: M3 m8 c
PEI:+ W" o; P. s4 o' A- i4 `2 Q8 r
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行! D, `) w5 y1 t; n
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
7 b6 Z: b7 ]0 X3 o2 r InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
; }9 B6 X8 r& U* H) o+ r6 j InitializeSercurityService函数,将Notify队列清空。7 F+ d5 {5 n- t! a6 ^' s2 T4 R
InitializeDispatcherData函数,将Dispatcher队列清空。4 f% |* u, O( g5 ?0 D* W6 j" M, h
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。% ~; d" P9 g. u7 p( \* e) j
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:7 u: d6 K( {. d% q' g8 ~" [, m @6 q
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
- L s0 I2 N4 z {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},- G! _+ \# K% G. K) r" N
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
2 n$ z ]' i* k, g3 l- n, H {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},, m* o t2 ^# m5 V5 o) D; ~
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
$ t" K' [- s+ ?0 V1 C- d {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
- i1 x0 k( E @ {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}" `! b% O* H6 M' q w
};
. h* r- H2 M: t" H/ m 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
' A" O8 R M1 V, n# ~5 R8 ? 这些PPI会在PEIDispatcher中用到。# E9 s( t# s- |+ K+ c; n" v# K# N
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
! C7 C3 L2 U+ M( u2 ] 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
5 I' c6 ^4 k x' x) E SwitchStacks (
# ]; D d' g" o% ]) _* h W- g (VOID *) (UINTN) DxeCoreEntryPoint,# a6 n4 {4 ?1 s8 j
(UINTN) (HobList.Raw), i" ^! Y6 z+ X% [) l. E
(VOID *) (UINTN) TopOfStack,( ?- @6 m9 M' `
(VOID *) (UINTN) BspStore/ h, ~/ M' A, f- I$ \- K6 j
);
* }1 _1 ~7 B8 ?/ |; `* g 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
! w5 ^3 M J; N' A8 h/ L! ?4 H
; m! f- D+ T3 {8 ~3 CDXE:
, ~3 r* \ \ k$ w8 ` 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
' P$ S5 v3 E9 }9 O& D接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
$ J! R8 r6 c2 P' H; a2 r# q. B 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
6 N; R; u i6 v' L' E% [1 Z3 v中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
+ j, [2 w4 `3 V5 O, t2 @1 z/ k 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
C1 u9 ]& ?" `, {, }
3 V! h+ k* O/ o0 X( K" C: Y8 R" MDriver:
$ V( q0 \) g7 @) s" O 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
( `* v4 r( q E% H! [% E9 v8 U4 U 大家请看一下我们的驱动的makefile.(EDK中的*.inf)+ {" E' G( q! K6 u- I6 `
[defines]; Y' s. \! T! k' V' N
BASE_NAME = OWEN
1 M1 C/ \3 ?) n% [0 l9 D FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110' R0 w/ y; \+ `- M2 N9 G/ ?
COMPONENT_TYPE = BS_DRIVER
5 v3 B! A6 g A/ R; U- P4 A2 K0 w/ H- D# m, r. Y7 Z3 j1 F
BASE_NAME告诉编译器最终生成的驱动的名字。
; M# b0 j! [ Y) }4 L FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
% k( W5 M* h0 C9 ~3 A' f+ E COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
0 t7 Z" @( J% m 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
0 t. b" g+ a! M COMP_TYPE_EXTENSION mCompTypeExtension[] = {
- X8 a0 ~6 d- e0 s- Q1 [ {"bs_driver", ".dxe" },
0 ]" O9 {3 t3 O" x$ A {"rt_driver", ".dxe" },& s6 J- ^- s4 x( u
{"sal_rt_driver", ".dxe"},
, @+ X) T" L' h; r* S {"security_core", ".sec"},
! c5 G( v3 ]* i {"pei_core", ".pei"},- m c4 o& H$ G; R4 G: Q J: z# N
{"pic_peim", ".pei"},
% w' t. f) z1 P4 _ {"pe32_peim", ".pei"},. H: e9 N/ d- [. h
{"relocatable_peim", ".pei"},
& w) J5 A$ v a% y( \4 P {"binary", ".ffs"},. H. ~( x1 `; J# t! `; w
{"application", ".app"},) }! j/ m4 B4 L; U; c ^
{"file", ".ffs"},7 K1 ]2 N$ m1 X. O9 g* a
{"fvimagefile", ".fvi"},! @+ A$ h& ^8 |+ @
{"rawfile", ".raw"},
7 G! {0 x0 l* J" J {"apriori", ".ffs"},
* U, g6 t, R- c; A {"combined_peim_driver", ".pei"},; I- U) K5 x/ u& \9 _; e
{ NULL, NULL }
% L& F1 ~6 k3 O! F2 h. p% n};$ W: J- p0 b- S- @* Z! z1 N0 h7 C
; j0 ?% b% l) j+ _: @4 p( ~' [+ ?. P
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever), S9 w* a* u9 r; r, ~6 A" m! {
$ e% a& H% s/ R2 J
! A! X: ^! I# j3 A# n: \3 E |
|