No longer builds, but this is a good intermediate save point.
[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
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(pde_t *pgdir, uintptr_t start, size_t size);
42 int vendor_id(char *);
43
44 static inline void breakpoint(void)
45 {
46         asm volatile("int3");
47 }
48
49 static inline void invlpg(void *addr)
50
51         asm volatile("invlpg (%0)" : : "r" (addr) : "memory");
52 }  
53
54 static inline void tlbflush(void)
55 {
56         unsigned long cr3;
57         asm volatile("mov %%cr3,%0" : "=r" (cr3));
58         asm volatile("mov %0,%%cr3" : : "r" (cr3));
59 }
60
61 static inline void icache_flush_page(void *va, void *kva)
62 {
63         // x86 handles self-modifying code (mostly) without SW support
64 }
65
66 static inline uint64_t read_tsc(void)
67 {
68         uint32_t edx, eax;
69         asm volatile("rdtsc" : "=d"(edx), "=a"(eax));
70         return (uint64_t)edx << 32 | eax;
71 }
72
73 /* non-core-id reporting style (it is in ecx) */
74 static inline uint64_t read_tscp(void)
75 {
76         uint32_t edx, eax;
77         asm volatile("rdtscp" : "=d"(edx), "=a"(eax) : : X86_REG_CX);
78         return (uint64_t)edx << 32 | eax;
79 }
80
81 static inline void mwait(void *eax)
82 {
83         asm volatile("xorq %%rcx, %%rcx;"
84                      "xorq %%rdx, %%rdx;"
85                      "monitor;"
86                                  /* this is racy, generically.  we never check if the write to
87                                   * the monitored address happened already. */
88                      "movq $0, %%rax;"  /* c-state hint.  this is C1 */
89                      "mwait;"
90                      : : "a"(eax));
91 }
92 /* Check out k/a/x86/rdtsc_test.c for more info */
93 static inline uint64_t read_tsc_serialized(void)
94 {
95         asm volatile("lfence" ::: "memory");    /* mfence on amd? */
96         return read_tsc();
97 }
98
99 static inline void enable_irq(void)
100 {
101         asm volatile("sti");
102 }
103
104 static inline void disable_irq(void)
105 {
106         asm volatile("cli");
107 }
108
109 static inline void enable_irqsave(int8_t *state)
110 {
111         // *state tracks the number of nested enables and disables
112         // initial value of state: 0 = first run / no favorite
113         // > 0 means more enabled calls have been made
114         // < 0 means more disabled calls have been made
115         // Mostly doing this so we can call disable_irqsave first if we want
116
117         // one side or another "gets a point" if interrupts were already the
118         // way it wanted to go.  o/w, state stays at 0.  if the state was not 0
119         // then, enabling/disabling isn't even an option.  just increment/decrement
120
121         // if enabling is winning or tied, make sure it's enabled
122         if ((*state == 0) && !irq_is_enabled())
123                 enable_irq();
124         else
125                 (*state)++;
126 }
127
128 static inline void disable_irqsave(int8_t *state)
129 {
130         if ((*state == 0) && irq_is_enabled())
131                 disable_irq();
132         else 
133                 (*state)--;
134 }
135
136 static inline void cpu_relax(void)
137 {
138         __cpu_relax();
139 }
140
141 /* This doesn't atomically enable interrupts and then halt, like we want, so
142  * x86 needs to use a custom helper in the irq handler in trap.c. */
143 static inline void cpu_halt(void)
144 {
145         asm volatile("sti; hlt" : : : "memory");
146 }
147
148 static inline void clflush(uintptr_t* addr)
149 {
150         asm volatile("clflush %0" : : "m"(*addr));
151 }
152
153 static inline int irq_is_enabled(void)
154 {
155         return read_flags() & FL_IF;
156 }
157
158 static inline void cache_flush(void)
159 {
160         wbinvd();
161 }
162
163 static inline void reboot(void)
164 {
165         uint8_t cf9 = inb(0xcf9) & ~6;
166         outb(0x92, 0x3);
167         outb(0xcf9, cf9 | 2);
168         outb(0xcf9, cf9 | 6);
169         asm volatile ("mov $0, %"X86_REG_SP"; int $0");
170         while (1);
171 }
172
173 #endif /* !ROS_INC_ARCH_H */