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