Skip to content

Commit

Permalink
Add IRQHandler class that can be subclasses to handle an IRQ.
Browse files Browse the repository at this point in the history
Also move Keyboard to a class implementation using this pattern.
  • Loading branch information
awesomekling committed Oct 22, 2018
1 parent 8f94156 commit a9ca75c
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 100 deletions.
25 changes: 25 additions & 0 deletions Kernel/IRQHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include "IRQHandler.h"
#include "i386.h"
#include "PIC.h"

IRQHandler::IRQHandler(byte irq)
: m_irqNumber(irq)
{
registerIRQHandler(m_irqNumber, *this);
}

IRQHandler::~IRQHandler()
{
unregisterIRQHandler(m_irqNumber, *this);
}

void IRQHandler::enableIRQ()
{
PIC::enable(m_irqNumber);
}

void IRQHandler::disableIRQ()
{
PIC::disable(m_irqNumber);
}

21 changes: 21 additions & 0 deletions Kernel/IRQHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include <AK/Types.h>

class IRQHandler {
public:
virtual ~IRQHandler();
virtual void handleIRQ() = 0;

byte irqNumber() const { return m_irqNumber; }

void enableIRQ();
void disableIRQ();

protected:
explicit IRQHandler(byte irq);

private:
byte m_irqNumber { 0 };
};

84 changes: 16 additions & 68 deletions Kernel/Keyboard.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
#include "types.h"
#include "i386.h"
#include "IO.h"
#include "IPC.h"
#include "Task.h"
#include "VGA.h"
#include "PIC.h"
#include "Keyboard.h"
#include <AK/Assertions.h>

#define IRQ_KEYBOARD 1

Expand All @@ -16,36 +15,6 @@
#define DATA_AVAILABLE 0x01
#define I8042_ACK 0xFA

extern "C" void handleKeyboardInterrupt();
extern "C" void keyboard_ISR();

static BYTE s_ledState;

asm(
".globl keyboard_ISR \n"
"keyboard_ISR: \n"
" pusha\n"
" pushw %ds\n"
" pushw %es\n"
" pushw %ss\n"
" pushw %ss\n"
" popw %ds\n"
" popw %es\n"
" call handleKeyboardInterrupt\n"
" popw %es\n"
" popw %ds\n"
" popa\n"
" iret\n"
);

void handleKeyboardInterrupt()
{
IRQHandlerScope scope(IRQ_KEYBOARD);
Keyboard::handleInterrupt();
}

namespace Keyboard {

#define MOD_ALT 1
#define MOD_CTRL 2
#define MOD_SHIFT 4
Expand All @@ -66,70 +35,49 @@ static char shift_map[0x100] =
'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?',
};

static BYTE s_modifiers;

void handleInterrupt()
void Keyboard::handleIRQ()
{
while (IO::in8(0x64) & 1) {
BYTE ch = IO::in8(0x60);
switch (ch) {
case 0x38: s_modifiers |= MOD_ALT; break;
case 0xB8: s_modifiers &= ~MOD_ALT; break;
case 0x1D: s_modifiers |= MOD_CTRL; break;
case 0x9D: s_modifiers &= ~MOD_CTRL; break;
case 0x2A: s_modifiers |= MOD_SHIFT; break;
case 0xAA: s_modifiers &= ~MOD_SHIFT; break;
case 0x38: m_modifiers |= MOD_ALT; break;
case 0xB8: m_modifiers &= ~MOD_ALT; break;
case 0x1D: m_modifiers |= MOD_CTRL; break;
case 0x9D: m_modifiers &= ~MOD_CTRL; break;
case 0x2A: m_modifiers |= MOD_SHIFT; break;
case 0xAA: m_modifiers &= ~MOD_SHIFT; break;
case 0x1C: /* enter */ kprintf("\n"); break;
case 0xFA: /* i8042 ack */ break;
default:
if (ch & 0x80) {
// key has been depressed
break;
}
if (!s_modifiers)
if (!m_modifiers)
kprintf("%c", map[ch]);
else if (s_modifiers & MOD_SHIFT)
else if (m_modifiers & MOD_SHIFT)
kprintf("%c", shift_map[ch]);
else if (s_modifiers & MOD_CTRL)
else if (m_modifiers & MOD_CTRL)
kprintf("^%c", shift_map[ch]);
}
//break;
}
}

void initialize()
Keyboard::Keyboard()
: IRQHandler(IRQ_KEYBOARD)
{
s_modifiers = 0;
s_ledState = 0;

// Empty the buffer of any pending data.
// I don't care what you've been pressing until now!
while (IO::in8(I8042_STATUS ) & DATA_AVAILABLE)
IO::in8(I8042_BUFFER);

registerInterruptHandler(IRQ_VECTOR_BASE + IRQ_KEYBOARD, keyboard_ISR);

PIC::enable(IRQ_KEYBOARD);
enableIRQ();
}

void setLED(LED led)
Keyboard::~Keyboard()
{
s_ledState |= (BYTE)led & 7;

while (IO::in8(I8042_STATUS) & DATA_AVAILABLE);
IO::out8(I8042_BUFFER, SET_LEDS);
while (IO::in8(I8042_BUFFER) != I8042_ACK);
IO::out8(I8042_BUFFER, s_ledState);
ASSERT_NOT_REACHED();
}

void unsetLED(LED led)
{
s_ledState &= ~((BYTE)led & 7);

while (IO::in8(I8042_STATUS) & DATA_AVAILABLE);
IO::out8(I8042_BUFFER, SET_LEDS);
while (IO::in8(I8042_BUFFER) != I8042_ACK);
IO::out8(I8042_BUFFER, s_ledState);
}

}
22 changes: 11 additions & 11 deletions Kernel/Keyboard.h
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
#pragma once

namespace Keyboard {
#include <AK/Types.h>
#include "IRQHandler.h"

enum class LED {
ScrollLock = 1 << 0,
NumLock = 1 << 1,
CapsLock = 1 << 2,
};
class Keyboard final : public IRQHandler {
public:
virtual ~Keyboard() override;
Keyboard();

private:
virtual void handleIRQ() override;

void initialize();
void setLED(LED);
void unsetLED(LED);
void handleInterrupt();
byte m_modifiers { 0 };
};

}
3 changes: 2 additions & 1 deletion Kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ KERNEL_OBJS = \
Userspace.o \
IDEDiskDevice.o \
MemoryManager.o \
Console.o
Console.o \
IRQHandler.o

VFS_OBJS = \
../VirtualFileSystem/DiskDevice.o \
Expand Down
65 changes: 65 additions & 0 deletions Kernel/i386.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "Assertions.h"
#include "Task.h"
#include "MemoryManager.h"
#include "IRQHandler.h"
#include "PIC.h"

struct DescriptorTablePointer {
WORD size;
Expand All @@ -16,6 +18,8 @@ static DescriptorTablePointer s_gdtr;
static Descriptor* s_idt;
static Descriptor* s_gdt;

static IRQHandler** s_irqHandler;

static WORD s_gdtLength;

WORD allocateGDTEntry()
Expand All @@ -27,6 +31,26 @@ WORD allocateGDTEntry()
return newGDTEntry;
}

extern "C" void handleIRQ();
extern "C" void commonIRQEntry();

asm(
".globl commonIRQEntry\n"
"commonIRQEntry: \n"
" pusha\n"
" pushw %ds\n"
" pushw %es\n"
" pushw %ss\n"
" pushw %ss\n"
" popw %ds\n"
" popw %es\n"
" call handleIRQ\n"
" popw %es\n"
" popw %ds\n"
" popa\n"
" iret\n"
);

extern volatile dword exception_state_dump;
extern volatile word exception_code;
asm(
Expand Down Expand Up @@ -290,6 +314,20 @@ static void unimp_trap()
HANG;
}

void registerIRQHandler(byte irq, IRQHandler& handler)
{
ASSERT(!s_irqHandler[irq]);
s_irqHandler[irq] = &handler;
kprintf("irq handler for %u: %p\n", irq, &handler);
registerInterruptHandler(IRQ_VECTOR_BASE + irq, commonIRQEntry);
}

void unregisterIRQHandler(byte irq, IRQHandler& handler)
{
ASSERT(s_irqHandler[irq] == &handler);
s_irqHandler[irq] = nullptr;
}

void registerInterruptHandler(BYTE index, void (*f)())
{
s_idt[index].low = 0x00080000 | LSW((f));
Expand Down Expand Up @@ -351,10 +389,37 @@ void idt_init()

registerInterruptHandler(0x57, irq7_handler);

s_irqHandler = new IRQHandler*[16];
for (byte i = 0; i < 16; ++i) {
s_irqHandler[i] = nullptr;
}

flushIDT();
}

void loadTaskRegister(WORD selector)
{
asm("ltr %0"::"r"(selector));
}

void handleIRQ()
{
WORD isr = PIC::getISR();
if (!isr) {
kprintf("Spurious IRQ\n");
return;
}

byte irq;
for (byte i = 0; i < 16; ++i) {
if (isr & (1 << i)) {
irq = i;
break;
}
}

if (s_irqHandler[irq])
s_irqHandler[irq]->handleIRQ();
PIC::eoi(irq);
}

4 changes: 4 additions & 0 deletions Kernel/i386.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,14 @@ union Descriptor {
}
} PACKED;

class IRQHandler;

void gdt_init();
void idt_init();
void registerInterruptHandler(BYTE number, void (*f)());
void registerUserCallableInterruptHandler(BYTE number, void (*f)());
void registerIRQHandler(BYTE number, IRQHandler&);
void unregisterIRQHandler(BYTE number, IRQHandler&);
void flushIDT();
void flushGDT();
void loadTaskRegister(WORD selector);
Expand Down
Loading

0 comments on commit a9ca75c

Please sign in to comment.