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