Reimplemented PIT Timer. Sleep is now a syscall. Also made docs/ that contains some info so i don't forget.

This commit is contained in:
2024-05-07 20:25:48 +02:00
parent e617f4fe69
commit 41e0b93f52
10 changed files with 137 additions and 62 deletions
+47
View File
@@ -0,0 +1,47 @@
#ifndef TIMER_H
#define TIMER_H
#include <stdint.h>
#include <idt.h>
#include <pic.h>
#include <screen.h>
#define CHANNEL_0 0x40 // Offset it by 1 or 2 for ch1 and ch2
#define COMMAND 0x43
#define INPUT_CLK 1193182
static uint32_t* timerTicks = (uint32_t*)0x1000;
__attribute__ ((interrupt))
void timerHandler(intFrame_t* iframe) {
*timerTicks += 1;
// TODO: Improve the cursor rendering
if (*timerTicks % 500 == 0) putcAt(' ', cursor.x, cursor.y);
else if (*timerTicks % 250 == 0) putcAt(127, cursor.x, cursor.y);
sendPicEOI(0);
}
void setPitPhase(uint8_t channel, uint8_t opMode, uint16_t hz) {
if (channel > 2 || opMode > 7) { return; }
__asm__ volatile ("cli");
// Send command - bits 7-6 channel, 5-4 Access mode, 3-1 operating mode, 0 - Should be zero in x86
outb(COMMAND, ((channel << 6) | (3 << 4) | (opMode << 1)));
// Send frequency
uint16_t freq = INPUT_CLK / hz; // I solved an equation to figure this out
outb(CHANNEL_0 + channel, (uint8_t)freq);
outb(CHANNEL_0 + channel, (uint8_t)(freq >> 8));
__asm__ volatile ("sti");
}
void setupTimer() { // Sets up IRQ 0 - PIT
idtSetGate(0x20, timerHandler, INT_GATE_FLAGS);
unsetIrqMask(0);
setPitPhase(0, 2, 1000); // Default setup: 1000Hz - 1 tick per 1ms
}
#endif
+10 -12
View File
@@ -1,27 +1,25 @@
#ifndef SYSCALL_H
#define SYSCALL_H
#include <screen.h>
#include <pit.h>
// System call count
#define MAX_SYSCALLS 2
void sys_test0() {
fgColor = YELLOW;
print("Syscall 0 - Test\n");
fgColor = FG_COLOR;
}
// Args: ebx - number of miliseconds
void sys_sleep() {
uint32_t ms;
__asm__ volatile ("movl %%ebx, %0" : "=r"(ms));
void sys_test1() {
fgColor = CYAN;
print("Syscall 1 - Test\n");
fgColor = FG_COLOR;
uint32_t requiredTicks = *timerTicks + ms;
while (*timerTicks != requiredTicks) { // Wait...
__asm__ volatile ("sti;hlt;cli;");
}
}
// System call table
void* syscalls[MAX_SYSCALLS] = {
sys_test0,
sys_test1,
sys_sleep,
};
// int 0x80 - Syscall interrupt, handled by this function
+8
View File
@@ -0,0 +1,8 @@
#ifndef TIME_H
#define TIME_H
void sleep(uint32_t ms) {
__asm__ volatile ("int $0x80" : : "a"(0), "b"(ms));
}
#endif
+22 -21
View File
@@ -4,43 +4,44 @@
#include <stdint.h>
#include <idt.h>
#include <pic.h>
#include <system.h>
#include <screen.h>
#define INPUT_CLK 1193180
#define CHANNEL_0 0x40 // Offset it by 1 or 2 for ch1 and ch2
#define COMMAND 0x43
#define INPUT_CLK 1193182
uint32_t timerTicks = 0;
static uint32_t* timerTicks = (uint32_t*)0x1000;
__attribute__ ((interrupt))
void timerHandler(intFrame_t* iframe) {
timerTicks++;
*timerTicks += 1;
// TODO: Improve the cursor rendering
if (timerTicks % 500 == 0) putcAt(127, cursor.x, cursor.y);
else if (timerTicks % 250 == 0) putcAt(' ', cursor.x, cursor.y);
if (*timerTicks % 500 == 0) putcAt(' ', cursor.x, cursor.y);
else if (*timerTicks % 250 == 0) putcAt(127, cursor.x, cursor.y);
sendPicEOI(0);
}
void setupTimer() {
idtSetGate(32, timerHandler, INT_GATE_FLAGS);
unsetIrqMask(0);
}
void setPitPhase(uint8_t channel, uint8_t opMode, uint16_t hz) {
if (channel > 2 || opMode > 7) { return; }
__asm__ volatile ("cli");
// Source: https://en.wikibooks.org/wiki/X86_Assembly/Programmable_Interval_Timer
void timerPhase(uint32_t hz) {
uint16_t div = INPUT_CLK / hz;
// Send command - bits 7-6 channel, 5-4 Access mode, 3-1 operating mode, 0 - Should be zero in x86
outb(COMMAND, ((channel << 6) | (3 << 4) | (opMode << 1)));
outb(0x43, 0x36); // Tell PIT that we're setting channel 0
outb(0x40, div & 0xff); // Low byte
outb(0x40, div >> 8); // High byte
}
void sleep(uint32_t ticks) {
uint32_t eticks = ticks + timerTicks;
// Send frequency
uint16_t freq = INPUT_CLK / hz; // I solved an equation to figure this out
outb(CHANNEL_0 + channel, (uint8_t)freq);
outb(CHANNEL_0 + channel, (uint8_t)(freq >> 8));
while (timerTicks != eticks); // Should ignore overflows unlike '<'
__asm__ volatile ("sti");
}
void setupTimer() { // Sets up IRQ 0 - PIT
idtSetGate(0x20, timerHandler, INT_GATE_FLAGS);
unsetIrqMask(0);
setPitPhase(0, 2, 1000); // Default setup: 1000Hz - 1 tick per 1ms
}
#endif