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 uint32 43 apic_read(uint32 offset) 44 { 45 return *(volatile uint32 *)((char *)sLocalAPIC + offset); 46 } 47 48 49 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 = 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 173 bool 174 apic_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 183 uint32 184 apic_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 193 void 194 apic_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 203 uint32 204 apic_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 213 void 214 apic_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 223 uint32 224 apic_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 233 void 234 apic_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 243 uint32 244 apic_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 253 void 254 apic_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 263 status_t 264 apic_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 298 status_t 299 apic_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