From e8a76b2f6b53d99640ceb2850bf4e45118b923f1 Mon Sep 17 00:00:00 2001 From: Ada Christine Date: Sun, 13 Feb 2022 18:47:58 +0000 Subject: rudimentary irq and timer support --- kc/core/Makefile | 2 +- kc/core/cpu/exceptions.S | 50 +++--------- kc/core/cpu/interrupt.h | 70 +++++++++++++++++ kc/core/cpu/irq.h | 30 ++++++++ kc/core/pic8259.c | 195 +++++++++++++++++++++++++++++++++++++++++++++++ kc/core/pic8259.h | 41 ++++++++++ kc/core/pic8259_isr.S | 38 +++++++++ kc/core/pit8253.c | 36 +++++++++ kc/core/pit8253.h | 9 +++ 9 files changed, 429 insertions(+), 42 deletions(-) create mode 100644 kc/core/cpu/interrupt.h create mode 100644 kc/core/cpu/irq.h create mode 100644 kc/core/pic8259.c create mode 100644 kc/core/pic8259.h create mode 100644 kc/core/pic8259_isr.S create mode 100644 kc/core/pit8253.c create mode 100644 kc/core/pit8253.h diff --git a/kc/core/Makefile b/kc/core/Makefile index 6874179..f2ab99c 100644 --- a/kc/core/Makefile +++ b/kc/core/Makefile @@ -13,7 +13,7 @@ SOBJS := GOBJS := entry_x86_64.o reloc_x86_64.o kprint.o serial.o port.o \ kc_main.o main.o memory.o memset.o memcpy.o memmove.o memcmp.o cpu.o \ vm_tree.o exceptions.o panic.o msr.o task.o cpu_task.o \ - kcc_memory.o string.o + kcc_memory.o string.o pic8259.o pic8259_isr.o pit8253.o IOBJS := # __attribute__((interrupt)) requires -mgeneral-regs-only diff --git a/kc/core/cpu/exceptions.S b/kc/core/cpu/exceptions.S index 8a19c8c..087cf12 100644 --- a/kc/core/cpu/exceptions.S +++ b/kc/core/cpu/exceptions.S @@ -1,67 +1,35 @@ #include "exceptions.h" +#include "interrupt.h" .macro EXCEPTION_BEGIN vec:req, code=0 // just in case something tried to be clever before cld // push param registers - push %rdi + ISR_STORE_PARAM_REGS // store certain parameters movb $\vec,%dil - push %rsi .if \code - movq 16(%rsp), %rsi + movq ISR_PARAM_REGS_SIZE(%rsp), %rsi .else xor %rsi, %rsi .endif - push %rdx - push %rcx - push %r8 - push %r9 // caller-saved registers - push %rax - push %r10 - push %r11 + ISR_STORE_CALLER_REGS // callee-saved registers - push %rbx - push %rbp - push %r12 - push %r13 - push %r14 - push %r15 + ISR_STORE_CALLEE_REGS .endm .macro EXCEPTION_END vec:req, code=0 // restore all the registers - pop %r15 - pop %r14 - pop %r13 - pop %r12 - pop %rbp - pop %rbx - pop %r11 - pop %r10 - pop %rax - pop %r9 - pop %r8 - pop %rcx - pop %rdx - pop %rsi - pop %rdi + ISR_RESTORE_CALLEE_REGS + ISR_RESTORE_CALLER_REGS + ISR_RESTORE_PARAM_REGS .if \code add $8, %rsp .endif iretq .endm -.macro EXCEPTION_CALL func - // align the stack for the call to the handler function - mov %rsp, %rbp - and $-16, %rsp - call \func - // restore stack pointer, possibly unaligned - mov %rbp, %rsp -.endm - .macro EXCEPTION_DEFINE name:req, vec:req \name\()_isr: .if \vec > 9 && \vec < 15 || \vec == 17 || \vec == 21 || \vec > 28 && \vec < 31 @@ -69,7 +37,7 @@ .else EXCEPTION_BEGIN \vec .endif - EXCEPTION_CALL \name\()_handler + ISR_CALL \name\()_handler .if \vec > 9 && \vec < 15 || \vec == 17 || \vec == 21 || \vec > 28 && \vec < 31 EXCEPTION_END \vec, 1 .else diff --git a/kc/core/cpu/interrupt.h b/kc/core/cpu/interrupt.h new file mode 100644 index 0000000..dff2d99 --- /dev/null +++ b/kc/core/cpu/interrupt.h @@ -0,0 +1,70 @@ +#pragma once + +#ifndef __ASSEMBLER__ +#else + +.macro ISR_STORE_PARAM_REGS +push %rdi +push %rsi +push %rdx +push %rcx +push %r8 +push %r9 +.endm + +#define ISR_PARAM_REGS_SIZE 48 + +.macro ISR_STORE_CALLER_REGS +push %rax +push %r10 +push %r11 +.endm + +#define ISR_CALLER_REGS_SIZE 24 + +.macro ISR_STORE_CALLEE_REGS +push %rbx +push %rbp +push %r12 +push %r13 +push %r14 +push %r15 +.endm + +#define ISR_CALLEE_REGS_SIZE 48 + +.macro ISR_RESTORE_PARAM_REGS +pop %r9 +pop %r8 +pop %rcx +pop %rdx +pop %rsi +pop %rdi +.endm + +.macro ISR_RESTORE_CALLER_REGS +pop %r11 +pop %r10 +pop %rax +.endm + +.macro ISR_RESTORE_CALLEE_REGS +pop %r15 +pop %r14 +pop %r13 +pop %r12 +pop %rbp +pop %rbx +.endm + +.macro ISR_CALL func + // align the stack for the call to the handler function + mov %rsp, %rbp + and $-16, %rsp + call \func + // restore stack pointer, possibly unaligned + mov %rbp, %rsp +.endm + +#endif + diff --git a/kc/core/cpu/irq.h b/kc/core/cpu/irq.h new file mode 100644 index 0000000..9874761 --- /dev/null +++ b/kc/core/cpu/irq.h @@ -0,0 +1,30 @@ +#pragma once + +#include "interrupt.h" + +#ifndef __ASSEMBLER__ +#else + +.macro IRQ_DECLARE name:req handler:req, irq:req, offset:req +.hidden \name\()_irq\()\irq\()_isr +.global \name\()_irq\()\irq\()_isr +.extern \handler +.type \name\()_irq\()\irq\()_isr, @function +.endm + +.macro IRQ_DEFINE name:req handler:req, irq:req +\name\()_irq\()\irq\()_isr: + ISR_STORE_PARAM_REGS + movb \irq, %dil + ISR_STORE_CALLER_REGS + ISR_STORE_CALLEE_REGS + ISR_CALL \handler + ISR_RESTORE_CALLEE_REGS + ISR_RESTORE_CALLER_REGS + ISR_RESTORE_PARAM_REGS + iretq +.size \name\()_irq\()\irq\()_isr, . - \name\()_irq\()\irq\()_isr +.endm + +#endif + diff --git a/kc/core/pic8259.c b/kc/core/pic8259.c new file mode 100644 index 0000000..f449e38 --- /dev/null +++ b/kc/core/pic8259.c @@ -0,0 +1,195 @@ +#include "pic8259.h" +#include "cpu.h" +#include "port.h" +#include "kprint.h" + +#include + +#define ICW1_ICW4 0x1 +#define ICW1_SINGLE 0x2 +#define ICW1_INTERVAL4 0x4 +#define ICW1_LEVEL 0x8 +#define ICW1_INIT 0x10 + +#define ICW4_8086 0x1 +#define ICW4_AUTO 0x2 +#define ICW4_BUF_SEC 0x8 +#define ICW4_BUF_PRI 0xc +#define ICW4_SFNM 0x10 + +#define OCW3_READ_IRR 0xa +#define OCW3_READ_ISR 0xb +#define OCW3_EOI 0x20 + +typedef int (*pic8259_handler_func)(uint8_t irq); + +pic8259_handler_func irq_handlers[PIC_ISR_COUNT]; + +__attribute__((optimize("O3"))) +static void wait(void) +{ + // stall for a few cycles + inb(0x80); + inb(0x80); +} + +void pic8259_init(void) +{ + // basic init. not gonna fret with this too much + outb(PIC_PRI_CMD, ICW1_INIT|ICW1_ICW4); + wait(); + outb(PIC_SEC_CMD, ICW1_INIT|ICW1_ICW4); + wait(); + outb(PIC_PRI_DATA, PIC_ISR_BASE); + wait(); + outb(PIC_SEC_DATA, PIC_ISR_BASE+8); + wait(); + outb(PIC_PRI_DATA, 4); + wait(); + outb(PIC_SEC_DATA, 2); + wait(); + outb(PIC_PRI_DATA, ICW4_8086); + wait(); + outb(PIC_SEC_DATA, ICW4_8086); + wait(); + // mask all interrupt lines + outb(PIC_PRI_DATA, 0xff); + outb(PIC_SEC_DATA, 0xff); + + isr_install(PIC_ISR_BASE + 0, pic8259_irq0_isr, 0, 0); + isr_install(PIC_ISR_BASE + 1, pic8259_irq1_isr, 0, 0); + isr_install(PIC_ISR_BASE + 2, pic8259_irq2_isr, 0, 0); + isr_install(PIC_ISR_BASE + 3, pic8259_irq3_isr, 0, 0); + isr_install(PIC_ISR_BASE + 4, pic8259_irq4_isr, 0, 0); + isr_install(PIC_ISR_BASE + 5, pic8259_irq5_isr, 0, 0); + isr_install(PIC_ISR_BASE + 6, pic8259_irq6_isr, 0, 0); + isr_install(PIC_ISR_BASE + 7, pic8259_irq7_isr, 0, 0); + isr_install(PIC_ISR_BASE + 8, pic8259_irq8_isr, 0, 0); + isr_install(PIC_ISR_BASE + 9, pic8259_irq9_isr, 0, 0); + isr_install(PIC_ISR_BASE + 10, pic8259_irq10_isr, 0, 0); + isr_install(PIC_ISR_BASE + 11, pic8259_irq11_isr, 0, 0); + isr_install(PIC_ISR_BASE + 12, pic8259_irq12_isr, 0, 0); + isr_install(PIC_ISR_BASE + 13, pic8259_irq13_isr, 0, 0); + isr_install(PIC_ISR_BASE + 14, pic8259_irq14_isr, 0, 0); + isr_install(PIC_ISR_BASE + 15, pic8259_irq15_isr, 0, 0); +} + +static bool irq_is_spurious(uint8_t irq) +{ + uint8_t isr_pri; + uint8_t isr_sec; + + // all other no other IRQs are + if (irq != 7 || irq != 15) + { + return false; + } + else if (irq == 7) + { + outb(PIC_PRI_CMD, OCW3_READ_ISR); + isr_pri = inb(PIC_PRI_CMD); + + if (isr_pri == 0x80) + { + return false; + } + } + else if (irq == 15) + { + outb(PIC_SEC_CMD, OCW3_READ_ISR); + isr_sec = inb(PIC_SEC_CMD); + + if (isr_sec == 0x80) + { + return false; + } + else + { + // tell primary to EOI + outb(PIC_PRI_CMD, OCW3_EOI); + } + } + + return true; +} + +void pic8259_irq_mask(uint8_t irq) +{ + uint16_t port = PIC_PRI_DATA; + uint8_t mask; + + if (irq > 7) + { + irq -= 8; + port = PIC_SEC_DATA; + + } + + mask = inb(port); + mask |= (1 << irq); + outb(port, mask); + + // mask the primary irq2 pin if there are no active lines + // on the secondary + if (irq > 7 && mask == 0xff) + { + pic8259_irq_mask(2); + } +} + +void pic8259_irq_unmask(uint8_t irq) +{ + uint8_t mask; + uint16_t port = PIC_PRI_DATA; + + if (irq > 7) + { + irq -= 8; + port = PIC_SEC_DATA; + // unmask the primary's cascade line + pic8259_irq_unmask(2); + } + + mask = inb(port); + mask &= ~(1 << irq); + outb(port, mask); +} + +void pic8259_irq_begin(uint8_t irq) +{ + int result; + + // check for spurious activations + if (irq_is_spurious(irq)) + { + kprintf("spurious activation of irq%hhu\n", irq); + return; + } + + else if (irq_handlers[irq]) + { + result = irq_handlers[irq](irq); + + if (result) + { + kprintf("error handling irq%hhu: % d\n", irq, result); + } + } + else + { + kprintf("%s of irq%hhu\n", "unhandled activation", irq); + } + + pic8259_irq_end(irq); +} + +void pic8259_irq_end(uint8_t irq) +{ + if (irq > 7) + { + outb(PIC_SEC_CMD, OCW3_EOI); + } + + outb(PIC_PRI_CMD, OCW3_EOI); +} + diff --git a/kc/core/pic8259.h b/kc/core/pic8259.h new file mode 100644 index 0000000..13aaaaa --- /dev/null +++ b/kc/core/pic8259.h @@ -0,0 +1,41 @@ +#pragma once + +#define PIC_PRI_IOBASE 0x20 +#define PIC_SEC_IOBASE 0xA0 +#define PIC_PRI_CMD PIC_PRI_IOBASE +#define PIC_SEC_CMD PIC_SEC_IOBASE +#define PIC_PRI_DATA (PIC_PRI_IOBASE+1) +#define PIC_SEC_DATA (PIC_SEC_IOBASE+1) + +#define PIC_ISR_BASE 240 +#define PIC_ISR_COUNT 16 + +#ifndef __ASSEMBLER__ + +#include + +void pic8259_init(void); +void pic8259_irq_begin(uint8_t irq); +void pic8259_irq_end(uint8_t irq); +void pic8259_irq_mask(uint8_t irq); +void pic8259_irq_unmask(uint8_t irq); + +extern void pic8259_irq0_isr(void); +extern void pic8259_irq1_isr(void); +extern void pic8259_irq2_isr(void); +extern void pic8259_irq3_isr(void); +extern void pic8259_irq4_isr(void); +extern void pic8259_irq5_isr(void); +extern void pic8259_irq6_isr(void); +extern void pic8259_irq7_isr(void); +extern void pic8259_irq8_isr(void); +extern void pic8259_irq9_isr(void); +extern void pic8259_irq10_isr(void); +extern void pic8259_irq11_isr(void); +extern void pic8259_irq12_isr(void); +extern void pic8259_irq13_isr(void); +extern void pic8259_irq14_isr(void); +extern void pic8259_irq15_isr(void); + +#endif + diff --git a/kc/core/pic8259_isr.S b/kc/core/pic8259_isr.S new file mode 100644 index 0000000..b770722 --- /dev/null +++ b/kc/core/pic8259_isr.S @@ -0,0 +1,38 @@ +#include "cpu/interrupt.h" +#include "cpu/irq.h" +#include "pic8259.h" + +IRQ_DECLARE pic8259, pic8259_irq_begin, 0, PIC8259_ISR_BASE +IRQ_DECLARE pic8259, pic8259_irq_begin, 1, PIC8259_ISR_BASE +IRQ_DECLARE pic8259, pic8259_irq_begin, 2, PIC8259_ISR_BASE +IRQ_DECLARE pic8259, pic8259_irq_begin, 3, PIC8259_ISR_BASE +IRQ_DECLARE pic8259, pic8259_irq_begin, 4, PIC8259_ISR_BASE +IRQ_DECLARE pic8259, pic8259_irq_begin, 5, PIC8259_ISR_BASE +IRQ_DECLARE pic8259, pic8259_irq_begin, 6, PIC8259_ISR_BASE +IRQ_DECLARE pic8259, pic8259_irq_begin, 7, PIC8259_ISR_BASE +IRQ_DECLARE pic8259, pic8259_irq_begin, 8, PIC8259_ISR_BASE +IRQ_DECLARE pic8259, pic8259_irq_begin, 9, PIC8259_ISR_BASE +IRQ_DECLARE pic8259, pic8259_irq_begin, 10, PIC8259_ISR_BASE +IRQ_DECLARE pic8259, pic8259_irq_begin, 11, PIC8259_ISR_BASE +IRQ_DECLARE pic8259, pic8259_irq_begin, 12, PIC8259_ISR_BASE +IRQ_DECLARE pic8259, pic8259_irq_begin, 13, PIC8259_ISR_BASE +IRQ_DECLARE pic8259, pic8259_irq_begin, 14, PIC8259_ISR_BASE +IRQ_DECLARE pic8259, pic8259_irq_begin, 15, PIC8259_ISR_BASE + +IRQ_DEFINE pic8259, pic8259_irq_begin, 0 +IRQ_DEFINE pic8259, pic8259_irq_begin, 1 +IRQ_DEFINE pic8259, pic8259_irq_begin, 2 +IRQ_DEFINE pic8259, pic8259_irq_begin, 3 +IRQ_DEFINE pic8259, pic8259_irq_begin, 4 +IRQ_DEFINE pic8259, pic8259_irq_begin, 5 +IRQ_DEFINE pic8259, pic8259_irq_begin, 6 +IRQ_DEFINE pic8259, pic8259_irq_begin, 7 +IRQ_DEFINE pic8259, pic8259_irq_begin, 8 +IRQ_DEFINE pic8259, pic8259_irq_begin, 9 +IRQ_DEFINE pic8259, pic8259_irq_begin, 10 +IRQ_DEFINE pic8259, pic8259_irq_begin, 11 +IRQ_DEFINE pic8259, pic8259_irq_begin, 12 +IRQ_DEFINE pic8259, pic8259_irq_begin, 13 +IRQ_DEFINE pic8259, pic8259_irq_begin, 14 +IRQ_DEFINE pic8259, pic8259_irq_begin, 15 + diff --git a/kc/core/pit8253.c b/kc/core/pit8253.c new file mode 100644 index 0000000..75e0467 --- /dev/null +++ b/kc/core/pit8253.c @@ -0,0 +1,36 @@ +#include "pit8253.h" +#include "pic8259.h" +#include "port.h" + +#define PIT8253_DATA0 0x40 +#define PIT8253_CMD 0x43 + +#define SEL_CHANNEL0 0x0 +#define ACC_LOHI 0x30 +#define MODE_RATE 0x04 +#define BIN_COUNT 0x0 + +#define CONFIG_CHANNEL_0 (SEL_CHANNEL0|ACC_LOHI|MODE_RATE|BIN_COUNT) + +void pit8253_init(void) +{ + outb(PIT8253_CMD, CONFIG_CHANNEL_0); + outb(PIT8253_DATA0, 0xff); + outb(PIT8253_DATA0, 0xff); + + pic8259_irq_unmask(0); +} + +void pit8253_start(void) +{ +} + +void pit8253_stop(void) +{ +} + +void pit8253_set_hz(uint16_t hz) +{ + (void)hz; +} + diff --git a/kc/core/pit8253.h b/kc/core/pit8253.h new file mode 100644 index 0000000..81374a3 --- /dev/null +++ b/kc/core/pit8253.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +void pit8253_init(void); +void pit8253_start(void); +void pit8253_stop(void); +void pit8253_set_hz(uint16_t hz); + -- cgit v1.3.1-1-g115d