On 14 April 2016 at 13:17, Mark Rutland <mark.rutl...@arm.com> wrote: > On Tue, Apr 12, 2016 at 08:57:46AM +0200, Ard Biesheuvel wrote: >> On ARM, manipulating live page tables is cumbersome since the architecture >> mandates the use of break-before-make, i.e., replacing a block entry with >> a table entry requires an intermediate step via an invalid entry, or TLB >> conflicts may occur. >> >> Since it is not generally feasible to decide in the page table manipulation >> routines whether such an invalid entry will result in those routines >> themselves to become unavailable, use a function that is callable with >> the MMU off (i.e., a leaf function that does not access the stack) to >> perform the change of a block entry into a table entry. >> >> Note that the opposite should never occur, i.e., table entries are never >> coalesced into block entries. >> >> Contributed-under: TianoCore Contribution Agreement 1.0 >> Signed-off-by: Ard Biesheuvel <ard.biesheu...@linaro.org> >> --- >> ArmPkg/Include/Library/ArmLib.h | 6 +++ >> ArmPkg/Library/ArmLib/AArch64/AArch64Lib.inf | 5 +- >> ArmPkg/Library/ArmLib/AArch64/AArch64LibConstructor.c | 36 +++++++++++++ >> ArmPkg/Library/ArmLib/AArch64/AArch64Mmu.c | 17 +++++- >> ArmPkg/Library/ArmLib/AArch64/AArch64Support.S | 57 >> ++++++++++++++++++++ >> 5 files changed, 119 insertions(+), 2 deletions(-) > > >> +RETURN_STATUS >> +EFIAPI >> +AArch64LibConstructor ( >> + VOID >> + ) >> +{ >> + extern UINT32 ArmReplaceLiveTranslationEntrySize; >> + >> + // >> + // The ArmReplaceLiveTranslationEntry () helper function may be invoked >> + // with the MMU off so we have to ensure that it gets cleaned to the PoC >> + // >> + WriteBackDataCacheRange (ArmReplaceLiveTranslationEntry, >> + ArmReplaceLiveTranslationEntrySize); >> + >> + return RETURN_SUCCESS; >> +} > > I take it that ArmReplaceLiveTranslationEntry isn't part of the static > image (e.g. it gets relocated or copied after the MMU is enabled for the > first time)? > > Otherwise I'm not following why the code wouldn't be clean to the PoC. >
Yes, the various DXE modules are loaded from a compressed firmware volume by a PE/COFF loader which may clean to the PoU only. >> + // write an entry and invalidate it in the caches >> + .macro __set_entry, reg >> + str \reg, [x0] >> + dmb sy >> + dc ivac, x0 >> + dsb sy >> + .endm >> + >> + .macro __replace_entry, el >> + mrs x8, sctlr_el\el >> + bic x9, x8, #CTRL_M_BIT // Clear MMU enable bit >> + msr sctlr_el\el, x9 >> + isb >> + >> + __set_entry xzr // write invalid entry > > The MMU is off, and thus there are no TLB walks, so I don't see the > point in storing+invalidating the invalid entry here. > Do you mean storing is sufficient? Or that we don't need bbm in the first place when disabling the MMU? Because it seems to me that one implies the other: if we can flush the TLBs without the risk of them refetching the stale entries, we can just write the new value here and be done with it. > It might be better to hoist the DC CIVAC from > ArmReplaceLiveTranslationEntry to here, to keep the maintenance > together, and avoid the redundant invalidate. > > With the __set_entry macro folded in here, it would be a little clearer, > too. > > Other than that, the general strategey seems sound to me. > Thanks. >> + .if \el == 1 >> + tlbi vmalle1 >> + .else >> + tlbi alle\el >> + .endif >> + dsb sy >> + __set_entry x1 // write updated entry >> + msr sctlr_el\el, x8 >> + isb >> + .endm >> + >> +//VOID >> +//ArmReplaceLiveTranslationEntry ( >> +// IN UINT64 *Entry, >> +// IN UINT64 Value >> +// ) >> +ASM_PFX(ArmReplaceLiveTranslationEntry): >> + >> + // disable interrupts >> + mrs x2, daif >> + msr daifset, #0xf >> + isb >> + >> + // clean and invalidate first so that we don't clobber adjacent entries >> + // that are dirty in the caches >> + dc civac, x0 >> + dsb ish >> + >> + EL1_OR_EL2_OR_EL3(x3) >> +1:__replace_entry 1 >> + b 4f >> +2:__replace_entry 2 >> + b 4f >> +3:__replace_entry 3 >> +4:msr daif, x2 >> + ret >> + >> +ASM_PFX(ArmReplaceLiveTranslationEntrySize): >> + .long . - ArmReplaceLiveTranslationEntry >> + >> ASM_FUNCTION_REMOVE_IF_UNREFERENCED >> -- >> 2.5.0 >> _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel