Add interrupts and keyboard driver
This commit is contained in:
@@ -37,6 +37,7 @@ python3 scripts/embed_js.py build/index.js > "$BUILD_DIR/embedded_js.h"
|
||||
|
||||
# Compiler flags
|
||||
CFLAGS="-m32 -march=i686 -ffreestanding -nostdlib -fno-builtin"
|
||||
CFLAGS="$CFLAGS -mno-sse -mno-sse2 -mno-mmx -mno-3dnow"
|
||||
CFLAGS="$CFLAGS -I$PICOLIBC_INSTALL/include"
|
||||
CFLAGS="$CFLAGS -I./lib/duktape/src"
|
||||
CFLAGS="$CFLAGS -I./src/lib"
|
||||
@@ -56,10 +57,19 @@ echo "=== Building kernel with picolibc ==="
|
||||
echo "Assembling boot code..."
|
||||
nasm -f elf32 src/boot/kernel.asm -o "$BUILD_DIR/kasm.o"
|
||||
|
||||
# Build interrupt assembly
|
||||
echo "Assembling interrupt handlers..."
|
||||
nasm -f elf32 src/kernel/interrupt/interrupt.asm -o "$BUILD_DIR/interrupt.o"
|
||||
|
||||
# Build duktape
|
||||
echo "Building Duktape..."
|
||||
gcc $CFLAGS -c lib/duktape/src/duktape.c -o "$BUILD_DIR/duktape.o"
|
||||
|
||||
# Build interrupt system
|
||||
echo "Building interrupt system..."
|
||||
gcc $CFLAGS -c src/kernel/interrupt/idt.c -o "$BUILD_DIR/idt.o"
|
||||
gcc $CFLAGS -c src/kernel/interrupt/isr.c -o "$BUILD_DIR/isr.o"
|
||||
|
||||
# Build kernel
|
||||
echo "Building kernel..."
|
||||
gcc $CFLAGS -c src/kernel/kernel.c -o "$BUILD_DIR/kc.o"
|
||||
@@ -72,6 +82,9 @@ gcc $CFLAGS -c src/lib/syscalls.c -o "$BUILD_DIR/syscalls.o"
|
||||
echo "Linking kernel..."
|
||||
ld $LDFLAGS -T src/link.ld -o "$OUT_DIR/kernel" \
|
||||
"$BUILD_DIR/kasm.o" \
|
||||
"$BUILD_DIR/interrupt.o" \
|
||||
"$BUILD_DIR/idt.o" \
|
||||
"$BUILD_DIR/isr.o" \
|
||||
"$BUILD_DIR/kc.o" \
|
||||
"$BUILD_DIR/duktape.o" \
|
||||
"$BUILD_DIR/syscalls.o" \
|
||||
|
||||
@@ -8,10 +8,18 @@ section .text
|
||||
|
||||
global start
|
||||
extern kmain ;kmain is defined in the kernel.c file
|
||||
extern __stack_top
|
||||
|
||||
start:
|
||||
cli ; stop interrupts
|
||||
cli ; stop interrupts during boot
|
||||
mov esp, __stack_top
|
||||
|
||||
; Initialize FPU (x87)
|
||||
finit ; Initialize FPU to default state
|
||||
|
||||
call kmain
|
||||
; Note: kmain will call sti to enable interrupts after IDT is set up
|
||||
|
||||
hang:
|
||||
hlt ; halt the CPU
|
||||
jmp hang
|
||||
22
src/kernel/interrupt/idt.c
Normal file
22
src/kernel/interrupt/idt.c
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "idt.h"
|
||||
|
||||
/* Define the IDT and IDT register here */
|
||||
idt_gate_t idt[IDT_ENTRIES];
|
||||
idt_register_t idt_reg;
|
||||
|
||||
void set_idt_gate(int n, u32 handler)
|
||||
{
|
||||
idt[n].low_offset = low_16(handler);
|
||||
idt[n].sel = KERNEL_CS;
|
||||
idt[n].always0 = 0;
|
||||
idt[n].flags = 0x8E;
|
||||
idt[n].high_offset = high_16(handler);
|
||||
}
|
||||
|
||||
void set_idt()
|
||||
{
|
||||
idt_reg.base = (u32)&idt;
|
||||
idt_reg.limit = IDT_ENTRIES * sizeof(idt_gate_t) - 1;
|
||||
/* Don't make the mistake of loading &idt -- always load &idt_reg */
|
||||
__asm__ __volatile__("lidtl (%0)" : : "r"(&idt_reg));
|
||||
}
|
||||
40
src/kernel/interrupt/idt.h
Normal file
40
src/kernel/interrupt/idt.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef IDT_H
|
||||
#define IDT_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/* Segment selectors */
|
||||
#define KERNEL_CS 0x08
|
||||
|
||||
/* How every interrupt gate (handler) is defined */
|
||||
typedef struct
|
||||
{
|
||||
u16 low_offset; /* Lower 16 bits of handler function address */
|
||||
u16 sel; /* Kernel segment selector */
|
||||
u8 always0;
|
||||
/* First byte
|
||||
* Bit 7: "Interrupt is present"
|
||||
* Bits 6-5: Privilege level of caller (0=kernel..3=user)
|
||||
* Bit 4: Set to 0 for interrupt gates
|
||||
* Bits 3-0: bits 1110 = decimal 14 = "32 bit interrupt gate" */
|
||||
u8 flags;
|
||||
u16 high_offset; /* Higher 16 bits of handler function address */
|
||||
} __attribute__((packed)) idt_gate_t;
|
||||
|
||||
/* A pointer to the array of interrupt handlers.
|
||||
* Assembly instruction 'lidt' will read it */
|
||||
typedef struct
|
||||
{
|
||||
u16 limit;
|
||||
u32 base;
|
||||
} __attribute__((packed)) idt_register_t;
|
||||
|
||||
#define IDT_ENTRIES 256
|
||||
extern idt_gate_t idt[IDT_ENTRIES];
|
||||
extern idt_register_t idt_reg;
|
||||
|
||||
/* Functions implemented in idt.c */
|
||||
void set_idt_gate(int n, u32 handler);
|
||||
void set_idt();
|
||||
|
||||
#endif
|
||||
446
src/kernel/interrupt/interrupt.asm
Normal file
446
src/kernel/interrupt/interrupt.asm
Normal file
@@ -0,0 +1,446 @@
|
||||
; Defined in isr.c
|
||||
[extern isr_handler]
|
||||
[extern irq_handler]
|
||||
|
||||
; Common ISR code
|
||||
isr_common_stub:
|
||||
; 1. Save CPU state
|
||||
pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
|
||||
mov ax, ds ; Lower 16-bits of eax = ds.
|
||||
push eax ; save the data segment descriptor
|
||||
mov ax, 0x10 ; kernel data segment descriptor
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
; 2. Call C handler - pass pointer to registers_t struct on stack
|
||||
push esp
|
||||
call isr_handler
|
||||
add esp, 4
|
||||
|
||||
; 3. Restore state
|
||||
pop eax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
popa
|
||||
add esp, 8 ; Cleans up the pushed error code and pushed ISR number
|
||||
iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP (and restores interrupt flag)
|
||||
|
||||
; Common IRQ code
|
||||
irq_common_stub:
|
||||
; 1. Save CPU state
|
||||
pusha
|
||||
mov ax, ds
|
||||
push eax
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
; 2. Call C handler - pass pointer to registers_t struct on stack
|
||||
push esp
|
||||
call irq_handler
|
||||
add esp, 4
|
||||
|
||||
; 3. Restore state
|
||||
pop ebx
|
||||
mov ds, bx
|
||||
mov es, bx
|
||||
mov fs, bx
|
||||
mov gs, bx
|
||||
popa
|
||||
add esp, 8
|
||||
iret ; iret restores the interrupt flag automatically from saved EFLAGS
|
||||
|
||||
; We don't get information about which interrupt was caller
|
||||
; when the handler is run, so we will need to have a different handler
|
||||
; for every interrupt.
|
||||
; Furthermore, some interrupts push an error code onto the stack but others
|
||||
; don't, so we will push a dummy error code for those which don't, so that
|
||||
; we have a consistent stack for all of them.
|
||||
|
||||
; First make the ISRs global
|
||||
global isr0
|
||||
global isr1
|
||||
global isr2
|
||||
global isr3
|
||||
global isr4
|
||||
global isr5
|
||||
global isr6
|
||||
global isr7
|
||||
global isr8
|
||||
global isr9
|
||||
global isr10
|
||||
global isr11
|
||||
global isr12
|
||||
global isr13
|
||||
global isr14
|
||||
global isr15
|
||||
global isr16
|
||||
global isr17
|
||||
global isr18
|
||||
global isr19
|
||||
global isr20
|
||||
global isr21
|
||||
global isr22
|
||||
global isr23
|
||||
global isr24
|
||||
global isr25
|
||||
global isr26
|
||||
global isr27
|
||||
global isr28
|
||||
global isr29
|
||||
global isr30
|
||||
global isr31
|
||||
|
||||
; 0: Divide By Zero Exception
|
||||
isr0:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 0
|
||||
jmp isr_common_stub
|
||||
|
||||
; 1: Debug Exception
|
||||
isr1:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 1
|
||||
jmp isr_common_stub
|
||||
|
||||
; 2: Non Maskable Interrupt Exception
|
||||
isr2:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 2
|
||||
jmp isr_common_stub
|
||||
|
||||
; 3: Int 3 Exception
|
||||
isr3:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 3
|
||||
jmp isr_common_stub
|
||||
|
||||
; 4: INTO Exception
|
||||
isr4:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 4
|
||||
jmp isr_common_stub
|
||||
|
||||
; 5: Out of Bounds Exception
|
||||
isr5:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 5
|
||||
jmp isr_common_stub
|
||||
|
||||
; 6: Invalid Opcode Exception
|
||||
isr6:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 6
|
||||
jmp isr_common_stub
|
||||
|
||||
; 7: Coprocessor Not Available Exception
|
||||
isr7:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 7
|
||||
jmp isr_common_stub
|
||||
|
||||
; 8: Double Fault Exception (With Error Code!)
|
||||
isr8:
|
||||
cli
|
||||
push byte 8
|
||||
jmp isr_common_stub
|
||||
|
||||
; 9: Coprocessor Segment Overrun Exception
|
||||
isr9:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 9
|
||||
jmp isr_common_stub
|
||||
|
||||
; 10: Bad TSS Exception (With Error Code!)
|
||||
isr10:
|
||||
cli
|
||||
push byte 10
|
||||
jmp isr_common_stub
|
||||
|
||||
; 11: Segment Not Present Exception (With Error Code!)
|
||||
isr11:
|
||||
cli
|
||||
push byte 11
|
||||
jmp isr_common_stub
|
||||
|
||||
; 12: Stack Fault Exception (With Error Code!)
|
||||
isr12:
|
||||
cli
|
||||
push byte 12
|
||||
jmp isr_common_stub
|
||||
|
||||
; 13: General Protection Fault Exception (With Error Code!)
|
||||
isr13:
|
||||
cli
|
||||
push byte 13
|
||||
jmp isr_common_stub
|
||||
|
||||
; 14: Page Fault Exception (With Error Code!)
|
||||
isr14:
|
||||
cli
|
||||
push byte 14
|
||||
jmp isr_common_stub
|
||||
|
||||
; 15: Reserved Exception
|
||||
isr15:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 15
|
||||
jmp isr_common_stub
|
||||
|
||||
; 16: Floating Point Exception
|
||||
isr16:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 16
|
||||
jmp isr_common_stub
|
||||
|
||||
; 17: Alignment Check Exception
|
||||
isr17:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 17
|
||||
jmp isr_common_stub
|
||||
|
||||
; 18: Machine Check Exception
|
||||
isr18:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 18
|
||||
jmp isr_common_stub
|
||||
|
||||
; 19: Reserved
|
||||
isr19:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 19
|
||||
jmp isr_common_stub
|
||||
|
||||
; 20: Reserved
|
||||
isr20:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 20
|
||||
jmp isr_common_stub
|
||||
|
||||
; 21: Reserved
|
||||
isr21:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 21
|
||||
jmp isr_common_stub
|
||||
|
||||
; 22: Reserved
|
||||
isr22:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 22
|
||||
jmp isr_common_stub
|
||||
|
||||
; 23: Reserved
|
||||
isr23:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 23
|
||||
jmp isr_common_stub
|
||||
|
||||
; 24: Reserved
|
||||
isr24:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 24
|
||||
jmp isr_common_stub
|
||||
|
||||
; 25: Reserved
|
||||
isr25:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 25
|
||||
jmp isr_common_stub
|
||||
|
||||
; 26: Reserved
|
||||
isr26:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 26
|
||||
jmp isr_common_stub
|
||||
|
||||
; 27: Reserved
|
||||
isr27:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 27
|
||||
jmp isr_common_stub
|
||||
|
||||
; 28: Reserved
|
||||
isr28:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 28
|
||||
jmp isr_common_stub
|
||||
|
||||
; 29: Reserved
|
||||
isr29:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 29
|
||||
jmp isr_common_stub
|
||||
|
||||
; 30: Reserved
|
||||
isr30:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 30
|
||||
jmp isr_common_stub
|
||||
|
||||
; 31: Reserved
|
||||
isr31:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 31
|
||||
jmp isr_common_stub
|
||||
|
||||
; IRQ handlers
|
||||
global irq0
|
||||
global irq1
|
||||
global irq2
|
||||
global irq3
|
||||
global irq4
|
||||
global irq5
|
||||
global irq6
|
||||
global irq7
|
||||
global irq8
|
||||
global irq9
|
||||
global irq10
|
||||
global irq11
|
||||
global irq12
|
||||
global irq13
|
||||
global irq14
|
||||
global irq15
|
||||
|
||||
; IRQ 0: System Timer
|
||||
irq0:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 32
|
||||
jmp irq_common_stub
|
||||
|
||||
; IRQ 1: Keyboard
|
||||
irq1:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 33
|
||||
jmp irq_common_stub
|
||||
|
||||
; IRQ 2: Cascade (never raised)
|
||||
irq2:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 34
|
||||
jmp irq_common_stub
|
||||
|
||||
; IRQ 3: COM2
|
||||
irq3:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 35
|
||||
jmp irq_common_stub
|
||||
|
||||
; IRQ 4: COM1
|
||||
irq4:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 36
|
||||
jmp irq_common_stub
|
||||
|
||||
; IRQ 5: LPT2
|
||||
irq5:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 37
|
||||
jmp irq_common_stub
|
||||
|
||||
; IRQ 6: Floppy Disk
|
||||
irq6:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 38
|
||||
jmp irq_common_stub
|
||||
|
||||
; IRQ 7: LPT1
|
||||
irq7:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 39
|
||||
jmp irq_common_stub
|
||||
|
||||
; IRQ 8: CMOS Real-time Clock
|
||||
irq8:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 40
|
||||
jmp irq_common_stub
|
||||
|
||||
; IRQ 9: Free for peripherals
|
||||
irq9:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 41
|
||||
jmp irq_common_stub
|
||||
|
||||
; IRQ 10: Free for peripherals
|
||||
irq10:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 42
|
||||
jmp irq_common_stub
|
||||
|
||||
; IRQ 11: Free for peripherals
|
||||
irq11:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 43
|
||||
jmp irq_common_stub
|
||||
|
||||
; IRQ 12: PS/2 Mouse
|
||||
irq12:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 44
|
||||
jmp irq_common_stub
|
||||
|
||||
; IRQ 13: FPU
|
||||
irq13:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 45
|
||||
jmp irq_common_stub
|
||||
|
||||
; IRQ 14: Primary ATA Hard Disk
|
||||
irq14:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 46
|
||||
jmp irq_common_stub
|
||||
|
||||
; IRQ 15: Secondary ATA Hard Disk
|
||||
irq15:
|
||||
cli
|
||||
push byte 0
|
||||
push byte 47
|
||||
jmp irq_common_stub
|
||||
317
src/kernel/interrupt/isr.c
Normal file
317
src/kernel/interrupt/isr.c
Normal file
@@ -0,0 +1,317 @@
|
||||
#include "isr.h"
|
||||
#include "idt.h"
|
||||
|
||||
/* Port I/O functions */
|
||||
static inline void outb(u16 port, u8 val)
|
||||
{
|
||||
__asm__ volatile("outb %0, %1" : : "a"(val), "Nd"(port));
|
||||
}
|
||||
|
||||
static inline u8 inb(u16 port)
|
||||
{
|
||||
u8 ret;
|
||||
__asm__ volatile("inb %1, %0" : "=a"(ret) : "Nd"(port));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* PIC (Programmable Interrupt Controller) constants */
|
||||
#define PIC1_COMMAND 0x20
|
||||
#define PIC1_DATA 0x21
|
||||
#define PIC2_COMMAND 0xA0
|
||||
#define PIC2_DATA 0xA1
|
||||
#define PIC_EOI 0x20
|
||||
|
||||
/* Array to store custom IRQ handlers */
|
||||
static irq_handler_t irq_handlers[16] = {0};
|
||||
|
||||
/* Can't do this with a loop because we need the address
|
||||
* of the function names */
|
||||
void isr_install()
|
||||
{
|
||||
set_idt_gate(0, (u32)isr0);
|
||||
set_idt_gate(1, (u32)isr1);
|
||||
set_idt_gate(2, (u32)isr2);
|
||||
set_idt_gate(3, (u32)isr3);
|
||||
set_idt_gate(4, (u32)isr4);
|
||||
set_idt_gate(5, (u32)isr5);
|
||||
set_idt_gate(6, (u32)isr6);
|
||||
set_idt_gate(7, (u32)isr7);
|
||||
set_idt_gate(8, (u32)isr8);
|
||||
set_idt_gate(9, (u32)isr9);
|
||||
set_idt_gate(10, (u32)isr10);
|
||||
set_idt_gate(11, (u32)isr11);
|
||||
set_idt_gate(12, (u32)isr12);
|
||||
set_idt_gate(13, (u32)isr13);
|
||||
set_idt_gate(14, (u32)isr14);
|
||||
set_idt_gate(15, (u32)isr15);
|
||||
set_idt_gate(16, (u32)isr16);
|
||||
set_idt_gate(17, (u32)isr17);
|
||||
set_idt_gate(18, (u32)isr18);
|
||||
set_idt_gate(19, (u32)isr19);
|
||||
set_idt_gate(20, (u32)isr20);
|
||||
set_idt_gate(21, (u32)isr21);
|
||||
set_idt_gate(22, (u32)isr22);
|
||||
set_idt_gate(23, (u32)isr23);
|
||||
set_idt_gate(24, (u32)isr24);
|
||||
set_idt_gate(25, (u32)isr25);
|
||||
set_idt_gate(26, (u32)isr26);
|
||||
set_idt_gate(27, (u32)isr27);
|
||||
set_idt_gate(28, (u32)isr28);
|
||||
set_idt_gate(29, (u32)isr29);
|
||||
set_idt_gate(30, (u32)isr30);
|
||||
set_idt_gate(31, (u32)isr31);
|
||||
|
||||
set_idt(); // Load with ASM
|
||||
}
|
||||
|
||||
/* Remap the PIC to avoid conflicts with CPU exceptions */
|
||||
static void pic_remap(void)
|
||||
{
|
||||
// Start initialization
|
||||
outb(PIC1_COMMAND, 0x11);
|
||||
outb(PIC2_COMMAND, 0x11);
|
||||
|
||||
// Set vector offsets (IRQs 0-7 -> interrupts 32-39, IRQs 8-15 -> interrupts 40-47)
|
||||
outb(PIC1_DATA, 0x20);
|
||||
outb(PIC2_DATA, 0x28);
|
||||
|
||||
// Tell master PIC there's a slave PIC at IRQ2
|
||||
outb(PIC1_DATA, 0x04);
|
||||
// Tell slave PIC its cascade identity
|
||||
outb(PIC2_DATA, 0x02);
|
||||
|
||||
// Set to 8086 mode
|
||||
outb(PIC1_DATA, 0x01);
|
||||
outb(PIC2_DATA, 0x01);
|
||||
|
||||
// Mask all interrupts initially
|
||||
outb(PIC1_DATA, 0xFF);
|
||||
outb(PIC2_DATA, 0xFF);
|
||||
}
|
||||
|
||||
/* Install IRQ handlers */
|
||||
void irq_install()
|
||||
{
|
||||
// Remap the PIC
|
||||
pic_remap();
|
||||
|
||||
// Install IRQ handlers (32-47)
|
||||
set_idt_gate(32, (u32)irq0);
|
||||
set_idt_gate(33, (u32)irq1);
|
||||
set_idt_gate(34, (u32)irq2);
|
||||
set_idt_gate(35, (u32)irq3);
|
||||
set_idt_gate(36, (u32)irq4);
|
||||
set_idt_gate(37, (u32)irq5);
|
||||
set_idt_gate(38, (u32)irq6);
|
||||
set_idt_gate(39, (u32)irq7);
|
||||
set_idt_gate(40, (u32)irq8);
|
||||
set_idt_gate(41, (u32)irq9);
|
||||
set_idt_gate(42, (u32)irq10);
|
||||
set_idt_gate(43, (u32)irq11);
|
||||
set_idt_gate(44, (u32)irq12);
|
||||
set_idt_gate(45, (u32)irq13);
|
||||
set_idt_gate(46, (u32)irq14);
|
||||
set_idt_gate(47, (u32)irq15);
|
||||
|
||||
set_idt(); // Reload IDT
|
||||
}
|
||||
|
||||
/* To print the message which defines every exception */
|
||||
char *exception_messages[] = {
|
||||
"Division By Zero",
|
||||
"Debug",
|
||||
"Non Maskable Interrupt",
|
||||
"Breakpoint",
|
||||
"Into Detected Overflow",
|
||||
"Out of Bounds",
|
||||
"Invalid Opcode",
|
||||
"No Coprocessor",
|
||||
|
||||
"Double Fault",
|
||||
"Coprocessor Segment Overrun",
|
||||
"Bad TSS",
|
||||
"Segment Not Present",
|
||||
"Stack Fault",
|
||||
"General Protection Fault",
|
||||
"Page Fault",
|
||||
"Unknown Interrupt",
|
||||
|
||||
"Coprocessor Fault",
|
||||
"Alignment Check",
|
||||
"Machine Check",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved"};
|
||||
|
||||
void isr_handler(registers_t *r)
|
||||
{
|
||||
// Write exception to VGA memory
|
||||
char *vidmem = (char *)0xb8000;
|
||||
const char *msg = "EXCEPTION: ";
|
||||
int i = 0;
|
||||
|
||||
// Clear first line
|
||||
for (i = 0; i < 80 * 2; i++)
|
||||
{
|
||||
vidmem[i] = 0;
|
||||
}
|
||||
|
||||
// Write message
|
||||
i = 0;
|
||||
while (msg[i])
|
||||
{
|
||||
vidmem[i * 2] = msg[i];
|
||||
vidmem[i * 2 + 1] = 0x4F; // White on red
|
||||
i++;
|
||||
}
|
||||
|
||||
// Write exception number
|
||||
vidmem[i * 2] = '0' + (r->int_no / 10);
|
||||
vidmem[i * 2 + 1] = 0x4F;
|
||||
i++;
|
||||
vidmem[i * 2] = '0' + (r->int_no % 10);
|
||||
vidmem[i * 2 + 1] = 0x4F;
|
||||
i++;
|
||||
|
||||
// Write error code
|
||||
vidmem[i * 2] = ' ';
|
||||
vidmem[i * 2 + 1] = 0x4F;
|
||||
i++;
|
||||
vidmem[i * 2] = 'E';
|
||||
vidmem[i * 2 + 1] = 0x4F;
|
||||
i++;
|
||||
vidmem[i * 2] = 'R';
|
||||
vidmem[i * 2 + 1] = 0x4F;
|
||||
i++;
|
||||
vidmem[i * 2] = 'R';
|
||||
vidmem[i * 2 + 1] = 0x4F;
|
||||
i++;
|
||||
vidmem[i * 2] = ':';
|
||||
vidmem[i * 2 + 1] = 0x4F;
|
||||
i++;
|
||||
|
||||
// Write error code in hex
|
||||
u32 err = r->err_code;
|
||||
for (int j = 7; j >= 0; j--)
|
||||
{
|
||||
u8 nibble = (err >> (j * 4)) & 0xF;
|
||||
vidmem[i * 2] = nibble < 10 ? '0' + nibble : 'A' + (nibble - 10);
|
||||
vidmem[i * 2 + 1] = 0x4F;
|
||||
i++;
|
||||
}
|
||||
|
||||
// Write EIP
|
||||
i++;
|
||||
vidmem[i * 2] = 'E';
|
||||
vidmem[i * 2 + 1] = 0x4F;
|
||||
i++;
|
||||
vidmem[i * 2] = 'I';
|
||||
vidmem[i * 2 + 1] = 0x4F;
|
||||
i++;
|
||||
vidmem[i * 2] = 'P';
|
||||
vidmem[i * 2 + 1] = 0x4F;
|
||||
i++;
|
||||
vidmem[i * 2] = ':';
|
||||
vidmem[i * 2 + 1] = 0x4F;
|
||||
i++;
|
||||
|
||||
// Write EIP in hex
|
||||
u32 eip = r->eip;
|
||||
for (int j = 7; j >= 0; j--)
|
||||
{
|
||||
u8 nibble = (eip >> (j * 4)) & 0xF;
|
||||
vidmem[i * 2] = nibble < 10 ? '0' + nibble : 'A' + (nibble - 10);
|
||||
vidmem[i * 2 + 1] = 0x4F;
|
||||
i++;
|
||||
}
|
||||
|
||||
// Halt
|
||||
__asm__ volatile("cli; hlt");
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
/* IRQ handler */
|
||||
void irq_handler(registers_t *r)
|
||||
{
|
||||
// Calculate IRQ number (interrupts 32-47 map to IRQ 0-15)
|
||||
u8 irq_no = r->int_no - 32;
|
||||
|
||||
// Handle spurious IRQ7 (from master PIC)
|
||||
if (irq_no == 7)
|
||||
{
|
||||
// Read In-Service Register (ISR)
|
||||
outb(PIC1_COMMAND, 0x0B);
|
||||
u8 isr = inb(PIC1_COMMAND);
|
||||
if (!(isr & 0x80))
|
||||
{
|
||||
// Spurious interrupt, don't send EOI
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle spurious IRQ15 (from slave PIC)
|
||||
if (irq_no == 15)
|
||||
{
|
||||
// Read In-Service Register (ISR) of slave PIC
|
||||
outb(PIC2_COMMAND, 0x0B);
|
||||
u8 isr = inb(PIC2_COMMAND);
|
||||
if (!(isr & 0x80))
|
||||
{
|
||||
// Spurious interrupt from slave, send EOI to master only
|
||||
outb(PIC1_COMMAND, PIC_EOI);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Call custom handler if registered
|
||||
if (irq_handlers[irq_no] != 0)
|
||||
{
|
||||
irq_handlers[irq_no](r);
|
||||
}
|
||||
|
||||
// Send EOI to PIC
|
||||
if (r->int_no >= 40)
|
||||
{
|
||||
// IRQ came from slave PIC, send EOI to both
|
||||
outb(PIC2_COMMAND, PIC_EOI);
|
||||
}
|
||||
outb(PIC1_COMMAND, PIC_EOI);
|
||||
}
|
||||
|
||||
/* Register a custom IRQ handler */
|
||||
void irq_register_handler(u8 irq, irq_handler_t handler)
|
||||
{
|
||||
if (irq < 16)
|
||||
{
|
||||
irq_handlers[irq] = handler;
|
||||
|
||||
// Unmask the IRQ on the PIC
|
||||
u16 port;
|
||||
u8 value;
|
||||
|
||||
if (irq < 8)
|
||||
{
|
||||
port = PIC1_DATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
port = PIC2_DATA;
|
||||
irq -= 8;
|
||||
}
|
||||
|
||||
value = inb(port) & ~(1 << irq);
|
||||
outb(port, value);
|
||||
}
|
||||
}
|
||||
78
src/kernel/interrupt/isr.h
Normal file
78
src/kernel/interrupt/isr.h
Normal file
@@ -0,0 +1,78 @@
|
||||
#ifndef ISR_H
|
||||
#define ISR_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/* ISRs reserved for CPU exceptions */
|
||||
extern void isr0();
|
||||
extern void isr1();
|
||||
extern void isr2();
|
||||
extern void isr3();
|
||||
extern void isr4();
|
||||
extern void isr5();
|
||||
extern void isr6();
|
||||
extern void isr7();
|
||||
extern void isr8();
|
||||
extern void isr9();
|
||||
extern void isr10();
|
||||
extern void isr11();
|
||||
extern void isr12();
|
||||
extern void isr13();
|
||||
extern void isr14();
|
||||
extern void isr15();
|
||||
extern void isr16();
|
||||
extern void isr17();
|
||||
extern void isr18();
|
||||
extern void isr19();
|
||||
extern void isr20();
|
||||
extern void isr21();
|
||||
extern void isr22();
|
||||
extern void isr23();
|
||||
extern void isr24();
|
||||
extern void isr25();
|
||||
extern void isr26();
|
||||
extern void isr27();
|
||||
extern void isr28();
|
||||
extern void isr29();
|
||||
extern void isr30();
|
||||
extern void isr31();
|
||||
|
||||
/* IRQ handlers */
|
||||
extern void irq0();
|
||||
extern void irq1();
|
||||
extern void irq2();
|
||||
extern void irq3();
|
||||
extern void irq4();
|
||||
extern void irq5();
|
||||
extern void irq6();
|
||||
extern void irq7();
|
||||
extern void irq8();
|
||||
extern void irq9();
|
||||
extern void irq10();
|
||||
extern void irq11();
|
||||
extern void irq12();
|
||||
extern void irq13();
|
||||
extern void irq14();
|
||||
extern void irq15();
|
||||
|
||||
/* Struct which aggregates many registers */
|
||||
typedef struct
|
||||
{
|
||||
u32 ds; /* Data segment selector */
|
||||
u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; /* Pushed by pusha. */
|
||||
u32 int_no, err_code; /* Interrupt number and error code (if applicable) */
|
||||
u32 eip, cs, eflags, useresp, ss; /* Pushed by the processor automatically */
|
||||
} registers_t;
|
||||
|
||||
/* Function pointer type for IRQ handlers */
|
||||
typedef void (*irq_handler_t)(registers_t *);
|
||||
|
||||
void isr_install();
|
||||
void isr_handler(registers_t *r);
|
||||
void irq_install();
|
||||
void irq_handler(registers_t *r);
|
||||
|
||||
/* Register a custom IRQ handler */
|
||||
void irq_register_handler(u8 irq, irq_handler_t handler);
|
||||
|
||||
#endif
|
||||
16
src/kernel/interrupt/types.h
Normal file
16
src/kernel/interrupt/types.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
/* Instead of using 'chars' to allocate non-character bytes,
|
||||
* we will use these new type with no semantic meaning */
|
||||
typedef unsigned int u32;
|
||||
typedef int s32;
|
||||
typedef unsigned short u16;
|
||||
typedef short s16;
|
||||
typedef unsigned char u8;
|
||||
typedef char s8;
|
||||
|
||||
#define low_16(address) (u16)((address) & 0xFFFF)
|
||||
#define high_16(address) (u16)(((address) >> 16) & 0xFFFF)
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,9 @@
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <duktape.h>
|
||||
#include "embedded_js.h"
|
||||
#include "interrupt/isr.h"
|
||||
|
||||
#define WHITE_TXT 0x0F
|
||||
|
||||
@@ -56,6 +58,35 @@ duk_ret_t native_ptout(duk_context *ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
duk_ret_t native_byte_in(duk_context *ctx)
|
||||
{
|
||||
// Get the port (first argument)
|
||||
uint16_t port = (uint16_t)duk_to_uint32(ctx, 0);
|
||||
|
||||
uint8_t result;
|
||||
__asm__ volatile("inb %1, %0"
|
||||
: "=a"(result)
|
||||
: "Nd"(port));
|
||||
|
||||
duk_push_uint(ctx, (duk_uint_t)result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
duk_ret_t native_byte_out(duk_context *ctx)
|
||||
{
|
||||
// Get the port (first argument)
|
||||
uint16_t port = (uint16_t)duk_to_uint32(ctx, 0);
|
||||
|
||||
// Get the value to write (second argument)
|
||||
uint8_t value = (uint8_t)duk_to_uint32(ctx, 1);
|
||||
|
||||
__asm__ volatile("outb %0, %1"
|
||||
:
|
||||
: "a"(value), "Nd"(port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
duk_ret_t native_dword_in(duk_context *ctx)
|
||||
{
|
||||
// Get the port (first argument)
|
||||
@@ -85,10 +116,90 @@ duk_ret_t native_dword_out(duk_context *ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Global context for IRQ handlers
|
||||
duk_context *global_ctx = NULL;
|
||||
|
||||
// JavaScript IRQ wrapper
|
||||
void js_irq_callback(registers_t *r)
|
||||
{
|
||||
if (global_ctx == NULL)
|
||||
return;
|
||||
|
||||
// Get IRQ number
|
||||
u8 irq_no = r->int_no - 32;
|
||||
|
||||
// Build the key for this IRQ handler manually (avoid snprintf in interrupt)
|
||||
char key[32] = "irq_handler_";
|
||||
int key_len = 12;
|
||||
if (irq_no >= 10)
|
||||
{
|
||||
key[key_len++] = '0' + (irq_no / 10);
|
||||
key[key_len++] = '0' + (irq_no % 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
key[key_len++] = '0' + irq_no;
|
||||
}
|
||||
key[key_len] = '\0';
|
||||
|
||||
// Call the JavaScript handler
|
||||
duk_push_global_stash(global_ctx);
|
||||
|
||||
if (duk_get_prop_string(global_ctx, -1, key))
|
||||
{
|
||||
// Function found, call it with IRQ number
|
||||
duk_push_uint(global_ctx, irq_no);
|
||||
|
||||
// Try protected call with error handler
|
||||
duk_int_t rc = duk_pcall(global_ctx, 1);
|
||||
duk_pop(global_ctx); // Pop result or error
|
||||
}
|
||||
else
|
||||
{
|
||||
duk_pop(global_ctx); // Pop undefined value
|
||||
}
|
||||
|
||||
duk_pop(global_ctx); // Pop stash
|
||||
}
|
||||
|
||||
// Native function to register IRQ from JavaScript
|
||||
duk_ret_t native_irq_register(duk_context *ctx)
|
||||
{
|
||||
// Get the IRQ number
|
||||
u8 irq = (u8)duk_to_uint32(ctx, 0);
|
||||
|
||||
// Get the handler function
|
||||
if (!duk_is_function(ctx, 1))
|
||||
{
|
||||
duk_push_boolean(ctx, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Store function in global stash
|
||||
char key[32];
|
||||
snprintf(key, sizeof(key), "irq_handler_%d", irq);
|
||||
|
||||
duk_push_global_stash(ctx);
|
||||
duk_dup(ctx, 1); // Duplicate the function
|
||||
duk_put_prop_string(ctx, -2, key);
|
||||
duk_pop(ctx); // Pop stash
|
||||
|
||||
// Register the C wrapper
|
||||
irq_register_handler(irq, js_irq_callback);
|
||||
|
||||
duk_push_boolean(ctx, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void kmain()
|
||||
{
|
||||
// Initialize IDT and ISRs
|
||||
isr_install();
|
||||
irq_install();
|
||||
|
||||
// Initialize Duktape heap
|
||||
ctx = duk_create_heap_default();
|
||||
global_ctx = ctx;
|
||||
|
||||
// Register native memory write function
|
||||
duk_push_c_function(ctx, native_addrw, 2);
|
||||
@@ -102,6 +213,14 @@ void kmain()
|
||||
duk_push_c_function(ctx, native_ptout, 2);
|
||||
duk_put_global_string(ctx, "$ptout");
|
||||
|
||||
// Register native byte in function
|
||||
duk_push_c_function(ctx, native_byte_in, 1);
|
||||
duk_put_global_string(ctx, "$bytein");
|
||||
|
||||
// Register native byte out function
|
||||
duk_push_c_function(ctx, native_byte_out, 2);
|
||||
duk_put_global_string(ctx, "$byteout");
|
||||
|
||||
// Register native dword in function
|
||||
duk_push_c_function(ctx, native_dword_in, 1);
|
||||
duk_put_global_string(ctx, "$dwordin");
|
||||
@@ -110,6 +229,13 @@ void kmain()
|
||||
duk_push_c_function(ctx, native_dword_out, 2);
|
||||
duk_put_global_string(ctx, "$dwordout");
|
||||
|
||||
// Register native IRQ registration function
|
||||
duk_push_c_function(ctx, native_irq_register, 2);
|
||||
duk_put_global_string(ctx, "$irqregister");
|
||||
|
||||
// Enable interrupts before JavaScript execution
|
||||
__asm__ volatile("sti");
|
||||
|
||||
// Execute embedded JavaScript code from build/index.js
|
||||
duk_push_string(ctx, embedded_js_code);
|
||||
duk_int_t returnCode = duk_peval(ctx);
|
||||
|
||||
57
src/os/src/config/keyboard.ts
Normal file
57
src/os/src/config/keyboard.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
export const Keycode = {
|
||||
Q: 16,
|
||||
W: 17,
|
||||
E: 18,
|
||||
R: 19,
|
||||
T: 20,
|
||||
Y: 21,
|
||||
U: 22,
|
||||
I: 23,
|
||||
O: 24,
|
||||
P: 25,
|
||||
A: 30,
|
||||
S: 31,
|
||||
D: 32,
|
||||
F: 33,
|
||||
G: 34,
|
||||
H: 35,
|
||||
J: 36,
|
||||
K: 37,
|
||||
L: 38,
|
||||
Z: 44,
|
||||
X: 45,
|
||||
C: 46,
|
||||
V: 47,
|
||||
B: 48,
|
||||
N: 49,
|
||||
M: 50,
|
||||
};
|
||||
|
||||
export const RKeycode = {
|
||||
16: "Q",
|
||||
17: "W",
|
||||
18: "E",
|
||||
19: "R",
|
||||
20: "T",
|
||||
21: "Y",
|
||||
22: "U",
|
||||
23: "I",
|
||||
24: "O",
|
||||
25: "P",
|
||||
30: "A",
|
||||
31: "S",
|
||||
32: "D",
|
||||
33: "F",
|
||||
34: "G",
|
||||
35: "H",
|
||||
36: "J",
|
||||
37: "K",
|
||||
38: "L",
|
||||
44: "Z",
|
||||
45: "X",
|
||||
46: "C",
|
||||
47: "V",
|
||||
48: "B",
|
||||
49: "N",
|
||||
50: "M",
|
||||
};
|
||||
29
src/os/src/kernel/drivers/dev/keyboard.ts
Normal file
29
src/os/src/kernel/drivers/dev/keyboard.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Keycode, RKeycode } from "../../../config/keyboard";
|
||||
import { Logger } from "../../../lib/libstd/logger/logger.kmod";
|
||||
import { bytein } from "../../../lib/libts/byte";
|
||||
import { kmod_cpu_irq_register } from "../../modules/cpu/interrupts";
|
||||
import { kmod_terminal_input_handleKeyboardInput } from "../../modules/terminal/input";
|
||||
|
||||
export function kdriver_dev_keyboard_handleInterrupt(): void {
|
||||
const scancode = bytein(0x60);
|
||||
|
||||
const key = RKeycode[scancode as keyof typeof RKeycode] as
|
||||
| keyof typeof Keycode
|
||||
| undefined;
|
||||
|
||||
if (key == undefined) return;
|
||||
|
||||
kmod_terminal_input_handleKeyboardInput(key);
|
||||
}
|
||||
|
||||
export function kdriver_dev_keyboard_init(): void {
|
||||
if (!kmod_cpu_irq_register(1, kdriver_dev_keyboard_handleInterrupt, null)) {
|
||||
Logger.log("[keyboard] Failed to register keyboard interrupt");
|
||||
return;
|
||||
}
|
||||
|
||||
let key = 0;
|
||||
while ((key = bytein(0x64) & 1) == 1) {
|
||||
bytein(0x60);
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,10 @@ import {
|
||||
kmod_graphics_vga_init,
|
||||
kmod_graphics_vga_pushLine,
|
||||
} from "./modules/graphics/graphics.kmod";
|
||||
import {
|
||||
kmod_terminal_input_init,
|
||||
kmod_terminal_input_onKeyboardInput,
|
||||
} from "./modules/terminal/input";
|
||||
|
||||
export function kmain() {
|
||||
kmod_drivers_init();
|
||||
@@ -33,14 +37,17 @@ export function kmain() {
|
||||
kmod_filesystem_init();
|
||||
kmod_filesystem_mount("/sys", sysfs_driver);
|
||||
|
||||
Logger.log("[Kernel] Initializing terminal module...");
|
||||
kmod_terminal_input_init();
|
||||
|
||||
Logger.log("[Kernel] Initializing PCI devices...");
|
||||
kdriver_dev_pci_detectDevices();
|
||||
|
||||
Logger.log("[Kernel] Initializing VGA module...");
|
||||
kmod_graphics_vga_init();
|
||||
kmod_graphics_vga_pushLine("[Kernel] Kernel initialized successfully.");
|
||||
kmod_graphics_vga_pushLine("Current date: " + getDate().toDateString());
|
||||
kmod_graphics_vga_pushLine(
|
||||
Number(kmod_filesystem_readFile("/sys/pci/0:1:0/vendor")).toString(16)
|
||||
);
|
||||
|
||||
kmod_terminal_input_onKeyboardInput(function (keycode) {
|
||||
kmod_graphics_vga_pushLine(keycode);
|
||||
});
|
||||
}
|
||||
|
||||
43
src/os/src/kernel/modules/cpu/interrupts.ts
Normal file
43
src/os/src/kernel/modules/cpu/interrupts.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { Logger } from "../../../lib/libstd/logger/logger.kmod";
|
||||
import type { KInterrupt, KInterruptHandler } from "../../../types/interrupt";
|
||||
|
||||
const kmod_cpu_irq_data: KInterrupt[] = [];
|
||||
|
||||
export function kmod_cpu_irq_register(
|
||||
irq: number,
|
||||
handler: KInterruptHandler,
|
||||
data: unknown
|
||||
): boolean {
|
||||
if (kmod_cpu_irq_data[irq]) {
|
||||
Logger.log("[IRQ] IRQ " + irq + " is already registered.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (irq > 15) {
|
||||
Logger.log("[IRQ] IRQ " + irq + " is out of bounds.");
|
||||
return false;
|
||||
}
|
||||
|
||||
kmod_cpu_irq_data[irq] = {
|
||||
handler: handler,
|
||||
data: data,
|
||||
};
|
||||
|
||||
function wrapper(irqNum: number) {
|
||||
const irqData = kmod_cpu_irq_data[irqNum];
|
||||
if (irqData) {
|
||||
irqData.handler(irqNum, irqData.data);
|
||||
}
|
||||
}
|
||||
|
||||
const success = $irqregister(irq, wrapper);
|
||||
|
||||
if (!success) {
|
||||
Logger.log("[IRQ] Failed to register IRQ " + irq + " with hardware.");
|
||||
delete kmod_cpu_irq_data[irq];
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger.log("[IRQ] Successfully registered IRQ " + irq);
|
||||
return true;
|
||||
}
|
||||
@@ -1,7 +1,12 @@
|
||||
import { kdriver_dev_keyboard_init } from "../../drivers/dev/keyboard";
|
||||
import { kdriver_dev_pci_init } from "../../drivers/dev/pci";
|
||||
import { kdriver_etc_serial_init } from "../../drivers/etc/serial";
|
||||
|
||||
const drivers = [kdriver_etc_serial_init, kdriver_dev_pci_init];
|
||||
const drivers = [
|
||||
kdriver_etc_serial_init,
|
||||
kdriver_dev_pci_init,
|
||||
kdriver_dev_keyboard_init,
|
||||
];
|
||||
|
||||
export function kmod_drivers_init(): void {}
|
||||
|
||||
|
||||
21
src/os/src/kernel/modules/terminal/input.ts
Normal file
21
src/os/src/kernel/modules/terminal/input.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import type { Keycode } from "../../../config/keyboard";
|
||||
|
||||
const kmod_terminal_input_keyboardInputHandlers: Array<
|
||||
(keycode: keyof typeof Keycode) => void
|
||||
> = [];
|
||||
|
||||
export function kmod_terminal_input_init(): void {}
|
||||
|
||||
export function kmod_terminal_input_onKeyboardInput(
|
||||
handler: (keycode: keyof typeof Keycode) => void
|
||||
) {
|
||||
kmod_terminal_input_keyboardInputHandlers.push(handler);
|
||||
}
|
||||
|
||||
export function kmod_terminal_input_handleKeyboardInput(
|
||||
keycode: keyof typeof Keycode
|
||||
): void {
|
||||
for (let i = 0; i < kmod_terminal_input_keyboardInputHandlers.length; i++) {
|
||||
kmod_terminal_input_keyboardInputHandlers[i]!(keycode);
|
||||
}
|
||||
}
|
||||
1
src/os/src/kernel/modules/terminal/terminal.kmod.ts
Normal file
1
src/os/src/kernel/modules/terminal/terminal.kmod.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./input";
|
||||
@@ -1,3 +1,11 @@
|
||||
export function bytein(port: number): number {
|
||||
return $bytein(port);
|
||||
}
|
||||
|
||||
export function byteout(port: number, value: number): void {
|
||||
$byteout(port, value);
|
||||
}
|
||||
|
||||
export function charc(char: string): number {
|
||||
return char.charCodeAt(0);
|
||||
}
|
||||
|
||||
6
src/os/src/types/c/bindings.d.ts
vendored
6
src/os/src/types/c/bindings.d.ts
vendored
@@ -1,5 +1,11 @@
|
||||
declare function $addrw(address: number, value: number): void;
|
||||
declare function $ptin(port: number): number;
|
||||
declare function $ptout(port: number, value: number): void;
|
||||
declare function $bytein(port: number): number;
|
||||
declare function $byteout(port: number, value: number): void;
|
||||
declare function $dwordin(port: number): number;
|
||||
declare function $dwordout(port: number, value: number): void;
|
||||
declare const $irqregister: (
|
||||
irq: number,
|
||||
handler: (irqNum: number) => void
|
||||
) => boolean;
|
||||
|
||||
9
src/os/src/types/interrupt.ts
Normal file
9
src/os/src/types/interrupt.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export type KInterruptHandler = (
|
||||
interruptNumber: number,
|
||||
data?: unknown
|
||||
) => void;
|
||||
|
||||
export type KInterrupt = {
|
||||
handler: KInterruptHandler;
|
||||
data: unknown;
|
||||
};
|
||||
Reference in New Issue
Block a user