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 <vm/vm.h> 17 18 #include "timers/apic_timer.h" 19 20 21 static void *sLocalAPIC = NULL; 22 23 24 bool 25 apic_available() 26 { 27 return sLocalAPIC != NULL; 28 } 29 30 31 uint32 32 apic_read(uint32 offset) 33 { 34 return *(volatile uint32 *)((char *)sLocalAPIC + offset); 35 } 36 37 38 void 39 apic_write(uint32 offset, uint32 data) 40 { 41 *(volatile uint32 *)((char *)sLocalAPIC + offset) = data; 42 } 43 44 45 uint32 46 apic_local_id() 47 { 48 return (apic_read(APIC_ID) & 0xffffffff) >> 24; 49 } 50 51 52 void 53 apic_end_of_interrupt() 54 { 55 apic_write(APIC_EOI, 0); 56 } 57 58 59 void 60 apic_disable_local_ints() 61 { 62 // just clear them out completely 63 apic_write(APIC_LVT_LINT0, APIC_LVT_MASKED); 64 apic_write(APIC_LVT_LINT1, APIC_LVT_MASKED); 65 } 66 67 68 status_t 69 apic_init(kernel_args *args) 70 { 71 if (args->arch_args.apic == NULL) 72 return B_NO_INIT; 73 74 sLocalAPIC = args->arch_args.apic; 75 dprintf("mapping local apic at %p\n", sLocalAPIC); 76 if (vm_map_physical_memory(B_SYSTEM_TEAM, "local apic", &sLocalAPIC, 77 B_EXACT_ADDRESS, B_PAGE_SIZE, 78 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 79 args->arch_args.apic_phys, true) < 0) { 80 panic("mapping the local apic failed"); 81 return B_ERROR; 82 } 83 84 return B_OK; 85 } 86 87 88 status_t 89 apic_per_cpu_init(kernel_args *args, int32 cpu) 90 { 91 dprintf("setting up apic for CPU %" B_PRId32 ": apic id %" B_PRIu32 ", " 92 "version %" B_PRIu32 "\n", cpu, apic_local_id(), 93 apic_read(APIC_VERSION)); 94 95 /* set spurious interrupt vector to 0xff */ 96 uint32 config = apic_read(APIC_SPURIOUS_INTR_VECTOR) & 0xffffff00; 97 config |= APIC_ENABLE | 0xff; 98 apic_write(APIC_SPURIOUS_INTR_VECTOR, config); 99 100 // don't touch the LINT0/1 configuration in virtual wire mode 101 // ToDo: implement support for other modes... 102 #if 0 103 if (cpu == 0) { 104 /* setup LINT0 as ExtINT */ 105 config = (apic_read(APIC_LINT0) & 0xffff00ff); 106 config |= APIC_LVT_DM_ExtINT | APIC_LVT_IIPP | APIC_LVT_TM; 107 apic_write(APIC_LINT0, config); 108 109 /* setup LINT1 as NMI */ 110 config = (apic_read(APIC_LINT1) & 0xffff00ff); 111 config |= APIC_LVT_DM_NMI | APIC_LVT_IIPP; 112 apic_write(APIC_LINT1, config); 113 } 114 if (cpu > 0) { 115 dprintf("LINT0: %p\n", (void *)apic_read(APIC_LINT0)); 116 dprintf("LINT1: %p\n", (void *)apic_read(APIC_LINT1)); 117 118 /* disable LINT0/1 */ 119 config = apic_read(APIC_LINT0); 120 apic_write(APIC_LINT0, config | APIC_LVT_MASKED); 121 122 config = apic_read(APIC_LINT1); 123 apic_write(APIC_LINT1, config | APIC_LVT_MASKED); 124 } else { 125 dprintf("0: LINT0: %p\n", (void *)apic_read(APIC_LINT0)); 126 dprintf("0: LINT1: %p\n", (void *)apic_read(APIC_LINT1)); 127 } 128 #endif 129 130 apic_timer_per_cpu_init(args, cpu); 131 132 /* setup error vector to 0xfe */ 133 config = (apic_read(APIC_LVT_ERROR) & 0xffffff00) | 0xfe; 134 apic_write(APIC_LVT_ERROR, config); 135 136 /* accept all interrupts */ 137 config = apic_read(APIC_TASK_PRIORITY) & 0xffffff00; 138 apic_write(APIC_TASK_PRIORITY, config); 139 140 config = apic_read(APIC_SPURIOUS_INTR_VECTOR); 141 apic_end_of_interrupt(); 142 143 return B_OK; 144 } 145