diff --git a/Makefile b/Makefile index 2776d87..71bb68a 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ GPPPARAMS = -m32 -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-excep ASPARAMS = --32 LDPARAMS = -melf_i386 -objs = loader.o gdt.o port.o kernel.o +objs = loader.o gdt.o port.o interruptstubs.o interrupts.o kernel.o %.o: src/%.cpp g++ $(GPPPARAMS) -o $@ -c $< diff --git a/include/interrupts.h b/include/interrupts.h new file mode 100644 index 0000000..2dc8ee9 --- /dev/null +++ b/include/interrupts.h @@ -0,0 +1,50 @@ +#ifndef __INTERRUPTS_H +#define __INTERRUPTS_H +#include "gdt.h" +#include "port.h" +#include "types.h" + +class InterruptManager { + protected: + struct GateDescriptor { + uint16_t handlerAddressLowBits; + uint16_t gdt_codeSegmentSelector; + uint8_t reserved; + uint8_t access; + uint16_t handlerAddressHiBits; + + } __attribute__((packed)); + + static GateDescriptor interruptDescriptorTable[256]; + + struct InterruptDescriptorTablePointer { + uint16_t size; + uint32_t base; + } __attribute__((packed)); + + static void + SetInterruptDescriptorTableEntries( + uint8_t interruptNumber, + uint16_t codeSegmentSelectorOffset, + void (*handler)(), + uint8_t descriptorPrivilegeLevel, + uint8_t descriptorType); + + Port8Bit_Slow picPrimaryCommand; + Port8Bit_Slow picPrimaryData; + Port8Bit_Slow picSecondaryCommand; + Port8Bit_Slow picSecondaryData; + + public: + InterruptManager(GlobalDescriptorTable* gdt); + ~InterruptManager(); + + void Activate(); + + static uint32_t HandleInterrupt(uint8_t interruptNumber, uint32_t esp); + + static void IgnoreInterruptRequest(); + static void HandleInterruptRequest0x00(); + static void HandleInterruptRequest0x01(); +}; +#endif \ No newline at end of file diff --git a/include/port.h b/include/port.h new file mode 100644 index 0000000..f88f639 --- /dev/null +++ b/include/port.h @@ -0,0 +1,55 @@ +/* + * port.h + * Author: Fergal Moran + * Copyright: 2020 Fergal Moran + * + * BSD License - do what you want + */ +#ifndef __PORT_H +#define __PORT_H + +#include "types.h" + +class Port { + protected: + uint16_t portNumber; + Port(uint16_t portNumber); + ~Port(); +}; + +class Port8Bit : public Port { + public: + Port8Bit(uint16_t portNumber); + ~Port8Bit(); + + virtual void Write(uint8_t data); + virtual uint8_t Read(); +}; + +class Port8Bit_Slow : public Port8Bit { + public: + Port8Bit_Slow(uint16_t portNumber); + ~Port8Bit_Slow(); + + virtual void Write(uint8_t data); +}; + +class Port16Bit : public Port { + public: + Port16Bit(uint16_t portNumber); + ~Port16Bit(); + + virtual void Write(uint16_t data); + virtual uint16_t Read(); +}; + +class Port32Bit : public Port { + public: + Port32Bit(uint16_t portNumber); + ~Port32Bit(); + + virtual void Write(uint32_t data); + virtual uint32_t Read(); +}; + +#endif \ No newline at end of file diff --git a/src/interrupts.cpp b/src/interrupts.cpp new file mode 100644 index 0000000..ec289fe --- /dev/null +++ b/src/interrupts.cpp @@ -0,0 +1,66 @@ +#include "../include/interrupts.h" + +void printf(char* str); + +InterruptManager::GateDescriptor InterruptManager::interruptDescriptorTable[256]; + +InterruptManager::InterruptManager(GlobalDescriptorTable* gdt) + : picPrimaryCommand(0x20), picPrimaryData(0x21), picSecondaryCommand(0xA0), picSecondaryData(0xA1) { + uint16_t codeSegment = gdt->CodeSegmentSelector(); + const uint8_t IDT_INTERRUPT_GATE = 0xE; + + for (uint16_t i = 0; i < 256; i++) { + SetInterruptDescriptorTableEntries(i, codeSegment, &IgnoreInterruptRequest, 0, IDT_INTERRUPT_GATE); + } + // see HandleInterruptRequest in interrupts.s + SetInterruptDescriptorTableEntries(0x20, codeSegment, &HandleInterruptRequest0x00, 0, IDT_INTERRUPT_GATE); + SetInterruptDescriptorTableEntries(0x21, codeSegment, &HandleInterruptRequest0x01, 0, IDT_INTERRUPT_GATE); + + picPrimaryCommand.Write(0x11); + picSecondaryCommand.Write(0x11); + + picPrimaryData.Write(0x20); + picSecondaryData.Write(0x28); + + picPrimaryData.Write(0x04); + picSecondaryData.Write(0x02); + + picPrimaryData.Write(0x01); + picSecondaryData.Write(0x01); + + picPrimaryData.Write(0x00); + picSecondaryData.Write(0x00); + + InterruptDescriptorTablePointer idt; + idt.size = 256 * sizeof(GateDescriptor) - 1; + idt.base = (uint32_t)interruptDescriptorTable; + + asm volatile("lidt %0" + : + : "m"(idt)); +} +InterruptManager::~InterruptManager() {} + +void InterruptManager::Activate() { + asm("sti"); +} + +void InterruptManager::SetInterruptDescriptorTableEntries( + uint8_t interruptNumber, + uint16_t codeSegmentSelectorOffset, + void (*handler)(), + uint8_t descriptorPrivilegeLevel, + uint8_t descriptorType) { + const uint8_t IDT_DESC_PRESENT = 0x80; + + interruptDescriptorTable[interruptNumber].handlerAddressLowBits = ((uint32_t)handler) & 0xFFFF; + interruptDescriptorTable[interruptNumber].handlerAddressHiBits = ((uint32_t)handler >> 16) & 0xFFFF; + interruptDescriptorTable[interruptNumber].gdt_codeSegmentSelector = codeSegmentSelectorOffset; + interruptDescriptorTable[interruptNumber].access = IDT_DESC_PRESENT | descriptorType | ((descriptorPrivilegeLevel & 3) << 5); + interruptDescriptorTable[interruptNumber].reserved = 0; +} + +uint32_t InterruptManager::HandleInterrupt(uint8_t interruptNumber, uint32_t esp) { + printf("INTERRUPT"); + return esp; +} diff --git a/src/interruptstubs.s b/src/interruptstubs.s new file mode 100644 index 0000000..d70048e --- /dev/null +++ b/src/interruptstubs.s @@ -0,0 +1,48 @@ +.set IRQ_BASE, 0x20 + +.section .text + +.extern _ZN16InterruptManager15HandleInterruptEhj +.global _ZN16InterruptManager22IgnoreInterruptRequestEv + + +.macro HandleException num +.global _ZN16InterruptManager16HandleException\num\()Ev +_ZN16InterruptManager16HandleException\num\()Ev: + movb $\num, (interruptnumber) + jmp int_bottom +.endm + +.macro HandleInterruptRequest num +.global _ZN16InterruptManager26HandleInterruptRequest\num\()Ev +_ZN16InterruptManager26HandleInterruptRequest\num\()Ev: + movb $\num + IRQ_BASE, (interruptnumber) + jmp int_bottom +.endm + +HandleInterruptRequest 0x00 +HandleInterruptRequest 0x01 + +int_bottom: + pusha + pushl %ds + pushl %es + pushl %fs + pushl %gs + + pushl %esp + push (interruptnumber) + call _ZN16InterruptManager15HandleInterruptEhj + movl %eax, %esp + + popl %gs + popl %fs + popl %es + popl %ds + popa + +_ZN16InterruptManager22IgnoreInterruptRequestEv: + + iret +.data + interruptnumber: .byte 0 diff --git a/src/kernel.cpp b/src/kernel.cpp index ab78512..e6d7c3d 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -7,6 +7,7 @@ */ #include "../include/gdt.h" +#include "../include/interrupts.h" #include "../include/types.h" void printf(char* str) { @@ -54,6 +55,12 @@ extern "C" void ferglos_Main(const void* multiboot_structure, uint32_t /*mb_mag* printf("Hitler blinks."); GlobalDescriptorTable gdt; + InterruptManager interrupts(&gdt); + + //instantiate hardware in here somewhere + + interrupts.Activate(); + while (1) ; } \ No newline at end of file diff --git a/src/port.cpp b/src/port.cpp new file mode 100644 index 0000000..943be86 --- /dev/null +++ b/src/port.cpp @@ -0,0 +1,71 @@ +/* + * port.cpp + * Author: Fergal Moran + * Copyright: 2020 Fergal Moran + * + * BSD License - do what you want + */ +#include "../include/port.h" + +Port::Port(uint16_t portNumber) { + this->portNumber = portNumber; +} +Port::~Port() { +} + +Port8Bit::Port8Bit(uint16_t portNumber) : Port(portNumber) {} +Port8Bit::~Port8Bit() {} + +void Port8Bit::Write(uint8_t data) { + __asm__ volatile("outb %0, %1" + : + : "a"(data), "Nd"(portNumber)); +} +uint8_t Port8Bit::Read() { + uint8_t result; + __asm__ volatile("inb %1, %0" + : "=a"(result) + : "Nd"(portNumber)); + return result; +} + +Port8Bit_Slow::Port8Bit_Slow(uint16_t portNumber) : Port8Bit(portNumber) {} +Port8Bit_Slow::~Port8Bit_Slow() {} + +void Port8Bit_Slow::Write(uint8_t data) { + __asm__ volatile("outb %0, %1\njmp 1f\n1: jmp 1f\n1:" + : + : "a"(data), "Nd"(portNumber)); +} + +Port16Bit::Port16Bit(uint16_t portNumber) : Port(portNumber) {} +Port16Bit::~Port16Bit() {} + +void Port16Bit::Write(uint16_t data) { + __asm__ volatile("outw %0, %1" + : + : "a"(data), "Nd"(portNumber)); +} +uint16_t Port16Bit::Read() { + uint16_t result; + __asm__ volatile("inw %1, %0" + : "=a"(result) + : "Nd"(portNumber)); + return result; +} + +Port32Bit::Port32Bit(uint16_t portNumber) : Port(portNumber) {} +Port32Bit::~Port32Bit() {} + +void Port32Bit::Write(uint32_t data) { + __asm__ volatile("outl %0, %1" + : + : "a"(data), "Nd"(portNumber)); +} +uint32_t Port32Bit::Read() { + uint32_t result; + __asm__ volatile("inl %1, %0" + : "=a"(result) + : "Nd"(portNumber)); + return result; +} \ No newline at end of file