^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * xen console driver interface to hvc_console.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * (c) 2007 Gerd Hoffmann <kraxel@suse.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/serial_core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <asm/xen/hypervisor.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <xen/xen.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <xen/interface/xen.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <xen/hvm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <xen/grant_table.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <xen/page.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <xen/events.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <xen/interface/io/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <xen/interface/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <xen/hvc-console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <xen/xenbus.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include "hvc_console.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define HVC_COOKIE 0x58656e /* "Xen" in hex */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct xencons_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct xenbus_device *xbdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct xencons_interface *intf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) unsigned int evtchn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) XENCONS_RING_IDX out_cons;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) unsigned int out_cons_same;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct hvc_struct *hvc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) int vtermno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) grant_ref_t gntref;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static LIST_HEAD(xenconsoles);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static DEFINE_SPINLOCK(xencons_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) /* ------------------------------------------------------------------ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static struct xencons_info *vtermno_to_xencons(int vtermno)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct xencons_info *entry, *n, *ret = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (list_empty(&xenconsoles))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) list_for_each_entry_safe(entry, n, &xenconsoles, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (entry->vtermno == vtermno) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) ret = entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static inline int xenbus_devid_to_vtermno(int devid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return devid + HVC_COOKIE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static inline void notify_daemon(struct xencons_info *cons)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /* Use evtchn: this is called early, before irq is set up. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) notify_remote_via_evtchn(cons->evtchn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static int __write_console(struct xencons_info *xencons,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) const char *data, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) XENCONS_RING_IDX cons, prod;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct xencons_interface *intf = xencons->intf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) int sent = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) cons = intf->out_cons;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) prod = intf->out_prod;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) mb(); /* update queue values before going on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if ((prod - cons) > sizeof(intf->out)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) pr_err_once("xencons: Illegal ring page indices");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) wmb(); /* write ring before updating pointer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) intf->out_prod = prod;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (sent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) notify_daemon(xencons);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return sent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static int domU_write_console(uint32_t vtermno, const char *data, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) int ret = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct xencons_info *cons = vtermno_to_xencons(vtermno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (cons == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) * Make sure the whole buffer is emitted, polling if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * necessary. We don't ever want to rely on the hvc daemon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * because the most interesting console output is when the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * kernel is crippled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) while (len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) int sent = __write_console(cons, data, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (sent < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return sent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) data += sent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) len -= sent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (unlikely(len))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static int domU_read_console(uint32_t vtermno, char *buf, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) struct xencons_interface *intf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) XENCONS_RING_IDX cons, prod;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) int recv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) struct xencons_info *xencons = vtermno_to_xencons(vtermno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) unsigned int eoiflag = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (xencons == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) intf = xencons->intf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) cons = intf->in_cons;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) prod = intf->in_prod;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) mb(); /* get pointers before reading ring */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if ((prod - cons) > sizeof(intf->in)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) pr_err_once("xencons: Illegal ring page indices");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) while (cons != prod && recv < len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) mb(); /* read ring before consuming */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) intf->in_cons = cons;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * When to mark interrupt having been spurious:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) * - there was no new data to be read, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) * - the backend did not consume some output bytes, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) * - the previous round with no read data didn't see consumed bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * (we might have a race with an interrupt being in flight while
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * updating xencons->out_cons, so account for that by allowing one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) * round without any visible reason)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (intf->out_cons != xencons->out_cons) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) xencons->out_cons = intf->out_cons;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) xencons->out_cons_same = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (recv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) notify_daemon(xencons);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) } else if (xencons->out_cons_same++ > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) eoiflag = XEN_EOI_FLAG_SPURIOUS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) xen_irq_lateeoi(xencons->irq, eoiflag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return recv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) static const struct hv_ops domU_hvc_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) .get_chars = domU_read_console,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) .put_chars = domU_write_console,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) .notifier_add = notifier_add_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) .notifier_del = notifier_del_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) .notifier_hangup = notifier_hangup_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) static int dom0_read_console(uint32_t vtermno, char *buf, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return HYPERVISOR_console_io(CONSOLEIO_read, len, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) * Either for a dom0 to write to the system console, or a domU with a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) * debug version of Xen
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) static int dom0_write_console(uint32_t vtermno, const char *str, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) static const struct hv_ops dom0_hvc_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) .get_chars = dom0_read_console,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) .put_chars = dom0_write_console,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) .notifier_add = notifier_add_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) .notifier_del = notifier_del_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) .notifier_hangup = notifier_hangup_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) static int xen_hvm_console_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) uint64_t v = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) unsigned long gfn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) struct xencons_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (!xen_hvm_domain())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) info = vtermno_to_xencons(HVC_COOKIE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (!info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) } else if (info->intf != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /* already configured */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * If the toolstack (or the hypervisor) hasn't set these values, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * default value is 0. Even though gfn = 0 and evtchn = 0 are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) * theoretically correct values, in practice they never are and they
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * mean that a legacy toolstack hasn't initialized the pv console correctly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) r = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (r < 0 || v == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) info->evtchn = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) v = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) r = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (r < 0 || v == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) gfn = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) info->intf = xen_remap(gfn << XEN_PAGE_SHIFT, XEN_PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (info->intf == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) info->vtermno = HVC_COOKIE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) spin_lock(&xencons_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) list_add_tail(&info->list, &xenconsoles);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) spin_unlock(&xencons_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) kfree(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) static int xencons_info_pv_init(struct xencons_info *info, int vtermno)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) info->evtchn = xen_start_info->console.domU.evtchn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) /* GFN == MFN for PV guest */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) info->intf = gfn_to_virt(xen_start_info->console.domU.mfn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) info->vtermno = vtermno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) list_add_tail(&info->list, &xenconsoles);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) static int xen_pv_console_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) struct xencons_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (!xen_pv_domain())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) if (!xen_start_info->console.domU.evtchn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) info = vtermno_to_xencons(HVC_COOKIE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) if (!info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) } else if (info->intf != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) /* already configured */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) spin_lock(&xencons_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) xencons_info_pv_init(info, HVC_COOKIE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) spin_unlock(&xencons_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) static int xen_initial_domain_console_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) struct xencons_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (!xen_initial_domain())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) info = vtermno_to_xencons(HVC_COOKIE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (!info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) info->vtermno = HVC_COOKIE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) spin_lock(&xencons_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) list_add_tail(&info->list, &xenconsoles);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) spin_unlock(&xencons_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) static void xen_console_update_evtchn(struct xencons_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) if (xen_hvm_domain()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) uint64_t v = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) err = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) if (!err && v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) info->evtchn = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) info->evtchn = xen_start_info->console.domU.evtchn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) void xen_console_resume(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) struct xencons_info *info = vtermno_to_xencons(HVC_COOKIE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (info != NULL && info->irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if (!xen_initial_domain())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) xen_console_update_evtchn(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) rebind_evtchn_irq(info->evtchn, info->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) #ifdef CONFIG_HVC_XEN_FRONTEND
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) static void xencons_disconnect_backend(struct xencons_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) if (info->irq > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) unbind_from_irqhandler(info->irq, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) info->irq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if (info->evtchn > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) xenbus_free_evtchn(info->xbdev, info->evtchn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) info->evtchn = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) if (info->gntref > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) gnttab_free_grant_references(info->gntref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) info->gntref = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (info->hvc != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) hvc_remove(info->hvc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) info->hvc = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) static void xencons_free(struct xencons_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) free_page((unsigned long)info->intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) info->intf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) info->vtermno = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) kfree(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) static int xen_console_remove(struct xencons_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) xencons_disconnect_backend(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) spin_lock(&xencons_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) list_del(&info->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) spin_unlock(&xencons_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) if (info->xbdev != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) xencons_free(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) if (xen_hvm_domain())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) iounmap(info->intf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) kfree(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) static int xencons_remove(struct xenbus_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) return xen_console_remove(dev_get_drvdata(&dev->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) static int xencons_connect_backend(struct xenbus_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) struct xencons_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) int ret, evtchn, devid, ref, irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) struct xenbus_transaction xbt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) grant_ref_t gref_head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) ret = xenbus_alloc_evtchn(dev, &evtchn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) info->evtchn = evtchn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) irq = bind_interdomain_evtchn_to_irq_lateeoi(dev->otherend_id, evtchn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) if (irq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) return irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) info->irq = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) devid = dev->nodename[strlen(dev->nodename) - 1] - '0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) info->hvc = hvc_alloc(xenbus_devid_to_vtermno(devid),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) irq, &domU_hvc_ops, 256);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) if (IS_ERR(info->hvc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) return PTR_ERR(info->hvc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) ret = gnttab_alloc_grant_references(1, &gref_head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) info->gntref = gref_head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) ref = gnttab_claim_grant_reference(&gref_head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) if (ref < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) return ref;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) gnttab_grant_foreign_access_ref(ref, info->xbdev->otherend_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) virt_to_gfn(info->intf), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) again:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) ret = xenbus_transaction_start(&xbt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) xenbus_dev_fatal(dev, ret, "starting transaction");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", ref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) goto error_xenbus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) ret = xenbus_printf(xbt, dev->nodename, "port", "%u",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) evtchn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) goto error_xenbus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) ret = xenbus_transaction_end(xbt, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if (ret == -EAGAIN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) goto again;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) xenbus_dev_fatal(dev, ret, "completing transaction");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) xenbus_switch_state(dev, XenbusStateInitialised);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) error_xenbus:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) xenbus_transaction_end(xbt, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) xenbus_dev_fatal(dev, ret, "writing xenstore");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) static int xencons_probe(struct xenbus_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) const struct xenbus_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) int ret, devid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) struct xencons_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) devid = dev->nodename[strlen(dev->nodename) - 1] - '0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) if (devid == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) dev_set_drvdata(&dev->dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) info->xbdev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) info->vtermno = xenbus_devid_to_vtermno(devid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) info->intf = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) if (!info->intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) goto error_nomem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) ret = xencons_connect_backend(dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) spin_lock(&xencons_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) list_add_tail(&info->list, &xenconsoles);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) spin_unlock(&xencons_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) error_nomem:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) xenbus_dev_fatal(dev, ret, "allocating device memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) xencons_disconnect_backend(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) xencons_free(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) static int xencons_resume(struct xenbus_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) struct xencons_info *info = dev_get_drvdata(&dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) xencons_disconnect_backend(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) memset(info->intf, 0, XEN_PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) return xencons_connect_backend(dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) static void xencons_backend_changed(struct xenbus_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) enum xenbus_state backend_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) switch (backend_state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) case XenbusStateReconfiguring:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) case XenbusStateReconfigured:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) case XenbusStateInitialising:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) case XenbusStateInitialised:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) case XenbusStateUnknown:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) case XenbusStateInitWait:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) case XenbusStateConnected:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) xenbus_switch_state(dev, XenbusStateConnected);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) case XenbusStateClosed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) if (dev->state == XenbusStateClosed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) fallthrough; /* Missed the backend's CLOSING state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) case XenbusStateClosing:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) xenbus_frontend_closed(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) static const struct xenbus_device_id xencons_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) { "console" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) { "" }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) static struct xenbus_driver xencons_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) .name = "xenconsole",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) .ids = xencons_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) .probe = xencons_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) .remove = xencons_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) .resume = xencons_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) .otherend_changed = xencons_backend_changed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) #endif /* CONFIG_HVC_XEN_FRONTEND */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) static int __init xen_hvc_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) struct xencons_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) const struct hv_ops *ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) if (!xen_domain())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) if (xen_initial_domain()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) ops = &dom0_hvc_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) r = xen_initial_domain_console_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) if (r < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) info = vtermno_to_xencons(HVC_COOKIE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) ops = &domU_hvc_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) if (xen_hvm_domain())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) r = xen_hvm_console_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) r = xen_pv_console_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) if (r < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) info = vtermno_to_xencons(HVC_COOKIE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) info->irq = bind_evtchn_to_irq_lateeoi(info->evtchn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) if (info->irq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) info->irq = 0; /* NO_IRQ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) irq_set_noprobe(info->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) info->hvc = hvc_alloc(HVC_COOKIE, info->irq, ops, 256);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) if (IS_ERR(info->hvc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) r = PTR_ERR(info->hvc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) spin_lock(&xencons_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) list_del(&info->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) spin_unlock(&xencons_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) if (info->irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) unbind_from_irqhandler(info->irq, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) kfree(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) r = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) #ifdef CONFIG_HVC_XEN_FRONTEND
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) r = xenbus_register_frontend(&xencons_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) device_initcall(xen_hvc_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) static int xen_cons_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) const struct hv_ops *ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) if (!xen_domain())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) if (xen_initial_domain())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) ops = &dom0_hvc_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) ops = &domU_hvc_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) if (xen_hvm_domain())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) r = xen_hvm_console_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) r = xen_pv_console_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) if (r < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) hvc_instantiate(HVC_COOKIE, 0, ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) console_initcall(xen_cons_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) #ifdef CONFIG_X86
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) static void xen_hvm_early_write(uint32_t vtermno, const char *str, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) if (xen_cpuid_base())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) outsb(0xe9, str, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) static void xen_hvm_early_write(uint32_t vtermno, const char *str, int len) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) #ifdef CONFIG_EARLY_PRINTK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) static int __init xenboot_console_setup(struct console *console, char *string)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) static struct xencons_info xenboot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) if (xen_initial_domain())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) if (!xen_pv_domain())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) return xencons_info_pv_init(&xenboot, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) static void xenboot_write_console(struct console *console, const char *string,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) unsigned len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) unsigned int linelen, off = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) const char *pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) if (!xen_pv_domain()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) xen_hvm_early_write(0, string, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) dom0_write_console(0, string, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) if (xen_initial_domain())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) domU_write_console(0, "(early) ", 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) linelen = pos-string+off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) if (off + linelen > len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) domU_write_console(0, string+off, linelen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) domU_write_console(0, "\r\n", 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) off += linelen + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) if (off < len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) domU_write_console(0, string+off, len-off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) struct console xenboot_console = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) .name = "xenboot",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) .write = xenboot_write_console,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) .setup = xenboot_console_setup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) .flags = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) .index = -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) #endif /* CONFIG_EARLY_PRINTK */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) void xen_raw_console_write(const char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) ssize_t len = strlen(str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) int rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) if (xen_domain()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) rc = dom0_write_console(0, str, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) if (rc != -ENOSYS || !xen_hvm_domain())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) xen_hvm_early_write(0, str, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) void xen_raw_printk(const char *fmt, ...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) static char buf[512];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) va_list ap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) va_start(ap, fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) vsnprintf(buf, sizeof(buf), fmt, ap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) va_end(ap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) xen_raw_console_write(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) static void xenboot_earlycon_write(struct console *console,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) const char *string,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) unsigned len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) dom0_write_console(0, string, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) static int __init xenboot_earlycon_setup(struct earlycon_device *device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) const char *opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) device->con->write = xenboot_earlycon_write;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) EARLYCON_DECLARE(xenboot, xenboot_earlycon_setup);