1
2
3
4
5
6
7
8
9
10
11#include <linux/types.h>
12#include <linux/export.h>
13#include <linux/mm.h>
14#include <linux/hyperv.h>
15#include <linux/arm-smccc.h>
16#include <linux/module.h>
17#include <asm-generic/bug.h>
18#include <asm/hyperv-tlfs.h>
19#include <asm/mshyperv.h>
20
21
22
23
24u64 hv_do_hypercall(u64 control, void *input, void *output)
25{
26 struct arm_smccc_res res;
27 u64 input_address;
28 u64 output_address;
29
30 input_address = input ? virt_to_phys(input) : 0;
31 output_address = output ? virt_to_phys(output) : 0;
32
33 arm_smccc_1_1_hvc(HV_FUNC_ID, control,
34 input_address, output_address, &res);
35 return res.a0;
36}
37EXPORT_SYMBOL_GPL(hv_do_hypercall);
38
39
40
41
42
43
44
45u64 hv_do_fast_hypercall8(u16 code, u64 input)
46{
47 struct arm_smccc_res res;
48 u64 control;
49
50 control = (u64)code | HV_HYPERCALL_FAST_BIT;
51
52 arm_smccc_1_1_hvc(HV_FUNC_ID, control, input, &res);
53 return res.a0;
54}
55EXPORT_SYMBOL_GPL(hv_do_fast_hypercall8);
56
57
58
59
60void hv_set_vpreg(u32 msr, u64 value)
61{
62 struct arm_smccc_res res;
63
64 arm_smccc_1_1_hvc(HV_FUNC_ID,
65 HVCALL_SET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT |
66 HV_HYPERCALL_REP_COMP_1,
67 HV_PARTITION_ID_SELF,
68 HV_VP_INDEX_SELF,
69 msr,
70 0,
71 value,
72 0,
73 &res);
74
75
76
77
78
79
80 BUG_ON(!hv_result_success(res.a0));
81}
82EXPORT_SYMBOL_GPL(hv_set_vpreg);
83
84
85
86
87
88
89
90
91void hv_get_vpreg_128(u32 msr, struct hv_get_vp_registers_output *result)
92{
93 struct arm_smccc_1_2_regs args;
94 struct arm_smccc_1_2_regs res;
95
96 args.a0 = HV_FUNC_ID;
97 args.a1 = HVCALL_GET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT |
98 HV_HYPERCALL_REP_COMP_1;
99 args.a2 = HV_PARTITION_ID_SELF;
100 args.a3 = HV_VP_INDEX_SELF;
101 args.a4 = msr;
102
103
104
105
106
107 arm_smccc_1_2_hvc(&args, &res);
108
109
110
111
112
113
114 BUG_ON(!hv_result_success(res.a0));
115
116 result->as64.low = res.a6;
117 result->as64.high = res.a7;
118}
119EXPORT_SYMBOL_GPL(hv_get_vpreg_128);
120
121u64 hv_get_vpreg(u32 msr)
122{
123 struct hv_get_vp_registers_output output;
124
125 hv_get_vpreg_128(msr, &output);
126
127 return output.as64.low;
128}
129EXPORT_SYMBOL_GPL(hv_get_vpreg);
130
131
132
133
134
135
136
137
138
139
140
141
142void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die)
143{
144 static bool panic_reported;
145 u64 guest_id;
146
147
148 if (in_die && !panic_on_oops)
149 return;
150
151
152
153
154
155
156
157
158
159 if (panic_reported)
160 return;
161 panic_reported = true;
162
163 guest_id = hv_get_vpreg(HV_REGISTER_GUEST_OSID);
164
165
166
167
168
169
170 hv_set_vpreg(HV_REGISTER_CRASH_P0, err);
171 hv_set_vpreg(HV_REGISTER_CRASH_P1, guest_id);
172 hv_set_vpreg(HV_REGISTER_CRASH_P2, regs->pc);
173 hv_set_vpreg(HV_REGISTER_CRASH_P3, regs->sp);
174 hv_set_vpreg(HV_REGISTER_CRASH_P4, 0);
175
176
177
178
179 hv_set_vpreg(HV_REGISTER_CRASH_CTL, HV_CRASH_CTL_CRASH_NOTIFY);
180}
181EXPORT_SYMBOL_GPL(hyperv_report_panic);
182