]>
Commit | Line | Data |
---|---|---|
04b0de0e WL |
1 | /* |
2 | * Copyright (C) 2014 Citrix Systems UK Ltd. | |
3 | * | |
4 | * This work is licensed under the terms of the GNU GPL, version 2. See | |
5 | * the COPYING file in the top-level directory. | |
6 | * | |
7 | * Contributions after 2012-01-13 are licensed under the terms of the | |
8 | * GNU GPL, version 2 or (at your option) any later version. | |
9 | */ | |
10 | ||
21cbfe5f | 11 | #include "qemu/osdep.h" |
47d17c0a | 12 | #include "qemu/error-report.h" |
0b8fa32f | 13 | #include "qemu/module.h" |
46472d82 | 14 | #include "qapi/error.h" |
2d0ed5e6 | 15 | #include "hw/xen/xen-legacy-backend.h" |
46472d82 | 16 | #include "hw/xen/xen_pt.h" |
8228e353 | 17 | #include "chardev/char.h" |
b152b05a | 18 | #include "sysemu/accel.h" |
da278d58 | 19 | #include "sysemu/xen.h" |
54d31236 | 20 | #include "sysemu/runstate.h" |
c4b63b7c | 21 | #include "migration/misc.h" |
84a899de | 22 | #include "migration/global_state.h" |
0dc0389f | 23 | #include "hw/boards.h" |
04b0de0e WL |
24 | |
25 | //#define DEBUG_XEN | |
26 | ||
27 | #ifdef DEBUG_XEN | |
28 | #define DPRINTF(fmt, ...) \ | |
29 | do { fprintf(stderr, "xen: " fmt, ## __VA_ARGS__); } while (0) | |
30 | #else | |
31 | #define DPRINTF(fmt, ...) \ | |
32 | do { } while (0) | |
33 | #endif | |
34 | ||
8e0ef068 | 35 | bool xen_allowed; |
da278d58 | 36 | |
260cabed PD |
37 | xc_interface *xen_xc; |
38 | xenforeignmemory_handle *xen_fmem; | |
d655f34e | 39 | xendevicemodel_handle *xen_dmod; |
260cabed | 40 | |
0ec7b3e7 | 41 | static int store_dev_info(int domid, Chardev *cs, const char *string) |
04b0de0e WL |
42 | { |
43 | struct xs_handle *xs = NULL; | |
44 | char *path = NULL; | |
45 | char *newpath = NULL; | |
46 | char *pts = NULL; | |
47 | int ret = -1; | |
48 | ||
49 | /* Only continue if we're talking to a pty. */ | |
315dd72d | 50 | if (!CHARDEV_IS_PTY(cs)) { |
04b0de0e WL |
51 | return 0; |
52 | } | |
53 | pts = cs->filename + 4; | |
54 | ||
55 | /* We now have everything we need to set the xenstore entry. */ | |
56 | xs = xs_open(0); | |
57 | if (xs == NULL) { | |
58 | fprintf(stderr, "Could not contact XenStore\n"); | |
59 | goto out; | |
60 | } | |
61 | ||
62 | path = xs_get_domain_path(xs, domid); | |
63 | if (path == NULL) { | |
64 | fprintf(stderr, "xs_get_domain_path() error\n"); | |
65 | goto out; | |
66 | } | |
67 | newpath = realloc(path, (strlen(path) + strlen(string) + | |
68 | strlen("/tty") + 1)); | |
69 | if (newpath == NULL) { | |
70 | fprintf(stderr, "realloc error\n"); | |
71 | goto out; | |
72 | } | |
73 | path = newpath; | |
74 | ||
75 | strcat(path, string); | |
76 | strcat(path, "/tty"); | |
77 | if (!xs_write(xs, XBT_NULL, path, pts, strlen(pts))) { | |
78 | fprintf(stderr, "xs_write for '%s' fail", string); | |
79 | goto out; | |
80 | } | |
81 | ret = 0; | |
82 | ||
83 | out: | |
84 | free(path); | |
85 | xs_close(xs); | |
86 | ||
87 | return ret; | |
88 | } | |
89 | ||
0ec7b3e7 | 90 | void xenstore_store_pv_console_info(int i, Chardev *chr) |
04b0de0e WL |
91 | { |
92 | if (i == 0) { | |
93 | store_dev_info(xen_domid, chr, "/console"); | |
94 | } else { | |
95 | char buf[32]; | |
96 | snprintf(buf, sizeof(buf), "/device/console/%d", i); | |
97 | store_dev_info(xen_domid, chr, buf); | |
98 | } | |
99 | } | |
100 | ||
101 | ||
102 | static void xenstore_record_dm_state(struct xs_handle *xs, const char *state) | |
103 | { | |
104 | char path[50]; | |
105 | ||
106 | if (xs == NULL) { | |
47d17c0a | 107 | error_report("xenstore connection not initialized"); |
04b0de0e WL |
108 | exit(1); |
109 | } | |
110 | ||
111 | snprintf(path, sizeof (path), "device-model/%u/state", xen_domid); | |
4473348a RL |
112 | /* |
113 | * This call may fail when running restricted so don't make it fatal in | |
114 | * that case. Toolstacks should instead use QMP to listen for state changes. | |
115 | */ | |
116 | if (!xs_write(xs, XBT_NULL, path, state, strlen(state)) && | |
117 | !xen_domid_restrict) { | |
47d17c0a | 118 | error_report("error recording dm state"); |
04b0de0e WL |
119 | exit(1); |
120 | } | |
121 | } | |
122 | ||
123 | ||
124 | static void xen_change_state_handler(void *opaque, int running, | |
125 | RunState state) | |
126 | { | |
127 | if (running) { | |
128 | /* record state running */ | |
129 | xenstore_record_dm_state(xenstore, "running"); | |
130 | } | |
131 | } | |
132 | ||
46472d82 PB |
133 | static bool xen_get_igd_gfx_passthru(Object *obj, Error **errp) |
134 | { | |
acd0c941 | 135 | return xen_igd_gfx_pt_enabled(); |
46472d82 PB |
136 | } |
137 | ||
138 | static void xen_set_igd_gfx_passthru(Object *obj, bool value, Error **errp) | |
139 | { | |
acd0c941 | 140 | xen_igd_gfx_pt_set(value, errp); |
46472d82 PB |
141 | } |
142 | ||
4564e63f IJ |
143 | static void xen_setup_post(MachineState *ms, AccelState *accel) |
144 | { | |
145 | int rc; | |
146 | ||
147 | if (xen_domid_restrict) { | |
148 | rc = xen_restrict(xen_domid); | |
149 | if (rc < 0) { | |
150 | perror("xen: failed to restrict"); | |
151 | exit(1); | |
152 | } | |
153 | } | |
154 | } | |
155 | ||
f6a1ef64 | 156 | static int xen_init(MachineState *ms) |
04b0de0e | 157 | { |
0dc0389f IM |
158 | MachineClass *mc = MACHINE_GET_CLASS(ms); |
159 | ||
81daba58 IC |
160 | xen_xc = xc_interface_open(0, 0, 0); |
161 | if (xen_xc == NULL) { | |
96c77dba | 162 | xen_pv_printf(NULL, 0, "can't open xen interface\n"); |
04b0de0e WL |
163 | return -1; |
164 | } | |
e0cb42ae IC |
165 | xen_fmem = xenforeignmemory_open(0, 0); |
166 | if (xen_fmem == NULL) { | |
96c77dba | 167 | xen_pv_printf(NULL, 0, "can't open xen fmem interface\n"); |
e0cb42ae IC |
168 | xc_interface_close(xen_xc); |
169 | return -1; | |
170 | } | |
d655f34e PD |
171 | xen_dmod = xendevicemodel_open(0, 0); |
172 | if (xen_dmod == NULL) { | |
173 | xen_pv_printf(NULL, 0, "can't open xen devicemodel interface\n"); | |
174 | xenforeignmemory_close(xen_fmem); | |
175 | xc_interface_close(xen_xc); | |
176 | return -1; | |
177 | } | |
04b0de0e | 178 | qemu_add_vm_change_state_handler(xen_change_state_handler, NULL); |
0dc0389f IM |
179 | /* |
180 | * opt out of system RAM being allocated by generic code | |
181 | */ | |
182 | mc->default_ram_id = NULL; | |
04b0de0e WL |
183 | return 0; |
184 | } | |
185 | ||
b152b05a EH |
186 | static void xen_accel_class_init(ObjectClass *oc, void *data) |
187 | { | |
188 | AccelClass *ac = ACCEL_CLASS(oc); | |
88cbe073 | 189 | static GlobalProperty compat[] = { |
6c36bddf EH |
190 | { "migration", "store-global-state", "off" }, |
191 | { "migration", "send-configuration", "off" }, | |
192 | { "migration", "send-section-footer", "off" }, | |
88cbe073 | 193 | }; |
ea9ce893 | 194 | |
b152b05a | 195 | ac->name = "Xen"; |
0d15da8e | 196 | ac->init_machine = xen_init; |
4564e63f | 197 | ac->setup_post = xen_setup_post; |
b152b05a | 198 | ac->allowed = &xen_allowed; |
ea9ce893 MAL |
199 | ac->compat_props = g_ptr_array_new(); |
200 | ||
88cbe073 | 201 | compat_props_add(ac->compat_props, compat, G_N_ELEMENTS(compat)); |
46472d82 PB |
202 | |
203 | object_class_property_add_bool(oc, "igd-passthru", | |
d2623129 | 204 | xen_get_igd_gfx_passthru, xen_set_igd_gfx_passthru); |
46472d82 | 205 | object_class_property_set_description(oc, "igd-passthru", |
7eecec7d | 206 | "Set on/off to enable/disable igd passthrou"); |
b152b05a EH |
207 | } |
208 | ||
209 | #define TYPE_XEN_ACCEL ACCEL_CLASS_NAME("xen") | |
210 | ||
211 | static const TypeInfo xen_accel_type = { | |
212 | .name = TYPE_XEN_ACCEL, | |
213 | .parent = TYPE_ACCEL, | |
214 | .class_init = xen_accel_class_init, | |
215 | }; | |
216 | ||
217 | static void xen_type_init(void) | |
218 | { | |
219 | type_register_static(&xen_accel_type); | |
220 | } | |
221 | ||
222 | type_init(xen_type_init); |