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;
15using namespace MaxOS::drivers;
16using namespace MaxOS::drivers::clock;
17
25: InterruptHandler(0x20),
26 m_apic(apic),
27 m_ticks_between_events(time_between_events)
28{
29 Logger::INFO() << "Setting up Clock \n";
30}
31
32Clock::~Clock() = default;
33
38void Clock::handle_interrupt() {
39
40 // Clock has ticked
41 m_ticks++;
42 m_ticks_until_next_event--;
43
44 // Dont raise events until needed
45 if (m_ticks_until_next_event != 0)
46 return;
47
48 // Raise the time event
49// Time time = get_time();
50// raise_event(new TimeEvent(&time));
51
52 // Reset
53 m_ticks_until_next_event = m_ticks_between_events;
54}
55
56
63uint8_t Clock::read_hardware_clock(uint8_t address) {
64
65 m_command_port.write(address);
66 return m_data_port.read();
67}
68
75uint8_t Clock::binary_representation(uint8_t number) const {
76
77 // Check if the conversion needed
78 if (m_binary)
79 return number;
80
81 // Convert to the binary representation
82 return ((number / 16) * 10) + (number & 0x0f);
83}
84
89
90 s_active_clock = this;
91
92 // Get the stats from the clock
93 uint8_t status = read_hardware_clock(0xB);
94
95 // Store the clock status
96 m_24_hour_clock = status & 0x02;
97 m_binary = status & 0x04;
98}
99
111
112 // Round the number of milliseconds UP to the nearest clock accuracy
114
115 // Wait until the time has passed
117 while (m_ticks < ticks_until_delay_is_over)
118 asm volatile("nop");
119}
120
127 return "Generic";
128}
129
136 return "Clock";
137}
138
145
146 Logger::INFO() << "Calibrating Clock \n";
148
149 // Get the ticks per ms
150 PIT pit(m_apic);
151 m_pit_ticks_per_ms = pit.ticks_per_ms();
152
153 // Calibrate the BSP apic to the desired time
154 setup_apic_clock(m_apic->local_apic());
155
156 Logger::DEBUG() << "Clock: Calibrated to " << ms_per_tick << "ms per kernel tick\n";
157}
158
164
165 // Configure the clock to periodic mode
166 uint32_t lvt = 0x20 | (1 << 17);
167 local_apic->write(0x320, lvt);
168
169 // Set the initial count
170 local_apic->write(0x380, m_pit_ticks_per_ms * clock_accuracy);
171
172 // Clear the interrupt mask for the clock
173 lvt &= ~(1 << 16);
174 local_apic->write(0x320, lvt);
175}
176
183
184 // Wait for the clock to be ready
185 while (read_hardware_clock(0xA) & 0x80)
186 asm volatile("nop");
187
188 // Read the time from the clock
189 time_t time{};
190 time.year = binary_representation(read_hardware_clock(0x9)) + 2000;
191 time.month = binary_representation(read_hardware_clock(0x8));
192 time.day = binary_representation(read_hardware_clock(0x7));
193 time.hour = binary_representation(read_hardware_clock(0x4));
194 time.minute = binary_representation(read_hardware_clock(0x2));
195 time.second = binary_representation(read_hardware_clock(0x0));
196
197 // If the clock is using 12hr format and PM is set then add 12 to the hour
198 if (!m_24_hour_clock && (time.hour & 0x80) != 0)
199 time.hour = ((time.hour & 0x7F) + 12) % 24;
200
201 return time;
202}
203
209 return s_active_clock;
210}
211
217: InterruptHandler(0x22),
218 m_data_port(0x40),
219 m_command_port(0x43),
220 m_local_apic(apic->local_apic()),
221 m_io_apic(apic->io_apic())
222{
223
224}
225
226PIT::~PIT() = default;
227
231void PIT::handle_interrupt() {
232 m_ticks++;
233}
234
240uint32_t PIT::ticks_per_ms() {
241
242 // Set the redirect for the timer interrupt
244 .type = 0x2,
245 .index = 0x14,
246 .interrupt = 0x22,
247 .destination = 0x00,
248 .flags = 0x00,
249 .mask = true,
250 };
251 m_io_apic->set_redirect(&redirect);
252
253 // Configure the PIT clock
254 pit_command_t command = {
255 .bcd_mode = (uint8_t) BCDMode::BINARY,
256 .operating_mode = (uint8_t) OperatingMode::RATE_GENERATOR,
257 .access_mode = (uint8_t) AccessMode::LOW_HIGH_BYTE,
258 .channel = (uint8_t) Channel::INTERRUPT
259 };
260 m_command_port.write(*(uint8_t *) &command);
261
262 // Set the clock rate to 1 ms;
263 uint16_t rate = 1193182 / 1000;
264 m_data_port.write(rate & 0xFF);
265 m_data_port.write(rate >> 8);
266
267 // Stop the clock
268 m_local_apic->write(0x380, 0x00);
269
270 // Set the divisor to 2
271 m_local_apic->write(0x3E0, 0x0);
272
273 // Unmask the PIT interrupt
274 m_io_apic->set_redirect_mask(redirect.index, false);
275
276 // Calculate the number of ticks in 1 ms
277 auto max = (uint32_t) -1;
278 m_local_apic->write(0x380, max);
279
280 while (m_ticks < TICK_CALIBRATE_LENGTH)
281 asm volatile("nop");
282
283 uint32_t elapsed = max - (m_local_apic->read(0x390));
284 uint32_t ticks_per_ms = elapsed / TICK_CALIBRATE_LENGTH;
285
286 Logger::DEBUG() << "Ticks per ms: " << (int) ticks_per_ms << "\n";
287
288 // Disable the PIT interrupt again
289 m_local_apic->write(0x380, 0x00);
290 m_io_apic->set_redirect_mask(redirect.index, true);
291
292 return ticks_per_ms;
293}
static Logger DEBUG()
Gets active logger set to DEBUG level.
Definition logger.cpp:193
static Logger INFO()
Gets active logger set to info level.
Definition logger.cpp:171
Stores the left, top, width and height of a rectangle.
Definition rectangle.h:22
Driver for the APIC clock.
Definition clock.h:123
common::time_t get_time()
Reads the current time from the APIC clock (in 24hr time)
Definition clock.cpp:182
void activate() override
Activates the clock, setting the binary coded decimal representation flag.
Definition clock.cpp:88
string device_name() final
Gets the name of the device.
Definition clock.cpp:135
void setup_apic_clock(hardwarecommunication::LocalAPIC *local_apic) const
Sets up the APIC clock to fire interrupts at the desired rate.
Definition clock.cpp:163
uint64_t clock_accuracy
How accurate the clock is in microseconds (how often should an interrupt be raised)
Definition clock.h:155
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:110
Clock(hardwarecommunication::AdvancedProgrammableInterruptController *apic, uint16_t time_between_events=10)
Constructor for the Clock class.
Definition clock.cpp:24
string vendor_name() final
Gets the vendor who created the device.
Definition clock.cpp:126
static Clock * active_clock()
Gets the currently active clock.
Definition clock.cpp:208
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:144
Driver for the Programmable Interval Timer.
Definition clock.h:95
PIT(hardwarecommunication::AdvancedProgrammableInterruptController *apic)
Constructor for the PIT class. Registers a handler for interrupt 0x22 and initialises ports.
Definition clock.cpp:216
Handles both the Local APIC (boot core) and IO APIC.
Definition apic.h:228
void set_redirect(interrupt_redirect_t *redirect)
Redirect a system interrupt to a different IRQ.
Definition apic.cpp:365
void set_redirect_mask(uint8_t index, bool mask)
Enables/Disables an interrupt redirect by masking it.
Definition apic.cpp:399
Handles a certain interrupt number.
Definition interrupts.h:30
Handles the local APIC for the current core.
Definition apic.h:24
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
virtual uint8_t read()
read a byte from the port
Definition port.cpp:51
virtual void write(uint8_t data)
write a byte to the port
Definition port.cpp:41
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:89
Defines a Logger class for logging messages with different severity levels to multiple output streams...
Stores the year, month, day, hour, minute and second of a time.
Definition time.h:24
The command byte to send to the PIT, specifies the channel, access mode, operating mode and BCD mode.
Definition clock.h:75
uint8_t bcd_mode
0 = binary, 1 = BCD
Definition clock.h:77
Defines how an interrupt input is redirected to a specific processor via the I/O APIC.
Definition apic.h:162