Sorry, fix typo.

DXE > (SMM communcation) > InSmm = TRUE > SMM driver dispatcher/SMM handler > 
InSmm = FALSE > (exit SMM communication) > DXE

-----Original Message-----
From: Zeng, Star 
Sent: Tuesday, June 12, 2018 11:35 AM
To: Laszlo Ersek <ler...@redhat.com>; Wang, Jian J <jian.j.w...@intel.com>; 
edk2-devel@lists.01.org
Cc: Ni, Ruiyu <ruiyu...@intel.com>; Yao, Jiewen <jiewen....@intel.com>; Dong, 
Eric <eric.d...@intel.com>; Zeng, Star <star.z...@intel.com>
Subject: RE: [edk2] [PATCH 1/2] UefiCpuPkg/CpuDxe: allow accessing (DXE) page 
table in SMM mode

Share some information here according to my knowledge.

The EFI_SMM_BASE2_PROTOCOL.InSmm definition in PI spec is really very 
confusion. The naming for it are not consistent.
The interface name: In*Smm*
The typedef name of InSmm: EFI_*SMM_INSIDE_OUT*2 The second parameter name of 
InSmm: In*Smram*
 
In reality, the implementation of EFI_SMM_BASE2_PROTOCOL.InSmm in PiSmmIpl 
returns the information that whether current executing code is SMM code or 
executed from SMM code.

DXE > (SMM communcation) > InSmm = TRUE > SMM driver dispatcher/SMM handler > 
(exit SMM communication) > InSmm = FALSE > DXE


Thanks,
Star

-----Original Message-----
From: edk2-devel [mailto:edk2-devel-boun...@lists.01.org] On Behalf Of Laszlo 
Ersek
Sent: Monday, June 11, 2018 8:18 PM
To: Wang, Jian J <jian.j.w...@intel.com>; edk2-devel@lists.01.org
Cc: Ni, Ruiyu <ruiyu...@intel.com>; Yao, Jiewen <jiewen....@intel.com>; Dong, 
Eric <eric.d...@intel.com>
Subject: Re: [edk2] [PATCH 1/2] UefiCpuPkg/CpuDxe: allow accessing (DXE) page 
table in SMM mode

Hi Jian,

On 06/11/18 09:08, Jian J Wang wrote:
> The SMM version of MemoryAllocationLib allows to free memory allocated 
> in DXE (before EndOfDxe). This is done by checking the memory range 
> and calling gBS services to do real operation if the memory to free is 
> out of SMRAM. This would cause problem if some memory related 
> features, like Heap Guard, have to update page table to change memory 
> attributes.
> Because page table in SMM mode is different from DXE mode, gBS memory 
> services cannot get the correct attributes of DXE memory from SMM page 
> table and then cause incorrect memory manipulations.

(1) I think this description makes sense, but it does not highlight the 
involvement of CpuDxe.

(1a) Please reference "MdePkg/Library/SmmMemoryAllocationLib" specifically.

(1b) The SmmMemoryAllocationLib instance implies that the call chain starts 
with a DXE_SMM_DRIVER calling FreePool() or FreePages().

DXE_SMM_DRIVERs can only call boot services, and protocols located with boot 
services, in their entry point functions.

CpuDxe is a DXE_DRIVER and it provides the CPU arch protocol (and the MP 
services protocol). Thus, our call chain can only occur if:

- a DXE_SMM_DRIVER calls the FreePool() or FreePages() library API,

- in its entry point function,

- releasing memory that's not SMRAM,

- and the heap guard feature is enabled, so the FreePool() or
  FreePages() boot service ends up calling
  EFI_CPU_ARCH_PROTOCOL.SetMemoryAttributes().

Please include this information in the commit message.

(2) Can you remind me how the SMM page tables map non-SMRAM memory?

Because, I assume that, after a FreePages() libary API call, the freed memory 
should not be accessible to either SMM code or normal DXE code.
This seems to imply that both sets of page tables should be modified.
What am I missing?

> 
> The solution in this patch is to store the DXE page table information 
> (e.g. value of CR0, CR3 registers, etc.) in a global variable of 
> CpuDxe driver. If CpuDxe detects it's in SMM mode, it will use this 
> global variable to access page table instead of current processor registers.
> 
> Change-Id: If810bb1828160b8bdd8cb616d86df2859c74971f

(3) I think this comes from Gerrit. Do you really need the "Change-Id"
tag in the commit message? It doesn't say anything to the upstream edk2 users.

If you really need it, I don't mind it though; just please let's not add it due 
to oversight.

(4) Please make sure that you don't *push* the patch with Gerrit. Gerrit does 
bad things to git metadata. Please see 
<4A89E2EF3DFEDB4C8BFDE51014F606A14E22344D@SHSMSX104.ccr.corp.intel.com">http://mid.mail-archive.com/4A89E2EF3DFEDB4C8BFDE51014F606A14E22344D@SHSMSX104.ccr.corp.intel.com>.

> Cc: Eric Dong <eric.d...@intel.com>
> Cc: Laszlo Ersek <ler...@redhat.com>
> Cc: Jiewen Yao <jiewen....@intel.com>
> Cc: Ruiyu Ni <ruiyu...@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Jian J Wang <jian.j.w...@intel.com>
> ---
>  UefiCpuPkg/CpuDxe/CpuDxe.c       |   2 +-
>  UefiCpuPkg/CpuDxe/CpuDxe.inf     |   1 +
>  UefiCpuPkg/CpuDxe/CpuPageTable.c | 108
> ++++++++++++++++++++++++++-------------
>  3 files changed, 75 insertions(+), 36 deletions(-)
> 
> diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.c b/UefiCpuPkg/CpuDxe/CpuDxe.c 
> index 6ae2dcd1c7..1fd996fc3f 100644
> --- a/UefiCpuPkg/CpuDxe/CpuDxe.c
> +++ b/UefiCpuPkg/CpuDxe/CpuDxe.c
> @@ -404,7 +404,7 @@ CpuSetMemoryAttributes (
>    // to avoid unnecessary computing.
>    //
>    if (mIsFlushingGCD) {
> -    DEBUG((DEBUG_INFO, "  Flushing GCD\n"));
> +    DEBUG((DEBUG_GCD, "  Flushing GCD\n"));
>      return EFI_SUCCESS;
>    }

(5) I think it would be cleaner if we fixed the debug level for this message in 
a separate patch. You are not touching "CpuDxe.c" for any other reason.

>  
> diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.inf 
> b/UefiCpuPkg/CpuDxe/CpuDxe.inf index 3c938cee53..8c8773af90 100644
> --- a/UefiCpuPkg/CpuDxe/CpuDxe.inf
> +++ b/UefiCpuPkg/CpuDxe/CpuDxe.inf
> @@ -66,6 +66,7 @@
>  [Protocols]
>    gEfiCpuArchProtocolGuid                       ## PRODUCES
>    gEfiMpServiceProtocolGuid                     ## PRODUCES
> +  gEfiSmmBase2ProtocolGuid

(6) protocol usage note is missing (should be "## SOMETIMES_CONSUMES" I
think.)

>  
>  [Guids]
>    gIdleLoopEventGuid                            ## CONSUMES           ## 
> Event
> diff --git a/UefiCpuPkg/CpuDxe/CpuPageTable.c
> b/UefiCpuPkg/CpuDxe/CpuPageTable.c
> index e2595b4d89..bf420d3792 100644
> --- a/UefiCpuPkg/CpuDxe/CpuPageTable.c
> +++ b/UefiCpuPkg/CpuDxe/CpuPageTable.c
> @@ -23,6 +23,7 @@
>  #include <Library/DebugLib.h>
>  #include <Library/UefiBootServicesTableLib.h>
>  #include <Protocol/MpService.h>
> +#include <Protocol/SmmBase2.h>
>  
>  #include "CpuDxe.h"
>  #include "CpuPageTable.h"
> @@ -87,7 +88,33 @@ PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = {
>    {Page1G,  SIZE_1GB, PAGING_1G_ADDRESS_MASK_64},  };
>  
> -PAGE_TABLE_POOL   *mPageTablePool = NULL;
> +PAGE_TABLE_POOL                   *mPageTablePool = NULL;
> +PAGE_TABLE_LIB_PAGING_CONTEXT     mPagingContext;
> +EFI_SMM_BASE2_PROTOCOL            *mSmmBase2 = NULL;
> +
> +BOOLEAN
> +IsInSmm (
> +  VOID
> +  )
> +{
> +  EFI_STATUS              Status;
> +  BOOLEAN                 InSmm;
> +
> +  InSmm = FALSE;
> +  if (mSmmBase2 == NULL) {
> +    Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL,
> +                                  (VOID **)&mSmmBase2);

(7) Indentation is incorrect.

> +    if (EFI_ERROR (Status)) {
> +      mSmmBase2 = NULL;
> +    }

(8) I think you can simply drop the EFI_ERROR (Status) branch; "mSmmBase2" will 
simply remain NULL.

> +  }
> +
> +  if (mSmmBase2 != NULL) {
> +    mSmmBase2->InSmm (mSmmBase2, &InSmm);  }
> +
> +  return InSmm;
> +}

(9) I don't understand how the InSmm() member function is supposed to work. 
According to the PI spec (v1.6):

"""
EFI_MM_BASE_PROTOCOL.InMm()
[...]
Service to indicate whether the driver is currently executing in the MM Driver 
Initialization phase.
[...]
InMmram
Pointer to a Boolean which, on return, indicates that the driver is currently 
executing inside of MMRAM (TRUE) or outside of MMRAM (FALSE).
[...]
This service returns whether the caller is being executed in the MM Driver 
Initialization phase. For MM Drivers, this will return TRUE in InMmram while 
inside the driver’s entry point and otherwise FALSE. For combination MM/DXE 
drivers, this will return FALSE in the DXE launch.
For the MM launch, it behaves as an MM Driver.
"""

First of all, to my knowledge, we don't have any combination MM/DXE drivers in 
edk2 (with dual entry point launches, binary type 0x0C). We have traditional MM 
drivers (binary type 0x0A) that are launched directly from SMRAM. However, it 
is not guaranteed that they are launched with the processor operating in System 
Management Mode.

Secondly, focusing on traditional MM drivers, the InMm() specification doesn't 
seem to say anything as to whether the processor is running in SMM (system 
management mode) or normal mode. Initially, SMRAM is open, and thus the 
processor can execute MM driver code out of it without actually operating in 
SMM (see above).

Furthermore, CpuDxe is a DXE_DRIVER, thus it is never loaded into SMRAM.

I notice that you call the "InMmram" parameter "InSmm". Are you saying that the 
PI spec is wrong, and edk2 actually returns whether the processor is executing 
CpuDxe code in Management Mode? (Due to a call from the entry point function of 
a traditional MM driver?)

Third, the spec is inconsistent even with itself. The general description says, 
"For MM Drivers, this will return TRUE in InMmram while inside the driver’s 
entry point and otherwise FALSE". But a DXE protocol must not even be invoked 
from a traditional MM driver *except* from the entry point! Which would imply 
that, for traditional MM drivers, the output parameter could only be set to 
TRUE.

So basically what I'd like to see here is evidence that

(9a) the IsInSmm() helper function is never called outside of the entry
     point of an MM driver, due to the restrictions on
     gBS->LocateProtocol() and mSmmBase2->InSmm(),

(9b) the mSmmBase2->InSmm() protocol member determines whether CpuDxe is
     being executed by the processor in Management Mode, and *not*
     whether the CpuDxe driver is being executed from within SMRAM.

>  
>  /**
>    Return current paging context.
> @@ -102,42 +129,45 @@ GetCurrentPagingContext (
>    UINT32                         RegEax;
>    UINT32                         RegEdx;
>  
> -  ZeroMem(PagingContext, sizeof(*PagingContext));
> -  if (sizeof(UINTN) == sizeof(UINT64)) {
> -    PagingContext->MachineType = IMAGE_FILE_MACHINE_X64;
> -  } else {
> -    PagingContext->MachineType = IMAGE_FILE_MACHINE_I386;
> -  }
> -  if ((AsmReadCr0 () & BIT31) != 0) {
> -    PagingContext->ContextData.X64.PageTableBase = (AsmReadCr3 () & 
> PAGING_4K_ADDRESS_MASK_64);
> -  } else {
> -    PagingContext->ContextData.X64.PageTableBase = 0;
> -  }
> +  if (!IsInSmm ()) {
> +    if (sizeof(UINTN) == sizeof(UINT64)) {
> +      mPagingContext.MachineType = IMAGE_FILE_MACHINE_X64;
> +    } else {
> +      mPagingContext.MachineType = IMAGE_FILE_MACHINE_I386;
> +    }
> +    if ((AsmReadCr0 () & BIT31) != 0) {
> +      mPagingContext.ContextData.X64.PageTableBase = (AsmReadCr3 () & 
> PAGING_4K_ADDRESS_MASK_64);
> +    } else {
> +      mPagingContext.ContextData.X64.PageTableBase = 0;
> +    }
>  
> -  if ((AsmReadCr4 () & BIT4) != 0) {
> -    PagingContext->ContextData.Ia32.Attributes |= 
> PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PSE;
> -  }
> -  if ((AsmReadCr4 () & BIT5) != 0) {
> -    PagingContext->ContextData.Ia32.Attributes |= 
> PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAE;
> -  }
> -  if ((AsmReadCr0 () & BIT16) != 0) {
> -    PagingContext->ContextData.Ia32.Attributes |= 
> PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_WP_ENABLE;
> -  }
> +    if ((AsmReadCr4 () & BIT4) != 0) {
> +      mPagingContext.ContextData.Ia32.Attributes |= 
> PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PSE;
> +    }
> +    if ((AsmReadCr4 () & BIT5) != 0) {
> +      mPagingContext.ContextData.Ia32.Attributes |= 
> PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAE;
> +    }
> +    if ((AsmReadCr0 () & BIT16) != 0) {
> +      mPagingContext.ContextData.Ia32.Attributes |= 
> PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_WP_ENABLE;
> +    }
>  
> -  AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> -  if (RegEax > 0x80000000) {
> -    AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
> -    if ((RegEdx & BIT20) != 0) {
> -      // XD supported
> -      if ((AsmReadMsr64 (0xC0000080) & BIT11) != 0) {
> -        // XD activated
> -        PagingContext->ContextData.Ia32.Attributes |= 
> PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_XD_ACTIVATED;
> +    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
> +    if (RegEax > 0x80000000) {
> +      AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
> +      if ((RegEdx & BIT20) != 0) {
> +        // XD supported
> +        if ((AsmReadMsr64 (0xC0000080) & BIT11) != 0) {
> +          // XD activated
> +          mPagingContext.ContextData.Ia32.Attributes |= 
> PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_XD_ACTIVATED;
> +        }
> +      }
> +      if ((RegEdx & BIT26) != 0) {
> +        mPagingContext.ContextData.Ia32.Attributes |= 
> + PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAGE_1G_SUPPORT;
>        }
> -    }
> -    if ((RegEdx & BIT26) != 0) {
> -      PagingContext->ContextData.Ia32.Attributes |= 
> PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_PAGE_1G_SUPPORT;
>      }
>    }
> +
> +  CopyMem (PagingContext, &mPagingContext, sizeof (mPagingContext));
>  }

(10) Even assuming that IsInSmm() always returns false -- for example because 
the platform does not include the SMM drivers --, this change does not look 
like a no-op to me.

The ZeroMem() call at the top is removed by the patch, but attributes like PSE, 
PAE, WP_ENABLE, XD_ACTIVATED and 1G_SUPPORT are never
*cleared* in "mPagingContext", once they are set.

I guess the idea is that a few (how many?) initial calls to
GetCurrentPagingContext() set up "mPagingContext", and after that,
GetCurrentPagingContext() just keeps returning the last set context. But I 
don't think that those "initial calls" work correctly.

>  
>  /**
> @@ -507,7 +537,10 @@ IsReadOnlyPageWriteProtected (
>    VOID
>    )
>  {
> -  return ((AsmReadCr0 () & BIT16) != 0);
> +  if (!IsInSmm ()) {
> +    return ((AsmReadCr0 () & BIT16) != 0);  }  return FALSE;
>  }
>  
>  /**
> @@ -518,7 +551,9 @@ DisableReadOnlyPageWriteProtect (
>    VOID
>    )
>  {
> -  AsmWriteCr0 (AsmReadCr0() & ~BIT16);
> +  if (!IsInSmm ()) {
> +    AsmWriteCr0 (AsmReadCr0 () & ~BIT16);  }
>  }
>  
>  /**
> @@ -529,7 +564,9 @@ EnableReadOnlyPageWriteProtect (
>    VOID
>    )
>  {
> -  AsmWriteCr0 (AsmReadCr0() | BIT16);
> +  if (!IsInSmm ()) {
> +    AsmWriteCr0 (AsmReadCr0 () | BIT16);  }
>  }

(11) I don't understand these changes at all. Why are these functions no-ops 
when CpuDxe is invoked in Management Mode?

Thanks
Laszlo

>  
>  /**
> @@ -1054,6 +1091,7 @@ InitializePageTableLib (  {
>    PAGE_TABLE_LIB_PAGING_CONTEXT     CurrentPagingContext;
>  
> +  ZeroMem (&mPagingContext, sizeof(mPagingContext));
>    GetCurrentPagingContext (&CurrentPagingContext);
>  
>    //
> 

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to