diff --git a/driver/irq/pic/rtc/handler.S b/driver/irq/pic/rtc/handler.S new file mode 100644 index 0000000..7571940 --- /dev/null +++ b/driver/irq/pic/rtc/handler.S @@ -0,0 +1,29 @@ +format elf64 + +public __pic_rtc_IRQ8 +public __pic_rtc_IRQHandler; + + +section '.bss' writable +__pic_rtc_IRQHandler: + rq 1 + +section '.text' executable +__pic_rtc_IRQ8: + push rax + + ; read the register C byte or the interrupt will block + mov al, 0x0c + out 0x70, al + in al, 0x71 + + ; tell if the irq handler is NULL + mov rax, [__pic_rtc_IRQHandler] + test rax, rax + pop rax + jz .end + jmp qword [__pic_rtc_IRQHandler] +.end: + iret + + diff --git a/driver/irq/pic/rtc/internal.h b/driver/irq/pic/rtc/internal.h new file mode 100644 index 0000000..22fc8ee --- /dev/null +++ b/driver/irq/pic/rtc/internal.h @@ -0,0 +1,8 @@ +#pragma once + +#include "rtc.h" +#include "../../../../main.h" + + +extern void * __pic_rtc_IRQHandler; +SYSV_ABI void __pic_rtc_IRQ8(); diff --git a/driver/irq/pic/rtc/rtc.c b/driver/irq/pic/rtc/rtc.c new file mode 100644 index 0000000..ac3e087 --- /dev/null +++ b/driver/irq/pic/rtc/rtc.c @@ -0,0 +1,34 @@ + +#include "rtc.h" +#include "internal.h" +#include "../pic.h" +#include "../internal.h" +#include "../../../../main.h" +#include "../../../../runtime/panic_assert.h" +#include "../../../../interrupt/interrupt.h" + + +bool pic_rtc_Enabled; + +void pic_rtc_Init() { + assert(irq_pic_Enabled && "pic/rtc requires pic to be enabled"); + + if (pic_rtc_Enabled) + return; + INTERRUPT_DISABLE; + + outb(0x70, 0x8b); // select register B, and disable NMI + uint8_t prev = inb(0x71); // read the current value of register B + outb(0x70, 0x8B); // set the index again (a read will reset the index to register D) + outb(0x71, prev | 0x40); // write the previous value ORed with 0x40. This turns on bit 6 of register B + + irq_pic_IRQHandlerRaw[8] = __pic_rtc_IRQ8; + irq_pic_Mask(8, false); + + pic_rtc_Enabled = true; + INTERRUPT_RESTORE; +} + +void pic_rtc_SetHandler(void *handler) { + __pic_rtc_IRQHandler = handler; +} diff --git a/driver/irq/pic/rtc/rtc.h b/driver/irq/pic/rtc/rtc.h new file mode 100644 index 0000000..88c04cd --- /dev/null +++ b/driver/irq/pic/rtc/rtc.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +extern bool pic_rtc_Enabled; + +// Init installs the required interrupt handlers. +void pic_rtc_Init(); + +// SetHandler sets the interrupt handler for RTC interrupts. +// +// The handler is jumped to, so it must use IRET and save registers is uses. +void pic_rtc_SetHandler(void *handler); + + +#ifdef __cplusplus +} +#endif