summaryrefslogtreecommitdiff
path: root/kc/core
diff options
context:
space:
mode:
Diffstat (limited to 'kc/core')
-rw-r--r--kc/core/Makefile2
-rw-r--r--kc/core/cpu/exceptions.S50
-rw-r--r--kc/core/cpu/interrupt.h70
-rw-r--r--kc/core/cpu/irq.h30
-rw-r--r--kc/core/pic8259.c195
-rw-r--r--kc/core/pic8259.h41
-rw-r--r--kc/core/pic8259_isr.S38
-rw-r--r--kc/core/pit8253.c36
-rw-r--r--kc/core/pit8253.h9
9 files changed, 429 insertions, 42 deletions
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 <stdbool.h>
+
+#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 <stdint.h>
+
+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 <stdint.h>
+
+void pit8253_init(void);
+void pit8253_start(void);
+void pit8253_stop(void);
+void pit8253_set_hz(uint16_t hz);
+