Max OS 0.3
Loading...
Searching...
No Matches
clock.cpp
Go to the documentation of this file.
1
10#include <common/logger.h>
11
12using namespace MaxOS;
13using namespace MaxOS::common;
14using namespace MaxOS::hardwarecommunication;
15
22Clock::Clock(AdvancedProgrammableInterruptController* apic, uint16_t time_between_events)
23: InterruptHandler(0x20),
24 m_apic(apic),
25 m_ticks_between_events(time_between_events)
26{
27 Logger::INFO() << "Setting up Clock \n";
28
29 s_active_clock = this;
30
31 // Get the stats from the clock
32 uint8_t status = read_hardware_clock(0xB);
33
34 // Store the clock status
35 m_24_hour_clock = status & 0x02;
36 m_binary = status & 0x04;
37}
38
39Clock::~Clock() = default;
40
45void Clock::handle_interrupt() {
46
47 // Clock has ticked
48 m_ticks++;
49 m_ticks_until_next_event--;
50
51 // Dont raise events until needed
52 if (m_ticks_until_next_event != 0)
53 return;
54
55 // Raise the time event
56// Time time = get_time();
57// raise_event(new TimeEvent(&time));
58
59 // Reset
60 m_ticks_until_next_event = m_ticks_between_events;
61}
62
63
70uint8_t Clock::read_hardware_clock(uint8_t address) {
71
72 m_command_port.write(address);
73 return m_data_port.read();
74}
75
82uint8_t Clock::binary_representation(uint8_t number) const {
83
84 // Check if the conversion needed
85 if (m_binary)
86 return number;
87
88 // Convert to the binary representation
89 return ((number / 16) * 10) + (number & 0x0f);
90}
91
102void Clock::delay(uint32_t milliseconds) const {
103
104 // Round the number of milliseconds UP to the nearest clock accuracy
105 uint64_t rounded_milliseconds = (milliseconds + clock_accuracy - 1) / clock_accuracy;
106
107 // Wait until the time has passed
108 uint64_t ticks_until_delay_is_over = m_ticks + rounded_milliseconds;
109 while (m_ticks < ticks_until_delay_is_over)
110 asm volatile("nop");
111}
112
118void Clock::calibrate(uint64_t ms_per_tick) {
119
120 Logger::INFO() << "Calibrating Clock \n";
121 clock_accuracy = ms_per_tick;
122
123 // Get the ticks per ms
124 PIT pit(m_apic);
125 m_pit_ticks_per_ms = pit.ticks_per_ms();
126
127 // Calibrate the BSP apic to the desired time
128 setup_apic_clock(m_apic->local_apic());
129
130 Logger::DEBUG() << "Clock: Calibrated to " << ms_per_tick << "ms per kernel tick\n";
131}
132
138
139 // Configure the clock to periodic mode
140 uint32_t lvt = 0x20 | (1 << 17);
141 local_apic->write(0x320, lvt);
142
143 // Set the initial count
144 local_apic->write(0x380, m_pit_ticks_per_ms * clock_accuracy);
145
146 // Clear the interrupt mask for the clock
147 lvt &= ~(1 << 16);
148 local_apic->write(0x320, lvt);
149}
150
156common::time_t Clock::get_time() {
157
158 // Wait for the clock to be ready
159 while (read_hardware_clock(0xA) & 0x80)
160 asm volatile("nop");
161
162 // Read the time from the clock
163 time_t time{};
164 time.year = binary_representation(read_hardware_clock(0x9)) + 2000;
165 time.month = binary_representation(read_hardware_clock(0x8));
166 time.day = binary_representation(read_hardware_clock(0x7));
167 time.hour = binary_representation(read_hardware_clock(0x4));
168 time.minute = binary_representation(read_hardware_clock(0x2));
169 time.second = binary_representation(read_hardware_clock(0x0));
170
171 // If the clock is using 12hr format and PM is set then add 12 to the hour
172 if (!m_24_hour_clock && (time.hour & 0x80) != 0)
173 time.hour = ((time.hour & 0x7F) + 12) % 24;
174
175 return time;
176}
177
183 return s_active_clock;
184}
185
191: InterruptHandler(0x22),
192 m_data_port(0x40),
193 m_command_port(0x43),
194 m_local_apic(apic->local_apic()),
195 m_io_apic(apic->io_apic())
196{
197
198}
199
200PIT::~PIT() = default;
201
205void PIT::handle_interrupt() {
206 m_ticks++;
207}
208
214uint32_t PIT::ticks_per_ms() {
215
216 // Set the redirect for the timer interrupt
217 interrupt_redirect_t redirect = {
218 .type = 0x2,
219 .index = 0x14,
220 .interrupt = 0x22,
221 .destination = 0x00,
222 .flags = 0x00,
223 .mask = true,
224 };
225 m_io_apic->set_redirect(&redirect);
226
227 // Configure the PIT clock
228 pit_command_t command = {
229 .bcd_mode = (uint8_t) BCDMode::BINARY,
230 .operating_mode = (uint8_t) OperatingMode::RATE_GENERATOR,
231 .access_mode = (uint8_t) AccessMode::LOW_HIGH_BYTE,
232 .channel = (uint8_t) Channel::INTERRUPT
233 };
234 m_command_port.write(*(uint8_t *) &command);
235
236 // Set the clock rate to 1 ms;
237 uint16_t rate = 1193182 / 1000;
238 m_data_port.write(rate & 0xFF);
239 m_data_port.write(rate >> 8);
240
241 // Stop the clock
242 m_local_apic->write(0x380, 0x00);
243
244 // Set the divisor to 2
245 m_local_apic->write(0x3E0, 0x0);
246
247 // Unmask the PIT interrupt
248 m_io_apic->set_redirect_mask(redirect.index, false);
249
250 // Calculate the number of ticks in 1 ms
251 auto max = (uint32_t) -1;
252 m_local_apic->write(0x380, max);
253
254 while (m_ticks < TICK_CALIBRATE_LENGTH)
255 asm volatile("nop");
256
257 uint32_t elapsed = max - (m_local_apic->read(0x390));
258 uint32_t ticks_per_ms = elapsed / TICK_CALIBRATE_LENGTH;
259
260 Logger::DEBUG() << "Ticks per ms: " << (int) ticks_per_ms << "\n";
261
262 // Disable the PIT interrupt again
263 m_local_apic->write(0x380, 0x00);
264 m_io_apic->set_redirect_mask(redirect.index, true);
265
266 return ticks_per_ms;
267}
static LogRecord DEBUG()
Gets the active logger for debug logs.
Definition logger.cpp:204
static LogRecord INFO()
Gets the active logger for info logs.
Definition logger.cpp:195
Handles both the Local APIC (boot core) and IO APIC.
Definition apic.h:240
Driver for the APIC clock.
Definition clock.h:124
common::time_t get_time()
Reads the current time from the APIC clock (in 24hr time)
Definition clock.cpp:156
uint64_t clock_accuracy
How accurate the clock is in microseconds (how often should an interrupt be raised)
Definition clock.h:156
Clock(AdvancedProgrammableInterruptController *apic, uint16_t time_between_events=10)
Constructor for the Clock class.
Definition clock.cpp:22
void setup_apic_clock(LocalAPIC *local_apic) const
Sets up the APIC clock to fire interrupts at the desired rate.
Definition clock.cpp:137
void delay(uint32_t milliseconds) const
Delays the program for a specified number of milliseconds (rounded up to the nearest degree of accura...
Definition clock.cpp:102
static Clock * active_clock()
Gets the currently active clock.
Definition clock.cpp:182
void calibrate(uint64_t ms_per_tick=1)
Configures the APIC clock to fire an interrupt at a specified interval in milliseconds.
Definition clock.cpp:118
void set_redirect(interrupt_redirect_t *redirect)
Redirect a system interrupt to a different IRQ.
Definition apic.cpp:412
void set_redirect_mask(uint8_t index, bool mask)
Enables/Disables an interrupt redirect by masking it.
Definition apic.cpp:446
Handles a certain interrupt number.
Definition interrupts.h:44
Handles the local APIC for the current core.
Definition apic.h:34
void write(uint32_t reg, uint32_t value) const
write a value to the apic register using the MSR or memory I/O depending on the local apic version
Definition apic.cpp:91
uint32_t read(uint32_t reg) const
read a value from the apic register using the MSR or memory I/O depending on the local apic version
Definition apic.cpp:76
Driver for the Programmable Interval Timer.
Definition clock.h:96
PIT(AdvancedProgrammableInterruptController *apic)
Constructor for the PIT class. Registers a handler for interrupt 0x22 and initialises ports.
Definition clock.cpp:190
Defines drivers for the Programmable Interval Timer (PIT) and APIC Clock.
constexpr uint16_t TICK_CALIBRATE_LENGTH
How many loops to spin for calibration.
Definition clock.h:90
Defines a Logger class for logging messages with different severity levels to multiple output streams...
Defines how an interrupt input is redirected to a specific processor via the I/O APIC.
Definition apic.h:174
uint8_t index
Where in the IO APIC redirection table this redirect should be placed.
Definition apic.h:177
uint8_t type
The type of redirect (should be 0 for normal interrupts)
Definition apic.h:176
The command byte to send to the PIT, specifies the channel, access mode, operating mode and BCD mode.
Definition clock.h:76
uint8_t bcd_mode
0 = binary, 1 = BCD
Definition clock.h:78