Assignment 3 (only src and notes)

This commit is contained in:
Teodor
2026-04-14 16:04:17 +00:00
parent d3d8b973c0
commit ea416765bf
16 changed files with 531 additions and 47 deletions

View File

View 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
)

View File

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

View 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

View 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

View 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

View 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

View File

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

View File

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

View File

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

View 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

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

View File

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

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

View File

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