1 /* 2 * Copyright 2010, Michael Lotz, mmlr@mlotz.ch. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 6 * Distributed under the terms of the MIT License. 7 * 8 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 9 * Distributed under the terms of the NewOS License. 10 */ 11 12 #include <arch/x86/apic.h> 13 #include <arch/x86/msi.h> 14 15 #include <debug.h> 16 #include <kernel/cpu.h> 17 #include <safemode.h> 18 #include <vm/vm.h> 19 #include <util/AutoLock.h> 20 21 #include "timers/apic_timer.h" 22 23 24 static void *sLocalAPIC = NULL; 25 static bool sX2APIC = false; 26 27 28 bool 29 apic_available() 30 { 31 return sLocalAPIC != NULL || sX2APIC; 32 } 33 34 35 bool 36 x2apic_available() 37 { 38 return sX2APIC; 39 } 40 41 42 static uint32 43 apic_read(uint32 offset) 44 { 45 return *(volatile uint32 *)((char *)sLocalAPIC + offset); 46 } 47 48 49 static void 50 apic_write(uint32 offset, uint32 data) 51 { 52 *(volatile uint32 *)((char *)sLocalAPIC + offset) = data; 53 } 54 55 56 uint32 57 apic_local_id() 58 { 59 if (sX2APIC) 60 return x86_read_msr(IA32_MSR_APIC_ID); 61 else 62 return (apic_read(APIC_ID) & 0xffffffff) >> 24; 63 } 64 65 66 uint32 67 apic_version() 68 { 69 if (sX2APIC) 70 return x86_read_msr(IA32_MSR_APIC_VERSION); 71 else 72 return apic_read(APIC_VERSION); 73 } 74 75 76 uint32 77 apic_task_priority() 78 { 79 if (sX2APIC) 80 return x86_read_msr(IA32_MSR_APIC_TASK_PRIORITY); 81 else 82 return apic_read(APIC_TASK_PRIORITY); 83 } 84 85 86 void 87 apic_set_task_priority(uint32 config) 88 { 89 if (sX2APIC) 90 x86_write_msr(IA32_MSR_APIC_TASK_PRIORITY, config); 91 else 92 apic_write(APIC_TASK_PRIORITY, config); 93 } 94 95 96 void 97 apic_end_of_interrupt() 98 { 99 if (sX2APIC) 100 x86_write_msr(IA32_MSR_APIC_EOI, 0); 101 else 102 apic_write(APIC_EOI, 0); 103 } 104 105 106 uint32 107 apic_logical_apic_id() 108 { 109 if (sX2APIC) 110 return x86_read_msr(IA32_MSR_APIC_LOGICAL_DEST); 111 else 112 return apic_read(APIC_LOGICAL_DEST); 113 } 114 115 116 void 117 apic_disable_local_ints() 118 { 119 // just clear them out completely 120 if (sX2APIC) { 121 x86_write_msr(IA32_MSR_APIC_LVT_LINT0, APIC_LVT_MASKED); 122 x86_write_msr(IA32_MSR_APIC_LVT_LINT1, APIC_LVT_MASKED); 123 } else { 124 apic_write(APIC_LVT_LINT0, APIC_LVT_MASKED); 125 apic_write(APIC_LVT_LINT1, APIC_LVT_MASKED); 126 } 127 } 128 129 130 uint32 131 apic_spurious_intr_vector() 132 { 133 if (sX2APIC) 134 return x86_read_msr(IA32_MSR_APIC_SPURIOUS_INTR_VECTOR); 135 else 136 return apic_read(APIC_SPURIOUS_INTR_VECTOR); 137 } 138 139 140 void 141 apic_set_spurious_intr_vector(uint32 config) 142 { 143 if (sX2APIC) 144 x86_write_msr(IA32_MSR_APIC_SPURIOUS_INTR_VECTOR, config); 145 else 146 apic_write(APIC_SPURIOUS_INTR_VECTOR, config); 147 } 148 149 150 void 151 apic_set_interrupt_command(uint32 destination, uint32 mode) 152 { 153 if (sX2APIC) { 154 uint64 command = 0; 155 command |= (uint64)destination << 32; 156 command |= mode; 157 x86_write_msr(IA32_MSR_APIC_INTR_COMMAND, command); 158 } else { 159 uint32 command2 = 0; 160 command2 |= destination << 24; 161 apic_write(APIC_INTR_COMMAND_2, command2); 162 163 uint32 command1 = mode; 164 apic_write(APIC_INTR_COMMAND_1, command1); 165 } 166 } 167 168 169 bool 170 apic_interrupt_delivered(void) 171 { 172 if (sX2APIC) 173 return true; 174 else 175 return (apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) == 0; 176 } 177 178 179 uint32 180 apic_lvt_timer() 181 { 182 if (sX2APIC) 183 return x86_read_msr(IA32_MSR_APIC_LVT_TIMER); 184 else 185 return apic_read(APIC_LVT_TIMER); 186 } 187 188 189 void 190 apic_set_lvt_timer(uint32 config) 191 { 192 if (sX2APIC) 193 x86_write_msr(IA32_MSR_APIC_LVT_TIMER, config); 194 else 195 apic_write(APIC_LVT_TIMER, config); 196 } 197 198 199 uint32 200 apic_lvt_error() 201 { 202 if (sX2APIC) 203 return x86_read_msr(IA32_MSR_APIC_LVT_ERROR); 204 else 205 return apic_read(APIC_LVT_ERROR); 206 } 207 208 209 void 210 apic_set_lvt_error(uint32 config) 211 { 212 if (sX2APIC) 213 x86_write_msr(IA32_MSR_APIC_LVT_ERROR, config); 214 else 215 apic_write(APIC_LVT_ERROR, config); 216 } 217 218 219 uint32 220 apic_lvt_initial_timer_count() 221 { 222 if (sX2APIC) 223 return x86_read_msr(IA32_MSR_APIC_INITIAL_TIMER_COUNT); 224 else 225 return apic_read(APIC_INITIAL_TIMER_COUNT); 226 } 227 228 229 void 230 apic_set_lvt_initial_timer_count(uint32 config) 231 { 232 if (sX2APIC) 233 x86_write_msr(IA32_MSR_APIC_INITIAL_TIMER_COUNT, config); 234 else 235 apic_write(APIC_INITIAL_TIMER_COUNT, config); 236 } 237 238 239 uint32 240 apic_lvt_timer_divide_config() 241 { 242 if (sX2APIC) 243 return x86_read_msr(IA32_MSR_APIC_TIMER_DIVIDE_CONFIG); 244 else 245 return apic_read(APIC_TIMER_DIVIDE_CONFIG); 246 } 247 248 249 void 250 apic_set_lvt_timer_divide_config(uint32 config) 251 { 252 if (sX2APIC) 253 x86_write_msr(IA32_MSR_APIC_TIMER_DIVIDE_CONFIG, config); 254 else 255 apic_write(APIC_TIMER_DIVIDE_CONFIG, config); 256 } 257 258 259 status_t 260 apic_init(kernel_args *args) 261 { 262 if (args->arch_args.apic == NULL) 263 return B_NO_INIT; 264 265 uint64 apic_base = x86_read_msr(IA32_MSR_APIC_BASE); 266 267 if (x86_check_feature(IA32_FEATURE_EXT_X2APIC, FEATURE_EXT) 268 && (x86_check_feature(IA32_FEATURE_EXT_HYPERVISOR, FEATURE_EXT) 269 || ((apic_base & IA32_MSR_APIC_BASE_X2APIC) != 0))) { 270 dprintf("found x2apic\n"); 271 272 if (get_safemode_boolean(B_SAFEMODE_DISABLE_X2APIC, false)) { 273 dprintf("x2apic disabled per safemode setting\n"); 274 } else { 275 sX2APIC = true; 276 return B_OK; 277 } 278 } 279 280 sLocalAPIC = args->arch_args.apic; 281 dprintf("mapping local apic at %p\n", sLocalAPIC); 282 if (vm_map_physical_memory(B_SYSTEM_TEAM, "local apic", &sLocalAPIC, 283 B_EXACT_ADDRESS, B_PAGE_SIZE, 284 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 285 args->arch_args.apic_phys, true) < 0) { 286 panic("mapping the local apic failed"); 287 return B_ERROR; 288 } 289 290 return B_OK; 291 } 292 293 294 status_t 295 apic_per_cpu_init(kernel_args *args, int32 cpu) 296 { 297 if (sX2APIC) { 298 uint64 apic_base = x86_read_msr(IA32_MSR_APIC_BASE); 299 if ((apic_base & IA32_MSR_APIC_BASE_X2APIC) == 0) { 300 x86_write_msr(IA32_MSR_APIC_BASE, apic_base 301 | IA32_MSR_APIC_BASE_X2APIC); 302 } 303 } 304 305 dprintf("setting up %sapic for CPU %" B_PRId32 ": apic id %" B_PRIu32 ", " 306 "version %" B_PRIu32 "\n", sX2APIC ? "x2" : "", cpu, apic_local_id(), 307 apic_version()); 308 309 if (!sX2APIC && cpu < 8) { 310 apic_write(APIC_DEST_FORMAT, uint32(-1)); 311 312 uint8 logical_apic_id = 1 << cpu; 313 uint32 value = apic_read(APIC_LOGICAL_DEST); 314 value &= 0xffffff; 315 apic_write(APIC_LOGICAL_DEST, value | (logical_apic_id << 24)); 316 } 317 318 // get logical APIC ID 319 gCPU[cpu].arch.logical_apic_id = apic_logical_apic_id(); 320 if (!sX2APIC) 321 gCPU[cpu].arch.logical_apic_id >>= 24; 322 dprintf("CPU %" B_PRId32 ": logical apic id: %#" B_PRIx32 "\n", cpu, 323 gCPU[cpu].arch.logical_apic_id); 324 325 /* set spurious interrupt vector to 0xff */ 326 uint32 config = apic_spurious_intr_vector() & 0xffffff00; 327 config |= APIC_ENABLE | 0xff; 328 apic_set_spurious_intr_vector(config); 329 330 // don't touch the LINT0/1 configuration in virtual wire mode 331 // ToDo: implement support for other modes... 332 #if 0 333 if (cpu == 0) { 334 /* setup LINT0 as ExtINT */ 335 config = (apic_read(APIC_LINT0) & 0xffff00ff); 336 config |= APIC_LVT_DM_ExtINT | APIC_LVT_IIPP | APIC_LVT_TM; 337 apic_write(APIC_LINT0, config); 338 339 /* setup LINT1 as NMI */ 340 config = (apic_read(APIC_LINT1) & 0xffff00ff); 341 config |= APIC_LVT_DM_NMI | APIC_LVT_IIPP; 342 apic_write(APIC_LINT1, config); 343 } 344 if (cpu > 0) { 345 dprintf("LINT0: %p\n", (void *)apic_read(APIC_LINT0)); 346 dprintf("LINT1: %p\n", (void *)apic_read(APIC_LINT1)); 347 348 /* disable LINT0/1 */ 349 config = apic_read(APIC_LINT0); 350 apic_write(APIC_LINT0, config | APIC_LVT_MASKED); 351 352 config = apic_read(APIC_LINT1); 353 apic_write(APIC_LINT1, config | APIC_LVT_MASKED); 354 } else { 355 dprintf("0: LINT0: %p\n", (void *)apic_read(APIC_LINT0)); 356 dprintf("0: LINT1: %p\n", (void *)apic_read(APIC_LINT1)); 357 } 358 #endif 359 360 apic_timer_per_cpu_init(args, cpu); 361 362 /* setup error vector to 0xfe */ 363 config = (apic_lvt_error() & 0xffffff00) | 0xfe; 364 apic_set_lvt_error(config); 365 366 /* accept all interrupts */ 367 config = apic_task_priority() & 0xffffff00; 368 apic_set_task_priority(config); 369 370 config = apic_spurious_intr_vector(); 371 apic_end_of_interrupt(); 372 373 return B_OK; 374 } 375