云计算百科
云计算领域专业知识百科平台

【UEFI系列】SMI系统管理中断

文章目录

  • 一、SMI的介绍
  • 二、SMI的作用
    • SMI作用
    • 如何触发SMI
  • 三、SMM状态的进入和退出
    • 1.SMM状态的进入和退出
    • 2.CPU的其他状态和SMM状态之间的转换
  • 四、SMI执行程序处理过程
  • 五、SMI action in Bios
  • 六、SMI相关的实际EDKII代码

一、SMI的介绍

Sytem Management Interrupt,系统管理中断。 打个比方,工作的时候,突然打来一个电话,这个时候你停下手中所有的事去接电话,电话打完了再回来继续工作,打电话这个过程就相当于SMI。

关于SMI和SMM(system management mode): SMI发出后,CPU进入SMM状态。 SMM是intel引入x86的一种CPU的执行模式,只能通过SMI进入,并只能通过执行RSM指令退出。 SMM driver,SMM模式下的执行的程序,由bios实现,code里会写入。

SMRAM:Sytem Management RAM。 内存中的一段区域,所有的SMM driver在SMRAM中运行,非SMM下SMRAM不可访问。

二、SMI的作用

SMI作用

  • 处理系统事件,比如memory或者chipset error。
  • 控制硬件,实现一些特殊功能或者虚拟某些硬件功能或规避一些硬件上的bug。
  • 比如某些刷写bios的工具使用SMI实现刷写工作。CPU进入SMM模式后,鼠标和键盘都是不能动的,此时其他的中断都不可切断进程,直到退出SMM。就算再来一个SMI也要等这个SMI处理完退出SMM、再触发SMI进入SMM。

  • 实现电源管理的一些功能。
  • 比如os下输入sleep number=3的睡眠模式,会触发SMI去做一些电源管理的功能:内存不断电。

  • 大多数情况下,usb driver通过SMI实现。
  • 如何触发SMI

    进入SMM的唯一途径是产生SMI信号。 这个信号会通过CPU的SMI pin脚产生,或者CPU从APIC bus上收到SMI message。

  • 硬件触发 系统event error,当有些硬件error产生的时候触发SMI。 RTC alarm (real time clock实时始终警告) GPIO触发 IO trap,读写某些IO端口时触发SMI(可以在代码里设定)。 其它等,例如电源按钮。

  • 软件触发 写任意数据到IO port 0XB2或者BIOS中定义的其他port。

  • 三、SMM状态的进入和退出

    1.SMM状态的进入和退出

    • SMM状态的进入和退出过程

    和interrupt的处理类似,但有些不同,SMI产生后,在进入SMM的时候,CPU保存了中断程序的上下文(状态、数据)到SMRAM中。 CPU跳转到SMRAM SmiHandler,执行完毕后,rsm指令执行,CPU restore context,原来的程序继续执行。

    • SMM状态的特点

    SMM状态下所有中断和SMI被屏蔽,SMI处理程序不可重入(还没执行完之前不能跳去执行其他的SMI)。 SMI的优先级比exception和中断的优先级高。如果NMI、可屏蔽硬件中断、调试指令和SMI同时向CPU发送信号,只有SMI会被处理。

    0x40-0xFE是逻辑设备的配置,分配资源和进行管理。

    2.CPU的其他状态和SMM状态之间的转换

    SMI信号产生后,不管CPU是实模式、保护模式还是虚拟8086模式,都会导致CPU切换到SMM状态。 执行指令RSM后,CPU回到进入SMM模式之前的那个模式。 在这里插入图片描述

    四、SMI执行程序处理过程

    内存地址空间中的某两段:CPU正在执行的程序、SMRAM。 SMI产生后,CPU从当前地址跳出,立马进入到SMRAM里去,入口地址为:SMRAM起始地址(SMBase)+8000H。 SMI的程序执行完之后,CPU再通过rsm指令退出SMM,回到原先的内存地址中去。

    • SMRAM usage

    当CPU在SMM里的时候,cpu执行代码实在SMRAM空间里,SMBase默认地址在30000H。 较早的bios,post过程中SMBase被设定为位于A000:0或B000:0,这个区域原本用于decode到video buffer地址,进SMI的时候,硬件会将这个地址切换到真实的内存区域,现在BIOS一般将SMBase设定为在Tseg区域,由CPU或北桥MCH控制。 SMRAM空间映射到CPU的物理地址空间,CPU使用这个空间来保存进入SMI之前CPU的上下文和存储SMI的处理程序代码、数据和堆栈。它也可以用来存储SMmessage(比如系统配置和关闭设备的具体信息)等。

    五、SMI action in Bios

    • SMRAM usage

    由Bios实现。 寻址空间0~4G。 无特权级别,类似big real mode,不存在任何权限级别或地址映射。 进SMM后,CPU的通用寄存器的值不确定,其它段寄存器等被初始化为特定值。 可以执行所有指令比如IO读写,但是CPU指令只在SMRAM内执行。

    • Bios中SMI程序作用

    flash操作,读、写、擦除,获取flash信息。 get/set smbios information。 USB driver的实现。 kbc emulation,键盘的模拟。 实现某些类似timer的功能,比如RTC。 error logging。 其它等,比如电源管理的s3、s4的实现调用smi。

    • SMI程序作用,举例
  • 系统post(power-on-self-test开机自检)过程中按下power button关机。
  • 进DOS后,读写USB key。
  • 六、SMI相关的实际EDKII代码

    UEFI规定了归于SMI的EFI_SMM_BASE2_PROTOCOL:

    struct _EFI_SMM_BASE2_PROTOCOL {
    EFI_SMM_INSIDE_OUT2 InSmm;
    EFI_SMM_GET_SMST_LOCATION2 GetSmstLocation;
    };

    InSmm:这个server提供的是这个driver是否运行在SMM初始化的阶段。是的话返回成功,失败的话返回NULL。

    GetSmstLocation:这个函数是locate到system management service table(SMST),SMST有单独的smmallocatepool、smminstallprotocol、smmlocateprotocol函数等,SMM不能调用之前外部的protocol。

    • SMM child dispatch protocol
  • EFI_SMM_SW_DISPATCH2_PROTOCOL 软件触发
  • EFI_SMM_SX_DISPATCH2_PROTOCOL 电源Sleep触发
  • EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL 按下电源按钮触发
  • EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL 访问某个io口触发
  • SMM触发代码,在inf类型为DXE_SMM_DRIVER里的c文件里执行。

    代码里先调用InSmm确保当前处在smm init阶段,如果是的话才往下执行。

    EFI_STATUS Status;
    BOOLEAN InSmm;
    EFI_SMM_BASE2_PROTOCOL *SmmBase2;
    EFI_SMM_SYSTEM_TABLE2 *mBootScriptSmst = NULL;

    gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID **)&SmmBase2);
    Status = SmmBase2->InSmm (SmmBase2, &InSmm);
    if (EFI_ERROR (Status)|(!InSmm)) {
    return RETURN_SUCCESS;
    }

    Status = SmmBase2->GetSmstLocation (SmmBase2, &mBootScriptSmst);

    e.g.要用EFI_SMM_SW_DISPATCH2_PROTOCOL进行软件触发的注册,对应的inf的protocol里包含:

    [Protocols]
    gEfiSmmSwDispatch2ProtocolGuid

    //我自己定义成9,触发smi(软件触发,写Sample_number到B2)后写8到80口
    #define Sample_number 9

    EFI_STATUS
    EFIAPI
    MyCallback(
    IN EFI_HANDLE DispatchHandle,
    IN CONST VOID *Context,
    IN OUT VOID *CommBuffer,
    IN OUT UINTN *CommBufferSize
    )
    {
    IoWrite8(0x80,Sample_number);
    return EFI_SUCCESS;
    }

    EFI_STATUS
    SwSample (
    VOID
    )
    {
    EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
    EFI_SMM_SW_REGISTER_CONTEXT SwContext;
    EFI_HANDLE SwHandle;
    EFI_STATUS Status;

    Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID **)&SwDispatch);
    ASSERT_EFI_ERROR (Status);
    SwContext.SwSmiInputValue = Sample_number; //具体数值自己定义,这是要写到B2口的数值
    Status = SwDispatch->Register (SwDispatch, MyCallback, &SwContext, &SwHandle); //MyCallback是调用的函数

    e.g.要用EFI_SMM_SX_DISPATCH2_PROTOCOL进行sleep触发,对应的inf的protocol里包含:

    [Protocols]
    gEfiSmmSxDispatch2ProtocolGuid

    EFI_STATUS
    EFIAPI
    SmmS3EntryCallBack(
    IN EFI_HANDLE DispatchHandle,
    IN CONST VOID *Context OPTIONAL,
    IN OUT VOID *CommBuffer OPTIONAL,
    IN OUT UINTN *CommBufferSize OPTIONAL
    )
    {
    mDuringS3Resume = TRUE; //自己写
    return EFI_SUCCESS;
    }

    EFI_STATUS
    SxSample (
    VOID
    )
    {
    EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch;
    EFI_SMM_SX_REGISTER_CONTEXT EntryRegisterContext;
    EFI_HANDLE S3EntryHandle;
    EFI_STATUS Status;

    Status = gSmst->SmmLocateProtocol (
    &gEfiSmmSxDispatch2ProtocolGuid,
    NULL,
    (VOID **)&SxDispatch //一会儿要用来register的
    );
    ASSERT_EFI_ERROR (Status);
    EntryRegisterContext.Type = SxS3; //S3阶段
    EntryRegisterContext.Phase = SxEntry; //进入的时候
    Status = SxDispatch->Register (
    SxDispatch,
    SmmS3EntryCallBack, //我们定义的callback函数
    &EntryRegisterContext,
    &S3EntryHandle
    );

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 【UEFI系列】SMI系统管理中断
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!