1 // Copyright 2017 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6
7 #pragma once
8
9 #include <hypervisor/guest_physical_address_space.h>
10 #include <hypervisor/trap_map.h>
11 #include <zircon/types.h>
12
13 typedef struct zx_port_packet zx_port_packet_t;
14
15 struct GuestState;
16 struct GichState;
17
18 // clang-format off
19
20 // Exception class of an exception syndrome.
21 enum class ExceptionClass : uint8_t {
22 WFI_WFE_INSTRUCTION = 0b000001,
23 SMC_INSTRUCTION = 0b010111,
24 SYSTEM_INSTRUCTION = 0b011000,
25 INSTRUCTION_ABORT = 0b100000,
26 DATA_ABORT = 0b100100,
27 };
28
exception_class_name(ExceptionClass exception_class)29 static inline const char* exception_class_name(ExceptionClass exception_class) {
30 #define EXCEPTION_CLASS_NAME(name) case ExceptionClass::name: return #name
31 switch (exception_class) {
32 EXCEPTION_CLASS_NAME(WFI_WFE_INSTRUCTION);
33 EXCEPTION_CLASS_NAME(SMC_INSTRUCTION);
34 EXCEPTION_CLASS_NAME(SYSTEM_INSTRUCTION);
35 EXCEPTION_CLASS_NAME(INSTRUCTION_ABORT);
36 EXCEPTION_CLASS_NAME(DATA_ABORT);
37 #undef EXIT_REASON_NAME
38 default: return "UNKNOWN";
39 }
40 }
41
42 // Exception syndrome for a VM exit.
43 struct ExceptionSyndrome {
44 ExceptionClass ec;
45 uint32_t iss;
46
47 ExceptionSyndrome(uint32_t esr);
48 };
49
50 // Wait instruction that caused a VM exit.
51 struct WaitInstruction {
52 bool is_wfe;
53
54 WaitInstruction(uint32_t iss);
55 };
56
57 // SMC instruction that cause a VM exit.
58 struct SmcInstruction {
59 uint16_t imm;
60
61 SmcInstruction(uint32_t iss);
62 };
63
64 // System register associated with a system instruction.
65 enum class SystemRegister : uint16_t {
66 MAIR_EL1 = 0b11000000 << 8 /* op */ | 0b10100010 /* cr */,
67 SCTLR_EL1 = 0b11000000 << 8 /* op */ | 0b00010000 /* cr */,
68 TCR_EL1 = 0b11010000 << 8 /* op */ | 0b00100000 /* cr */,
69 TTBR0_EL1 = 0b11000000 << 8 /* op */ | 0b00100000 /* cr */,
70 TTBR1_EL1 = 0b11001000 << 8 /* op */ | 0b00100000 /* cr */,
71
72 // Debug Registers, trapped by MDCR_EL2.TDOSA = 1
73 OSLAR_EL1 = 0b10100000 << 8 /* op */ | 0b00010000 /* cr */,
74 OSLSR_EL1 = 0b10100000 << 8 /* op */ | 0b00010001 /* cr */,
75 OSDLR_EL1 = 0b10100000 << 8 /* op */ | 0b00010011 /* cr */,
76 DBGPRCR_EL1 = 0b10100000 << 8 /* op */ | 0b00010100 /* cr */,
77
78 // Interrupt Controller System Registers. See GIC v3/v4 Architecture Spec Section 8.2.
79 ICC_SGI1R_EL1 = 0b11101000 << 8 /* op */ | 0b11001011 /* cr */,
80 };
81
82 // System instruction that caused a VM exit.
83 struct SystemInstruction {
84 SystemRegister sysreg;
85 uint8_t xt;
86 bool read;
87
88 SystemInstruction(uint32_t iss);
89 };
90
91 struct SgiRegister {
92 uint8_t aff3;
93 uint8_t aff2;
94 uint8_t aff1;
95 uint8_t rs;
96 uint16_t target_list;
97 uint8_t int_id;
98 bool all_but_local;
99
100 SgiRegister(uint64_t sgi);
101 };
102
103 // Data abort that caused a VM exit.
104 struct DataAbort {
105 bool valid;
106 uint8_t access_size;
107 bool sign_extend;
108 uint8_t xt;
109 bool read;
110
111 DataAbort(uint32_t iss);
112 };
113
114 // clang-format on
115
116 void timer_maybe_interrupt(GuestState* guest_state, GichState* gich_state);
117 zx_status_t vmexit_handler(uint64_t* hcr, GuestState* guest_state, GichState* gich_state,
118 hypervisor::GuestPhysicalAddressSpace* gpas, hypervisor::TrapMap* traps,
119 zx_port_packet_t* packet);
120