kconfig: use pkg-config for ncurses detection
[akaros.git] / kern / arch / x86 / arch.h
1 #pragma once
2
3 #include <ros/arch/arch.h>
4 #include <ros/common.h>
5 #include <arch/x86.h>
6
7 /* Arch Constants */
8 #define ARCH_CL_SIZE                             64
9
10 static inline void breakpoint(void) __attribute__((always_inline));
11 static inline void icache_flush_page(void *va, void *kva)
12               __attribute__((always_inline));
13 static inline uint64_t read_tsc(void) __attribute__((always_inline));
14 static inline uint64_t read_tscp(void) __attribute__((always_inline));
15 static inline uint64_t read_tsc_serialized(void) __attribute__((always_inline));
16 static inline void enable_irq(void) __attribute__((always_inline));
17 static inline void disable_irq(void) __attribute__((always_inline));
18 static inline void enable_irqsave(int8_t *state) __attribute__((always_inline));
19 static inline void disable_irqsave(int8_t *state)
20               __attribute__((always_inline));
21 static inline void cpu_relax(void) __attribute__((always_inline));
22 static inline void clflush(uintptr_t* addr) __attribute__((always_inline));
23 static inline int irq_is_enabled(void) __attribute__((always_inline));
24 static inline void cache_flush(void) __attribute__((always_inline));
25 static inline void reboot(void)
26               __attribute__((always_inline)) __attribute__((noreturn));
27 static inline void prefetch(void *addr);
28 static inline void prefetchw(void *addr);
29 static inline void swap_gs(void);
30 static inline void __attribute__((noreturn))
31 __reset_stack_pointer(void *arg, uintptr_t sp, void (*f)(void *));
32
33 /* in trap.c */
34 void send_ipi(uint32_t os_coreid, uint8_t vector);
35 /* in cpuinfo.c */
36 int x86_family, x86_model, x86_stepping;
37 void print_cpuinfo(void);
38 void show_mapping(pgdir_t pgdir, uintptr_t start, size_t size);
39 int vendor_id(char *);
40 /* pmap.c */
41 void invlpg(void *addr);
42 void tlbflush(void);
43 void tlb_flush_global(void);
44 /* idle.c */
45 void cpu_halt(void);
46 struct preempt_data;
47 void cpu_halt_notif_pending(struct preempt_data *vcpd);
48
49 static inline void breakpoint(void)
50 {
51         asm volatile("int3");
52 }
53
54 static inline void icache_flush_page(void *va, void *kva)
55 {
56         // x86 handles self-modifying code (mostly) without SW support
57 }
58
59 static inline uint64_t read_tsc(void)
60 {
61         uint32_t edx, eax;
62         asm volatile("rdtsc" : "=d"(edx), "=a"(eax));
63         return (uint64_t)edx << 32 | eax;
64 }
65
66 /* non-core-id reporting style (it is in ecx) */
67 static inline uint64_t read_tscp(void)
68 {
69         uint32_t edx, eax;
70         asm volatile("rdtscp" : "=d"(edx), "=a"(eax) : : X86_REG_CX);
71         return (uint64_t)edx << 32 | eax;
72 }
73
74 static inline void mwait(void *eax)
75 {
76         asm volatile("xorq %%rcx, %%rcx;"
77                      "xorq %%rdx, %%rdx;"
78                      "monitor;"
79                                  /* this is racy, generically.  we never check
80                                   * if the write to the monitored address
81                                   * happened already. */
82                      "movq $0, %%rax;"  /* c-state hint.  this is C1 */
83                      "mwait;"
84                      : : "a"(eax));
85 }
86
87 /* Check out k/a/x86/rdtsc_test.c for more info */
88 static inline uint64_t read_tsc_serialized(void)
89 {
90         asm volatile("lfence" ::: "memory");    /* mfence on amd? */
91         return read_tsc();
92 }
93
94 static inline void enable_irq(void)
95 {
96         asm volatile("sti");
97 }
98
99 static inline void disable_irq(void)
100 {
101         asm volatile("cli");
102 }
103
104 static inline void enable_irqsave(int8_t *state)
105 {
106         // *state tracks the number of nested enables and disables
107         // initial value of state: 0 = first run / no favorite
108         // > 0 means more enabled calls have been made
109         // < 0 means more disabled calls have been made
110         // Mostly doing this so we can call disable_irqsave first if we want
111
112         // one side or another "gets a point" if interrupts were already the way
113         // it wanted to go.  o/w, state stays at 0.  if the state was not 0
114         // then, enabling/disabling isn't even an option.  just
115         // increment/decrement
116
117         // if enabling is winning or tied, make sure it's enabled
118         if ((*state == 0) && !irq_is_enabled())
119                 enable_irq();
120         else
121                 (*state)++;
122 }
123
124 static inline void disable_irqsave(int8_t *state)
125 {
126         if ((*state == 0) && irq_is_enabled())
127                 disable_irq();
128         else
129                 (*state)--;
130 }
131
132 static inline void cpu_relax(void)
133 {
134         __cpu_relax();
135 }
136
137 static inline void clflush(uintptr_t* addr)
138 {
139         asm volatile("clflush %0" : : "m"(*addr));
140 }
141
142 static inline int irq_is_enabled(void)
143 {
144         return read_flags() & FL_IF;
145 }
146
147 static inline void cache_flush(void)
148 {
149         wbinvd();
150 }
151
152 static inline void reboot(void)
153 {
154         uint8_t cf9 = inb(0xcf9) & ~6;
155
156         outb(0x92, 0x3);
157         outb(0xcf9, cf9 | 2);
158         outb(0xcf9, cf9 | 6);
159         asm volatile ("mov $0, %"X86_REG_SP"; int $0");
160         while (1);
161 }
162
163 static inline void prefetch(void *addr)
164 {
165         asm volatile("prefetchnta (%0)" : : "r"(addr));
166 }
167
168 static inline void prefetchw(void *addr)
169 {
170         asm volatile("prefetchw (%0)" : : "r"(addr));
171 }
172
173 /* Guest VMs have a maximum physical address they can use.  Guest
174  * physical addresses are mapped into this MCP 1:1, but limited to
175  * this max address *in hardware*.  I.e., the MCP process can address
176  * more memory than the VMMCP can.  This is great; it means that
177  * keeping VM management stuff separate from the VM is trivial: just
178  * map it above max_vm_address. There's no need, as in other systems,
179  * to tweak the page table or root pointer to protect management
180  * memory from VM memory.
181  *
182  * TODO: read a register the first time this is called and save it
183  * away.  But this is more than enough for now.
184  */
185 static inline uint64_t max_guest_pa(void)
186 {
187         return (1ULL<<40) - 1;
188 }
189
190 static inline void swap_gs(void)
191 {
192         asm volatile ("swapgs");
193 }
194
195 /* Resets a stack pointer to sp, then calls f(arg) */
196 static inline void __attribute__((noreturn))
197 __reset_stack_pointer(void *arg, uintptr_t sp, void (*f)(void *))
198 {
199         /* FP must be zeroed before SP.  Ideally, we'd do both atomically.  If
200          * we take an IRQ/NMI in between and set SP first, then a backtrace
201          * would be confused since FP points *below* the SP that the *IRQ
202          * handler* is now using.  By zeroing FP first, at least we won't BT at
203          * all (though FP is still out of sync with SP). */
204         asm volatile ("mov $0x0, %%rbp;"
205                       "mov %0, %%rsp;"
206                       "jmp *%%rdx;"
207                       : : "q"(sp), "D"(arg), "d"(f));
208         while (1);
209 }