keyboard drivers

This commit is contained in:
TriMill 2023-04-21 09:39:35 -04:00
parent 0fa2351940
commit bca17fe5b9
30 changed files with 931 additions and 220 deletions

View File

@ -1,6 +1,6 @@
CC=i386-elf-gcc CC=i386-elf-gcc
LD=i386-elf-ld LD=i386-elf-ld
CFLAGS=-ffreestanding -g -m32 -std=c2x -O2 -Wall -Wextra -pedantic -lgcc -isystem ./libk/include CFLAGS=-ffreestanding -ggdb -m32 -std=gnu17 -O3 -Wall -Wextra -pedantic -lgcc -isystem ./libk/include
C_SOURCE=$(shell find kernel -type f -name "*.c") C_SOURCE=$(shell find kernel -type f -name "*.c")
C_OBJ=$(patsubst %.c,bin/%.o,$(C_SOURCE)) C_OBJ=$(patsubst %.c,bin/%.o,$(C_SOURCE))
@ -31,11 +31,11 @@ bin/libk.a: $(LIBK_OBJ)
@mkdir -p $(@D) @mkdir -p $(@D)
$(AR) rcs bin/libk.a $(LIBK_OBJ) $(AR) rcs bin/libk.a $(LIBK_OBJ)
bin/kernel.bin: bin/libk.a $(A_OBJ) $(C_OBJ) bin/kernel.bin: bin/libk.a linker.ld $(A_OBJ) $(C_OBJ)
@mkdir -p $(@D) @mkdir -p $(@D)
$(LD) -nmagic -o bin/kernel.bin -T linker.ld $(A_OBJ) $(C_OBJ) bin/libk.a $(LD) -nmagic -o bin/kernel.bin -T linker.ld $(A_OBJ) $(C_OBJ) bin/libk.a
bin/os.iso: bin/kernel.bin bin/os.iso: bin/kernel.bin grub.cfg
@mkdir -p $(@D) @mkdir -p $(@D)
@mkdir -p bin/iso/boot/grub @mkdir -p bin/iso/boot/grub
cp grub.cfg bin/iso/boot/grub cp grub.cfg bin/iso/boot/grub

View File

@ -1,4 +1,4 @@
set timeout=0 set timeout=1
set default=0 set default=0
menuentry "trios" { menuentry "trios" {

46
kernel/bootinfo.c Normal file
View File

@ -0,0 +1,46 @@
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "panic.h"
#include "term.h"
#include "bootinfo.h"
#define CMDLINE_MAX 128
static char boot_cmdline[CMDLINE_MAX];
static uint32_t *read_tag(uint32_t *tag) {
uint32_t type = tag[0];
size_t size = tag[1];
switch(type) {
case 0: return NULL;
case 1: {
size_t cmdline_len = size - 2 * sizeof(uint32_t);
if(cmdline_len > CMDLINE_MAX) {
panic("Command line argument length %d exceeds maximum length %d", cmdline_len, CMDLINE_MAX);
}
char* cmdline = (char*)(tag + 2);
memcpy(boot_cmdline, cmdline, cmdline_len);
break;
}
default: break;
}
if(size % 8 != 0) {
size += 8 - (size % 8);
}
return tag + size / sizeof(uint32_t);
}
void bootinfo_load(void *ptr) {
uint32_t *p = ptr;
p += 2;
while(p != NULL) {
p = read_tag(p);
}
}
char* bootinfo_get_cmdline(void) {
return boot_cmdline;
}

7
kernel/bootinfo.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include <stdint.h>
void bootinfo_load(void* ptr);
char* bootinfo_get_cmdline(void);

134
kernel/drivers/keycodes.h Normal file
View File

@ -0,0 +1,134 @@
#pragma once
#include <stdint.h>
struct Keycode {
uint8_t key;
uint8_t flags;
};
#define KC_FLAG_KEY_DOWN 0x01
#define KC_FLAG_KEY_UP 0x02
#define KC_FLAG_ERROR 0x04
#define KEY_NONE 0x00
#define KEY_UNKNOWN 0x01
#define KEY_ESCAPE 0x10
#define KEY_1 0x11
#define KEY_2 0x12
#define KEY_3 0x13
#define KEY_4 0x14
#define KEY_5 0x15
#define KEY_6 0x16
#define KEY_7 0x17
#define KEY_8 0x18
#define KEY_9 0x19
#define KEY_0 0x1A
#define KEY_MINUS 0x1B
#define KEY_EQUAL 0x1C
#define KEY_BACKSPACE 0x1D
#define KEY_L_SHIFT 0x1E
#define KEY_R_SHIFT 0x1F
#define KEY_TAB 0x20
#define KEY_Q 0x21
#define KEY_W 0x22
#define KEY_E 0x23
#define KEY_R 0x24
#define KEY_T 0x25
#define KEY_Y 0x26
#define KEY_U 0x27
#define KEY_I 0x28
#define KEY_O 0x29
#define KEY_P 0x2A
#define KEY_L_BRACE 0x2B
#define KEY_R_BRACE 0x2C
#define KEY_BACKSLASH 0x2D
#define KEY_L_CTRL 0x2E
#define KEY_R_CTRL 0x2F
#define KEY_CAPS_LOCK 0x30
#define KEY_A 0x31
#define KEY_S 0x32
#define KEY_D 0x33
#define KEY_F 0x34
#define KEY_G 0x35
#define KEY_H 0x36
#define KEY_J 0x37
#define KEY_K 0x38
#define KEY_L 0x39
#define KEY_SEMICOLON 0x3A
#define KEY_QUOTE 0x3B
#define KEY_ENTER 0x3C
#define KEY_MENU 0x3D
#define KEY_L_ALT 0x3E
#define KEY_R_ALT 0x3F
#define KEY_SPACE 0x40
#define KEY_Z 0x41
#define KEY_X 0x42
#define KEY_C 0x43
#define KEY_V 0x44
#define KEY_B 0x45
#define KEY_N 0x46
#define KEY_M 0x47
#define KEY_COMMA 0x48
#define KEY_PERIOD 0x49
#define KEY_SLASH 0x4A
#define KEY_BACKTICK 0x4B
#define KEY_NUM_LOCK 0x4C
#define KEY_SCROLL_LOCK 0x4D
#define KEY_L_META 0x4E
#define KEY_R_META 0x4F
#define KEY_NP_SLASH 0x50
#define KEY_NP_7 0x51
#define KEY_NP_8 0x52
#define KEY_NP_9 0x53
#define KEY_NP_ASTERISK 0x54
#define KEY_NP_4 0x55
#define KEY_NP_5 0x56
#define KEY_NP_6 0x57
#define KEY_NP_MINUS 0x58
#define KEY_NP_1 0x59
#define KEY_NP_2 0x5A
#define KEY_NP_3 0x5B
#define KEY_NP_PLUS 0x5C
#define KEY_NP_0 0x5D
#define KEY_NP_PERIOD 0x5E
#define KEY_NP_ENTER 0x5F
#define KEY_PRINT_SCREEN 0x60
#define KEY_PAUSE 0x61
#define KEY_INSERT 0x62
#define KEY_HOME 0x63
#define KEY_PAGE_UP 0x64
#define KEY_DELETE 0x65
#define KEY_END 0x66
#define KEY_PAGE_DOWN 0x67
#define KEY_UP 0x68
#define KEY_DOWN 0x69
#define KEY_LEFT 0x6A
#define KEY_RIGHT 0x6B
// #define _ 0x6C
// #define _ 0x6D
// #define _ 0x6E
// #define _ 0x6F
#define KEY_F1 0x70
#define KEY_F2 0x71
#define KEY_F3 0x72
#define KEY_F4 0x73
#define KEY_F5 0x74
#define KEY_F6 0x75
#define KEY_F7 0x76
#define KEY_F8 0x77
#define KEY_F9 0x78
#define KEY_F10 0x79
#define KEY_F11 0x7A
#define KEY_F12 0x7B
// #define _ 0x7C
// #define _ 0x7D
// #define _ 0x7E
// #define _ 0x7F

73
kernel/drivers/ps2ctrl.c Normal file
View File

@ -0,0 +1,73 @@
#include <stdint.h>
#include <sys.h>
#include "ps2ctrl.h"
#include "../panic.h"
#include "../interrupt/pic.h"
#define STATUS_OUT_BUF ((uint8_t)0x01)
#define STATUS_IN_BUF ((uint8_t)0x02)
#define CONFIG_INT_0 ((uint8_t)0x01)
#define CONFIG_INT_1 ((uint8_t)0x02)
#define CONFIG_SYS ((uint8_t)0x04)
#define CONFIG_CLOCK_0 ((uint8_t)0x10)
#define CONFIG_CLOCK_1 ((uint8_t)0x20)
#define CONFIG_TRANS ((uint8_t)0x40)
uint8_t ps2ctrl_in_status(void) {
return inb(0x64);
}
uint8_t ps2ctrl_in(void) {
while((ps2ctrl_in_status() & STATUS_OUT_BUF) == 0) {
io_wait();
}
return inb(0x60);
}
void ps2ctrl_out_cmd(uint8_t cmd) {
while((ps2ctrl_in_status() & STATUS_IN_BUF) != 0) {
io_wait();
}
outb(0x64, cmd);
}
void ps2ctrl_out_data(uint8_t data) {
while((ps2ctrl_in_status() & STATUS_IN_BUF) != 0) {
io_wait();
}
outb(0x60, data);
}
static bool is_init = false;
void ps2ctrl_init(void) {
is_init = false;
pic_mask(1);
// clear buffer
inb(0x60);
// self-test
ps2ctrl_out_cmd(0xAA);
uint8_t response = ps2ctrl_in();
if(response != 0x55) {
panic("PS/2 controller failed to initialize");
}
// set config
ps2ctrl_out_cmd(0x20);
uint8_t config = ps2ctrl_in();
config = (config | CONFIG_INT_0) & ~CONFIG_TRANS & ~CONFIG_INT_1;
ps2ctrl_out_cmd(0x60);
ps2ctrl_out_data(config);
// enable port 0
ps2ctrl_out_cmd(0xAE);
pic_unmask(1);
is_init = true;
}
bool ps2ctrl_is_init(void) {
return is_init;
}

13
kernel/drivers/ps2ctrl.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
uint8_t ps2ctrl_in(void);
uint8_t ps2ctrl_in_status(void);
void ps2ctrl_out_cmd(uint8_t cmd);
void ps2ctrl_out_data(uint8_t data);
void ps2ctrl_init(void);
bool ps2ctrl_is_init(void);

127
kernel/drivers/ps2kb.c Normal file
View File

@ -0,0 +1,127 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include "../term.h"
#include "../panic.h"
#include "../interrupt/pic.h"
#include <string.h>
#include <sys.h>
#include "ps2ctrl.h"
#include "ps2kb.h"
#include "keycodes.h"
#define BUFFER_LEN 16
#define KEYCODE_ARRAY_LEN 0x84
static uint8_t scancodes[] = {
// 00/08 01/09 02/0A 03/0B 04/0C 05/0D 06/0E 07/0F
/*00*/ KEY_NONE, KEY_F9, KEY_NONE, KEY_F5, KEY_F3, KEY_F1, KEY_F2, KEY_F12,
/*08*/ KEY_NONE, KEY_F10, KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_BACKTICK, KEY_NONE,
/*10*/ KEY_NONE, KEY_L_ALT, KEY_L_SHIFT, KEY_NONE, KEY_L_CTRL, KEY_Q, KEY_1, KEY_NONE,
/*18*/ KEY_NONE, KEY_NONE, KEY_Z, KEY_S, KEY_A, KEY_W, KEY_2, KEY_NONE,
/*20*/ KEY_NONE, KEY_C, KEY_X, KEY_D, KEY_E, KEY_4, KEY_3, KEY_NONE,
/*28*/ KEY_NONE, KEY_SPACE, KEY_V, KEY_F, KEY_T, KEY_R, KEY_5, KEY_NONE,
/*30*/ KEY_NONE, KEY_N, KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, KEY_NONE,
/*38*/ KEY_NONE, KEY_NONE, KEY_M, KEY_J, KEY_U, KEY_7, KEY_8, KEY_NONE,
/*40*/ KEY_NONE, KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, KEY_9, KEY_NONE,
/*48*/ KEY_NONE, KEY_PERIOD, KEY_SLASH, KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KEY_NONE,
/*50*/ KEY_NONE, KEY_NONE, KEY_QUOTE, KEY_NONE, KEY_L_BRACE, KEY_EQUAL, KEY_NONE, KEY_NONE,
/*58*/ KEY_CAPS_LOCK, KEY_R_SHIFT, KEY_ENTER, KEY_R_BRACE, KEY_NONE, KEY_BACKSLASH, KEY_NONE, KEY_NONE,
/*60*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_BACKSPACE, KEY_NONE,
/*68*/ KEY_NONE, KEY_NP_1, KEY_NONE, KEY_NP_4, KEY_NP_7, KEY_NONE, KEY_NONE, KEY_NONE,
/*70*/ KEY_NP_0, KEY_NP_PERIOD, KEY_NP_2, KEY_NP_5, KEY_NP_6, KEY_NP_8, KEY_ESCAPE, KEY_NUM_LOCK,
/*78*/ KEY_F11, KEY_NP_PLUS, KEY_NP_3, KEY_NP_MINUS, KEY_NP_ASTERISK, KEY_NP_9, KEY_SCROLL_LOCK, KEY_NONE,
/*80*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_F7,
};
static uint8_t scancodes_ext[] = {
// 00/08 01/09 02/0A 03/0B 04/0C 05/0D 06/0E 07/0F
/*00*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
/*08*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
/*10*/ KEY_UNKNOWN, KEY_R_ALT, KEY_PRINT_SCREEN, KEY_NONE, KEY_R_CTRL, KEY_UNKNOWN, KEY_NONE, KEY_NONE,
/*18*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_L_META,
/*20*/ KEY_UNKNOWN, KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_R_META,
/*28*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_MENU,
/*30*/ KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_UNKNOWN,
/*38*/ KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_UNKNOWN,
/*40*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
/*48*/ KEY_UNKNOWN, KEY_NONE, KEY_NP_SLASH, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE,
/*50*/ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
/*58*/ KEY_NONE, KEY_NONE, KEY_NP_ENTER, KEY_NONE, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE,
/*60*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
/*68*/ KEY_NONE, KEY_END, KEY_NONE, KEY_LEFT, KEY_HOME, KEY_NONE, KEY_NONE, KEY_NONE,
/*70*/ KEY_INSERT, KEY_DELETE, KEY_DOWN, KEY_NONE, KEY_RIGHT, KEY_UP, KEY_NONE, KEY_NONE,
/*78*/ KEY_NONE, KEY_NONE, KEY_PAGE_DOWN, KEY_NONE, KEY_NONE, KEY_PAGE_UP, KEY_NONE, KEY_NONE,
/*80*/ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
};
static struct Keycode last_keycode;
static bool is_init = false;
static bool state_keyup = false;
static bool state_ext = false;
void ps2kb_init(void) {
is_init = false;
pic_mask(1);
uint8_t result;
ps2ctrl_out_data(0xFF);
result = ps2ctrl_in();
if(result != 0xFA) {
panic("Failed to reset PS/2 keyboard: expected 0xFA, got 0x%X\n", result);
}
result = ps2ctrl_in();
if(result != 0xAA) {
panic("Failed to reset PS/2 keyboard: expected 0xAA, got 0x%X\n", result);
}
ps2ctrl_out_data(0xF4);
result = ps2ctrl_in();
if(result != 0xFA) {
panic("Failed to enable PS/2 keyboard: expected 0xFA, got 0x%X\n", result);
}
pic_unmask(1);
is_init = true;
}
void ps2kb_recv(void) {
if(!ps2ctrl_is_init() || !is_init) {
inb(0x60);
return;
}
uint8_t code = ps2ctrl_in();
if (code == 0x00 || code == 0x0F) {
last_keycode.key = KEY_NONE;
last_keycode.flags = KC_FLAG_ERROR;
} else if(code == 0xF0) {
state_keyup = true;
} else if(code == 0xE0) {
state_ext = true;
} else if(code <= KEYCODE_ARRAY_LEN) {
uint8_t *scancode_table = state_ext ? scancodes_ext : scancodes;
uint8_t keycode = scancode_table[code];
if(keycode != KEY_NONE) {
last_keycode.key = keycode;
last_keycode.flags = state_keyup ? KC_FLAG_KEY_UP : KC_FLAG_KEY_DOWN;
}
state_keyup = false;
state_ext = false;
}
}
struct Keycode ps2kb_get(void) {
struct Keycode code;
if(is_init) {
code = last_keycode;
} else {
code.key = KEY_NONE;
code.flags = KC_FLAG_ERROR;
}
last_keycode.key = KEY_NONE;
last_keycode.flags = 0;
return code;
}

11
kernel/drivers/ps2kb.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "keycodes.h"
void ps2kb_init(void);
void ps2kb_recv(void);
struct Keycode ps2kb_get(void);

39
kernel/drivers/serial.c Normal file
View File

@ -0,0 +1,39 @@
#include <stdbool.h>
#include <sys.h>
#include "serial.h"
#include "../panic.h"
#define PORT 0x3f8 // COM1
void serial_init(void) {
outb(PORT + 1, 0x00); // Disable all interrupts
outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
outb(PORT + 0, 0x01); // Set divisor to 1 (lo byte) 38400 baud
outb(PORT + 1, 0x00); // (hi byte)
outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit
outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip
outb(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte)
// Check if serial is faulty (i.e: not same byte as sent)
uint8_t response = inb(PORT + 0);
if(response != 0xAE) {
panic("Serial is faulty: %X\n", response);
}
// If serial is not faulty set it in normal operation mode
// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
outb(PORT + 4, 0x0F);
}
void serial_write(uint8_t a) {
while((inb(PORT + 5) & 0x20) != 0);
outb(PORT, a);
}
void serial_write_s(const char* str) {
while(*str != '\0') {
serial_write(*str++);
}
}

7
kernel/drivers/serial.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include <stdint.h>
void serial_init(void);
void serial_write(uint8_t a);
void serial_write_s(const char* str);

View File

@ -1,7 +1,7 @@
extern idt_exception_handler extern idt_exception_handler
extern idt_pic_timer extern idt_pic_timer
extern idt_pic_keyboard extern idt_pic_keyboard
extern idt_pic_handler extern idt_pic_generic
global isr_stub_table global isr_stub_table
%macro ISRErrorStub 1 %macro ISRErrorStub 1
@ -15,7 +15,7 @@ isr_stub_%+%1:
%macro PICGeneric 1 %macro PICGeneric 1
isr_stub_%+%1: isr_stub_%+%1:
push dword %1 push dword %1
call idt_pic_handler call idt_pic_generic
pop eax pop eax
iret iret
%endmacro %endmacro
@ -23,7 +23,7 @@ isr_stub_%+%1:
%macro PICTimer 1 %macro PICTimer 1
isr_stub_%+%1: isr_stub_%+%1:
push dword %1 push dword %1
call idt_pic_handler call idt_pic_generic
call idt_pic_timer call idt_pic_timer
pop eax pop eax
iret iret
@ -32,7 +32,7 @@ isr_stub_%+%1:
%macro PICKeyboard 1 %macro PICKeyboard 1
isr_stub_%+%1: isr_stub_%+%1:
push dword %1 push dword %1
call idt_pic_handler call idt_pic_generic
call idt_pic_keyboard call idt_pic_keyboard
pop eax pop eax
iret iret
@ -51,6 +51,7 @@ isr_stub_%+%1:
%endmacro %endmacro
section .text section .text
align 8
%assign i 0 %assign i 0
%rep 32 %rep 32
ISRErrorStub i ISRErrorStub i
@ -79,6 +80,7 @@ PICGeneric 47
%endrep %endrep
section .rodata section .rodata
align 8
isr_stub_table: isr_stub_table:
%assign i 0x00 %assign i 0x00
%rep 256 %rep 256

View File

@ -3,55 +3,71 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys.h> #include <sys.h>
#include "idt.h" #include "idt.h"
#include "../term.h"
#include "pic.h" #include "pic.h"
#include "../term.h"
#include "../panic.h"
#include "../drivers/ps2kb.h"
#include "../drivers/ps2ctrl.h"
static int timer = 0; static int timer = 0;
void idt_pic_handler(uint8_t exception) { void idt_pic_generic(uint8_t exception) {
pic_eoi(exception - PIC_REMAP_OFFSET); pic_eoi(exception - PIC_REMAP_OFFSET);
} }
void idt_pic_timer(void) { void idt_pic_timer(void) {
uint32_t state = term_save(); uint32_t state = term_save();
term_setcol(0x0a); term_setcol(0x0a);
char buf[20]; term_setpos(60, 0);
itoa(timer, buf); puts(" ");
term_setpos(0, 20); term_setpos(60, 0);
puts(" "); printf("%d", timer);
term_setpos(0, 20); term_flush();
puts(buf); timer += 1;
timer += 1; term_load(state);
term_load(state);
} }
void idt_pic_keyboard(void) { void idt_pic_keyboard(void) {
uint8_t c = inb(0x60); ps2kb_recv();
uint32_t state = term_save();
term_setcol(0x0c);
term_setpos(0, 21);
puts(" ");
term_setpos(0, 21);
char buf[20];
itoa(c, buf);
puts(buf);
term_load(state);
} }
void idt_exception_handler(uint8_t exception) { void idt_exception_handler(uint8_t exception) {
switch(exception) { char* msg;
case 0x00: switch(exception) {
puts("Div by zero"); case 0x00:
break; msg = "Division by zero";
case 0x08: break;
puts("Double fault"); case 0x02:
break; msg = "NMI";
default: break;
puts("Error"); case 0x04:
break; msg = "Overflow";
} break;
halt(); case 0x06:
msg = "invalid opcode";
break;
case 0x08:
msg = "double fault";
break;
case 0x0A:
msg = "invalid task state segment";
break;
case 0x0C:
msg = "stack segment fault";
break;
case 0x0D:
msg = "general protection fault";
break;
case 0x0E:
msg = "page fault";
break;
default:
msg = "unknown exception";
break;
}
panic("E%u: %s", exception, msg);
} }
__attribute__((aligned(0x10))) __attribute__((aligned(0x10)))
@ -72,7 +88,7 @@ void idt_init(void) {
idtr.base = (uintptr_t)&idt[0]; idtr.base = (uintptr_t)&idt[0];
idtr.limit = (uint16_t)sizeof(struct IdtEntry) * IDT_SIZE - 1; idtr.limit = (uint16_t)sizeof(struct IdtEntry) * IDT_SIZE - 1;
for(uint8_t i = 0; i < IDT_INTERRUPTS; i++) { for(int i = 0; i < IDT_INTERRUPTS; i++) {
set_descriptor(i, isr_stub_table[i], 0x8e); set_descriptor(i, isr_stub_table[i], 0x8e);
} }

View File

@ -2,7 +2,7 @@
#include <stdint.h> #include <stdint.h>
#define IDT_SIZE 256 #define IDT_SIZE 256
#define IDT_INTERRUPTS 48 #define IDT_INTERRUPTS 256
struct IdtEntry { struct IdtEntry {
uint16_t isr_low; uint16_t isr_low;
@ -18,18 +18,18 @@ struct Idtr {
} __attribute__((packed)); } __attribute__((packed));
typedef enum { typedef enum {
IDT_FLAG_GATE_TASK = 0x5, IDT_FLAG_GATE_TASK = 0x5,
IDT_FLAG_GATE_16BIT_INT = 0x6, IDT_FLAG_GATE_16BIT_INT = 0x6,
IDT_FLAG_GATE_16BIT_TRAP = 0x7, IDT_FLAG_GATE_16BIT_TRAP = 0x7,
IDT_FLAG_GATE_32BIT_INT = 0xE, IDT_FLAG_GATE_32BIT_INT = 0xE,
IDT_FLAG_GATE_32BIT_TRAP = 0xF, IDT_FLAG_GATE_32BIT_TRAP = 0xF,
IDT_FLAG_RING0 = (0 << 5), IDT_FLAG_RING0 = (0 << 5),
IDT_FLAG_RING1 = (1 << 5), IDT_FLAG_RING1 = (1 << 5),
IDT_FLAG_RING2 = (2 << 5), IDT_FLAG_RING2 = (2 << 5),
IDT_FLAG_RING3 = (3 << 5), IDT_FLAG_RING3 = (3 << 5),
IDT_FLAG_PRESENT = 0x80, IDT_FLAG_PRESENT = 0x80,
} IDTFlags; } IDTFlags;

View File

@ -9,74 +9,72 @@
void pic_remap(uint8_t offset) { void pic_remap(uint8_t offset) {
char a1 = inb(PIC1_DATA_PORT); char a1 = inb(PIC1_DATA_PORT);
char a2 = inb(PIC2_DATA_PORT); char a2 = inb(PIC2_DATA_PORT);
// control word 1 // control word 1
// 0x11: initialize, enable ICW4 // 0x11: initialize, enable ICW4
outb(PIC1_COMMAND_PORT, 0x11); outb(PIC1_COMMAND_PORT, 0x11);
io_wait(); io_wait();
outb(PIC2_COMMAND_PORT, 0x11); outb(PIC2_COMMAND_PORT, 0x11);
io_wait(); io_wait();
// control word 2 // control word 2
// interrupt offset // interrupt offset
outb(PIC1_DATA_PORT, offset); outb(PIC1_DATA_PORT, offset);
io_wait(); io_wait();
outb(PIC2_DATA_PORT, offset + 8); outb(PIC2_DATA_PORT, offset + 8);
io_wait(); io_wait();
// control word 3 // control word 3
// primary pic: set which pin secondary is connected to // primary pic: set which pin secondary is connected to
// (pin 2) // (pin 2)
outb(PIC1_DATA_PORT, 0b00000100); outb(PIC1_DATA_PORT, 0b00000100);
io_wait(); io_wait();
outb(PIC2_DATA_PORT, 2); outb(PIC2_DATA_PORT, 2);
io_wait(); io_wait();
// control word 3 // control word 3
// 0x01: enable 8086 mode // 0x01: enable 8086 mode
outb(PIC1_DATA_PORT, 0x01); outb(PIC1_DATA_PORT, 0x01);
io_wait(); io_wait();
outb(PIC2_DATA_PORT, 0x01); outb(PIC2_DATA_PORT, 0x01);
io_wait(); io_wait();
// clear data registers // clear data registers
outb(PIC1_DATA_PORT, a1); outb(PIC1_DATA_PORT, a1);
outb(PIC2_DATA_PORT, a2); outb(PIC2_DATA_PORT, a2);
} }
void pic_mask(int irq) { void pic_mask(int irq) {
uint8_t port; uint8_t port;
if(irq < 8) { if(irq < 8) {
port = PIC1_DATA_PORT; port = PIC1_DATA_PORT;
} else { } else {
irq -= 8; irq -= 8;
port = PIC2_DATA_PORT; port = PIC2_DATA_PORT;
} }
uint8_t mask = inb(port); uint8_t mask = inb(port);
outb(port, mask | (1 << irq)); outb(port, mask | (1 << irq));
} }
void pic_unmask(int irq) { void pic_unmask(int irq) {
uint8_t port; uint8_t port;
if(irq < 8) { if(irq < 8) {
port = PIC1_DATA_PORT; port = PIC1_DATA_PORT;
} else { } else {
irq -= 8; irq -= 8;
port = PIC2_DATA_PORT; port = PIC2_DATA_PORT;
} }
uint8_t mask = inb(port); uint8_t mask = inb(port);
outb(port, mask & ~(1 << irq)); outb(port, mask & ~(1 << irq));
} }
// completely disable the PIC void pic_disable(void) {
void pic_disable() { outb(PIC1_DATA_PORT, 0xff);
outb(PIC1_DATA_PORT, 0xff); io_wait();
io_wait(); outb(PIC2_DATA_PORT, 0xff);
outb(PIC2_DATA_PORT, 0xff); io_wait();
io_wait();
} }
// end of interrupt
void pic_eoi(int irq) { void pic_eoi(int irq) {
if(irq >= 8) { if(irq >= 8) {
outb(PIC2_COMMAND_PORT, 0x20); outb(PIC2_COMMAND_PORT, 0x20);
} }
outb(PIC1_COMMAND_PORT, 0x20); outb(PIC1_COMMAND_PORT, 0x20);
} }

View File

@ -6,5 +6,5 @@
void pic_remap(uint8_t offset); void pic_remap(uint8_t offset);
void pic_mask(int irq); void pic_mask(int irq);
void pic_unmask(int irq); void pic_unmask(int irq);
void pic_disable(); void pic_disable(void);
void pic_eoi(int irq); void pic_eoi(int irq);

View File

@ -1,22 +1,44 @@
#include <sys.h> #include <sys.h>
#include <stdlib.h>
#include "bootinfo.h"
#include "drivers/keycodes.h"
#include "drivers/ps2ctrl.h"
#include "drivers/ps2kb.h"
#include "drivers/serial.h"
#include "panic.h"
#include "term.h" #include "term.h"
#include "interrupt/pic.h" #include "interrupt/pic.h"
#include "interrupt/idt.h" #include "interrupt/idt.h"
extern void kmain(void) { extern void kmain(void* boot_info) {
term_clear(); term_clear();
term_setcol(0x0f); term_setcol(0x0f);
puts("loading kernel\n"); puts("loading kernel\n");
idt_init(); bootinfo_load(boot_info);
puts("initialized idt\n"); puts("loaded boot info\n");
pic_remap(PIC_REMAP_OFFSET); printf("cmdline: %s\n", bootinfo_get_cmdline());
puts("remapped pic\n"); idt_init();
int_enable(); puts("initialized idt\n");
puts("enabled interrupts\n"); pic_remap(PIC_REMAP_OFFSET);
outb(0x60, 0xF4); puts("remapped pic\n");
puts("enabled keyboard\n"); serial_init();
puts("initialized serial\n");
ps2ctrl_init();
puts("enabled ps/2 controller\n");
ps2kb_init();
puts("enabled keyboard\n");
while(1) { while(1) {
int_wait(); int_wait();
} struct Keycode code = ps2kb_get();
if(code.key != KEY_NONE) {
if(code.flags & KC_FLAG_ERROR) {
printf("error: %X\n", code.key);
} else if(code.flags & KC_FLAG_KEY_DOWN) {
printf("pressed: %X\n", code.key);
} else {
printf("released: %X\n", code.key);
}
}
}
} }

23
kernel/panic.c Normal file
View File

@ -0,0 +1,23 @@
#include <sys.h>
#include <stdarg.h>
#include <stdlib.h>
#include "term.h"
#include "panic.h"
__attribute__((noreturn))
void _panic_impl(char* msg, int line, char* file, ...) {
int_disable();
printf("BBBBBBBB\n");
va_list args;
va_start(args, file);
term_clear();
term_setpos(0, 0);
term_setcol(0x0c);
puts("!!!PANIC!!!\n");
term_setcol(0x0f);
vprintf(msg, args);
printf("\nin %s at line %d\n", file, line);
while(1) {
halt();
}
}

6
kernel/panic.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#define panic(msg, ...) _panic_impl(msg, __LINE__, __FILE__ __VA_OPT__(,) __VA_ARGS__)
__attribute__((noreturn))
void _panic_impl(char* msg, int line, char* file, ...);

View File

@ -4,32 +4,35 @@ bits 32
; base, limit, access, flags ; base, limit, access, flags
%macro gdt_entry 4 %macro gdt_entry 4
db %2 & 0xff db %2 & 0xff
db (%2 >> 8) & 0xff db (%2 >> 8) & 0xff
db %1 & 0xff db %1 & 0xff
db (%1 >> 8) & 0xff db (%1 >> 8) & 0xff
db (%1 >> 16) & 0xff db (%1 >> 16) & 0xff
db %3 db %3
db ((%2 >> 16) & 0x0f) | (%4 << 4) db ((%2 >> 16) & 0x0f) | (%4 << 4)
db (%1 >> 24) & 0xff db (%1 >> 24) & 0xff
%endmacro %endmacro
section .multiboot_header section .multiboot
align 8 align 8
mb_start: mb_start:
; header
dd 0xe85250d6 dd 0xe85250d6
dd 0 dd 0
dd mb_end - mb_start dd mb_end - mb_start
dd 0x100000000 - (0xe85250d6 + (mb_end - mb_start)) dd 0x100000000 - (0xe85250d6 + (mb_end - mb_start))
; null tag
dw 0 dw 0
dw 0 dw 0
dd 8 dd 8
;
mb_end: mb_end:
section .bss section .bss
align 16 align 16
stack_start: stack_start:
resb 16384 resb 16384
stack_end: stack_end:
section .rodata section .rodata
@ -40,27 +43,29 @@ gdt_entry 0, 0xFFFFF, 0x9A, 0xC
gdt_entry 0, 0xFFFFF, 0x92, 0xC gdt_entry 0, 0xFFFFF, 0x92, 0xC
gdt_end: gdt_end:
gdt_descriptor: gdt_descriptor:
dw gdt_end - gdt_start - 1 dw gdt_end - gdt_start - 1
dd gdt_start dd gdt_start
section .text section .text
align 8 align 8
start: start:
cli cli
lgdt [gdt_descriptor] lgdt [gdt_descriptor]
jmp 0x08:after_lgdt jmp 0x08:after_lgdt
after_lgdt: after_lgdt:
mov ax, 0x10 mov ax, 0x10
mov ds, ax mov ds, ax
mov ss, ax mov ss, ax
mov es, ax mov es, ax
mov fs, ax mov fs, ax
mov gs, ax mov gs, ax
mov esp, stack_end mov esp, stack_end
mov ebp, stack_end mov ebp, stack_end
call kmain sti
cli push ebx
call kmain
cli
halt: halt:
hlt hlt
jmp halt jmp halt

View File

@ -1,12 +1,18 @@
#include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <string_volatile.h>
#include <stdarg.h>
#include <sys.h>
#include "term.h" #include "term.h"
static uint16_t* screen = (uint16_t*)0xb8000; static volatile uint16_t *screen = (uint16_t*)0xb8000;
static size_t x = 0; static size_t term_x = 0;
static size_t y = 0; static size_t term_y = 0;
static uint8_t color = 0x0f; static uint8_t color = 0x0f;
static uint16_t screen_buf[TERM_W * TERM_H * 2];
static inline uint16_t screen_entry(char c, uint8_t col) { static inline uint16_t screen_entry(char c, uint8_t col) {
return (uint16_t)c | ((uint16_t)col << 8); return (uint16_t)c | ((uint16_t)col << 8);
@ -15,49 +21,186 @@ static inline uint16_t screen_entry(char c, uint8_t col) {
void putc(char c) { void putc(char c) {
switch(c) { switch(c) {
case '\n': case '\n':
x = TERM_W; term_x = TERM_W;
break; break;
case '\t': case '\t':
if(x % 8 == 0) x += 8; if(term_x % 8 == 0) term_x += 8;
x += 7 - (x % 8); term_x += 7 - (term_x % 8);
break; break;
default: default:
screen[x + y * TERM_W] = screen_entry(c, color); screen_buf[term_x + term_y * TERM_W] = screen_entry(c, color);
x += 1; term_x += 1;
break; break;
} }
if(x >= TERM_W) { if(term_x >= TERM_W) {
x = 0; term_x = 0;
y += 1; term_y += 1;
}
if(term_y >= TERM_H) {
term_scroll(1);
}
if(c == '\n') {
term_flush();
} }
} }
void puts(char* s) { void puts(const char *s) {
for(char* c = s; *c != '\0'; c++) { for(; *s != '\0'; s++) {
putc(*c); putc(*s);
} }
} }
static uint8_t hex2i(char hex) {
if(hex < 'A') {
return hex - '0';
} else if(hex < 'a') {
return hex - 'A' + 10;
} else {
return hex - 'a' + 10;
}
}
static char i2d(int i, bool upper) {
if(i < 10) {
return '0' + i;
} else {
return 'a' + (i - 10) + (upper ? 'A' - 'a' : 0);
}
}
static void itoa(int n, char *buf, int base, bool upper) {
if(n == 0) {
buf[0] = '0';
buf[1] = '\0';
return;
}
if(n < 0) {
n = -n;
buf[0] = '-';
buf++;
}
char *start = buf;
while(n != 0) {
*buf++ = i2d(n % base, upper);
n /= base;
}
*buf-- = '\0';
while(buf > start) {
char tmp = *start;
*start++ = *buf;
*buf-- = tmp;
}
}
static void utoa(unsigned int n, char *buf, int base, bool upper) {
if(n == 0) {
buf[0] = '0';
buf[1] = '\0';
return;
}
char *start = buf;
while(n != 0) {
*buf++ = i2d(n % base, upper);
n /= base;
}
*buf-- = '\0';
while(buf > start) {
char tmp = *start;
*start++ = *buf;
*buf-- = tmp;
}
}
void vprintf(const char *fstr, va_list args) {
char buf[80];
for(; *fstr != '\0'; fstr++) {
if(*fstr == '%') {
fstr++;
switch(*fstr) {
case '%':
putc('%');
break;
case 's':
puts(va_arg(args, char*));
break;
case 'd':
itoa(va_arg(args, int), buf, 10, false);
puts(buf);
break;
case 'u':
utoa(va_arg(args, unsigned int), buf, 10, false);
puts(buf);
break;
case 'x':
utoa(va_arg(args, unsigned int), buf, 16, false);
puts(buf);
break;
case 'X':
utoa(va_arg(args, unsigned int), buf, 16, true);
puts(buf);
break;
case '@': {
uint8_t hi = hex2i(*++fstr);
uint8_t lo = hex2i(*++fstr);
term_setcol((hi << 4) | lo);
break;
}
default:
break;
}
} else {
putc(*fstr);
}
}
}
void printf(const char *fstr, ...) {
va_list args;
va_start(args, fstr);
vprintf(fstr, args);
va_end(args);
}
void term_clear(void) { void term_clear(void) {
memset(screen, 0, TERM_W * TERM_H * 2); memset(screen_buf, 0, TERM_W * TERM_H * 2);
} }
void term_setpos(size_t new_x, size_t new_y) { void term_setpos(size_t new_x, size_t new_y) {
x = new_x; term_x = new_x;
y = new_y; term_y = new_y;
} }
void term_setcol(uint8_t new_col) { void term_setcol(uint8_t new_col) {
color = new_col; color = new_col;
} }
void term_scroll(ptrdiff_t lines) {
term_y -= lines;
if(lines == 0) return;
if(lines >= TERM_H || lines <= -TERM_H) {
term_clear();
} else if(lines > 0) {
memmove(screen_buf, screen_buf + lines * TERM_W, 2 * (TERM_H - lines) * TERM_W);
memset(screen_buf + (TERM_H - lines) * TERM_W, 0, 2 * lines * TERM_W);
} else {
memmove(screen_buf + lines * TERM_W, screen_buf + lines, (TERM_H + lines) * TERM_W);
}
}
void term_flush(void) {
int_disable();
memcpy_volatile(screen, screen_buf, TERM_W * TERM_H * 2);
int_enable();
}
uint32_t term_save(void) { uint32_t term_save(void) {
return color | ((x + y * TERM_W) << 8); return color | ((term_x + term_y * TERM_W) << 8);
} }
void term_load(uint32_t state) { void term_load(uint32_t state) {
color = state & 0xff; color = state & 0xff;
state >>= 8; state >>= 8;
x = state % TERM_W; term_x = state % TERM_W;
y = state / TERM_W; term_y = state / TERM_W;
} }

View File

@ -1,15 +1,20 @@
#pragma once #pragma once
#include <stddef.h> #include <stddef.h>
#include <stdarg.h>
#include <stdint.h> #include <stdint.h>
#define TERM_W 80 #define TERM_W 80
#define TERM_H 25 #define TERM_H 25
void putc(char c); void putc(char c);
void puts(char* s); void puts(const char* s);
void printf(const char* s, ...);
void vprintf(const char* s, va_list args);
void term_clear(void); void term_clear(void);
void term_setcol(uint8_t new_col); void term_setcol(uint8_t new_col);
void term_setpos(size_t new_x, size_t new_y); void term_setpos(size_t new_x, size_t new_y);
uint32_t term_save(void); uint32_t term_save(void);
void term_load(uint32_t pos); void term_load(uint32_t pos);
void term_scroll(ptrdiff_t lines);
void term_flush(void);

View File

@ -1,4 +1,3 @@
#pragma once #pragma once
int atoi(const char* s); int atoi(const char* s);
void itoa(int n, char* buf);

View File

@ -6,3 +6,6 @@ int memcmp(const void *lhs, const void *rhs, size_t n);
void *memcpy(void *restrict dst, const void *restrict src, size_t n); void *memcpy(void *restrict dst, const void *restrict src, size_t n);
void *memmove(void *dst, const void *src, size_t n); void *memmove(void *dst, const void *src, size_t n);
void *memset(void *dest, int c, size_t n); void *memset(void *dest, int c, size_t n);
char *strcpy(char *restrict dst, const char *restrict src);
char *strncpy(char *restrict dst, const char *restrict src, size_t n);

View File

@ -0,0 +1,5 @@
#include <stddef.h>
volatile void *memmove_volatile(volatile void *dst, const volatile void *src, size_t n);
volatile void *memset_volatile(volatile void *dest, int c, size_t n);
volatile void *memcpy_volatile(volatile void *restrict dst, const volatile void *restrict src, volatile size_t n);

View File

@ -17,30 +17,3 @@ int atoi(const char* s) {
} }
return neg ? -n : n; return neg ? -n : n;
} }
void itoa(int n, char* buf) {
if(n < 0) {
n = -n;
*buf = '-';
buf++;
} else if(n == 0) {
buf[0] = '0';
buf[1] = '\0';
return;
}
char* start = buf;
while(n > 0) {
*buf= n % 10 + '0';
n /= 10;
buf++;
}
*buf = '\0';
buf--;
while(start < buf) {
char tmp = *start;
*start = *buf;
*buf = tmp;
start++;
buf--;
}
}

View File

@ -41,7 +41,25 @@ void *memmove(void *dst, const void *src, size_t n) {
void *memset(void *dest, int c, size_t n) { void *memset(void *dest, int c, size_t n) {
unsigned char *d = dest; unsigned char *d = dest;
while(n--) { while(n--) {
*d = c; *d++ = c;
} }
return dest; return dest;
} }
char *strcpy(char *restrict dst, const char *restrict src) {
while((*dst = *src) != '\0') {
dst++;
src++;
}
return dst;
}
char *strncpy(char *restrict dst, const char *restrict src, size_t n) {
while((*dst = *src) != '\0' && n != 0) {
dst++;
src++;
n--;
}
memset(dst, 0, n);
return dst;
}

36
libk/string_volatile.c Normal file
View File

@ -0,0 +1,36 @@
#include <stddef.h>
#include "include/string_volatile.h"
volatile void *memmove_volatile(volatile void *dst, const volatile void *src, volatile size_t n) {
volatile char *d = dst;
volatile const char *s = src;
if(s < d) {
d += n;
s += n;
while(n--) {
*--d = *--s;
}
} else {
while(n--) {
*d++ = *s++;
}
}
return dst;
}
volatile void *memset_volatile(volatile void *dest, int c, volatile size_t n) {
volatile unsigned char *d = dest;
while(n--) {
*d++ = c;
}
return dest;
}
volatile void *memcpy_volatile(volatile void *restrict dst, const volatile void *restrict src, volatile size_t n) {
volatile char *d = dst;
volatile const char *s = src;
while(n--) {
*d++ = *s++;
}
return dst;
}

View File

@ -15,17 +15,17 @@ void io_wait(void) {
} }
void int_enable(void) { void int_enable(void) {
__asm__ volatile ("sti"); __asm__ volatile ("sti");
} }
void int_disable(void) { void int_disable(void) {
__asm__ volatile ("cli"); __asm__ volatile ("cli");
} }
void int_wait(void) { void int_wait(void) {
__asm__ volatile ("hlt"); __asm__ volatile ("sti; hlt");
} }
void halt(void) { void halt(void) {
__asm__ volatile ("cli; hlt"); __asm__ volatile ("cli; hlt");
} }

View File

@ -3,23 +3,23 @@ ENTRY(start)
SECTIONS { SECTIONS {
. = 1M; . = 1M;
.boot : .boot BLOCK(4K) : ALIGN(4K)
{ {
*(.multiboot_header) *(.multiboot)
} }
.rodata : .rodata BLOCK(4K) : ALIGN(4K)
{ {
*(.rodata) *(.rodata)
} }
.bss : .text BLOCK(4K) : ALIGN(4K)
{
*(.bss)
}
.text :
{ {
*(.text) *(.text)
} }
.bss BLOCK(4K) : ALIGN(4K)
{
*(.bss)
}
} }