Skip to content

Commit 50b6a1a

Browse files
kelleymhSasha Levin
authored andcommitted
arm64: hyperv: Add kexec and panic handlers
Add functions to set up and remove kexec and panic handlers, and to inform Hyper-V about a guest panic. These functions are called from architecture independent code in the VMbus driver. This code is built only when CONFIG_HYPERV is enabled. Signed-off-by: Michael Kelley <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent b7cfc0b commit 50b6a1a

File tree

3 files changed

+108
-0
lines changed

3 files changed

+108
-0
lines changed

arch/arm64/hyperv/hv_core.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,3 +211,83 @@ void hv_get_vpreg_128(u32 msr, struct hv_get_vp_registers_output *res)
211211
kfree(output);
212212
}
213213
EXPORT_SYMBOL_GPL(hv_get_vpreg_128);
214+
215+
216+
/*
217+
* hyperv_report_panic - report a panic to Hyper-V. This function uses
218+
* the older version of the Hyper-V interface that admittedly doesn't
219+
* pass enough information to be useful beyond just recording the
220+
* occurrence of a panic. The parallel hyperv_report_panic_msg() uses the
221+
* new interface that allows reporting 4 Kbytes of data, which is much
222+
* more useful. Hyper-V on ARM64 always supports the newer interface, but
223+
* we retain support for the older version because the sysadmin is allowed
224+
* to disable the newer version via sysctl in case of information security
225+
* concerns about the more verbose version.
226+
*/
227+
void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die)
228+
{
229+
static bool panic_reported;
230+
u64 guest_id;
231+
232+
/* Don't report a panic to Hyper-V if we're not going to panic */
233+
if (in_die && !panic_on_oops)
234+
return;
235+
236+
/*
237+
* We prefer to report panic on 'die' chain as we have proper
238+
* registers to report, but if we miss it (e.g. on BUG()) we need
239+
* to report it on 'panic'.
240+
*
241+
* Calling code in the 'die' and 'panic' paths ensures that only
242+
* one CPU is running this code, so no atomicity is needed.
243+
*/
244+
if (panic_reported)
245+
return;
246+
panic_reported = true;
247+
248+
guest_id = hv_get_vpreg(HV_REGISTER_GUEST_OSID);
249+
250+
/*
251+
* Hyper-V provides the ability to store only 5 values.
252+
* Pick the passed in error value, the guest_id, and the PC.
253+
* The first two general registers are added arbitrarily.
254+
*/
255+
hv_set_vpreg(HV_REGISTER_CRASH_P0, err);
256+
hv_set_vpreg(HV_REGISTER_CRASH_P1, guest_id);
257+
hv_set_vpreg(HV_REGISTER_CRASH_P2, regs->pc);
258+
hv_set_vpreg(HV_REGISTER_CRASH_P3, regs->regs[0]);
259+
hv_set_vpreg(HV_REGISTER_CRASH_P4, regs->regs[1]);
260+
261+
/*
262+
* Let Hyper-V know there is crash data available
263+
*/
264+
hv_set_vpreg(HV_REGISTER_CRASH_CTL, HV_CRASH_CTL_CRASH_NOTIFY);
265+
}
266+
EXPORT_SYMBOL_GPL(hyperv_report_panic);
267+
268+
/*
269+
* hyperv_report_panic_msg - report panic message to Hyper-V
270+
* @pa: physical address of the panic page containing the message
271+
* @size: size of the message in the page
272+
*/
273+
void hyperv_report_panic_msg(phys_addr_t pa, size_t size)
274+
{
275+
/*
276+
* P3 to contain the physical address of the panic page & P4 to
277+
* contain the size of the panic data in that page. Rest of the
278+
* registers are no-op when the NOTIFY_MSG flag is set.
279+
*/
280+
hv_set_vpreg(HV_REGISTER_CRASH_P0, 0);
281+
hv_set_vpreg(HV_REGISTER_CRASH_P1, 0);
282+
hv_set_vpreg(HV_REGISTER_CRASH_P2, 0);
283+
hv_set_vpreg(HV_REGISTER_CRASH_P3, pa);
284+
hv_set_vpreg(HV_REGISTER_CRASH_P4, size);
285+
286+
/*
287+
* Let Hyper-V know there is crash data available along with
288+
* the panic message.
289+
*/
290+
hv_set_vpreg(HV_REGISTER_CRASH_CTL,
291+
(HV_CRASH_CTL_CRASH_NOTIFY | HV_CRASH_CTL_CRASH_NOTIFY_MSG));
292+
}
293+
EXPORT_SYMBOL_GPL(hyperv_report_panic_msg);

arch/arm64/hyperv/mshyperv.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
static void (*vmbus_handler)(void);
2525
static void (*hv_stimer0_handler)(void);
26+
static void (*hv_kexec_handler)(void);
27+
static void (*hv_crash_handler)(struct pt_regs *regs);
2628

2729
static int vmbus_irq;
2830
static long __percpu *vmbus_evt;
@@ -131,3 +133,27 @@ void hv_remove_stimer0_irq(int irq)
131133
}
132134
}
133135
EXPORT_SYMBOL_GPL(hv_remove_stimer0_irq);
136+
137+
void hv_setup_kexec_handler(void (*handler)(void))
138+
{
139+
hv_kexec_handler = handler;
140+
}
141+
EXPORT_SYMBOL_GPL(hv_setup_kexec_handler);
142+
143+
void hv_remove_kexec_handler(void)
144+
{
145+
hv_kexec_handler = NULL;
146+
}
147+
EXPORT_SYMBOL_GPL(hv_remove_kexec_handler);
148+
149+
void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs))
150+
{
151+
hv_crash_handler = handler;
152+
}
153+
EXPORT_SYMBOL_GPL(hv_setup_crash_handler);
154+
155+
void hv_remove_crash_handler(void)
156+
{
157+
hv_crash_handler = NULL;
158+
}
159+
EXPORT_SYMBOL_GPL(hv_remove_crash_handler);

arch/arm64/include/asm/mshyperv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ static inline int hv_get_vector(void)
149149
return vmbus_interrupt;
150150
}
151151

152+
#define hv_get_crash_ctl(val) \
153+
(val = hv_get_vpreg(HV_REGISTER_CRASH_CTL))
152154

153155
/* SMCCC hypercall parameters */
154156
#define HV_SMCCC_FUNC_NUMBER 1

0 commit comments

Comments
 (0)