- Update Xen patches to 3.3-rc5 and c/s 1157.
[linux-flexiantxendom0-3.2.10.git] / drivers / xen / core / domctl.c
1 /*
2  * !!!  dirty hack alert  !!!
3  *
4  * Problem: old guests kernels don't have a "protocol" node
5  *          in the frontend xenstore directory, so mixing
6  *          32 and 64bit domains doesn't work.
7  *
8  * Upstream plans to solve this in the tools, by letting them
9  * create a protocol node.  Which certainly makes sense.
10  * But it isn't trivial and isn't done yet.  Too bad.
11  *
12  * So for the time being we use the get_address_size domctl
13  * hypercall for a pretty good guess.  Not nice as the domctl
14  * hypercall isn't supposed to be used by the kernel.  Because
15  * we don't want to have dependencies between dom0 kernel and
16  * xen kernel versions.  Now we have one.  Ouch.
17  */
18 #undef __XEN_PUBLIC_XEN_H__
19 #undef __XEN_PUBLIC_GRANT_TABLE_H__
20 #undef __XEN_TOOLS__
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/slab.h>
24 #include <linux/percpu.h>
25 #include <asm/hypervisor.h>
26 #include <xen/blkif.h>
27
28 #include "domctl.h"
29
30 /* stuff copied from xen/interface/domctl.h, which we can't
31  * include directly for the reasons outlined above .... */
32
33 typedef struct xen_domctl_address_size {
34         uint32_t size;
35 } xen_domctl_address_size_t;
36
37 typedef __attribute__((aligned(8))) uint64_t uint64_aligned_t;
38
39 struct xenctl_cpumap_v4 {
40         XEN_GUEST_HANDLE(uint8) bitmap;
41         uint32_t nr_cpus;
42 };
43
44 struct xenctl_cpumap_v5 {
45         union {
46                 XEN_GUEST_HANDLE(uint8) bitmap;
47                 uint64_aligned_t _align;
48         };
49         uint32_t nr_cpus;
50 };
51
52 struct xen_domctl_vcpuaffinity_v4 {
53     uint32_t vcpu;
54     struct xenctl_cpumap_v4 cpumap;
55 };
56
57 struct xen_domctl_vcpuaffinity_v5 {
58     uint32_t vcpu;
59     struct xenctl_cpumap_v5 cpumap;
60 };
61
62 union xen_domctl {
63         /* v4: sle10 sp1: xen 3.0.4 + 32-on-64 patches */
64         struct {
65                 uint32_t cmd;
66                 uint32_t interface_version;
67                 domid_t  domain;
68                 union {
69                         /* left out lots of other struct xen_domctl_foobar */
70                         struct xen_domctl_address_size       address_size;
71                         struct xen_domctl_vcpuaffinity_v4    vcpu_affinity;
72                         uint64_t                             dummy_align;
73                         uint8_t                              dummy_pad[128];
74                 };
75         } v4;
76
77         /*
78          * v5: upstream: xen 3.1
79          * v6: upstream: xen 4.0
80          * v7: upstream: xen 4.1; sle11 sp1: xen 4.0 + cpupools patches
81          * v8: upstream: xen 4.2
82          */
83         struct {
84                 uint32_t cmd;
85                 uint32_t interface_version;
86                 domid_t  domain;
87                 union {
88                         struct xen_domctl_address_size       address_size;
89                         struct xen_domctl_vcpuaffinity_v5    vcpu_affinity;
90                         uint64_aligned_t                     dummy_align;
91                         uint8_t                              dummy_pad[128];
92                 };
93         } v5, v6, v7, v8;
94 };
95
96 struct xen_sysctl_physinfo_v6 {
97         uint32_t threads_per_core;
98         uint32_t cores_per_socket;
99         uint32_t nr_cpus;
100         uint32_t nr_nodes;
101         uint32_t cpu_khz;
102         uint64_aligned_t total_pages;
103         uint64_aligned_t free_pages;
104         uint64_aligned_t scrub_pages;
105         uint32_t hw_cap[8];
106         uint32_t max_cpu_id;
107         union {
108                 XEN_GUEST_HANDLE(uint32) cpu_to_node;
109                 uint64_aligned_t _ctn_align;
110         };
111         uint32_t capabilities;
112 };
113
114 struct xen_sysctl_physinfo_v7 {
115         uint32_t threads_per_core;
116         uint32_t cores_per_socket;
117         uint32_t nr_cpus;
118         uint32_t max_node_id;
119         uint32_t cpu_khz;
120         uint64_aligned_t total_pages;
121         uint64_aligned_t free_pages;
122         uint64_aligned_t scrub_pages;
123         uint32_t hw_cap[8];
124         uint32_t max_cpu_id;
125         union {
126                 XEN_GUEST_HANDLE(uint32) cpu_to_node;
127                 uint64_aligned_t _ctn_align;
128         };
129         uint32_t capabilities;
130 };
131
132 #define XEN_SYSCTL_pm_op_get_cputopo 0x20
133 struct xen_get_cputopo_v6 {
134         uint32_t max_cpus;
135         union {
136                 XEN_GUEST_HANDLE(uint32) cpu_to_core;
137                 uint64_aligned_t _ctc_align;
138         };
139         union {
140                 XEN_GUEST_HANDLE(uint32) cpu_to_socket;
141                 uint64_aligned_t _cts_align;
142         };
143         uint32_t nr_cpus;
144 };
145
146 struct xen_sysctl_pm_op_v6 {
147         uint32_t cmd;
148         uint32_t cpuid;
149         union {
150                 struct xen_get_cputopo_v6 get_topo;
151         };
152 };
153 #define xen_sysctl_pm_op_v7 xen_sysctl_pm_op_v6
154
155 struct xen_sysctl_topologyinfo_v8 {
156         uint32_t max_cpu_index;
157         union {
158                 XEN_GUEST_HANDLE(uint32) cpu_to_core;
159                 uint64_aligned_t _ctc_align;
160         };
161         union {
162                 XEN_GUEST_HANDLE(uint32) cpu_to_socket;
163                 uint64_aligned_t _cts_align;
164         };
165         union {
166                 XEN_GUEST_HANDLE(uint32) cpu_to_node;
167                 uint64_aligned_t _ctn_align;
168         };
169 };
170
171 union xen_sysctl {
172         /* v6: Xen 3.4.x */
173         struct {
174                 uint32_t cmd;
175                 uint32_t interface_version;
176                 union {
177                         struct xen_sysctl_physinfo_v6 physinfo;
178                         struct xen_sysctl_pm_op_v6 pm_op;
179                 };
180         } v6;
181         /* v7: Xen 4.0.x */
182         struct {
183                 uint32_t cmd;
184                 uint32_t interface_version;
185                 union {
186                         struct xen_sysctl_physinfo_v7 physinfo;
187                         struct xen_sysctl_pm_op_v7 pm_op;
188                 };
189         } v7;
190         /*
191          * v8: Xen 4.1.x
192          * v9: Xen 4.2+
193          */
194         struct {
195                 uint32_t cmd;
196                 uint32_t interface_version;
197                 union {
198                         struct xen_sysctl_topologyinfo_v8 topologyinfo;
199                 };
200         } v8, v9;
201 };
202
203 /* The actual code comes here */
204
205 static inline int hypervisor_domctl(void *domctl)
206 {
207         return _hypercall1(int, domctl, domctl);
208 }
209
210 static inline int hypervisor_sysctl(void *sysctl)
211 {
212         return _hypercall1(int, sysctl, sysctl);
213 }
214
215 int xen_guest_address_size(int domid)
216 {
217         union xen_domctl domctl;
218         int low, ret;
219
220 #define guest_address_size(ver) do {                                    \
221         memset(&domctl, 0, sizeof(domctl));                             \
222         domctl.v##ver.cmd = XEN_DOMCTL_get_address_size;                \
223         domctl.v##ver.interface_version = low = ver;                    \
224         domctl.v##ver.domain = domid;                                   \
225         ret = hypervisor_domctl(&domctl) ?: domctl.v##ver.address_size.size; \
226         if (ret == 32 || ret == 64) {                                   \
227                 pr_info("v" #ver " domctl worked ok: dom%d is %d-bit\n",\
228                         domid, ret);                                    \
229                 return ret;                                             \
230         }                                                               \
231 } while (0)
232
233         BUILD_BUG_ON(XEN_DOMCTL_INTERFACE_VERSION > 8);
234         guest_address_size(8);
235 #if CONFIG_XEN_COMPAT < 0x040200
236         guest_address_size(7);
237 #endif
238 #if CONFIG_XEN_COMPAT < 0x040100
239         guest_address_size(6);
240 #endif
241 #if CONFIG_XEN_COMPAT < 0x040000
242         guest_address_size(5);
243 #endif
244 #if CONFIG_XEN_COMPAT < 0x030100
245         guest_address_size(4);
246 #endif
247
248         ret = BITS_PER_LONG;
249         pr_warn("v%d...%d domctls failed, assuming dom%d is native: %d\n",
250                 low, XEN_DOMCTL_INTERFACE_VERSION, domid, ret);
251
252         return ret;
253 }
254 EXPORT_SYMBOL_GPL(xen_guest_address_size);
255
256 int xen_guest_blkif_protocol(int domid)
257 {
258         int address_size = xen_guest_address_size(domid);
259
260         if (address_size == BITS_PER_LONG)
261                 return BLKIF_PROTOCOL_NATIVE;
262         if (address_size == 32)
263                 return BLKIF_PROTOCOL_X86_32;
264         if (address_size == 64)
265                 return BLKIF_PROTOCOL_X86_64;
266         return BLKIF_PROTOCOL_NATIVE;
267 }
268 EXPORT_SYMBOL_GPL(xen_guest_blkif_protocol);
269
270 #ifdef CONFIG_X86
271
272 #define vcpuaffinity(what, ver) ({                                      \
273         memset(&domctl, 0, sizeof(domctl));                             \
274         domctl.v##ver.cmd = XEN_DOMCTL_##what##vcpuaffinity;            \
275         domctl.v##ver.interface_version = ver;                          \
276         /* domctl.v##ver.domain = 0; */                                 \
277         domctl.v##ver.vcpu_affinity.vcpu = smp_processor_id();          \
278         domctl.v##ver.vcpu_affinity.cpumap.nr_cpus = nr;                \
279         set_xen_guest_handle(domctl.v##ver.vcpu_affinity.cpumap.bitmap, \
280                              mask);                                     \
281         hypervisor_domctl(&domctl);                                     \
282 })
283
284 static inline int get_vcpuaffinity(unsigned int nr, void *mask)
285 {
286         union xen_domctl domctl;
287         int rc;
288
289         BUILD_BUG_ON(XEN_DOMCTL_INTERFACE_VERSION > 8);
290         rc = vcpuaffinity(get, 8);
291 #if CONFIG_XEN_COMPAT < 0x040200
292         if (rc)
293                 rc = vcpuaffinity(get, 7);
294 #endif
295 #if CONFIG_XEN_COMPAT < 0x040100
296         if (rc)
297                 rc = vcpuaffinity(get, 6);
298 #endif
299 #if CONFIG_XEN_COMPAT < 0x040000
300         if (rc)
301                 rc = vcpuaffinity(get, 5);
302 #endif
303 #if CONFIG_XEN_COMPAT < 0x030100
304         if (rc)
305                 rc = vcpuaffinity(get, 4);
306 #endif
307         return rc;
308 }
309
310 static inline int set_vcpuaffinity(unsigned int nr, void *mask)
311 {
312         union xen_domctl domctl;
313         int rc;
314
315         BUILD_BUG_ON(XEN_DOMCTL_INTERFACE_VERSION > 8);
316         rc = vcpuaffinity(set, 8);
317 #if CONFIG_XEN_COMPAT < 0x040200
318         if (rc)
319                 rc = vcpuaffinity(set, 7);
320 #endif
321 #if CONFIG_XEN_COMPAT < 0x040100
322         if (rc)
323                 rc = vcpuaffinity(set, 6);
324 #endif
325 #if CONFIG_XEN_COMPAT < 0x040000
326         if (rc)
327                 rc = vcpuaffinity(set, 5);
328 #endif
329 #if CONFIG_XEN_COMPAT < 0x030100
330         if (rc)
331                 rc = vcpuaffinity(set, 4);
332 #endif
333         return rc;
334 }
335
336 static DEFINE_PER_CPU(void *, saved_pcpu_affinity);
337
338 #define BITS_PER_PAGE (PAGE_SIZE * BITS_PER_LONG / sizeof(long))
339
340 int xen_set_physical_cpu_affinity(int pcpu)
341 {
342         int rc;
343
344         if (!is_initial_xendomain())
345                 return -EPERM;
346
347         if (pcpu >= 0) {
348                 void *oldmap;
349
350                 if (pcpu > BITS_PER_PAGE)
351                         return -ERANGE;
352
353                 if (percpu_read(saved_pcpu_affinity))
354                         return -EBUSY;
355
356                 oldmap = (void *)get_zeroed_page(GFP_KERNEL);
357                 if (!oldmap)
358                         return -ENOMEM;
359
360                 rc = get_vcpuaffinity(BITS_PER_PAGE, oldmap);
361                 if (!rc) {
362                         void *newmap = kcalloc(BITS_TO_LONGS(pcpu + 1),
363                                                sizeof(long), GFP_KERNEL);
364
365                         if (newmap) {
366                                 __set_bit(pcpu, newmap);
367                                 rc = set_vcpuaffinity(pcpu + 1, newmap);
368                                 kfree(newmap);
369                         } else
370                                 rc = -ENOMEM;
371                 }
372
373                 if (!rc)
374                         percpu_write(saved_pcpu_affinity, oldmap);
375                 else
376                         free_page((unsigned long)oldmap);
377         } else {
378                 if (!percpu_read(saved_pcpu_affinity))
379                         return 0;
380                 rc = set_vcpuaffinity(BITS_PER_PAGE,
381                                       percpu_read(saved_pcpu_affinity));
382                 free_page((unsigned long)percpu_read(saved_pcpu_affinity));
383                 percpu_write(saved_pcpu_affinity, NULL);
384         }
385
386         return rc;
387 }
388 EXPORT_SYMBOL_GPL(xen_set_physical_cpu_affinity);
389
390 int xen_get_topology_info(unsigned int cpu, u32 *core, u32 *sock, u32 *node)
391 {
392         union xen_sysctl sysctl;
393         uint32_t *cores = NULL, *socks = NULL, *nodes = NULL;
394         unsigned int nr;
395         int rc;
396
397         if (core)
398                 cores = kmalloc((cpu + 1) * sizeof(*cores), GFP_KERNEL);
399         if (sock)
400                 socks = kmalloc((cpu + 1) * sizeof(*socks), GFP_KERNEL);
401         if (node)
402                 nodes = kmalloc((cpu + 1) * sizeof(*nodes), GFP_KERNEL);
403         if ((core && !cores) || (sock && !socks) || (node && !nodes)) {
404                 kfree(cores);
405                 kfree(socks);
406                 kfree(nodes);
407                 return -ENOMEM;
408         }
409
410 #define topologyinfo(ver) do {                                          \
411         memset(&sysctl, 0, sizeof(sysctl));                             \
412         sysctl.v##ver.cmd = XEN_SYSCTL_topologyinfo;                    \
413         sysctl.v##ver.interface_version = ver;                          \
414         sysctl.v##ver.topologyinfo.max_cpu_index = cpu;                 \
415         set_xen_guest_handle(sysctl.v##ver.topologyinfo.cpu_to_core,    \
416                              cores);                                    \
417         set_xen_guest_handle(sysctl.v##ver.topologyinfo.cpu_to_socket,  \
418                              socks);                                    \
419         set_xen_guest_handle(sysctl.v##ver.topologyinfo.cpu_to_node,    \
420                              nodes);                                    \
421         rc = hypervisor_sysctl(&sysctl);                                \
422         nr = sysctl.v##ver.topologyinfo.max_cpu_index + 1;              \
423 } while (0)
424
425         BUILD_BUG_ON(XEN_SYSCTL_INTERFACE_VERSION > 9);
426         topologyinfo(9);
427 #if CONFIG_XEN_COMPAT < 0x040200
428         if (rc)
429                 topologyinfo(8);
430 #endif
431
432 #if CONFIG_XEN_COMPAT < 0x040100
433 #define pm_op_cputopo(ver) do {                                         \
434         memset(&sysctl, 0, sizeof(sysctl));                             \
435         sysctl.v##ver.cmd = XEN_SYSCTL_pm_op;                           \
436         sysctl.v##ver.interface_version = ver;                          \
437         sysctl.v##ver.pm_op.cmd = XEN_SYSCTL_pm_op_get_cputopo;         \
438         sysctl.v##ver.pm_op.cpuid = 0;                                  \
439         sysctl.v##ver.pm_op.get_topo.max_cpus = cpu + 1;                \
440         set_xen_guest_handle(sysctl.v##ver.pm_op.get_topo.cpu_to_core,  \
441                              cores);                                    \
442         set_xen_guest_handle(sysctl.v##ver.pm_op.get_topo.cpu_to_socket,\
443                              socks);                                    \
444         rc = hypervisor_sysctl(&sysctl);                                \
445         memset(&sysctl, 0, sizeof(sysctl));                             \
446         sysctl.v##ver.cmd = XEN_SYSCTL_physinfo;                        \
447         sysctl.v##ver.interface_version = ver;                          \
448         sysctl.v##ver.physinfo.max_cpu_id = cpu;                        \
449         set_xen_guest_handle(sysctl.v##ver.physinfo.cpu_to_node, nodes);\
450         rc = hypervisor_sysctl(&sysctl) ?: rc;                          \
451         nr = sysctl.v##ver.physinfo.max_cpu_id + 1;                     \
452 } while (0)
453
454         if (rc)
455                 pm_op_cputopo(7);
456 #endif
457 #if CONFIG_XEN_COMPAT < 0x040000
458         if (rc)
459                 pm_op_cputopo(6);
460 #endif
461
462         if (!rc && cpu >= nr)
463                 rc = -EDOM;
464
465         if (!rc && core && (*core = cores[cpu]) == INVALID_TOPOLOGY_ID)
466                 rc = -ENOENT;
467         kfree(cores);
468
469         if (!rc && sock && (*sock = socks[cpu]) == INVALID_TOPOLOGY_ID)
470                 rc = -ENOENT;
471         kfree(socks);
472
473         if (!rc && node && (*node = nodes[cpu]) == INVALID_TOPOLOGY_ID)
474                 rc = -ENOENT;
475         kfree(nodes);
476
477         return rc;
478 }
479 EXPORT_SYMBOL_GPL(xen_get_topology_info);
480
481 #include <xen/pcpu.h>
482 #include <asm/msr.h>
483
484 int rdmsr_safe_on_pcpu(unsigned int pcpu, u32 msr_no, u32 *l, u32 *h)
485 {
486         int err = xen_set_physical_cpu_affinity(pcpu);
487
488         switch (err) {
489         case 0:
490                 err = rdmsr_safe(msr_no, l, h);
491                 WARN_ON_ONCE(xen_set_physical_cpu_affinity(-1));
492                 break;
493         case -EINVAL:
494                 /* Fall back in case this is due to dom0_vcpus_pinned. */
495                 err = rdmsr_safe_on_cpu(pcpu, msr_no, l, h) ?: 1;
496                 break;
497         }
498
499         return err;
500 }
501 EXPORT_SYMBOL_GPL(rdmsr_safe_on_pcpu);
502
503 int wrmsr_safe_on_pcpu(unsigned int pcpu, u32 msr_no, u32 l, u32 h)
504 {
505         int err = xen_set_physical_cpu_affinity(pcpu);
506
507         switch (err) {
508         case 0:
509                 err = wrmsr_safe(msr_no, l, h);
510                 WARN_ON_ONCE(xen_set_physical_cpu_affinity(-1));
511                 break;
512         case -EINVAL:
513                 /* Fall back in case this is due to dom0_vcpus_pinned. */
514                 err = wrmsr_safe_on_cpu(pcpu, msr_no, l, h) ?: 1;
515                 break;
516         }
517
518         return err;
519 }
520 EXPORT_SYMBOL_GPL(wrmsr_safe_on_pcpu);
521
522 int rdmsr_safe_regs_on_pcpu(unsigned int pcpu, u32 *regs)
523 {
524         int err = xen_set_physical_cpu_affinity(pcpu);
525
526         switch (err) {
527         case 0:
528                 err = rdmsr_safe_regs(regs);
529                 WARN_ON_ONCE(xen_set_physical_cpu_affinity(-1));
530                 break;
531         case -EINVAL:
532                 /* Fall back in case this is due to dom0_vcpus_pinned. */
533                 err = rdmsr_safe_regs_on_cpu(pcpu, regs) ?: 1;
534                 break;
535         }
536
537         return err;
538 }
539 EXPORT_SYMBOL_GPL(rdmsr_safe_regs_on_pcpu);
540
541 int wrmsr_safe_regs_on_pcpu(unsigned int pcpu, u32 *regs)
542 {
543         int err = xen_set_physical_cpu_affinity(pcpu);
544
545         switch (err) {
546         case 0:
547                 err = wrmsr_safe_regs(regs);
548                 WARN_ON_ONCE(xen_set_physical_cpu_affinity(-1));
549                 break;
550         case -EINVAL:
551                 /* Fall back in case this is due to dom0_vcpus_pinned. */
552                 err = wrmsr_safe_regs_on_cpu(pcpu, regs) ?: 1;
553                 break;
554         }
555
556         return err;
557 }
558 EXPORT_SYMBOL_GPL(wrmsr_safe_regs_on_pcpu);
559
560 #endif /* CONFIG_X86 */
561
562 MODULE_LICENSE("GPL");