dead@root

This commit is contained in:
assada 2024-05-21 18:41:16 +03:00
commit b739f2adc8
39 changed files with 1647 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 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)

35
boot.s Normal file
View File

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

18
build.sh Executable file
View File

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

29
gdt.c Normal file
View File

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

26
gdt.h Normal file
View File

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

19
gdt_flush.s Normal file
View File

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

3
grub.cfg Normal file
View File

@ -0,0 +1,3 @@
menuentry "deadOS" {
multiboot /boot/deados.bin
}

55
idt.c Normal file
View File

@ -0,0 +1,55 @@
#include "idt.h"
#include "io.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));
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);
}

11
idt.h Normal file
View File

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

48
interrupts.h Normal file
View File

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

18
io.c Normal file
View File

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

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

99
irq.c Normal file
View File

@ -0,0 +1,99 @@
#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(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);
}

59
irq_e.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_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

161
isr.c Normal file
View File

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

85
isr_e.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_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

45
kernel.c Normal file
View File

@ -0,0 +1,45 @@
#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)
{
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();
}

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

24
linker.ld Normal file
View File

@ -0,0 +1,24 @@
ENTRY(_start)
SECTIONS
{
. = 1M;
.text ALIGN(4K) :
{
*(.multiboot)
*(.text)
*(.rodata)
}
.data ALIGN(4K) :
{
*(.data)
}
.bss ALIGN(4K) :
{
*(.bss)
*(COMMON)
}
}

12
pit_handler.s Normal file
View File

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

113
shell.c Normal file
View File

@ -0,0 +1,113 @@
#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_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");
}
}

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

76
string.c Normal file
View File

@ -0,0 +1,76 @@
#include "string.h"
#include <stddef.h>
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;
}

8
string.h Normal file
View File

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

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

26
syscall.c Normal file
View File

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

6
syscall.h Normal file
View File

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

40
timer.c Normal file
View File

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

14
timer.h Normal file
View File

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

190
tty.c Normal file
View File

@ -0,0 +1,190 @@
#include "tty.h"
#include "vga.h"
#include "io.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
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();
}

17
tty.h Normal file
View File

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

23
user_space.c Normal file
View File

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

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