commit b739f2adc871f4971ada19177af3246efebef046 Author: assada Date: Tue May 21 18:41:16 2024 +0300 dead@root diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a1fad8b --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.o +*.bin +*.elf +*.img +isodir/ +.vscode/ +.idea/ +*.iso \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f3a9fb5 --- /dev/null +++ b/Makefile @@ -0,0 +1,45 @@ +CFLAGS = -ffreestanding -nostdlib -fno-builtin -fno-stack-protector -Wall -Wextra +LDFLAGS = -ffreestanding -nostdlib -lgcc +ASFLAGS = +CC = i686-elf-gcc +AS = i686-elf-as +LD = i686-elf-gcc +GRUB_FILE = grub-file +GRUB_MKRESCUE = grub-mkrescue +KERNEL = deados.bin +ISO = deados.iso + +SOURCES_C = kernel.c tty.c idt.c timer.c io.c vga.c gdt.c sys.c irq.c isr.c keyboard.c shell.c string.c user_space.c syscall.c +SOURCES_ASM = boot.s idt_load.s gdt_flush.s pit_handler.s irq_e.s isr_e.s +OBJECTS = $(SOURCES_ASM:.s=.o) $(SOURCES_C:.c=.o) + +ISO_DIR = isodir +GRUB_DIR = $(ISO_DIR)/boot/grub + +.PHONY: all clean iso + +all: $(ISO) + +$(KERNEL): $(OBJECTS) linker.ld + $(LD) -T linker.ld -o $(KERNEL) $(OBJECTS) $(LDFLAGS) + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +%.o: %.s + $(AS) $(ASFLAGS) $< -o $@ + +iso: $(ISO) + +$(ISO): $(KERNEL) grub.cfg + mkdir -p $(GRUB_DIR) + cp $(KERNEL) $(ISO_DIR)/boot/$(KERNEL) + cp grub.cfg $(GRUB_DIR)/grub.cfg + $(GRUB_MKRESCUE) -o $(ISO) $(ISO_DIR) + +check-multiboot: $(KERNEL) + $(GRUB_FILE) --is-x86-multiboot $(KERNEL) && echo "multiboot confirmed" || echo "the file is not multiboot" + +clean: + rm -f $(OBJECTS) $(KERNEL) $(ISO) + rm -rf $(ISO_DIR) diff --git a/boot.s b/boot.s new file mode 100644 index 0000000..10899ee --- /dev/null +++ b/boot.s @@ -0,0 +1,35 @@ +.set ALIGN, 1<<0 +.set MEMINFO, 1<<1 +.set FLAGS, ALIGN | MEMINFO +.set MAGIC, 0x1BADB002 /* multiboot 1 */ +.set CHECKSUM, -(MAGIC + FLAGS) + +.section .multiboot +.align 4 +.long MAGIC +.long FLAGS +.long CHECKSUM + +.section .bss +.align 16 + +stack_bottom: + .skip 1024 * 32 # 32 KB + +stack_top: + .section .text + .global _start + .type _start, @function +_start: + cli + mov $stack_top, %esp + + call kernel_main + + hlt + jmp 1 +1: + jmp 1 + + +.size _start, . - _start diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..b91c05c --- /dev/null +++ b/build.sh @@ -0,0 +1,18 @@ +set -ex + +i686-elf-as boot.s -o boot.o +i686-elf-as idt_load.s -o idt_load.o +i686-elf-gcc -c kernel.c -o kernel.o -std=gnu99 -ffreestanding -O2 -Wall -Wextra +i686-elf-gcc -T linker.ld -o myos.bin -ffreestanding -O2 -nostdlib boot.o kernel.o idt_load.o -lgcc + +if grub-file --is-x86-multiboot myos.bin; then + echo multiboot confirmed +else + echo the file is not multiboot +fi + + +mkdir -p isodir/boot/grub +cp myos.bin isodir/boot/myos.bin +cp grub.cfg isodir/boot/grub/grub.cfg +grub-mkrescue -o myos.iso isodir diff --git a/gdt.c b/gdt.c new file mode 100644 index 0000000..1d4ca72 --- /dev/null +++ b/gdt.c @@ -0,0 +1,29 @@ +#include "gdt.h" + +struct gdt_entry gdt[3]; +struct gdt_ptr gdtp; + +extern void gdt_flush(uint32_t); + +void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) { + gdt[num].base_low = (base & 0xFFFF); + gdt[num].base_middle = (base >> 16) & 0xFF; + gdt[num].base_high = (base >> 24) & 0xFF; + + gdt[num].limit_low = (limit & 0xFFFF); + gdt[num].granularity = (limit >> 16) & 0x0F; + + gdt[num].granularity |= gran & 0xF0; + gdt[num].access = access; +} + +void gdt_install() { + gdtp.limit = (sizeof(struct gdt_entry) * 3) - 1; + gdtp.base = (uint32_t)&gdt; + + gdt_set_gate(0, 0, 0, 0, 0); // Null segment + gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment + gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment + + gdt_flush((uint32_t)&gdtp); +} diff --git a/gdt.h b/gdt.h new file mode 100644 index 0000000..25c63ca --- /dev/null +++ b/gdt.h @@ -0,0 +1,26 @@ +#ifndef GDT_H +#define GDT_H + +#include + +struct gdt_entry { + uint16_t limit_low; + uint16_t base_low; + uint8_t base_middle; + uint8_t access; + uint8_t granularity; + uint8_t base_high; +} __attribute__((packed)); + +struct gdt_ptr { + uint16_t limit; + uint32_t base; +} __attribute__((packed)); + +extern struct gdt_entry gdt[3]; +extern struct gdt_ptr gdtp; + +void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran); +void gdt_install(); + +#endif \ No newline at end of file diff --git a/gdt_flush.s b/gdt_flush.s new file mode 100644 index 0000000..0527400 --- /dev/null +++ b/gdt_flush.s @@ -0,0 +1,19 @@ +.global gdt_flush + +gdt_flush: + cli + + mov 4(%esp), %eax + lgdt (%eax) + + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + + jmp $0x08, $.flush + +.flush: + ret diff --git a/grub.cfg b/grub.cfg new file mode 100644 index 0000000..2038825 --- /dev/null +++ b/grub.cfg @@ -0,0 +1,3 @@ +menuentry "deadOS" { + multiboot /boot/deados.bin +} \ No newline at end of file diff --git a/idt.c b/idt.c new file mode 100644 index 0000000..fbb6bcd --- /dev/null +++ b/idt.c @@ -0,0 +1,55 @@ +#include "idt.h" +#include "io.h" +#include + +#define IDT_ENTRIES 256 + +struct idt_entry { + uint16_t base_lo; + uint16_t sel; + uint8_t always0; + uint8_t flags; + uint16_t base_hi; +} __attribute__((packed)); + +struct idt_ptr { + uint16_t limit; + uint32_t base; +} __attribute__((packed)); + +struct idt_entry idt[IDT_ENTRIES]; +struct idt_ptr idtp; + +void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) { + idt[num].base_lo = base & 0xFFFF; + idt[num].base_hi = (base >> 16) & 0xFFFF; + idt[num].sel = sel; + idt[num].always0 = 0; + idt[num].flags = flags | 0x60; +} + +void idt_install() { + idtp.limit = (sizeof(struct idt_entry) * IDT_ENTRIES) - 1; + idtp.base = (uint32_t)&idt; + idt_load(); +} + +void pic_remap(int offset1, int offset2) { + unsigned char a1, a2; + + a1 = inb(0x21); + a2 = inb(0xA1); + + outb(0x20, 0x11); + outb(0xA0, 0x11); + outb(0x21, offset1); + outb(0xA1, offset2); + outb(0x21, 0x04); + outb(0xA1, 0x02); + + outb(0x21, 0x01); + outb(0xA1, 0x01); + + outb(0x21, a1); + outb(0xA1, a2); +} \ No newline at end of file diff --git a/idt.h b/idt.h new file mode 100644 index 0000000..8612aef --- /dev/null +++ b/idt.h @@ -0,0 +1,11 @@ +#ifndef IDT_H +#define IDT_H + +#include + +extern void idt_load(); + +void idt_install(); +void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags); + +#endif \ No newline at end of file diff --git a/idt_load.s b/idt_load.s new file mode 100644 index 0000000..9023c29 --- /dev/null +++ b/idt_load.s @@ -0,0 +1,5 @@ +.section .text +.global idt_load +idt_load: + lidt [idtp] + ret diff --git a/interrupts.h b/interrupts.h new file mode 100644 index 0000000..ab68303 --- /dev/null +++ b/interrupts.h @@ -0,0 +1,48 @@ +#ifndef INTERUPTS_H +#define INTERUPTS_H + +#include + +typedef struct stack_t Stack; +struct stack_t +{ + /* Pushed the segs last */ + uint32_t gs, fs, es, ds; + /* Pushed by 'pusha' */ + uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; + /* Our 'push #' and ecodes do this */ + uint32_t id, err_code; + /* Pushed by the processor automatically */ + uint32_t eip, cs, eflags, useresp, ss; +}; + +#define NB_ISR_ROUTINES 256 + +void isr_install_handler(uint8_t isr, void (*handler)(Stack *registers)); +void isr_uninstall_handler(uint8_t isr); +void isr_call_handler(Stack *registers); +void isr_install(void); + +#define NB_IRQ_ROUTINES 16 + +#define PIC1 0x20 /* master PIC */ +#define PIC2 0xA0 /* slave PIC */ +#define PIC1_CMD PIC1 +#define PIC1_DATA (PIC1 + 1) +#define PIC2_CMD PIC2 +#define PIC2_DATA (PIC2 + 1) +#define PIC1_OFFSET 0x20 +#define PIC2_OFFSET 0x28 + +#define PIC_EOI 0x20 + +#define ICW1_ICW4 0x01 +#define ICW1_INIT 0x10 +#define ICW4_8086 0x01 + +void irq_install_handler(uint8_t irq, void (*handler)(Stack *registers)); +void irq_uninstall_handler(uint8_t irq); +void irq_call_handler(Stack *registers); +void irq_install(void); + +#endif diff --git a/io.c b/io.c new file mode 100644 index 0000000..047ed28 --- /dev/null +++ b/io.c @@ -0,0 +1,18 @@ +#include "io.h" + +void outb(uint16_t port, uint8_t val) { + asm volatile ("outb %0, %1" : : "a"(val), "Nd"(port)); +} + +uint8_t inb(uint16_t port) { + uint8_t ret; + asm volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port)); + return ret; +} + +void io_wait(void) +{ + asm volatile ( "jmp 1f\n\t" + "1:jmp 2f\n\t" + "2:" ); +} diff --git a/io.h b/io.h new file mode 100644 index 0000000..1babee8 --- /dev/null +++ b/io.h @@ -0,0 +1,10 @@ +#ifndef IO_H +#define IO_H + +#include + +void outb(uint16_t port, uint8_t val); +uint8_t inb(uint16_t port); +void io_wait(void); + +#endif \ No newline at end of file diff --git a/irq.c b/irq.c new file mode 100644 index 0000000..11642da --- /dev/null +++ b/irq.c @@ -0,0 +1,99 @@ +#include + +#include "interrupts.h" +#include "io.h" +#include "sys.h" +#include "idt.h" + +extern void irq0(void); +extern void irq1(void); +extern void irq2(void); +extern void irq3(void); +extern void irq4(void); +extern void irq5(void); +extern void irq6(void); +extern void irq7(void); +extern void irq8(void); +extern void irq9(void); +extern void irq10(void); +extern void irq11(void); +extern void irq12(void); +extern void irq13(void); +extern void irq14(void); +extern void irq15(void); + +void *irq_routines[NB_IRQ_ROUTINES] = {0}; + +void irq_install_handler(uint8_t irq, void (*handler)(Stack *registers)) +{ + irq_routines[irq] = handler; +} + +void irq_uninstall_handler(uint8_t irq) +{ + irq_routines[irq] = 0; +} + +void irq_call_handler(Stack *registers) +{ + void (*handler)(Stack *registers); + handler = irq_routines[registers->id - 32]; + if (handler) + handler(registers); +} + +static void irq_remap(void) +{ + outb(PIC1_CMD, ICW1_INIT | ICW1_ICW4); + io_wait(); + outb(PIC2_CMD, ICW1_INIT | ICW1_ICW4); + io_wait(); + outb(PIC1_DATA, PIC1_OFFSET); + io_wait(); + outb(PIC2_DATA, PIC2_OFFSET); + io_wait(); + outb(PIC1_DATA, 0x04); + io_wait(); + outb(PIC2_DATA, 0x02); + io_wait(); + outb(PIC1_DATA, ICW4_8086); + io_wait(); + outb(PIC2_DATA, ICW4_8086); + io_wait(); +} + +void irq_install(void) +{ + irq_remap(); + + idt_set_gate(32, (uint32_t)irq0, 0x08, 0x8E); + idt_set_gate(33, (uint32_t)irq1, 0x08, 0x8E); + idt_set_gate(34, (uint32_t)irq2, 0x08, 0x8E); + idt_set_gate(35, (uint32_t)irq3, 0x08, 0x8E); + idt_set_gate(36, (uint32_t)irq4, 0x08, 0x8E); + idt_set_gate(37, (uint32_t)irq5, 0x08, 0x8E); + idt_set_gate(38, (uint32_t)irq6, 0x08, 0x8E); + idt_set_gate(39, (uint32_t)irq7, 0x08, 0x8E); + idt_set_gate(40, (uint32_t)irq8, 0x08, 0x8E); + idt_set_gate(41, (uint32_t)irq9, 0x08, 0x8E); + idt_set_gate(42, (uint32_t)irq10, 0x08, 0x8E); + idt_set_gate(43, (uint32_t)irq11, 0x08, 0x8E); + idt_set_gate(44, (uint32_t)irq12, 0x08, 0x8E); + idt_set_gate(45, (uint32_t)irq13, 0x08, 0x8E); + idt_set_gate(46, (uint32_t)irq14, 0x08, 0x8E); + idt_set_gate(47, (uint32_t)irq15, 0x08, 0x8E); + + sys_enable_interrupts(); +} + +void irq_handler(Stack *registers) +{ + irq_call_handler(registers); + + if (registers->id >= 40) + { + outb(PIC2_CMD, PIC_EOI); + } + + outb(PIC1_CMD, PIC_EOI); +} \ No newline at end of file diff --git a/irq_e.s b/irq_e.s new file mode 100644 index 0000000..4b71781 --- /dev/null +++ b/irq_e.s @@ -0,0 +1,59 @@ +.section .text +.align 4 + +.macro IRQ index entry + .global irq\index + .type irq\index, @function + irq\index: + cli + push $0x00 + push $\entry + jmp irq_common_stub +.endm + +IRQ 0, 32 +IRQ 1, 33 +IRQ 2, 34 +IRQ 3, 35 +IRQ 4, 36 +IRQ 5, 37 +IRQ 6, 38 +IRQ 7, 39 +IRQ 8, 40 +IRQ 9, 41 +IRQ 10, 42 +IRQ 11, 43 +IRQ 12, 44 +IRQ 13, 45 +IRQ 14, 46 +IRQ 15, 47 + +irq_common_stub: + pusha + + push %ds + push %es + push %fs + push %gs + + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + + mov %esp, %eax + push %eax + mov $irq_handler, %eax + + call *%eax + pop %eax + + pop %gs + pop %fs + pop %es + pop %ds + popa + + add $8, %esp + iret diff --git a/isr.c b/isr.c new file mode 100644 index 0000000..4a91979 --- /dev/null +++ b/isr.c @@ -0,0 +1,161 @@ +#include "interrupts.h" +#include "io.h" +#include "sys.h" +#include "idt.h" +#include "tty.h" + +extern void isr0(void); +extern void isr1(void); +extern void isr2(void); +extern void isr3(void); +extern void isr4(void); +extern void isr5(void); +extern void isr6(void); +extern void isr7(void); +extern void isr8(void); +extern void isr9(void); +extern void isr10(void); +extern void isr11(void); +extern void isr12(void); +extern void isr13(void); +extern void isr14(void); +extern void isr15(void); +extern void isr16(void); +extern void isr17(void); +extern void isr18(void); +extern void isr19(void); +extern void isr20(void); +extern void isr21(void); +extern void isr22(void); +extern void isr23(void); +extern void isr24(void); +extern void isr25(void); +extern void isr26(void); +extern void isr27(void); +extern void isr28(void); +extern void isr29(void); +extern void isr30(void); +extern void isr31(void); +extern void isr128(void); + +void *isr_routines[NB_ISR_ROUTINES] = {0}; + +void isr_install_handler(uint8_t isr, void (*handler)(Stack *registers)) +{ + isr_routines[isr] = handler; +} + +void isr_uninstall_handler(uint8_t isr) +{ + isr_routines[isr] = 0; +} + +void isr_call_handler(Stack *registers) +{ + void (*handler)(Stack *registers); + handler = isr_routines[registers->id]; + if (handler) + handler(registers); +} + +void isr_install(void) +{ + idt_set_gate(0, (uint32_t)isr0, 0x08, 0x8E); + idt_set_gate(1, (uint32_t)isr1, 0x08, 0x8E); + idt_set_gate(2, (uint32_t)isr2, 0x08, 0x8E); + idt_set_gate(3, (uint32_t)isr3, 0x08, 0x8E); + idt_set_gate(4, (uint32_t)isr4, 0x08, 0x8E); + idt_set_gate(5, (uint32_t)isr5, 0x08, 0x8E); + idt_set_gate(6, (uint32_t)isr6, 0x08, 0x8E); + idt_set_gate(7, (uint32_t)isr7, 0x08, 0x8E); + + idt_set_gate(8, (uint32_t)isr8, 0x08, 0x8E); + idt_set_gate(9, (uint32_t)isr9, 0x08, 0x8E); + idt_set_gate(10, (uint32_t)isr10, 0x08, 0x8E); + idt_set_gate(11, (uint32_t)isr11, 0x08, 0x8E); + idt_set_gate(12, (uint32_t)isr12, 0x08, 0x8E); + idt_set_gate(13, (uint32_t)isr13, 0x08, 0x8E); + idt_set_gate(14, (uint32_t)isr14, 0x08, 0x8E); + idt_set_gate(15, (uint32_t)isr15, 0x08, 0x8E); + + idt_set_gate(16, (uint32_t)isr16, 0x08, 0x8E); + idt_set_gate(17, (uint32_t)isr17, 0x08, 0x8E); + idt_set_gate(18, (uint32_t)isr18, 0x08, 0x8E); + idt_set_gate(19, (uint32_t)isr19, 0x08, 0x8E); + idt_set_gate(20, (uint32_t)isr20, 0x08, 0x8E); + idt_set_gate(21, (uint32_t)isr21, 0x08, 0x8E); + idt_set_gate(22, (uint32_t)isr22, 0x08, 0x8E); + idt_set_gate(23, (uint32_t)isr23, 0x08, 0x8E); + + idt_set_gate(24, (uint32_t)isr24, 0x08, 0x8E); + idt_set_gate(25, (uint32_t)isr25, 0x08, 0x8E); + idt_set_gate(26, (uint32_t)isr26, 0x08, 0x8E); + idt_set_gate(27, (uint32_t)isr27, 0x08, 0x8E); + idt_set_gate(28, (uint32_t)isr28, 0x08, 0x8E); + idt_set_gate(29, (uint32_t)isr29, 0x08, 0x8E); + idt_set_gate(30, (uint32_t)isr30, 0x08, 0x8E); + idt_set_gate(31, (uint32_t)isr31, 0x08, 0x8E); + + idt_set_gate(128, (uint32_t)isr128, 0x08, 0x8E); +} + +static const 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 fault_handler(Stack *registers) +{ + if (registers->id == 128) + isr_call_handler(registers); + + if (registers->id < 32) + { + terminal_printc("Exception. System Halted!\n"); + + const char *message = exception_messages[registers->id]; + while (*message) + { + terminal_putchar(*message); + message++; + } + + isr_call_handler(registers); + + for (;;) + sys_halt(); + } +} \ No newline at end of file diff --git a/isr_e.s b/isr_e.s new file mode 100644 index 0000000..e638953 --- /dev/null +++ b/isr_e.s @@ -0,0 +1,85 @@ +.section .text +.align 4 + +.macro ISR_NO_ERR index + .global isr\index + isr\index: + cli + push $0 + push $\index + jmp isr_common_stub +.endm + +.macro ISR_ERR index + .global isr\index + isr\index: + cli + push $\index + jmp isr_common_stub +.endm + + +ISR_NO_ERR 0 # Division By Zero Exception +ISR_NO_ERR 1 # Debug Exception +ISR_NO_ERR 2 # Non Maskable Interrupt Exception +ISR_NO_ERR 3 # Breakpoint Exception +ISR_NO_ERR 4 # Into Detected Overflow Exception +ISR_NO_ERR 5 # Out of Bounds Exception +ISR_NO_ERR 6 # Invalid Opcode Exception +ISR_NO_ERR 7 # No Coprocessor Exception +ISR_ERR 8 # Double Fault Exception +ISR_NO_ERR 9 # Coprocessor Segment Overrun Exception +ISR_ERR 10 # Bad TSS Exception +ISR_ERR 11 # Segment Not Present Exception +ISR_ERR 12 # Stack Fault Exception +ISR_ERR 13 # General Protection Fault Exception +ISR_ERR 14 # Page Fault Exception +ISR_NO_ERR 15 # Unknown Interrupt Exception +ISR_NO_ERR 16 # Coprocessor Fault Exception +ISR_NO_ERR 17 # Alignment Check Exception +ISR_NO_ERR 18 # Machine Check Exception + +ISR_NO_ERR 19 # Other +ISR_NO_ERR 20 +ISR_NO_ERR 21 +ISR_NO_ERR 22 +ISR_NO_ERR 23 +ISR_NO_ERR 24 +ISR_NO_ERR 25 +ISR_NO_ERR 26 +ISR_NO_ERR 27 +ISR_NO_ERR 28 +ISR_NO_ERR 29 +ISR_NO_ERR 30 +ISR_NO_ERR 31 +ISR_NO_ERR 128 # Syscal + + +isr_common_stub: + pusha + push %ds + push %es + push %fs + push %gs + + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + + mov %esp, %eax + push %eax + mov $fault_handler, %eax + + call *%eax + pop %eax + + pop %gs + pop %fs + pop %es + pop %ds + popa + + add $8, %esp + iret diff --git a/kernel.c b/kernel.c new file mode 100644 index 0000000..db4538a --- /dev/null +++ b/kernel.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include "tty.h" +#include "gdt.h" +#include "idt.h" +#include "timer.h" +#include "sys.h" +#include "interrupts.h" +#include "keyboard.h" +#include "shell.h" +#include "user_space.h" +#include "syscall.h" + +void kernel_main(void) +{ + terminal_initialize(); + gdt_install(); + + idt_install(); + + isr_install(); + irq_install(); + + timer_install(); + + keyboard_install(); + + sys_enable_interrupts(); + + terminal_printc("Hello, &ekernel &7World!\n&5Magenta String Example\nThis is a &4red string&7.\n"); + for (int i = 0; i < 3; i++) + { + terminal_printc("&cDead &7"); + terminal_putchar('0' + (i / 10)); + terminal_putchar('0' + (i % 10)); + terminal_printc("\n"); + delay(500); + } + // syscall_init(); + + // enter_user_space(); + + shell_init(); +} \ No newline at end of file diff --git a/keyboard.c b/keyboard.c new file mode 100644 index 0000000..69d253f --- /dev/null +++ b/keyboard.c @@ -0,0 +1,202 @@ +#include +#include + +#include "interrupts.h" +#include "io.h" +#include "keyboard.h" + +unsigned char us_layout[] = { + /* SHIFT CTRL ALT */ + 0x1B, 0x1B, 0x1B, 0x1B, /* esc (0x01) */ + '1', '!', '1', '1', + '2', '@', '2', '2', + '3', '#', '3', '3', + '4', '$', '4', '4', + '5', '%', '5', '5', + '6', '^', '6', '6', + '7', '&', '7', '7', + '8', '*', '8', '8', + '9', '(', '9', '9', + '0', ')', '0', '0', + '-', '_', '-', '-', + '=', '+', '=', '=', + 0x08, 0x08, 0x7F, 0x08, /* backspace */ + 0x09, 0x09, 0x09, 0x09, /* tab */ + 'q', 'Q', 'q', 'q', + 'w', 'W', 'w', 'w', + 'e', 'E', 'e', 'e', + 'r', 'R', 'r', 'r', + 't', 'T', 't', 't', + 'y', 'Y', 'y', 'y', + 'u', 'U', 'u', 'u', + 'i', 'I', 'i', 'i', + 'o', 'O', 'o', 'o', + 'p', 'P', 'p', 'p', + '[', '{', '[', '[', + ']', '}', ']', ']', + 0x0A, 0x0A, 0x0A, 0x0A, /* enter */ + 0xFF, 0xFF, 0xFF, 0xFF, /* ctrl */ + 'a', 'A', 'a', 'a', + 's', 'S', 's', 's', + 'd', 'D', 'd', 'd', + 'f', 'F', 'f', 'f', + 'g', 'G', 'g', 'g', + 'h', 'H', 'h', 'h', + 'j', 'J', 'j', 'j', + 'k', 'K', 'k', 'k', + 'l', 'L', 'l', 'l', + ';', ':', ';', ';', + 0x27, 0x22, 0x27, 0x27, /* '" */ + '`', '~', '`', '`', /* `~ */ + 0xFF, 0xFF, 0xFF, 0xFF, /* Lshift (0x2a) */ + '\\', '|', '\\', '\\', + 'z', 'Z', 'z', 'z', + 'x', 'X', 'x', 'x', + 'c', 'C', 'c', 'c', + 'v', 'V', 'v', 'v', + 'b', 'B', 'b', 'b', + 'n', 'N', 'n', 'n', + 'm', 'M', 'm', 'm', + 0x2C, 0x3C, 0x2C, 0x2C, /* ,< */ + 0x2E, 0x3E, 0x2E, 0x2E, /* .> */ + 0x2F, 0x3F, 0x2F, 0x2F, /* /? */ + 0xFF, 0xFF, 0xFF, 0xFF, /* Rshift (0x36) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x37) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x38) */ + ' ', ' ', ' ', ' ', /* space */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x3a) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x3b) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x3c) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x3d) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x3e) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x3f) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x40) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x41) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x42) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x43) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x44) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x45) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x46) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x47) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x48) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x49) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x4a) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x4b) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x4c) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x4d) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x4e) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x4f) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x50) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x51) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x52) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x53) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x54) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x55) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x56) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x57) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x58) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x59) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x5a) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x5b) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x5c) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x5d) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x5e) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x5f) */ + 0xFF, 0xFF, 0xFF, 0xFF, /* (0x60) */ + 0xFF, 0xFF, 0xFF, 0xFF /* (0x61) */ +}; + +volatile unsigned char buffer[KEYBOARD_BUFFER_SIZE]; +volatile size_t buffer_index; +volatile size_t read_index; + +void keyboard_clear_buffer(void) +{ + buffer_index = 0; + read_index = 0; +} + +int keyboard_getchar(void) +{ + while (read_index == buffer_index) + ; + + int c = (int)buffer[read_index]; + ++read_index; + return c; +} + +unsigned char keyboard_getscancode(void) +{ + uint8_t scancode; + uint16_t index; + static uint8_t offset = 0; + + scancode = inb(KEYBOARD_DATA); + --scancode; + + if (scancode < 0x80) + { + switch (scancode) + { + case LSHIFT: + offset = 1; + break; + case RSHIFT: + offset = 1; + break; + case CTRL: + offset = 2; + break; + case ALT: + offset = 3; + break; + /* Character */ + default: + index = scancode * 4 + offset; + return us_layout[index]; + } + } + else + { + scancode -= 0x80; + switch (scancode) + { + case LSHIFT: + offset = 0; + break; + case RSHIFT: + offset = 0; + break; + case CTRL: + offset = 0; + break; + case ALT: + offset = 0; + break; + } + } + + return 0; +} + +void keyboard_handler(Stack *registers) +{ + (void)(registers); + + unsigned char c = keyboard_getscancode(); + + if (c) + { + buffer[buffer_index] = c; + ++buffer_index; + if (buffer_index == KEYBOARD_BUFFER_SIZE) + keyboard_clear_buffer(); + } +} + +void keyboard_install(void) +{ + keyboard_clear_buffer(); + irq_install_handler(1, keyboard_handler); +} \ No newline at end of file diff --git a/keyboard.h b/keyboard.h new file mode 100644 index 0000000..ab890fe --- /dev/null +++ b/keyboard.h @@ -0,0 +1,18 @@ +#ifndef KEYBOARD_H +#define KEYBOARD_H + +#define KEYBOARD_BUFFER_SIZE 256 + +#define KEYBOARD_DATA 0x60 + +#define LSHIFT 0x29 +#define RSHIFT 0x35 +#define CTRL 0x1C +#define ALT 0x37 + +void keyboard_clear_buffer(void); +int keyboard_getchar(void); +unsigned char keyboard_getscancode(void); +void keyboard_install(void); + +#endif \ No newline at end of file diff --git a/linker.ld b/linker.ld new file mode 100644 index 0000000..d2ab833 --- /dev/null +++ b/linker.ld @@ -0,0 +1,24 @@ +ENTRY(_start) + +SECTIONS +{ + . = 1M; + + .text ALIGN(4K) : + { + *(.multiboot) + *(.text) + *(.rodata) + } + + .data ALIGN(4K) : + { + *(.data) + } + + .bss ALIGN(4K) : + { + *(.bss) + *(COMMON) + } +} diff --git a/pit_handler.s b/pit_handler.s new file mode 100644 index 0000000..51ef0fb --- /dev/null +++ b/pit_handler.s @@ -0,0 +1,12 @@ +.section .text +.global pit_handler_asm + +pit_handler_asm: + push %eax # Save the registers used by the C handler + push %ecx + push %edx + call pit_handler # Call the C handler + pop %edx # Restore the registers in reverse order + pop %ecx + pop %eax + iret # Return from interrupt diff --git a/shell.c b/shell.c new file mode 100644 index 0000000..a1869e8 --- /dev/null +++ b/shell.c @@ -0,0 +1,113 @@ +#include +#include "keyboard.h" +#include "shell.h" +#include "tty.h" +#include "string.h" + +void shell_init(void) +{ + char input_buffer[SHELL_BUFFER_SIZE + 1]; + size_t i; + char c; + + while (true) + { + terminal_printc("\n"); + terminal_printc("&7dead@&croot&7: /> "); + + i = 0; + c = 0; + + while (i < SHELL_BUFFER_SIZE) + { + c = keyboard_getchar(); + + if (c == '\b') + { + if (i > 0) + { + terminal_printc("\b \b"); + --i; + } + } + else + { + terminal_putchar(c); + input_buffer[i] = c; + ++i; + + if (c == '\n') + break; + } + } + + input_buffer[i] = '\0'; + keyboard_clear_buffer(); + shell_parse_input(input_buffer); + } +} + +void shell_help_command(void) +{ + terminal_printc("List of commands:\n"); + terminal_printc("help - Print out the list of commands.\n"); + terminal_printc("exit - Exit the shell.\n"); + terminal_printc("echo - Print out the message. &eWITH colors!&7\n"); + terminal_printc("clear - Clear the terminal.\n"); +} + +void shell_exit_command(void) +{ + terminal_printc("Exiting shell...\n"); + terminal_printc("Goodbye!\n"); + while (1) + ; +} + +void shell_echo_command(char *input) +{ + char *message = input; + + while (*message == ' ') + { + message++; + } + + terminal_printc(message); + terminal_printc("\n"); +} + +void shell_parse_input(char *input) +{ + char *command = strtok(input, " \n"); + char *first_param = strtok(NULL, " \n"); + + if (command == NULL || *command == '\0') + { + return; + } + + if (strcmp(command, "help") == 0) + { + shell_help_command(); + } + else if (strcmp(command, "echo") == 0) + { + shell_echo_command(first_param); + } + else if (strcmp(command, "exit") == 0) + { + shell_exit_command(); + } + else if (strcmp(command, "clear") == 0) + { + terminal_clear(); + } + else + { + terminal_printc("Unknown command: '"); + terminal_writestring(command); + terminal_printc("'\n"); + terminal_printc("Type 'help' to print out the list of commands.\n"); + } +} diff --git a/shell.h b/shell.h new file mode 100644 index 0000000..2f8548e --- /dev/null +++ b/shell.h @@ -0,0 +1,9 @@ +#ifndef _KERNEL_SHELL_H +#define _KERNEL_SHELL_H + +#define SHELL_BUFFER_SIZE 256 + +void shell_init(void); +void shell_parse_input(char *input); + +#endif \ No newline at end of file diff --git a/string.c b/string.c new file mode 100644 index 0000000..36119de --- /dev/null +++ b/string.c @@ -0,0 +1,76 @@ +#include "string.h" +#include + +int strcmp(const char *str1, const char *str2) +{ + while (*str1 && (*str1 == *str2)) + { + str1++; + str2++; + } + return *(const unsigned char *)str1 - *(const unsigned char *)str2; +} + +char *strchr(const char *str, int c) +{ + while (*str != '\0') + { + if (*str == c) + { + return (char *)str; + } + str++; + } + return NULL; +} + +char *strtok(char *str, const char *delim) +{ + static char *last_token = NULL; + char *token_start; + char *current; + + if (str != NULL) + { + current = str; + } + else + { + current = last_token; + } + + if (current == NULL) + { + return NULL; + } + + while (*current != '\0' && strchr(delim, *current) != NULL) + { + current++; + } + + if (*current == '\0') + { + last_token = NULL; + return NULL; + } + + token_start = current; + + while (*current != '\0' && strchr(delim, *current) == NULL) + { + current++; + } + + if (*current != '\0') + { + *current = '\0'; + last_token = current + 1; + } + else + { + last_token = NULL; + } + + return token_start; +} diff --git a/string.h b/string.h new file mode 100644 index 0000000..db9d985 --- /dev/null +++ b/string.h @@ -0,0 +1,8 @@ +#ifndef STRING_H +#define STRING_H + +char *strchr(const char *str, int c); +char *strtok(char *str, const char *delim); +int strcmp(const char *str1, const char *str2); + +#endif \ No newline at end of file diff --git a/sys.c b/sys.c new file mode 100644 index 0000000..2c30ad0 --- /dev/null +++ b/sys.c @@ -0,0 +1,16 @@ +#include "sys.h" + +void sys_halt(void) +{ + asm volatile("hlt" ::: "memory"); +} + +void sys_enable_interrupts(void) +{ + asm volatile("sti" ::: "memory"); +} + +void sys_disable_interrupts(void) +{ + asm volatile("cli" ::: "memory"); +} \ No newline at end of file diff --git a/sys.h b/sys.h new file mode 100644 index 0000000..90f39a6 --- /dev/null +++ b/sys.h @@ -0,0 +1,8 @@ +#ifndef _KERNEL_SYS_H +#define _KERNEL_SYS_H + +void sys_halt(void); +void sys_enable_interrupts(void); +void sys_disable_interrupts(void); + +#endif \ No newline at end of file diff --git a/syscall.c b/syscall.c new file mode 100644 index 0000000..26eac7b --- /dev/null +++ b/syscall.c @@ -0,0 +1,26 @@ +#include +#include "interrupts.h" +#include "syscall.h" +#include "tty.h" + +void test_syscall() +{ + terminal_printc("Test syscall called\n"); +} + +void syscall_handler(Stack *registers) +{ + int sys_index = registers->eax; + + if (sys_index != 0) + { + return; + } + + test_syscall(); +} + +void syscall_init(void) +{ + isr_install_handler(128, syscall_handler); +} \ No newline at end of file diff --git a/syscall.h b/syscall.h new file mode 100644 index 0000000..5973d40 --- /dev/null +++ b/syscall.h @@ -0,0 +1,6 @@ +#ifndef SYSCALL_H +#define SYSCALL_H + +void syscall_init(void); + +#endif \ No newline at end of file diff --git a/timer.c b/timer.c new file mode 100644 index 0000000..6a6d1e6 --- /dev/null +++ b/timer.c @@ -0,0 +1,40 @@ +#include "timer.h" +#include "io.h" +#include "sys.h" +#include "idt.h" + +#define PIT_FREQUENCY 1193182 +#define PIT_CHANNEL_0 0x40 +#define PIT_COMMAND 0x43 + +volatile uint32_t tick = 0; + +void pit_handler() +{ + tick++; + outb(0x20, 0x20); +} + +void delay(uint32_t milliseconds) +{ + uint32_t end = tick + milliseconds; + while (tick < end) + { + sys_halt(); + } +} + +void pit_set_frequency(uint32_t frequency) +{ + uint32_t divisor = PIT_FREQUENCY / frequency; + outb(PIT_COMMAND, 0x36); + outb(PIT_CHANNEL_0, divisor & 0xFF); + outb(PIT_CHANNEL_0, (divisor >> 8) & 0xFF); +} + +void timer_install(void) +{ + pic_remap(0x20, 0x28); + pit_set_frequency(1000); + idt_set_gate(32, (uint32_t)pit_handler_asm, 0x08, 0x8E); +} \ No newline at end of file diff --git a/timer.h b/timer.h new file mode 100644 index 0000000..c7c705c --- /dev/null +++ b/timer.h @@ -0,0 +1,14 @@ +#ifndef TIMER_H +#define TIMER_H + +#include + +extern void pit_handler_asm(); + +void pit_handler(); +void delay(uint32_t milliseconds); +void pit_set_frequency(uint32_t frequency); +void pic_remap(int offset1, int offset2); +void timer_install(void); + +#endif \ No newline at end of file diff --git a/tty.c b/tty.c new file mode 100644 index 0000000..72fb0e9 --- /dev/null +++ b/tty.c @@ -0,0 +1,190 @@ +#include "tty.h" +#include "vga.h" +#include "io.h" +#include +#include +#include + +size_t strlen(const char *str) +{ + size_t len = 0; + while (str[len]) + len++; + return len; +} + +static const size_t VGA_WIDTH = 80; +static const size_t VGA_HEIGHT = 25; + +size_t terminal_row; +size_t terminal_column; +uint8_t terminal_color; +uint16_t *terminal_buffer; + +void terminal_initialize(void) +{ + terminal_row = 0; + terminal_column = 0; + terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); + terminal_buffer = (uint16_t *)0xB8000; + for (size_t y = 0; y < VGA_HEIGHT; y++) + { + for (size_t x = 0; x < VGA_WIDTH; x++) + { + const size_t index = y * VGA_WIDTH + x; + terminal_buffer[index] = vga_entry(' ', terminal_color); + } + } +} + +void terminal_setcolor(uint8_t color) +{ + terminal_color = color; +} + +void terminal_putentryat(char c, uint8_t color, size_t x, size_t y) +{ + const size_t index = y * VGA_WIDTH + x; + terminal_buffer[index] = vga_entry(c, color); +} + +static uint16_t terminal_pos(uint8_t x, uint8_t y) +{ + return y * VGA_WIDTH + x; +} + +void terminal_scroll(void) +{ + for (size_t y = 0; y < VGA_HEIGHT - 1; y++) + { + for (size_t x = 0; x < VGA_WIDTH; x++) + { + terminal_buffer[y * VGA_WIDTH + x] = terminal_buffer[(y + 1) * VGA_WIDTH + x]; + } + } + for (size_t x = 0; x < VGA_WIDTH; x++) + { + terminal_buffer[(VGA_HEIGHT - 1) * VGA_WIDTH + x] = vga_entry(' ', terminal_color); + } + terminal_row = VGA_HEIGHT - 1; +} + +static void terminal_backspace(void) +{ + if (terminal_column == 0) + { + terminal_column = VGA_WIDTH - 1; + if (terminal_row == 0) + { + terminal_column = 0; + } + else + { + --terminal_row; + } + uint16_t empty = vga_entry(' ', terminal_color); + uint16_t index = terminal_pos(terminal_column, terminal_row); + while (terminal_column > 0 && terminal_buffer[index] == empty) + { + --terminal_column; + index = terminal_pos(terminal_column, terminal_row); + } + if (terminal_buffer[index] != empty && terminal_column + 1 < VGA_WIDTH) + { + ++terminal_column; + } + } + else + { + --terminal_column; + } + uint16_t index = terminal_pos(terminal_column, terminal_row); + terminal_buffer[index] = vga_entry(' ', terminal_color); +} + +void terminal_putchar(char c) +{ + if (c == '\n') + { + terminal_column = 0; + if (++terminal_row == VGA_HEIGHT) + { + terminal_scroll(); + } + } + else if (c == '\b') + { + terminal_backspace(); + } + else + { + uint16_t index = terminal_pos(terminal_column, terminal_row); + terminal_buffer[index] = vga_entry(c, terminal_color); + if (++terminal_column == VGA_WIDTH) + { + terminal_column = 0; + if (++terminal_row == VGA_HEIGHT) + { + terminal_scroll(); + } + } + } + terminal_update_cursor(); +} + +void terminal_write(const char *data, size_t size) +{ + for (size_t i = 0; i < size; i++) + { + terminal_putchar(data[i]); + } +} + +void terminal_writestring(const char *data) +{ + terminal_write(data, strlen(data)); +} + +void terminal_printc(const char *data) +{ + while (*data) + { + if (*data == '&' && ((*(data + 1) >= '0' && *(data + 1) <= '9') || + (*(data + 1) >= 'a' && *(data + 1) <= 'f'))) + { + terminal_setcolor(vga_entry_color(vga_color_from_char(*(data + 1)), VGA_COLOR_BLACK)); + data += 2; + } + else + { + terminal_putchar(*data); + data++; + } + } +} + +void terminal_update_cursor(void) +{ + uint16_t pos = terminal_row * VGA_WIDTH + terminal_column; + + outb(0x3D4, 14); + outb(0x3D5, pos >> 8); + outb(0x3D4, 15); + outb(0x3D5, pos); +} + +void terminal_clear(void) +{ + for (size_t y = 0; y < VGA_HEIGHT; y++) + { + for (size_t x = 0; x < VGA_WIDTH; x++) + { + const size_t index = y * VGA_WIDTH + x; + terminal_buffer[index] = vga_entry(' ', terminal_color); + } + } + + terminal_column = 0; + terminal_row = 0; + terminal_update_cursor(); +} \ No newline at end of file diff --git a/tty.h b/tty.h new file mode 100644 index 0000000..56641bc --- /dev/null +++ b/tty.h @@ -0,0 +1,17 @@ +#ifndef TERMINAL_H +#define TERMINAL_H + +#include +#include + +void terminal_initialize(void); +void terminal_setcolor(uint8_t color); +void terminal_putentryat(char c, uint8_t color, size_t x, size_t y); +void terminal_putchar(char c); +void terminal_write(const char *data, size_t size); +void terminal_writestring(const char *data); +void terminal_printc(const char *data); +void terminal_update_cursor(void); +void terminal_clear(void); + +#endif \ No newline at end of file diff --git a/user_space.c b/user_space.c new file mode 100644 index 0000000..fdc633a --- /dev/null +++ b/user_space.c @@ -0,0 +1,23 @@ +#include "user_space.h" + +void enter_user_space(void) +{ + asm volatile(" cli; \ + mov $0x23, %ax; \ + mov %ax, %ds; \ + mov %ax, %es; \ + mov %ax, %fs; \ + mov %ax, %gs; \ + mov %esp, %eax; \ + pushl $0x23; \ + pushl %eax; \ + pushf; \ + popl %eax; \ + orl $0x200, %eax; \ + pushl %eax; \ + pushl $0x1B; \ + push $1f; \ + iret; \ + 1: \ + "); +} \ No newline at end of file diff --git a/user_space.h b/user_space.h new file mode 100644 index 0000000..7102d6a --- /dev/null +++ b/user_space.h @@ -0,0 +1,6 @@ +#ifndef _USER_SPACE_H +#define _USER_SPACE_H + +void enter_user_space(void); + +#endif \ No newline at end of file diff --git a/vga.c b/vga.c new file mode 100644 index 0000000..a23632e --- /dev/null +++ b/vga.c @@ -0,0 +1,31 @@ +#include "vga.h" + +uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) { + return fg | bg << 4; +} + +uint16_t vga_entry(unsigned char uc, uint8_t color) { + return (uint16_t) uc | (uint16_t) color << 8; +} + +uint8_t vga_color_from_char(char color_code) { + switch (color_code) { + case '0': return VGA_COLOR_BLACK; + case '1': return VGA_COLOR_BLUE; + case '2': return VGA_COLOR_GREEN; + case '3': return VGA_COLOR_CYAN; + case '4': return VGA_COLOR_RED; + case '5': return VGA_COLOR_MAGENTA; + case '6': return VGA_COLOR_BROWN; + case '7': return VGA_COLOR_LIGHT_GREY; + case '8': return VGA_COLOR_DARK_GREY; + case '9': return VGA_COLOR_LIGHT_BLUE; + case 'a': return VGA_COLOR_LIGHT_GREEN; + case 'b': return VGA_COLOR_LIGHT_CYAN; + case 'c': return VGA_COLOR_LIGHT_RED; + case 'd': return VGA_COLOR_LIGHT_MAGENTA; + case 'e': return VGA_COLOR_LIGHT_BROWN; + case 'f': return VGA_COLOR_WHITE; + default: return VGA_COLOR_LIGHT_GREY; + } +} \ No newline at end of file diff --git a/vga.h b/vga.h new file mode 100644 index 0000000..1a4e48f --- /dev/null +++ b/vga.h @@ -0,0 +1,29 @@ +#ifndef VGA_H +#define VGA_H + +#include + +enum vga_color { + VGA_COLOR_BLACK = 0, + VGA_COLOR_BLUE = 1, + VGA_COLOR_GREEN = 2, + VGA_COLOR_CYAN = 3, + VGA_COLOR_RED = 4, + VGA_COLOR_MAGENTA = 5, + VGA_COLOR_BROWN = 6, + VGA_COLOR_LIGHT_GREY = 7, + VGA_COLOR_DARK_GREY = 8, + VGA_COLOR_LIGHT_BLUE = 9, + VGA_COLOR_LIGHT_GREEN = 10, + VGA_COLOR_LIGHT_CYAN = 11, + VGA_COLOR_LIGHT_RED = 12, + VGA_COLOR_LIGHT_MAGENTA = 13, + VGA_COLOR_LIGHT_BROWN = 14, + VGA_COLOR_WHITE = 15, +}; + +uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg); +uint16_t vga_entry(unsigned char uc, uint8_t color); +uint8_t vga_color_from_char(char color_code); + +#endif \ No newline at end of file