13cab2bb3Spatrick //===-- xray_powerpc64.cpp --------------------------------------*- C++ -*-===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of XRay, a dynamic runtime instrumentation system.
103cab2bb3Spatrick //
113cab2bb3Spatrick // Implementation of powerpc64 and powerpc64le routines.
123cab2bb3Spatrick //
133cab2bb3Spatrick //===----------------------------------------------------------------------===//
143cab2bb3Spatrick #include "sanitizer_common/sanitizer_common.h"
153cab2bb3Spatrick #include "xray_defs.h"
163cab2bb3Spatrick #include "xray_interface_internal.h"
173cab2bb3Spatrick #include "xray_utils.h"
183cab2bb3Spatrick #include <atomic>
193cab2bb3Spatrick #include <cassert>
203cab2bb3Spatrick #include <cstring>
213cab2bb3Spatrick 
223cab2bb3Spatrick #ifndef __LITTLE_ENDIAN__
233cab2bb3Spatrick #error powerpc64 big endian is not supported for now.
243cab2bb3Spatrick #endif
253cab2bb3Spatrick 
263cab2bb3Spatrick namespace {
273cab2bb3Spatrick 
283cab2bb3Spatrick constexpr unsigned long long JumpOverInstNum = 7;
293cab2bb3Spatrick 
clearCache(void * Addr,size_t Len)303cab2bb3Spatrick void clearCache(void *Addr, size_t Len) {
313cab2bb3Spatrick   const size_t LineSize = 32;
323cab2bb3Spatrick 
333cab2bb3Spatrick   const intptr_t Mask = ~(LineSize - 1);
343cab2bb3Spatrick   const intptr_t StartLine = ((intptr_t)Addr) & Mask;
353cab2bb3Spatrick   const intptr_t EndLine = ((intptr_t)Addr + Len + LineSize - 1) & Mask;
363cab2bb3Spatrick 
373cab2bb3Spatrick   for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize)
383cab2bb3Spatrick     asm volatile("dcbf 0, %0" : : "r"(Line));
393cab2bb3Spatrick   asm volatile("sync");
403cab2bb3Spatrick 
413cab2bb3Spatrick   for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize)
423cab2bb3Spatrick     asm volatile("icbi 0, %0" : : "r"(Line));
433cab2bb3Spatrick   asm volatile("isync");
443cab2bb3Spatrick }
453cab2bb3Spatrick 
463cab2bb3Spatrick } // namespace
473cab2bb3Spatrick 
483cab2bb3Spatrick extern "C" void __clear_cache(void *start, void *end);
493cab2bb3Spatrick 
503cab2bb3Spatrick namespace __xray {
513cab2bb3Spatrick 
patchFunctionEntry(const bool Enable,uint32_t FuncId,const XRaySledEntry & Sled,void (* Trampoline)())523cab2bb3Spatrick bool patchFunctionEntry(const bool Enable, uint32_t FuncId,
533cab2bb3Spatrick                         const XRaySledEntry &Sled,
543cab2bb3Spatrick                         void (*Trampoline)()) XRAY_NEVER_INSTRUMENT {
55*1f9cb04fSpatrick   const uint64_t Address = Sled.address();
563cab2bb3Spatrick   if (Enable) {
573cab2bb3Spatrick     // lis 0, FuncId[16..32]
583cab2bb3Spatrick     // li 0, FuncId[0..15]
59*1f9cb04fSpatrick     *reinterpret_cast<uint64_t *>(Address) =
603cab2bb3Spatrick         (0x3c000000ull + (FuncId >> 16)) +
613cab2bb3Spatrick         ((0x60000000ull + (FuncId & 0xffff)) << 32);
623cab2bb3Spatrick   } else {
633cab2bb3Spatrick     // b +JumpOverInstNum instructions.
64*1f9cb04fSpatrick     *reinterpret_cast<uint32_t *>(Address) =
653cab2bb3Spatrick         0x48000000ull + (JumpOverInstNum << 2);
663cab2bb3Spatrick   }
67*1f9cb04fSpatrick   clearCache(reinterpret_cast<void *>(Address), 8);
683cab2bb3Spatrick   return true;
693cab2bb3Spatrick }
703cab2bb3Spatrick 
patchFunctionExit(const bool Enable,uint32_t FuncId,const XRaySledEntry & Sled)713cab2bb3Spatrick bool patchFunctionExit(const bool Enable, uint32_t FuncId,
723cab2bb3Spatrick                        const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
73*1f9cb04fSpatrick   const uint64_t Address = Sled.address();
743cab2bb3Spatrick   if (Enable) {
753cab2bb3Spatrick     // lis 0, FuncId[16..32]
763cab2bb3Spatrick     // li 0, FuncId[0..15]
77*1f9cb04fSpatrick     *reinterpret_cast<uint64_t *>(Address) =
783cab2bb3Spatrick         (0x3c000000ull + (FuncId >> 16)) +
793cab2bb3Spatrick         ((0x60000000ull + (FuncId & 0xffff)) << 32);
803cab2bb3Spatrick   } else {
813cab2bb3Spatrick     // Copy the blr/b instruction after JumpOverInstNum instructions.
82*1f9cb04fSpatrick     *reinterpret_cast<uint32_t *>(Address) =
83*1f9cb04fSpatrick         *(reinterpret_cast<uint32_t *>(Address) + JumpOverInstNum);
843cab2bb3Spatrick   }
85*1f9cb04fSpatrick   clearCache(reinterpret_cast<void *>(Address), 8);
863cab2bb3Spatrick   return true;
873cab2bb3Spatrick }
883cab2bb3Spatrick 
patchFunctionTailExit(const bool Enable,const uint32_t FuncId,const XRaySledEntry & Sled)893cab2bb3Spatrick bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId,
903cab2bb3Spatrick                            const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
913cab2bb3Spatrick   return patchFunctionExit(Enable, FuncId, Sled);
923cab2bb3Spatrick }
933cab2bb3Spatrick 
943cab2bb3Spatrick // FIXME: Maybe implement this better?
probeRequiredCPUFeatures()953cab2bb3Spatrick bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; }
963cab2bb3Spatrick 
patchCustomEvent(const bool Enable,const uint32_t FuncId,const XRaySledEntry & Sled)973cab2bb3Spatrick bool patchCustomEvent(const bool Enable, const uint32_t FuncId,
983cab2bb3Spatrick                       const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
993cab2bb3Spatrick   // FIXME: Implement in powerpc64?
1003cab2bb3Spatrick   return false;
1013cab2bb3Spatrick }
1023cab2bb3Spatrick 
patchTypedEvent(const bool Enable,const uint32_t FuncId,const XRaySledEntry & Sled)1033cab2bb3Spatrick bool patchTypedEvent(const bool Enable, const uint32_t FuncId,
1043cab2bb3Spatrick                      const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
1053cab2bb3Spatrick   // FIXME: Implement in powerpc64?
1063cab2bb3Spatrick   return false;
1073cab2bb3Spatrick }
1083cab2bb3Spatrick 
1093cab2bb3Spatrick } // namespace __xray
1103cab2bb3Spatrick 
__xray_ArgLoggerEntry()1113cab2bb3Spatrick extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT {
1123cab2bb3Spatrick   // FIXME: this will have to be implemented in the trampoline assembly file
1133cab2bb3Spatrick }
114