On 02/02/18 11:06, Ard Biesheuvel wrote:
> On 31 January 2018 at 10:40, Laszlo Ersek <ler...@redhat.com> wrote:
>> On 01/30/18 23:25, Kinney, Michael D wrote:
>>> Laszlo,
>>>
>>> I agree that the function is better than a macro.
>>>
>>> I thought of the alignment issues as well.  CopyMem()
>>> is a good solution.  We could also consider
>>> WriteUnalignedxx() functions in BaseLib.
>>
>> IMO, the WriteUnalignedxx functions are a bit pointless in the exact
>> form they are declared (this was discussed earlier esp. with regard to
>> aarch64). The functions take pointers to objects that already have the
>> target type, such as
>>
>> UINT32
>> EFIAPI
>> WriteUnaligned32 (
>>   OUT UINT32                    *Buffer,
>>   IN  UINT32                    Value
>>   )
>>
>> Here the type of Buffer should be (VOID *), not (UINT32 *). Otherwise,
>> the undefined behavior (due to mis-alignment) surfaces as soon as the
>> function is called with an unaligned pointer (i.e. before the target
>> area is actually written).
>>
>>> I was originally thinking this functionality would go
>>> into BaseLib.  But with the use of CopyMem(), we can't
>>> do that.
>>
>> Can we put it in BaseMemoryLib instead (which is where CopyMem() is
>> from)? That library class is still low-level enough. And, while I count
>> 9 library instances, PatchAssembly() is not a large function, we could
>> tolerate adding it to all 9 instances, identically.
>>
>> Let me also ask the opposite question: should we perhaps make the
>> PatchAssembly() API *less* abstract? (Also suggested by your naming of
>> the macro, PATCH_X86_ASM.) If the instruction encoding on e.g. AARCH64
>> doesn't lend itself to such patching (= expressed through the address
>> right after the instruction), then even BaseMemoryLib may be too generic
>> for the API.
>>
>>> Maybe we should use WriteUnalignedxx() and
>>> add some ASSERT() checks.
>>>
>>> VOID
>>> PatchAssembly (
>>>   VOID    *BufferEnd,
>>>   UINT64  PatchValue,
>>>   UINTN   ValueSize
>>>   )
>>> {
>>>   ASSERT ((UINTN)BufferEnd > ValueSize);
>>>   switch (ValueSize) {
>>>   case 1:
>>>     ASSERT (PatchValue <= MAX_UINT8);
>>>     *((UINT8 *)BufferEnd - 1) = (UINT8)PatchValue;
>>>   case 2:
>>>     ASSERT (PatchValue <= MAX_UINT16);
>>>     WriteUnaligned16 ((UINT16 *)(BufferEnd) - 1, (UINT16)PatchValue));
>>>     break;
>>>   case 4:
>>>     ASSERT (PatchValue <= MAX_UINT32);
>>>     WriteUnaligned32 ((UINT32 *)(BufferEnd) - 1, (UINT32)PatchValue));
>>>     break;
>>>   case 8:
>>>     WriteUnaligned64 ((UINT64 *)(BufferEnd) - 1, PatchValue));
>>>     break;
>>>   default:
>>>     ASSERT (FALSE);
>>>   }
>>> }
>>
>> In my opinion:
>>
>> - If Ard and Leif say that PatchAssembly() API makes sense for AARCH64,
>>   then I think we can go with the above generic implementation (for
>>   BaseLib).
>>
> 
> Code patching on ARM/AARCH64 has some hoops to jump through, i.e.,
> clean the D-cache to the point of unification, invalidate the I-cache,
> probably some barriers in case the patching function happened to end
> up in the same cache line as the patchee (which may not be a concern
> for this specific use case, but it does need to be taken into account
> if this is turned into a patch-any-assembly-anywhere function)
> 
> So if the PatchAssembly() prototype does end up in a generic library
> class, we'd have to provide ARM and AARCH64 specific implementations
> anyway, and given that I don't see any use for this on ARM/AARCH64 in
> the first place, I think this should belong in an IA32/X64 specific
> package.

Thank you for the response!

For now I'm going to post the series with the function introduced as
PatchInstructionX86() to BaseLib, visibly only to IA32 and X64 edk2
platforms. If a better place than BaseLib looks necessary, I can move it
according to review comments.

Thanks!
Laszlo

> 
>> - If Ard and Leif say the API is only useful on x86, then I suggest that
>>   we implement the API separately for all arches (still in BaseLib):
>>
>>   - On x86, we should simply open-code the unaligned accesses (like you
>>     originall suggested). The pointer arithmetic will look a bit wild,
>>     but it's safely hidden behind a BaseLib API, so client code will
>>     look nice.
>>
>>   - On all other arches, we should implement the function with
>>     ASSERT(FALSE).
>>
>> Thanks!
>> Laszlo
>>
>>>
>>> Mike
>>>
>>>> -----Original Message-----
>>>> From: Laszlo Ersek [mailto:ler...@redhat.com]
>>>> Sent: Tuesday, January 30, 2018 1:45 PM
>>>> To: Kinney, Michael D <michael.d.kin...@intel.com>; edk2-
>>>> devel-01 <edk2-devel@lists.01.org>
>>>> Cc: Ni, Ruiyu <ruiyu...@intel.com>; Paolo Bonzini
>>>> <pbonz...@redhat.com>; Yao, Jiewen
>>>> <jiewen....@intel.com>; Dong, Eric <eric.d...@intel.com>
>>>> Subject: Re: [edk2] [PATCH 1/3]
>>>> UefiCpuPkg/PiSmmCpuDxeSmm: update comments in IA32
>>>> SmmStartup()
>>>>
>>>> On 01/30/18 21:31, Kinney, Michael D wrote:
>>>>> Laszlo,
>>>>>
>>>>> We have already used this technique in other NASM files
>>>>> to remove DBs.
>>>>
>>>> OK.
>>>>
>>>>> Let us know if you have suggestions on how to make the
>>>>> C code that performs the patches easier to read and
>>>>> maintain.
>>>>
>>>> How about this:
>>>>
>>>>   VOID
>>>>   PatchAssembly (
>>>>     VOID   *BufferEnd,
>>>>     UINT64 PatchValue,
>>>>     UINTN  ValueSize
>>>>     )
>>>>   {
>>>>     CopyMem (
>>>>       (VOID *)((UINTN)BufferEnd - ValueSize),
>>>>       &PatchValue,
>>>>       ValueSize
>>>>       );
>>>>   }
>>>>
>>>>   extern UINT8 gAsmSmmCr0;
>>>>   extern UINT8 gAsmSmmCr3;
>>>>   extern UINT8 gAsmSmmCr4;
>>>>
>>>>   ...
>>>>   {
>>>>     PatchAssembly (&gAsmSmmCr0, AsmReadCr0 (), 4);
>>>>     PatchAssembly (&gAsmSmmCr3, AsmReadCr3 (), 4);
>>>>     PatchAssembly (&gAsmSmmCr4, AsmReadCr4 (), 4);
>>>>     ...
>>>>   }
>>>>
>>>> (I think it's fine to open-code the last argument as "4",
>>>> rather than
>>>> "sizeof (UINT32)", because for patching, we must have
>>>> intimate knowledge
>>>> of the instruction anyway.)
>>>>
>>>> To me, this is easier to read, because:
>>>>
>>>> - there are no complex casts in the "business logic"
>>>> - the size is spelled out once per patching
>>>> - the function name and the variable names make it clear
>>>> we are patching
>>>>   separately compiled assembly code that was linked into
>>>> the same
>>>>   module.
>>>>
>>>> What do you think?
>>>>
>>>> Thanks!
>>>> Laszlo
>>>>
>>>>>> -----Original Message-----
>>>>>> From: edk2-devel [mailto:edk2-devel-
>>>> boun...@lists.01.org]
>>>>>> On Behalf Of Laszlo Ersek
>>>>>> Sent: Tuesday, January 30, 2018 10:17 AM
>>>>>> To: Kinney, Michael D <michael.d.kin...@intel.com>;
>>>> edk2-
>>>>>> devel-01 <edk2-devel@lists.01.org>
>>>>>> Cc: Ni, Ruiyu <ruiyu...@intel.com>; Paolo Bonzini
>>>>>> <pbonz...@redhat.com>; Yao, Jiewen
>>>>>> <jiewen....@intel.com>; Dong, Eric
>>>> <eric.d...@intel.com>
>>>>>> Subject: Re: [edk2] [PATCH 1/3]
>>>>>> UefiCpuPkg/PiSmmCpuDxeSmm: update comments in IA32
>>>>>> SmmStartup()
>>>>>>
>>>>>> On 01/30/18 18:22, Kinney, Michael D wrote:
>>>>>>> Laszlo,
>>>>>>>
>>>>>>> The DBs can be removed if the label is moved after
>>>>>>> the instruction and the patch is done to the label
>>>>>>> minus the size of the patch value.
>>>>>>
>>>>>> Indeed I haven't thought of this.
>>>>>>
>>>>>> If I understand correctly, it means
>>>>>>
>>>>>>   extern UINT8 gSmmCr0;
>>>>>>
>>>>>>   *(UINT32*)(&gSmmCr0 - sizeof (UINT32)) =
>>>>>> (UINT32)AsmReadCr0 ();
>>>>>>
>>>>>> TBH, the DB feels less ugly to me than this :)
>>>>>>
>>>>>> Still, if you think it would be an acceptable price to
>>>>>> pay for removing
>>>>>> the remaining DBs, I can respin.
>>>>>>
>>>>>> Thanks
>>>>>> Laszlo
>>>>>>
>>>>>>>> -----Original Message-----
>>>>>>>> From: edk2-devel [mailto:edk2-devel-
>>>>>> boun...@lists.01.org]
>>>>>>>> On Behalf Of Laszlo Ersek
>>>>>>>> Sent: Tuesday, January 30, 2018 7:34 AM
>>>>>>>> To: edk2-devel-01 <edk2-devel@lists.01.org>
>>>>>>>> Cc: Ni, Ruiyu <ruiyu...@intel.com>; Yao, Jiewen
>>>>>>>> <jiewen....@intel.com>; Dong, Eric
>>>>>> <eric.d...@intel.com>;
>>>>>>>> Paolo Bonzini <pbonz...@redhat.com>
>>>>>>>> Subject: [edk2] [PATCH 1/3]
>>>> UefiCpuPkg/PiSmmCpuDxeSmm:
>>>>>>>> update comments in IA32 SmmStartup()
>>>>>>>>
>>>>>>>> The gSmmCr3, gSmmCr4, gSmmCr0 and gSmmJmpAddr global
>>>>>>>> variables  are used
>>>>>>>> for patching assembly instructions, thus we can
>>>> never
>>>>>>>> remove the DB
>>>>>>>> encodings for those instructions. At least we should
>>>>>> add
>>>>>>>> the intended
>>>>>>>> meanings in comments.
>>>>>>>>
>>>>>>>> This patch only changes comments.
>>>>>>>>
>>>>>>>> Cc: Eric Dong <eric.d...@intel.com>
>>>>>>>> Cc: Jian J Wang <jian.j.w...@intel.com>
>>>>>>>> Cc: Jiewen Yao <jiewen....@intel.com>
>>>>>>>> Cc: Paolo Bonzini <pbonz...@redhat.com>
>>>>>>>> Cc: Ruiyu Ni <ruiyu...@intel.com>
>>>>>>>> Contributed-under: TianoCore Contribution Agreement
>>>>>> 1.1
>>>>>>>> Signed-off-by: Laszlo Ersek <ler...@redhat.com>
>>>>>>>> ---
>>>>>>>>  UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmInit.nasm | 8
>>>> ++++-
>>>>>> ---
>>>>>>>>  1 file changed, 4 insertions(+), 4 deletions(-)
>>>>>>>>
>>>>>>>> diff --git
>>>>>> a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmInit.nasm
>>>>>>>> b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmInit.nasm
>>>>>>>> index e96dd8d2392a..08534dba64b7 100644
>>>>>>>> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmInit.nasm
>>>>>>>> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmInit.nasm
>>>>>>>> @@ -44,34 +44,34 @@ global ASM_PFX(SmmStartup)
>>>>>>>>  ASM_PFX(SmmStartup):
>>>>>>>>      DB      0x66
>>>>>>>>      mov     eax, 0x80000001             ; read
>>>>>>>> capability
>>>>>>>>      cpuid
>>>>>>>>      DB      0x66
>>>>>>>>      mov     ebx, edx                    ; rdmsr
>>>> will
>>>>>>>> change edx. keep it in ebx.
>>>>>>>> -    DB      0x66, 0xb8
>>>>>>>> +    DB      0x66, 0xb8                  ; mov eax,
>>>>>> imm32
>>>>>>>>  ASM_PFX(gSmmCr3): DD 0
>>>>>>>>      mov     cr3, eax
>>>>>>>>      DB      0x67, 0x66
>>>>>>>>      lgdt    [cs:ebp + (ASM_PFX(gcSmiInitGdtr) -
>>>>>>>> ASM_PFX(SmmStartup))]
>>>>>>>> -    DB      0x66, 0xb8
>>>>>>>> +    DB      0x66, 0xb8                  ; mov eax,
>>>>>> imm32
>>>>>>>>  ASM_PFX(gSmmCr4): DD 0
>>>>>>>>      mov     cr4, eax
>>>>>>>>      DB      0x66
>>>>>>>>      mov     ecx, 0xc0000080             ; IA32_EFER
>>>>>> MSR
>>>>>>>>      rdmsr
>>>>>>>>      DB      0x66
>>>>>>>>      test    ebx, BIT20                  ; check NXE
>>>>>>>> capability
>>>>>>>>      jz      .1
>>>>>>>>      or      ah, BIT3                    ; set NXE
>>>> bit
>>>>>>>>      wrmsr
>>>>>>>>  .1:
>>>>>>>> -    DB      0x66, 0xb8
>>>>>>>> +    DB      0x66, 0xb8                  ; mov eax,
>>>>>> imm32
>>>>>>>>  ASM_PFX(gSmmCr0): DD 0
>>>>>>>>      DB      0xbf, PROTECT_MODE_DS, 0    ; mov di,
>>>>>>>> PROTECT_MODE_DS
>>>>>>>>      mov     cr0, eax
>>>>>>>> -    DB      0x66, 0xea                   ; jmp far
>>>>>>>> [ptr48]
>>>>>>>> +    DB      0x66, 0xea                  ; jmp far
>>>>>>>> [ptr48]
>>>>>>>>  ASM_PFX(gSmmJmpAddr):
>>>>>>>>      DD      @32bit
>>>>>>>>      DW      PROTECT_MODE_CS
>>>>>>>>  @32bit:
>>>>>>>>      mov     ds, edi
>>>>>>>>      mov     es, edi
>>>>>>>> --
>>>>>>>> 2.14.1.3.gb7cf6e02401b
>>>>>>>>
>>>>>>>>
>>>>>>>> _______________________________________________
>>>>>>>> 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
>>>
>>> _______________________________________________
>>> 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