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