dead@root
This commit is contained in:
parent
23fe286eec
commit
0e5bd43f55
6
Makefile
6
Makefile
@ -9,9 +9,9 @@ GRUB_MKRESCUE = grub-mkrescue
|
||||
KERNEL = myos.bin
|
||||
ISO = myos.iso
|
||||
|
||||
SOURCES_C = kernel.c terminal.c idt.c timer.c io.c vga.c gdt.c
|
||||
SOURCES_ASM = boot.s idt_load.s gdt_flush.s pit_handler.s
|
||||
OBJECTS = $(SOURCES_C:.c=.o) $(SOURCES_ASM:.s=.o)
|
||||
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
|
||||
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
|
||||
|
@ -16,4 +16,4 @@ gdt_flush:
|
||||
jmp $0x08, $.flush
|
||||
|
||||
.flush:
|
||||
ret
|
||||
ret
|
||||
|
3
idt.h
3
idt.h
@ -3,12 +3,9 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
extern void idt_load();
|
||||
extern void pit_handler_asm();
|
||||
|
||||
void idt_install();
|
||||
void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags);
|
||||
void pic_remap(int offset1, int offset2);
|
||||
|
||||
#endif
|
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
|
9
io.c
9
io.c
@ -8,4 +8,11 @@ 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:" );
|
||||
}
|
||||
|
1
io.h
1
io.h
@ -5,5 +5,6 @@
|
||||
|
||||
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
|
31
kernel.c
31
kernel.c
@ -1,25 +1,40 @@
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "terminal.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"
|
||||
|
||||
void kernel_main(void) {
|
||||
void kernel_main(void)
|
||||
{
|
||||
terminal_initialize();
|
||||
gdt_install();
|
||||
|
||||
idt_install();
|
||||
pic_remap(0x20, 0x28);
|
||||
pit_set_frequency(1000);
|
||||
idt_set_gate(32, (uint32_t)pit_handler_asm, 0x08, 0x8E);
|
||||
asm volatile("sti");
|
||||
|
||||
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 < 30; i++) {
|
||||
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(1000);
|
||||
delay(500);
|
||||
}
|
||||
|
||||
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
|
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("&7root@dead: /> ");
|
||||
|
||||
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_printc(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
|
92
terminal.c
92
terminal.c
@ -1,92 +0,0 @@
|
||||
#include "terminal.h"
|
||||
#include "vga.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);
|
||||
}
|
||||
|
||||
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_putchar(char c) {
|
||||
if (c == '\n') {
|
||||
terminal_column = 0;
|
||||
if (++terminal_row == VGA_HEIGHT) {
|
||||
terminal_scroll();
|
||||
}
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
23
timer.c
23
timer.c
@ -1,5 +1,7 @@
|
||||
#include "timer.h"
|
||||
#include "io.h"
|
||||
#include "sys.h"
|
||||
#include "idt.h"
|
||||
|
||||
#define PIT_FREQUENCY 1193182
|
||||
#define PIT_CHANNEL_0 0x40
|
||||
@ -7,21 +9,32 @@
|
||||
|
||||
volatile uint32_t tick = 0;
|
||||
|
||||
void pit_handler() {
|
||||
void pit_handler()
|
||||
{
|
||||
tick++;
|
||||
outb(0x20, 0x20);
|
||||
}
|
||||
|
||||
void delay(uint32_t milliseconds) {
|
||||
void delay(uint32_t milliseconds)
|
||||
{
|
||||
uint32_t end = tick + milliseconds;
|
||||
while (tick < end) {
|
||||
asm volatile("hlt");
|
||||
while (tick < end)
|
||||
{
|
||||
sys_halt();
|
||||
}
|
||||
}
|
||||
|
||||
void pit_set_frequency(uint32_t frequency) {
|
||||
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);
|
||||
}
|
4
timer.h
4
timer.h
@ -3,8 +3,12 @@
|
||||
|
||||
#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();
|
||||
}
|
@ -8,8 +8,10 @@ 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_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
|
Loading…
Reference in New Issue
Block a user