@@ -211,3 +211,83 @@ void hv_get_vpreg_128(u32 msr, struct hv_get_vp_registers_output *res)
211211 kfree (output );
212212}
213213EXPORT_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 );
0 commit comments