diff --git a/kernel/boot/boot.S b/kernel/boot/boot.S index d7b8f20..53c6d0f 100644 --- a/kernel/boot/boot.S +++ b/kernel/boot/boot.S @@ -18,9 +18,9 @@ stack_top: .section .text .global _start -.type _start, @function _start: + cli mov $stack_top, %esp call kmain -1: - jmp 1b +loop: + jmp loop diff --git a/kernel/common_stubs.S b/kernel/common_stubs.S index d9b3cfb..5370460 100644 --- a/kernel/common_stubs.S +++ b/kernel/common_stubs.S @@ -3,4 +3,9 @@ .global enable_interrupts enable_interrupts: sti + ret + +.global io_wait +io_wait: + outb %al, $0x80 ret \ No newline at end of file diff --git a/kernel/drivers/pic/pic_stubs.S b/kernel/drivers/pic/pic_stubs.S index 42332bd..43dfae5 100644 --- a/kernel/drivers/pic/pic_stubs.S +++ b/kernel/drivers/pic/pic_stubs.S @@ -1,6 +1,8 @@ #include "drivers/pic/pic.h" .code32 +.extern io_wait + .global init_pic init_pic: # init command @@ -17,7 +19,7 @@ init_pic: # cascade mov $0x04, %al outb %al, $PIC1_DATA - mov $0x02, %al + mov $0x02, %al outb %al, $PIC2_DATA # env @@ -25,7 +27,7 @@ init_pic: outb %al, $PIC1_DATA outb %al, $PIC2_DATA - # mask all + # mask mov $0xFC, %al outb %al, $PIC1_DATA mov $0xFF, %al @@ -33,10 +35,6 @@ init_pic: ret -.global io_wait -io_wait: - ret - .global send_eoi_master send_eoi_master: mov $0x20, %al @@ -49,3 +47,19 @@ send_eoi_slave: outb %al, $PIC2_COMMAND call send_eoi_master ret + +.global read_isr_master +read_isr_master: + xorl %eax, %eax + mov $0x0B, %al + outb %al, $PIC1_COMMAND + in $PIC1_COMMAND, %al + ret + +.global read_isr_slave +read_isr_slave: + xorl %eax, %eax + mov $0x0B, %al + outb %al, $PIC2_COMMAND + in $PIC2_COMMAND, %al + ret \ No newline at end of file diff --git a/kernel/drivers/ps2/ps2.c b/kernel/drivers/ps2/ps2.c new file mode 100644 index 0000000..b4b06c9 --- /dev/null +++ b/kernel/drivers/ps2/ps2.c @@ -0,0 +1,70 @@ +#include +#include + +extern void ps2_wait_input_empty(void); +extern void ps2_wait_output_full(void); +extern void ps2_write_command(uint8_t); +extern uint8_t ps2_read_data(void); +extern void ps2_write_data(uint8_t); +extern void ps2_flush_output_buffer(void); + +extern void io_wait(void); + +static uint8_t read_ccb() { + ps2_write_command(CMD_READ_CCB); + io_wait(); + return ps2_read_data(); +} + +static void write_ccb(uint8_t ccb) { + ps2_write_command(CMD_WRITE_CCB); + io_wait(); + ps2_write_data(ccb); + io_wait(); +} + +static int perform_self_test() { + ps2_write_command(CMD_SELF_TEST); + io_wait(); + return ps2_read_data(); +} + +static int test_port_1() { + ps2_write_command(CMD_TEST_P1); + io_wait(); + return ps2_read_data(); +} + +static void enable_port_1() { + ps2_write_command(CMD_ENABLE_P1); + io_wait(); +} + +int init_ps2() { + ps2_write_command(CMD_DISABLE_P1); + ps2_write_command(CMD_DISABLE_P2); + + ps2_flush_output_buffer(); + + uint8_t ccb = read_ccb(); + ccb = ccb & 0xEC; + write_ccb(ccb); + + int result = perform_self_test(); + if (result != SELF_TEST_SUCCESS) { + return -1; + } + + result = test_port_1(); + if (result != PORT_TEST_SUCCESS) { + return -1; + } + + enable_port_1(); + + ccb = read_ccb(); + ccb |= 0x01; // this enables interrupts for port 1, which we want + write_ccb(ccb); + + return 0; +} \ No newline at end of file diff --git a/kernel/drivers/ps2/ps2.h b/kernel/drivers/ps2/ps2.h new file mode 100644 index 0000000..5019f50 --- /dev/null +++ b/kernel/drivers/ps2/ps2.h @@ -0,0 +1,19 @@ +#ifndef KPS2_H +#define KPS2_H + +#define PS2_DATA 0x60 +#define PS2_STATUS 0x64 +#define PS2_COMMAND 0x64 + +#define CMD_DISABLE_P1 0xAD +#define CMD_DISABLE_P2 0xAE +#define CMD_READ_CCB 0x20 +#define CMD_WRITE_CCB 0x60 +#define CMD_SELF_TEST 0xAA +#define CMD_TEST_P1 0xAB +#define CMD_ENABLE_P1 0xAE + +#define SELF_TEST_SUCCESS 0x55 +#define PORT_TEST_SUCCESS 0x00 + +#endif \ No newline at end of file diff --git a/kernel/drivers/ps2/ps2_stubs.S b/kernel/drivers/ps2/ps2_stubs.S new file mode 100644 index 0000000..79a2145 --- /dev/null +++ b/kernel/drivers/ps2/ps2_stubs.S @@ -0,0 +1,87 @@ +#include "drivers/ps2/ps2.h" + +.code32 + +.global ps2_wait_input_empty +.global ps2_wait_output_full +.global ps2_write_command +.global ps2_read_data +.global ps2_write_data +.global ps2_flush_output_buffer + +.extern io_wait + +# helpers +ps2_wait_input_empty: #(void) -> void + push %ebp + mov %esp, %ebp +1: + inb $PS2_STATUS, %al + andb $0x02, %al + jnz 1b + + leave + ret + +ps2_wait_output_full: #(void) -> void + push %ebp + mov %esp, %ebp +1: + inb $PS2_STATUS, %al + andb $0x01, %al + jz 1b + + leave + ret + +ps2_write_command: #(uint8_t command) -> void + push %ebp + mov %esp, %ebp + + call ps2_wait_input_empty + + xor %eax, %eax + movb 8(%ebp), %al + outb %al, $PS2_COMMAND + + leave + ret + +ps2_read_data: #(void) -> uint8_t + push %ebp + mov %esp, %ebp + + call ps2_wait_output_full + + xor %eax, %eax + inb $PS2_DATA, %al + + leave + ret + +ps2_write_data: #(uint8_t) -> void + push %ebp + mov %esp, %ebp + + call ps2_wait_input_empty + + xor %eax, %eax + movb 8(%ebp), %al + outb %al, $PS2_DATA + + leave + ret + + +ps2_flush_output_buffer: #(void) -> void + push %ebp + mov %esp, %ebp +1: + inb $PS2_STATUS, %al + andb $0x01, %al + jz 2f + inb $PS2_DATA, %al + jmp 1b +2: + leave + ret \ No newline at end of file diff --git a/kernel/idt_stubs.S b/kernel/idt_stubs.S index e097fdc..cebc1ec 100644 --- a/kernel/idt_stubs.S +++ b/kernel/idt_stubs.S @@ -27,12 +27,6 @@ isr_common_stub: addl $8, %esp iret -.global master_eoi -master_eoi: - movb $0x20, %al - outb %al, $0x20 - ret - .extern idtr .global load_idt load_idt: diff --git a/kernel/interrupts.c b/kernel/interrupts.c index 357869f..58a508f 100644 --- a/kernel/interrupts.c +++ b/kernel/interrupts.c @@ -3,6 +3,10 @@ extern void send_eoi_master(void); extern void send_eoi_slave(void); +extern uint8_t read_isr_master(void); +extern uint8_t read_isr_slave(void); + +extern uint8_t ps2_read_data(); struct registers { uint32_t edi, esi, ebp, esp_dummy, ebx, edx, ecx, eax; @@ -17,29 +21,42 @@ const char* err_messages[32] = { [0] = "Divide by 0", [1] = "", [8] = "", - [13] = "General Protection Fault", + [13] = "General Protection Fault",a->i [14] = "Page Fault", }; -void common_interrupt_handler(struct registers *regs) { - switch (regs->int_no) { +void common_interrupt_handler(struct registers *args) { + switch (args->int_no) { case 0: case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: case 8: + case 9: + case 10: + case 11: + case 12: case 13: case 14: + case 15: + case 16: kprint("CPU Error: "); - kprint(err_messages[regs->int_no]); + kprint(err_messages[args->int_no]); kprint("\n"); break; case 32: // wake the PIT timer driver send_eoi_master(); break; - case 33: - kprint("keypress detected\n"); + case 33: { + uint8_t data = ps2_read_data(); send_eoi_master(); break; + } default: kprint("Received unhandled interrupt\n"); return; diff --git a/kernel/kmain.c b/kernel/kmain.c index debc051..3259920 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -9,6 +9,7 @@ extern void init_idt(); extern void init_gdt(); extern void init_pic(); extern void init_pit(); +extern int init_ps2(); extern void enable_interrupts(); void kmain(void) @@ -32,6 +33,13 @@ void kmain(void) init_pit(); kprint("PIT initialized\n"); + int result = init_ps2(); + if (result == -1) { + kprint("PS2 init failed\n"); + return; + } + kprint("PS2 initialized\n"); + enable_interrupts(); kprint("Interrupts enabled\n"); diff --git a/kernel/lib/print.c b/kernel/lib/print.c index a499f16..52eff96 100644 --- a/kernel/lib/print.c +++ b/kernel/lib/print.c @@ -8,4 +8,8 @@ void kprint(const char *str) { kout->putchar(*str); str++; } +} + +void kputc(const char c) { + kout->putchar(c); } \ No newline at end of file diff --git a/kernel/lib/print.h b/kernel/lib/print.h index 43c0b75..4949898 100644 --- a/kernel/lib/print.h +++ b/kernel/lib/print.h @@ -2,5 +2,6 @@ #define KLIBPRINT_H void kprint(const char* str); +void kputc(const char c); #endif \ No newline at end of file