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