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