dead@root
This commit is contained in:
commit
b739f2adc8
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 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
35
boot.s
Normal 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
18
build.sh
Executable 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
29
gdt.c
Normal 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
26
gdt.h
Normal 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
19
gdt_flush.s
Normal 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
|
55
idt.c
Normal file
55
idt.c
Normal 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
11
idt.h
Normal 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
5
idt_load.s
Normal file
@ -0,0 +1,5 @@
|
||||
.section .text
|
||||
.global idt_load
|
||||
idt_load:
|
||||
lidt [idtp]
|
||||
ret
|
48
interrupts.h
Normal file
48
interrupts.h
Normal 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
18
io.c
Normal 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
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
|
99
irq.c
Normal file
99
irq.c
Normal 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
59
irq_e.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_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
161
isr.c
Normal 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
85
isr_e.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_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
45
kernel.c
Normal 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
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
|
24
linker.ld
Normal file
24
linker.ld
Normal 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
12
pit_handler.s
Normal 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
113
shell.c
Normal 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
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
|
76
string.c
Normal file
76
string.c
Normal 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
8
string.h
Normal 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
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
|
26
syscall.c
Normal file
26
syscall.c
Normal 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
6
syscall.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef SYSCALL_H
|
||||
#define SYSCALL_H
|
||||
|
||||
void syscall_init(void);
|
||||
|
||||
#endif
|
40
timer.c
Normal file
40
timer.c
Normal 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
14
timer.h
Normal 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
190
tty.c
Normal 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
17
tty.h
Normal 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
23
user_space.c
Normal 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
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