xref: /kvm-unit-tests/lib/x86/smp.h (revision 4c8a99ca02252d4a2bee43f4558fe47ce5ab7ec0)
1 #ifndef _X86_SMP_H_
2 #define _X86_SMP_H_
3 
4 #include <stddef.h>
5 #include <asm/spinlock.h>
6 #include "libcflat.h"
7 #include "atomic.h"
8 #include "apic-defs.h"
9 
10 /* Address where to store the address of realmode GDT descriptor. */
11 #define REALMODE_GDT_LOWMEM (PAGE_SIZE - 2)
12 
13 /* Offsets into the per-cpu page. */
14 struct percpu_data {
15 	uint32_t  smp_id;
16 	union {
17 		struct {
18 			uint8_t   exception_vector;
19 			uint8_t   exception_rflags_rf;
20 			uint16_t  exception_error_code;
21 		};
22 		uint32_t exception_data;
23 	};
24 	void *apic_ops;
25 };
26 
27 #define typeof_percpu(name) typeof(((struct percpu_data *)0)->name)
28 #define offsetof_percpu(name) offsetof(struct percpu_data, name)
29 
30 #define BUILD_PERCPU_OP(name)								\
31 static inline typeof_percpu(name) this_cpu_read_##name(void)				\
32 {											\
33 	typeof_percpu(name) val;							\
34 											\
35 	switch (sizeof(val)) {								\
36 	case 1:										\
37 		asm("movb %%gs:%c1, %0" : "=q" (val) : "i" (offsetof_percpu(name)));	\
38 		break;									\
39 	case 2:										\
40 		asm("movw %%gs:%c1, %0" : "=r" (val) : "i" (offsetof_percpu(name)));	\
41 		break;									\
42 	case 4:										\
43 		asm("movl %%gs:%c1, %0" : "=r" (val) : "i" (offsetof_percpu(name)));	\
44 		break;									\
45 	case 8:										\
46 		asm("movq %%gs:%c1, %0" : "=r" (val) : "i" (offsetof_percpu(name)));	\
47 		break;									\
48 	default:									\
49 		asm volatile("ud2");							\
50 	}										\
51 	return val;									\
52 }											\
53 static inline void this_cpu_write_##name(typeof_percpu(name) val)			\
54 {											\
55 	switch (sizeof(val)) {								\
56 	case 1:										\
57 		asm("movb %0, %%gs:%c1" :: "q" (val), "i" (offsetof_percpu(name)));	\
58 		break;									\
59 	case 2:										\
60 		asm("movw %0, %%gs:%c1" :: "r" (val), "i" (offsetof_percpu(name)));	\
61 		break;									\
62 	case 4:										\
63 		asm("movl %0, %%gs:%c1" :: "r" (val), "i" (offsetof_percpu(name)));	\
64 		break;									\
65 	case 8:										\
66 		asm("movq %0, %%gs:%c1" :: "r" (val), "i" (offsetof_percpu(name)));	\
67 		break;									\
68 	default:									\
69 		asm volatile("ud2");							\
70 	}										\
71 }
72 BUILD_PERCPU_OP(smp_id);
73 BUILD_PERCPU_OP(exception_vector);
74 BUILD_PERCPU_OP(exception_rflags_rf);
75 BUILD_PERCPU_OP(exception_error_code);
76 BUILD_PERCPU_OP(apic_ops);
77 
78 void smp_init(void);
79 
80 int cpu_count(void);
81 int smp_id(void);
82 int cpus_active(void);
83 void on_cpu(int cpu, void (*function)(void *data), void *data);
84 void on_cpu_async(int cpu, void (*function)(void *data), void *data);
85 void on_cpus(void (*function)(void *data), void *data);
86 void smp_reset_apic(void);
87 void bringup_aps(void);
88 void ap_online(void);
89 
90 extern atomic_t cpu_online_count;
91 extern unsigned char online_cpus[(MAX_TEST_CPUS + 7) / 8];
92 
93 #endif
94