blob: 7f2940c196724b3e16cfb3c06641c55b0befd402 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
#include "types.h"
#include "mp.h"
#include "defs.h"
#include "param.h"
#include "x86.h"
#include "traps.h"
#include "mmu.h"
#include "proc.h"
#include "lapic.h"
// Local APIC registers, divided by 4 for use as uint[] indices.
#define ID (0x0020/4) // ID
#define VER (0x0030/4) // Version
#define TPR (0x0080/4) // Task Priority
#define APR (0x0090/4) // Arbitration Priority
#define PPR (0x00A0/4) // Processor Priority
#define EOI (0x00B0/4) // EOI
#define LDR (0x00D0/4) // Logical Destination
#define DFR (0x00E0/4) // Destination Format
#define SVR (0x00F0/4) // Spurious Interrupt Vector
#define ISR (0x0100/4) // Interrupt Status (8 registers)
#define TMR (0x0180/4) // Trigger Mode (8 registers)
#define IRR (0x0200/4) // Interrupt Request (8 registers)
#define ESR (0x0280/4) // Error Status
#define ICRLO (0x0300/4) // Interrupt Command
#define ICRHI (0x0310/4) // Interrupt Command [63:32]
#define TIMER (0x0320/4) // Local Vector Table 0 (TIMER)
#define PCINT (0x0340/4) // Performance Counter LVT
#define LINT0 (0x0350/4) // Local Vector Table 1 (LINT0)
#define LINT1 (0x0360/4) // Local Vector Table 2 (LINT1)
#define ERROR (0x0370/4) // Local Vector Table 3 (ERROR)
#define TICR (0x0380/4) // Timer Initial Count
#define TCCR (0x0390/4) // Timer Current Count
#define TDCR (0x03E0/4) // Timer Divide Configuration
// SVR
#define ENABLE 0x00000100 // Unit Enable
#define FOCUS 0x00000200 // Focus Processor Checking Disable
// ICRLO
// [14] IPI Trigger Mode Level (RW)
#define DEASSERT 0x00000000 // Deassert level-sensitive interrupt
#define ASSERT 0x00004000 // Assert level-sensitive interrupt
// [17:16] Remote Read Status
#define INVALID 0x00000000 // Invalid
#define WAIT 0x00010000 // In-Progress
#define VALID 0x00020000 // Valid
// [19:18] Destination Shorthand
#define FIELD 0x00000000 // No shorthand
#define SELF 0x00040000 // Self is single destination
#define ALLINC 0x00080000 // All including self
#define ALLEXC 0x000C0000 // All Excluding self
// ESR
#define SENDCS 0x00000001 // Send CS Error
#define RCVCS 0x00000002 // Receive CS Error
#define SENDACCEPT 0x00000004 // Send Accept Error
#define RCVACCEPT 0x00000008 // Receive Accept Error
#define SENDVECTOR 0x00000020 // Send Illegal Vector
#define RCVVECTOR 0x00000040 // Receive Illegal Vector
#define REGISTER 0x00000080 // Illegal Register Address
// [17] Timer Mode (RW)
#define ONESHOT 0x00000000 // One-shot
#define PERIODIC 0x00020000 // Periodic
// [19:18] Timer Base (RW)
#define CLKIN 0x00000000 // use CLKIN as input
#define TMBASE 0x00040000 // use TMBASE
#define DIVIDER 0x00080000 // use output of the divider
#define X2 0x00000000 // divide by 2
#define X4 0x00000001 // divide by 4
#define X8 0x00000002 // divide by 8
#define X16 0x00000003 // divide by 16
#define X32 0x00000008 // divide by 32
#define X64 0x00000009 // divide by 64
#define X128 0x0000000A // divide by 128
#define X1 0x0000000B // divide by 1
//PAGEBREAK!
volatile uint *lapic; // Initialized in mp.c
void
lapic_init(int c)
{
uint r, lvt;
if(!lapic)
return;
lapic[DFR] = 0xFFFFFFFF; // Set dst format register
r = (lapic[ID]>>24) & 0xFF; // Read APIC ID
lapic[LDR] = (1<<r) << 24;
lapic[TPR] = 0xFF; // No interrupts for now
// Enable APIC
lapic[SVR] = ENABLE | (IRQ_OFFSET+IRQ_SPURIOUS);
// In virtual wire mode, set up the LINT0 and LINT1 as follows:
lapic[LINT0] = APIC_IMASK | APIC_EXTINT;
lapic[LINT1] = APIC_IMASK | APIC_NMI;
lapic[EOI] = 0; // Ack any outstanding interrupts.
lvt = (lapic[VER]>>16) & 0xFF;
if(lvt >= 4)
lapic[PCINT] = APIC_IMASK;
lapic[ERROR] = IRQ_OFFSET+IRQ_ERROR;
lapic[ESR] = 0;
lapic[ESR];
// Issue an INIT Level De-Assert to synchronise arbitration ID's.
lapic[ICRHI] = 0;
lapic[ICRLO] = ALLINC | APIC_LEVEL |
DEASSERT | APIC_INIT;
while(lapic[ICRLO] & APIC_DELIVS)
;
// Initialize the interrupt timer.
// On real hardware would need to do more XXX.
lapic[TDCR] = X1;
lapic[TIMER] = CLKIN | PERIODIC | (IRQ_OFFSET + IRQ_TIMER);
lapic[TCCR] = 10000000;
lapic[TICR] = 10000000;
// Enable interrupts on the APIC (but not on processor).
lapic[TPR] = 0;
}
int
cpu(void)
{
if(lapic)
return lapic[ID]>>24;
return 0;
}
// Acknowledge interrupt.
void
lapic_eoi(void)
{
if(lapic)
lapic[EOI] = 0;
}
// Start additional processor running bootstrap code at addr.
void
lapic_startap(uchar apicid, uint addr)
{
int i;
volatile int j = 0;
lapic[ICRHI] = apicid<<24;
lapic[ICRLO] = FIELD | APIC_LEVEL | ASSERT | APIC_INIT;
for(j=0; j<10000; j++); // 200us
lapic[ICRLO] = FIELD | APIC_LEVEL | DEASSERT | APIC_INIT;
for(j=0; j<1000000; j++); // 10ms
for(i = 0; i < 2; i++){
lapic[ICRHI] = apicid<<24;
lapic[ICRLO] = FIELD | APIC_EDGE | APIC_STARTUP | (addr/4096);
for(j=0; j<10000; j++); // 200us
}
}
|