diff options
Diffstat (limited to 'contrib/llvm-project/lld/ELF/AArch64ErrataFix.cpp')
| -rw-r--r-- | contrib/llvm-project/lld/ELF/AArch64ErrataFix.cpp | 80 |
1 files changed, 39 insertions, 41 deletions
diff --git a/contrib/llvm-project/lld/ELF/AArch64ErrataFix.cpp b/contrib/llvm-project/lld/ELF/AArch64ErrataFix.cpp index b2eda4dcbc4e..398320af71e3 100644 --- a/contrib/llvm-project/lld/ELF/AArch64ErrataFix.cpp +++ b/contrib/llvm-project/lld/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. @@ -64,7 +61,7 @@ static bool isADRP(uint32_t instr) { // Instructions appear in order of appearance starting from table in // C4.1.3 Loads and Stores. -// All loads and stores have 1 (at bit postion 27), (0 at bit position 25). +// All loads and stores have 1 (at bit position 27), (0 at bit position 25). // | op0 x op1 (2) | 1 op2 0 op3 (2) | x | op4 (5) | xxxx | op5 (2) | x (10) | static bool isLoadStoreClass(uint32_t instr) { return (instr & 0x0a000000) == 0x08000000; @@ -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); @@ -384,15 +381,19 @@ public: uint64_t getLDSTAddr() const; + static bool classof(const SectionBase *d) { + return d->kind() == InputSectionBase::Synthetic && d->name == ".text.patch"; + } + // 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 +404,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 +462,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 +512,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 +530,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 +576,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 +592,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 +601,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()) @@ -627,10 +623,10 @@ AArch64Err843419Patcher::patchInputSectionDescription( // // PostConditions: // Returns true if at least one patch was added. The addresses of the -// Ouptut and Input Sections may have been changed. +// Output 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 +645,5 @@ bool AArch64Err843419Patcher::createFixes() { } return addressesChanged; } +} // namespace elf +} // namespace lld |
