dead@root
This commit is contained in:
commit
ea8f6b4ce0
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
*.o
|
||||||
|
*.bin
|
||||||
|
*.elf
|
||||||
|
*.img
|
||||||
|
isodir/
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.iso
|
45
Makefile
Normal file
45
Makefile
Normal 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
37
README.md
Normal 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
29
boot.s
Normal 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
63
gdt.c
Normal 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
63
gdt.h
Normal 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
14
gdt_flush.s
Normal 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
6
grub.cfg
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
default=0
|
||||||
|
timeout=0
|
||||||
|
|
||||||
|
menuentry "deadOS" {
|
||||||
|
multiboot /boot/deados.bin
|
||||||
|
}
|
27
idt.c
Normal file
27
idt.c
Normal 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
28
idt.h
Normal 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
5
idt_load.s
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.section .text
|
||||||
|
.global idt_load
|
||||||
|
idt_load:
|
||||||
|
lidt idtp
|
||||||
|
ret
|
44
interrupts.h
Normal file
44
interrupts.h
Normal 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
20
io.c
Normal 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
10
io.h
Normal 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
93
irq.c
Normal 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
59
irq_flush.s
Normal 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
156
isr.c
Normal 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
85
isr_flush.s
Normal 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
46
kernel.c
Normal 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
202
keyboard.c
Normal 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
18
keyboard.h
Normal 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
32
linker.ld
Normal 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
112
shell.c
Normal 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
9
shell.h
Normal 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
125
string.c
Normal 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
14
string.h
Normal 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
16
sys.c
Normal 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
8
sys.h
Normal 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
47
syscall.c
Normal 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
6
syscall.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef SYSCALL_H
|
||||||
|
#define SYSCALL_H
|
||||||
|
|
||||||
|
void syscall_init(void);
|
||||||
|
|
||||||
|
#endif
|
35
timer.c
Normal file
35
timer.c
Normal 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
13
timer.h
Normal 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
9
tss_flush.s
Normal 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
184
tty.c
Normal 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
13
tty.h
Normal 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
22
user_space.c
Normal 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
6
user_space.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#ifndef _USER_SPACE_H
|
||||||
|
#define _USER_SPACE_H
|
||||||
|
|
||||||
|
void enter_user_space(void);
|
||||||
|
|
||||||
|
#endif
|
31
vga.c
Normal file
31
vga.c
Normal 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
29
vga.h
Normal 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
|
Loading…
Reference in New Issue
Block a user