|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
0 v, }- g9 p+ j. e+ L5 ^
5 v- I: p# X/ p' ESEC/CEI:
- a( |& y4 E* a5 I: u( h UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。/ E7 I- Y/ c6 K# q
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
& p7 L* G- W; A. Z3 R& K$ w+ n: f
# m! n' P& v1 O% @" vPEI:8 X x7 ?+ W- ]$ ?3 X
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行% _/ J8 d# [9 ` K
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。/ J. ~& a/ i/ C" G/ K
InitializePPIService函数,将PPI队列清空,这个队列长0x3F.# n9 ^& F0 a, D: R' _( m( f& B7 n. z
InitializeSercurityService函数,将Notify队列清空。
3 K: }; a2 s) q* J$ e InitializeDispatcherData函数,将Dispatcher队列清空。
0 m% K' w/ v& t+ S$ x8 m" G9 g4 Y 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。5 J2 ^ B2 ~% r* c- \8 ]$ `0 M' f# g) Y
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
, M+ H; `& Y6 w' B* }' k EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
1 r. z- x" s+ ], D! E' h1 ~ {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi}, `3 F( T* h: }! S- _
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},4 Y* u4 n: V6 M0 |3 E+ a" V3 p
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},9 h/ s: y3 T2 i+ M) {( d3 q
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},9 m3 l7 h1 w. E. T2 C- W/ a" I7 z
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},: |) ]# Q. D7 S! x! C7 `" B' d2 }
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}) ~) W5 c2 n: Z8 X
};
# i) S. r2 x# i a% @% q8 k 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
N2 {3 a. s1 n5 f( K2 t 这些PPI会在PEIDispatcher中用到。
, q# |$ \) v6 J( O; a, X 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。, z+ Q2 N6 X/ O6 [0 t' Z& d
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
. D% n0 S8 K% [- Y SwitchStacks (/ S8 \; Q" W5 E( p k' Q4 t/ s
(VOID *) (UINTN) DxeCoreEntryPoint, M9 X) U) h N2 |5 t+ b
(UINTN) (HobList.Raw),
1 {- k1 M6 U P# d$ n (VOID *) (UINTN) TopOfStack,, f, d K! g/ U" j& h' D
(VOID *) (UINTN) BspStore
# B ~0 w, I3 J8 Y( E+ `/ X );7 S9 z* h& K6 Y8 W. h
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
1 F; w. u3 i9 |" L% r9 ^/ N# {( p- R/ x( p/ `" @9 a. j
DXE:
6 X, }8 a& ^5 a2 l/ H% Z0 \. i 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
+ \. ^% M& V' w8 f" p$ `7 d接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。* J8 e- S1 f4 W) x& K! _0 T
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
( l6 I' q6 i7 q8 z1 Y中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
; K5 ^, U: w# K0 M 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
0 I& ~+ G+ J; f9 W & O& ~% A" Y4 i0 d& z. j
Driver:
, @9 w: ^; \# c 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
! v% A; n, `- r' b2 z 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
5 X8 `$ f$ b g* E [defines]' F& P( V( N, V1 p
BASE_NAME = OWEN
- i/ b+ T# N7 P0 v$ N" g FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110, i$ H. N/ u2 v' R1 l
COMPONENT_TYPE = BS_DRIVER$ R; W- s9 N$ K8 c, O3 k
g; Y. T; H( Q; O
BASE_NAME告诉编译器最终生成的驱动的名字。
4 Z/ [" h T. F" l8 D FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。' W8 p" O+ _1 N- R1 w% _
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
, T0 f, @/ Z/ a9 x& p 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名; q% D- H6 \& z; x* E" n6 O
COMP_TYPE_EXTENSION mCompTypeExtension[] = {5 ~9 J; O# | Z, l
{"bs_driver", ".dxe" },$ |+ I+ @. C9 K4 I* n |$ D
{"rt_driver", ".dxe" },
0 X/ b8 T7 r! }' Z# q# c/ J- w {"sal_rt_driver", ".dxe"},( g# D0 ~7 h$ R: A ~
{"security_core", ".sec"},
1 B. l: q: h3 ^/ O* f {"pei_core", ".pei"}, p( v0 K! S- |- b: j. z- G# J
{"pic_peim", ".pei"},
/ p0 u* [6 J) G% W M {"pe32_peim", ".pei"}," x) u2 W* g* Y0 I* [) H
{"relocatable_peim", ".pei"},
+ \) w3 i g& d {"binary", ".ffs"},
* V# z. Z( s$ i5 h# }6 N {"application", ".app"}, @* g! J0 ?+ [
{"file", ".ffs"},* d+ r2 {4 L1 t
{"fvimagefile", ".fvi"},
) A2 L. r" k; B; l {"rawfile", ".raw"},/ Z! P( u) J) w
{"apriori", ".ffs"},7 T1 x1 y- s- k6 {* _! i+ D
{"combined_peim_driver", ".pei"}, ?- P7 i! M1 s; O, O3 J" u
{ NULL, NULL }& h; V1 ?* E" r1 c u7 _
};8 F* K6 v' T# z" x
4 u) L0 y* ~) t, v+ E7 k了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)( h. c) i8 H% [# l, c
( T3 `0 |) a9 P! B8 v, {
% }. [! \3 \6 s# S: y2 |! E) z- g |
|