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 24static void *sLocalAPIC = NULL; 25static bool sX2APIC = false; 26 27 28bool 29apic_available() 30{ 31 return sLocalAPIC != NULL || sX2APIC; 32} 33 34 35bool 36x2apic_available() 37{ 38 return sX2APIC; 39} 40 41 42uint32 43apic_read(uint32 offset) 44{ 45 return *(volatile uint32 *)((char *)sLocalAPIC + offset); 46} 47 48 49void 50apic_write(uint32 offset, uint32 data) 51{ 52 *(volatile uint32 *)((char *)sLocalAPIC + offset) = data; 53} 54 55 56uint32 57apic_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 66uint32 67apic_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 76uint32 77apic_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 86void 87apic_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 96void 97apic_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 106uint32 107apic_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 116void 117apic_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 130uint32 131apic_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 140void 141apic_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 150void 151apic_set_interrupt_command(uint32 destination, uint32 mode) 152{ 153 if (sX2APIC) { 154 uint64 command = x86_read_msr(IA32_MSR_APIC_INTR_COMMAND); 155 command &= APIC_INTR_COMMAND_1_MASK; 156 command |= (uint64)destination << 32; 157 command |= mode; 158 x86_write_msr(IA32_MSR_APIC_INTR_COMMAND, command); 159 } else { 160 uint32 command2 = apic_read(APIC_INTR_COMMAND_2) 161 & APIC_INTR_COMMAND_2_MASK; 162 command2 |= destination << 24; 163 apic_write(APIC_INTR_COMMAND_2, command2); 164 165 uint32 command1 = apic_read(APIC_INTR_COMMAND_1) 166 & APIC_INTR_COMMAND_1_MASK; 167 command1 |= mode; 168 apic_write(APIC_INTR_COMMAND_1, command1); 169 } 170} 171 172 173bool 174apic_interrupt_delivered(void) 175{ 176 if (sX2APIC) 177 return true; 178 else 179 return (apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS) == 0; 180} 181 182 183uint32 184apic_lvt_timer() 185{ 186 if (sX2APIC) 187 return x86_read_msr(IA32_MSR_APIC_LVT_TIMER); 188 else 189 return apic_read(APIC_LVT_TIMER); 190} 191 192 193void 194apic_set_lvt_timer(uint32 config) 195{ 196 if (sX2APIC) 197 x86_write_msr(IA32_MSR_APIC_LVT_TIMER, config); 198 else 199 apic_write(APIC_LVT_TIMER, config); 200} 201 202 203uint32 204apic_lvt_error() 205{ 206 if (sX2APIC) 207 return x86_read_msr(IA32_MSR_APIC_LVT_ERROR); 208 else 209 return apic_read(APIC_LVT_ERROR); 210} 211 212 213void 214apic_set_lvt_error(uint32 config) 215{ 216 if (sX2APIC) 217 x86_write_msr(IA32_MSR_APIC_LVT_ERROR, config); 218 else 219 apic_write(APIC_LVT_ERROR, config); 220} 221 222 223uint32 224apic_lvt_initial_timer_count() 225{ 226 if (sX2APIC) 227 return x86_read_msr(IA32_MSR_APIC_INITIAL_TIMER_COUNT); 228 else 229 return apic_read(APIC_INITIAL_TIMER_COUNT); 230} 231 232 233void 234apic_set_lvt_initial_timer_count(uint32 config) 235{ 236 if (sX2APIC) 237 x86_write_msr(IA32_MSR_APIC_INITIAL_TIMER_COUNT, config); 238 else 239 apic_write(APIC_INITIAL_TIMER_COUNT, config); 240} 241 242 243uint32 244apic_lvt_timer_divide_config() 245{ 246 if (sX2APIC) 247 return x86_read_msr(IA32_MSR_APIC_TIMER_DIVIDE_CONFIG); 248 else 249 return apic_read(APIC_TIMER_DIVIDE_CONFIG); 250} 251 252 253void 254apic_set_lvt_timer_divide_config(uint32 config) 255{ 256 if (sX2APIC) 257 x86_write_msr(IA32_MSR_APIC_TIMER_DIVIDE_CONFIG, config); 258 else 259 apic_write(APIC_TIMER_DIVIDE_CONFIG, config); 260} 261 262 263status_t 264apic_init(kernel_args *args) 265{ 266 if (args->arch_args.apic == NULL) 267 return B_NO_INIT; 268 269 uint64 apic_base = x86_read_msr(IA32_MSR_APIC_BASE); 270 271 if (x86_check_feature(IA32_FEATURE_EXT_X2APIC, FEATURE_EXT) 272 && (x86_check_feature(IA32_FEATURE_EXT_HYPERVISOR, FEATURE_EXT) 273 || ((apic_base & IA32_MSR_APIC_BASE_X2APIC) != 0))) { 274 dprintf("found x2apic\n"); 275 276 if (get_safemode_boolean(B_SAFEMODE_DISABLE_X2APIC, false)) { 277 dprintf("x2apic disabled per safemode setting\n"); 278 } else { 279 sX2APIC = true; 280 return B_OK; 281 } 282 } 283 284 sLocalAPIC = args->arch_args.apic; 285 dprintf("mapping local apic at %p\n", sLocalAPIC); 286 if (vm_map_physical_memory(B_SYSTEM_TEAM, "local apic", &sLocalAPIC, 287 B_EXACT_ADDRESS, B_PAGE_SIZE, 288 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 289 args->arch_args.apic_phys, true) < 0) { 290 panic("mapping the local apic failed"); 291 return B_ERROR; 292 } 293 294 return B_OK; 295} 296 297 298status_t 299apic_per_cpu_init(kernel_args *args, int32 cpu) 300{ 301 if (sX2APIC) { 302 uint64 apic_base = x86_read_msr(IA32_MSR_APIC_BASE); 303 if ((apic_base & IA32_MSR_APIC_BASE_X2APIC) == 0) { 304 x86_write_msr(IA32_MSR_APIC_BASE, apic_base 305 | IA32_MSR_APIC_BASE_X2APIC); 306 } 307 } 308 309 dprintf("setting up %sapic for CPU %" B_PRId32 ": apic id %" B_PRIu32 ", " 310 "version %" B_PRIu32 "\n", sX2APIC ? "x2" : "", cpu, apic_local_id(), 311 apic_version()); 312 313 if (!sX2APIC && cpu < 8) { 314 apic_write(APIC_DEST_FORMAT, uint32(-1)); 315 316 uint8 logical_apic_id = 1 << cpu; 317 uint32 value = apic_read(APIC_LOGICAL_DEST); 318 value &= 0xffffff; 319 apic_write(APIC_LOGICAL_DEST, value | (logical_apic_id << 24)); 320 } 321 322 // get logical APIC ID 323 gCPU[cpu].arch.logical_apic_id = apic_logical_apic_id(); 324 if (!sX2APIC) 325 gCPU[cpu].arch.logical_apic_id >>= 24; 326 dprintf("CPU %" B_PRId32 ": logical apic id: %#" B_PRIx32 "\n", cpu, 327 gCPU[cpu].arch.logical_apic_id); 328 329 /* set spurious interrupt vector to 0xff */ 330 uint32 config = apic_spurious_intr_vector() & 0xffffff00; 331 config |= APIC_ENABLE | 0xff; 332 apic_set_spurious_intr_vector(config); 333 334 // don't touch the LINT0/1 configuration in virtual wire mode 335 // ToDo: implement support for other modes... 336#if 0 337 if (cpu == 0) { 338 /* setup LINT0 as ExtINT */ 339 config = (apic_read(APIC_LINT0) & 0xffff00ff); 340 config |= APIC_LVT_DM_ExtINT | APIC_LVT_IIPP | APIC_LVT_TM; 341 apic_write(APIC_LINT0, config); 342 343 /* setup LINT1 as NMI */ 344 config = (apic_read(APIC_LINT1) & 0xffff00ff); 345 config |= APIC_LVT_DM_NMI | APIC_LVT_IIPP; 346 apic_write(APIC_LINT1, config); 347 } 348 if (cpu > 0) { 349 dprintf("LINT0: %p\n", (void *)apic_read(APIC_LINT0)); 350 dprintf("LINT1: %p\n", (void *)apic_read(APIC_LINT1)); 351 352 /* disable LINT0/1 */ 353 config = apic_read(APIC_LINT0); 354 apic_write(APIC_LINT0, config | APIC_LVT_MASKED); 355 356 config = apic_read(APIC_LINT1); 357 apic_write(APIC_LINT1, config | APIC_LVT_MASKED); 358 } else { 359 dprintf("0: LINT0: %p\n", (void *)apic_read(APIC_LINT0)); 360 dprintf("0: LINT1: %p\n", (void *)apic_read(APIC_LINT1)); 361 } 362#endif 363 364 apic_timer_per_cpu_init(args, cpu); 365 366 /* setup error vector to 0xfe */ 367 config = (apic_lvt_error() & 0xffffff00) | 0xfe; 368 apic_set_lvt_error(config); 369 370 /* accept all interrupts */ 371 config = apic_task_priority() & 0xffffff00; 372 apic_set_task_priority(config); 373 374 config = apic_spurious_intr_vector(); 375 apic_end_of_interrupt(); 376 377 return B_OK; 378} 379