1 // Copyright 2014 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Declares a Simulator for PPC instructions if we are not generating a native 6 // PPC binary. This Simulator allows us to run and debug PPC code generation on 7 // regular desktop machines. 8 // V8 calls into generated code via the GeneratedCode wrapper, 9 // which will start execution in the Simulator or forwards to the real entry 10 // on a PPC HW platform. 11 12 #ifndef V8_EXECUTION_PPC_SIMULATOR_PPC_H_ 13 #define V8_EXECUTION_PPC_SIMULATOR_PPC_H_ 14 15 // globals.h defines USE_SIMULATOR. 16 #include "src/common/globals.h" 17 18 #if defined(USE_SIMULATOR) 19 // Running with a simulator. 20 21 #include "src/base/hashmap.h" 22 #include "src/base/lazy-instance.h" 23 #include "src/base/platform/mutex.h" 24 #include "src/base/platform/wrappers.h" 25 #include "src/codegen/assembler.h" 26 #include "src/codegen/ppc/constants-ppc.h" 27 #include "src/execution/simulator-base.h" 28 #include "src/utils/allocation.h" 29 30 namespace v8 { 31 namespace internal { 32 33 class CachePage { 34 public: 35 static const int LINE_VALID = 0; 36 static const int LINE_INVALID = 1; 37 38 static const int kPageShift = 12; 39 static const int kPageSize = 1 << kPageShift; 40 static const int kPageMask = kPageSize - 1; 41 static const int kLineShift = 2; // The cache line is only 4 bytes right now. 42 static const int kLineLength = 1 << kLineShift; 43 static const int kLineMask = kLineLength - 1; 44 CachePage()45 CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); } 46 ValidityByte(int offset)47 char* ValidityByte(int offset) { 48 return &validity_map_[offset >> kLineShift]; 49 } 50 CachedData(int offset)51 char* CachedData(int offset) { return &data_[offset]; } 52 53 private: 54 char data_[kPageSize]; // The cached data. 55 static const int kValidityMapSize = kPageSize >> kLineShift; 56 char validity_map_[kValidityMapSize]; // One byte per line. 57 }; 58 59 class Simulator : public SimulatorBase { 60 public: 61 friend class PPCDebugger; 62 enum Register { 63 no_reg = -1, 64 r0 = 0, 65 sp, 66 r2, 67 r3, 68 r4, 69 r5, 70 r6, 71 r7, 72 r8, 73 r9, 74 r10, 75 r11, 76 r12, 77 r13, 78 r14, 79 r15, 80 r16, 81 r17, 82 r18, 83 r19, 84 r20, 85 r21, 86 r22, 87 r23, 88 r24, 89 r25, 90 r26, 91 r27, 92 r28, 93 r29, 94 r30, 95 fp, 96 kNumGPRs = 32, 97 d0 = 0, 98 d1, 99 d2, 100 d3, 101 d4, 102 d5, 103 d6, 104 d7, 105 d8, 106 d9, 107 d10, 108 d11, 109 d12, 110 d13, 111 d14, 112 d15, 113 d16, 114 d17, 115 d18, 116 d19, 117 d20, 118 d21, 119 d22, 120 d23, 121 d24, 122 d25, 123 d26, 124 d27, 125 d28, 126 d29, 127 d30, 128 d31, 129 kNumFPRs = 32, 130 // PPC Simd registers are a serapre set from Floating Point registers. Refer 131 // to register-ppc.h for more details. 132 v0 = 0, 133 v1, 134 v2, 135 v3, 136 v4, 137 v5, 138 v6, 139 v7, 140 v8, 141 v9, 142 v10, 143 v11, 144 v12, 145 v13, 146 v14, 147 v15, 148 v16, 149 v17, 150 v18, 151 v19, 152 v20, 153 v21, 154 v22, 155 v23, 156 v24, 157 v25, 158 v26, 159 v27, 160 v28, 161 v29, 162 v30, 163 v31, 164 kNumSIMDRs = 32 165 }; 166 167 explicit Simulator(Isolate* isolate); 168 ~Simulator(); 169 170 // The currently executing Simulator instance. Potentially there can be one 171 // for each native thread. 172 static Simulator* current(v8::internal::Isolate* isolate); 173 174 // Accessors for register state. 175 void set_register(int reg, intptr_t value); 176 intptr_t get_register(int reg) const; 177 double get_double_from_register_pair(int reg); set_d_register_from_double(int dreg,const double dbl)178 void set_d_register_from_double(int dreg, const double dbl) { 179 DCHECK(dreg >= 0 && dreg < kNumFPRs); 180 *bit_cast<double*>(&fp_registers_[dreg]) = dbl; 181 } get_double_from_d_register(int dreg)182 double get_double_from_d_register(int dreg) { 183 DCHECK(dreg >= 0 && dreg < kNumFPRs); 184 return *bit_cast<double*>(&fp_registers_[dreg]); 185 } set_d_register(int dreg,int64_t value)186 void set_d_register(int dreg, int64_t value) { 187 DCHECK(dreg >= 0 && dreg < kNumFPRs); 188 fp_registers_[dreg] = value; 189 } get_d_register(int dreg)190 int64_t get_d_register(int dreg) { 191 DCHECK(dreg >= 0 && dreg < kNumFPRs); 192 return fp_registers_[dreg]; 193 } 194 195 // Special case of set_register and get_register to access the raw PC value. 196 void set_pc(intptr_t value); 197 intptr_t get_pc() const; 198 get_sp()199 Address get_sp() const { return static_cast<Address>(get_register(sp)); } 200 201 // Accessor to the internal Link Register 202 intptr_t get_lr() const; 203 204 // Accessor to the internal simulator stack area. 205 uintptr_t StackLimit(uintptr_t c_limit) const; 206 207 // Executes PPC instructions until the PC reaches end_sim_pc. 208 void Execute(); 209 210 template <typename Return, typename... Args> Call(Address entry,Args...args)211 Return Call(Address entry, Args... args) { 212 return VariadicCall<Return>(this, &Simulator::CallImpl, entry, args...); 213 } 214 215 // Alternative: call a 2-argument double function. 216 void CallFP(Address entry, double d0, double d1); 217 int32_t CallFPReturnsInt(Address entry, double d0, double d1); 218 double CallFPReturnsDouble(Address entry, double d0, double d1); 219 220 // Push an address onto the JS stack. 221 uintptr_t PushAddress(uintptr_t address); 222 223 // Pop an address from the JS stack. 224 uintptr_t PopAddress(); 225 226 // Debugger input. 227 void set_last_debugger_input(char* input); last_debugger_input()228 char* last_debugger_input() { return last_debugger_input_; } 229 230 // Redirection support. 231 static void SetRedirectInstruction(Instruction* instruction); 232 233 // ICache checking. 234 static bool ICacheMatch(void* one, void* two); 235 static void FlushICache(base::CustomMatcherHashMap* i_cache, void* start, 236 size_t size); 237 238 // Returns true if pc register contains one of the 'special_values' defined 239 // below (bad_lr, end_sim_pc). 240 bool has_bad_pc() const; 241 242 enum special_values { 243 // Known bad pc value to ensure that the simulator does not execute 244 // without being properly setup. 245 bad_lr = -1, 246 // A pc value used to signal the simulator to stop execution. Generally 247 // the lr is set to this value on transition from native C code to 248 // simulated execution, so that the simulator can "return" to the native 249 // C code. 250 end_sim_pc = -2 251 }; 252 253 intptr_t CallImpl(Address entry, int argument_count, 254 const intptr_t* arguments); 255 256 enum BCType { BC_OFFSET, BC_LINK_REG, BC_CTR_REG }; 257 258 // Unsupported instructions use Format to print an error and stop execution. 259 void Format(Instruction* instr, const char* format); 260 261 // Helper functions to set the conditional flags in the architecture state. 262 bool CarryFrom(int32_t left, int32_t right, int32_t carry = 0); 263 bool BorrowFrom(int32_t left, int32_t right); 264 bool OverflowFrom(int32_t alu_out, int32_t left, int32_t right, 265 bool addition); 266 267 // Helper functions to decode common "addressing" modes 268 int32_t GetShiftRm(Instruction* instr, bool* carry_out); 269 int32_t GetImm(Instruction* instr, bool* carry_out); 270 void ProcessPUW(Instruction* instr, int num_regs, int operand_size, 271 intptr_t* start_address, intptr_t* end_address); 272 void HandleRList(Instruction* instr, bool load); 273 void HandleVList(Instruction* inst); 274 void SoftwareInterrupt(Instruction* instr); 275 void DebugAtNextPC(); 276 277 // Stop helper functions. 278 inline bool isStopInstruction(Instruction* instr); 279 inline bool isWatchedStop(uint32_t bkpt_code); 280 inline bool isEnabledStop(uint32_t bkpt_code); 281 inline void EnableStop(uint32_t bkpt_code); 282 inline void DisableStop(uint32_t bkpt_code); 283 inline void IncreaseStopCounter(uint32_t bkpt_code); 284 void PrintStopInfo(uint32_t code); 285 286 // Read and write memory. 287 template <typename T> Read(uintptr_t address,T * value)288 inline void Read(uintptr_t address, T* value) { 289 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); 290 memcpy(value, reinterpret_cast<const char*>(address), sizeof(T)); 291 } 292 293 template <typename T> ReadEx(uintptr_t address,T * value)294 inline void ReadEx(uintptr_t address, T* value) { 295 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); 296 GlobalMonitor::Get()->NotifyLoadExcl( 297 address, static_cast<TransactionSize>(sizeof(T)), 298 isolate_->thread_id()); 299 memcpy(value, reinterpret_cast<const char*>(address), sizeof(T)); 300 } 301 302 template <typename T> Write(uintptr_t address,T value)303 inline void Write(uintptr_t address, T value) { 304 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); 305 GlobalMonitor::Get()->NotifyStore(address, 306 static_cast<TransactionSize>(sizeof(T)), 307 isolate_->thread_id()); 308 memcpy(reinterpret_cast<char*>(address), &value, sizeof(T)); 309 } 310 311 template <typename T> WriteEx(uintptr_t address,T value)312 inline int32_t WriteEx(uintptr_t address, T value) { 313 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); 314 if (GlobalMonitor::Get()->NotifyStoreExcl( 315 address, static_cast<TransactionSize>(sizeof(T)), 316 isolate_->thread_id())) { 317 memcpy(reinterpret_cast<char*>(address), &value, sizeof(T)); 318 return 0; 319 } else { 320 return 1; 321 } 322 } 323 324 // Byte Reverse. __builtin_bswap128(__uint128_t v)325 static inline __uint128_t __builtin_bswap128(__uint128_t v) { 326 union { 327 uint64_t u64[2]; 328 __uint128_t u128; 329 } res, val; 330 val.u128 = v; 331 res.u64[0] = __builtin_bswap64(val.u64[1]); 332 res.u64[1] = __builtin_bswap64(val.u64[0]); 333 return res.u128; 334 } 335 336 #define RW_VAR_LIST(V) \ 337 V(QWU, unsigned __int128) \ 338 V(QW, __int128) \ 339 V(DWU, uint64_t) \ 340 V(DW, int64_t) \ 341 V(WU, uint32_t) \ 342 V(W, int32_t) V(HU, uint16_t) V(H, int16_t) V(BU, uint8_t) V(B, int8_t) 343 344 #define GENERATE_RW_FUNC(size, type) \ 345 inline type Read##size(uintptr_t addr); \ 346 inline type ReadEx##size(uintptr_t addr); \ 347 inline void Write##size(uintptr_t addr, type value); \ 348 inline int32_t WriteEx##size(uintptr_t addr, type value); 349 350 RW_VAR_LIST(GENERATE_RW_FUNC) 351 #undef GENERATE_RW_FUNC 352 353 void Trace(Instruction* instr); 354 void SetCR0(intptr_t result, bool setSO = false); 355 void SetCR6(bool true_for_all, bool false_for_all); 356 void ExecuteBranchConditional(Instruction* instr, BCType type); 357 void ExecuteGeneric(Instruction* instr); 358 SetFPSCR(int bit)359 void SetFPSCR(int bit) { fp_condition_reg_ |= (1 << (31 - bit)); } ClearFPSCR(int bit)360 void ClearFPSCR(int bit) { fp_condition_reg_ &= ~(1 << (31 - bit)); } 361 362 // Executes one instruction. 363 void ExecuteInstruction(Instruction* instr); 364 365 // ICache. 366 static void CheckICache(base::CustomMatcherHashMap* i_cache, 367 Instruction* instr); 368 static void FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t start, 369 int size); 370 static CachePage* GetCachePage(base::CustomMatcherHashMap* i_cache, 371 void* page); 372 373 // Handle arguments and return value for runtime FP functions. 374 void GetFpArgs(double* x, double* y, intptr_t* z); 375 void SetFpResult(const double& result); 376 void TrashCallerSaveRegisters(); 377 378 void CallInternal(Address entry); 379 380 // Architecture state. 381 // Saturating instructions require a Q flag to indicate saturation. 382 // There is currently no way to read the CPSR directly, and thus read the Q 383 // flag, so this is left unimplemented. 384 intptr_t registers_[kNumGPRs]; 385 int32_t condition_reg_; 386 int32_t fp_condition_reg_; 387 intptr_t special_reg_lr_; 388 intptr_t special_reg_pc_; 389 intptr_t special_reg_ctr_; 390 int32_t special_reg_xer_; 391 392 int64_t fp_registers_[kNumFPRs]; 393 394 // Simd registers. 395 union simdr_t { 396 int8_t int8[16]; 397 uint8_t uint8[16]; 398 int16_t int16[8]; 399 uint16_t uint16[8]; 400 int32_t int32[4]; 401 uint32_t uint32[4]; 402 int64_t int64[2]; 403 uint64_t uint64[2]; 404 float f32[4]; 405 double f64[2]; 406 }; 407 simdr_t simd_registers_[kNumSIMDRs]; 408 409 // Vector register lane numbers on IBM machines are reversed compared to 410 // x64. For example, doing an I32x4 extract_lane with lane number 0 on x64 411 // will be equal to lane number 3 on IBM machines. Vector registers are only 412 // used for compiling Wasm code at the moment. To keep the Wasm 413 // simulation accurate, we need to make sure accessing a lane is correctly 414 // simulated and as such we reverse the lane number on the getters and setters 415 // below. We need to be careful when getting/setting values on the Low or High 416 // side of a simulated register. In the simulation, "Low" is equal to the MSB 417 // and "High" is equal to the LSB in memory. "force_ibm_lane_numbering" could 418 // be used to disabled automatic lane number reversal and help with accessing 419 // the Low or High side of a simulated register. 420 template <class T> 421 T get_simd_register_by_lane(int reg, int lane, 422 bool force_ibm_lane_numbering = true) { 423 if (force_ibm_lane_numbering) { 424 lane = (kSimd128Size / sizeof(T)) - 1 - lane; 425 } 426 CHECK_LE(lane, kSimd128Size / sizeof(T)); 427 CHECK_LT(reg, kNumSIMDRs); 428 CHECK_GE(lane, 0); 429 CHECK_GE(reg, 0); 430 return (reinterpret_cast<T*>(&simd_registers_[reg]))[lane]; 431 } 432 433 template <class T> get_simd_register_bytes(int reg,int byte_from)434 T get_simd_register_bytes(int reg, int byte_from) { 435 // Byte location is reversed in memory. 436 int from = kSimd128Size - 1 - (byte_from + sizeof(T) - 1); 437 void* src = bit_cast<uint8_t*>(&simd_registers_[reg]) + from; 438 T dst; 439 memcpy(&dst, src, sizeof(T)); 440 return dst; 441 } 442 443 template <class T> 444 void set_simd_register_by_lane(int reg, int lane, const T& value, 445 bool force_ibm_lane_numbering = true) { 446 if (force_ibm_lane_numbering) { 447 lane = (kSimd128Size / sizeof(T)) - 1 - lane; 448 } 449 CHECK_LE(lane, kSimd128Size / sizeof(T)); 450 CHECK_LT(reg, kNumSIMDRs); 451 CHECK_GE(lane, 0); 452 CHECK_GE(reg, 0); 453 (reinterpret_cast<T*>(&simd_registers_[reg]))[lane] = value; 454 } 455 456 template <class T> set_simd_register_bytes(int reg,int byte_from,T value)457 void set_simd_register_bytes(int reg, int byte_from, T value) { 458 // Byte location is reversed in memory. 459 int from = kSimd128Size - 1 - (byte_from + sizeof(T) - 1); 460 void* dst = bit_cast<uint8_t*>(&simd_registers_[reg]) + from; 461 memcpy(dst, &value, sizeof(T)); 462 } 463 get_simd_register(int reg)464 simdr_t& get_simd_register(int reg) { return simd_registers_[reg]; } 465 set_simd_register(int reg,const simdr_t & value)466 void set_simd_register(int reg, const simdr_t& value) { 467 simd_registers_[reg] = value; 468 } 469 470 // Simulator support. 471 char* stack_; 472 static const size_t stack_protection_size_ = 256 * kSystemPointerSize; 473 bool pc_modified_; 474 int icount_; 475 476 // Debugger input. 477 char* last_debugger_input_; 478 479 // Registered breakpoints. 480 Instruction* break_pc_; 481 Instr break_instr_; 482 483 v8::internal::Isolate* isolate_; 484 485 // A stop is watched if its code is less than kNumOfWatchedStops. 486 // Only watched stops support enabling/disabling and the counter feature. 487 static const uint32_t kNumOfWatchedStops = 256; 488 489 // Breakpoint is disabled if bit 31 is set. 490 static const uint32_t kStopDisabledBit = 1 << 31; 491 492 // A stop is enabled, meaning the simulator will stop when meeting the 493 // instruction, if bit 31 of watched_stops_[code].count is unset. 494 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times 495 // the breakpoint was hit or gone through. 496 struct StopCountAndDesc { 497 uint32_t count; 498 char* desc; 499 }; 500 StopCountAndDesc watched_stops_[kNumOfWatchedStops]; 501 502 // Synchronization primitives. See ARM DDI 0406C.b, A2.9. 503 enum class MonitorAccess { 504 Open, 505 Exclusive, 506 }; 507 508 enum class TransactionSize { 509 None = 0, 510 Byte = 1, 511 HalfWord = 2, 512 Word = 4, 513 DWord = 8, 514 }; 515 516 class GlobalMonitor { 517 public: 518 // Exposed so it can be accessed by Simulator::{Read,Write}Ex*. 519 base::Mutex mutex; 520 521 void NotifyLoadExcl(uintptr_t addr, TransactionSize size, 522 ThreadId thread_id); 523 void NotifyStore(uintptr_t addr, TransactionSize size, ThreadId thread_id); 524 bool NotifyStoreExcl(uintptr_t addr, TransactionSize size, 525 ThreadId thread_id); 526 527 static GlobalMonitor* Get(); 528 529 private: 530 // Private constructor. Call {GlobalMonitor::Get()} to get the singleton. 531 GlobalMonitor() = default; 532 friend class base::LeakyObject<GlobalMonitor>; 533 534 void Clear(); 535 536 MonitorAccess access_state_ = MonitorAccess::Open; 537 uintptr_t tagged_addr_ = 0; 538 TransactionSize size_ = TransactionSize::None; 539 ThreadId thread_id_ = ThreadId::Invalid(); 540 }; 541 }; 542 543 } // namespace internal 544 } // namespace v8 545 546 #endif // defined(USE_SIMULATOR) 547 #endif // V8_EXECUTION_PPC_SIMULATOR_PPC_H_ 548