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
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_OBJ=$(patsubst %.c,bin/%.o,$(C_SOURCE))
@ -31,11 +31,11 @@ bin/libk.a: $(LIBK_OBJ)
@mkdir -p $(@D)
$(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)
$(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 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
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_pic_timer
extern idt_pic_keyboard
extern idt_pic_handler
extern idt_pic_generic
global isr_stub_table
%macro ISRErrorStub 1
@ -15,7 +15,7 @@ isr_stub_%+%1:
%macro PICGeneric 1
isr_stub_%+%1:
push dword %1
call idt_pic_handler
call idt_pic_generic
pop eax
iret
%endmacro
@ -23,7 +23,7 @@ isr_stub_%+%1:
%macro PICTimer 1
isr_stub_%+%1:
push dword %1
call idt_pic_handler
call idt_pic_generic
call idt_pic_timer
pop eax
iret
@ -32,7 +32,7 @@ isr_stub_%+%1:
%macro PICKeyboard 1
isr_stub_%+%1:
push dword %1
call idt_pic_handler
call idt_pic_generic
call idt_pic_keyboard
pop eax
iret
@ -51,6 +51,7 @@ isr_stub_%+%1:
%endmacro
section .text
align 8
%assign i 0
%rep 32
ISRErrorStub i
@ -79,6 +80,7 @@ PICGeneric 47
%endrep
section .rodata
align 8
isr_stub_table:
%assign i 0x00
%rep 256

View File

@ -3,55 +3,71 @@
#include <stdbool.h>
#include <stdlib.h>
#include <sys.h>
#include "idt.h"
#include "../term.h"
#include "pic.h"
#include "../term.h"
#include "../panic.h"
#include "../drivers/ps2kb.h"
#include "../drivers/ps2ctrl.h"
static int timer = 0;
void idt_pic_handler(uint8_t exception) {
pic_eoi(exception - PIC_REMAP_OFFSET);
void idt_pic_generic(uint8_t exception) {
pic_eoi(exception - PIC_REMAP_OFFSET);
}
void idt_pic_timer(void) {
uint32_t state = term_save();
term_setcol(0x0a);
char buf[20];
itoa(timer, buf);
term_setpos(0, 20);
puts(" ");
term_setpos(0, 20);
puts(buf);
timer += 1;
term_load(state);
uint32_t state = term_save();
term_setcol(0x0a);
term_setpos(60, 0);
puts(" ");
term_setpos(60, 0);
printf("%d", timer);
term_flush();
timer += 1;
term_load(state);
}
void idt_pic_keyboard(void) {
uint8_t c = inb(0x60);
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);
ps2kb_recv();
}
void idt_exception_handler(uint8_t exception) {
switch(exception) {
case 0x00:
puts("Div by zero");
break;
case 0x08:
puts("Double fault");
break;
default:
puts("Error");
break;
}
halt();
char* msg;
switch(exception) {
case 0x00:
msg = "Division by zero";
break;
case 0x02:
msg = "NMI";
break;
case 0x04:
msg = "Overflow";
break;
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)))
@ -72,7 +88,7 @@ void idt_init(void) {
idtr.base = (uintptr_t)&idt[0];
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);
}

View File

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

View File

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

View File

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

View File

@ -1,22 +1,44 @@
#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 "interrupt/pic.h"
#include "interrupt/idt.h"
extern void kmain(void) {
term_clear();
term_setcol(0x0f);
puts("loading kernel\n");
idt_init();
puts("initialized idt\n");
pic_remap(PIC_REMAP_OFFSET);
puts("remapped pic\n");
int_enable();
puts("enabled interrupts\n");
outb(0x60, 0xF4);
puts("enabled keyboard\n");
extern void kmain(void* boot_info) {
term_clear();
term_setcol(0x0f);
puts("loading kernel\n");
bootinfo_load(boot_info);
puts("loaded boot info\n");
printf("cmdline: %s\n", bootinfo_get_cmdline());
idt_init();
puts("initialized idt\n");
pic_remap(PIC_REMAP_OFFSET);
puts("remapped pic\n");
serial_init();
puts("initialized serial\n");
ps2ctrl_init();
puts("enabled ps/2 controller\n");
ps2kb_init();
puts("enabled keyboard\n");
while(1) {
int_wait();
}
while(1) {
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
%macro gdt_entry 4
db %2 & 0xff
db (%2 >> 8) & 0xff
db %1 & 0xff
db (%1 >> 8) & 0xff
db (%1 >> 16) & 0xff
db %3
db ((%2 >> 16) & 0x0f) | (%4 << 4)
db (%1 >> 24) & 0xff
db %2 & 0xff
db (%2 >> 8) & 0xff
db %1 & 0xff
db (%1 >> 8) & 0xff
db (%1 >> 16) & 0xff
db %3
db ((%2 >> 16) & 0x0f) | (%4 << 4)
db (%1 >> 24) & 0xff
%endmacro
section .multiboot_header
section .multiboot
align 8
mb_start:
; header
dd 0xe85250d6
dd 0
dd mb_end - mb_start
dd 0x100000000 - (0xe85250d6 + (mb_end - mb_start))
; null tag
dw 0
dw 0
dd 8
;
mb_end:
section .bss
align 16
stack_start:
resb 16384
resb 16384
stack_end:
section .rodata
@ -40,27 +43,29 @@ gdt_entry 0, 0xFFFFF, 0x9A, 0xC
gdt_entry 0, 0xFFFFF, 0x92, 0xC
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1
dd gdt_start
dw gdt_end - gdt_start - 1
dd gdt_start
section .text
align 8
start:
cli
lgdt [gdt_descriptor]
jmp 0x08:after_lgdt
cli
lgdt [gdt_descriptor]
jmp 0x08:after_lgdt
after_lgdt:
mov ax, 0x10
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov esp, stack_end
mov ebp, stack_end
call kmain
cli
mov ax, 0x10
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov esp, stack_end
mov ebp, stack_end
sti
push ebx
call kmain
cli
halt:
hlt
jmp halt
hlt
jmp halt

View File

@ -1,12 +1,18 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <string_volatile.h>
#include <stdarg.h>
#include <sys.h>
#include "term.h"
static uint16_t* screen = (uint16_t*)0xb8000;
static size_t x = 0;
static size_t y = 0;
static volatile uint16_t *screen = (uint16_t*)0xb8000;
static size_t term_x = 0;
static size_t term_y = 0;
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) {
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) {
switch(c) {
case '\n':
x = TERM_W;
term_x = TERM_W;
break;
case '\t':
if(x % 8 == 0) x += 8;
x += 7 - (x % 8);
if(term_x % 8 == 0) term_x += 8;
term_x += 7 - (term_x % 8);
break;
default:
screen[x + y * TERM_W] = screen_entry(c, color);
x += 1;
screen_buf[term_x + term_y * TERM_W] = screen_entry(c, color);
term_x += 1;
break;
}
if(x >= TERM_W) {
x = 0;
y += 1;
if(term_x >= TERM_W) {
term_x = 0;
term_y += 1;
}
if(term_y >= TERM_H) {
term_scroll(1);
}
if(c == '\n') {
term_flush();
}
}
void puts(char* s) {
for(char* c = s; *c != '\0'; c++) {
putc(*c);
void puts(const char *s) {
for(; *s != '\0'; s++) {
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) {
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) {
x = new_x;
y = new_y;
term_x = new_x;
term_y = new_y;
}
void term_setcol(uint8_t 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) {
return color | ((x + y * TERM_W) << 8);
return color | ((term_x + term_y * TERM_W) << 8);
}
void term_load(uint32_t state) {
color = state & 0xff;
state >>= 8;
x = state % TERM_W;
y = state / TERM_W;
term_x = state % TERM_W;
term_y = state / TERM_W;
}

View File

@ -1,15 +1,20 @@
#pragma once
#include <stddef.h>
#include <stdarg.h>
#include <stdint.h>
#define TERM_W 80
#define TERM_H 25
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_setcol(uint8_t new_col);
void term_setpos(size_t new_x, size_t new_y);
uint32_t term_save(void);
void term_load(uint32_t pos);
void term_scroll(ptrdiff_t lines);
void term_flush(void);

View File

@ -1,4 +1,3 @@
#pragma once
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 *memmove(void *dst, const void *src, 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;
}
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) {
unsigned char *d = dest;
while(n--) {
*d = c;
*d++ = c;
}
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) {
__asm__ volatile ("sti");
__asm__ volatile ("sti");
}
void int_disable(void) {
__asm__ volatile ("cli");
__asm__ volatile ("cli");
}
void int_wait(void) {
__asm__ volatile ("hlt");
__asm__ volatile ("sti; hlt");
}
void halt(void) {
__asm__ volatile ("cli; hlt");
__asm__ volatile ("cli; hlt");
}

View File

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