Changes rdtsc serialization methods
[akaros.git] / kern / arch / i686 / 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 #include <arch/trap.h>
8 #include <arch/apic.h>
9
10 /* Arch Constants */
11 #define HW_CACHE_ALIGN                           64
12 /* Top of the kernel virtual mapping area (KERNBASE) */
13 /* For sanity reasons, I don't plan to map the top page */
14 #define KERN_VMAP_TOP                           0xfffff000
15
16 static __inline void breakpoint(void) __attribute__((always_inline));
17 static __inline void invlpg(void *SNT addr) __attribute__((always_inline));
18 static __inline void tlbflush(void) __attribute__((always_inline));
19 static __inline void icache_flush_page(void* va, void* kva) __attribute__((always_inline));
20 static __inline uint64_t read_tsc(void) __attribute__((always_inline));
21 static __inline uint64_t read_tsc_serialized(void) __attribute__((always_inline));
22 static __inline void enable_irq(void) __attribute__((always_inline));
23 static __inline void disable_irq(void) __attribute__((always_inline));
24 static __inline void enable_irqsave(int8_t* state) __attribute__((always_inline));
25 static __inline void disable_irqsave(int8_t* state) __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 int get_hw_coreid(uint32_t coreid);
31 static __inline int hw_core_id(void) __attribute__((always_inline));
32 static __inline int get_os_coreid(int hw_coreid);
33 static __inline int core_id(void) __attribute__((always_inline));
34 static __inline void cache_flush(void) __attribute__((always_inline));
35 static __inline void reboot(void) __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(uintptr_t start, size_t size);
42
43 /* declared in smp.c */
44 int hw_coreid_lookup[MAX_NUM_CPUS];
45 int os_coreid_lookup[MAX_NUM_CPUS];
46
47 static __inline void
48 breakpoint(void)
49 {
50         __asm __volatile("int3");
51 }
52
53 static __inline void 
54 invlpg(void *addr)
55
56         __asm __volatile("invlpg (%0)" : : "r" (addr) : "memory");
57 }  
58
59 static __inline void
60 tlbflush(void)
61 {
62         uint32_t cr3;
63         __asm __volatile("movl %%cr3,%0" : "=r" (cr3));
64         __asm __volatile("movl %0,%%cr3" : : "r" (cr3));
65 }
66
67 static __inline void
68 icache_flush_page(void* va, void* kva)
69 {
70         // x86 handles self-modifying code (mostly) without SW support
71 }
72
73 static __inline uint64_t
74 read_tsc(void)
75 {
76         uint64_t tsc;
77         __asm __volatile("rdtsc" : "=A" (tsc));
78         return tsc;
79 }
80
81 /* non-core-id reporting style (it is in ecx) */
82 static __inline uint64_t
83 read_tscp(void)
84 {
85         uint64_t tsc;
86         __asm __volatile("rdtscp" : "=A" (tsc) : : "ecx");
87         return tsc;
88 }
89
90 /* Check out k/a/i686/rdtsc_test.c for more info */
91 static __inline uint64_t 
92 read_tsc_serialized(void)
93 {
94         asm volatile("lfence"); /* mfence on amd */
95         return read_tsc();
96 }
97
98 static __inline void
99 enable_irq(void)
100 {
101         asm volatile("sti");
102 }
103
104 static __inline void
105 disable_irq(void)
106 {
107         asm volatile("cli");
108 }
109
110 static __inline void
111 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
131 disable_irqsave(int8_t* state)
132 {
133         if ((*state == 0) && irq_is_enabled())
134                 disable_irq();
135         else 
136                 (*state)--;
137 }
138
139 static __inline void
140 cpu_relax(void)
141 {
142         __cpu_relax();
143 }
144
145 /* This doesn't atomically enable interrupts and then halt, like we want, so
146  * x86 needs to use a custom helper in the irq handler in trap.c. */
147 static __inline void
148 cpu_halt(void)
149 {
150         asm volatile("sti; hlt" : : : "memory");
151 }
152
153 static __inline void
154 clflush(uintptr_t* addr)
155 {
156         asm volatile("clflush %0" : : "m"(*addr));
157 }
158
159 static __inline int
160 irq_is_enabled(void)
161 {
162         return read_eflags() & FL_IF;
163 }
164
165 /* os_coreid -> hw_coreid */
166 static __inline int
167 get_hw_coreid(uint32_t coreid)
168 {
169         return hw_coreid_lookup[coreid];
170 }
171
172 static __inline int
173 hw_core_id(void)
174 {
175         return lapic_get_id();
176 }
177
178 /* hw_coreid -> os_coreid */
179 static __inline int
180 get_os_coreid(int hw_coreid)
181 {
182         return os_coreid_lookup[hw_coreid];
183 }
184
185 /* core_id() returns the OS core number, not to be confused with the
186  * hardware-specific core identifier (such as the lapic id) returned by
187  * hw_core_id() */
188 static __inline int
189 core_id(void)
190 {
191         return get_os_coreid(hw_core_id());
192 }
193
194 static __inline void
195 cache_flush(void)
196 {
197         wbinvd();
198 }
199
200 static __inline void
201 reboot(void)
202 {
203         outb(0x92, 0x3);
204         asm volatile ("movl $0, %esp; int $0");
205         while(1);
206 }
207
208 #endif /* !ROS_INC_ARCH_H */