当处理器的SMM 中断pin(SMI#) 被激活,或者收到一个从APIC( advanced programmable interrupt controller)发来的SMI,处理器就会进入SMM,
SMM 模式下的执行程序被称作SMM处理程序,所有的SMM处理程序只能在称作系统管理内存(System Management RAM, SRAM)的空间内运行。
在SMM中,当保存好当前程序的内容后,CPU会去另外一个地址空间执行程序,SMM相关代码会在后台悄悄的执行。当从SMM返回的时候,CPU回到中断前的状态。
1. SMM Service
SMM service 是高优先级的system management interrupt(SMI), 在runtime的时候
仍然可接管系统。下面分成三个特性及两个service特点来介绍。 characteristics
1. 在smi的时候, CPU 执行pre-defined starting vector.
2. smm的code放在 SMRAM中,在SMM初始化后会lock 起来。
3 . smi 是由hardware event 或system interrupt所产生的。它可以被侦测,清除或disable.
Services
1. SMM service是一个handers 的list.并且都是DXE foundation service的subset.
2. SMM service和DXE foundation services 提供同样的functionality,但不同的是smm locate在smram中。
3. SMI 是由hardware event 或 system interrupt 所产生的。它可以被侦测,清除或disable.
在UEFI的架构中,SMM Driver是一个独立的driver, efi 会有dispatcher 来负责执行driver,当执行过
程中发现是driver 是smm driver时,这时会调用Kernel的function.将此driver搬到 SMM RAM里面。
SMM driver 可以从entry point 发现与DXE Driver 的不同,SMM的Entry point 会先去Locate一下叫
efi_smm_base_protocol Protocol, 透过此protocol 来知道目前是否在smm mode下,如果不是在
smm mode下的话,程序会先去注册(register), 将这支smm driver的FV地址以及大小register起来,
如此一来系统就会依照这些信息将此smm dirver 搬到smm ram里面去,搬完之后系统产生一次smi,
此时会再进入一次smm driver的entry point.第二次进入entry point 通过 efi_smm_base_protocol.insmm() 就会知道目前是在SMM MODE下,
第二次就要通过efis_smm_base_protocol.registercallback() 注册callback function.等下一次smi触发
时,就可以进入到callback function去执行。
// Procedure: InSmmFunction
//
// Description: Installs North Bridge SMM Child Dispatcher Handler.
//
// Input: ImageHandle - Image handle
// *SystemTable - Pointer to the system table
//
// Output: EFI_STATUS
//----------------------------------------------------------------------------
EFI_STATUS InSmmFunction (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable )
{
EFI_STATUS Status;
EFI_SMM_SW_DISPATCH_PROTOCOL *pSwDispatch;
EFI_SMM_SW_DISPATCH_CONTEXT AcpiS3Context = {SB_SWSMI_ACPI_S3};
EFI_SMM_SW_DISPATCH_CONTEXT SwContext = {SB_SWSMI};
EFI_SMM_POWER_BUTTON_DISPATCH_PROTOCOL *pPowerButton;
EFI_SMM_POWER_BUTTON_DISPATCH_CONTEXT PowerButtonContext = {PowerButtonEntry};
EFI_HANDLE Handle;
Status = pBS->LocateProtocol( &gEfiSmmSwDispatchProtocolGuid,
NULL,
&pSwDispatch );
if (!EFI_ERROR(Status))
{
Status = pSwDispatch->Register(
pSwDispatch,
SbS3PatchSmiHandler,
&AcpiS3Context,
&Handle );
Status = pSwDispatch->Register(
pSwDispatch,
SbSwSmiHandler,
&SwContext,
&Handle );
}
Status = pBS->LocateProtocol( &gEfiSmmPowerButtonDispatchProtocolGuid,
NULL,
&pPowerButton );
if (!EFI_ERROR(Status))
{
Status = pPowerButton->Register(
pPowerButton,
PowerButtonHandler,
&PowerButtonContext,
&Handle);
}
pBS->InstallMultipleProtocolInterfaces(
&ImageHandle,
&gAmiSbSmiProtocolGuid,
&SbSmiProtocol,
NULL);
ASSERT_EFI_ERROR(Status);
return EFI_SUCCESS;
}
SMM Q & A
当收到SMI(system management interput)的时候,就会进入SMM, SMI 可以下面几种方式触发:
Motherboard hardware or chipset signaling via a designated pin SMI# of the processor chip.[10] This signal can be an independent event.
Software SMI triggered by the system software via an I/O access to a location considered special by the motherboard logic (port 0B2h is common).[11][12]
An I/O write to a location which the firmware has requested that the processor chip act on.
SMI 产生的时候,现行BIOS 同时进SMM ,是考虑到冲突的问题,写BIOS 的人,觉得这样写比较安全,如果一个处理器A陷入了smm 里面,其他处理器在normal 模式,当处理器A 改变了某个寄存器的值,处于normal 状态的可能会有某个动作去override 这个值.
如果这个SMI是南桥产生的,那么所有核都进SMM, 如果是CPU生成的,他是可以指定具体哪个cpu进smm的(通过APIC ID)。
上面这段话,有争议,skylake 除了smi ipi 是可以指定具体发给那个core, 其他都是broadcast
Various causes of SMI are routed through the system agent and PCH and signaled to
each processor via an SMI message. Other SMIs are generated by a processor. SMIIPIs
can be sent to directed threads, all other SMIs are broadcast to all thread.
发送 INIT IPI 的时候,调用的SendInterrupt ,并且第一个参数为BROADCAST_MODE_ALL_EXCLUDING_SELF ,字面意思发给其他所有的,除了自己。
///
/// Send INIT IPI - SIPI to all APs
///
SendInterrupt (
BROADCAST_MODE_ALL_EXCLUDING_SELF,
0,
0,
DELIVERY_MODE_INIT,
TRIGGER_MODE_EDGE,
TRUE
);
第一个参数是 BroadcastMode 即中断广播模式,它有三个取值:
#define BROADCAST_MODE_SPECIFY_CPU 0x00
#define BROADCAST_MODE_ALL_INCLUDING_SELF 0x01
#define BROADCAST_MODE_ALL_EXCLUDING_SELF 0x02
即发给特定的,所有,包括自己,所有,但不包括自己。
其相应的处理方式为:
switch (BroadcastMode) {
case BROADCAST_MODE_SPECIFY_CPU:
if (X2apicEnabled) {
IcrHigh = (UINT32) ApicID;
} else {
IcrHigh = ApicID << 24;
}
break;
case BROADCAST_MODE_ALL_INCLUDING_SELF:
IcrLow |= 0x80000;
break;
case BROADCAST_MODE_ALL_EXCLUDING_SELF:
IcrLow |= 0xC0000;
break;
default:
return EFI_INVALID_PARAMETER;
}
可以是lock, close, open, lock
mSmmAccess.SmmAccess.Open = Open;
mSmmAccess.SmmAccess.Close = Close;
mSmmAccess.SmmAccess.Lock = Lock;
在CPU里面,有个叫System Management RAM Control 的寄存器,负责对SMRAM 这段空间访问权限的设定
下面以lock 为例。
277: 将合适的值写到smram这个变量里。
282: 最生写这个这个寄存器里面,完成lock.
对于open, close, 搞法一样,先把相应的值读出来,在正确的bit上填入相应的值,最后将这个变量写到寄存器里面。