kernel: add timers via pit
This commit is contained in:
parent
e698cfdfd1
commit
02e855c066
8 changed files with 172 additions and 1 deletions
|
|
@ -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 wait_for_mouse_packet(struct mouse_packet *packet_out);
|
||||||
|
|
||||||
void *map_pages(uint64_t count);
|
void *map_pages(uint64_t count);
|
||||||
|
|
||||||
|
void sleep_ms(uint64_t ms_to_sleep);
|
||||||
|
|
|
||||||
|
|
@ -25,5 +25,6 @@ enum {
|
||||||
SYSCALL_GET_FILE_SIZE,
|
SYSCALL_GET_FILE_SIZE,
|
||||||
SYSCALL_READ_FILE,
|
SYSCALL_READ_FILE,
|
||||||
SYSCALL_WAIT_FOR_MOUSE_PACKET,
|
SYSCALL_WAIT_FOR_MOUSE_PACKET,
|
||||||
SYSCALL_MAP_PAGES
|
SYSCALL_MAP_PAGES,
|
||||||
|
SYSCALL_SLEEP_MS
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
|
#include "timer.h"
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
#include "pata.h"
|
#include "pata.h"
|
||||||
#include "ps2.h"
|
#include "ps2.h"
|
||||||
|
|
@ -243,9 +244,13 @@ static const char *cmdline_look_up(const char *key) {
|
||||||
|
|
||||||
//set up interrupts
|
//set up interrupts
|
||||||
|
|
||||||
|
init_timer();
|
||||||
init_ps2();
|
init_ps2();
|
||||||
|
|
||||||
|
set_irq_handler(0x00, &on_pit_irq);
|
||||||
set_irq_handler(0x01, &on_keyboard_irq);
|
set_irq_handler(0x01, &on_keyboard_irq);
|
||||||
set_irq_handler(0x0c, &on_mouse_irq);
|
set_irq_handler(0x0c, &on_mouse_irq);
|
||||||
|
|
||||||
enable_interrupts();
|
enable_interrupts();
|
||||||
|
|
||||||
//set up syscalls
|
//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_READ_FILE, (void *)&syscall_read_file);
|
||||||
register_syscall(SYSCALL_WAIT_FOR_MOUSE_PACKET, (void *)&syscall_wait_for_mouse_packet);
|
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_MAP_PAGES, (void *)&syscall_map_pages);
|
||||||
|
register_syscall(SYSCALL_SLEEP_MS, (void *)&syscall_sleep_ms);
|
||||||
|
|
||||||
//probe for drives
|
//probe for drives
|
||||||
|
|
||||||
|
|
|
||||||
37
src/kernel/timer.asm
Normal file
37
src/kernel/timer.asm
Normal 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
93
src/kernel/timer.c
Normal 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
26
src/kernel/timer.h
Normal 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);
|
||||||
|
|
@ -76,6 +76,8 @@ void main() {
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
|
sleep_ms(10);
|
||||||
|
|
||||||
struct mouse_packet packet;
|
struct mouse_packet packet;
|
||||||
wait_for_mouse_packet(&packet);
|
wait_for_mouse_packet(&packet);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,3 +60,7 @@ void wait_for_mouse_packet(struct mouse_packet *packet_out) {
|
||||||
void *map_pages(uint64_t count) {
|
void *map_pages(uint64_t count) {
|
||||||
return (void *)do_syscall(count, 0, 0, SYSCALL_MAP_PAGES);
|
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);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue