Fixed cpu_halt on SPARC
[akaros.git] / kern / arch / sparc / arch.h
1 #ifndef ROS_INC_ARCH_H
2 #define ROS_INC_ARCH_H
3
4 #include <ros/arch/arch.h>
5
6 /* Arch Constants */
7 #define HW_CACHE_ALIGN          64
8 #define IOAPIC_BASE             0xFEC00000 // max virtual address
9
10 #include <arch/mmu.h>
11 #include <arch/sparc.h>
12
13 #ifndef __ASSEMBLER__
14
15 #include <ros/common.h>
16 #include <arch/timer.h>
17
18 static __inline void breakpoint(void) __attribute__((always_inline));
19 static __inline void invlpg(void *addr) __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 tlbflush(void) __attribute__((always_inline));
28 static __inline void icache_flush_page(void* va, void* pa)__attribute__((always_inline));
29 static __inline void clflush(uintptr_t* addr) __attribute__((always_inline));
30 static __inline int irq_is_enabled(void) __attribute__((always_inline));
31 static __inline uint32_t core_id(void) __attribute__((always_inline));
32 static __inline void cache_flush(void) __attribute__((always_inline));
33 static __inline void reboot(void) __attribute__((always_inline)) __attribute__((noreturn));
34 static __inline void lcr3(uint32_t val) __attribute__((always_inline));
35 static __inline uint32_t rcr3(void) __attribute__((always_inline));
36
37 void print_cpuinfo(void);
38 void show_mapping(uintptr_t start, size_t size);
39 void backtrace(void);
40 void cpu_halt(void);
41
42 extern uintptr_t mmu_context_tables[MAX_NUM_CPUS][NCONTEXTS+CONTEXT_TABLE_PAD];
43
44 static __inline void
45 breakpoint(void)
46 {
47         asm volatile ("ta 0x7f");
48 }
49
50 static __inline void 
51 invlpg(void *addr)
52
53         store_alternate(((uintptr_t)addr) & ~0xFFF,3,0);
54 }  
55
56 static __inline void
57 tlbflush(void)
58 {
59         store_alternate(0x400,3,0);
60 }
61
62 static __inline void
63 icache_flush_page(void* va, void* kva)
64 {
65         for(int i = 0; i < PGSIZE; i+=32) // functional pipeline line size
66                 clflush((uintptr_t*)((char*)kva+i));
67 }
68
69 static __inline uint64_t
70 read_tsc(void)
71 {
72         return read_perfctr(0,0);
73 }
74
75 static __inline uint64_t 
76 read_tsc_serialized(void)
77 {
78         return read_tsc();
79 }
80
81 static __inline void
82 enable_irq(void)
83 {
84         write_psr(read_psr() & ~0xF00);
85 }
86
87 static __inline void
88 disable_irq(void)
89 {
90         write_psr(read_psr() | 0xF00);
91 }
92
93 static __inline void
94 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
114 disable_irqsave(int8_t* state)
115 {
116         if ((*state == 0) && irq_is_enabled())
117                 disable_irq();
118         else 
119                 (*state)--;
120 }
121
122 static __inline uint64_t
123 read_perfctr(uint32_t cpu, uint32_t which)
124 {
125         register uint32_t hi asm("o0"), lo asm("o1");
126         uintptr_t addr = cpu<<10 | which<<3;
127
128         #ifdef ROS_KERNEL
129                 int8_t state = 0;
130                 disable_irqsave(&state);
131                 hi = load_iobus(0,addr);
132                 lo = load_iobus(0,addr+4);
133                 enable_irqsave(&state);
134         #else
135                 // can't use two load_iobuses in userspace because of atomicity
136                 asm volatile("mov %2,%%o0; ta 9"
137                              : "=r"(hi),"=r"(lo) : "r"(addr));
138         #endif
139         return (((uint64_t)hi) << 32) | lo;
140 }
141
142 static __inline void
143 cpu_relax(void)
144 {
145         int ctr = 8;
146         asm volatile("1: deccc %0; bne 1b; nop" :
147                      "=r"(ctr) : "0"(ctr) : "cc","memory");
148 }
149
150 static __inline void
151 clflush(uintptr_t* addr)
152 {
153         asm volatile("flush %0" : : "r"(addr));
154 }
155
156 static __inline int
157 irq_is_enabled(void)
158 {
159         return (read_psr() & 0xF00) == 0;
160 }
161
162 static __inline uint32_t
163 core_id(void)
164 {
165         uint32_t reg;
166         asm ("mov %" XSTR(CORE_ID_REG) ",%0" : "=r"(reg));
167         return reg;
168 }
169
170 static __inline void
171 cache_flush(void)
172 {
173 }
174
175 static __inline void
176 reboot(void)
177 {
178         extern void appserver_die(int code);
179         appserver_die(0);
180         while(1);
181 }
182
183 static __inline void
184 lcr3(uint32_t val)
185 {
186         mmu_context_tables[core_id()][0] = val >> 4 | PTE_PTD;
187         tlbflush();
188 }
189
190 static __inline uint32_t
191 rcr3(void)
192 {
193         return (mmu_context_tables[core_id()][0] & ~0x3) << 4;
194 }
195
196 #endif /* !__ASSEMBLER__ */
197
198 #endif /* !ROS_INC_X86_H */