1 /* This file is part of the dynarmic project. 2 * Copyright (c) 2018 MerryMage 3 * SPDX-License-Identifier: 0BSD 4 */ 5 6 #pragma once 7 8 #include <atomic> 9 #include <array> 10 #include <cstddef> 11 #include <cstdint> 12 #include <cstring> 13 #include <vector> 14 15 namespace Dynarmic { 16 namespace A64 { 17 18 using VAddr = std::uint64_t; 19 using Vector = std::array<std::uint64_t, 2>; 20 21 class ExclusiveMonitor { 22 public: 23 /// @param processor_count Maximum number of processors using this global 24 /// exclusive monitor. Each processor must have a 25 /// unique id. 26 explicit ExclusiveMonitor(size_t processor_count); 27 28 size_t GetProcessorCount() const; 29 30 /// Marks a region containing [address, address+size) to be exclusive to 31 /// processor processor_id. 32 template <typename T, typename Function> ReadAndMark(size_t processor_id,VAddr address,Function op)33 T ReadAndMark(size_t processor_id, VAddr address, Function op) { 34 static_assert(std::is_trivially_copyable_v<T>); 35 const VAddr masked_address = address & RESERVATION_GRANULE_MASK; 36 37 Lock(); 38 exclusive_addresses[processor_id] = masked_address; 39 const T value = op(); 40 std::memcpy(exclusive_values[processor_id].data(), &value, sizeof(T)); 41 Unlock(); 42 return value; 43 } 44 45 /// Checks to see if processor processor_id has exclusive access to the 46 /// specified region. If it does, executes the operation then clears 47 /// the exclusive state for processors if their exclusive region(s) 48 /// contain [address, address+size). 49 template <typename T, typename Function> DoExclusiveOperation(size_t processor_id,VAddr address,Function op)50 bool DoExclusiveOperation(size_t processor_id, VAddr address, Function op) { 51 static_assert(std::is_trivially_copyable_v<T>); 52 if (!CheckAndClear(processor_id, address)) { 53 return false; 54 } 55 56 T saved_value; 57 std::memcpy(&saved_value, exclusive_values[processor_id].data(), sizeof(T)); 58 const bool result = op(saved_value); 59 60 Unlock(); 61 return result; 62 } 63 64 /// Unmark everything. 65 void Clear(); 66 /// Unmark processor id 67 void ClearProcessor(size_t processor_id); 68 69 private: 70 bool CheckAndClear(size_t processor_id, VAddr address); 71 72 void Lock(); 73 void Unlock(); 74 75 static constexpr VAddr RESERVATION_GRANULE_MASK = 0xFFFF'FFFF'FFFF'FFFFull; 76 static constexpr VAddr INVALID_EXCLUSIVE_ADDRESS = 0xDEAD'DEAD'DEAD'DEADull; 77 std::atomic_flag is_locked; 78 std::vector<VAddr> exclusive_addresses; 79 std::vector<Vector> exclusive_values; 80 }; 81 82 } // namespace A64 83 } // namespace Dynarmic 84