kernel: add timers via pit

This commit is contained in:
Benji Dial 2025-12-28 22:30:37 -05:00
parent e698cfdfd1
commit 02e855c066
8 changed files with 172 additions and 1 deletions

View file

@ -36,3 +36,5 @@ enum fs_access_result read_file_splat(file_handle_t handle, void *buffer, uint64
void wait_for_mouse_packet(struct mouse_packet *packet_out);
void *map_pages(uint64_t count);
void sleep_ms(uint64_t ms_to_sleep);

View file

@ -25,5 +25,6 @@ enum {
SYSCALL_GET_FILE_SIZE,
SYSCALL_READ_FILE,
SYSCALL_WAIT_FOR_MOUSE_PACKET,
SYSCALL_MAP_PAGES
SYSCALL_MAP_PAGES,
SYSCALL_SLEEP_MS
};

View file

@ -25,6 +25,7 @@
#include "paging.h"
#include "input.h"
#include "panic.h"
#include "timer.h"
#include "heap.h"
#include "pata.h"
#include "ps2.h"
@ -243,9 +244,13 @@ static const char *cmdline_look_up(const char *key) {
//set up interrupts
init_timer();
init_ps2();
set_irq_handler(0x00, &on_pit_irq);
set_irq_handler(0x01, &on_keyboard_irq);
set_irq_handler(0x0c, &on_mouse_irq);
enable_interrupts();
//set up syscalls
@ -259,6 +264,7 @@ static const char *cmdline_look_up(const char *key) {
register_syscall(SYSCALL_READ_FILE, (void *)&syscall_read_file);
register_syscall(SYSCALL_WAIT_FOR_MOUSE_PACKET, (void *)&syscall_wait_for_mouse_packet);
register_syscall(SYSCALL_MAP_PAGES, (void *)&syscall_map_pages);
register_syscall(SYSCALL_SLEEP_MS, (void *)&syscall_sleep_ms);
//probe for drives

37
src/kernel/timer.asm Normal file
View file

@ -0,0 +1,37 @@
; Calcite, src/kernel/timer.asm
; Copyright 2025 Benji Dial
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful, but
; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
; for more details.
;
; You should have received a copy of the GNU General Public License along
; with this program. If not, see <https://www.gnu.org/licenses/>.
bits 64
default rel
section .text
global init_timer
init_timer:
;generate an irq every 1193 cycles (~ every millisecond)
mov al, 0x34
out 0x43, al
mov al, 0xa9
out 0x40, al
mov al, 0x04
out 0x40, al
ret

93
src/kernel/timer.c Normal file
View file

@ -0,0 +1,93 @@
/* Calcite, src/kernel/timer.c
* Copyright 2025 Benji Dial
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "scheduler.h"
#include "timer.h"
#include "heap.h"
struct sleeping_list_entry {
struct sleeping_list_entry *next;
uint64_t sleeping_until;//pit irqs since boot
struct continuation_info continuation;
};
//entries are always sorted increasing by sleeping_until
static struct sleeping_list_entry *first_entry = 0;
static struct sleeping_list_entry *last_entry = 0;
//pit irq happens ~ once per millisecond
static uint64_t pit_irqs_since_boot = 0;
void on_pit_irq() {
++pit_irqs_since_boot;
while (first_entry != 0 && pit_irqs_since_boot >= first_entry->sleeping_until) {
add_to_queue(&ready_continuations, &first_entry->continuation);
struct sleeping_list_entry *old_first = first_entry;
first_entry = old_first->next;
heap_dealloc(old_first, sizeof(struct sleeping_list_entry));
if (first_entry == 0)
last_entry = 0;
}
}
//until in pit irqs since boot
static void sleep_until(uint64_t until) {
struct sleeping_list_entry *entry = heap_alloc(sizeof(struct sleeping_list_entry));
entry->sleeping_until = until;
__asm__ ("cli");
if (first_entry == 0) {
entry->next = 0;
first_entry = entry;
last_entry = entry;
}
else if (first_entry->sleeping_until >= until) {
entry->next = first_entry;
first_entry = entry;
}
else if (last_entry->sleeping_until <= until) {
entry->next = 0;
last_entry->next = entry;
last_entry = entry;
}
else {
struct sleeping_list_entry *just_before = first_entry;
while (just_before->next->sleeping_until <= until)
just_before = just_before->next;
entry->next = just_before->next;
just_before->next = entry;
}
yield_sti(&entry->continuation);
}
void syscall_sleep_ms(uint64_t ms_to_sleep) {
sleep_until(pit_irqs_since_boot + ms_to_sleep);
}

26
src/kernel/timer.h Normal file
View file

@ -0,0 +1,26 @@
/* Calcite, src/kernel/timer.h
* Copyright 2025 Benji Dial
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
void init_timer();
void on_pit_irq();
void syscall_sleep_ms(uint64_t ms_to_sleep);

View file

@ -76,6 +76,8 @@ void main() {
while (1) {
sleep_ms(10);
struct mouse_packet packet;
wait_for_mouse_packet(&packet);

View file

@ -60,3 +60,7 @@ void wait_for_mouse_packet(struct mouse_packet *packet_out) {
void *map_pages(uint64_t count) {
return (void *)do_syscall(count, 0, 0, SYSCALL_MAP_PAGES);
}
void sleep_ms(uint64_t ms_to_sleep) {
do_syscall(ms_to_sleep, 0, 0, SYSCALL_SLEEP_MS);
}