Commit 5b335394 authored by Luca Miccio's avatar Luca Miccio Committed by Juergen Gross

xen: add support for initializing xenstore later as HVM domain

When running as dom0less guest (HVM domain on ARM) the xenstore event
channel is available at domain creation but the shared xenstore
interface page only becomes available later on.

In that case, wait for a notification on the xenstore event channel,
then complete the xenstore initialization later, when the shared page
is actually available.

The xenstore page has few extra field. Add them to the shared struct.
One of the field is "connection", when the connection is ready, it is
zero. If the connection is not-zero, wait for a notification.
Signed-off-by: default avatarLuca Miccio <lucmiccio@gmail.com>
Signed-off-by: default avatarStefano Stabellini <stefano.stabellini@xilinx.com>
Reviewed-by: default avatarBoris Ostrovsky <boris.ostrovsky@oracle.com>
Link: https://lore.kernel.org/r/20220513211938.719341-2-sstabellini@kernel.orgSigned-off-by: default avatarJuergen Gross <jgross@suse.com>
parent 62db0faf
...@@ -65,6 +65,7 @@ ...@@ -65,6 +65,7 @@
#include "xenbus.h" #include "xenbus.h"
static int xs_init_irq;
int xen_store_evtchn; int xen_store_evtchn;
EXPORT_SYMBOL_GPL(xen_store_evtchn); EXPORT_SYMBOL_GPL(xen_store_evtchn);
...@@ -750,6 +751,20 @@ static void xenbus_probe(void) ...@@ -750,6 +751,20 @@ static void xenbus_probe(void)
{ {
xenstored_ready = 1; xenstored_ready = 1;
if (!xen_store_interface) {
xen_store_interface = xen_remap(xen_store_gfn << XEN_PAGE_SHIFT,
XEN_PAGE_SIZE);
/*
* Now it is safe to free the IRQ used for xenstore late
* initialization. No need to unbind: it is about to be
* bound again from xb_init_comms. Note that calling
* unbind_from_irqhandler now would result in xen_evtchn_close()
* being called and the event channel not being enabled again
* afterwards, resulting in missed event notifications.
*/
free_irq(xs_init_irq, &xb_waitq);
}
/* /*
* In the HVM case, xenbus_init() deferred its call to * In the HVM case, xenbus_init() deferred its call to
* xs_init() in case callbacks were not operational yet. * xs_init() in case callbacks were not operational yet.
...@@ -798,20 +813,22 @@ static int __init xenbus_probe_initcall(void) ...@@ -798,20 +813,22 @@ static int __init xenbus_probe_initcall(void)
{ {
/* /*
* Probe XenBus here in the XS_PV case, and also XS_HVM unless we * Probe XenBus here in the XS_PV case, and also XS_HVM unless we
* need to wait for the platform PCI device to come up. * need to wait for the platform PCI device to come up or
* xen_store_interface is not ready.
*/ */
if (xen_store_domain_type == XS_PV || if (xen_store_domain_type == XS_PV ||
(xen_store_domain_type == XS_HVM && (xen_store_domain_type == XS_HVM &&
!xs_hvm_defer_init_for_callback())) !xs_hvm_defer_init_for_callback() &&
xen_store_interface != NULL))
xenbus_probe(); xenbus_probe();
/* /*
* For XS_LOCAL, spawn a thread which will wait for xenstored * For XS_LOCAL or when xen_store_interface is not ready, spawn a
* or a xenstore-stubdom to be started, then probe. It will be * thread which will wait for xenstored or a xenstore-stubdom to be
* triggered when communication starts happening, by waiting * started, then probe. It will be triggered when communication
* on xb_waitq. * starts happening, by waiting on xb_waitq.
*/ */
if (xen_store_domain_type == XS_LOCAL) { if (xen_store_domain_type == XS_LOCAL || xen_store_interface == NULL) {
struct task_struct *probe_task; struct task_struct *probe_task;
probe_task = kthread_run(xenbus_probe_thread, NULL, probe_task = kthread_run(xenbus_probe_thread, NULL,
...@@ -907,10 +924,25 @@ static struct notifier_block xenbus_resume_nb = { ...@@ -907,10 +924,25 @@ static struct notifier_block xenbus_resume_nb = {
.notifier_call = xenbus_resume_cb, .notifier_call = xenbus_resume_cb,
}; };
static irqreturn_t xenbus_late_init(int irq, void *unused)
{
int err;
uint64_t v = 0;
err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v);
if (err || !v || !~v)
return IRQ_HANDLED;
xen_store_gfn = (unsigned long)v;
wake_up(&xb_waitq);
return IRQ_HANDLED;
}
static int __init xenbus_init(void) static int __init xenbus_init(void)
{ {
int err; int err;
uint64_t v = 0; uint64_t v = 0;
bool wait = false;
xen_store_domain_type = XS_UNKNOWN; xen_store_domain_type = XS_UNKNOWN;
if (!xen_domain()) if (!xen_domain())
...@@ -957,12 +989,15 @@ static int __init xenbus_init(void) ...@@ -957,12 +989,15 @@ static int __init xenbus_init(void)
* been properly initialized. Instead of attempting to map a * been properly initialized. Instead of attempting to map a
* wrong guest physical address return error. * wrong guest physical address return error.
* *
* Also recognize all bits set as an invalid value. * Also recognize all bits set as an invalid/uninitialized value.
*/ */
if (!v || !~v) { if (!v) {
err = -ENOENT; err = -ENOENT;
goto out_error; goto out_error;
} }
if (v == ~0ULL) {
wait = true;
} else {
/* Avoid truncation on 32-bit. */ /* Avoid truncation on 32-bit. */
#if BITS_PER_LONG == 32 #if BITS_PER_LONG == 32
if (v > ULONG_MAX) { if (v > ULONG_MAX) {
...@@ -976,6 +1011,22 @@ static int __init xenbus_init(void) ...@@ -976,6 +1011,22 @@ static int __init xenbus_init(void)
xen_store_interface = xen_store_interface =
xen_remap(xen_store_gfn << XEN_PAGE_SHIFT, xen_remap(xen_store_gfn << XEN_PAGE_SHIFT,
XEN_PAGE_SIZE); XEN_PAGE_SIZE);
if (xen_store_interface->connection != XENSTORE_CONNECTED)
wait = true;
}
if (wait) {
err = bind_evtchn_to_irqhandler(xen_store_evtchn,
xenbus_late_init,
0, "xenstore_late_init",
&xb_waitq);
if (err < 0) {
pr_err("xenstore_late_init couldn't bind irq err=%d\n",
err);
return err;
}
xs_init_irq = err;
}
break; break;
default: default:
pr_warn("Xenstore state unknown\n"); pr_warn("Xenstore state unknown\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment