Avoids nehalem keyboard issues, better monitors
[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
13 static __inline void breakpoint(void) __attribute__((always_inline));
14 static __inline void invlpg(void *SNT addr) __attribute__((always_inline));
15 static __inline void tlbflush(void) __attribute__((always_inline));
16 static __inline void icache_flush_page(void* va, void* kva) __attribute__((always_inline));
17 static __inline uint64_t read_tsc(void) __attribute__((always_inline));
18 static __inline uint64_t read_tsc_serialized(void) __attribute__((always_inline));
19 static __inline void enable_irq(void) __attribute__((always_inline));
20 static __inline void disable_irq(void) __attribute__((always_inline));
21 static __inline void enable_irqsave(int8_t* state) __attribute__((always_inline));
22 static __inline void disable_irqsave(int8_t* state) __attribute__((always_inline));
23 static __inline void cpu_relax(void) __attribute__((always_inline));
24 static __inline void cpu_halt(void) __attribute__((always_inline));
25 static __inline void clflush(uintptr_t* addr) __attribute__((always_inline));
26 static __inline int irq_is_enabled(void) __attribute__((always_inline));
27 static __inline int get_hw_coreid(int coreid);
28 static __inline int hw_core_id(void) __attribute__((always_inline));
29 static __inline int get_os_coreid(int hw_coreid);
30 static __inline int core_id(void) __attribute__((always_inline));
31 static __inline void cache_flush(void) __attribute__((always_inline));
32 static __inline void reboot(void) __attribute__((always_inline)) __attribute__((noreturn));
33
34 void print_cpuinfo(void);
35 void show_mapping(uintptr_t start, size_t size);
36 void backtrace(void);
37
38 /* declared in smp.c */
39 int hw_coreid_lookup[MAX_NUM_CPUS];
40 int os_coreid_lookup[MAX_NUM_CPUS];
41
42 static __inline void
43 breakpoint(void)
44 {
45         __asm __volatile("int3");
46 }
47
48 static __inline void 
49 invlpg(void *addr)
50
51         __asm __volatile("invlpg (%0)" : : "r" (addr) : "memory");
52 }  
53
54 static __inline void
55 tlbflush(void)
56 {
57         uint32_t cr3;
58         __asm __volatile("movl %%cr3,%0" : "=r" (cr3));
59         __asm __volatile("movl %0,%%cr3" : : "r" (cr3));
60 }
61
62 static __inline void
63 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
69 read_tsc(void)
70 {
71         uint64_t tsc;
72         __asm __volatile("rdtsc" : "=A" (tsc));
73         return tsc;
74 }
75
76 static __inline uint64_t 
77 read_tsc_serialized(void)
78 {
79     uint64_t tsc;
80         cpuid(0, 0, 0, 0, 0);
81         tsc = read_tsc();
82         return tsc;
83 }
84
85 static __inline void
86 enable_irq(void)
87 {
88         asm volatile("sti");
89 }
90
91 static __inline void
92 disable_irq(void)
93 {
94         asm volatile("cli");
95 }
96
97 static __inline void
98 enable_irqsave(int8_t* state)
99 {
100         // *state tracks the number of nested enables and disables
101         // initial value of state: 0 = first run / no favorite
102         // > 0 means more enabled calls have been made
103         // < 0 means more disabled calls have been made
104         // Mostly doing this so we can call disable_irqsave first if we want
105
106         // one side or another "gets a point" if interrupts were already the
107         // way it wanted to go.  o/w, state stays at 0.  if the state was not 0
108         // then, enabling/disabling isn't even an option.  just increment/decrement
109
110         // if enabling is winning or tied, make sure it's enabled
111         if ((*state == 0) && !irq_is_enabled())
112                 enable_irq();
113         else
114                 (*state)++;
115 }
116
117 static __inline void
118 disable_irqsave(int8_t* state)
119 {
120         if ((*state == 0) && irq_is_enabled())
121                 disable_irq();
122         else 
123                 (*state)--;
124 }
125
126 static __inline void
127 cpu_relax(void)
128 {
129         __cpu_relax();
130 }
131
132 static __inline void
133 cpu_halt(void)
134 {
135         asm volatile("hlt" : : : "memory");
136 }
137
138 static __inline void
139 clflush(uintptr_t* addr)
140 {
141         asm volatile("clflush %0" : : "m"(*addr));
142 }
143
144 static __inline int
145 irq_is_enabled(void)
146 {
147         return read_eflags() & FL_IF;
148 }
149
150 /* os_coreid -> hw_coreid */
151 static __inline int
152 get_hw_coreid(int coreid)
153 {
154         return hw_coreid_lookup[coreid];
155 }
156
157 static __inline int
158 hw_core_id(void)
159 {
160         return lapic_get_id();
161 }
162
163 /* hw_coreid -> os_coreid */
164 static __inline int
165 get_os_coreid(int hw_coreid)
166 {
167         return os_coreid_lookup[hw_coreid];
168 }
169
170 /* core_id() returns the OS core number, not to be confused with the
171  * hardware-specific core identifier (such as the lapic id) returned by
172  * hw_core_id() */
173 static __inline int
174 core_id(void)
175 {
176         return get_os_coreid(hw_core_id());
177 }
178
179 static __inline void
180 cache_flush(void)
181 {
182         wbinvd();
183 }
184
185 static __inline void
186 reboot(void)
187 {
188         outb(0x92, 0x3);
189         asm volatile ("movl $0, %esp; int $0");
190         while(1);
191 }
192
193 #endif /* !ROS_INC_ARCH_H */