1 #include "types.h" 2 #include "mp.h" 3 #include "defs.h" 4 #include "param.h" 5 #include "x86.h" 6 #include "traps.h" 7 #include "mmu.h" 8 #include "proc.h" 9 10 enum { // Local APIC registers 11 LAPIC_ID = 0x0020, // ID 12 LAPIC_VER = 0x0030, // Version 13 LAPIC_TPR = 0x0080, // Task Priority 14 LAPIC_APR = 0x0090, // Arbitration Priority 15 LAPIC_PPR = 0x00A0, // Processor Priority 16 LAPIC_EOI = 0x00B0, // EOI 17 LAPIC_LDR = 0x00D0, // Logical Destination 18 LAPIC_DFR = 0x00E0, // Destination Format 19 LAPIC_SVR = 0x00F0, // Spurious Interrupt Vector 20 LAPIC_ISR = 0x0100, // Interrupt Status (8 registers) 21 LAPIC_TMR = 0x0180, // Trigger Mode (8 registers) 22 LAPIC_IRR = 0x0200, // Interrupt Request (8 registers) 23 LAPIC_ESR = 0x0280, // Error Status 24 LAPIC_ICRLO = 0x0300, // Interrupt Command 25 LAPIC_ICRHI = 0x0310, // Interrupt Command [63:32] 26 LAPIC_TIMER = 0x0320, // Local Vector Table 0 (TIMER) 27 LAPIC_PCINT = 0x0340, // Performance Counter LVT 28 LAPIC_LINT0 = 0x0350, // Local Vector Table 1 (LINT0) 29 LAPIC_LINT1 = 0x0360, // Local Vector Table 2 (LINT1) 30 LAPIC_ERROR = 0x0370, // Local Vector Table 3 (ERROR) 31 LAPIC_TICR = 0x0380, // Timer Initial Count 32 LAPIC_TCCR = 0x0390, // Timer Current Count 33 LAPIC_TDCR = 0x03E0, // Timer Divide Configuration 34 }; 35 36 enum { // LAPIC_SVR 37 LAPIC_ENABLE = 0x00000100, // Unit Enable 38 LAPIC_FOCUS = 0x00000200, // Focus Processor Checking Disable 39 }; 40 41 enum { // LAPIC_ICRLO 42 // [14] IPI Trigger Mode Level (RW) 43 LAPIC_DEASSERT = 0x00000000, // Deassert level-sensitive interrupt 44 LAPIC_ASSERT = 0x00004000, // Assert level-sensitive interrupt 45 46 // [17:16] Remote Read Status 47 LAPIC_INVALID = 0x00000000, // Invalid 48 LAPIC_WAIT = 0x00010000, // In-Progress 49 LAPIC_VALID = 0x00020000, // Valid 50 51 // [19:18] Destination Shorthand 52 LAPIC_FIELD = 0x00000000, // No shorthand 53 LAPIC_SELF = 0x00040000, // Self is single destination 54 LAPIC_ALLINC = 0x00080000, // All including self 55 LAPIC_ALLEXC = 0x000C0000, // All Excluding self 56 }; 57 58 enum { // LAPIC_ESR 59 LAPIC_SENDCS = 0x00000001, // Send CS Error 60 LAPIC_RCVCS = 0x00000002, // Receive CS Error 61 LAPIC_SENDACCEPT = 0x00000004, // Send Accept Error 62 LAPIC_RCVACCEPT = 0x00000008, // Receive Accept Error 63 LAPIC_SENDVECTOR = 0x00000020, // Send Illegal Vector 64 LAPIC_RCVVECTOR = 0x00000040, // Receive Illegal Vector 65 LAPIC_REGISTER = 0x00000080, // Illegal Register Address 66 }; 67 68 enum { // LAPIC_TIMER 69 // [17] Timer Mode (RW) 70 LAPIC_ONESHOT = 0x00000000, // One-shot 71 LAPIC_PERIODIC = 0x00020000, // Periodic 72 73 // [19:18] Timer Base (RW) 74 LAPIC_CLKIN = 0x00000000, // use CLKIN as input 75 LAPIC_TMBASE = 0x00040000, // use TMBASE 76 LAPIC_DIVIDER = 0x00080000, // use output of the divider 77 }; 78 79 enum { // LAPIC_TDCR 80 LAPIC_X2 = 0x00000000, // divide by 2 81 LAPIC_X4 = 0x00000001, // divide by 4 82 LAPIC_X8 = 0x00000002, // divide by 8 83 LAPIC_X16 = 0x00000003, // divide by 16 84 LAPIC_X32 = 0x00000008, // divide by 32 85 LAPIC_X64 = 0x00000009, // divide by 64 86 LAPIC_X128 = 0x0000000A, // divide by 128 87 LAPIC_X1 = 0x0000000B, // divide by 1 88 }; 89 90 uint *lapicaddr; 91 92 static int 93 lapic_read(int r) 94 { 95 return *(lapicaddr+(r/sizeof(*lapicaddr))); 96 } 97 98 static void 99 lapic_write(int r, int data) 100 { 101 *(lapicaddr+(r/sizeof(*lapicaddr))) = data; 102 } 103 104 105 void 106 lapic_timerinit(void) 107 { 108 if (!lapicaddr) 109 return; 110 111 lapic_write(LAPIC_TDCR, LAPIC_X1); 112 lapic_write(LAPIC_TIMER, LAPIC_CLKIN | LAPIC_PERIODIC | 113 (IRQ_OFFSET + IRQ_TIMER)); 114 lapic_write(LAPIC_TCCR, 10000000); 115 lapic_write(LAPIC_TICR, 10000000); 116 } 117 118 void 119 lapic_timerintr(void) 120 { 121 if (lapicaddr) 122 lapic_write(LAPIC_EOI, 0); 123 } 124 125 void 126 lapic_init(int c) 127 { 128 uint r, lvt; 129 130 if (!lapicaddr) 131 return; 132 133 lapic_write(LAPIC_DFR, 0xFFFFFFFF); // Set dst format register 134 r = (lapic_read(LAPIC_ID)>>24) & 0xFF; // Read APIC ID 135 lapic_write(LAPIC_LDR, (1<<r)<<24); // Set logical dst register to r 136 lapic_write(LAPIC_TPR, 0xFF); // No interrupts for now 137 138 // Enable APIC 139 lapic_write(LAPIC_SVR, LAPIC_ENABLE|(IRQ_OFFSET+IRQ_SPURIOUS)); 140 141 // In virtual wire mode, set up the LINT0 and LINT1 as follows: 142 lapic_write(LAPIC_LINT0, APIC_IMASK | APIC_EXTINT); 143 lapic_write(LAPIC_LINT1, APIC_IMASK | APIC_NMI); 144 145 lapic_write(LAPIC_EOI, 0); // Ack any outstanding interrupts. 146 147 lvt = (lapic_read(LAPIC_VER)>>16) & 0xFF; 148 if(lvt >= 4) 149 lapic_write(LAPIC_PCINT, APIC_IMASK); 150 lapic_write(LAPIC_ERROR, IRQ_OFFSET+IRQ_ERROR); 151 lapic_write(LAPIC_ESR, 0); 152 lapic_read(LAPIC_ESR); 153 154 // Issue an INIT Level De-Assert to synchronise arbitration ID's. 155 lapic_write(LAPIC_ICRHI, 0); 156 lapic_write(LAPIC_ICRLO, LAPIC_ALLINC|APIC_LEVEL| 157 LAPIC_DEASSERT|APIC_INIT); 158 while(lapic_read(LAPIC_ICRLO) & APIC_DELIVS) 159 ; 160 } 161 162 void 163 lapic_enableintr(void) 164 { 165 if (lapicaddr) 166 lapic_write(LAPIC_TPR, 0); 167 } 168 169 void 170 lapic_disableintr(void) 171 { 172 if (lapicaddr) 173 lapic_write(LAPIC_TPR, 0xFF); 174 } 175 176 void 177 lapic_eoi(void) 178 { 179 if (lapicaddr) 180 lapic_write(LAPIC_EOI, 0); 181 } 182 183 int 184 cpu(void) 185 { 186 int x; 187 if (lapicaddr) 188 x = (lapic_read(LAPIC_ID)>>24) & 0xFF; 189 else 190 x = 0; 191 return x; 192 } 193 194 void 195 lapic_startap(uchar apicid, int v) 196 { 197 int crhi, i; 198 volatile int j = 0; 199 200 crhi = apicid<<24; 201 lapic_write(LAPIC_ICRHI, crhi); 202 lapic_write(LAPIC_ICRLO, LAPIC_FIELD|APIC_LEVEL| 203 LAPIC_ASSERT|APIC_INIT); 204 205 while(j++ < 10000) {;} 206 lapic_write(LAPIC_ICRLO, LAPIC_FIELD|APIC_LEVEL| 207 LAPIC_DEASSERT|APIC_INIT); 208 209 while(j++ < 1000000) {;} 210 211 // in p9 code, this was i < 2, which is what the spec says on page B-3 212 for(i = 0; i < 1; i++){ 213 lapic_write(LAPIC_ICRHI, crhi); 214 lapic_write(LAPIC_ICRLO, LAPIC_FIELD|APIC_EDGE|APIC_STARTUP|(v/4096)); 215 while(j++ < 100000) {;} 216 } 217 } 218