2 * !!! dirty hack alert !!!
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.
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.
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.
18 #undef __XEN_PUBLIC_XEN_H__
19 #undef __XEN_PUBLIC_GRANT_TABLE_H__
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>
30 /* stuff copied from xen/interface/domctl.h, which we can't
31 * include directly for the reasons outlined above .... */
33 typedef struct xen_domctl_address_size {
35 } xen_domctl_address_size_t;
37 typedef __attribute__((aligned(8))) uint64_t uint64_aligned_t;
39 struct xenctl_cpumap_v4 {
40 XEN_GUEST_HANDLE(uint8) bitmap;
44 struct xenctl_cpumap_v5 {
46 XEN_GUEST_HANDLE(uint8) bitmap;
47 uint64_aligned_t _align;
52 struct xen_domctl_vcpuaffinity_v4 {
54 struct xenctl_cpumap_v4 cpumap;
57 struct xen_domctl_vcpuaffinity_v5 {
59 struct xenctl_cpumap_v5 cpumap;
63 /* v4: sle10 sp1: xen 3.0.4 + 32-on-64 patches */
66 uint32_t interface_version;
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;
73 uint8_t dummy_pad[128];
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
85 uint32_t interface_version;
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];
96 struct xen_sysctl_physinfo_v6 {
97 uint32_t threads_per_core;
98 uint32_t cores_per_socket;
102 uint64_aligned_t total_pages;
103 uint64_aligned_t free_pages;
104 uint64_aligned_t scrub_pages;
108 XEN_GUEST_HANDLE(uint32) cpu_to_node;
109 uint64_aligned_t _ctn_align;
111 uint32_t capabilities;
114 struct xen_sysctl_physinfo_v7 {
115 uint32_t threads_per_core;
116 uint32_t cores_per_socket;
118 uint32_t max_node_id;
120 uint64_aligned_t total_pages;
121 uint64_aligned_t free_pages;
122 uint64_aligned_t scrub_pages;
126 XEN_GUEST_HANDLE(uint32) cpu_to_node;
127 uint64_aligned_t _ctn_align;
129 uint32_t capabilities;
132 #define XEN_SYSCTL_pm_op_get_cputopo 0x20
133 struct xen_get_cputopo_v6 {
136 XEN_GUEST_HANDLE(uint32) cpu_to_core;
137 uint64_aligned_t _ctc_align;
140 XEN_GUEST_HANDLE(uint32) cpu_to_socket;
141 uint64_aligned_t _cts_align;
146 struct xen_sysctl_pm_op_v6 {
150 struct xen_get_cputopo_v6 get_topo;
153 #define xen_sysctl_pm_op_v7 xen_sysctl_pm_op_v6
155 struct xen_sysctl_topologyinfo_v8 {
156 uint32_t max_cpu_index;
158 XEN_GUEST_HANDLE(uint32) cpu_to_core;
159 uint64_aligned_t _ctc_align;
162 XEN_GUEST_HANDLE(uint32) cpu_to_socket;
163 uint64_aligned_t _cts_align;
166 XEN_GUEST_HANDLE(uint32) cpu_to_node;
167 uint64_aligned_t _ctn_align;
175 uint32_t interface_version;
177 struct xen_sysctl_physinfo_v6 physinfo;
178 struct xen_sysctl_pm_op_v6 pm_op;
184 uint32_t interface_version;
186 struct xen_sysctl_physinfo_v7 physinfo;
187 struct xen_sysctl_pm_op_v7 pm_op;
196 uint32_t interface_version;
198 struct xen_sysctl_topologyinfo_v8 topologyinfo;
203 /* The actual code comes here */
205 static inline int hypervisor_domctl(void *domctl)
207 return _hypercall1(int, domctl, domctl);
210 static inline int hypervisor_sysctl(void *sysctl)
212 return _hypercall1(int, sysctl, sysctl);
215 int xen_guest_address_size(int domid)
217 union xen_domctl domctl;
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",\
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);
238 #if CONFIG_XEN_COMPAT < 0x040100
239 guest_address_size(6);
241 #if CONFIG_XEN_COMPAT < 0x040000
242 guest_address_size(5);
244 #if CONFIG_XEN_COMPAT < 0x030100
245 guest_address_size(4);
249 pr_warn("v%d...%d domctls failed, assuming dom%d is native: %d\n",
250 low, XEN_DOMCTL_INTERFACE_VERSION, domid, ret);
254 EXPORT_SYMBOL_GPL(xen_guest_address_size);
256 int xen_guest_blkif_protocol(int domid)
258 int address_size = xen_guest_address_size(domid);
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;
268 EXPORT_SYMBOL_GPL(xen_guest_blkif_protocol);
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, \
281 hypervisor_domctl(&domctl); \
284 static inline int get_vcpuaffinity(unsigned int nr, void *mask)
286 union xen_domctl domctl;
289 BUILD_BUG_ON(XEN_DOMCTL_INTERFACE_VERSION > 8);
290 rc = vcpuaffinity(get, 8);
291 #if CONFIG_XEN_COMPAT < 0x040200
293 rc = vcpuaffinity(get, 7);
295 #if CONFIG_XEN_COMPAT < 0x040100
297 rc = vcpuaffinity(get, 6);
299 #if CONFIG_XEN_COMPAT < 0x040000
301 rc = vcpuaffinity(get, 5);
303 #if CONFIG_XEN_COMPAT < 0x030100
305 rc = vcpuaffinity(get, 4);
310 static inline int set_vcpuaffinity(unsigned int nr, void *mask)
312 union xen_domctl domctl;
315 BUILD_BUG_ON(XEN_DOMCTL_INTERFACE_VERSION > 8);
316 rc = vcpuaffinity(set, 8);
317 #if CONFIG_XEN_COMPAT < 0x040200
319 rc = vcpuaffinity(set, 7);
321 #if CONFIG_XEN_COMPAT < 0x040100
323 rc = vcpuaffinity(set, 6);
325 #if CONFIG_XEN_COMPAT < 0x040000
327 rc = vcpuaffinity(set, 5);
329 #if CONFIG_XEN_COMPAT < 0x030100
331 rc = vcpuaffinity(set, 4);
336 static DEFINE_PER_CPU(void *, saved_pcpu_affinity);
338 #define BITS_PER_PAGE (PAGE_SIZE * BITS_PER_LONG / sizeof(long))
340 int xen_set_physical_cpu_affinity(int pcpu)
344 if (!is_initial_xendomain())
350 if (pcpu > BITS_PER_PAGE)
353 if (percpu_read(saved_pcpu_affinity))
356 oldmap = (void *)get_zeroed_page(GFP_KERNEL);
360 rc = get_vcpuaffinity(BITS_PER_PAGE, oldmap);
362 void *newmap = kcalloc(BITS_TO_LONGS(pcpu + 1),
363 sizeof(long), GFP_KERNEL);
366 __set_bit(pcpu, newmap);
367 rc = set_vcpuaffinity(pcpu + 1, newmap);
374 percpu_write(saved_pcpu_affinity, oldmap);
376 free_page((unsigned long)oldmap);
378 if (!percpu_read(saved_pcpu_affinity))
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);
388 EXPORT_SYMBOL_GPL(xen_set_physical_cpu_affinity);
390 int xen_get_topology_info(unsigned int cpu, u32 *core, u32 *sock, u32 *node)
392 union xen_sysctl sysctl;
393 uint32_t *cores = NULL, *socks = NULL, *nodes = NULL;
398 cores = kmalloc((cpu + 1) * sizeof(*cores), GFP_KERNEL);
400 socks = kmalloc((cpu + 1) * sizeof(*socks), GFP_KERNEL);
402 nodes = kmalloc((cpu + 1) * sizeof(*nodes), GFP_KERNEL);
403 if ((core && !cores) || (sock && !socks) || (node && !nodes)) {
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, \
417 set_xen_guest_handle(sysctl.v##ver.topologyinfo.cpu_to_socket, \
419 set_xen_guest_handle(sysctl.v##ver.topologyinfo.cpu_to_node, \
421 rc = hypervisor_sysctl(&sysctl); \
422 nr = sysctl.v##ver.topologyinfo.max_cpu_index + 1; \
425 BUILD_BUG_ON(XEN_SYSCTL_INTERFACE_VERSION > 9);
427 #if CONFIG_XEN_COMPAT < 0x040200
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, \
442 set_xen_guest_handle(sysctl.v##ver.pm_op.get_topo.cpu_to_socket,\
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; \
457 #if CONFIG_XEN_COMPAT < 0x040000
462 if (!rc && cpu >= nr)
465 if (!rc && core && (*core = cores[cpu]) == INVALID_TOPOLOGY_ID)
469 if (!rc && sock && (*sock = socks[cpu]) == INVALID_TOPOLOGY_ID)
473 if (!rc && node && (*node = nodes[cpu]) == INVALID_TOPOLOGY_ID)
479 EXPORT_SYMBOL_GPL(xen_get_topology_info);
481 #include <xen/pcpu.h>
484 int rdmsr_safe_on_pcpu(unsigned int pcpu, u32 msr_no, u32 *l, u32 *h)
486 int err = xen_set_physical_cpu_affinity(pcpu);
490 err = rdmsr_safe(msr_no, l, h);
491 WARN_ON_ONCE(xen_set_physical_cpu_affinity(-1));
494 /* Fall back in case this is due to dom0_vcpus_pinned. */
495 err = rdmsr_safe_on_cpu(pcpu, msr_no, l, h) ?: 1;
501 EXPORT_SYMBOL_GPL(rdmsr_safe_on_pcpu);
503 int wrmsr_safe_on_pcpu(unsigned int pcpu, u32 msr_no, u32 l, u32 h)
505 int err = xen_set_physical_cpu_affinity(pcpu);
509 err = wrmsr_safe(msr_no, l, h);
510 WARN_ON_ONCE(xen_set_physical_cpu_affinity(-1));
513 /* Fall back in case this is due to dom0_vcpus_pinned. */
514 err = wrmsr_safe_on_cpu(pcpu, msr_no, l, h) ?: 1;
520 EXPORT_SYMBOL_GPL(wrmsr_safe_on_pcpu);
522 int rdmsr_safe_regs_on_pcpu(unsigned int pcpu, u32 *regs)
524 int err = xen_set_physical_cpu_affinity(pcpu);
528 err = rdmsr_safe_regs(regs);
529 WARN_ON_ONCE(xen_set_physical_cpu_affinity(-1));
532 /* Fall back in case this is due to dom0_vcpus_pinned. */
533 err = rdmsr_safe_regs_on_cpu(pcpu, regs) ?: 1;
539 EXPORT_SYMBOL_GPL(rdmsr_safe_regs_on_pcpu);
541 int wrmsr_safe_regs_on_pcpu(unsigned int pcpu, u32 *regs)
543 int err = xen_set_physical_cpu_affinity(pcpu);
547 err = wrmsr_safe_regs(regs);
548 WARN_ON_ONCE(xen_set_physical_cpu_affinity(-1));
551 /* Fall back in case this is due to dom0_vcpus_pinned. */
552 err = wrmsr_safe_regs_on_cpu(pcpu, regs) ?: 1;
558 EXPORT_SYMBOL_GPL(wrmsr_safe_regs_on_pcpu);
560 #endif /* CONFIG_X86 */
562 MODULE_LICENSE("GPL");