parlib: Remove get_user_ctx_stack()
[akaros.git] / user / parlib / include / parlib / x86 / arch.h
1 #pragma once
2
3 #include <ros/trapframe.h>
4 #include <ros/arch/mmu.h>
5 #include <ros/procinfo.h>
6 #include <parlib/cpu_feat.h>
7
8 __BEGIN_DECLS
9
10 #define ARCH_CL_SIZE 64
11 #ifdef __x86_64__
12
13 #define internal_function
14 #define X86_REG_BP                                      "rbp"
15 #define X86_REG_SP                                      "rsp"
16 #define X86_REG_IP                                      "rip"
17 #define X86_REG_AX                                      "rax"
18 #define X86_REG_BX                                      "rbx"
19 #define X86_REG_CX                                      "rcx"
20 #define X86_REG_DX                                      "rdx"
21
22 #else /* 32 bit */
23
24 #define internal_function   __attribute ((regparm (3), stdcall))
25 #define X86_REG_BP                                      "ebp"
26 #define X86_REG_SP                                      "esp"
27 #define X86_REG_IP                                      "eip"
28 #define X86_REG_AX                                      "eax"
29 #define X86_REG_BX                                      "ebx"
30 #define X86_REG_CX                                      "ecx"
31 #define X86_REG_DX                                      "edx"
32
33 #endif /* 64bit / 32bit */
34
35 /* Make sure you subtract off/save enough space at the top of the stack for
36  * whatever you compiler might want to use when calling a noreturn function or
37  * to handle a HW spill or whatever. */
38 static inline void __attribute__((always_inline))
39 set_stack_pointer(void *sp)
40 {
41         asm volatile("mov %0,%%"X86_REG_SP"" : : "r"(sp) : "memory", X86_REG_SP);
42 }
43
44 static inline unsigned long get_stack_pointer(void)
45 {
46         unsigned long sp;
47
48         asm volatile("mov %%"X86_REG_SP",%0" : "=r"(sp));
49         return sp;
50 }
51
52 static inline void breakpoint(void)
53 {
54         asm volatile("int3");
55 }
56
57 static inline uint64_t read_tsc(void)
58 {
59         uint32_t edx, eax;
60         asm volatile("rdtsc" : "=d"(edx), "=a"(eax));
61         return (uint64_t)edx << 32 | eax;
62 }
63
64 /* Check out k/a/x86/rdtsc_test.c for more info */
65 static inline uint64_t read_tsc_serialized(void)
66 {
67         asm volatile("lfence"); /* mfence on amd */
68         return read_tsc();
69 }
70
71 static inline void cpu_relax(void)
72 {
73         asm volatile("pause" : : : "memory");
74 }
75
76 static inline void save_fp_state(struct ancillary_state *silly)
77 {
78         uint64_t x86_default_xcr0 = __proc_global_info.x86_default_xcr0;
79         uint32_t eax, edx;
80
81         /* PLEASE NOTE:
82          * AMD CPUs ignore the FOP/FIP/FDP fields when there is
83          * no pending exception. When you are on AMD, we zero these fields in the
84          * ancillary_state argument before saving. This way, if you are on AMD and
85          * re-using an ancillary_state memory region, an old save's information
86          * won't leak into your new data. The side-effect of this is that you can't
87          * trust these fields to report accurate information on AMD unless an
88          * exception was pending. Granted, AMD says that only exception handlers
89          * should care about FOP/FIP/FDP, so that's probably okay.
90          *
91          * You should also note that on newer Intel 64 processors, while the value
92          * of the FOP is always saved and restored, it contains the opcode of the
93          * most recent x87 FPU instruction that triggered an unmasked exception,
94          * rather than simply the most recent opcode. Some older Xeons and P4s had
95          * the fopcode compatibility mode feature, which you could use to make the
96          * FOP update on every x87 non-control instruction, but that has been
97          * eliminated in newer hardware.
98          *
99          */
100         if (cpu_has_feat(CPU_FEAT_X86_VENDOR_AMD)) {
101                 silly->fp_head_64d.fop      = 0x0;
102                 silly->fp_head_64d.fpu_ip   = 0x0;
103                 silly->fp_head_64d.cs       = 0x0;
104                 silly->fp_head_64d.padding1 = 0x0; // padding1 is FIP or rsvd, proc dep.
105                 silly->fp_head_64d.fpu_dp   = 0x0;
106                 silly->fp_head_64d.ds       = 0x0;
107                 silly->fp_head_64d.padding2 = 0x0; // padding2 is FDP or rsvd, proc dep.
108         }
109
110
111         if (cpu_has_feat(CPU_FEAT_X86_XSAVEOPT)) {
112                 edx = x86_default_xcr0 >> 32;
113                 eax = x86_default_xcr0;
114                 asm volatile("xsaveopt64 %0" : : "m"(*silly), "a"(eax), "d"(edx));
115         } else if (cpu_has_feat(CPU_FEAT_X86_XSAVE)) {
116                 edx = x86_default_xcr0 >> 32;
117                 eax = x86_default_xcr0;
118                 asm volatile("xsave64 %0" : : "m"(*silly), "a"(eax), "d"(edx));
119         } else {
120                 asm volatile("fxsave64 %0" : : "m"(*silly));
121         }
122 }
123
124 // NOTE: If you try to restore from a garbage ancillary_state,
125 //       you might trigger a fault and crash your program.
126 static inline void restore_fp_state(struct ancillary_state *silly)
127 {
128         uint64_t x86_default_xcr0 = __proc_global_info.x86_default_xcr0;
129         uint32_t eax, edx;
130
131         /*
132          * Since AMD CPUs ignore the FOP/FIP/FDP fields when there is
133          * no pending exception, we clear those fields before restoring
134          * when we are both on AMD and there is no pending exception in
135          * the ancillary_state argument to restore_fp_state.
136          * If there is a pending exception in the ancillary_state,
137          * these fields will be written to the FPU upon executing
138          * a restore instruction, and there is nothing to worry about.
139          *
140          * See CVE-2006-1056 and CVE-2013-2076 on cve.mitre.org.
141          *
142          * We check for a pending exception by checking FSW.ES (bit 7)
143          *
144          * FNINIT clears FIP and FDP and, even though it is technically a
145          * control instruction, it clears FOP because it is initializing the FPU.
146          *
147          * NOTE: This might not be the most efficient way to do things, and
148          *       could be an optimization target for context switch performance
149          *       on AMD processors in the future.
150          */
151         if (!(silly->fp_head_64d.fsw & 0x80)
152                 && cpu_has_feat(CPU_FEAT_X86_VENDOR_AMD))
153                 asm volatile ("fninit;");
154
155         if (cpu_has_feat(CPU_FEAT_X86_XSAVE)) {
156                 edx = x86_default_xcr0 >> 32;
157                 eax = x86_default_xcr0;
158                 asm volatile("xrstor64 %0" : : "m"(*silly), "a"(eax), "d"(edx));
159         } else {
160                 asm volatile("fxrstor64 %0" : : "m"(*silly));
161         }
162 }
163
164 __END_DECLS