FreeNOS
IntelAPIC.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015 Niek Linnenbank
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <Log.h>
19#include <MemoryContext.h>
20#include <CoreInfo.h>
21#include <FreeNOS/System.h>
22#include "IntelPIT.h"
23#include "IntelAPIC.h"
24
25#pragma clang optimize off
26#pragma GCC push_options
27#pragma GCC optimize ("O0")
28
29#define APIC_DEST(x) ((x) << 24)
30#define APIC_DEST_FIELD 0x00000
31#define APIC_DEST_LEVELTRIG 0x08000
32#define APIC_DEST_ASSERT 0x04000
33#define APIC_DEST_DM_INIT 0x00500
34#define APIC_DEST_DM_STARTUP 0x00600
35
44
46{
47 return m_io;
48}
49
51{
52 return m_io.read(InitialCount);
53}
54
56{
57 u32 t1, t2, loops = 20;
58
59 // Start the APIC timer
61 m_io.write(InitialCount, 0xffffffff);
63
64 // Measure the speed of the APIC timer using the
65 // known absolute frequency of the PIT timer. First
66 // wait for the next PIT trigger.
67 pit->waitTrigger();
68
69 // Collect the current APIC timer counter
71
72 // Wait for several PIT triggers
73 for (uint i = 0; i < loops; i++)
74 pit->waitTrigger();
75
76 // Measure the current APIC timer counter again.
78
79 // Configure the APIC timer to run at the same frequency as the PIT.
80 m_initialCounter = (t1 - t2) / loops;
83
84 // Calculate APIC bus frequency in hertz using the known PIT
85 // frequency as reference for diagnostics.
86 u32 busFreq = m_initialCounter * 16 * pit->getFrequency();
87 NOTICE("Detected " << busFreq / 1000000 << "."
88 << busFreq % 1000000 << " Mhz APIC bus");
89 NOTICE("APIC counter set at " << m_initialCounter);
90 return Timer::Success;
91}
92
94{
95 if (!isKernel)
96 {
97 Timer::Info info;
98
99 // Get current kernel timer ticks
100 if (ProcessCtl(SELF, InfoTimer, (Address) &info) != API::Success)
101 return Timer::IOError;
102
103 // Frequency must be set
104 if (!info.frequency)
105 return Timer::IOError;
106
107 // Set time to wait (very rough approximation)
108 u32 msecPerTick = 1000.0 / info.frequency;
109 u32 msecToWait = microseconds / 1000;
110 info.ticks += (msecToWait / msecPerTick) + 1;
111
112 // Wait until the timer expires
113 if (ProcessCtl(SELF, WaitTimer, (Address) &info) != API::Success)
114 return Timer::IOError;
115 }
116 else
117 {
118 Size usecPerInt = 1000000 / m_frequency;
119 Size usecPerTick = usecPerInt / m_io.read(InitialCount);
120 u32 t1 = m_io.read(CurrentCount), t2;
121 u32 waited = 0;
122
123 while (waited < microseconds)
124 {
125 t2 = m_io.read(CurrentCount);
126 if (t2 < t1)
127 {
128 waited += (t1 - t2) * usecPerTick;
129 t1 = t2;
130 }
131 t1 = t2;
132 }
133 }
134 return Timer::Success;
135}
136
138{
139 // Set members
140 m_frequency = hertz;
141 m_initialCounter = initialCounter;
142
143 // Start the APIC timer
146 return start();
147}
148
150{
151 // Start the APIC timer
153 return Timer::Success;
154}
155
161
163{
164 // Map the registers into the address space
166 return Timer::IOError;
167
168 // Initialize and disable the timer
173
174 // Enable the APIC
176 return Timer::Success;
177}
178
183
188
194
196{
197 ulong cfg;
198
199 // Write APIC Destination
200 cfg = m_io.read(IntCommand2);
201 cfg &= 0x00ffffff;
202 m_io.write(IntCommand2, cfg | APIC_DEST(cpuId));
203
204 // Assert INIT
205 cfg = m_io.read(IntCommand1);
206 cfg &= ~0xcdfff;
209 m_io.write(IntCommand1, cfg);
210
211 // Wait 10 miliseconds
212 wait(10000);
213
214 // Send two SIPI's
215 for (Size i = 0; i < 2; i++)
216 {
217 // Write APIC Destination
218 cfg = m_io.read(IntCommand2);
219 cfg &= 0x00ffffff;
220 m_io.write(IntCommand2, cfg | APIC_DEST(cpuId));
221
222 // Assert STARTUP
223 cfg = m_io.read(IntCommand1);
224 cfg &= ~0xcdfff;
226 (addr >> 12));
227 m_io.write(IntCommand1, cfg);
228
229 // Wait 1 milisecond
230 wait(1000);
231 }
232
233 // Startup interrupt delivered.
235}
236
238{
239 ulong cfg;
240
241 // Write APIC Destination
242 cfg = m_io.read(IntCommand2);
243 cfg &= 0x00ffffff;
244 m_io.write(IntCommand2, cfg | APIC_DEST(cpuId));
245
246 // Write to lower 32-bits of Interrupt Command, which triggers the IPI.
249 cfg |= vector;
250 m_io.write(IntCommand1, cfg);
251
252 // Done
254}
#define APIC_DEST_DM_STARTUP
Definition IntelAPIC.cpp:34
#define APIC_DEST(x)
Definition IntelAPIC.cpp:29
#define APIC_DEST_ASSERT
Definition IntelAPIC.cpp:32
#define APIC_DEST_LEVELTRIG
Definition IntelAPIC.cpp:31
#define APIC_DEST_DM_INIT
Definition IntelAPIC.cpp:33
#define APIC_DEST_FIELD
Definition IntelAPIC.cpp:30
@ Success
Definition API.h:70
void setBase(const Address base)
Set memory I/O base offset.
Definition IO.cpp:33
Result map(Address phys, Size size=4096, Memory::Access access=Memory::Readable|Memory::Writable|Memory::User)
Map I/O address space.
Definition IO.cpp:38
@ Success
Definition IO.h:44
Interrupt controller interface.
Result
Result codes.
virtual IntController::Result enable(uint irq)
Enable hardware interrupt (IRQ).
virtual Timer::Result initialize()
Initialize the APIC.
virtual IntController::Result disable(uint irq)
Disable hardware interrupt (IRQ).
IntelAPIC()
Constructor.
Definition IntelAPIC.cpp:36
virtual Timer::Result wait(u32 microseconds) const
Busy wait a number of microseconds.
Definition IntelAPIC.cpp:93
virtual Timer::Result stop()
Stop the APIC timer.
uint m_initialCounter
Saved initial counter value for APIC timer.
Definition IntelAPIC.h:237
virtual Timer::Result start()
(Re)start the APIC timer.
IntController::Result sendStartupIPI(uint cpuId, Address addr)
Send startup Intercore-Processor-Interrupt.
IntController::Result sendIPI(uint coreId, uint vector)
Send Intercore-Processor-Interrupt.
IntelIO & getIO()
Get I/O object.
Definition IntelAPIC.cpp:45
static const uint IOBase
APIC memory mapped I/O register base offset (physical address).
Definition IntelAPIC.h:52
static const uint TimerVector
APIC timer interrupt vector is fixed at 48.
Definition IntelAPIC.h:55
virtual IntController::Result clear(uint irq)
Clear hardware interrupt (IRQ).
uint getCounter() const
Get timer initial counter.
Definition IntelAPIC.cpp:50
IntelIO m_io
I/O object.
Definition IntelAPIC.h:234
@ DivideConfig
Definition IntelAPIC.h:85
@ InitialCount
Definition IntelAPIC.h:83
@ IntCommand1
Definition IntelAPIC.h:75
@ IntCommand2
Definition IntelAPIC.h:76
@ EndOfInterrupt
Definition IntelAPIC.h:69
@ CurrentCount
Definition IntelAPIC.h:84
@ SpuriousIntVec
Definition IntelAPIC.h:70
Intel I/O functions.
Definition IntelIO.h:39
void set(Address addr, u32 data)
Set bits in memory mapped register.
Definition IntelIO.h:188
void write(const Address addr, const u32 data)
Write memory mapped register.
Definition IntelIO.h:161
u32 read(const Address addr) const
Read memory mapped register.
Definition IntelIO.h:134
Intel 8254 Programmable Interrupt Timer (PIT).
Definition IntelPIT.h:41
Result waitTrigger()
Busy wait for one trigger period.
Definition IntelPIT.cpp:58
Represents a configurable timer device.
Definition Timer.h:36
Size getFrequency() const
Get timer frequency.
Definition Timer.cpp:33
Size m_int
Timer interrupt number.
Definition Timer.h:165
Result
Result codes.
Definition Timer.h:53
@ Success
Definition Timer.h:54
@ IOError
Definition Timer.h:56
Size m_frequency
Frequency of the Timer.
Definition Timer.h:162
#define SELF
Definition ProcessID.h:35
API::Result ProcessCtl(const ProcessID proc, const ProcessOperation op, const Address addr=0, const Address output=0)
Prototype for user applications.
Definition ProcessCtl.h:93
@ WaitTimer
Definition ProcessCtl.h:50
@ InfoTimer
Definition ProcessCtl.h:49
C uint isKernel
Non-zero if this executable is linked as the kernel.
unsigned int u32
Unsigned 32-bit number.
Definition Types.h:53
unsigned long Address
A memory address.
Definition Types.h:131
#define NOTICE(msg)
Output a notice message.
Definition Log.h:75
unsigned long ulong
Unsigned long number.
Definition Types.h:47
unsigned int uint
Unsigned integer number.
Definition Types.h:44
unsigned int Size
Any sane size indicator cannot go negative.
Definition Types.h:128
Timer information structure.
Definition Timer.h:43
u32 ticks
Definition Timer.h:44
Size frequency
Definition Timer.h:45