PCI device locking and synchronization
[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 #define __always_inline __attribute__((always_inline))
12 static inline void breakpoint(void) __attribute__((always_inline));
13 static inline void invlpg(void *addr) __attribute__((always_inline));  
14 static inline void tlbflush(void) __attribute__((always_inline));
15 static inline void icache_flush_page(void *va, void *kva)
16               __attribute__((always_inline));
17 static inline uint64_t read_tsc(void) __attribute__((always_inline));
18 static inline uint64_t read_tscp(void) __attribute__((always_inline));
19 static inline uint64_t read_tsc_serialized(void) __attribute__((always_inline));
20 static inline void enable_irq(void) __attribute__((always_inline));
21 static inline void disable_irq(void) __attribute__((always_inline));
22 static inline void enable_irqsave(int8_t *state) __attribute__((always_inline));
23 static inline void disable_irqsave(int8_t *state)
24               __attribute__((always_inline));
25 static inline void cpu_relax(void) __attribute__((always_inline));
26 static inline void cpu_halt(void) __attribute__((always_inline));
27 static inline void clflush(uintptr_t* addr) __attribute__((always_inline));
28 static inline int irq_is_enabled(void) __attribute__((always_inline));
29 static inline void cache_flush(void) __attribute__((always_inline));
30 static inline void reboot(void)
31               __attribute__((always_inline)) __attribute__((noreturn));
32
33 /* in trap.c */
34 void send_ipi(uint32_t os_coreid, uint8_t vector);
35 /* in cpuinfo.c */
36 void print_cpuinfo(void);
37 void show_mapping(uintptr_t start, size_t size);
38 int vendor_id(char *);
39
40 static inline void breakpoint(void)
41 {
42         asm volatile("int3");
43 }
44
45 static inline void invlpg(void *addr)
46
47         asm volatile("invlpg (%0)" : : "r" (addr) : "memory");
48 }  
49
50 static inline void tlbflush(void)
51 {
52         unsigned long cr3;
53         asm volatile("mov %%cr3,%0" : "=r" (cr3));
54         asm volatile("mov %0,%%cr3" : : "r" (cr3));
55 }
56
57 static inline void icache_flush_page(void *va, void *kva)
58 {
59         // x86 handles self-modifying code (mostly) without SW support
60 }
61
62 static inline uint64_t read_tsc(void)
63 {
64         uint32_t edx, eax;
65         asm volatile("rdtsc" : "=d"(edx), "=a"(eax));
66         return (uint64_t)edx << 32 | eax;
67 }
68
69 /* non-core-id reporting style (it is in ecx) */
70 static inline uint64_t read_tscp(void)
71 {
72         uint32_t edx, eax;
73         asm volatile("rdtscp" : "=d"(edx), "=a"(eax) : : X86_REG_CX);
74         return (uint64_t)edx << 32 | eax;
75 }
76
77 /* Check out k/a/x86/rdtsc_test.c for more info */
78 static inline uint64_t read_tsc_serialized(void)
79 {
80         asm volatile("lfence" ::: "memory");    /* mfence on amd? */
81         return read_tsc();
82 }
83
84 static inline void enable_irq(void)
85 {
86         asm volatile("sti");
87 }
88
89 static inline void disable_irq(void)
90 {
91         asm volatile("cli");
92 }
93
94 static inline void enable_irqsave(int8_t *state)
95 {
96         // *state tracks the number of nested enables and disables
97         // initial value of state: 0 = first run / no favorite
98         // > 0 means more enabled calls have been made
99         // < 0 means more disabled calls have been made
100         // Mostly doing this so we can call disable_irqsave first if we want
101
102         // one side or another "gets a point" if interrupts were already the
103         // way it wanted to go.  o/w, state stays at 0.  if the state was not 0
104         // then, enabling/disabling isn't even an option.  just increment/decrement
105
106         // if enabling is winning or tied, make sure it's enabled
107         if ((*state == 0) && !irq_is_enabled())
108                 enable_irq();
109         else
110                 (*state)++;
111 }
112
113 static inline void disable_irqsave(int8_t *state)
114 {
115         if ((*state == 0) && irq_is_enabled())
116                 disable_irq();
117         else 
118                 (*state)--;
119 }
120
121 static inline void cpu_relax(void)
122 {
123         __cpu_relax();
124 }
125
126 /* This doesn't atomically enable interrupts and then halt, like we want, so
127  * x86 needs to use a custom helper in the irq handler in trap.c. */
128 static inline void cpu_halt(void)
129 {
130         asm volatile("sti; hlt" : : : "memory");
131 }
132
133 static inline void clflush(uintptr_t* addr)
134 {
135         asm volatile("clflush %0" : : "m"(*addr));
136 }
137
138 static inline int irq_is_enabled(void)
139 {
140         return read_flags() & FL_IF;
141 }
142
143 static inline void cache_flush(void)
144 {
145         wbinvd();
146 }
147
148 static inline void reboot(void)
149 {
150         uint8_t cf9 = inb(0xcf9) & ~6;
151         outb(0x92, 0x3);
152         outb(0xcf9, cf9 | 2);
153         outb(0xcf9, cf9 | 6);
154         asm volatile ("mov $0, %"X86_REG_SP"; int $0");
155         while (1);
156 }
157
158 #endif /* !ROS_INC_ARCH_H */