[CPU] MMIO: Arm64, load register writes + exception cleanup

This commit is contained in:
Triang3l
2022-07-06 21:02:59 +03:00
parent fd03d886e9
commit 326e718035
9 changed files with 496 additions and 105 deletions

View File

@@ -48,13 +48,19 @@ namespace xe {
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
constexpr uint32_t kArm64LoadStoreAnyMask = UINT32_C(0x0A000000);
constexpr uint32_t kArm64LoadStoreAnyValue = UINT32_C(0x08000000);
constexpr uint32_t kArm64LoadStorePairAnyMask = UINT32_C(0x3A000000);
constexpr uint32_t kArm64LoadStorePairAnyValue = UINT32_C(0x28000000);
constexpr uint32_t kArm64LoadStorePairLoadBit = UINT32_C(1) << 22;
constexpr uint32_t kArm64LoadStoreMask = UINT32_C(0xC4C00000);
// `Instruction address + literal offset` loads.
// This includes PRFM_lit.
constexpr uint32_t kArm64LoadLiteralFMask = UINT32_C(0x3B000000);
constexpr uint32_t kArm64LoadLiteralFixed = UINT32_C(0x18000000);
constexpr uint32_t kArm64LoadStoreAnyFMask = UINT32_C(0x0A000000);
constexpr uint32_t kArm64LoadStoreAnyFixed = UINT32_C(0x08000000);
constexpr uint32_t kArm64LoadStorePairAnyFMask = UINT32_C(0x3A000000);
constexpr uint32_t kArm64LoadStorePairAnyFixed = UINT32_C(0x28000000);
constexpr uint32_t kArm64LoadStorePairLoadBit = UINT32_C(1) << 22;
constexpr uint32_t kArm64LoadStoreMask = UINT32_C(0xC4C00000);
enum class Arm64LoadStoreOp : uint32_t {
kSTRB_w = UINT32_C(0x00000000),
kSTRH_w = UINT32_C(0x40000000),
@@ -82,6 +88,17 @@ enum class Arm64LoadStoreOp : uint32_t {
kPRFM = UINT32_C(0xC0800000),
};
constexpr uint32_t kArm64LoadStoreOffsetFMask = UINT32_C(0x3B200C00);
enum class Arm64LoadStoreOffsetFixed : uint32_t {
kUnscaledOffset = UINT32_C(0x38000000),
kPostIndex = UINT32_C(0x38000400),
kPreIndex = UINT32_C(0x38000C00),
kRegisterOffset = UINT32_C(0x38200800),
};
constexpr uint32_t kArm64LoadStoreUnsignedOffsetFMask = UINT32_C(0x3B000000);
constexpr uint32_t kArm64LoadStoreUnsignedOffsetFixed = UINT32_C(0x39000000);
bool IsArm64LoadPrefetchStore(uint32_t instruction, bool& is_store_out);
class Exception {
@@ -114,6 +131,14 @@ class Exception {
Code code() const { return code_; }
// Returns the platform-specific thread context info.
// Note that certain registers must be modified through Modify* proxy
// functions rather than directly:
// x86-64:
// - General-purpose registers (r##, r8-r15).
// - XMM registers.
// AArch64:
// - General-purpose registers (Xn), including FP and LR.
// - SIMD and floating-point registers (Vn).
HostThreadContext* thread_context() const { return thread_context_; }
// Returns the program counter where the exception occurred.
@@ -139,6 +164,35 @@ class Exception {
#endif // XE_ARCH
}
#if XE_ARCH_AMD64
// The index is relative to X64Register::kIntRegisterFirst.
uint64_t& ModifyIntRegister(uint32_t index) {
assert_true(index <= 15);
modified_int_registers_ |= UINT16_C(1) << index;
return thread_context_->int_registers[index];
}
uint16_t modified_int_registers() const { return modified_int_registers_; }
vec128_t& ModifyXmmRegister(uint32_t index) {
assert_true(index <= 15);
modified_xmm_registers_ |= UINT16_C(1) << index;
return thread_context_->xmm_registers[index];
}
uint16_t modified_xmm_registers() const { return modified_xmm_registers_; }
#elif XE_ARCH_ARM64
uint64_t& ModifyXRegister(uint32_t index) {
assert_true(index <= 30);
modified_x_registers_ |= UINT32_C(1) << index;
return thread_context_->x[index];
}
uint32_t modified_x_registers() const { return modified_x_registers_; }
vec128_t& ModifyVRegister(uint32_t index) {
assert_true(index <= 31);
modified_v_registers_ |= UINT32_C(1) << index;
return thread_context_->v[index];
}
uint32_t modified_v_registers() const { return modified_v_registers_; }
#endif // XE_ARCH
// In case of AV, address that was read from/written to.
uint64_t fault_address() const { return fault_address_; }
@@ -150,6 +204,13 @@ class Exception {
private:
Code code_ = Code::kInvalidException;
HostThreadContext* thread_context_ = nullptr;
#if XE_ARCH_AMD64
uint16_t modified_int_registers_ = 0;
uint16_t modified_xmm_registers_ = 0;
#elif XE_ARCH_ARM64
uint32_t modified_x_registers_ = 0;
uint32_t modified_v_registers_ = 0;
#endif // XE_ARCH
uint64_t fault_address_ = 0;
AccessViolationOperation access_violation_operation_ =
AccessViolationOperation::kUnknown;