VMM: Use the I_POKE_CORE IRQ for posted IRQs
[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 /* Used by arch/bitops.h.  Everyone else (so far) does it manually, but maybe
11  * other Linux code will use this.  We need to say both inline and apply the
12  * attrib, o/w newer gcc's complain. */
13 #define __always_inline inline __attribute__((always_inline))
14
15 static inline void breakpoint(void) __attribute__((always_inline));
16 static inline void icache_flush_page(void *va, void *kva)
17               __attribute__((always_inline));
18 static inline uint64_t read_tsc(void) __attribute__((always_inline));
19 static inline uint64_t read_tscp(void) __attribute__((always_inline));
20 static inline uint64_t read_tsc_serialized(void) __attribute__((always_inline));
21 static inline void enable_irq(void) __attribute__((always_inline));
22 static inline void disable_irq(void) __attribute__((always_inline));
23 static inline void enable_irqsave(int8_t *state) __attribute__((always_inline));
24 static inline void disable_irqsave(int8_t *state)
25               __attribute__((always_inline));
26 static inline void cpu_relax(void) __attribute__((always_inline));
27 static inline void cpu_halt(void) __attribute__((always_inline));
28 static inline void clflush(uintptr_t* addr) __attribute__((always_inline));
29 static inline int irq_is_enabled(void) __attribute__((always_inline));
30 static inline void cache_flush(void) __attribute__((always_inline));
31 static inline void reboot(void)
32               __attribute__((always_inline)) __attribute__((noreturn));
33 static inline void prefetch(void *addr);
34 static inline void prefetchw(void *addr);
35 static inline void swap_gs(void);
36
37 /* in trap.c */
38 void send_ipi(uint32_t os_coreid, uint8_t vector);
39 /* in cpuinfo.c */
40 void print_cpuinfo(void);
41 void show_mapping(pgdir_t pgdir, uintptr_t start, size_t size);
42 int vendor_id(char *);
43 /* pmap.c */
44 void invlpg(void *addr);
45 void tlbflush(void);
46 void tlb_flush_global(void);
47
48 static inline void breakpoint(void)
49 {
50         asm volatile("int3");
51 }
52
53 static inline void icache_flush_page(void *va, void *kva)
54 {
55         // x86 handles self-modifying code (mostly) without SW support
56 }
57
58 static inline uint64_t read_tsc(void)
59 {
60         uint32_t edx, eax;
61         asm volatile("rdtsc" : "=d"(edx), "=a"(eax));
62         return (uint64_t)edx << 32 | eax;
63 }
64
65 /* non-core-id reporting style (it is in ecx) */
66 static inline uint64_t read_tscp(void)
67 {
68         uint32_t edx, eax;
69         asm volatile("rdtscp" : "=d"(edx), "=a"(eax) : : X86_REG_CX);
70         return (uint64_t)edx << 32 | eax;
71 }
72
73 static inline void mwait(void *eax)
74 {
75         asm volatile("xorq %%rcx, %%rcx;"
76                      "xorq %%rdx, %%rdx;"
77                      "monitor;"
78                                  /* this is racy, generically.  we never check if the write to
79                                   * the monitored address happened already. */
80                      "movq $0, %%rax;"  /* c-state hint.  this is C1 */
81                      "mwait;"
82                      : : "a"(eax));
83 }
84 /* Check out k/a/x86/rdtsc_test.c for more info */
85 static inline uint64_t read_tsc_serialized(void)
86 {
87         asm volatile("lfence" ::: "memory");    /* mfence on amd? */
88         return read_tsc();
89 }
90
91 static inline void enable_irq(void)
92 {
93         asm volatile("sti");
94 }
95
96 static inline void disable_irq(void)
97 {
98         asm volatile("cli");
99 }
100
101 static inline void enable_irqsave(int8_t *state)
102 {
103         // *state tracks the number of nested enables and disables
104         // initial value of state: 0 = first run / no favorite
105         // > 0 means more enabled calls have been made
106         // < 0 means more disabled calls have been made
107         // Mostly doing this so we can call disable_irqsave first if we want
108
109         // one side or another "gets a point" if interrupts were already the
110         // way it wanted to go.  o/w, state stays at 0.  if the state was not 0
111         // then, enabling/disabling isn't even an option.  just increment/decrement
112
113         // if enabling is winning or tied, make sure it's enabled
114         if ((*state == 0) && !irq_is_enabled())
115                 enable_irq();
116         else
117                 (*state)++;
118 }
119
120 static inline void disable_irqsave(int8_t *state)
121 {
122         if ((*state == 0) && irq_is_enabled())
123                 disable_irq();
124         else 
125                 (*state)--;
126 }
127
128 static inline void cpu_relax(void)
129 {
130         __cpu_relax();
131 }
132
133 /* This atomically enables interrupts and halts.  sti does not take effect until
134  * after the *next* instruction */
135 static inline void cpu_halt(void)
136 {
137         asm volatile("sti; hlt" : : : "memory");
138 }
139
140 static inline void clflush(uintptr_t* addr)
141 {
142         asm volatile("clflush %0" : : "m"(*addr));
143 }
144
145 static inline int irq_is_enabled(void)
146 {
147         return read_flags() & FL_IF;
148 }
149
150 static inline void cache_flush(void)
151 {
152         wbinvd();
153 }
154
155 static inline void reboot(void)
156 {
157         uint8_t cf9 = inb(0xcf9) & ~6;
158         outb(0x92, 0x3);
159         outb(0xcf9, cf9 | 2);
160         outb(0xcf9, cf9 | 6);
161         asm volatile ("mov $0, %"X86_REG_SP"; int $0");
162         while (1);
163 }
164
165 static inline void prefetch(void *addr)
166 {
167         asm volatile("prefetchnta (%0)" : : "r"(addr));
168 }
169
170 static inline void prefetchw(void *addr)
171 {
172         asm volatile("prefetchw (%0)" : : "r"(addr));
173 }
174
175 /* Guest VMs have a maximum physical address they can use.  Guest
176  * physical addresses are mapped into this MCP 1:1, but limited to
177  * this max address *in hardware*.  I.e., the MCP process can address
178  * more memory than the VMMCP can.  This is great; it means that
179  * keeping VM management stuff separate from the VM is trivial: just
180  * map it above max_vm_address. There's no need, as in other systems,
181  * to tweak the page table or root pointer to protect management
182  * memory from VM memory.
183  *
184  * TODO: read a register the first time this is called and save it
185  * away.  But this is more than enough for now.
186  */
187 static inline uint64_t max_guest_pa(void)
188 {
189         return (1ULL<<40) - 1;
190 }
191
192 static inline void swap_gs(void)
193 {
194         asm volatile ("swapgs");
195 }