Assignment 3 (only src and notes)
This commit is contained in:
0
notes/work-summary-2026-04-11-to-14.md
Normal file
0
notes/work-summary-2026-04-11-to-14.md
Normal file
@@ -63,6 +63,10 @@ add_executable(uiaos-kernel
|
||||
src/kernel.c
|
||||
src/gdt.c
|
||||
src/terminal.c
|
||||
src/idt.c
|
||||
src/interrupt.c
|
||||
src/interrupt.asm
|
||||
src/keyboard.c
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -8,19 +8,19 @@
|
||||
#define GDT_DATA_SELECTOR 0x10
|
||||
|
||||
struct GdtEntry {
|
||||
uint16_t limit_low;
|
||||
uint16_t base_low;
|
||||
uint8_t base_middle;
|
||||
uint8_t access;
|
||||
uint8_t granularity;
|
||||
uint8_t base_high;
|
||||
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 GdtDescriptor {
|
||||
uint16_t size;
|
||||
uint32_t offset;
|
||||
uint16_t size;
|
||||
uint32_t offset;
|
||||
} __attribute__((packed));
|
||||
|
||||
void gdtInitialize(void);
|
||||
void GdtInitialize(void);
|
||||
|
||||
#endif
|
||||
24
src/OSDev_18/include/kernel/idt.h
Normal file
24
src/OSDev_18/include/kernel/idt.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef KERNEL_IDT_H
|
||||
#define KERNEL_IDT_H
|
||||
|
||||
#include <libc/stdint.h>
|
||||
|
||||
#define IDT_ENTRIES 256
|
||||
|
||||
struct IdtEntry{
|
||||
uint16_t interrupt_low;
|
||||
uint16_t kernel_cs;
|
||||
uint8_t reserved;
|
||||
uint8_t attributes;
|
||||
uint16_t interrupt_high;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct Idtr {
|
||||
uint16_t limit;
|
||||
uint32_t base;
|
||||
} __attribute__((packed));
|
||||
|
||||
void IdtInitialize(void);
|
||||
void IdtSetDescriptor(uint8_t vector, uint32_t interrupt, uint8_t flags);
|
||||
|
||||
#endif
|
||||
54
src/OSDev_18/include/kernel/interrupt.h
Normal file
54
src/OSDev_18/include/kernel/interrupt.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef KERNEL_INTERRUPT_H
|
||||
#define KERNEL_INTERRUPT_H
|
||||
|
||||
#include <libc/stdint.h>
|
||||
|
||||
#define IRQ0 32
|
||||
#define IRQ1 33
|
||||
#define IRQ2 34
|
||||
#define IRQ3 35
|
||||
#define IRQ4 36
|
||||
#define IRQ5 37
|
||||
#define IRQ6 38
|
||||
#define IRQ7 39
|
||||
#define IRQ8 40
|
||||
#define IRQ9 41
|
||||
#define IRQ10 42
|
||||
#define IRQ11 43
|
||||
#define IRQ12 44
|
||||
#define IRQ13 45
|
||||
#define IRQ14 46
|
||||
#define IRQ15 47
|
||||
|
||||
struct Registers {
|
||||
uint32_t ds;
|
||||
|
||||
uint32_t edi;
|
||||
uint32_t esi;
|
||||
uint32_t ebp;
|
||||
uint32_t esp;
|
||||
uint32_t ebx;
|
||||
uint32_t edx;
|
||||
uint32_t ecx;
|
||||
uint32_t eax;
|
||||
|
||||
uint32_t int_no;
|
||||
uint32_t err_code;
|
||||
|
||||
uint32_t eip;
|
||||
uint32_t cs;
|
||||
uint32_t eflags;
|
||||
uint32_t useresp;
|
||||
uint32_t ss;
|
||||
};
|
||||
|
||||
void PicSendEoi(uint8_t irqNum);
|
||||
void PicRemap(void);
|
||||
|
||||
void IsrHandler(struct Registers* registers);
|
||||
void IrqHandler(struct Registers* registers);
|
||||
|
||||
typedef void (*InterruptHandler)(struct Registers* registers);
|
||||
void RegisterInterruptHandler(uint8_t iNum, InterruptHandler handler);
|
||||
|
||||
#endif
|
||||
20
src/OSDev_18/include/kernel/io.h
Normal file
20
src/OSDev_18/include/kernel/io.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef KERNEL_IO_H
|
||||
#define KERNEL_IO_H
|
||||
|
||||
#include <libc/stdint.h>
|
||||
|
||||
static inline void OutPortByte(uint16_t port, uint8_t val) {
|
||||
__asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port));
|
||||
}
|
||||
|
||||
static inline uint8_t InPortByte(uint16_t port) {
|
||||
uint8_t ret;
|
||||
__asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void IoWait(void) {
|
||||
__asm__ volatile ("outb %%al, $0x80" : : "a"(0));
|
||||
}
|
||||
|
||||
#endif
|
||||
11
src/OSDev_18/include/kernel/keyboard.h
Normal file
11
src/OSDev_18/include/kernel/keyboard.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef KERNEL_KEYBOARD_H
|
||||
#define KERNEL_KEYBOARD_H
|
||||
|
||||
#include <kernel/interrupt.h>
|
||||
|
||||
#define KEYBOARD_DATA_PORT 0x60
|
||||
#define KEYBOARD_BUFFER_SIZE 256
|
||||
|
||||
void KeyboardHandler(struct Registers* registers);
|
||||
|
||||
#endif
|
||||
@@ -23,14 +23,16 @@ enum vga_colour{
|
||||
VGA_COLOR_WHITE = 15,
|
||||
};
|
||||
|
||||
uint8_t vgaEntryColour(enum vga_colour fg, enum vga_colour bg);
|
||||
uint16_t vgaEntry(unsigned char uc, uint8_t color);
|
||||
uint8_t VgaEntryColour(enum vga_colour fg, enum vga_colour bg);
|
||||
uint16_t VgaEntry(unsigned char uc, uint8_t color);
|
||||
|
||||
void terminalEntryAt(char c, uint8_t colour, size_t x, size_t y);
|
||||
void terminalInitialize(void);
|
||||
void terminalSetColour(uint8_t colour);
|
||||
void terminalPutChar(char c);
|
||||
void terminalWrite(const char* data, size_t size);
|
||||
void terminalWriteString(const char* data);
|
||||
void TerminalEntryAt(char c, uint8_t colour, size_t x, size_t y);
|
||||
void TerminalInitialize(void);
|
||||
void TerminalSetColour(uint8_t colour);
|
||||
void TerminalUpdateCursor(void);
|
||||
void TerminalPutChar(char c);
|
||||
void TerminalWrite(const char* data, size_t size);
|
||||
void TerminalWriteString(const char* data);
|
||||
void TerminalWriteUInt(uint32_t num);
|
||||
|
||||
#endif
|
||||
@@ -1,12 +1,12 @@
|
||||
%define GDT_CODE_SELECTOR 0x08
|
||||
%define GDT_DATA_SELECTOR 0x10
|
||||
|
||||
global gdtFlush
|
||||
global GdtFlush
|
||||
|
||||
section .text
|
||||
bits 32
|
||||
|
||||
gdtFlush:
|
||||
GdtFlush:
|
||||
mov eax, [esp + 4]
|
||||
lgdt [eax]
|
||||
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
static struct GdtEntry gdtEntries[3];
|
||||
static struct GdtDescriptor gdtDescriptor;
|
||||
|
||||
extern void gdtFlush(uint32_t gdtDescriptorAddress);
|
||||
extern void GdtFlush(uint32_t gdtDescriptorAddress);
|
||||
|
||||
static void gdtSetEntry(
|
||||
static void GdtSetEntry(
|
||||
uint32_t index,
|
||||
uint32_t base,
|
||||
uint32_t limit,
|
||||
uint8_t access,
|
||||
uint8_t granularity
|
||||
uint8_t access,
|
||||
uint8_t granularity
|
||||
) {
|
||||
gdtEntries[index].base_low = (uint16_t)(base & 0xFFFF);
|
||||
gdtEntries[index].base_middle = (uint8_t)((base >> 16) & 0xFF);
|
||||
@@ -22,17 +22,17 @@ static void gdtSetEntry(
|
||||
gdtEntries[index].access = access;
|
||||
}
|
||||
|
||||
void gdtInitialize(void) {
|
||||
void GdtInitialize(void) {
|
||||
gdtDescriptor.size = sizeof(gdtEntries) - 1;
|
||||
gdtDescriptor.offset = (uint32_t)&gdtEntries;
|
||||
|
||||
gdtSetEntry(0, 0, 0, 0, 0);
|
||||
GdtSetEntry(0, 0, 0, 0, 0);
|
||||
|
||||
// Kernel code segment: base 0, 4 GiB span, ring 0, executable, readable
|
||||
gdtSetEntry(1, 0, 0x000FFFFF, 0x9A, 0xCF);
|
||||
GdtSetEntry(1, 0, 0x000FFFFF, 0x9A, 0xCF);
|
||||
|
||||
// Kernel data segment: base 0, 4 GiB span, ring 0, writable
|
||||
gdtSetEntry(2, 0, 0x000FFFFF, 0x92, 0xCF);
|
||||
GdtSetEntry(2, 0, 0x000FFFFF, 0x92, 0xCF);
|
||||
|
||||
gdtFlush((uint32_t)&gdtDescriptor);
|
||||
GdtFlush((uint32_t)&gdtDescriptor);
|
||||
}
|
||||
39
src/OSDev_18/src/idt.c
Normal file
39
src/OSDev_18/src/idt.c
Normal file
@@ -0,0 +1,39 @@
|
||||
#include <kernel/idt.h>
|
||||
#include <kernel/gdt.h>
|
||||
#include <kernel/interrupt.h>
|
||||
#include <libc/stdbool.h>
|
||||
|
||||
static struct IdtEntry idt[IDT_ENTRIES];
|
||||
static struct Idtr idtr;
|
||||
|
||||
void IdtSetDescriptor(uint8_t vector, uint32_t interrupt, uint8_t flags) {
|
||||
struct IdtEntry* descriptor = &idt[vector];
|
||||
|
||||
descriptor->interrupt_low = (uint32_t)interrupt & 0xFFFF;
|
||||
descriptor->kernel_cs = GDT_CODE_SELECTOR;
|
||||
descriptor->attributes = flags;
|
||||
descriptor->interrupt_high = (uint32_t)interrupt >> 16;
|
||||
descriptor->reserved = 0;
|
||||
}
|
||||
|
||||
extern void* isr_stub_table[];
|
||||
extern void* irq_stub_table[];
|
||||
|
||||
void IdtInitialize(void) {
|
||||
idtr.base = (uint32_t)&idt[0];
|
||||
idtr.limit = (uint16_t)sizeof(struct IdtEntry) * IDT_ENTRIES - 1;
|
||||
|
||||
for (uint8_t iNum = 0; iNum < 32; iNum++) {
|
||||
IdtSetDescriptor(iNum, (uint32_t)isr_stub_table[iNum], 0x8E);
|
||||
}
|
||||
|
||||
for (uint8_t iNum = 32; iNum < 48; iNum++) {
|
||||
IdtSetDescriptor(iNum, (uint32_t)irq_stub_table[iNum - 32], 0x8E);
|
||||
}
|
||||
|
||||
PicRemap();
|
||||
|
||||
__asm__ volatile ("lidt %0" : : "m"(idtr));
|
||||
__asm__ volatile ("sti");
|
||||
}
|
||||
|
||||
130
src/OSDev_18/src/interrupt.asm
Normal file
130
src/OSDev_18/src/interrupt.asm
Normal file
@@ -0,0 +1,130 @@
|
||||
extern IsrHandler
|
||||
extern IrqHandler
|
||||
|
||||
isr_common_stub:
|
||||
pusha
|
||||
mov ax, ds
|
||||
push eax
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
push esp
|
||||
call IsrHandler
|
||||
add esp, 4
|
||||
pop eax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
popa
|
||||
add esp, 8
|
||||
iret
|
||||
|
||||
irq_common_stub:
|
||||
pusha
|
||||
mov ax, ds
|
||||
push eax
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
push esp
|
||||
call IrqHandler
|
||||
add esp, 4
|
||||
pop eax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
popa
|
||||
add esp, 8
|
||||
iret
|
||||
|
||||
%macro isr_no_err_stub 1
|
||||
isr_stub_%+%1:
|
||||
push dword 0
|
||||
push dword %1
|
||||
jmp isr_common_stub
|
||||
%endmacro
|
||||
|
||||
%macro isr_err_stub 1
|
||||
isr_stub_%+%1:
|
||||
push dword %1
|
||||
jmp isr_common_stub
|
||||
%endmacro
|
||||
|
||||
%macro irq_stub 1
|
||||
irq_stub_%+%1:
|
||||
push dword 0
|
||||
push dword (32 + %1)
|
||||
jmp irq_common_stub
|
||||
%endmacro
|
||||
|
||||
isr_no_err_stub 0
|
||||
isr_no_err_stub 1
|
||||
isr_no_err_stub 2
|
||||
isr_no_err_stub 3
|
||||
isr_no_err_stub 4
|
||||
isr_no_err_stub 5
|
||||
isr_no_err_stub 6
|
||||
isr_no_err_stub 7
|
||||
isr_err_stub 8
|
||||
isr_no_err_stub 9
|
||||
isr_err_stub 10
|
||||
isr_err_stub 11
|
||||
isr_err_stub 12
|
||||
isr_err_stub 13
|
||||
isr_err_stub 14
|
||||
isr_no_err_stub 15
|
||||
isr_no_err_stub 16
|
||||
isr_err_stub 17
|
||||
isr_no_err_stub 18
|
||||
isr_no_err_stub 19
|
||||
isr_no_err_stub 20
|
||||
isr_no_err_stub 21
|
||||
isr_no_err_stub 22
|
||||
isr_no_err_stub 23
|
||||
isr_no_err_stub 24
|
||||
isr_no_err_stub 25
|
||||
isr_no_err_stub 26
|
||||
isr_no_err_stub 27
|
||||
isr_no_err_stub 28
|
||||
isr_no_err_stub 29
|
||||
isr_err_stub 30
|
||||
isr_no_err_stub 31
|
||||
|
||||
irq_stub 0
|
||||
irq_stub 1
|
||||
irq_stub 2
|
||||
irq_stub 3
|
||||
irq_stub 4
|
||||
irq_stub 5
|
||||
irq_stub 6
|
||||
irq_stub 7
|
||||
irq_stub 8
|
||||
irq_stub 9
|
||||
irq_stub 10
|
||||
irq_stub 11
|
||||
irq_stub 12
|
||||
irq_stub 13
|
||||
irq_stub 14
|
||||
irq_stub 15
|
||||
|
||||
global isr_stub_table
|
||||
isr_stub_table:
|
||||
%assign i 0
|
||||
%rep 32
|
||||
dd isr_stub_%+i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
global irq_stub_table
|
||||
irq_stub_table:
|
||||
%assign i 0
|
||||
%rep 16
|
||||
dd irq_stub_%+i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
114
src/OSDev_18/src/interrupt.c
Normal file
114
src/OSDev_18/src/interrupt.c
Normal file
@@ -0,0 +1,114 @@
|
||||
#include <kernel/interrupt.h>
|
||||
#include <kernel/terminal.h>
|
||||
#include <kernel/io.h>
|
||||
|
||||
#define PIC1_COMMAND 0x20
|
||||
#define PIC1_DATA 0x21
|
||||
#define PIC2_COMMAND 0xA0
|
||||
#define PIC2_DATA 0xA1
|
||||
#define PIC_EOI 0x20
|
||||
|
||||
static InterruptHandler interruptHandlers[256];
|
||||
|
||||
const char* isrMessages[] = {
|
||||
"Division By Zero",
|
||||
"Debug",
|
||||
"Non Maskable Interrupt",
|
||||
"Breakpoint",
|
||||
"Overflow",
|
||||
"Bound Range Exceeded",
|
||||
"Invalid Opcode",
|
||||
"Device Not Available",
|
||||
"Double Fault",
|
||||
"Coprocessor Segment Overrun",
|
||||
"Invalid TSS",
|
||||
"Segment Not Present",
|
||||
"Stack-Segment Fault",
|
||||
"General Protection Fault",
|
||||
"Page Fault",
|
||||
"Reserved",
|
||||
"x87 Floating-Point Exception",
|
||||
"Alignment Check",
|
||||
"Machine Check",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved"
|
||||
};
|
||||
|
||||
void PicSendEoi(uint8_t irqNum) {
|
||||
if (irqNum >= 8) {
|
||||
OutPortByte(PIC2_COMMAND, PIC_EOI);
|
||||
}
|
||||
OutPortByte(PIC1_COMMAND, PIC_EOI);
|
||||
}
|
||||
|
||||
void PicRemap(void) {
|
||||
OutPortByte(PIC1_COMMAND, 0x11);
|
||||
OutPortByte(PIC2_COMMAND, 0x11);
|
||||
|
||||
OutPortByte(PIC1_DATA, 0x20);
|
||||
OutPortByte(PIC2_DATA, 0x28);
|
||||
|
||||
OutPortByte(PIC1_DATA, 0x04);
|
||||
OutPortByte(PIC2_DATA, 0x02);
|
||||
|
||||
OutPortByte(PIC1_DATA, 0x01);
|
||||
OutPortByte(PIC2_DATA, 0x01);
|
||||
|
||||
OutPortByte(PIC1_DATA, 0x00);
|
||||
OutPortByte(PIC2_DATA, 0x00);
|
||||
}
|
||||
|
||||
void IsrHandler(struct Registers* registers) {
|
||||
TerminalWriteString("\n=== INTERRUPT RECEIVED ===\n");
|
||||
|
||||
TerminalWriteString("Interrupt Number: ");
|
||||
TerminalWriteUInt(registers->int_no);
|
||||
TerminalWriteString("\n");
|
||||
|
||||
TerminalWriteString("Message: ");
|
||||
if (registers->int_no < 32) {
|
||||
TerminalWriteString(isrMessages[registers->int_no]);
|
||||
} else {
|
||||
TerminalWriteString("Unknown Interrupt");
|
||||
}
|
||||
TerminalWriteString("\n");
|
||||
|
||||
TerminalWriteString("Error Code: ");
|
||||
TerminalWriteUInt(registers->err_code);
|
||||
TerminalWriteString("\n");
|
||||
|
||||
TerminalWriteString("==========================\n");
|
||||
|
||||
for (;;) {
|
||||
__asm__ volatile("cli; hlt");
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterInterruptHandler(uint8_t iNum, InterruptHandler handler) {
|
||||
interruptHandlers[iNum] = handler;
|
||||
}
|
||||
|
||||
void IrqHandler(struct Registers* registers) {
|
||||
uint8_t irqNum = (uint8_t)(registers->int_no - 32);
|
||||
|
||||
if (interruptHandlers[registers->int_no] != 0) {
|
||||
interruptHandlers[registers->int_no](registers);
|
||||
} else if (irqNum != 0) {
|
||||
TerminalWriteString("IRQ triggered: ");
|
||||
TerminalWriteUInt(irqNum);
|
||||
TerminalWriteString("\n");
|
||||
}
|
||||
|
||||
PicSendEoi(irqNum);
|
||||
}
|
||||
@@ -1,14 +1,18 @@
|
||||
#include <libc/stdint.h>
|
||||
#include <kernel/terminal.h>
|
||||
#include <kernel/gdt.h>
|
||||
#include <kernel/idt.h>
|
||||
#include <kernel/interrupt.h>
|
||||
#include <kernel/keyboard.h>
|
||||
|
||||
void main(void) {
|
||||
gdtInitialize();
|
||||
TerminalInitialize();
|
||||
GdtInitialize();
|
||||
IdtInitialize();
|
||||
|
||||
RegisterInterruptHandler(IRQ1, KeyboardHandler);
|
||||
|
||||
terminalInitialize();
|
||||
terminalWriteString("Hello, World!\n");
|
||||
|
||||
for (;;) {
|
||||
__asm__ volatile ("hlt");
|
||||
__asm__ volatile("hlt");
|
||||
}
|
||||
}
|
||||
43
src/OSDev_18/src/keyboard.c
Normal file
43
src/OSDev_18/src/keyboard.c
Normal file
@@ -0,0 +1,43 @@
|
||||
#include <kernel/keyboard.h>
|
||||
#include <kernel/interrupt.h>
|
||||
#include <kernel/io.h>
|
||||
#include <kernel/terminal.h>
|
||||
#include <libc/stdint.h>
|
||||
|
||||
static uint32_t index = 0;
|
||||
static uint8_t keyboardBuffer[KEYBOARD_BUFFER_SIZE];
|
||||
|
||||
static const char scancodeToAscii[128] = {
|
||||
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
|
||||
'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
|
||||
0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
|
||||
0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0,
|
||||
'*', 0, ' ', 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, '7', '8', '9', '-', '4', '5', '6', '+',
|
||||
'1', '2', '3', '0', '.',
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
void KeyboardHandler(struct Registers* registers) {
|
||||
(void) registers;
|
||||
|
||||
uint8_t scancode = InPortByte(KEYBOARD_DATA_PORT);
|
||||
|
||||
if (index < KEYBOARD_BUFFER_SIZE) {
|
||||
keyboardBuffer[index] = scancode;
|
||||
index++;
|
||||
}
|
||||
|
||||
if (scancode & 0x80) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (scancode < 128) {
|
||||
char ascii = scancodeToAscii[scancode];
|
||||
|
||||
if (ascii != 0) {
|
||||
TerminalPutChar(ascii);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <kernel/gdt.h>
|
||||
#include <kernel/terminal.h>
|
||||
#include <kernel/io.h>
|
||||
|
||||
const size_t VGA_HEIGHT = 25;
|
||||
const size_t VGA_WIDTH = 80;
|
||||
@@ -11,44 +12,55 @@ static uint8_t terminal_colour;
|
||||
static uint16_t* terminal_buffer = (uint16_t*) 0xB8000;
|
||||
|
||||
// Builds the colour byte
|
||||
uint8_t vgaEntryColour(enum vga_colour fg, enum vga_colour bg) {
|
||||
uint8_t VgaEntryColour(enum vga_colour fg, enum vga_colour bg) {
|
||||
return fg | bg << 4;
|
||||
}
|
||||
|
||||
// Builds the full cell
|
||||
uint16_t vgaEntry(unsigned char uc, uint8_t color) {
|
||||
uint16_t VgaEntry(unsigned char uc, uint8_t color) {
|
||||
return (uint16_t) uc | (uint16_t) color << 8;
|
||||
}
|
||||
|
||||
void terminalEntryAt(char c, uint8_t colour, size_t x, size_t y){
|
||||
void TerminalEntryAt(char c, uint8_t colour, size_t x, size_t y){
|
||||
size_t index = y * VGA_WIDTH + x;
|
||||
terminal_buffer[index] = vgaEntry(c, colour);
|
||||
terminal_buffer[index] = VgaEntry(c, colour);
|
||||
}
|
||||
|
||||
void terminalInitialize(void) {
|
||||
void TerminalInitialize(void) {
|
||||
terminal_row = 0;
|
||||
terminal_column = 0;
|
||||
terminal_colour = vgaEntryColour(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
|
||||
terminal_colour = VgaEntryColour(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++) {
|
||||
terminalEntryAt(' ', terminal_colour, x, y);
|
||||
TerminalEntryAt(' ', terminal_colour, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void terminalSetColour(uint8_t colour) {
|
||||
void TerminalSetColour(uint8_t colour) {
|
||||
terminal_colour = colour;
|
||||
}
|
||||
|
||||
void terminalPutChar(char c) {
|
||||
void TerminalUpdateCursor(void) {
|
||||
uint16_t pos = (uint16_t)(terminal_row * VGA_WIDTH + terminal_column);
|
||||
|
||||
OutPortByte(0x3D4, 0x0F);
|
||||
OutPortByte(0x3D5, (uint8_t)(pos & 0xFF));
|
||||
|
||||
OutPortByte(0x3D4, 0x0E);
|
||||
OutPortByte(0x3D5, (uint8_t)((pos >> 8) & 0xFF));
|
||||
}
|
||||
|
||||
void TerminalPutChar(char c) {
|
||||
if (c == '\n') {
|
||||
terminal_column = 0;
|
||||
terminal_row++;
|
||||
TerminalUpdateCursor();
|
||||
return;
|
||||
}
|
||||
terminalEntryAt(c, terminal_colour,terminal_column, terminal_row);
|
||||
TerminalEntryAt(c, terminal_colour,terminal_column, terminal_row);
|
||||
terminal_column++;
|
||||
|
||||
if (terminal_column == VGA_WIDTH) {
|
||||
@@ -59,21 +71,48 @@ void terminalPutChar(char c) {
|
||||
if (terminal_row == VGA_HEIGHT) {
|
||||
terminal_row = 0;
|
||||
}
|
||||
|
||||
TerminalUpdateCursor();
|
||||
}
|
||||
|
||||
void terminalWrite(const char* data, size_t size) {
|
||||
void TerminalWrite(const char* data, size_t size) {
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
terminalPutChar(data[i]);
|
||||
TerminalPutChar(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void terminalWriteString(const char* data) {
|
||||
void TerminalWriteString(const char* data) {
|
||||
size_t len = 0;
|
||||
|
||||
while (data[len] != '\0') {
|
||||
len++;
|
||||
}
|
||||
|
||||
terminalWrite(data, len);
|
||||
TerminalWrite(data, len);
|
||||
}
|
||||
|
||||
void TerminalWriteUInt(uint32_t num) {
|
||||
if (num == 0) {
|
||||
TerminalPutChar('0');
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[10];
|
||||
size_t i = 0;
|
||||
|
||||
while (num > 0) {
|
||||
buffer[i++] = '0' + (num % 10);
|
||||
num /= 10;
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < i / 2; j++) {
|
||||
char temp = buffer[j];
|
||||
buffer[j] = buffer[i - j - 1];
|
||||
buffer[i - j - 1] = temp;
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < i; j++) {
|
||||
TerminalPutChar(buffer[j]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user