diff options
Diffstat (limited to 'ELF/AArch64ErrataFix.cpp')
-rw-r--r-- | ELF/AArch64ErrataFix.cpp | 72 |
1 files changed, 33 insertions, 39 deletions
diff --git a/ELF/AArch64ErrataFix.cpp b/ELF/AArch64ErrataFix.cpp index b2eda4dcbc4e9..7fb3e02e7ee4f 100644 --- a/ELF/AArch64ErrataFix.cpp +++ b/ELF/AArch64ErrataFix.cpp @@ -6,7 +6,10 @@ // //===----------------------------------------------------------------------===// // This file implements Section Patching for the purpose of working around -// errata in CPUs. The general principle is that an erratum sequence of one or +// the AArch64 Cortex-53 errata 843419 that affects r0p0, r0p1, r0p2 and r0p4 +// versions of the core. +// +// The general principle is that an erratum sequence of one or // more instructions is detected in the instruction stream, one of the // instructions in the sequence is replaced with a branch to a patch sequence // of replacement instructions. At the end of the replacement sequence the @@ -20,12 +23,6 @@ // - We can overwrite an instruction in the erratum sequence with a branch to // the replacement sequence. // - We can place the replacement sequence within range of the branch. - -// FIXME: -// - The implementation here only supports one patch, the AArch64 Cortex-53 -// errata 843419 that affects r0p0, r0p1, r0p2 and r0p4 versions of the core. -// To keep the initial version simple there is no support for multiple -// architectures or selection of different patches. //===----------------------------------------------------------------------===// #include "AArch64ErrataFix.h" @@ -48,8 +45,8 @@ using namespace llvm::object; using namespace llvm::support; using namespace llvm::support::endian; -using namespace lld; -using namespace lld::elf; +namespace lld { +namespace elf { // Helper functions to identify instructions and conditions needed to trigger // the Cortex-A53-843419 erratum. @@ -333,16 +330,16 @@ static bool is843419ErratumSequence(uint32_t instr1, uint32_t instr2, } // Scan the instruction sequence starting at Offset Off from the base of -// InputSection IS. We update Off in this function rather than in the caller as -// we can skip ahead much further into the section when we know how many +// InputSection isec. We update Off in this function rather than in the caller +// as we can skip ahead much further into the section when we know how many // instructions we've scanned. -// Return the offset of the load or store instruction in IS that we want to +// Return the offset of the load or store instruction in isec that we want to // patch or 0 if no patch required. static uint64_t scanCortexA53Errata843419(InputSection *isec, uint64_t &off, uint64_t limit) { uint64_t isecAddr = isec->getVA(0); - // Advance Off so that (ISAddr + Off) modulo 0x1000 is at least 0xff8. + // Advance Off so that (isecAddr + Off) modulo 0x1000 is at least 0xff8. uint64_t initialPageOff = (isecAddr + off) & 0xfff; if (initialPageOff < 0xff8) off += 0xff8 - initialPageOff; @@ -374,7 +371,7 @@ static uint64_t scanCortexA53Errata843419(InputSection *isec, uint64_t &off, return patchOff; } -class lld::elf::Patch843419Section : public SyntheticSection { +class Patch843419Section : public SyntheticSection { public: Patch843419Section(InputSection *p, uint64_t off); @@ -386,13 +383,13 @@ public: // The Section we are patching. const InputSection *patchee; - // The offset of the instruction in the Patchee section we are patching. + // The offset of the instruction in the patchee section we are patching. uint64_t patcheeOffset; // A label for the start of the Patch that we can use as a relocation target. Symbol *patchSym; }; -lld::elf::Patch843419Section::Patch843419Section(InputSection *p, uint64_t off) +Patch843419Section::Patch843419Section(InputSection *p, uint64_t off) : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 4, ".text.patch"), patchee(p), patcheeOffset(off) { @@ -403,16 +400,16 @@ lld::elf::Patch843419Section::Patch843419Section(InputSection *p, uint64_t off) addSyntheticLocal(saver.save("$x"), STT_NOTYPE, 0, 0, *this); } -uint64_t lld::elf::Patch843419Section::getLDSTAddr() const { +uint64_t Patch843419Section::getLDSTAddr() const { return patchee->getVA(patcheeOffset); } -void lld::elf::Patch843419Section::writeTo(uint8_t *buf) { +void Patch843419Section::writeTo(uint8_t *buf) { // Copy the instruction that we will be replacing with a branch in the - // Patchee Section. + // patchee Section. write32le(buf, read32le(patchee->data().begin() + patcheeOffset)); - // Apply any relocation transferred from the original PatcheeSection. + // Apply any relocation transferred from the original patchee section. // For a SyntheticSection Buf already has outSecOff added, but relocateAlloc // also adds outSecOff so we need to subtract to avoid double counting. this->relocateAlloc(buf - outSecOff, buf - outSecOff + getSize()); @@ -461,18 +458,18 @@ void AArch64Err843419Patcher::init() { // $d.0 $d.1 $x.1. for (auto &kv : sectionMap) { std::vector<const Defined *> &mapSyms = kv.second; - if (mapSyms.size() <= 1) - continue; llvm::stable_sort(mapSyms, [](const Defined *a, const Defined *b) { return a->value < b->value; }); mapSyms.erase( std::unique(mapSyms.begin(), mapSyms.end(), [=](const Defined *a, const Defined *b) { - return (isCodeMapSymbol(a) && isCodeMapSymbol(b)) || - (isDataMapSymbol(a) && isDataMapSymbol(b)); + return isCodeMapSymbol(a) == isCodeMapSymbol(b); }), mapSyms.end()); + // Always start with a Code Mapping Symbol. + if (!mapSyms.empty() && !isCodeMapSymbol(mapSyms.front())) + mapSyms.erase(mapSyms.begin()); } initialized = true; } @@ -511,19 +508,16 @@ void AArch64Err843419Patcher::insertPatches( (*patchIt)->outSecOff = isecLimit; } - // merge all patch sections. We use the outSecOff assigned above to + // Merge all patch sections. We use the outSecOff assigned above to // determine the insertion point. This is ok as we only merge into an // InputSectionDescription once per pass, and at the end of the pass // assignAddresses() will recalculate all the outSecOff values. std::vector<InputSection *> tmp; tmp.reserve(isd.sections.size() + patches.size()); auto mergeCmp = [](const InputSection *a, const InputSection *b) { - if (a->outSecOff < b->outSecOff) - return true; - if (a->outSecOff == b->outSecOff && isa<Patch843419Section>(a) && - !isa<Patch843419Section>(b)) - return true; - return false; + if (a->outSecOff != b->outSecOff) + return a->outSecOff < b->outSecOff; + return isa<Patch843419Section>(a) && !isa<Patch843419Section>(b); }; std::merge(isd.sections.begin(), isd.sections.end(), patches.begin(), patches.end(), std::back_inserter(tmp), mergeCmp); @@ -532,7 +526,7 @@ void AArch64Err843419Patcher::insertPatches( // Given an erratum sequence that starts at address adrpAddr, with an // instruction that we need to patch at patcheeOffset from the start of -// InputSection IS, create a Patch843419 Section and add it to the +// InputSection isec, create a Patch843419 Section and add it to the // Patches that we need to insert. static void implementPatch(uint64_t adrpAddr, uint64_t patcheeOffset, InputSection *isec, @@ -578,7 +572,7 @@ static void implementPatch(uint64_t adrpAddr, uint64_t patcheeOffset, // Scan all the instructions in InputSectionDescription, for each instance of // the erratum sequence create a Patch843419Section. We return the list of -// Patch843419Sections that need to be applied to ISD. +// Patch843419Sections that need to be applied to the InputSectionDescription. std::vector<Patch843419Section *> AArch64Err843419Patcher::patchInputSectionDescription( InputSectionDescription &isd) { @@ -594,10 +588,7 @@ AArch64Err843419Patcher::patchInputSectionDescription( // section size). std::vector<const Defined *> &mapSyms = sectionMap[isec]; - auto codeSym = llvm::find_if(mapSyms, [&](const Defined *ms) { - return ms->getName().startswith("$x"); - }); - + auto codeSym = mapSyms.begin(); while (codeSym != mapSyms.end()) { auto dataSym = std::next(codeSym); uint64_t off = (*codeSym)->value; @@ -606,7 +597,8 @@ AArch64Err843419Patcher::patchInputSectionDescription( while (off < limit) { uint64_t startAddr = isec->getVA(off); - if (uint64_t patcheeOffset = scanCortexA53Errata843419(isec, off, limit)) + if (uint64_t patcheeOffset = + scanCortexA53Errata843419(isec, off, limit)) implementPatch(startAddr, patcheeOffset, isec, patches); } if (dataSym == mapSyms.end()) @@ -630,7 +622,7 @@ AArch64Err843419Patcher::patchInputSectionDescription( // Ouptut and Input Sections may have been changed. // Returns false if no patches were required and no changes were made. bool AArch64Err843419Patcher::createFixes() { - if (initialized == false) + if (!initialized) init(); bool addressesChanged = false; @@ -649,3 +641,5 @@ bool AArch64Err843419Patcher::createFixes() { } return addressesChanged; } +} // namespace elf +} // namespace lld |