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/lazy-instance.h" 22 #include "src/base/platform/mutex.h" 23 #include "src/utils/allocation.h" 24 25 #include "src/base/hashmap.h" 26 #include "src/codegen/assembler.h" 27 #include "src/codegen/ppc/constants-ppc.h" 28 #include "src/execution/simulator-base.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 }; 131 132 explicit Simulator(Isolate* isolate); 133 ~Simulator(); 134 135 // The currently executing Simulator instance. Potentially there can be one 136 // for each native thread. 137 static Simulator* current(v8::internal::Isolate* isolate); 138 139 // Accessors for register state. 140 void set_register(int reg, intptr_t value); 141 intptr_t get_register(int reg) const; 142 double get_double_from_register_pair(int reg); set_d_register_from_double(int dreg,const double dbl)143 void set_d_register_from_double(int dreg, const double dbl) { 144 DCHECK(dreg >= 0 && dreg < kNumFPRs); 145 *bit_cast<double*>(&fp_registers_[dreg]) = dbl; 146 } get_double_from_d_register(int dreg)147 double get_double_from_d_register(int dreg) { 148 DCHECK(dreg >= 0 && dreg < kNumFPRs); 149 return *bit_cast<double*>(&fp_registers_[dreg]); 150 } set_d_register(int dreg,int64_t value)151 void set_d_register(int dreg, int64_t value) { 152 DCHECK(dreg >= 0 && dreg < kNumFPRs); 153 fp_registers_[dreg] = value; 154 } get_d_register(int dreg)155 int64_t get_d_register(int dreg) { 156 DCHECK(dreg >= 0 && dreg < kNumFPRs); 157 return fp_registers_[dreg]; 158 } 159 160 // Special case of set_register and get_register to access the raw PC value. 161 void set_pc(intptr_t value); 162 intptr_t get_pc() const; 163 get_sp()164 Address get_sp() const { return static_cast<Address>(get_register(sp)); } 165 166 // Accessor to the internal Link Register 167 intptr_t get_lr() const; 168 169 // Accessor to the internal simulator stack area. 170 uintptr_t StackLimit(uintptr_t c_limit) const; 171 172 // Executes PPC instructions until the PC reaches end_sim_pc. 173 void Execute(); 174 175 template <typename Return, typename... Args> Call(Address entry,Args...args)176 Return Call(Address entry, Args... args) { 177 return VariadicCall<Return>(this, &Simulator::CallImpl, entry, args...); 178 } 179 180 // Alternative: call a 2-argument double function. 181 void CallFP(Address entry, double d0, double d1); 182 int32_t CallFPReturnsInt(Address entry, double d0, double d1); 183 double CallFPReturnsDouble(Address entry, double d0, double d1); 184 185 // Push an address onto the JS stack. 186 uintptr_t PushAddress(uintptr_t address); 187 188 // Pop an address from the JS stack. 189 uintptr_t PopAddress(); 190 191 // Debugger input. 192 void set_last_debugger_input(char* input); last_debugger_input()193 char* last_debugger_input() { return last_debugger_input_; } 194 195 // Redirection support. 196 static void SetRedirectInstruction(Instruction* instruction); 197 198 // ICache checking. 199 static bool ICacheMatch(void* one, void* two); 200 static void FlushICache(base::CustomMatcherHashMap* i_cache, void* start, 201 size_t size); 202 203 // Returns true if pc register contains one of the 'special_values' defined 204 // below (bad_lr, end_sim_pc). 205 bool has_bad_pc() const; 206 207 private: 208 enum special_values { 209 // Known bad pc value to ensure that the simulator does not execute 210 // without being properly setup. 211 bad_lr = -1, 212 // A pc value used to signal the simulator to stop execution. Generally 213 // the lr is set to this value on transition from native C code to 214 // simulated execution, so that the simulator can "return" to the native 215 // C code. 216 end_sim_pc = -2 217 }; 218 219 intptr_t CallImpl(Address entry, int argument_count, 220 const intptr_t* arguments); 221 222 enum BCType { BC_OFFSET, BC_LINK_REG, BC_CTR_REG }; 223 224 // Unsupported instructions use Format to print an error and stop execution. 225 void Format(Instruction* instr, const char* format); 226 227 // Helper functions to set the conditional flags in the architecture state. 228 bool CarryFrom(int32_t left, int32_t right, int32_t carry = 0); 229 bool BorrowFrom(int32_t left, int32_t right); 230 bool OverflowFrom(int32_t alu_out, int32_t left, int32_t right, 231 bool addition); 232 233 // Helper functions to decode common "addressing" modes 234 int32_t GetShiftRm(Instruction* instr, bool* carry_out); 235 int32_t GetImm(Instruction* instr, bool* carry_out); 236 void ProcessPUW(Instruction* instr, int num_regs, int operand_size, 237 intptr_t* start_address, intptr_t* end_address); 238 void HandleRList(Instruction* instr, bool load); 239 void HandleVList(Instruction* inst); 240 void SoftwareInterrupt(Instruction* instr); 241 void DebugAtNextPC(); 242 243 // Stop helper functions. 244 inline bool isStopInstruction(Instruction* instr); 245 inline bool isWatchedStop(uint32_t bkpt_code); 246 inline bool isEnabledStop(uint32_t bkpt_code); 247 inline void EnableStop(uint32_t bkpt_code); 248 inline void DisableStop(uint32_t bkpt_code); 249 inline void IncreaseStopCounter(uint32_t bkpt_code); 250 void PrintStopInfo(uint32_t code); 251 252 // Read and write memory. 253 template <typename T> Read(uintptr_t address,T * value)254 inline void Read(uintptr_t address, T* value) { 255 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); 256 memcpy(value, reinterpret_cast<const char*>(address), sizeof(T)); 257 } 258 259 template <typename T> ReadEx(uintptr_t address,T * value)260 inline void ReadEx(uintptr_t address, T* value) { 261 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); 262 GlobalMonitor::Get()->NotifyLoadExcl( 263 address, static_cast<TransactionSize>(sizeof(T)), 264 isolate_->thread_id()); 265 memcpy(value, reinterpret_cast<const char*>(address), sizeof(T)); 266 } 267 268 template <typename T> Write(uintptr_t address,T value)269 inline void Write(uintptr_t address, T value) { 270 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); 271 GlobalMonitor::Get()->NotifyStore(address, 272 static_cast<TransactionSize>(sizeof(T)), 273 isolate_->thread_id()); 274 memcpy(reinterpret_cast<char*>(address), &value, sizeof(T)); 275 } 276 277 template <typename T> WriteEx(uintptr_t address,T value)278 inline int32_t WriteEx(uintptr_t address, T value) { 279 base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); 280 if (GlobalMonitor::Get()->NotifyStoreExcl( 281 address, static_cast<TransactionSize>(sizeof(T)), 282 isolate_->thread_id())) { 283 memcpy(reinterpret_cast<char*>(address), &value, sizeof(T)); 284 return 0; 285 } else { 286 return 1; 287 } 288 } 289 290 #define RW_VAR_LIST(V) \ 291 V(DWU, uint64_t) \ 292 V(DW, int64_t) \ 293 V(WU, uint32_t) \ 294 V(W, int32_t) V(HU, uint16_t) V(H, int16_t) V(BU, uint8_t) V(B, int8_t) 295 296 #define GENERATE_RW_FUNC(size, type) \ 297 inline type Read##size(uintptr_t addr); \ 298 inline type ReadEx##size(uintptr_t addr); \ 299 inline void Write##size(uintptr_t addr, type value); \ 300 inline int32_t WriteEx##size(uintptr_t addr, type value); 301 302 RW_VAR_LIST(GENERATE_RW_FUNC) 303 #undef GENERATE_RW_FUNC 304 305 void Trace(Instruction* instr); 306 void SetCR0(intptr_t result, bool setSO = false); 307 void ExecuteBranchConditional(Instruction* instr, BCType type); 308 void ExecuteGeneric(Instruction* instr); 309 SetFPSCR(int bit)310 void SetFPSCR(int bit) { fp_condition_reg_ |= (1 << (31 - bit)); } ClearFPSCR(int bit)311 void ClearFPSCR(int bit) { fp_condition_reg_ &= ~(1 << (31 - bit)); } 312 313 // Executes one instruction. 314 void ExecuteInstruction(Instruction* instr); 315 316 // ICache. 317 static void CheckICache(base::CustomMatcherHashMap* i_cache, 318 Instruction* instr); 319 static void FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t start, 320 int size); 321 static CachePage* GetCachePage(base::CustomMatcherHashMap* i_cache, 322 void* page); 323 324 // Handle arguments and return value for runtime FP functions. 325 void GetFpArgs(double* x, double* y, intptr_t* z); 326 void SetFpResult(const double& result); 327 void TrashCallerSaveRegisters(); 328 329 void CallInternal(Address entry); 330 331 // Architecture state. 332 // Saturating instructions require a Q flag to indicate saturation. 333 // There is currently no way to read the CPSR directly, and thus read the Q 334 // flag, so this is left unimplemented. 335 intptr_t registers_[kNumGPRs]; 336 int32_t condition_reg_; 337 int32_t fp_condition_reg_; 338 intptr_t special_reg_lr_; 339 intptr_t special_reg_pc_; 340 intptr_t special_reg_ctr_; 341 int32_t special_reg_xer_; 342 343 int64_t fp_registers_[kNumFPRs]; 344 345 // Simulator support. 346 char* stack_; 347 static const size_t stack_protection_size_ = 256 * kSystemPointerSize; 348 bool pc_modified_; 349 int icount_; 350 351 // Debugger input. 352 char* last_debugger_input_; 353 354 // Registered breakpoints. 355 Instruction* break_pc_; 356 Instr break_instr_; 357 358 v8::internal::Isolate* isolate_; 359 360 // A stop is watched if its code is less than kNumOfWatchedStops. 361 // Only watched stops support enabling/disabling and the counter feature. 362 static const uint32_t kNumOfWatchedStops = 256; 363 364 // Breakpoint is disabled if bit 31 is set. 365 static const uint32_t kStopDisabledBit = 1 << 31; 366 367 // A stop is enabled, meaning the simulator will stop when meeting the 368 // instruction, if bit 31 of watched_stops_[code].count is unset. 369 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times 370 // the breakpoint was hit or gone through. 371 struct StopCountAndDesc { 372 uint32_t count; 373 char* desc; 374 }; 375 StopCountAndDesc watched_stops_[kNumOfWatchedStops]; 376 377 // Synchronization primitives. See ARM DDI 0406C.b, A2.9. 378 enum class MonitorAccess { 379 Open, 380 Exclusive, 381 }; 382 383 enum class TransactionSize { 384 None = 0, 385 Byte = 1, 386 HalfWord = 2, 387 Word = 4, 388 DWord = 8, 389 }; 390 391 class GlobalMonitor { 392 public: 393 // Exposed so it can be accessed by Simulator::{Read,Write}Ex*. 394 base::Mutex mutex; 395 396 void NotifyLoadExcl(uintptr_t addr, TransactionSize size, 397 ThreadId thread_id); 398 void NotifyStore(uintptr_t addr, TransactionSize size, ThreadId thread_id); 399 bool NotifyStoreExcl(uintptr_t addr, TransactionSize size, 400 ThreadId thread_id); 401 402 static GlobalMonitor* Get(); 403 404 private: 405 // Private constructor. Call {GlobalMonitor::Get()} to get the singleton. 406 GlobalMonitor() = default; 407 friend class base::LeakyObject<GlobalMonitor>; 408 409 void Clear(); 410 411 MonitorAccess access_state_ = MonitorAccess::Open; 412 uintptr_t tagged_addr_ = 0; 413 TransactionSize size_ = TransactionSize::None; 414 ThreadId thread_id_ = ThreadId::Invalid(); 415 }; 416 }; 417 418 } // namespace internal 419 } // namespace v8 420 421 #endif // defined(USE_SIMULATOR) 422 #endif // V8_EXECUTION_PPC_SIMULATOR_PPC_H_ 423