x86_64: Add basic keyboard support with an ASYNC DRIVER
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
ed34009b50
commit
7952d1d8a0
@ -186,4 +186,5 @@ ISR 19 ; SIMD floating-point exception (#XM)
|
|||||||
ISR 20 ; virtualization exception (#VE)
|
ISR 20 ; virtualization exception (#VE)
|
||||||
ISR_ERROR 21 ; control-protection exception (#CP)
|
ISR_ERROR 21 ; control-protection exception (#CP)
|
||||||
; ISR 22-31 reserved
|
; ISR 22-31 reserved
|
||||||
IRQ 32, 0 ; timer interrupt
|
IRQ 32, 0 ; timer interrupt
|
||||||
|
IRQ 33, 0 ; keyboard interrupt
|
@ -2,10 +2,12 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "arch/Timer.h"
|
#include "arch/Timer.h"
|
||||||
#include "arch/x86_64/CPU.h"
|
#include "arch/x86_64/CPU.h"
|
||||||
|
#include "arch/x86_64/IO.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include <cpuid.h>
|
#include <cpuid.h>
|
||||||
#include <luna/CString.h>
|
#include <luna/CString.h>
|
||||||
|
#include <luna/CircularQueue.h>
|
||||||
#include <luna/Result.h>
|
#include <luna/Result.h>
|
||||||
#include <luna/SystemError.h>
|
#include <luna/SystemError.h>
|
||||||
#include <luna/Types.h>
|
#include <luna/Types.h>
|
||||||
@ -76,16 +78,35 @@ extern "C" void handle_x86_exception(Registers* regs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CircularQueue<u8, 60> scancode_queue;
|
||||||
|
|
||||||
|
void io_thread()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
u8 scancode;
|
||||||
|
while (!scancode_queue.try_pop(scancode)) { kernel_sleep(10); }
|
||||||
|
|
||||||
|
kinfoln("Read scancode: %#hhx", scancode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Called from _asm_interrupt_entry
|
// Called from _asm_interrupt_entry
|
||||||
extern "C" void arch_interrupt_entry(Registers* regs)
|
extern "C" void arch_interrupt_entry(Registers* regs)
|
||||||
{
|
{
|
||||||
if (regs->isr < 32) handle_x86_exception(regs);
|
if (regs->isr < 32) handle_x86_exception(regs);
|
||||||
else if (regs->isr == 32)
|
else if (regs->isr == 32) // Timer interrupt
|
||||||
{
|
{
|
||||||
Timer::tick();
|
Timer::tick();
|
||||||
if (should_invoke_scheduler()) Scheduler::invoke(regs);
|
if (should_invoke_scheduler()) Scheduler::invoke(regs);
|
||||||
pic_eoi(regs);
|
pic_eoi(regs);
|
||||||
}
|
}
|
||||||
|
else if (regs->isr == 33) // Keyboard interrupt
|
||||||
|
{
|
||||||
|
u8 scancode = IO::inb(0x60);
|
||||||
|
scancode_queue.try_push(scancode);
|
||||||
|
pic_eoi(regs);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
kwarnln("IRQ catched! Halting.");
|
kwarnln("IRQ catched! Halting.");
|
||||||
@ -151,6 +172,8 @@ namespace CPU
|
|||||||
|
|
||||||
void platform_finish_init()
|
void platform_finish_init()
|
||||||
{
|
{
|
||||||
|
Scheduler::new_kernel_thread(io_thread).expect_value("Could not create the IO background thread!");
|
||||||
|
|
||||||
remap_pic();
|
remap_pic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +82,7 @@ INT(19);
|
|||||||
INT(20);
|
INT(20);
|
||||||
INT(21);
|
INT(21);
|
||||||
INT(32);
|
INT(32);
|
||||||
|
INT(33);
|
||||||
|
|
||||||
void setup_idt()
|
void setup_idt()
|
||||||
{
|
{
|
||||||
@ -108,6 +109,7 @@ void setup_idt()
|
|||||||
TRAP(20);
|
TRAP(20);
|
||||||
TRAP(21);
|
TRAP(21);
|
||||||
IRQ(32);
|
IRQ(32);
|
||||||
|
IRQ(33);
|
||||||
|
|
||||||
static IDTR idtr;
|
static IDTR idtr;
|
||||||
idtr.limit = 0x0FFF;
|
idtr.limit = 0x0FFF;
|
||||||
|
@ -36,7 +36,7 @@ void remap_pic()
|
|||||||
IO::outb(PIC2_DATA, ICW4_8086);
|
IO::outb(PIC2_DATA, ICW4_8086);
|
||||||
io_delay();
|
io_delay();
|
||||||
|
|
||||||
IO::outb(PIC1_DATA, 0b11111110);
|
IO::outb(PIC1_DATA, 0b11111100);
|
||||||
io_delay();
|
io_delay();
|
||||||
IO::outb(PIC2_DATA, 0b11111111);
|
IO::outb(PIC2_DATA, 0b11111111);
|
||||||
}
|
}
|
||||||
|
@ -12,25 +12,12 @@
|
|||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include <luna/CString.h>
|
#include <luna/CString.h>
|
||||||
|
#include <luna/CircularQueue.h>
|
||||||
#include <luna/Result.h>
|
#include <luna/Result.h>
|
||||||
#include <luna/Units.h>
|
#include <luna/Units.h>
|
||||||
|
|
||||||
extern const BOOTBOOT bootboot;
|
extern const BOOTBOOT bootboot;
|
||||||
|
|
||||||
void async_thread()
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
Thread* current = Scheduler::current();
|
|
||||||
kinfoln("Ticks: %lu, %lu user, %lu kernel, %lu idle", current->ticks, current->ticks_in_user,
|
|
||||||
current->ticks_in_kernel, Scheduler::idle()->ticks);
|
|
||||||
|
|
||||||
CPU::wait_for_interrupt();
|
|
||||||
|
|
||||||
kernel_sleep(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void heap_thread()
|
void heap_thread()
|
||||||
{
|
{
|
||||||
CPU::disable_interrupts();
|
CPU::disable_interrupts();
|
||||||
@ -90,7 +77,6 @@ Result<void> init()
|
|||||||
Thread::init();
|
Thread::init();
|
||||||
Scheduler::init();
|
Scheduler::init();
|
||||||
|
|
||||||
TRY(Scheduler::new_kernel_thread(async_thread));
|
|
||||||
TRY(Scheduler::new_kernel_thread(heap_thread));
|
TRY(Scheduler::new_kernel_thread(heap_thread));
|
||||||
TRY(Scheduler::new_kernel_thread(reap_thread));
|
TRY(Scheduler::new_kernel_thread(reap_thread));
|
||||||
|
|
||||||
|
57
luna/include/luna/CircularQueue.h
Normal file
57
luna/include/luna/CircularQueue.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <luna/Atomic.h>
|
||||||
|
#include <luna/Types.h>
|
||||||
|
|
||||||
|
template <typename T, usize Size> class CircularQueue
|
||||||
|
{
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Capacity = Size + 1
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
CircularQueue()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_push(const T& value)
|
||||||
|
{
|
||||||
|
usize current_tail = m_tail.load(MemoryOrder::Relaxed);
|
||||||
|
const usize new_tail = (current_tail + 1) % Capacity;
|
||||||
|
if (new_tail == m_head.load(MemoryOrder::Acquire))
|
||||||
|
{
|
||||||
|
// Queue is full
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_data[current_tail] = value;
|
||||||
|
if (!m_tail.compare_exchange_strong(current_tail, new_tail, MemoryOrder::Release, MemoryOrder::Relaxed))
|
||||||
|
{
|
||||||
|
// Someone else updated the tail
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_pop(T& value)
|
||||||
|
{
|
||||||
|
usize current_head = m_head.load(MemoryOrder::Relaxed);
|
||||||
|
if (current_head == m_tail.load(MemoryOrder::Acquire))
|
||||||
|
{
|
||||||
|
// Queue is empty
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = m_data[current_head];
|
||||||
|
const usize new_head = (current_head + 1) % Capacity;
|
||||||
|
if (!m_head.compare_exchange_strong(current_head, new_head, MemoryOrder::Release, MemoryOrder::Relaxed))
|
||||||
|
{
|
||||||
|
// Someone else updated the head
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T m_data[Capacity];
|
||||||
|
Atomic<usize> m_head = 0;
|
||||||
|
Atomic<usize> m_tail = 0;
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user