diff --git a/include/calcite/syscalls.h b/include/calcite/syscalls.h index 2ed46f0..65f7a38 100644 --- a/include/calcite/syscalls.h +++ b/include/calcite/syscalls.h @@ -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); diff --git a/include/kernel-public/syscall-numbers.h b/include/kernel-public/syscall-numbers.h index 22d25bd..24440bc 100644 --- a/include/kernel-public/syscall-numbers.h +++ b/include/kernel-public/syscall-numbers.h @@ -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 }; diff --git a/src/kernel/entry.c b/src/kernel/entry.c index 87af06f..272d4b2 100644 --- a/src/kernel/entry.c +++ b/src/kernel/entry.c @@ -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 diff --git a/src/kernel/timer.asm b/src/kernel/timer.asm new file mode 100644 index 0000000..45e1c27 --- /dev/null +++ b/src/kernel/timer.asm @@ -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 . + + +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 diff --git a/src/kernel/timer.c b/src/kernel/timer.c new file mode 100644 index 0000000..405da78 --- /dev/null +++ b/src/kernel/timer.c @@ -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 . + */ + +#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); +} diff --git a/src/kernel/timer.h b/src/kernel/timer.h new file mode 100644 index 0000000..9e53a09 --- /dev/null +++ b/src/kernel/timer.h @@ -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 . + */ + +#pragma once + +#include + +void init_timer(); + +void on_pit_irq(); + +void syscall_sleep_ms(uint64_t ms_to_sleep); diff --git a/src/user-apps/hello/hello.c b/src/user-apps/hello/hello.c index 744abfb..069b78a 100644 --- a/src/user-apps/hello/hello.c +++ b/src/user-apps/hello/hello.c @@ -76,6 +76,8 @@ void main() { while (1) { + sleep_ms(10); + struct mouse_packet packet; wait_for_mouse_packet(&packet); diff --git a/src/user-libs/calcite/syscalls.c b/src/user-libs/calcite/syscalls.c index 013ae67..80a5b7f 100644 --- a/src/user-libs/calcite/syscalls.c +++ b/src/user-libs/calcite/syscalls.c @@ -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); +}