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