dead@root

This commit is contained in:
assada 2024-05-25 19:20:33 +03:00
commit ea8f6b4ce0
39 changed files with 1769 additions and 0 deletions

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
*.o
*.bin
*.elf
*.img
isodir/
.vscode/
.idea/
*.iso

45
Makefile Normal file
View File

@ -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 tss_flush.s irq_flush.s isr_flush.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)

37
README.md Normal file
View File

@ -0,0 +1,37 @@
# Simple OS implementation
DeadOS is a minimalist operating system designed for x86 architecture, created solely for educational purposes. It is an ideal platform for learning and understanding the fundamental concepts of operating system development. While it is not intended to evolve into a fully-fledged OS, DeadOS provides a straightforward and manageable codebase that makes it perfect for experimentation and study.
## Requirements
- make
- GCC Cross-Compiler
- QEMU
## How to run
- `make`
- `qemu-system-x86_64 -monitor stdio -cdrom deados.iso`
## Features
- [x] Bootloader
- [x] Kernel
- [x] VGA Driver
- [x] Keyboard Driver
- [x] Shell
- [x] Basic commands
- [x] Timers
- [x] Interrupts
- [x] Kernel Extensions handling
- [ ] Paging
- [] Memory Management
- [] File System
- [x] User Space
- [x] Syscalls
- [ ] Multitasking
- [] stdlib
## Screenshot:
![image](https://github.com/assada/os/assets/1472664/9b67c053-36e1-4816-ad7f-093b89b03fce)

29
boot.s Normal file
View File

@ -0,0 +1,29 @@
.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 .stack, "aw", @nobits
.global stack_top
stack_bottom:
.skip 16384
stack_top:
.section .text
.global _start
.type _start, @function
_start:
movl $stack_top, %esp
push %ebx
call kernel_main
1:
jmp 1b

63
gdt.c Normal file
View File

@ -0,0 +1,63 @@
#include "gdt.h"
#include "string.h"
#define GDT_ENTRY 6
Gdt_entry gdt[GDT_ENTRY];
Gdt_ptr gdtp;
extern void gdt_flush(uint32_t);
Tss_entry tss;
extern void tss_flush(void);
static void gdt_set_gate(uint8_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t granularity)
{
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) & 0xF;
gdt[num].granularity |= (granularity & 0xF0);
gdt[num].access = access;
}
static void tss_install(uint8_t num, uint16_t kernel_ss, uint16_t kernel_esp)
{
uint32_t base = (uint32_t)&tss;
uint32_t limit = base + sizeof(Tss_entry);
gdt_set_gate(num, base, limit, 0xE9, 0x0);
memset(&tss, 0, sizeof(Tss_entry));
tss.ss0 = kernel_ss;
tss.esp0 = kernel_esp;
tss.cs = 0x1B;
tss.ss = 0x23;
tss.es = 0x23;
tss.ds = 0x23;
tss.fs = 0x23;
tss.gs = 0x23;
}
void gdt_install()
{
gdt_set_gate(0, 0x0, 0x0, 0x0, 0x0); // Null segment
gdt_set_gate(1, 0x0, 0xFFFFFFFF, 0x9A, 0xCF); // Kernel code segment
gdt_set_gate(2, 0x0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment
gdt_set_gate(3, 0x0, 0xFFFFFFFF, 0xFA, 0xCF); // User code segment
gdt_set_gate(4, 0x0, 0xFFFFFFFF, 0xF2, 0xCF); // User data segment
tss_install(5, 0x10, stack_top);
gdtp.limit = (sizeof(Gdt_entry) * GDT_ENTRY) - 1;
gdtp.base = (uint32_t)&gdt;
gdt_flush((uint32_t)&gdtp);
tss_flush();
}

63
gdt.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef GDT_H
#define GDT_H
#include <stdint.h>
extern uint32_t stack_top;
typedef struct gdt_entry_t Gdt_entry;
struct gdt_entry_t
{
uint16_t limit_low;
uint16_t base_low;
uint8_t base_middle;
uint8_t access;
uint8_t granularity;
uint8_t base_high;
} __attribute__((packed));
typedef struct gdt_ptr_t Gdt_ptr;
struct gdt_ptr_t
{
uint16_t limit;
uint32_t base;
} __attribute__((packed));
static void gdt_set_gate(uint8_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t granularity);
void gdt_install();
void set_kernel_stack(uint32_t stack);
typedef struct tss_entry_t Tss_entry;
struct tss_entry_t
{
uint32_t prevTss;
uint32_t esp0;
uint32_t ss0;
uint32_t esp1;
uint32_t ss1;
uint32_t esp2;
uint32_t ss2;
uint32_t cr3;
uint32_t eip;
uint32_t eflags;
uint32_t eax;
uint32_t ecx;
uint32_t edx;
uint32_t ebx;
uint32_t esp;
uint32_t ebp;
uint32_t esi;
uint32_t edi;
uint32_t es;
uint32_t cs;
uint32_t ss;
uint32_t ds;
uint32_t fs;
uint32_t gs;
uint32_t ldt;
uint16_t trap;
uint16_t iomap;
} __attribute__((packed));
#endif

14
gdt_flush.s Normal file
View File

@ -0,0 +1,14 @@
.global gdt_flush
gdt_flush:
lgdt gdtp
jmp $0x08, $reload_cs
reload_cs:
movw $0x10, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
ret

6
grub.cfg Normal file
View File

@ -0,0 +1,6 @@
default=0
timeout=0
menuentry "deadOS" {
multiboot /boot/deados.bin
}

27
idt.c Normal file
View File

@ -0,0 +1,27 @@
#include <stdint.h>
#include "idt.h"
#include "io.h"
#include "string.h"
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;
memset(&idt, 0, sizeof(struct idt_entry) * IDT_ENTRIES);
idt_load();
}

28
idt.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef IDT_H
#define IDT_H
#include <stdint.h>
#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));
extern void idt_load();
void idt_install();
void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags);
#endif

5
idt_load.s Normal file
View File

@ -0,0 +1,5 @@
.section .text
.global idt_load
idt_load:
lidt idtp
ret

44
interrupts.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef INTERUPTS_H
#define INTERUPTS_H
#include <stdint.h>
typedef struct stack_t Stack;
struct stack_t
{
uint32_t gs, fs, es, ds;
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
uint32_t id, err_code;
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
#define PIC2 0xA0
#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

20
io.c Normal file
View File

@ -0,0 +1,20 @@
#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 wait(void)
{
asm volatile("jmp 1f\n\t"
"1:jmp 2f\n\t"
"2:");
}

10
io.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef IO_H
#define IO_H
#include <stdint.h>
void outb(uint16_t port, uint8_t val);
uint8_t inb(uint16_t port);
void io_wait(void);
#endif

93
irq.c Normal file
View File

@ -0,0 +1,93 @@
#include <stdint.h>
#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(0x20, 0x11);
outb(0xA0, 0x11);
outb(0x21, 0x20);
outb(0xA1, 0x28);
outb(0x21, 0x04);
outb(0xA1, 0x02);
outb(0x21, 0x01);
outb(0xA1, 0x01);
outb(0x21, 0x00);
outb(0xA1, 0x00);
}
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(0xA0, 0x20);
outb(0x20, 0x20);
}

59
irq_flush.s Normal file
View File

@ -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_flush
.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_flush:
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

156
isr.c Normal file
View File

@ -0,0 +1,156 @@
#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_printf("Exception. System Halted!\n");
terminal_printf("Exception: ");
terminal_printf(exception_messages[registers->id]);
isr_call_handler(registers);
for (;;)
sys_halt();
}
}

85
isr_flush.s Normal file
View File

@ -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_flush
.endm
.macro ISR_ERR index
.global isr\index
isr\index:
cli
push $\index
jmp isr_flush
.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 # 80h syscall
isr_flush:
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

46
kernel.c Normal file
View File

@ -0,0 +1,46 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#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)
{
gdt_install();
idt_install();
isr_install();
irq_install();
timer_install();
keyboard_install();
syscall_init();
enter_user_space();
}
void main(void)
{
terminal_initialize();
for (int i = 1; i < 4; i++)
{
terminal_printf("&cTest &7%d\n", i);
delay(500);
}
terminal_clear();
terminal_printf("Welcome to &cDeadOS&7.\n");
terminal_printf("You are now in user space.\n");
terminal_printf("Type 'help' for a list of available commands.\n");
shell_init();
}

202
keyboard.c Normal file
View File

@ -0,0 +1,202 @@
#include <stddef.h>
#include <stdint.h>
#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);
}

18
keyboard.h Normal file
View File

@ -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

32
linker.ld Normal file
View File

@ -0,0 +1,32 @@
ENTRY(_start)
SECTIONS
{
. = 1M;
kernel_start = .;
.text BLOCK(4K) : ALIGN(4K)
{
*(.multiboot)
*(.text)
}
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.rodata)
}
.data BLOCK(4K) : ALIGN(4K)
{
*(.data)
}
.bss BLOCK(4K) : ALIGN(4K)
{
*(.bss)
*(.stack)
}
kernel_end = .;
}

112
shell.c Normal file
View File

@ -0,0 +1,112 @@
#include <stdbool.h>
#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_printf("&7dead@&croot&7: /> ");
i = 0;
c = 0;
while (i < SHELL_BUFFER_SIZE)
{
c = keyboard_getchar();
if (c == '\b')
{
if (i > 0)
{
terminal_printf("\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_printf("List of commands:\n");
terminal_printf("help - Print out the list of commands.\n");
terminal_printf("exit - Exit the shell.\n");
terminal_printf("echo - Print out the message. &eWITH colors!&7\n");
terminal_printf("clear - Clear the terminal.\n");
}
void shell_exit_command(void)
{
terminal_printf("Exiting shell...\n");
terminal_printf("Goodbye!\n");
while (1)
;
}
void shell_echo_command(char *input)
{
char *message = input;
while (*message == ' ')
{
message++;
}
terminal_printf(message);
terminal_printf("\n");
}
void shell_parse_input(char *input)
{
char *command = strtok(input, " \n");
char *args = input + strlen(command) + 1;
if (command == NULL || *command == '\0')
{
return;
}
if (strcmp(command, "help") == 0)
{
shell_help_command();
}
else if (strcmp(command, "echo") == 0)
{
shell_echo_command(args);
}
else if (strcmp(command, "exit") == 0)
{
shell_exit_command();
}
else if (strcmp(command, "clear") == 0)
{
terminal_clear();
}
else
{
terminal_printf("Unknown command: '");
terminal_print(command);
terminal_printf("'\n");
terminal_printf("Type 'help' to print out the list of commands.\n");
}
}

9
shell.h Normal file
View File

@ -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

125
string.c Normal file
View File

@ -0,0 +1,125 @@
#include "string.h"
#include <stddef.h>
size_t strlen(const char *str)
{
size_t len = 0;
while (str[len])
++len;
return len;
}
void *memset(void *ptr, int value, size_t size)
{
unsigned char *buf = (unsigned char *)ptr;
for (size_t i = 0; i < size; ++i)
buf[i] = (unsigned char)value;
return ptr;
}
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 character)
{
size_t i = 0;
while (str[i] != (char)character)
{
if (str[i] == '\0')
return NULL;
++i;
}
return (char *)(str + i);
}
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;
}
void itoa(int value, char *str, int base)
{
char *rc;
char *ptr;
char *low;
if (value < 0 && base == 10)
{
*str++ = '-';
value = -value;
}
rc = ptr = str;
do
{
*ptr++ = "0123456789abcdef"[value % base];
value /= base;
} while (value);
*ptr-- = '\0';
for (low = rc; low < ptr; low++, ptr--)
{
char tmp = *low;
*low = *ptr;
*ptr = tmp;
}
}

14
string.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef STRING_H
#define STRING_H
#include <stddef.h>
char *strchr(const char *str, int c);
char *strtok(char *str, const char *delim);
int strcmp(const char *str1, const char *str2);
size_t strlen(const char *str);
void itoa(int value, char *str, int base);
void *memset(void *ptr, int value, size_t size);
#endif

16
sys.c Normal file
View File

@ -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");
}

8
sys.h Normal file
View File

@ -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

47
syscall.c Normal file
View File

@ -0,0 +1,47 @@
#include <stdint.h>
#include "interrupts.h"
#include "keyboard.h"
#include "sys.h"
#include "syscall.h"
#include "tty.h"
#include "timer.h"
#define NB_SYSCALL 2
void *syscalls[NB_SYSCALL] = {
keyboard_getchar,
sys_halt};
void syscall_handler(Stack *registers)
{
int sys_index = registers->eax;
if (sys_index >= NB_SYSCALL)
return;
void *function = syscalls[sys_index];
int ret;
asm volatile(" push %1; \
push %2; \
push %3; \
push %4; \
push %5; \
call *%6; \
pop %%ebx; \
pop %%ebx; \
pop %%ebx; \
pop %%ebx; \
pop %%ebx; \
" : "=a"(ret) : "r"(registers->edi), "r"(registers->esi),
"r"(registers->edx), "r"(registers->ecx),
"r"(registers->ebx), "r"(function));
registers->eax = ret;
}
void syscall_init(void)
{
isr_install_handler(128, syscall_handler);
}

6
syscall.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef SYSCALL_H
#define SYSCALL_H
void syscall_init(void);
#endif

35
timer.c Normal file
View File

@ -0,0 +1,35 @@
#include <stdint.h>
#include "interrupts.h"
#include "io.h"
#include "timer.h"
volatile uint32_t timer_ticks = 0;
void delay(const uint32_t ticks)
{
uint32_t total_ticks = timer_ticks + ticks;
while (timer_ticks < total_ticks)
;
}
void timer_handler(Stack *registers)
{
++timer_ticks;
}
static void timer_phase(const uint32_t hz)
{
uint32_t divisor = PIT_FREQUENCY / hz;
outb(PIT_COMMAND, 0x36);
outb(PIT_CHANNEL_0, divisor & 0xFF);
outb(PIT_CHANNEL_0, divisor >> 8);
}
void timer_install(void)
{
irq_install_handler(0, timer_handler);
timer_phase(1000);
}

13
timer.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef TIMER_H
#define TIMER_H
#include <stdint.h>
#define PIT_FREQUENCY 1193182
#define PIT_CHANNEL_0 0x40
#define PIT_COMMAND 0x43
void delay(uint32_t milliseconds);
void timer_install(void);
#endif

9
tss_flush.s Normal file
View File

@ -0,0 +1,9 @@
.section .text
.align 4
.global tss_flush
.type tss_flush, @function
tss_flush:
mov $0x2B, %ax
ltr %ax
ret

184
tty.c Normal file
View File

@ -0,0 +1,184 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdarg.h>
#include "tty.h"
#include "vga.h"
#include "io.h"
#include "string.h"
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 i = 0; i < VGA_WIDTH * VGA_HEIGHT; i++)
{
terminal_buffer[i] = 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;
}
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);
}
static void terminal_backspace(void)
{
if (terminal_column == 0)
{
terminal_column = VGA_WIDTH - 1;
if (terminal_row > 0)
{
--terminal_row;
}
}
else
{
--terminal_column;
}
terminal_buffer[terminal_pos(terminal_column, terminal_row)] = 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
{
terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
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_print(const char *data)
{
terminal_write(data, strlen(data));
}
void terminal_printf(const char *format, ...)
{
va_list args;
va_start(args, format);
const char *p = format;
while (*p)
{
if (*p == '%' && (*(p + 1) == 's' || *(p + 1) == 'd' || *(p + 1) == 'x'))
{
p++;
if (*p == 's')
{
terminal_print(va_arg(args, const char *));
}
else if (*p == 'd')
{
char buffer[12];
itoa(va_arg(args, int), buffer, 10);
terminal_print(buffer);
}
else if (*p == 'x')
{
char buffer[12];
itoa(va_arg(args, unsigned int), buffer, 16);
terminal_print(buffer);
}
}
else if (*p == '&' && ((*(p + 1) >= '0' && *(p + 1) <= '9') || (*(p + 1) >= 'a' && *(p + 1) <= 'f')))
{
terminal_setcolor(vga_entry_color(vga_color_from_char(*(p + 1)), VGA_COLOR_BLACK));
p++;
}
else
{
terminal_putchar(*p);
}
p++;
}
va_end(args);
}
void terminal_clear(void)
{
for (size_t i = 0; i < VGA_WIDTH * VGA_HEIGHT; i++)
{
terminal_buffer[i] = vga_entry(' ', terminal_color);
}
terminal_column = 0;
terminal_row = 0;
terminal_update_cursor();
}

13
tty.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef TERMINAL_H
#define TERMINAL_H
#include <stddef.h>
#include <stdint.h>
void terminal_initialize(void);
void terminal_printf(const char *data, ...);
void terminal_print(const char *data);
void terminal_clear(void);
void terminal_putchar(char c);
#endif

22
user_space.c Normal file
View File

@ -0,0 +1,22 @@
void enter_user_space()
{
asm volatile("cli; \
mov $0x23, %ax; \
mov %ax, %ds; \
mov %ax, %es; \
mov %ax, %fs; \
mov %ax, %gs; \
mov %esp, %eax; \
push $0x23; \
push %eax; \
pushf; \
pop %eax; \
or $0x200, %eax; \
push %eax; \
push $0x1B; \
push $user_code_entry; \
iret; \
user_code_entry: \
call main; \
");
}

6
user_space.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef _USER_SPACE_H
#define _USER_SPACE_H
void enter_user_space(void);
#endif

31
vga.c Normal file
View File

@ -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;
}
}

29
vga.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef VGA_H
#define VGA_H
#include <stdint.h>
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