xref: /openbmc/qemu/hw/i386/kvm/xen_primary_console.c (revision a72ccc7f)
1*a72ccc7fSDavid Woodhouse /*
2*a72ccc7fSDavid Woodhouse  * QEMU Xen emulation: Primary console support
3*a72ccc7fSDavid Woodhouse  *
4*a72ccc7fSDavid Woodhouse  * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5*a72ccc7fSDavid Woodhouse  *
6*a72ccc7fSDavid Woodhouse  * Authors: David Woodhouse <dwmw2@infradead.org>
7*a72ccc7fSDavid Woodhouse  *
8*a72ccc7fSDavid Woodhouse  * This work is licensed under the terms of the GNU GPL, version 2 or later.
9*a72ccc7fSDavid Woodhouse  * See the COPYING file in the top-level directory.
10*a72ccc7fSDavid Woodhouse  */
11*a72ccc7fSDavid Woodhouse 
12*a72ccc7fSDavid Woodhouse #include "qemu/osdep.h"
13*a72ccc7fSDavid Woodhouse 
14*a72ccc7fSDavid Woodhouse #include "qapi/error.h"
15*a72ccc7fSDavid Woodhouse 
16*a72ccc7fSDavid Woodhouse #include "hw/sysbus.h"
17*a72ccc7fSDavid Woodhouse #include "hw/xen/xen.h"
18*a72ccc7fSDavid Woodhouse #include "hw/xen/xen_backend_ops.h"
19*a72ccc7fSDavid Woodhouse #include "xen_evtchn.h"
20*a72ccc7fSDavid Woodhouse #include "xen_overlay.h"
21*a72ccc7fSDavid Woodhouse #include "xen_primary_console.h"
22*a72ccc7fSDavid Woodhouse 
23*a72ccc7fSDavid Woodhouse #include "sysemu/kvm.h"
24*a72ccc7fSDavid Woodhouse #include "sysemu/kvm_xen.h"
25*a72ccc7fSDavid Woodhouse 
26*a72ccc7fSDavid Woodhouse #include "trace.h"
27*a72ccc7fSDavid Woodhouse 
28*a72ccc7fSDavid Woodhouse #include "hw/xen/interface/event_channel.h"
29*a72ccc7fSDavid Woodhouse #include "hw/xen/interface/grant_table.h"
30*a72ccc7fSDavid Woodhouse 
31*a72ccc7fSDavid Woodhouse #define TYPE_XEN_PRIMARY_CONSOLE "xen-primary-console"
32*a72ccc7fSDavid Woodhouse OBJECT_DECLARE_SIMPLE_TYPE(XenPrimaryConsoleState, XEN_PRIMARY_CONSOLE)
33*a72ccc7fSDavid Woodhouse 
34*a72ccc7fSDavid Woodhouse struct XenPrimaryConsoleState {
35*a72ccc7fSDavid Woodhouse     /*< private >*/
36*a72ccc7fSDavid Woodhouse     SysBusDevice busdev;
37*a72ccc7fSDavid Woodhouse     /*< public >*/
38*a72ccc7fSDavid Woodhouse 
39*a72ccc7fSDavid Woodhouse     MemoryRegion console_page;
40*a72ccc7fSDavid Woodhouse     void *cp;
41*a72ccc7fSDavid Woodhouse 
42*a72ccc7fSDavid Woodhouse     evtchn_port_t guest_port;
43*a72ccc7fSDavid Woodhouse     evtchn_port_t be_port;
44*a72ccc7fSDavid Woodhouse 
45*a72ccc7fSDavid Woodhouse     struct xengntdev_handle *gt;
46*a72ccc7fSDavid Woodhouse     void *granted_xs;
47*a72ccc7fSDavid Woodhouse };
48*a72ccc7fSDavid Woodhouse 
49*a72ccc7fSDavid Woodhouse struct XenPrimaryConsoleState *xen_primary_console_singleton;
50*a72ccc7fSDavid Woodhouse 
xen_primary_console_realize(DeviceState * dev,Error ** errp)51*a72ccc7fSDavid Woodhouse static void xen_primary_console_realize(DeviceState *dev, Error **errp)
52*a72ccc7fSDavid Woodhouse {
53*a72ccc7fSDavid Woodhouse     XenPrimaryConsoleState *s = XEN_PRIMARY_CONSOLE(dev);
54*a72ccc7fSDavid Woodhouse 
55*a72ccc7fSDavid Woodhouse     if (xen_mode != XEN_EMULATE) {
56*a72ccc7fSDavid Woodhouse         error_setg(errp, "Xen primary console support is for Xen emulation");
57*a72ccc7fSDavid Woodhouse         return;
58*a72ccc7fSDavid Woodhouse     }
59*a72ccc7fSDavid Woodhouse 
60*a72ccc7fSDavid Woodhouse     memory_region_init_ram(&s->console_page, OBJECT(dev), "xen:console_page",
61*a72ccc7fSDavid Woodhouse                            XEN_PAGE_SIZE, &error_abort);
62*a72ccc7fSDavid Woodhouse     memory_region_set_enabled(&s->console_page, true);
63*a72ccc7fSDavid Woodhouse     s->cp = memory_region_get_ram_ptr(&s->console_page);
64*a72ccc7fSDavid Woodhouse     memset(s->cp, 0, XEN_PAGE_SIZE);
65*a72ccc7fSDavid Woodhouse 
66*a72ccc7fSDavid Woodhouse     /* We can't map it this early as KVM isn't ready */
67*a72ccc7fSDavid Woodhouse     xen_primary_console_singleton = s;
68*a72ccc7fSDavid Woodhouse }
69*a72ccc7fSDavid Woodhouse 
xen_primary_console_class_init(ObjectClass * klass,void * data)70*a72ccc7fSDavid Woodhouse static void xen_primary_console_class_init(ObjectClass *klass, void *data)
71*a72ccc7fSDavid Woodhouse {
72*a72ccc7fSDavid Woodhouse     DeviceClass *dc = DEVICE_CLASS(klass);
73*a72ccc7fSDavid Woodhouse 
74*a72ccc7fSDavid Woodhouse     dc->realize = xen_primary_console_realize;
75*a72ccc7fSDavid Woodhouse }
76*a72ccc7fSDavid Woodhouse 
77*a72ccc7fSDavid Woodhouse static const TypeInfo xen_primary_console_info = {
78*a72ccc7fSDavid Woodhouse     .name          = TYPE_XEN_PRIMARY_CONSOLE,
79*a72ccc7fSDavid Woodhouse     .parent        = TYPE_SYS_BUS_DEVICE,
80*a72ccc7fSDavid Woodhouse     .instance_size = sizeof(XenPrimaryConsoleState),
81*a72ccc7fSDavid Woodhouse     .class_init    = xen_primary_console_class_init,
82*a72ccc7fSDavid Woodhouse };
83*a72ccc7fSDavid Woodhouse 
84*a72ccc7fSDavid Woodhouse 
xen_primary_console_create(void)85*a72ccc7fSDavid Woodhouse void xen_primary_console_create(void)
86*a72ccc7fSDavid Woodhouse {
87*a72ccc7fSDavid Woodhouse     DeviceState *dev = sysbus_create_simple(TYPE_XEN_PRIMARY_CONSOLE, -1, NULL);
88*a72ccc7fSDavid Woodhouse 
89*a72ccc7fSDavid Woodhouse     trace_xen_primary_console_create();
90*a72ccc7fSDavid Woodhouse 
91*a72ccc7fSDavid Woodhouse     xen_primary_console_singleton = XEN_PRIMARY_CONSOLE(dev);
92*a72ccc7fSDavid Woodhouse 
93*a72ccc7fSDavid Woodhouse     /*
94*a72ccc7fSDavid Woodhouse      * Defer the init (xen_primary_console_reset()) until KVM is set up and the
95*a72ccc7fSDavid Woodhouse      * overlay page can be mapped.
96*a72ccc7fSDavid Woodhouse      */
97*a72ccc7fSDavid Woodhouse }
98*a72ccc7fSDavid Woodhouse 
xen_primary_console_register_types(void)99*a72ccc7fSDavid Woodhouse static void xen_primary_console_register_types(void)
100*a72ccc7fSDavid Woodhouse {
101*a72ccc7fSDavid Woodhouse     type_register_static(&xen_primary_console_info);
102*a72ccc7fSDavid Woodhouse }
103*a72ccc7fSDavid Woodhouse 
type_init(xen_primary_console_register_types)104*a72ccc7fSDavid Woodhouse type_init(xen_primary_console_register_types)
105*a72ccc7fSDavid Woodhouse 
106*a72ccc7fSDavid Woodhouse uint16_t xen_primary_console_get_port(void)
107*a72ccc7fSDavid Woodhouse {
108*a72ccc7fSDavid Woodhouse     XenPrimaryConsoleState *s = xen_primary_console_singleton;
109*a72ccc7fSDavid Woodhouse     if (!s) {
110*a72ccc7fSDavid Woodhouse         return 0;
111*a72ccc7fSDavid Woodhouse     }
112*a72ccc7fSDavid Woodhouse     return s->guest_port;
113*a72ccc7fSDavid Woodhouse }
114*a72ccc7fSDavid Woodhouse 
xen_primary_console_set_be_port(uint16_t port)115*a72ccc7fSDavid Woodhouse void xen_primary_console_set_be_port(uint16_t port)
116*a72ccc7fSDavid Woodhouse {
117*a72ccc7fSDavid Woodhouse     XenPrimaryConsoleState *s = xen_primary_console_singleton;
118*a72ccc7fSDavid Woodhouse     if (s) {
119*a72ccc7fSDavid Woodhouse         s->be_port = port;
120*a72ccc7fSDavid Woodhouse     }
121*a72ccc7fSDavid Woodhouse }
122*a72ccc7fSDavid Woodhouse 
xen_primary_console_get_pfn(void)123*a72ccc7fSDavid Woodhouse uint64_t xen_primary_console_get_pfn(void)
124*a72ccc7fSDavid Woodhouse {
125*a72ccc7fSDavid Woodhouse     XenPrimaryConsoleState *s = xen_primary_console_singleton;
126*a72ccc7fSDavid Woodhouse     if (!s) {
127*a72ccc7fSDavid Woodhouse         return 0;
128*a72ccc7fSDavid Woodhouse     }
129*a72ccc7fSDavid Woodhouse     return XEN_SPECIAL_PFN(CONSOLE);
130*a72ccc7fSDavid Woodhouse }
131*a72ccc7fSDavid Woodhouse 
xen_primary_console_get_map(void)132*a72ccc7fSDavid Woodhouse void *xen_primary_console_get_map(void)
133*a72ccc7fSDavid Woodhouse {
134*a72ccc7fSDavid Woodhouse     XenPrimaryConsoleState *s = xen_primary_console_singleton;
135*a72ccc7fSDavid Woodhouse     if (!s) {
136*a72ccc7fSDavid Woodhouse         return 0;
137*a72ccc7fSDavid Woodhouse     }
138*a72ccc7fSDavid Woodhouse     return s->cp;
139*a72ccc7fSDavid Woodhouse }
140*a72ccc7fSDavid Woodhouse 
alloc_guest_port(XenPrimaryConsoleState * s)141*a72ccc7fSDavid Woodhouse static void alloc_guest_port(XenPrimaryConsoleState *s)
142*a72ccc7fSDavid Woodhouse {
143*a72ccc7fSDavid Woodhouse     struct evtchn_alloc_unbound alloc = {
144*a72ccc7fSDavid Woodhouse         .dom = DOMID_SELF,
145*a72ccc7fSDavid Woodhouse         .remote_dom = DOMID_QEMU,
146*a72ccc7fSDavid Woodhouse     };
147*a72ccc7fSDavid Woodhouse 
148*a72ccc7fSDavid Woodhouse     if (!xen_evtchn_alloc_unbound_op(&alloc)) {
149*a72ccc7fSDavid Woodhouse         s->guest_port = alloc.port;
150*a72ccc7fSDavid Woodhouse     }
151*a72ccc7fSDavid Woodhouse }
152*a72ccc7fSDavid Woodhouse 
rebind_guest_port(XenPrimaryConsoleState * s)153*a72ccc7fSDavid Woodhouse static void rebind_guest_port(XenPrimaryConsoleState *s)
154*a72ccc7fSDavid Woodhouse {
155*a72ccc7fSDavid Woodhouse     struct evtchn_bind_interdomain inter = {
156*a72ccc7fSDavid Woodhouse         .remote_dom = DOMID_QEMU,
157*a72ccc7fSDavid Woodhouse         .remote_port = s->be_port,
158*a72ccc7fSDavid Woodhouse     };
159*a72ccc7fSDavid Woodhouse 
160*a72ccc7fSDavid Woodhouse     if (!xen_evtchn_bind_interdomain_op(&inter)) {
161*a72ccc7fSDavid Woodhouse         s->guest_port = inter.local_port;
162*a72ccc7fSDavid Woodhouse     }
163*a72ccc7fSDavid Woodhouse 
164*a72ccc7fSDavid Woodhouse     s->be_port = 0;
165*a72ccc7fSDavid Woodhouse }
166*a72ccc7fSDavid Woodhouse 
xen_primary_console_reset(void)167*a72ccc7fSDavid Woodhouse int xen_primary_console_reset(void)
168*a72ccc7fSDavid Woodhouse {
169*a72ccc7fSDavid Woodhouse     XenPrimaryConsoleState *s = xen_primary_console_singleton;
170*a72ccc7fSDavid Woodhouse     if (!s) {
171*a72ccc7fSDavid Woodhouse         return 0;
172*a72ccc7fSDavid Woodhouse     }
173*a72ccc7fSDavid Woodhouse 
174*a72ccc7fSDavid Woodhouse     if (!memory_region_is_mapped(&s->console_page)) {
175*a72ccc7fSDavid Woodhouse         uint64_t gpa = XEN_SPECIAL_PFN(CONSOLE) << TARGET_PAGE_BITS;
176*a72ccc7fSDavid Woodhouse         xen_overlay_do_map_page(&s->console_page, gpa);
177*a72ccc7fSDavid Woodhouse     }
178*a72ccc7fSDavid Woodhouse 
179*a72ccc7fSDavid Woodhouse     if (s->be_port) {
180*a72ccc7fSDavid Woodhouse         rebind_guest_port(s);
181*a72ccc7fSDavid Woodhouse     } else {
182*a72ccc7fSDavid Woodhouse         alloc_guest_port(s);
183*a72ccc7fSDavid Woodhouse     }
184*a72ccc7fSDavid Woodhouse 
185*a72ccc7fSDavid Woodhouse     trace_xen_primary_console_reset(s->guest_port);
186*a72ccc7fSDavid Woodhouse 
187*a72ccc7fSDavid Woodhouse     s->gt = qemu_xen_gnttab_open();
188*a72ccc7fSDavid Woodhouse     uint32_t xs_gntref = GNTTAB_RESERVED_CONSOLE;
189*a72ccc7fSDavid Woodhouse     s->granted_xs = qemu_xen_gnttab_map_refs(s->gt, 1, xen_domid, &xs_gntref,
190*a72ccc7fSDavid Woodhouse                                              PROT_READ | PROT_WRITE);
191*a72ccc7fSDavid Woodhouse 
192*a72ccc7fSDavid Woodhouse     return 0;
193*a72ccc7fSDavid Woodhouse }
194