首页 > 代码库 > Cstyle的UEFI导读:第19.0篇 SMM在UEFI当中的实现

Cstyle的UEFI导读:第19.0篇 SMM在UEFI当中的实现


     晚上吃的比较多不敢太早睡,趁空闲来看点东西,概念就不说了来看看SMM的几个阶段。
    SMM大概分为两个阶段:SMM初始化阶段和SMM runtime阶段,先来看看初始化阶段,还是先上图,下面的这幅图是讲的SMM的初始化和runtime整个阶段,整个阶段由DXE Dispatcher加载SMM IPL开始,到我们每一个注册的SMM hander被不断的执行为止,当然我们的SMM IPL也是一只DXE_RUNTIME_DRIVER,这里我开始也很奇怪为什么是DXE_RUNTIME_DRIVER而不是DXE_DRIVER这个问题之后再来回答,这里要说的是这只driver是有它特定的dependency的gEfiSmmAccess2ProtocolGuid AND gEfiSmmControl2ProtocolGuid。
说到这里需要再上一张图如下,这里我们的SMMIPL driver需要的三个protocol,而这三个protocol分别是由三个与体系结构相关的driver来install的。
        EFI_SMM_ACCESS2_PROTOCOL是与内存相关的,这个部分主要是控制DXE driver在SMM模式之外能读写SMRAM的区域,一般是设置相关的寄存器来实现的,在RC里面搜索SmmAccessDriver.c一般能找到你想要的东西。同时这里还一个东西需要注意,上面说到的该protocol与硬件相关,所以涉及到cpu的内存空间分配,所以需要在MRC跑完之后根据实际侦测到的内存空间,在PEI阶段建立相关的EFI_SMM_PEI_SMRAM_MEMORY_RESERVE类型的HOB来获取内存分布,在DXE阶段driver被加载的时候获取hob以此来创建EFI_SMRAM_DESCRIPTOR,建立GetCapabilities()服务指示出SMRAM的区域与大小。
下面是protocol提供的每一个服务的类型,Open可以让所有的UEFI service和SMM service访问SMRAM;Close使得只能是被SMM service访问;Lock使得SMRAM被锁定也不能被再次打开(Write once);GetCapabilities可以获取SMRAM的大小和位置(TSEG~TSEG-SMRAMsize)。

    EFI_SMM_CONTROL2_PROTOCOL用来同步触发SMI,它可以使用IPI来实现,也可以通过Chipset提供的SMI触发的IO端口来实现,在x86当中一般是0xB2,当写0xB2端口的时候就会触发SMI。一般EFI_SMM_COMMUNICATION_PROTOCOL的实现需要这个protocol的支持。在RC里面搜索SmmControlDriver.c一般能找到其实现,具体提供的服务很容易理解,就是触发SMI,清除触发源,周期触发的间隔时间(单位:10ns)。

    EFI_SMM_CONFIGURATION_PROTOCOL,由于SMST会提供一些内存管理的服务,EFI_SMM_RESERVED_SMRAM_REGION服务会提供给SMST一些信息表示那些内存段是不能作为SMRAM 堆来使用的,比如:作为栈来使用,做为SMM入口的相关保存的寄存器及返回地址,作为SMM entrypoint等。RegisterSmmEntry用来注册SMMCORE的入口地址SmmEntryPoint ( IN CONST EFI_SMM_ENTRY_CONTEXT *SmmEntryContext ).当然注册SMMEntryPoint还需要SmmCpuDxeSmm driver来把SmmEntryPoint加载到x86的SMM入口的地方,这里主要包括为MP里面的每个核心分配SMRAM,重新设置SMRAM的的入口地址,从x86的默认SMM地址0x30000,重新映射SMM entry的入口到SMMCore里面去。可以参考IA32FamilyCpuPkg/PiSmmCpuDxeSmm\PiSmmCpuDxeSmm.c.
.
    EFI_SMM_COMMUNICATION_PROTOCOL,用来处理DXE drivers and a registered  SMI handler.
    还有一个Protocol不得不提,它提供了driver去判断当前的环境是在SMM里面还是在SMM外面,以及获取SMST指针的服务,一旦获取到了SMST我们就可以使用它提供的基本的服务了。包括:memory 服务;protocol服务,可以用来注册用户自定义的SMM内提供的protocol(Cpu io,PCI IO,Status Code,S3Save,Ready to Lock);注册/删除SMI handle来扩展SMST提供的服务;SMIManage服务,用来在SMI触发的时候根据SMI源的不同调用预先注册的SMI handle;SMMConfigurationTable服务等。
    SMMIPL会调用SmmAccess2Protocol打开SMRAM让上面提到的各种UEFI的service可以访问到SMRAM,同时获取分配到的SMRAM的大小,同时使用EFI_SMM_CONFIGURATION_PROTOCOL来排除一些保留的SMRAM区域,设置SMRAM区域内存属性为EFI_MEMORY_WB,加载SMMCORE到SMRAM当中,并且执行SMMCORE,从SMMCORE返回设置SMMRAM属性为EFI_MEMORY_UC,install SmmBase2跟SmmCommunication protocol,当然这里还需要注册一些EVENT_NOTIFICATION 用来通知,比如:SmmIplSmmConfigurationEventNotify用来注册SmmEntryPoint,SmmIplReadyToLockEventNotify用来锁定SMRAM,SmmIplDxeDispatchEventNotify用来通知SMMCORE去dispatcher所有的SMM Driver(通过SmmCommunication触发SMI来在SMM模式下使用SmmDriverDispatchHandler()来dispatcher driver)。
    先到这里,之后有时间再看细节,具体可参考UDK里面SMM core以及IA32FamilyCpuPkg里面关于IA32的MP以及SMM的初始化部分的实现。


转载请注明出处
Cstyle.z.zhou@outlook.com  //  http://blog.csdn.net/CStyle_0x007

Cstyle的UEFI导读:第19.0篇 SMM在UEFI当中的实现