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