From 95d32f025acfe533065809abecae63c92e570407 Mon Sep 17 00:00:00 2001 From: Tom-on64 Date: Wed, 9 Oct 2024 16:45:37 +0200 Subject: [PATCH] Implemented a proper libk --- Makefile | 32 ++++-- include/disk/disk.h | 51 +-------- include/error/bigerr.h | 56 +--------- include/fs/impl.h | 40 ++----- include/interrupt/exceptions.h | 47 +------- include/interrupt/idt.h | 23 +--- include/interrupt/pic.h | 81 +------------- include/interrupt/pit.h | 40 +------ include/interrupt/rtc.h | 141 +---------------------- include/interrupt/syscalls.h | 198 +-------------------------------- include/keyboard/keyboard.h | 31 +----- include/keyboard/keys.h | 40 ++++--- include/memory/addresses.h | 4 +- include/memory/malloc.h | 115 ++----------------- include/memory/physical.h | 126 ++------------------- include/memory/virtual.h | 158 ++------------------------ include/ports/io.h | 29 +---- include/screen/gfxmode.h | 16 +-- include/screen/graphics.h | 147 ++---------------------- include/screen/text.h | 90 +-------------- include/sound/pcspk.h | 28 +---- include/terminal/terminal.h | 127 +-------------------- kern.iso | Bin 1470464 -> 1470464 bytes libk/disk/disk.c | 53 +++++++++ libk/error/bigerr.c | 58 ++++++++++ libk/fs/impl.c | 63 +++++++++++ libk/interrupt/exceptions.c | 48 ++++++++ libk/interrupt/idt.c | 25 +++++ libk/interrupt/pic.c | 79 +++++++++++++ libk/interrupt/pit.c | 43 +++++++ libk/interrupt/rtc.c | 140 +++++++++++++++++++++++ libk/interrupt/syscalls.c | 194 ++++++++++++++++++++++++++++++++ libk/keyboard/keyboard.c | 36 ++++++ libk/memory/malloc.c | 114 +++++++++++++++++++ libk/memory/physical.c | 122 ++++++++++++++++++++ libk/memory/virtual.c | 153 +++++++++++++++++++++++++ libk/ports/io.c | 29 +++++ libk/screen/gfxmode.c | 20 ++++ libk/screen/graphics.c | 143 ++++++++++++++++++++++++ libk/screen/text.c | 91 +++++++++++++++ libk/sound/pcspk.c | 27 +++++ libk/terminal/terminal.c | 129 +++++++++++++++++++++ makedisk.c | 4 +- src/kernel.c | 32 +----- src/stage3.c | 14 +-- 45 files changed, 1713 insertions(+), 1524 deletions(-) create mode 100644 libk/disk/disk.c create mode 100644 libk/error/bigerr.c create mode 100644 libk/fs/impl.c create mode 100644 libk/interrupt/exceptions.c create mode 100644 libk/interrupt/idt.c create mode 100644 libk/interrupt/pic.c create mode 100644 libk/interrupt/pit.c create mode 100644 libk/interrupt/rtc.c create mode 100644 libk/interrupt/syscalls.c create mode 100644 libk/keyboard/keyboard.c create mode 100644 libk/memory/malloc.c create mode 100644 libk/memory/physical.c create mode 100644 libk/memory/virtual.c create mode 100644 libk/ports/io.c create mode 100644 libk/screen/gfxmode.c create mode 100644 libk/screen/graphics.c create mode 100644 libk/screen/text.c create mode 100644 libk/sound/pcspk.c create mode 100644 libk/terminal/terminal.c diff --git a/Makefile b/Makefile index c71d52a..e488f9f 100644 --- a/Makefile +++ b/Makefile @@ -16,14 +16,14 @@ LIBK_INC := ./include LIBC_INC := ./include/libc LIBC_DIR := ./libc LIBK_DIR := ./libk +LIBK_SRC := $(shell find $(LIBK_DIR) -type f -name "**.c") -C_FILES := calc edit FONTS := testfont term16n BOOTLOADER := $(BIN)/stage1.bin $(BIN)/stage2.bin $(BIN)/stage3.bin KERNEL := $(BIN)/kernel.bin LIBC := $(BIN)/libc.o -# TODO: LIBK := $(BIN)/libk.o +LIBK := $(BIN)/libk.o ISO := kern.iso .PHONY: os clean run @@ -40,36 +40,44 @@ $(BIN): rm -rf $(BIN)/* # Bootloader: This target is responsible for creating stage?.bin (1,2,3) -$(BOOTLOADER): $(SRC)/stage1.asm $(SRC)/stage2.asm $(SRC)/stage3.c $(LIBC) +$(BOOTLOADER): $(SRC)/stage1.asm $(SRC)/stage2.asm $(SRC)/stage3.c $(LIBC) $(LIBK) @echo "Assembling $(SRC)/stage1.asm..." $(AS) -fbin -o $(BIN)/stage1.bin $(SRC)/stage1.asm $(ASFLAGS) @echo "Assembling $(SRC)/stage2.asm..." $(AS) -fbin -o $(BIN)/stage2.bin $(SRC)/stage2.asm $(ASFLAGS) @echo "Compiling $(SRC)/stage3.c..." $(CC) $(CCFLAGS) -I$(LIBK_INC) -I$(LIBC_INC) -o $(BIN)/stage3.o -c $(SRC)/stage3.c - $(LD) $(LDFLAGS) -T$(SRC)/stage3.ld --oformat binary -o $(BIN)/stage3.bin $(BIN)/stage3.o $(LIBC) + $(LD) $(LDFLAGS) -T$(SRC)/stage3.ld --oformat binary -o $(BIN)/stage3.bin $(BIN)/stage3.o $(LIBC) $(LIBK) rm $(BIN)/stage3.o # Kernel: This target is responsible for creating kernel.bin $(KERNEL): $(SRC)/kernel.c $(LIBC) #TODO: $(LIBK) @echo "Compiling $(SRC)/kernel.c..." $(CC) $(CCFLAGS) -I$(LIBK_INC) -I$(LIBC_INC) -o $(BIN)/kernel.o -c $(SRC)/kernel.c - $(LD) $(LDFLAGS) -T$(SRC)/kernel.ld --oformat binary -o $(BIN)/kernel.bin $(BIN)/kernel.o $(LIBC) #TODO: LIBK + $(LD) $(LDFLAGS) -T$(SRC)/kernel.ld --oformat binary -o $(BIN)/kernel.bin $(BIN)/kernel.o $(LIBC) $(LIBK) rm $(BIN)/kernel.o -# This target compiles *.c (except kernel.c) -$(C_FILES): $(LIBC) - @echo "Compiling $(SRC)/$@.c..." - $(CC) $(CCFLAGS) -I$(LIBC_INC) -o $(BIN)/$@.o -c $(SRC)/$@.c - $(LD) $(LDFLAGS) -T$(SRC)/$@.ld --oformat binary -o $(BIN)/$@.bin $(BIN)/$@.o $(LIBC) - rm $(BIN)/$@.o +# TODO: user programs $(LIBC): $(LIBC_DIR)/**.c @echo "Compiling $(LIBC)..." mkdir -p $(BIN)/libc - for f in libc/*.c; do $(CC) $(CCFLAGS) -I$(LIBC_INC) -o $(BIN)/$$f.o -c $$f; done + for f in libc/*.c; do\ + filename=$$(basename $$f .c);\ + $(CC) $(CCFLAGS) -I$(LIBC_INC) -o $(BIN)/libc/$$filename.o -c $$f;\ + done $(LD) $(LDFLAGS) -r -o $(LIBC) $(BIN)/libc/**.o +$(LIBK): $(LIBK_SRC) + @echo "Compiling $(LIBK)..." + mkdir -p $(BIN)/libk + for f in $(LIBK_SRC); do\ + filename=$$(basename $$f .c);\ + $(CC) $(CCFLAGS) -I$(LIBC_INC) -I$(LIBK_INC) -o $(BIN)/libk/$$filename.o -c $$f;\ + done + $(LD) $(LDFLAGS) -r -o $@ $(BIN)/libk/**.o + + # This target retrieves all fonts inside src/fonts $(FONTS): cp $(SRC)/fonts/$@.fnt $(BIN)/$@.fnt diff --git a/include/disk/disk.h b/include/disk/disk.h index 096b9bc..dc35039 100644 --- a/include/disk/disk.h +++ b/include/disk/disk.h @@ -2,60 +2,13 @@ #define DISK_DISK_H #include -#include #define PIO_PORT 0x1f0 #define READ_COMMAND 0x20 #define WRITE_COMMAND 0x30 #define CACHE_FLUSH 0xE7 -void diskRead(uint32_t lbaAddress, uint8_t sectorCount, char* dst) { - outb(PIO_PORT + 6, ((lbaAddress >> 24) & 0x0f) | 0xe0); // 6 - Use LBA; 4 - Drive number; 3-0 - Highest lba address nibble - outb(PIO_PORT + 2, sectorCount); // Sector count register - outb(PIO_PORT + 3, (uint8_t)(lbaAddress)); // Lowest lba address byte - outb(PIO_PORT + 4, (uint8_t)(lbaAddress >> 8)); // Middle lba address byte - outb(PIO_PORT + 5, (uint8_t)(lbaAddress >> 16)); // High lba address byte - outb(PIO_PORT + 7, READ_COMMAND); // Command register - - uint16_t* address = (uint16_t*)dst; - - for (uint8_t i = sectorCount; i > 0; i--) { - while (inb(PIO_PORT + 7) & (1 << 7)); // Poll status register untill BSY bit is clear - - for (size_t j = 0; j < 256; j++) { - *address++ = inw(PIO_PORT); // Read 256 words (512 Bytes = 1 Sector) - } - - for (uint8_t delay = 0; delay < 4; delay++) { // 400ns delay - inb(0x3f6); // Alternate status register - } - } -} - -void diskWrite(uint32_t lbaAddress, uint8_t sectorCount, char* src) { - outb(PIO_PORT + 6, ((lbaAddress >> 24) & 0x0f) | 0xe0); // 6 - Use LBA; 4 - Drive number; 3-0 - Highest lba address nibble - outb(PIO_PORT + 2, sectorCount); // Sector count register - outb(PIO_PORT + 3, (uint8_t)(lbaAddress)); // Lowest lba address byte - outb(PIO_PORT + 4, (uint8_t)(lbaAddress >> 8)); // Middle lba address byte - outb(PIO_PORT + 5, (uint8_t)(lbaAddress >> 16)); // High lba address byte - outb(PIO_PORT + 7, WRITE_COMMAND); // Command register - - uint16_t* address = (uint16_t*)src; - - for (uint8_t i = sectorCount; i > 0; i--) { - while (inb(PIO_PORT + 7) & (1 << 7)); // Poll status register untill BSY bit is clear - - for (size_t j = 0; j < 256; j++) { - outw(PIO_PORT, *address++); // Write 256 words (512 Bytes = 1 Sector) - } - - for (uint8_t delay = 0; delay < 4; delay++) { // 400ns delay - inb(0x3f6); // Alternate status register - } - } - - outb(PIO_PORT + 7, CACHE_FLUSH); // Cache flush - while (inb(PIO_PORT + 7) & (1 << 7)); // Poll status register untill BSY bit is clear -} +void diskRead(uint32_t lbaAddress, uint8_t sectorCount, char* dst); +void diskWrite(uint32_t lbaAddress, uint8_t sectorCount, char* src); #endif diff --git a/include/error/bigerr.h b/include/error/bigerr.h index 56b5434..ef390c5 100644 --- a/include/error/bigerr.h +++ b/include/error/bigerr.h @@ -7,60 +7,8 @@ */ #include -#include -void rect(uint32_t c, uint16_t x, uint16_t y, uint16_t w, uint16_t h) { - uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr; - uint8_t bytesPerPx = gfxMode->bpp / 8; - uint32_t convColor = convertColor(c); - - for (uint32_t dx = 0; dx < w; dx++) { - for (uint32_t dy = 0; dy < h; dy++) { - uint32_t offset = (((y + dy) * gfxMode->xRes) + (x + dx)) * bytesPerPx; - - for (uint8_t i = 0; i < gfxMode->bpp; i++) { - vidmem[offset + i] = (uint8_t)(convColor >> (i*8)); - } - } - } -} - -void bigError(uint32_t err) { - // Red BG - rect(0x00ff0000, 0, 0, gfxMode->xRes, gfxMode->yRes); - // E - rect(0x00ffffff, 20, 10, 10, 50); - rect(0x00ffffff, 30, 10, 30, 10); - rect(0x00ffffff, 30, 30, 30, 10); - rect(0x00ffffff, 30, 50, 30, 10); - // R - rect(0x00ffffff, 70, 10, 10, 50); - rect(0x00ffffff, 70, 10, 30, 10); - rect(0x00ffffff, 70, 30, 30, 10); - rect(0x00ffffff, 90, 10, 10, 30); - rect(0x00ffffff, 80, 40, 10, 10); - rect(0x00ffffff, 90, 50, 10, 10); - // R - rect(0x00ffffff, 110, 10, 10, 50); - rect(0x00ffffff, 110, 10, 30, 10); - rect(0x00ffffff, 110, 30, 30, 10); - rect(0x00ffffff, 130, 10, 10, 30); - rect(0x00ffffff, 120, 40, 10, 10); - rect(0x00ffffff, 130, 50, 10, 10); - // O - rect(0x00ffffff, 150, 10, 10, 50); - rect(0x00ffffff, 170, 10, 10, 50); - rect(0x00ffffff, 150, 10, 30, 10); - rect(0x00ffffff, 150, 50, 30, 10); - // R - rect(0x00ffffff, 190, 10, 10, 50); - rect(0x00ffffff, 190, 10, 30, 10); - rect(0x00ffffff, 190, 30, 30, 10); - rect(0x00ffffff, 210, 10, 10, 30); - rect(0x00ffffff, 200, 40, 10, 10); - rect(0x00ffffff, 210, 50, 10, 10); - - __asm__ volatile ("cli; hlt" :: "a"(err)); -} +void rect(uint32_t c, uint16_t x, uint16_t y, uint16_t w, uint16_t h); +void bigError(uint32_t err); #endif diff --git a/include/fs/impl.h b/include/fs/impl.h index 48adabf..c7d07c0 100644 --- a/include/fs/impl.h +++ b/include/fs/impl.h @@ -2,42 +2,20 @@ #define FS_IMPL_H #include -#include -#include #include +#include #define MAX_OPEN_FILES 256 -superblock_t* impl_superblock = (superblock_t*)SUPERBLOCK_LOC; +typedef struct { + FILE* openFileTable; + uint32_t openFiles; +} fsInfo_t; -inode_t* getInode(char* path, dirEntry_t* dentries) { - while (dentries->name[0] != '\0') { - if (strcmp(dentries->name, path) == 0) break; - dentries++; - } - if (dentries->name[0] == '\0') { return NULL; } +extern superblock_t* impl_superblock; +extern fsInfo_t* fsInfo; - inode_t* inode = (inode_t*)BOOT_FIRST_INODE_LOC + dentries->id; - - return inode; -} - -uint8_t loadFile(inode_t* inode, void* dest) { - uint32_t totalBlocks = BYTES2BLOCKS(inode->sizeBytes); - uint32_t offset = 0; - - for (uint8_t i = 0; i < 4 && totalBlocks > 0; i++) { - diskRead(inode->extent[i].block * 8, inode->extent[i].length * 8, dest + offset); - offset += inode->extent[i].length * FS_BLOCK_SIZE; - totalBlocks -= inode->extent[i].length; - } - - if (totalBlocks > 0) { - // TODO: Indirect extents - return 1; - } - - return 0; -} +inode_t* getInode(char* path, dirEntry_t* dentries); +uint8_t loadFile(inode_t* inode, void* dest); #endif diff --git a/include/interrupt/exceptions.h b/include/interrupt/exceptions.h index 24a73d9..a5ea882 100644 --- a/include/interrupt/exceptions.h +++ b/include/interrupt/exceptions.h @@ -1,51 +1,6 @@ #ifndef INTERRUPT_EXCEPTIONS_H #define INTERRUPT_EXCEPTIONS_H -#include -#include - -// Exception handlers -__attribute__ ((interrupt)) -void excp_divideErr(intFrame_t* iframe) { // ISR 0 - printf("\x1b[1M[ Division Error ]\n\x1b[8M"); - iframe->eip++; -} - -__attribute__ ((interrupt)) -void excp_doubleFault(intFrame_t* iframe, uint32_t errCode) { // ISR 8 - printf("\x1b[1M[ Double Fault ]\n\x1b[8M"); // Error code should be 0 (TODO: Maybe check if it's != 0?) - __asm__ volatile ("cli; hlt"); -} - -__attribute__ ((interrupt)) -void excp_pageFault(intFrame_t* iframe, uint32_t errCode) { // ISR 14 - uint32_t badAddress = 0; - - // cr2 should contain invalid address - __asm__ volatile("movl %%cr2, %0" : "=r"(badAddress)); - - printf("\x1b[1M[ Page Fault : 0x%x ] - Tried to access 0x%x.\n\x1b[8M", errCode, badAddress); - __asm__ volatile ("cli; hlt"); -} - -__attribute__ ((interrupt)) -void excp_reserved(intFrame_t* iframe) { // ISR 15 - print("\x1b[1M[ Unknown Exception ]\n\x1b[8M"); - __asm__ volatile ("cli; hlt"); -} - -// TODO: Add more (because there's always more) - -// Repetative isr definitions -void setupExceptions() { - for (uint8_t i = 0; i < 32; i++) { - idtSetGate(i, excp_reserved, TRAP_GATE_FLAGS); // Doesn't account for err codes, will just halt anyways - } - - idtSetGate(0, excp_divideErr, TRAP_GATE_FLAGS); - idtSetGate(8, excp_doubleFault, TRAP_GATE_FLAGS); - idtSetGate(14, excp_pageFault, TRAP_GATE_FLAGS); - idtSetGate(15, excp_reserved, TRAP_GATE_FLAGS); -} +void setupExceptions(); #endif diff --git a/include/interrupt/idt.h b/include/interrupt/idt.h index f7c886d..49c291f 100644 --- a/include/interrupt/idt.h +++ b/include/interrupt/idt.h @@ -28,27 +28,8 @@ typedef struct { uint32_t ss; } __attribute__ ((packed)) intFrame_t; -__attribute__ ((aligned(0x10))) // For performance -idtEntry_t idt[256] = { 0 }; -idtp_t idtp; - -void idtSetGate(uint8_t i, void* handler, uint8_t flags) { - uint32_t offset = (uint32_t)handler; - idtEntry_t* entry = &idt[i]; - - entry->offsetLow = (uint16_t)offset; - entry->selector = 0x08; - entry->zero = 0; - entry->typeAttr = flags; - entry->offsetHigh = (uint16_t)(offset >> 16); -} - -void setupIdt() { - idtp.limit = sizeof(idtEntry_t) * 256; - idtp.base = (uint32_t)&idt; - - __asm__ volatile ("lidt %0" : : "m"(idtp)); -} +void idtSetGate(uint8_t i, void* handler, uint8_t flags); +void setupIdt(); #endif diff --git a/include/interrupt/pic.h b/include/interrupt/pic.h index 31d743a..2bb4276 100644 --- a/include/interrupt/pic.h +++ b/include/interrupt/pic.h @@ -1,7 +1,7 @@ #ifndef INTERRUPT_PIC_H #define INTERRUPT_PIC_H -#include +#include // PIC I/O Ports #define PIC_1_CMD 0x20 @@ -17,79 +17,10 @@ #define PIC_EOI 0x20 // End Of Interrupt #define PIC_DISABLE 0xff -void sendPicEOI(uint8_t irq) { - if (irq >= 8) { - outb(PIC_2_CMD, PIC_EOI); - } - outb(PIC_1_CMD, PIC_EOI); -} - -void disableIrqs() { - outb(PIC_2_DATA, PIC_DISABLE); - outb(PIC_1_DATA, PIC_DISABLE); -} - -void setIrqMask(uint8_t irq) { - uint16_t port; - uint8_t value; - - if (irq < 8) { - port = PIC_1_DATA; - } else { - irq -= 8; - port = PIC_2_DATA; - } - - value = inb(port) | (1 << irq); - outb(port, value); -} - -void unsetIrqMask(uint8_t irq) { - uint16_t port; - uint8_t value; - - if (irq < 8) { - port = PIC_1_DATA; - } else { - irq -= 8; - port = PIC_2_DATA; - } - - value = inb(port) & ~(1 << irq); - outb(port, value); -} - -void remapPic() { - uint8_t pic1Mask = inb(PIC_1_DATA); - uint8_t pic2Mask = inb(PIC_2_DATA); - - // Send Init Control Word 1-4 to both PICs - // ICW 1: bit 0 - send up to 4 ICWs, bit 4 - Init PIC - outb(PIC_1_CMD, 0x11); - ioWait(); // For slower machines - outb(PIC_2_CMD, 0x11); - ioWait(); - - // ICW 2: Where to map IRW bases in IDT - outb(PIC_1_DATA, NEW_IRQ_0); - ioWait(); - outb(PIC_2_DATA, NEW_IRQ_8); - ioWait(); - - // ICW 3: Which IRQ in PIC1 is PIC2; Mapping PIC2 to IRQ 2 - outb(PIC_1_DATA, 0x04); - ioWait(); - outb(PIC_2_DATA, 0x02); - ioWait(); - - // ICW 4 - Set x86 mode - outb(PIC_1_DATA, 0x01); - ioWait(); - outb(PIC_2_DATA, 0x01); - ioWait(); - - outb(PIC_1_DATA, pic1Mask); - outb(PIC_2_DATA, pic2Mask); -} +void sendPicEOI(uint8_t irq); +void disableIrqs(); +void setIrqMask(uint8_t irq); +void unsetIrqMask(uint8_t irq); +void remapPic(); #endif diff --git a/include/interrupt/pit.h b/include/interrupt/pit.h index f993c4d..e210205 100644 --- a/include/interrupt/pit.h +++ b/include/interrupt/pit.h @@ -1,49 +1,13 @@ #ifndef INTERRUPT_PIT_H #define INTERRUPT_PIT_H -#include -#include -#include -#include #include #define CHANNEL_0 0x40 // Offset it by 1 or 2 for ch1 and ch2 #define COMMAND 0x43 #define INPUT_CLK 1193182 -__attribute__ ((interrupt)) -void timerHandler(intFrame_t* iframe) { - static uint32_t cursorTicks = 0; - cursorTicks++; - - if (!terminal->hideCursor) { // TODO: Make a better cursor drawing thing - if (cursorTicks % 500 == 0) toggleCursor(); - } - - if (*(uint32_t*)SLEEP_TIMER > 0) { --(*(uint32_t*)SLEEP_TIMER); } - - sendPicEOI(0); -} - -void setPitPhase(uint8_t channel, uint8_t opMode, uint16_t hz) { - if (channel > 2 || opMode > 7) { return; } - __asm__ volatile ("cli"); - - // Send command - bits 7-6 channel, 5-4 Access mode, 3-1 operating mode, 0 - Should be zero in x86 - outb(COMMAND, ((channel << 6) | (3 << 4) | (opMode << 1))); - - // Send frequency - uint16_t freq = INPUT_CLK / hz; // I solved an equation to figure this out - outb(CHANNEL_0 + channel, (uint8_t)freq); - outb(CHANNEL_0 + channel, (uint8_t)(freq >> 8)); - - __asm__ volatile ("sti"); -} - -void setupTimer() { // Sets up IRQ 0 - PIT - idtSetGate(0x20, timerHandler, INT_GATE_FLAGS); - unsetIrqMask(0); - setPitPhase(0, 2, 1000); // Default setup: 1000Hz - 1 tick per 1ms -} +void setPitPhase(uint8_t channel, uint8_t opMode, uint16_t hz); +void setupTimer(); #endif diff --git a/include/interrupt/rtc.h b/include/interrupt/rtc.h index 3714088..e9d452f 100644 --- a/include/interrupt/rtc.h +++ b/include/interrupt/rtc.h @@ -1,13 +1,8 @@ #ifndef INTERRUPT_RTC_H #define INTERRUPT_RTC_H -#include -#include -#include -#include -#include +#include #include -#include #define CMOS_ADDRESS 0x70 #define CMOS_DATA 0x71 @@ -21,134 +16,10 @@ typedef struct { uint16_t year; } __attribute__ ((packed)) datetime_t; -static datetime_t* datetime = (datetime_t*)DATETIME_LOC; - -bool cmosUpdateProgress() { - outb(CMOS_ADDRESS, 0x8a); // Read status reg A, disable NMI - return inb(CMOS_DATA) & 0x80; -} - -uint8_t getRtcRegister(uint8_t reg) { - outb(CMOS_ADDRESS, reg | 0x80); // Disable NMI when sending - return inb(CMOS_DATA); -} - -void enableRtc() { - uint8_t regB = getRtcRegister(0x0b); - outb(CMOS_ADDRESS, 0x8b); - outb(CMOS_DATA, regB | 0x40); // Set bit 6 - periodic int at 1024Hz - - getRtcRegister(0x0c); // Clear pending interrupts -} - -void disableRtc() { - __asm__ volatile ("cli"); - uint8_t regB = getRtcRegister(0x0b); - outb(CMOS_ADDRESS, 0x8b); - outb(CMOS_DATA, regB & 0xbf); // Clear bit 6 - __asm__ volatile ("sti"); -} - -__attribute__ ((interrupt)) void rtcHandler(intFrame_t* iframe) { - datetime_t newDatetime, oldDatetime; - static uint16_t rtcTicks = 0; - - __asm__ volatile ("cli"); - rtcTicks++; - if (rtcTicks % 1024 == 0) { // 1 Second has passed - while (cmosUpdateProgress()); // Wait - - newDatetime.second = getRtcRegister(0); - newDatetime.minute = getRtcRegister(2); - newDatetime.hour = getRtcRegister(4); - newDatetime.day = getRtcRegister(7); - newDatetime.month = getRtcRegister(8); - newDatetime.year = getRtcRegister(9); - - do { - oldDatetime = newDatetime; - - while (cmosUpdateProgress()); // Wait - newDatetime.second = getRtcRegister(0); - newDatetime.minute = getRtcRegister(2); - newDatetime.hour = getRtcRegister(4); - newDatetime.day = getRtcRegister(7); - newDatetime.month = getRtcRegister(8); - newDatetime.year = getRtcRegister(9); - - } while ( - newDatetime.second != oldDatetime.second || - newDatetime.minute != oldDatetime.minute || - newDatetime.hour != oldDatetime.hour || - newDatetime.day != oldDatetime.day || - newDatetime.month != oldDatetime.month || - newDatetime.year != oldDatetime.year - ); - - uint8_t regB = getRtcRegister(0x0b); - if (!(regB & 0x04)) { - newDatetime.second = (newDatetime.second & 0x0f) + ((newDatetime.second >> 4) * 10); - newDatetime.minute = (newDatetime.minute & 0x0f) + ((newDatetime.minute >> 4) * 10); - newDatetime.hour = ((newDatetime.hour & 0x0F) + (((newDatetime.hour & 0x70) / 16) * 10)) | (newDatetime.hour & 0x80); // 12/24 Hour format bs - newDatetime.day = (newDatetime.day & 0x0f) + ((newDatetime.day >> 4) * 10); - newDatetime.month = (newDatetime.month & 0x0f) + ((newDatetime.month >> 4) * 10); - newDatetime.year = (newDatetime.year & 0x0f) + ((newDatetime.year >> 4) * 10); - } - - // Convert 12 to 14 hour format - if (!(regB & 0x02) && (newDatetime.hour & 0x80)) { - newDatetime.hour = ((newDatetime.hour & 0x7f) + 12) % 24; - } - - newDatetime.year += 2000; // Add current century - - //*datetime = newDatetime; - - datetime->second = newDatetime.second; - datetime->minute = newDatetime.minute; - datetime->hour = newDatetime.hour; - datetime->day = newDatetime.day; - datetime->month = newDatetime.month; - datetime->year = newDatetime.year; - - if (true) { // TODO: Probably get rid of this idk - char buf[20] = { 0 }; // "12/12 2012 12:12:12" - Max string 20 chars with null byte - - strcat(buf, itoa(datetime->day, 10)); - strcat(buf, "/"); - strcat(buf, itoa(datetime->month, 10)); - strcat(buf, " "); - strcat(buf, itoa(datetime->year, 10)); - strcat(buf, " "); - if (datetime->hour < 10) strcat(buf, "0"); - strcat(buf, itoa(datetime->hour, 10)); - strcat(buf, ":"); - if (datetime->minute < 10) strcat(buf, "0"); - strcat(buf, itoa(datetime->minute, 10)); - strcat(buf, ":"); - if (datetime->second < 10) strcat(buf, "0"); - strcat(buf, itoa(datetime->second, 10)); - - // The clock is a little offset down (about 0.4 of a character) It does look nice though! - uint8_t len = strlen(buf); - uint32_t x = gfxMode->xRes - len - 1; - char* str = &buf[0]; - for (uint8_t i = 0; i != len; i++, x++) { - drawChar(str[i], x, 0, terminal->fg, terminal->bg); - } - } - } - - getRtcRegister(0x0c); - sendPicEOI(8); - - __asm__ volatile ("sti"); -} - -void setupRtc() { // IRQ 8 - Real Time Clock - idtSetGate(0x28, rtcHandler, INT_GATE_FLAGS); - unsetIrqMask(8); - enableRtc(); -} +bool cmosUpdateProgress(); +uint8_t getRtcRegister(uint8_t reg); +void enableRtc(); +void disableRtc(); +void setupRtc(); #endif diff --git a/include/interrupt/syscalls.h b/include/interrupt/syscalls.h index 04a372e..8bc7612 100644 --- a/include/interrupt/syscalls.h +++ b/include/interrupt/syscalls.h @@ -2,21 +2,7 @@ #define INTERRUPT_SYSCALLS_H #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include - -/* - * XXX WARNING - Update MAX_SYSCALLS in the handler XXX - */ typedef struct { uint32_t esp; @@ -33,188 +19,6 @@ typedef struct { uint32_t eax; } __attribute__ ((packed)) sys_regs_t; -int sys_reserved(sys_regs_t) { - printf("\e[1N\e[6M Illegal use of Reserved() system call! \e[8M\e[8N\n"); - return -1; -} - -// Args: ebx - number of miliseconds -int sys_sleep(sys_regs_t regs) { - uint32_t* sleepTimerTicks = (uint32_t*)SLEEP_TIMER; - *sleepTimerTicks = regs.ebx; - - while (*sleepTimerTicks > 0) { // Wait... - __asm__ volatile ("sti;hlt;cli;"); - } - - return 0; -} - -// Args: ebx - int fd -// ecx - void* buf -// edx - uint32_t len -// Rets: Number of bytes written -int sys_write(sys_regs_t regs) { - int32_t fd = regs.ebx; - void* buf = (void*)regs.ecx; - uint32_t len = regs.edx; - - // TODO: Open fd table? - if (fd == 1) { // "stdout" - return terminalWrite(buf, len); // Call a terminal print function - } else { - return -1; - } -} - -// TODO: Use a Read() sycall and read from stdin -// Args: ebx - char* buffer -int sys_read(sys_regs_t regs) { - char* s = (char*)regs.ebx; - reads(s); - - return 0; -} - -// Args: ebx - size_t count -// Rets: Pointer to malloc-ed memory -int sys_malloc(sys_regs_t regs) { - uint32_t count = regs.ebx; - - // First Malloc() - if (!mallocListHead) { - mallocInit(count); // Setup malloc linked list - } - - void* ptr = mallocNextNode(count); - mallocMergeFree(); - - return (uint32_t)ptr; -} - -// Args: ebx - void* ptr -int sys_free(sys_regs_t regs) { - void* ptr = (void*)regs.ebx; - mallocFree(ptr); - return 0; -} - -// Args: ebx - path, -// ecx - oflag -// Rets: Opened file descriptor -int sys_open(sys_regs_t regs) { - int fd = 0; - char* path = (char*)regs.ebx; - uint32_t oflag = regs.ecx; - - extern FILE* openFileTable; - extern uint32_t openFiles; - - // TODO: better file finding - inode_t* root = (inode_t*)impl_superblock->rootInodePtr; - loadFile(root, (void*)SCRATCH_BLOCK_LOC); - - inode_t* inode = getInode(path, (dirEntry_t*)SCRATCH_BLOCK_LOC); - if (inode == NULL) { - return -1; - } - - // TODO: check if max open files have'nt been reached - fd = openFiles++; - FILE* fp = openFileTable + fd; - fp->_ptr = (void*)0xd000; - fp->_offset = 0; - fp->_size = inode->sizeBytes; - fp->_flag = oflag; - fp->_file = fd; - - loadFile(inode, fp->_ptr); - - return fd; -} - -// Args: ebx - int fd -// Rets: status -int sys_close(sys_regs_t regs) { - int fd = regs.ebx; - - extern FILE* openFileTable; - extern uint32_t openFiles; - - FILE* fp = openFileTable + fd; - free(fp->_ptr); - openFiles--; - - return 0; -} - -// TODO -int sys_seek(sys_regs_t regs) { return -1; } - -// System call table -int (*syscalls[MAX_SYSCALLS])(sys_regs_t) = { - [SYS_RESERVED] = sys_reserved, - [SYS_SLEEP] = sys_sleep, - [SYS_WRITE] = sys_write, - [SYS_READ] = sys_read, - [SYS_MALLOC] = sys_malloc, - [SYS_FREE] = sys_free, - [SYS_OPEN] = sys_open, - [SYS_CLOSE] = sys_close, - [SYS_SEEK] = sys_seek, -}; - -// int 0x80 - Syscall interrupt, handled by this function -// eax : Syscall number -__attribute__ ((naked)) // No prologue or epilogue, just assembly -void syscallHandler(intFrame_t* iframe) { - // Interrupt - Stack should contain: ss, esp, eflags, cs, eip - // We should also push these regs: ax, gs, fs, es, ds, bp, di, si, dx, cx, bx - __asm__ volatile ( - ".intel_syntax noprefix\n" // We use intel syntax - ".equ MAX_SYSCALLS, 9\n" // Define MAX_SYSCALLS again TODO: I don't want to have to do this - - // Check if syscall exists - "cmp eax, MAX_SYSCALLS - 1\n" - "ja invalidSyscall\n" - - // Call the syscall - "push eax\n" - "push gs\n" - "push fs\n" - "push es\n" - "push ds\n" - "push ebp\n" - "push edi\n" - "push esi\n" - "push edx\n" - "push ecx\n" - "push ebx\n" - "push esp\n" // Push stack pointer again (for variables and such idk) - - "call [syscalls + eax * 4]\n" // Call syscall from table. Syscall number should be in eax - "add esp, 4\n" // Do not override ESP - "pop ebx\n" - "pop ecx\n" - "add esp, 4\n" // Do not override EDX, some syscalls use it - - "pop esi\n" - "pop edi\n" - "pop ebp\n" - "pop ds\n" - "pop es\n" - "pop fs\n" - "pop gs\n" - "add esp, 4\n" // Save eax value - "iretd\n" // Return from interrupt (32 bit) - - // TODO: Send an error or something here - "invalidSyscall:\n" - "mov eax, -1\n" // Current error thing - "iretd\n" - - ".att_syntax" // Switch back to AT&T Syntax (Just in case) - ); -} +__attribute__ ((naked)) void syscallHandler(intFrame_t* iframe); #endif diff --git a/include/keyboard/keyboard.h b/include/keyboard/keyboard.h index 5acacbc..b312140 100644 --- a/include/keyboard/keyboard.h +++ b/include/keyboard/keyboard.h @@ -1,11 +1,6 @@ #ifndef KEYBOARD_KEYBOARD_H #define KEYBOARD_KEYBOARD_H -#include -#include -#include -#include -#include #include typedef struct { @@ -13,30 +8,6 @@ typedef struct { bool shift; } keyboardState_t; -keyboardState_t* keyboard = (keyboardState_t*)KEYBOARD_STATE_LOC; - -__attribute__ ((interrupt)) -void keyboardHandler(intFrame_t* iframe) { // TODO: Make this better and be able to read multi-byte scancode - uint8_t scancode = inb(0x60); - char c = US_Keyboard[keyboard->shift][scancode]; - - if (scancode == LEFT_SHIFT_PRESS || scancode == RIGHT_SHIFT_PRESS) { - keyboard->shift = true; - } else if (scancode == LEFT_SHIFT_RELEASE || scancode == RIGHT_SHIFT_RELEASE) { - keyboard->shift = false; - } - - if (scancode & 0x80) { // Keyup - } else if (c != '\0') { - keyboard->character = c; - } - - sendPicEOI(1); -} - -void setupKeyboard() { - idtSetGate(0x21, keyboardHandler, INT_GATE_FLAGS); - unsetIrqMask(1); -} +void setupKeyboard(); #endif diff --git a/include/keyboard/keys.h b/include/keyboard/keys.h index bb6d5f8..a488a8e 100644 --- a/include/keyboard/keys.h +++ b/include/keyboard/keys.h @@ -1,8 +1,6 @@ #ifndef KEYBOARD_KEYS_H #define KEYBOARD_KEYS_H -#include - #define LEFT_SHIFT_PRESS 0x2a #define LEFT_SHIFT_RELEASE (LEFT_SHIFT_PRESS | 0x80) #define RIGHT_SHIFT_PRESS 0x36 @@ -17,24 +15,24 @@ #define RIGHT_ALT_RELEASE (RIGHT_ALT_PRESS | 0x80) // Basic US Keyboard layout -static const char US_Keyboard[2][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, - '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.', // Numpad - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, - { - 0, 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\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, '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 - } -}; +#define US_KEYBOARD {\ + {\ + 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,\ + '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\ + },\ + {\ + 0, 27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\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, '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\ + }\ +} #endif diff --git a/include/memory/addresses.h b/include/memory/addresses.h index 08fbde3..6b01b81 100644 --- a/include/memory/addresses.h +++ b/include/memory/addresses.h @@ -7,7 +7,7 @@ * 0x1000-0x17ff - Free * 0x1800-0x1fff - Global Variables * 0x2000-0x2fff - Larger structs - * 0x3000-0x3fff - Free + * 0x3000-0x3fff - Filesystem Info * 0x4000-0x4fff - Font area * 0x6000-0x6fff - VBE info area * 0x7000-0x7bff - SMAP Area @@ -30,7 +30,7 @@ #define DATETIME_LOC 0x2200 // Filesystem Area 0x3000 - 0x3fff -#define OPEN_FILE_TABLE_LOC 0x3000 +#define FS_INFO_LOC 0x3000 // Font area 0x4000 - 0x4fff #define FONT_LOC 0x4000 diff --git a/include/memory/malloc.h b/include/memory/malloc.h index 84c19bb..c305403 100644 --- a/include/memory/malloc.h +++ b/include/memory/malloc.h @@ -13,112 +13,15 @@ typedef struct mallocNode_s { struct mallocNode_s* next; } mallocNode_t; -mallocNode_t* mallocListHead = NULL; -static uint32_t mallocVirtualAddr = 0; -static uint32_t mallocPhysicalAddr = 0; -static uint32_t mallocPages = 0; +extern mallocNode_t* mallocListHead; +extern uint32_t mallocVirtualAddr; +extern uint32_t mallocPhysicalAddr; +extern uint32_t mallocPages; -void mallocInit(uint32_t size) { - mallocPages = size / PAGE_SIZE; - if (size % PAGE_SIZE > 0) { mallocPages++; } - - mallocPhysicalAddr = (uint32_t)allocBlocks(mallocPages); - mallocListHead = (mallocNode_t*)mallocVirtualAddr; - - // Map pages - for (uint32_t i = 0, virtualAddr = mallocVirtualAddr; i < mallocPages; i++, virtualAddr += PAGE_SIZE) { - mapPage((void*)(mallocPhysicalAddr + i * PAGE_SIZE), (void*)virtualAddr); - - ptEntry_t* page = getPage(virtualAddr); - SET_ATTR(page, PTE_READ_WRITE); - } - - if (mallocListHead) { - mallocListHead->size = (mallocPages * PAGE_SIZE) - sizeof(mallocNode_t); - mallocListHead->free = true; - mallocListHead->next = NULL; - } -} - -void mallocSplit(mallocNode_t* node, uint32_t size) { - if (node->size < size + sizeof(mallocNode_t)) { return; } // Can't split - node too small - - // Remainder node - mallocNode_t* newNode = (mallocNode_t*)((void*)node + size + sizeof(mallocNode_t)); - newNode->size = node->size - size - sizeof(mallocNode_t); - newNode->free = true; - newNode->next = node->next; - - // Split node - node->size = size; - node->free = false; - node->next = newNode; -} - -void* mallocNextNode(uint32_t size) { - if (size == 0) { return NULL; } // Why would you try that? (undefined behaviour i guess) - - mallocNode_t* current = mallocListHead; - - if (mallocListHead->size == 0) { mallocInit(size); } - - while (((current->size < size) || !current->free) && current->next != NULL) { - current = current->next; - } - - if (current->size == size) { - current->free = false; - } else if (current->size > size + sizeof(mallocNode_t)) { - mallocSplit(current, size); // Modifies current into the right size and makes it point to the remainder - } else { // There's no large enough node -> try to allocate more pages - uint8_t pageCount = 1; - while (current->size + pageCount * PAGE_SIZE < size + sizeof(mallocNode_t)) { - pageCount++; - } - - // Allocate and map new pages - uint32_t virtualAddr = mallocVirtualAddr + mallocPages * PAGE_SIZE; - for (uint32_t i = 0; i < pageCount; i++) { - ptEntry_t page = 0; - uint32_t* temp = allocPage(&page); - - mapPage((void*)temp, (void*)virtualAddr); - SET_ATTR(&page, PTE_READ_WRITE); - virtualAddr += PAGE_SIZE; - current->size += PAGE_SIZE; - mallocPages++; - } - - mallocSplit(current, size); - } - - return (void*)current + sizeof(mallocNode_t); -} - -void mallocMergeFree() { - mallocNode_t* current = mallocListHead; - - while (current && current->next != NULL) { - if (current->free && current->next->free) { - current->size += (current->next->size) + sizeof(mallocNode_t); - current->next = current->next->next; - } - current = current->next; - } -} - -void mallocFree(void* ptr) { - mallocNode_t* current = mallocListHead; - - while (current->next) { - if ((void*)current + sizeof(mallocNode_t) == ptr) { - current->free = true; - mallocMergeFree(); - break; - } - - current = current->next; - } -} +void mallocInit(uint32_t size); +void mallocSplit(mallocNode_t* node, uint32_t size); +void* mallocNextNode(uint32_t size); +void mallocMergeFree(); +void mallocFree(void* ptr); #endif diff --git a/include/memory/physical.h b/include/memory/physical.h index 0d5379e..4fac758 100644 --- a/include/memory/physical.h +++ b/include/memory/physical.h @@ -15,121 +15,19 @@ typedef struct smapEntry_s { uint32_t acpiAttr; } __attribute__ ((packed)) smapEntry_t; -static uint32_t* memoryMap = 0; -static uint32_t maxBlocks; -static uint32_t usedBlocks = 0; +extern uint32_t* memoryMap; +extern uint32_t maxBlocks; +extern uint32_t usedBlocks; -void setBlock(uint32_t block) { - // Set the right bit to 1 - memoryMap[block/32] |= (1 << (block % 32)); -} +void setBlock(uint32_t block); +void unsetBlock(uint32_t block); +uint8_t testBlock(uint32_t block); -void unsetBlock(uint32_t block) { - // Set the right bit to 0 - memoryMap[block/32] &= ~(1 << (block % 32)); -} - -uint8_t testBlock(uint32_t block) { - // Check the bit - return memoryMap[block/32] & (1 << (block % 32)) ? 1 : 0; -} - -// TODO: Refactor whatever the fuck this is -int32_t findFreeBlocks(uint32_t blockCount) { - if (blockCount == 0) { // Error - return -1; - } - - uint32_t maxBlockEntries = maxBlocks / 32; - for (uint32_t i = 0; i < maxBlockEntries; i++) { - if (memoryMap[i] != 0xffffffff) { - for (uint8_t j = 0; j < 32; j++) { - uint32_t block = 1 << j; - - if (!(memoryMap[i] & block)) { - // uint32_t startBlock = i * 32 + block; - // uint32_t freeBlocks = 0; - - for (uint32_t count = i, freeBlocks = 0; count < blockCount; count++) { - if (j + count > 31 && i + 1 <= maxBlocks / 32) { - if (!(memoryMap[i+1] & (1 << (j + count)))) { - freeBlocks++; - } - } else { - if (!(memoryMap[i] & (1 << (j + count)))) { - freeBlocks++; - } - } - - if (freeBlocks == blockCount) { - return i * 32 + j; - } - } - } - } - } - } - - return -1; // No free memory found :/ -} - -void setupPhysicalMemoryManager(uint32_t startAddress, uint32_t size) { - memoryMap = (uint32_t*)startAddress; - maxBlocks = size / BLOCK_SIZE; - usedBlocks = maxBlocks; - - memset((char*)memoryMap, 0xff, maxBlocks / BLOCKS_PER_BYTE); -} - -void initMemoryRegion(uint32_t baseAddress, uint32_t size) { - uint32_t align = baseAddress / BLOCK_SIZE; - uint32_t blockCount = size / BLOCK_SIZE; - - while (blockCount-- > 0) { - unsetBlock(align++); - usedBlocks--; - } - - setBlock(0); // Make sure we don't override the first block that contains IDT, BIOS stuff etc. -} - -void deinitMemoryRegion(uint32_t baseAddress, uint32_t size) { - uint32_t align = baseAddress / BLOCK_SIZE; - uint32_t blockCount = size / BLOCK_SIZE; - - while (blockCount-- > 0) { - setBlock(align++); - usedBlocks++; - } -} - -void* allocBlocks(uint32_t blockCount) { - if ((maxBlocks - usedBlocks) < blockCount) { - return NULL; - } - - int32_t startBlock = findFreeBlocks(blockCount); - if (startBlock == -1) { - return NULL; - } - - for (uint32_t i = 0; i < blockCount; i++) { - setBlock(startBlock + i); - usedBlocks++; - } - - return (void*)(startBlock * BLOCK_SIZE); -} - -void freeBlocks(void* address, uint32_t blockCount) { - uint32_t startBlock = (uint32_t)(address) / BLOCK_SIZE; - - for (uint32_t i = 0; i < blockCount; i++) { - unsetBlock(startBlock + i); - usedBlocks--; - } - - setBlock(0); // Make sure that block 0 is always set -} +int32_t findFreeBlocks(uint32_t blockCount); +void setupPhysicalMemoryManager(uint32_t startAddress, uint32_t size); +void initMemoryRegion(uint32_t baseAddress, uint32_t size); +void deinitMemoryRegion(uint32_t baseAddress, uint32_t size); +void* allocBlocks(uint32_t blockCount); +void freeBlocks(void* address, uint32_t blockCount); #endif diff --git a/include/memory/virtual.h b/include/memory/virtual.h index d5af850..50a8e99 100644 --- a/include/memory/virtual.h +++ b/include/memory/virtual.h @@ -3,8 +3,6 @@ #include #include -#include -#include #define PAGES_PER_TABLE 1024 #define TABLES_PER_DIRECTORY 1024 @@ -56,151 +54,17 @@ typedef struct { pdEntry_t entries[TABLES_PER_DIRECTORY]; } pageDirectory_t; -pageDirectory_t* currentPd = NULL; +extern pageDirectory_t* currentPd; -ptEntry_t* getPtEntry(pageTable_t* pt, uint32_t virtualAddress) { - if (pt) return &pt->entries[PT_INDEX(virtualAddress)]; - return NULL; -} - -pdEntry_t* getPdEntry(pageDirectory_t* pd, uint32_t virtualAddress) { - if (pd) return &pd->entries[PT_INDEX(virtualAddress)]; // It it supposed to be PT_INDEX, don't worry - return NULL; -} - -ptEntry_t* getPage(uint32_t virtualAddress) { - pageDirectory_t* pd = currentPd; - pdEntry_t* entry = &pd->entries[PD_INDEX(virtualAddress)]; - pageTable_t* table = (pageTable_t*)PAGE_PHYS_ADDRESS(entry); - ptEntry_t* page = &table->entries[PT_INDEX(virtualAddress)]; - return page; -} - -void* allocPage(ptEntry_t* page) { - void* block = allocBlocks(1); - if (block) { - SET_FRAME(page, (uint32_t)block); - SET_ATTR(page, PTE_PRESENT); - } - - return block; -} - -void freePage(ptEntry_t* page) { - void* address = (void*)PAGE_PHYS_ADDRESS(page); - if (address) { - freeBlocks(address, 1); - } - - CLEAR_ATTR(page, PTE_PRESENT); -} - -uint8_t setPageDirectory(pageDirectory_t* pd) { - if (!pd) { return 1; } // Nuh uh - currentPd = pd; - - // cr3 (Control register 3) - current page dir address - __asm__ volatile("movl %%eax, %%cr3" : : "a"(currentPd)); - - return 0; // Success -} - -void flushTlbEntry(uint32_t virtualAddress) { - __asm__ volatile("cli; invlpg (%0); sti" : : "r"(virtualAddress)); -} - -uint8_t mapPage(void* physicalAddr, void* virtualAddr) { - pageDirectory_t* pd = currentPd; - pdEntry_t* entry = &pd->entries[PD_INDEX((uint32_t)virtualAddr)]; - - if (!TEST_ATTR(entry, PTE_PRESENT)) { - // Assuming that the page is not allocated since it's not present - pageTable_t* table = (pageTable_t*)allocBlocks(1); - if (!table) return 1; // Out of memory!! - - // Clear page table (may be slow?) - memset(table, 0, sizeof(pageTable_t)); - - pdEntry_t* entry = &pd->entries[PD_INDEX((uint32_t)virtualAddr)]; - // Enable attributes and map in table - SET_ATTR(entry, PDE_PRESENT); - SET_ATTR(entry, PDE_READ_WRITE); - SET_FRAME(entry, (uint32_t)table); - } - - pageTable_t* table = (pageTable_t*)PAGE_PHYS_ADDRESS(entry); - ptEntry_t* page = &table->entries[PT_INDEX((uint32_t)virtualAddr)]; - - SET_ATTR(page, PTE_PRESENT); - SET_FRAME(page, (uint32_t)physicalAddr); - - return 0; // Success -} - -void unmapPage(void* virtualAddress) { - ptEntry_t* page = getPage((uint32_t)virtualAddress); - - SET_FRAME(page, 0); - CLEAR_ATTR(page, PDE_PRESENT); -} - -uint8_t setupVirtualMemoryManager() { - // Create a default page dir - pageDirectory_t* dir = (pageDirectory_t*)allocBlocks(3); - - if (!dir) { return 1; } // Out of memory - - memset(dir, 0, sizeof(pageDirectory_t)); - for (uint32_t i = 0; i < 1024; i++) { - dir->entries[i] = 0x02; // Supervisor, r/w, not present - } - - // Alloc default page table - pageTable_t* table = (pageTable_t*)allocBlocks(1); - if (!table) { return 1; } // Out of memory - - // Alloc a 3GB page - pageTable_t* table3gb = (pageTable_t*)allocBlocks(1); - if (!table) { return 1; } // Out of memory - - memset(table, 0, sizeof(pageTable_t)); - memset(table3gb, 0, sizeof(pageTable_t)); - - // Identity map first 4MB - for (uint32_t i = 0, frame = 0, virt = 0; i < 1024; i++, frame += PAGE_SIZE, virt += PAGE_SIZE) { - ptEntry_t page = 0; - SET_ATTR(&page, PTE_PRESENT); - SET_ATTR(&page, PTE_READ_WRITE); - SET_FRAME(&page, frame); - - table3gb->entries[PT_INDEX(virt)] = page; - } - - // Map kernel to 3GB+ - for (uint32_t i = 0, frame = KERNEL_LOC, virt = 0xc0000000; i < 1024; i++, frame += PAGE_SIZE, virt += PAGE_SIZE) { - ptEntry_t page = 0; - SET_ATTR(&page, PTE_PRESENT); - SET_ATTR(&page, PTE_READ_WRITE); - SET_FRAME(&page, frame); - - table->entries[PT_INDEX(virt)] = page; - } - - pdEntry_t* entry = &dir->entries[PD_INDEX(0xc0000000)]; - SET_ATTR(entry, PDE_PRESENT); - SET_ATTR(entry, PDE_READ_WRITE); - SET_FRAME(entry, (uint32_t)table); - - pdEntry_t* entry2 = &dir->entries[PD_INDEX(0x00000000)]; - SET_ATTR(entry2, PDE_PRESENT); - SET_ATTR(entry2, PDE_READ_WRITE); - SET_FRAME(entry2, (uint32_t)table3gb); - - setPageDirectory(dir); - - // ENABLE PAGING!!! Set PG bit 31 and PE bit 0 in cr0 - __asm__ volatile("movl %cr0, %eax; orl $0x80000001, %eax; movl %eax, %cr0"); - return 0; // Success -} +ptEntry_t* getPtEntry(pageTable_t* pt, uint32_t virtualAddress); +pdEntry_t* getPdEntry(pageDirectory_t* pd, uint32_t virtualAddress); +ptEntry_t* getPage(uint32_t virtualAddress); +void* allocPage(ptEntry_t* page); +void freePage(ptEntry_t* page); +uint8_t setPageDirectory(pageDirectory_t* pd); +void flushTlbEntry(uint32_t virtualAddress); +uint8_t mapPage(void* physicalAddr, void* virtualAddr); +void unmapPage(void* virtualAddress); +uint8_t setupVirtualMemoryManager(); #endif diff --git a/include/ports/io.h b/include/ports/io.h index 479f7b1..ba0dbd4 100644 --- a/include/ports/io.h +++ b/include/ports/io.h @@ -4,29 +4,10 @@ #include // Port functions -uint8_t inb(uint16_t port) { - uint8_t result; - __asm__ volatile("inb %1, %0" : "=a"(result) : "Nd"(port)); - return result; -} - -void outb(uint16_t port, uint8_t data) { - __asm__ volatile("outb %0, %1" :: "a"(data), "Nd"(port)); -} - -uint16_t inw(uint16_t port) { - uint16_t result; - __asm__ volatile("inw %1, %0" : "=a"(result) : "Nd"(port)); - return result; -} - -void outw(uint16_t port, uint16_t data) { - __asm__ volatile("outw %0, %1" :: "a"(data), "Nd"(port)); -} - -void ioWait() { - // Waits ~1 I/O Cycle (Linux uses this so it should be good) - __asm__ volatile("outb %%al, $0x80" : : "a"(0)); -} +uint8_t inb(uint16_t port); +void outb(uint16_t port, uint8_t data); +uint16_t inw(uint16_t port); +void outw(uint16_t port, uint16_t data); +void ioWait(); #endif diff --git a/include/screen/gfxmode.h b/include/screen/gfxmode.h index 1710819..edfd384 100644 --- a/include/screen/gfxmode.h +++ b/include/screen/gfxmode.h @@ -65,20 +65,8 @@ typedef struct modeInfoBlock_s { uint8_t reserved4[190]; } __attribute__ ((packed)) modeInfoBlock_t; -static modeInfoBlock_t* gfxMode = (modeInfoBlock_t*)MODE_INFO_BLOCK_LOC; +extern modeInfoBlock_t* gfxMode; -uint32_t convertColor(uint32_t color) { - if (gfxMode->bpp == 8) { // Uses VGA Color pallete, idk how to support that - return color & 0xff; - } - - // TODO: !! Important !! - Is should be divided by 255.0 (for floats), but using '-mgeneral-regs-only' removes fp-registers and - // wants to use some dumb functions for converting fp numbers in the stdlib (that we don't have) - uint8_t red = ((color >> 16) & 0xff) * (((1 << gfxMode->linearRedMaskSize) - 1) / 255); - uint8_t green = ((color >> 8 ) & 0xff) * (((1 << gfxMode->linearGreenMaskSize) - 1) / 255); - uint8_t blue = ((color ) & 0xff) * (((1 << gfxMode->linearBlueMaskSize) - 1) / 255); - - return (red << gfxMode->redFieldPos) | (green << gfxMode->greenFieldPos) | (blue << gfxMode->blueFieldPos); -} +uint32_t convertColor(uint32_t color); #endif diff --git a/include/screen/graphics.h b/include/screen/graphics.h index 4c54bf0..7de1e7c 100644 --- a/include/screen/graphics.h +++ b/include/screen/graphics.h @@ -2,146 +2,17 @@ #define SCREEN_GRAPHICS_H #include -#include -#include #define rgb(r,g,b) ( ((r) << 16 | (g) << 8 | (b)) & 0x00ffffff ) -void drawPixel(int32_t x, int32_t y, uint32_t color) { - uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr; - uint8_t bytesPerPx = gfxMode->bpp / 8; - uint32_t convColor = convertColor(color); // Idk if i should convert this for every px or just put in a preconverted color - - uint32_t offset = ((y * gfxMode->xRes) + x) * bytesPerPx; - - for (uint8_t i = 0; i < bytesPerPx; i++) { - vidmem[offset + i] = (uint8_t)(convColor >> (i*8)); - } -} - -// Source: https://en.wikipedia.org/wiki/Bresenham's_line_algorithm -void drawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color) { - int32_t dx = abs(x2 - x1); - int32_t dy = -abs(y2 - y1); - int8_t sx = (x1 < x2) ? 1 : -1; - int8_t sy = (y1 < y2) ? 1 : -1; - int16_t err = dx + dy; - - // TODO: Sometimes the condition isn't met for some reason and it breaks everything - while (!(x1 == x2 && y1 == y2)) { - drawPixel(x1, y1, color); - - if (err * 2 >= dy) { - err += dy; - x1 += sx; - } - if (err * 2 <= dx) { - err += dx; - y1 += sy; - } - } -} - -void drawRect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color) { - drawLine(x1, y1, x2, y1, color); - drawLine(x2, y1, x2, y2, color); - drawLine(x2, y2, x1, y2, color); - drawLine(x1, y2, x1, y1, color); -} - -void drawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, uint32_t color) { - drawLine(x1, y1, x2, y2, color); - drawLine(x2, y2, x3, y3, color); - drawLine(x3, y3, x1, y1, color); -} - -void drawCircle(int32_t x, int32_t y, uint16_t radius, uint32_t color) { - int16_t offX = 0; - int16_t offY = radius; - int16_t p = 1 - radius; - - // Draw 8 octant points - drawPixel(x + offX, y + offY, color); - drawPixel(x - offX, y + offY, color); - drawPixel(x + offX, y - offY, color); - drawPixel(x - offX, y - offY, color); - drawPixel(x + offY, y + offX, color); - drawPixel(x - offY, y + offX, color); - drawPixel(x + offY, y - offX, color); - drawPixel(x - offY, y - offX, color); - - while (offX < offY) { - offX++; - if (p < 0) p += 2 * offX + 1; - else { - offY--; - p += 2 * (offX - offY) + 1; - } - - drawPixel(x + offX, y + offY, color); - drawPixel(x - offX, y + offY, color); - drawPixel(x + offX, y - offY, color); - drawPixel(x - offX, y - offY, color); - drawPixel(x + offY, y + offX, color); - drawPixel(x - offY, y + offX, color); - drawPixel(x + offY, y - offX, color); - drawPixel(x - offY, y - offX, color); - } -} - -// Recursive (may need large stack) -// TODO: Fix this for all bpp values -void boundaryFill(int32_t x, int32_t y, uint32_t fillColor, uint32_t boundaryColor) { - uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr; - uint8_t bytesPerPx = (gfxMode->bpp+1) / 8; - uint32_t convColorF = convertColor(fillColor); - uint32_t convColorB = convertColor(boundaryColor); - - uint32_t offset = (y * gfxMode->xRes + x) * bytesPerPx; - - uint8_t draw = 0; - for (uint8_t i = 0; i < bytesPerPx; i++) { - if (vidmem[offset + i] != (uint8_t)(convColorF >> (i*8)) && vidmem[offset + i] != (uint8_t)(convColorB >> (i*8))) { - draw = 1; - break; - } - } - - if (draw) { - for (uint8_t i = 0; i < bytesPerPx; i++) { - vidmem[offset + i] = (uint8_t)(convColorF >> (i*8)); - } - - boundaryFill(x + 1, y, fillColor, boundaryColor); - boundaryFill(x, y + 1, fillColor, boundaryColor); - boundaryFill(x - 1, y, fillColor, boundaryColor); - boundaryFill(x, y - 1, fillColor, boundaryColor); - } -} - -// TODO: After i fix boundary fill, uncomment it from these functions -void fillRect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color) { - int32_t cx = (x1 + x2) / 2; - int32_t cy = (y1 + y2) / 2; - - drawRect(x1, y1, x2, y2, color - 1); - boundaryFill(cx, cy, color, color - 1); - drawRect(x1, y1, x2, y2, color); -} - -void fillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, uint32_t color) { - int32_t cx = (x1 + x2 + x3) / 3; - int32_t cy = (y1 + y2 + y3) / 3; - - drawTriangle(x1, y1, x2, y2, x3, y3, color - 1); - boundaryFill(cx, cy, color, color - 1); - drawTriangle(x1, y1, x2, y2, x3, y3, color); -} - -void fillCircle(int32_t x, int32_t y, uint16_t radius, uint32_t color) { - drawCircle(x, y, radius, color - 1); - // boundaryFill(x, y, color, color - 1); TODO: It just doesn't feel like working here and hangs - drawCircle(x, y, radius, color); -} +void drawPixel(int32_t x, int32_t y, uint32_t color); +void drawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color); +void drawRect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color); +void drawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, uint32_t color); +void drawCircle(int32_t x, int32_t y, uint16_t radius, uint32_t color); +void boundaryFill(int32_t x, int32_t y, uint32_t fillColor, uint32_t boundaryColor); +void fillRect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color); +void fillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, uint32_t color); +void fillCircle(int32_t x, int32_t y, uint16_t radius, uint32_t color); #endif diff --git a/include/screen/text.h b/include/screen/text.h index c8fdd07..bddfc9d 100644 --- a/include/screen/text.h +++ b/include/screen/text.h @@ -1,11 +1,7 @@ #ifndef SCREEN_TEXT_H #define SCREEN_TEXT_H -#include -#include -#include #include -#include typedef union { struct { @@ -15,88 +11,8 @@ typedef union { uint8_t data[4096]; } __attribute__ ((packed)) font_t; -// TODO: Reimplement larger text -void drawChar(char c, uint32_t x, uint32_t y, uint32_t fgColor, uint32_t bgColor) { - // Font info - font_t* font = (font_t*)FONT_LOC; - uint8_t charWidth = font->width; - uint8_t charHeight = font->height; - // uint8_t bitmapRowLen = (charWidth - 1) / 8 + 1; // TODO: Larger font support - - // Video stuff - uint8_t bytesPerPx = (gfxMode->bpp+1) / 8; - uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr; - uint32_t offset = (gfxMode->xRes * y * charHeight + x * charWidth) * bytesPerPx; - - uint8_t* bitmap = &font->data[(c - 1) * charHeight]; - for (uint8_t i = 0; i < charHeight; i++) { // Rows - char bitmapRow = bitmap[i]; - uint32_t color = convertColor((bitmapRow & 0x80) ? fgColor : bgColor); - - for (uint8_t j = 0; j < charWidth * bytesPerPx; ++j) { // Cols - uint8_t byte = j % bytesPerPx; - vidmem[offset + j] = (uint8_t)(color >> (8 * byte)); - - if (byte == bytesPerPx - 1) { - bitmapRow = bitmapRow << 1; - color = convertColor((bitmapRow & 0x80) ? fgColor : bgColor); - } - } - - offset += gfxMode->linearBytesPerScanline; // gfxMode->xRes * bytesPerPx - } -} - -void scroll() { // TODO: Make this faster (still kinda slow, but memcpy32() helped alot) - uint8_t charHeight = ((font_t*)FONT_LOC)->height; - if (terminal->y+1 < terminal->height) { return; } // Check if we should scroll - - uint32_t bytesPerLine = charHeight * gfxMode->bytesPerScanline; - uint32_t lines = terminal->height; - uint32_t vidmem = gfxMode->physicalBasePtr; - - for (uint32_t i = 1; i < lines; i++) { - uint32_t address = vidmem + i * bytesPerLine; - memcpy32((char*)address, (char*)(address - bytesPerLine), bytesPerLine); - } - - uint32_t color = convertColor(terminal->bg); - uint8_t* lastLine = (uint8_t*)(vidmem + (lines-1) * bytesPerLine); - uint8_t bytesPerPx = (gfxMode->bpp+1) / 8; - - for (uint32_t i = 0; i < bytesPerLine; i++) { - for (uint8_t j = 0; j < bytesPerPx; j++) { - lastLine[j] = (uint8_t)(color >> (j * 8)); - } - lastLine += bytesPerPx; - } - - terminal->y--; -} - -// TODO: Make this comply with the new terminal.h thing! -void clearScreen(uint32_t bgColor) { - uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr; - uint8_t bytesPerPx = (gfxMode->bpp+1) / 8; - - terminal->x = 0; - terminal->y = 0; - - uint32_t color = convertColor(bgColor); - - for (uint32_t i = 0; i < gfxMode->xRes; i++) { // Clear one line of pixels - for (uint8_t j = 0; j < bytesPerPx; j++) { - vidmem[j] = (uint8_t)(color >> (j * 8)); - } - vidmem += bytesPerPx; - } - - vidmem -= gfxMode->bytesPerScanline; - - for (uint32_t i = 0; i < gfxMode->yRes; i++) { // Copy that line to clear the entire screen (using memcpy32 is fast!) - memcpy32(vidmem, vidmem + gfxMode->bytesPerScanline, gfxMode->bytesPerScanline); - vidmem += gfxMode->bytesPerScanline; - } -} +void drawChar(char c, uint32_t x, uint32_t y, uint32_t fgColor, uint32_t bgColor); +void scroll(); +void clearScreen(uint32_t bgColor); #endif diff --git a/include/sound/pcspk.h b/include/sound/pcspk.h index 545a67b..f5bfc6d 100644 --- a/include/sound/pcspk.h +++ b/include/sound/pcspk.h @@ -1,32 +1,14 @@ #ifndef SOUND_PCSPK_H #define SOUND_PCSPK_H -#include #include -#include -#include -#include +#include #define PC_SPEAKER 0x61 -void enableSpeaker() { - uint8_t temp = inb(PC_SPEAKER); - outb(PC_SPEAKER, temp | 0x03); // Set first 2 bits -} - -void disableSpeaker() { - uint8_t temp = inb(PC_SPEAKER); - outb(PC_SPEAKER, temp & 0xfc); // Set first 2 bits -} - -void playNote(note_t note, uint32_t ms) { - setPitPhase(2, 3, note); - sleep(ms); -} - -void rest(uint32_t ms) { - setPitPhase(2, 3, 30000); // Unhearable noise - sleep(ms); -} +void enableSpeaker(); +void disableSpeaker(); +void playNote(note_t note, uint32_t ms); +void rest(uint32_t ms); #endif diff --git a/include/terminal/terminal.h b/include/terminal/terminal.h index 793222d..559195e 100644 --- a/include/terminal/terminal.h +++ b/include/terminal/terminal.h @@ -1,12 +1,8 @@ #ifndef TERMINAL_TERMINAL_H #define TERMINAL_TERMINAL_H -#include -#include -#include #include #include -#include typedef struct { uint32_t x; // X Position of cursor in characters @@ -19,126 +15,9 @@ typedef struct { bool hideCursor; // Should we display the cursor } terminal_t; -terminal_t* terminal = (terminal_t*)TERMINAL_INFO_LOC; +extern terminal_t* terminal; -#include // This needs to be here because it uses 'terminal' and otherwise it would be undeclared - -int32_t terminalWrite(const void* buf, uint32_t len) { - terminal->width = gfxMode->xRes / *(uint8_t*)(FONT_LOC); - terminal->height = gfxMode->yRes / *(uint8_t*)(FONT_LOC+1); - - char* str = (char*)buf; - uint32_t i; - - // Do we need to check for NULL? Can we just skip it/ignore it? - for (i = 0; i < len && str[i] != '\0'; i++) { - if (str[i] == '\n') { - drawChar(' ', terminal->x, terminal->y, terminal->fg, terminal->bg); - terminal->y++; - terminal->x = 0; - } else if (str[i] == '\b') { - drawChar(' ', terminal->x, terminal->y, terminal->fg, terminal->bg); - if (terminal->x == 0) { - terminal->x = terminal->width - 1; - terminal->y--; // Y could be 0? - } else { - terminal->x--; - } - drawChar(' ', terminal->x, terminal->y, terminal->fg, terminal->bg); - } else if (str[i] == '\x1b') { // Escape sequence - if (str[++i] != '[') { // TODO: Support more types of escape sequences - i--; - continue; - } - - i++; - uint32_t args[8] = { 0 }; - uint8_t argc = 0; - while (1) { // I'm not 100% sure this works, but i'd like to imagine it does - if (argc > 8) break; // Max arg count? idk - - uint32_t value = atoi(&str[i]); - args[argc++] = value; - - while (value != 0) { // Skip by the number string - value /= 10; - i++; - } - - if (str[i] != ';') break; - i++; - } - - switch (str[i]) { // TODO: Add default values (see docs/escape.txt) - case 'A': // Cursor up - terminal->y -= args[0]; - break; - case 'B': // Cursor down - terminal->y += args[0]; - break; - case 'C': // Cursor left - terminal->x -= args[0]; - break; - case 'D': // Cursor right - terminal->x += args[0]; - break; - case 'E': // nth row - terminal->x = args[0]; - break; - case 'F': // nth col - terminal->y = args[0]; - break; - case 'G': // show/hide cursor - terminal->hideCursor = args[0] ? false : true; - break; - case 'H': // move cursor to (x,y) - terminal->x = args[0]; - terminal->y = args[1]; - break; - case 'I': // RESERVED - case 'J': // Erase screen - clearScreen(terminal->bg); - break; - case 'K': // Erase line - break; // TODO - case 'L': // Erase collumn - break; // TODO - case 'M': // Set FG - if (args[0] < 8) { - terminal->fg = codeToColor(args[0]); - } else if (args[0] == 8) { - terminal->fg = FG_COLOR; - } - break; - case 'N': // Set BG - if (args[0] < 8) { - terminal->bg = codeToColor(args[0]); - } else if (args[0] == 8) { - terminal->bg = BG_COLOR; - } - break; - default: break; - } - } else { - drawChar(str[i], terminal->x, terminal->y, terminal->fg, terminal->bg); - terminal->x++; - - if (terminal->x >= terminal->width) { // Go to next line - terminal->y++; - terminal->x = 0; - } - } - } - scroll(); - - return i; // Number of characters that were printed -} - -void toggleCursor() { - static bool visible = false; - visible = !visible; - - drawChar(visible ? 127 : ' ', terminal->x, terminal->y, terminal->fg, terminal->bg); -} +int32_t terminalWrite(const void* buf, uint32_t len); +void toggleCursor(); #endif diff --git a/kern.iso b/kern.iso index 0d4121c9532e915c60e64403b4e8312ecdeb8f15..12bc63e2590c3a23128965845663a9dd54506678 100644 GIT binary patch delta 21113 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 T!R4jk@=Ey6vl3>R{Ko$V!t>qW delta 14325 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 diff --git a/libk/disk/disk.c b/libk/disk/disk.c new file mode 100644 index 0000000..9a67b8f --- /dev/null +++ b/libk/disk/disk.c @@ -0,0 +1,53 @@ +#include +#include +#include + +void diskRead(uint32_t lbaAddress, uint8_t sectorCount, char* dst) { + outb(PIO_PORT + 6, ((lbaAddress >> 24) & 0x0f) | 0xe0); // 6 - Use LBA; 4 - Drive number; 3-0 - Highest lba address nibble + outb(PIO_PORT + 2, sectorCount); // Sector count register + outb(PIO_PORT + 3, (uint8_t)(lbaAddress)); // Lowest lba address byte + outb(PIO_PORT + 4, (uint8_t)(lbaAddress >> 8)); // Middle lba address byte + outb(PIO_PORT + 5, (uint8_t)(lbaAddress >> 16)); // High lba address byte + outb(PIO_PORT + 7, READ_COMMAND); // Command register + + uint16_t* address = (uint16_t*)dst; + + for (uint8_t i = sectorCount; i > 0; i--) { + while (inb(PIO_PORT + 7) & (1 << 7)); // Poll status register untill BSY bit is clear + + for (size_t j = 0; j < 256; j++) { + *address++ = inw(PIO_PORT); // Read 256 words (512 Bytes = 1 Sector) + } + + for (uint8_t delay = 0; delay < 4; delay++) { // 400ns delay + inb(0x3f6); // Alternate status register + } + } +} + +void diskWrite(uint32_t lbaAddress, uint8_t sectorCount, char* src) { + outb(PIO_PORT + 6, ((lbaAddress >> 24) & 0x0f) | 0xe0); // 6 - Use LBA; 4 - Drive number; 3-0 - Highest lba address nibble + outb(PIO_PORT + 2, sectorCount); // Sector count register + outb(PIO_PORT + 3, (uint8_t)(lbaAddress)); // Lowest lba address byte + outb(PIO_PORT + 4, (uint8_t)(lbaAddress >> 8)); // Middle lba address byte + outb(PIO_PORT + 5, (uint8_t)(lbaAddress >> 16)); // High lba address byte + outb(PIO_PORT + 7, WRITE_COMMAND); // Command register + + uint16_t* address = (uint16_t*)src; + + for (uint8_t i = sectorCount; i > 0; i--) { + while (inb(PIO_PORT + 7) & (1 << 7)); // Poll status register untill BSY bit is clear + + for (size_t j = 0; j < 256; j++) { + outw(PIO_PORT, *address++); // Write 256 words (512 Bytes = 1 Sector) + } + + for (uint8_t delay = 0; delay < 4; delay++) { // 400ns delay + inb(0x3f6); // Alternate status register + } + } + + outb(PIO_PORT + 7, CACHE_FLUSH); // Cache flush + while (inb(PIO_PORT + 7) & (1 << 7)); // Poll status register untill BSY bit is clear +} + diff --git a/libk/error/bigerr.c b/libk/error/bigerr.c new file mode 100644 index 0000000..99a5e2e --- /dev/null +++ b/libk/error/bigerr.c @@ -0,0 +1,58 @@ +#include +#include +#include + +void rect(uint32_t c, uint16_t x, uint16_t y, uint16_t w, uint16_t h) { + uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr; + uint8_t bytesPerPx = gfxMode->bpp / 8; + uint32_t convColor = convertColor(c); + + for (uint32_t dx = 0; dx < w; dx++) { + for (uint32_t dy = 0; dy < h; dy++) { + uint32_t offset = (((y + dy) * gfxMode->xRes) + (x + dx)) * bytesPerPx; + + for (uint8_t i = 0; i < gfxMode->bpp; i++) { + vidmem[offset + i] = (uint8_t)(convColor >> (i*8)); + } + } + } +} + +void bigError(uint32_t err) { + // Red BG + rect(0x00ff0000, 0, 0, gfxMode->xRes, gfxMode->yRes); + // E + rect(0x00ffffff, 20, 10, 10, 50); + rect(0x00ffffff, 30, 10, 30, 10); + rect(0x00ffffff, 30, 30, 30, 10); + rect(0x00ffffff, 30, 50, 30, 10); + // R + rect(0x00ffffff, 70, 10, 10, 50); + rect(0x00ffffff, 70, 10, 30, 10); + rect(0x00ffffff, 70, 30, 30, 10); + rect(0x00ffffff, 90, 10, 10, 30); + rect(0x00ffffff, 80, 40, 10, 10); + rect(0x00ffffff, 90, 50, 10, 10); + // R + rect(0x00ffffff, 110, 10, 10, 50); + rect(0x00ffffff, 110, 10, 30, 10); + rect(0x00ffffff, 110, 30, 30, 10); + rect(0x00ffffff, 130, 10, 10, 30); + rect(0x00ffffff, 120, 40, 10, 10); + rect(0x00ffffff, 130, 50, 10, 10); + // O + rect(0x00ffffff, 150, 10, 10, 50); + rect(0x00ffffff, 170, 10, 10, 50); + rect(0x00ffffff, 150, 10, 30, 10); + rect(0x00ffffff, 150, 50, 30, 10); + // R + rect(0x00ffffff, 190, 10, 10, 50); + rect(0x00ffffff, 190, 10, 30, 10); + rect(0x00ffffff, 190, 30, 30, 10); + rect(0x00ffffff, 210, 10, 10, 30); + rect(0x00ffffff, 200, 40, 10, 10); + rect(0x00ffffff, 210, 50, 10, 10); + + __asm__ volatile ("cli; hlt" :: "a"(err)); +} + diff --git a/libk/fs/impl.c b/libk/fs/impl.c new file mode 100644 index 0000000..a13cc5f --- /dev/null +++ b/libk/fs/impl.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +superblock_t* impl_superblock = (superblock_t*)SUPERBLOCK_LOC; +fsInfo_t* fsInfo = (fsInfo_t*)FS_INFO_LOC; + +inode_t* getInode(char* path, dirEntry_t* dentries) { + while (dentries->name[0] != '\0') { + if (strcmp(dentries->name, path) == 0) break; + dentries++; + } + if (dentries->name[0] == '\0') { return NULL; } + + inode_t* inode = (inode_t*)BOOT_FIRST_INODE_LOC + dentries->id; + + return inode; +} + +uint8_t loadFile(inode_t* inode, void* dest) { + uint32_t totalBlocks = BYTES2BLOCKS(inode->sizeBytes); + uint32_t offset = 0; + + for (uint8_t i = 0; i < 4 && totalBlocks > 0; i++) { + diskRead(inode->extent[i].block * 8, inode->extent[i].length * 8, dest + offset); + offset += inode->extent[i].length * FS_BLOCK_SIZE; + totalBlocks -= inode->extent[i].length; + } + + if (totalBlocks > 0) { + // TODO: Indirect extents + return 1; + } + + return 0; +} + +void initOpenFileTable() { + fsInfo->openFileTable = malloc(sizeof(FILE) * MAX_OPEN_FILES); + if (fsInfo->openFileTable == NULL) { printf("\e[1MFailed to init file table! Malloc() error.\e[8M"); } + memset(fsInfo->openFileTable, 0, sizeof(FILE) * MAX_OPEN_FILES); + + // offset and ptr are unused in these + stdin = fsInfo->openFileTable + 0; + stdin->_file = 0; + stdin->_flag = O_RDONLY; + + stdout = fsInfo->openFileTable + 1; + stdout->_file = 1; + stdout->_flag = O_WRONLY | O_APPEND; + + stderr = fsInfo->openFileTable + 2; + stderr->_file = 2; + stderr->_flag = O_WRONLY | O_APPEND; + + fsInfo->openFiles = 3; +} + diff --git a/libk/interrupt/exceptions.c b/libk/interrupt/exceptions.c new file mode 100644 index 0000000..e93086d --- /dev/null +++ b/libk/interrupt/exceptions.c @@ -0,0 +1,48 @@ +#include +#include +#include + +// Exception handlers +__attribute__ ((interrupt)) +void excp_divideErr(intFrame_t* iframe) { // ISR 0 + printf("\x1b[1M[ Division Error ]\n\x1b[8M"); + iframe->eip++; +} + +__attribute__ ((interrupt)) +void excp_doubleFault(intFrame_t* iframe, uint32_t errCode) { // ISR 8 + printf("\x1b[1M[ Double Fault ]\n\x1b[8M"); // Error code should be 0 (TODO: Maybe check if it's != 0?) + __asm__ volatile ("cli; hlt"); +} + +__attribute__ ((interrupt)) +void excp_pageFault(intFrame_t* iframe, uint32_t errCode) { // ISR 14 + uint32_t badAddress = 0; + + // cr2 should contain invalid address + __asm__ volatile("movl %%cr2, %0" : "=r"(badAddress)); + + printf("\x1b[1M[ Page Fault : 0x%x ] - Tried to access 0x%x.\n\x1b[8M", errCode, badAddress); + __asm__ volatile ("cli; hlt"); +} + +__attribute__ ((interrupt)) +void excp_reserved(intFrame_t* iframe) { // ISR 15 + print("\x1b[1M[ Unknown Exception ]\n\x1b[8M"); + __asm__ volatile ("cli; hlt"); +} + +// TODO: Add more (because there's always more) + +// Repetative isr definitions +void setupExceptions() { + for (uint8_t i = 0; i < 32; i++) { + idtSetGate(i, excp_reserved, TRAP_GATE_FLAGS); // Doesn't account for err codes, will just halt anyways + } + + idtSetGate(0, excp_divideErr, TRAP_GATE_FLAGS); + idtSetGate(8, excp_doubleFault, TRAP_GATE_FLAGS); + idtSetGate(14, excp_pageFault, TRAP_GATE_FLAGS); + idtSetGate(15, excp_reserved, TRAP_GATE_FLAGS); +} + diff --git a/libk/interrupt/idt.c b/libk/interrupt/idt.c new file mode 100644 index 0000000..dc7918a --- /dev/null +++ b/libk/interrupt/idt.c @@ -0,0 +1,25 @@ +#include +#include + +__attribute__ ((aligned(0x10))) // For performance +idtEntry_t idt[256] = { 0 }; +idtp_t idtp; + +void idtSetGate(uint8_t i, void* handler, uint8_t flags) { + uint32_t offset = (uint32_t)handler; + idtEntry_t* entry = &idt[i]; + + entry->offsetLow = (uint16_t)offset; + entry->selector = 0x08; + entry->zero = 0; + entry->typeAttr = flags; + entry->offsetHigh = (uint16_t)(offset >> 16); +} + +void setupIdt() { + idtp.limit = sizeof(idtEntry_t) * 256; + idtp.base = (uint32_t)&idt; + + __asm__ volatile ("lidt %0" : : "m"(idtp)); +} + diff --git a/libk/interrupt/pic.c b/libk/interrupt/pic.c new file mode 100644 index 0000000..4cb9357 --- /dev/null +++ b/libk/interrupt/pic.c @@ -0,0 +1,79 @@ +#include +#include +#include + +void sendPicEOI(uint8_t irq) { + if (irq >= 8) { + outb(PIC_2_CMD, PIC_EOI); + } + outb(PIC_1_CMD, PIC_EOI); +} + +void disableIrqs() { + outb(PIC_2_DATA, PIC_DISABLE); + outb(PIC_1_DATA, PIC_DISABLE); +} + +void setIrqMask(uint8_t irq) { + uint16_t port; + uint8_t value; + + if (irq < 8) { + port = PIC_1_DATA; + } else { + irq -= 8; + port = PIC_2_DATA; + } + + value = inb(port) | (1 << irq); + outb(port, value); +} + +void unsetIrqMask(uint8_t irq) { + uint16_t port; + uint8_t value; + + if (irq < 8) { + port = PIC_1_DATA; + } else { + irq -= 8; + port = PIC_2_DATA; + } + + value = inb(port) & ~(1 << irq); + outb(port, value); +} + +void remapPic() { + uint8_t pic1Mask = inb(PIC_1_DATA); + uint8_t pic2Mask = inb(PIC_2_DATA); + + // Send Init Control Word 1-4 to both PICs + // ICW 1: bit 0 - send up to 4 ICWs, bit 4 - Init PIC + outb(PIC_1_CMD, 0x11); + ioWait(); // For slower machines + outb(PIC_2_CMD, 0x11); + ioWait(); + + // ICW 2: Where to map IRW bases in IDT + outb(PIC_1_DATA, NEW_IRQ_0); + ioWait(); + outb(PIC_2_DATA, NEW_IRQ_8); + ioWait(); + + // ICW 3: Which IRQ in PIC1 is PIC2; Mapping PIC2 to IRQ 2 + outb(PIC_1_DATA, 0x04); + ioWait(); + outb(PIC_2_DATA, 0x02); + ioWait(); + + // ICW 4 - Set x86 mode + outb(PIC_1_DATA, 0x01); + ioWait(); + outb(PIC_2_DATA, 0x01); + ioWait(); + + outb(PIC_1_DATA, pic1Mask); + outb(PIC_2_DATA, pic2Mask); +} + diff --git a/libk/interrupt/pit.c b/libk/interrupt/pit.c new file mode 100644 index 0000000..03c5343 --- /dev/null +++ b/libk/interrupt/pit.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include +#include + +__attribute__ ((interrupt)) +void timerHandler(intFrame_t* iframe) { + static uint32_t cursorTicks = 0; + cursorTicks++; + + if (!terminal->hideCursor) { // TODO: Make a better cursor drawing thing + if (cursorTicks % 500 == 0) toggleCursor(); + } + + if (*(uint32_t*)SLEEP_TIMER > 0) { --(*(uint32_t*)SLEEP_TIMER); } + + sendPicEOI(0); +} + +void setPitPhase(uint8_t channel, uint8_t opMode, uint16_t hz) { + if (channel > 2 || opMode > 7) { return; } + __asm__ volatile ("cli"); + + // Send command - bits 7-6 channel, 5-4 Access mode, 3-1 operating mode, 0 - Should be zero in x86 + outb(COMMAND, ((channel << 6) | (3 << 4) | (opMode << 1))); + + // Send frequency + uint16_t freq = INPUT_CLK / hz; // I solved an equation to figure this out + outb(CHANNEL_0 + channel, (uint8_t)freq); + outb(CHANNEL_0 + channel, (uint8_t)(freq >> 8)); + + __asm__ volatile ("sti"); +} + +void setupTimer() { // Sets up IRQ 0 - PIT + idtSetGate(0x20, timerHandler, INT_GATE_FLAGS); + unsetIrqMask(0); + setPitPhase(0, 2, 1000); // Default setup: 1000Hz - 1 tick per 1ms +} + diff --git a/libk/interrupt/rtc.c b/libk/interrupt/rtc.c new file mode 100644 index 0000000..1abc3ab --- /dev/null +++ b/libk/interrupt/rtc.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static datetime_t* datetime = (datetime_t*)DATETIME_LOC; + +bool cmosUpdateProgress() { + outb(CMOS_ADDRESS, 0x8a); // Read status reg A, disable NMI + return inb(CMOS_DATA) & 0x80; +} + +uint8_t getRtcRegister(uint8_t reg) { + outb(CMOS_ADDRESS, reg | 0x80); // Disable NMI when sending + return inb(CMOS_DATA); +} + +void enableRtc() { + uint8_t regB = getRtcRegister(0x0b); + outb(CMOS_ADDRESS, 0x8b); + outb(CMOS_DATA, regB | 0x40); // Set bit 6 - periodic int at 1024Hz + + getRtcRegister(0x0c); // Clear pending interrupts +} + +void disableRtc() { + __asm__ volatile ("cli"); + uint8_t regB = getRtcRegister(0x0b); + outb(CMOS_ADDRESS, 0x8b); + outb(CMOS_DATA, regB & 0xbf); // Clear bit 6 + __asm__ volatile ("sti"); +} + +__attribute__ ((interrupt)) void rtcHandler(intFrame_t* iframe) { + datetime_t newDatetime, oldDatetime; + static uint16_t rtcTicks = 0; + + __asm__ volatile ("cli"); + rtcTicks++; + if (rtcTicks % 1024 == 0) { // 1 Second has passed + while (cmosUpdateProgress()); // Wait + + newDatetime.second = getRtcRegister(0); + newDatetime.minute = getRtcRegister(2); + newDatetime.hour = getRtcRegister(4); + newDatetime.day = getRtcRegister(7); + newDatetime.month = getRtcRegister(8); + newDatetime.year = getRtcRegister(9); + + do { + oldDatetime = newDatetime; + + while (cmosUpdateProgress()); // Wait + newDatetime.second = getRtcRegister(0); + newDatetime.minute = getRtcRegister(2); + newDatetime.hour = getRtcRegister(4); + newDatetime.day = getRtcRegister(7); + newDatetime.month = getRtcRegister(8); + newDatetime.year = getRtcRegister(9); + + } while ( + newDatetime.second != oldDatetime.second || + newDatetime.minute != oldDatetime.minute || + newDatetime.hour != oldDatetime.hour || + newDatetime.day != oldDatetime.day || + newDatetime.month != oldDatetime.month || + newDatetime.year != oldDatetime.year + ); + + uint8_t regB = getRtcRegister(0x0b); + if (!(regB & 0x04)) { + newDatetime.second = (newDatetime.second & 0x0f) + ((newDatetime.second >> 4) * 10); + newDatetime.minute = (newDatetime.minute & 0x0f) + ((newDatetime.minute >> 4) * 10); + newDatetime.hour = ((newDatetime.hour & 0x0F) + (((newDatetime.hour & 0x70) / 16) * 10)) | (newDatetime.hour & 0x80); // 12/24 Hour format bs + newDatetime.day = (newDatetime.day & 0x0f) + ((newDatetime.day >> 4) * 10); + newDatetime.month = (newDatetime.month & 0x0f) + ((newDatetime.month >> 4) * 10); + newDatetime.year = (newDatetime.year & 0x0f) + ((newDatetime.year >> 4) * 10); + } + + // Convert 12 to 14 hour format + if (!(regB & 0x02) && (newDatetime.hour & 0x80)) { + newDatetime.hour = ((newDatetime.hour & 0x7f) + 12) % 24; + } + + newDatetime.year += 2000; // Add current century + + //*datetime = newDatetime; + + datetime->second = newDatetime.second; + datetime->minute = newDatetime.minute; + datetime->hour = newDatetime.hour; + datetime->day = newDatetime.day; + datetime->month = newDatetime.month; + datetime->year = newDatetime.year; + + if (true) { // TODO: Probably get rid of this idk + char buf[20] = { 0 }; // "12/12 2012 12:12:12" - Max string 20 chars with null byte + + strcat(buf, itoa(datetime->day, 10)); + strcat(buf, "/"); + strcat(buf, itoa(datetime->month, 10)); + strcat(buf, " "); + strcat(buf, itoa(datetime->year, 10)); + strcat(buf, " "); + if (datetime->hour < 10) strcat(buf, "0"); + strcat(buf, itoa(datetime->hour, 10)); + strcat(buf, ":"); + if (datetime->minute < 10) strcat(buf, "0"); + strcat(buf, itoa(datetime->minute, 10)); + strcat(buf, ":"); + if (datetime->second < 10) strcat(buf, "0"); + strcat(buf, itoa(datetime->second, 10)); + + // The clock is a little offset down (about 0.4 of a character) It does look nice though! + uint8_t len = strlen(buf); + uint32_t x = gfxMode->xRes - len - 1; + char* str = &buf[0]; + for (uint8_t i = 0; i != len; i++, x++) { + drawChar(str[i], x, 0, terminal->fg, terminal->bg); + } + } + } + + getRtcRegister(0x0c); + sendPicEOI(8); + + __asm__ volatile ("sti"); +} + +void setupRtc() { // IRQ 8 - Real Time Clock + idtSetGate(0x28, rtcHandler, INT_GATE_FLAGS); + unsetIrqMask(8); + enableRtc(); +} + diff --git a/libk/interrupt/syscalls.c b/libk/interrupt/syscalls.c new file mode 100644 index 0000000..ec37c45 --- /dev/null +++ b/libk/interrupt/syscalls.c @@ -0,0 +1,194 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * XXX WARNING - Update MAX_SYSCALLS in the handler XXX + */ + +int sys_reserved(sys_regs_t) { + printf("\e[1N\e[6M Illegal use of Reserved() system call! \e[8M\e[8N\n"); + return -1; +} + +// Args: ebx - number of miliseconds +int sys_sleep(sys_regs_t regs) { + uint32_t* sleepTimerTicks = (uint32_t*)SLEEP_TIMER; + *sleepTimerTicks = regs.ebx; + + while (*sleepTimerTicks > 0) { // Wait... + __asm__ volatile ("sti;hlt;cli;"); + } + + return 0; +} + +// Args: ebx - int fd +// ecx - void* buf +// edx - uint32_t len +// Rets: Number of bytes written +int sys_write(sys_regs_t regs) { + int32_t fd = regs.ebx; + void* buf = (void*)regs.ecx; + uint32_t len = regs.edx; + + // TODO: Open fd table? + if (fd == 1) { + return terminalWrite(buf, len); // Call a terminal print function + } else { return -1; } +} + +// TODO: Use a Read() sycall and read from stdin +// Args: ebx - char* buffer +int sys_read(sys_regs_t regs) { + char* s = (char*)regs.ebx; + reads(s); + + return 0; +} + +// Args: ebx - size_t count +// Rets: Pointer to malloc-ed memory +int sys_malloc(sys_regs_t regs) { + uint32_t count = regs.ebx; + + // First Malloc() + if (!mallocListHead) { + mallocInit(count); // Setup malloc linked list + } + + void* ptr = mallocNextNode(count); + mallocMergeFree(); + + return (uint32_t)ptr; +} + +// Args: ebx - void* ptr +int sys_free(sys_regs_t regs) { + void* ptr = (void*)regs.ebx; + mallocFree(ptr); + return 0; +} + +// Args: ebx - path, +// ecx - oflag +// Rets: Opened file descriptor +int sys_open(sys_regs_t regs) { + int fd = 0; + char* path = (char*)regs.ebx; + uint32_t oflag = regs.ecx; + + // TODO: better file finding + inode_t* root = (inode_t*)impl_superblock->rootInodePtr; + loadFile(root, (void*)SCRATCH_BLOCK_LOC); + + inode_t* inode = getInode(path, (dirEntry_t*)SCRATCH_BLOCK_LOC); + if (inode == NULL) { + return -1; + } + + // TODO: check if max open files have'nt been reached + fd = fsInfo->openFiles++; + FILE* fp = fsInfo->openFileTable + fd; + fp->_ptr = (void*)0xd000; + fp->_offset = 0; + fp->_size = inode->sizeBytes; + fp->_flag = oflag; + fp->_file = fd; + + loadFile(inode, fp->_ptr); + + return fd; +} + +// Args: ebx - int fd +// Rets: status +int sys_close(sys_regs_t regs) { + int fd = regs.ebx; + + FILE* fp = fsInfo->openFileTable + fd; + free(fp->_ptr); + fsInfo->openFiles--; + + return 0; +} + +// TODO +int sys_seek(sys_regs_t regs) { return -1; } + +// System call table +int (*syscalls[MAX_SYSCALLS])(sys_regs_t) = { + [SYS_RESERVED] = sys_reserved, + [SYS_SLEEP] = sys_sleep, + [SYS_WRITE] = sys_write, + [SYS_READ] = sys_read, + [SYS_MALLOC] = sys_malloc, + [SYS_FREE] = sys_free, + [SYS_OPEN] = sys_open, + [SYS_CLOSE] = sys_close, + [SYS_SEEK] = sys_seek, +}; + +// int 0x80 - Syscall interrupt, handled by this function +// eax : Syscall number +__attribute__ ((naked)) // No prologue or epilogue, just assembly +void syscallHandler(intFrame_t* iframe) { + // Interrupt - Stack should contain: ss, esp, eflags, cs, eip + // We should also push these regs: ax, gs, fs, es, ds, bp, di, si, dx, cx, bx + __asm__ volatile ( + ".intel_syntax noprefix\n" // We use intel syntax + ".equ MAX_SYSCALLS, 9\n" // Define MAX_SYSCALLS again TODO: I don't want to have to do this + + // Check if syscall exists + "cmp eax, MAX_SYSCALLS - 1\n" + "ja invalidSyscall\n" + + // Call the syscall + "push eax\n" + "push gs\n" + "push fs\n" + "push es\n" + "push ds\n" + "push ebp\n" + "push edi\n" + "push esi\n" + "push edx\n" + "push ecx\n" + "push ebx\n" + "push esp\n" // Push stack pointer again (for variables and such idk) + + "call [syscalls + eax * 4]\n" // Call syscall from table. Syscall number should be in eax + "add esp, 4\n" // Do not override ESP + "pop ebx\n" + "pop ecx\n" + "add esp, 4\n" // Do not override EDX, some syscalls use it + + "pop esi\n" + "pop edi\n" + "pop ebp\n" + "pop ds\n" + "pop es\n" + "pop fs\n" + "pop gs\n" + "add esp, 4\n" // Save eax value + "iretd\n" // Return from interrupt (32 bit) + + // TODO: Send an error or something here + "invalidSyscall:\n" + "mov eax, -1\n" // Current error thing + "iretd\n" + + ".att_syntax" // Switch back to AT&T Syntax (Just in case) + ); +} + diff --git a/libk/keyboard/keyboard.c b/libk/keyboard/keyboard.c new file mode 100644 index 0000000..d013955 --- /dev/null +++ b/libk/keyboard/keyboard.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static const uint8_t US_Keyboard[2][128] = US_KEYBOARD; +keyboardState_t* keyboard = (keyboardState_t*)KEYBOARD_STATE_LOC; + +__attribute__ ((interrupt)) +void keyboardHandler(intFrame_t* iframe) { // TODO: Make this better and be able to read multi-byte scancode + uint8_t scancode = inb(0x60); + char c = US_Keyboard[keyboard->shift][scancode]; + + if (scancode == LEFT_SHIFT_PRESS || scancode == RIGHT_SHIFT_PRESS) { + keyboard->shift = true; + } else if (scancode == LEFT_SHIFT_RELEASE || scancode == RIGHT_SHIFT_RELEASE) { + keyboard->shift = false; + } + + if (scancode & 0x80) { // Keyup + } else if (c != '\0') { + keyboard->character = c; + } + + sendPicEOI(1); +} + +void setupKeyboard() { + idtSetGate(0x21, keyboardHandler, INT_GATE_FLAGS); + unsetIrqMask(1); +} + diff --git a/libk/memory/malloc.c b/libk/memory/malloc.c new file mode 100644 index 0000000..ec0203e --- /dev/null +++ b/libk/memory/malloc.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include + +mallocNode_t* mallocListHead = NULL; +uint32_t mallocVirtualAddr = 0; +uint32_t mallocPhysicalAddr = 0; +uint32_t mallocPages = 0; + +void mallocInit(uint32_t size) { + mallocPages = size / PAGE_SIZE; + if (size % PAGE_SIZE > 0) { mallocPages++; } + + mallocPhysicalAddr = (uint32_t)allocBlocks(mallocPages); + mallocListHead = (mallocNode_t*)mallocVirtualAddr; + + // Map pages + for (uint32_t i = 0, virtualAddr = mallocVirtualAddr; i < mallocPages; i++, virtualAddr += PAGE_SIZE) { + mapPage((void*)(mallocPhysicalAddr + i * PAGE_SIZE), (void*)virtualAddr); + + ptEntry_t* page = getPage(virtualAddr); + SET_ATTR(page, PTE_READ_WRITE); + } + + if (mallocListHead) { + mallocListHead->size = (mallocPages * PAGE_SIZE) - sizeof(mallocNode_t); + mallocListHead->free = true; + mallocListHead->next = NULL; + } +} + +void mallocSplit(mallocNode_t* node, uint32_t size) { + if (node->size < size + sizeof(mallocNode_t)) { return; } // Can't split - node too small + + // Remainder node + mallocNode_t* newNode = (mallocNode_t*)((void*)node + size + sizeof(mallocNode_t)); + newNode->size = node->size - size - sizeof(mallocNode_t); + newNode->free = true; + newNode->next = node->next; + + // Split node + node->size = size; + node->free = false; + node->next = newNode; +} + +void* mallocNextNode(uint32_t size) { + if (size == 0) { return NULL; } // Why would you try that? (undefined behaviour i guess) + + mallocNode_t* current = mallocListHead; + + if (mallocListHead->size == 0) { mallocInit(size); } + + while (((current->size < size) || !current->free) && current->next != NULL) { + current = current->next; + } + + if (current->size == size) { + current->free = false; + } else if (current->size > size + sizeof(mallocNode_t)) { + mallocSplit(current, size); // Modifies current into the right size and makes it point to the remainder + } else { // There's no large enough node -> try to allocate more pages + uint8_t pageCount = 1; + while (current->size + pageCount * PAGE_SIZE < size + sizeof(mallocNode_t)) { + pageCount++; + } + + // Allocate and map new pages + uint32_t virtualAddr = mallocVirtualAddr + mallocPages * PAGE_SIZE; + for (uint32_t i = 0; i < pageCount; i++) { + ptEntry_t page = 0; + uint32_t* temp = allocPage(&page); + + mapPage((void*)temp, (void*)virtualAddr); + SET_ATTR(&page, PTE_READ_WRITE); + virtualAddr += PAGE_SIZE; + current->size += PAGE_SIZE; + mallocPages++; + } + + mallocSplit(current, size); + } + + return (void*)current + sizeof(mallocNode_t); +} + +void mallocMergeFree() { + mallocNode_t* current = mallocListHead; + + while (current && current->next != NULL) { + if (current->free && current->next->free) { + current->size += (current->next->size) + sizeof(mallocNode_t); + current->next = current->next->next; + } + current = current->next; + } +} + +void mallocFree(void* ptr) { + mallocNode_t* current = mallocListHead; + + while (current->next) { + if ((void*)current + sizeof(mallocNode_t) == ptr) { + current->free = true; + mallocMergeFree(); + break; + } + + current = current->next; + } +} + diff --git a/libk/memory/physical.c b/libk/memory/physical.c new file mode 100644 index 0000000..7f775e7 --- /dev/null +++ b/libk/memory/physical.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include + +uint32_t* memoryMap = 0; +uint32_t maxBlocks; +uint32_t usedBlocks = 0; + +void setBlock(uint32_t block) { + // Set the right bit to 1 + memoryMap[block/32] |= (1 << (block % 32)); +} + +void unsetBlock(uint32_t block) { + // Set the right bit to 0 + memoryMap[block/32] &= ~(1 << (block % 32)); +} + +uint8_t testBlock(uint32_t block) { + // Check the bit + return memoryMap[block/32] & (1 << (block % 32)) ? 1 : 0; +} + +// TODO: Refactor whatever the fuck this is +int32_t findFreeBlocks(uint32_t blockCount) { + if (blockCount == 0) { // Error + return -1; + } + + uint32_t maxBlockEntries = maxBlocks / 32; + for (uint32_t i = 0; i < maxBlockEntries; i++) { + if (memoryMap[i] != 0xffffffff) { + for (uint8_t j = 0; j < 32; j++) { + uint32_t block = 1 << j; + + if (!(memoryMap[i] & block)) { + // uint32_t startBlock = i * 32 + block; + // uint32_t freeBlocks = 0; + + for (uint32_t count = i, freeBlocks = 0; count < blockCount; count++) { + if (j + count > 31 && i + 1 <= maxBlocks / 32) { + if (!(memoryMap[i+1] & (1 << (j + count)))) { + freeBlocks++; + } + } else { + if (!(memoryMap[i] & (1 << (j + count)))) { + freeBlocks++; + } + } + + if (freeBlocks == blockCount) { + return i * 32 + j; + } + } + } + } + } + } + + return -1; // No free memory found :/ +} + +void setupPhysicalMemoryManager(uint32_t startAddress, uint32_t size) { + memoryMap = (uint32_t*)startAddress; + maxBlocks = size / BLOCK_SIZE; + usedBlocks = maxBlocks; + + memset((char*)memoryMap, 0xff, maxBlocks / BLOCKS_PER_BYTE); +} + +void initMemoryRegion(uint32_t baseAddress, uint32_t size) { + uint32_t align = baseAddress / BLOCK_SIZE; + uint32_t blockCount = size / BLOCK_SIZE; + + while (blockCount-- > 0) { + unsetBlock(align++); + usedBlocks--; + } + + setBlock(0); // Make sure we don't override the first block that contains IDT, BIOS stuff etc. +} + +void deinitMemoryRegion(uint32_t baseAddress, uint32_t size) { + uint32_t align = baseAddress / BLOCK_SIZE; + uint32_t blockCount = size / BLOCK_SIZE; + + while (blockCount-- > 0) { + setBlock(align++); + usedBlocks++; + } +} + +void* allocBlocks(uint32_t blockCount) { + if ((maxBlocks - usedBlocks) < blockCount) { + return NULL; + } + + int32_t startBlock = findFreeBlocks(blockCount); + if (startBlock == -1) { + return NULL; + } + + for (uint32_t i = 0; i < blockCount; i++) { + setBlock(startBlock + i); + usedBlocks++; + } + + return (void*)(startBlock * BLOCK_SIZE); +} + +void freeBlocks(void* address, uint32_t blockCount) { + uint32_t startBlock = (uint32_t)(address) / BLOCK_SIZE; + + for (uint32_t i = 0; i < blockCount; i++) { + unsetBlock(startBlock + i); + usedBlocks--; + } + + setBlock(0); // Make sure that block 0 is always set +} + diff --git a/libk/memory/virtual.c b/libk/memory/virtual.c new file mode 100644 index 0000000..a8f8e6a --- /dev/null +++ b/libk/memory/virtual.c @@ -0,0 +1,153 @@ +#include +#include +#include +#include +#include + +pageDirectory_t* currentPd = NULL; + +ptEntry_t* getPtEntry(pageTable_t* pt, uint32_t virtualAddress) { + if (pt) return &pt->entries[PT_INDEX(virtualAddress)]; + return NULL; +} + +pdEntry_t* getPdEntry(pageDirectory_t* pd, uint32_t virtualAddress) { + if (pd) return &pd->entries[PT_INDEX(virtualAddress)]; // It it supposed to be PT_INDEX, don't worry + return NULL; +} + +ptEntry_t* getPage(uint32_t virtualAddress) { + pageDirectory_t* pd = currentPd; + pdEntry_t* entry = &pd->entries[PD_INDEX(virtualAddress)]; + pageTable_t* table = (pageTable_t*)PAGE_PHYS_ADDRESS(entry); + ptEntry_t* page = &table->entries[PT_INDEX(virtualAddress)]; + return page; +} + +void* allocPage(ptEntry_t* page) { + void* block = allocBlocks(1); + if (block) { + SET_FRAME(page, (uint32_t)block); + SET_ATTR(page, PTE_PRESENT); + } + + return block; +} + +void freePage(ptEntry_t* page) { + void* address = (void*)PAGE_PHYS_ADDRESS(page); + if (address) { + freeBlocks(address, 1); + } + + CLEAR_ATTR(page, PTE_PRESENT); +} + +uint8_t setPageDirectory(pageDirectory_t* pd) { + if (!pd) { return 1; } // Nuh uh + currentPd = pd; + + // cr3 (Control register 3) - current page dir address + __asm__ volatile("movl %%eax, %%cr3" : : "a"(currentPd)); + + return 0; // Success +} + +void flushTlbEntry(uint32_t virtualAddress) { + __asm__ volatile("cli; invlpg (%0); sti" : : "r"(virtualAddress)); +} + +uint8_t mapPage(void* physicalAddr, void* virtualAddr) { + pageDirectory_t* pd = currentPd; + pdEntry_t* entry = &pd->entries[PD_INDEX((uint32_t)virtualAddr)]; + + if (!TEST_ATTR(entry, PTE_PRESENT)) { + // Assuming that the page is not allocated since it's not present + pageTable_t* table = (pageTable_t*)allocBlocks(1); + if (!table) return 1; // Out of memory!! + + // Clear page table (may be slow?) + memset(table, 0, sizeof(pageTable_t)); + + pdEntry_t* entry = &pd->entries[PD_INDEX((uint32_t)virtualAddr)]; + // Enable attributes and map in table + SET_ATTR(entry, PDE_PRESENT); + SET_ATTR(entry, PDE_READ_WRITE); + SET_FRAME(entry, (uint32_t)table); + } + + pageTable_t* table = (pageTable_t*)PAGE_PHYS_ADDRESS(entry); + ptEntry_t* page = &table->entries[PT_INDEX((uint32_t)virtualAddr)]; + + SET_ATTR(page, PTE_PRESENT); + SET_FRAME(page, (uint32_t)physicalAddr); + + return 0; // Success +} + +void unmapPage(void* virtualAddress) { + ptEntry_t* page = getPage((uint32_t)virtualAddress); + + SET_FRAME(page, 0); + CLEAR_ATTR(page, PDE_PRESENT); +} + +uint8_t setupVirtualMemoryManager() { + // Create a default page dir + pageDirectory_t* dir = (pageDirectory_t*)allocBlocks(3); + + if (!dir) { return 1; } // Out of memory + + memset(dir, 0, sizeof(pageDirectory_t)); + for (uint32_t i = 0; i < 1024; i++) { + dir->entries[i] = 0x02; // Supervisor, r/w, not present + } + + // Alloc default page table + pageTable_t* table = (pageTable_t*)allocBlocks(1); + if (!table) { return 1; } // Out of memory + + // Alloc a 3GB page + pageTable_t* table3gb = (pageTable_t*)allocBlocks(1); + if (!table) { return 1; } // Out of memory + + memset(table, 0, sizeof(pageTable_t)); + memset(table3gb, 0, sizeof(pageTable_t)); + + // Identity map first 4MB + for (uint32_t i = 0, frame = 0, virt = 0; i < 1024; i++, frame += PAGE_SIZE, virt += PAGE_SIZE) { + ptEntry_t page = 0; + SET_ATTR(&page, PTE_PRESENT); + SET_ATTR(&page, PTE_READ_WRITE); + SET_FRAME(&page, frame); + + table3gb->entries[PT_INDEX(virt)] = page; + } + + // Map kernel to 3GB+ + for (uint32_t i = 0, frame = KERNEL_LOC, virt = 0xc0000000; i < 1024; i++, frame += PAGE_SIZE, virt += PAGE_SIZE) { + ptEntry_t page = 0; + SET_ATTR(&page, PTE_PRESENT); + SET_ATTR(&page, PTE_READ_WRITE); + SET_FRAME(&page, frame); + + table->entries[PT_INDEX(virt)] = page; + } + + pdEntry_t* entry = &dir->entries[PD_INDEX(0xc0000000)]; + SET_ATTR(entry, PDE_PRESENT); + SET_ATTR(entry, PDE_READ_WRITE); + SET_FRAME(entry, (uint32_t)table); + + pdEntry_t* entry2 = &dir->entries[PD_INDEX(0x00000000)]; + SET_ATTR(entry2, PDE_PRESENT); + SET_ATTR(entry2, PDE_READ_WRITE); + SET_FRAME(entry2, (uint32_t)table3gb); + + setPageDirectory(dir); + + // ENABLE PAGING!!! Set PG bit 31 and PE bit 0 in cr0 + __asm__ volatile("movl %cr0, %eax; orl $0x80000001, %eax; movl %eax, %cr0"); + return 0; // Success +} + diff --git a/libk/ports/io.c b/libk/ports/io.c new file mode 100644 index 0000000..fd70921 --- /dev/null +++ b/libk/ports/io.c @@ -0,0 +1,29 @@ +#include +#include + +// Port functions +uint8_t inb(uint16_t port) { + uint8_t result; + __asm__ volatile("inb %1, %0" : "=a"(result) : "Nd"(port)); + return result; +} + +void outb(uint16_t port, uint8_t data) { + __asm__ volatile("outb %0, %1" :: "a"(data), "Nd"(port)); +} + +uint16_t inw(uint16_t port) { + uint16_t result; + __asm__ volatile("inw %1, %0" : "=a"(result) : "Nd"(port)); + return result; +} + +void outw(uint16_t port, uint16_t data) { + __asm__ volatile("outw %0, %1" :: "a"(data), "Nd"(port)); +} + +void ioWait() { + // Waits ~1 I/O Cycle (Linux uses this so it should be good) + __asm__ volatile("outb %%al, $0x80" : : "a"(0)); +} + diff --git a/libk/screen/gfxmode.c b/libk/screen/gfxmode.c new file mode 100644 index 0000000..60eef43 --- /dev/null +++ b/libk/screen/gfxmode.c @@ -0,0 +1,20 @@ +#include +#include +#include + +modeInfoBlock_t* gfxMode = (modeInfoBlock_t*)MODE_INFO_BLOCK_LOC; + +uint32_t convertColor(uint32_t color) { + if (gfxMode->bpp == 8) { // Uses VGA Color pallete, idk how to support that + return color & 0xff; + } + + // TODO: !! Important !! - Is should be divided by 255.0 (for floats), but using '-mgeneral-regs-only' removes fp-registers and + // wants to use some dumb functions for converting fp numbers in the stdlib (that we don't have) + uint8_t red = ((color >> 16) & 0xff) * (((1 << gfxMode->linearRedMaskSize) - 1) / 255); + uint8_t green = ((color >> 8 ) & 0xff) * (((1 << gfxMode->linearGreenMaskSize) - 1) / 255); + uint8_t blue = ((color ) & 0xff) * (((1 << gfxMode->linearBlueMaskSize) - 1) / 255); + + return (red << gfxMode->redFieldPos) | (green << gfxMode->greenFieldPos) | (blue << gfxMode->blueFieldPos); +} + diff --git a/libk/screen/graphics.c b/libk/screen/graphics.c new file mode 100644 index 0000000..e615b3c --- /dev/null +++ b/libk/screen/graphics.c @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include + +void drawPixel(int32_t x, int32_t y, uint32_t color) { + uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr; + uint8_t bytesPerPx = gfxMode->bpp / 8; + uint32_t convColor = convertColor(color); // Idk if i should convert this for every px or just put in a preconverted color + + uint32_t offset = ((y * gfxMode->xRes) + x) * bytesPerPx; + + for (uint8_t i = 0; i < bytesPerPx; i++) { + vidmem[offset + i] = (uint8_t)(convColor >> (i*8)); + } +} + +// Source: https://en.wikipedia.org/wiki/Bresenham's_line_algorithm +void drawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color) { + int32_t dx = abs(x2 - x1); + int32_t dy = -abs(y2 - y1); + int8_t sx = (x1 < x2) ? 1 : -1; + int8_t sy = (y1 < y2) ? 1 : -1; + int16_t err = dx + dy; + + // TODO: Sometimes the condition isn't met for some reason and it breaks everything + while (!(x1 == x2 && y1 == y2)) { + drawPixel(x1, y1, color); + + if (err * 2 >= dy) { + err += dy; + x1 += sx; + } + if (err * 2 <= dx) { + err += dx; + y1 += sy; + } + } +} + +void drawRect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color) { + drawLine(x1, y1, x2, y1, color); + drawLine(x2, y1, x2, y2, color); + drawLine(x2, y2, x1, y2, color); + drawLine(x1, y2, x1, y1, color); +} + +void drawTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, uint32_t color) { + drawLine(x1, y1, x2, y2, color); + drawLine(x2, y2, x3, y3, color); + drawLine(x3, y3, x1, y1, color); +} + +void drawCircle(int32_t x, int32_t y, uint16_t radius, uint32_t color) { + int16_t offX = 0; + int16_t offY = radius; + int16_t p = 1 - radius; + + // Draw 8 octant points + drawPixel(x + offX, y + offY, color); + drawPixel(x - offX, y + offY, color); + drawPixel(x + offX, y - offY, color); + drawPixel(x - offX, y - offY, color); + drawPixel(x + offY, y + offX, color); + drawPixel(x - offY, y + offX, color); + drawPixel(x + offY, y - offX, color); + drawPixel(x - offY, y - offX, color); + + while (offX < offY) { + offX++; + if (p < 0) p += 2 * offX + 1; + else { + offY--; + p += 2 * (offX - offY) + 1; + } + + drawPixel(x + offX, y + offY, color); + drawPixel(x - offX, y + offY, color); + drawPixel(x + offX, y - offY, color); + drawPixel(x - offX, y - offY, color); + drawPixel(x + offY, y + offX, color); + drawPixel(x - offY, y + offX, color); + drawPixel(x + offY, y - offX, color); + drawPixel(x - offY, y - offX, color); + } +} + +// Recursive (may need large stack) +// TODO: Fix this for all bpp values +void boundaryFill(int32_t x, int32_t y, uint32_t fillColor, uint32_t boundaryColor) { + uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr; + uint8_t bytesPerPx = (gfxMode->bpp+1) / 8; + uint32_t convColorF = convertColor(fillColor); + uint32_t convColorB = convertColor(boundaryColor); + + uint32_t offset = (y * gfxMode->xRes + x) * bytesPerPx; + + uint8_t draw = 0; + for (uint8_t i = 0; i < bytesPerPx; i++) { + if (vidmem[offset + i] != (uint8_t)(convColorF >> (i*8)) && vidmem[offset + i] != (uint8_t)(convColorB >> (i*8))) { + draw = 1; + break; + } + } + + if (draw) { + for (uint8_t i = 0; i < bytesPerPx; i++) { + vidmem[offset + i] = (uint8_t)(convColorF >> (i*8)); + } + + boundaryFill(x + 1, y, fillColor, boundaryColor); + boundaryFill(x, y + 1, fillColor, boundaryColor); + boundaryFill(x - 1, y, fillColor, boundaryColor); + boundaryFill(x, y - 1, fillColor, boundaryColor); + } +} + +// TODO: After i fix boundary fill, uncomment it from these functions +void fillRect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint32_t color) { + int32_t cx = (x1 + x2) / 2; + int32_t cy = (y1 + y2) / 2; + + drawRect(x1, y1, x2, y2, color - 1); + boundaryFill(cx, cy, color, color - 1); + drawRect(x1, y1, x2, y2, color); +} + +void fillTriangle(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, uint32_t color) { + int32_t cx = (x1 + x2 + x3) / 3; + int32_t cy = (y1 + y2 + y3) / 3; + + drawTriangle(x1, y1, x2, y2, x3, y3, color - 1); + boundaryFill(cx, cy, color, color - 1); + drawTriangle(x1, y1, x2, y2, x3, y3, color); +} + +void fillCircle(int32_t x, int32_t y, uint16_t radius, uint32_t color) { + drawCircle(x, y, radius, color - 1); + // boundaryFill(x, y, color, color - 1); TODO: It just doesn't feel like working here and hangs + drawCircle(x, y, radius, color); +} + diff --git a/libk/screen/text.c b/libk/screen/text.c new file mode 100644 index 0000000..06ac37c --- /dev/null +++ b/libk/screen/text.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include + +// TODO: Reimplement larger text +void drawChar(char c, uint32_t x, uint32_t y, uint32_t fgColor, uint32_t bgColor) { + // Font info + font_t* font = (font_t*)FONT_LOC; + uint8_t charWidth = font->width; + uint8_t charHeight = font->height; + // uint8_t bitmapRowLen = (charWidth - 1) / 8 + 1; // TODO: Larger font support + + // Video stuff + uint8_t bytesPerPx = (gfxMode->bpp+7) / 8; + uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr; + uint32_t offset = (gfxMode->xRes * y * charHeight + x * charWidth) * bytesPerPx; + + uint8_t* bitmap = &font->data[(c - 1) * charHeight]; + for (uint8_t i = 0; i < charHeight; i++) { // Rows + uint8_t bitmapRow = bitmap[i]; + uint32_t color = convertColor((bitmapRow & 0x80) ? fgColor : bgColor); + + for (uint8_t j = 0; j < charWidth * bytesPerPx; ++j) { // Cols + uint8_t byte = j % bytesPerPx; + vidmem[offset + j] = (uint8_t)(color >> (8 * byte)); + + if (byte == bytesPerPx - 1) { + bitmapRow = bitmapRow << 1; + color = convertColor((bitmapRow & 0x80) ? fgColor : bgColor); + } + } + + offset += gfxMode->linearBytesPerScanline; // gfxMode->xRes * bytesPerPx + } +} + +void scroll() { // TODO: Make this faster (still kinda slow, but memcpy32() helped alot) + uint8_t charHeight = ((font_t*)FONT_LOC)->height; + if (terminal->y+1 < terminal->height) { return; } // Check if we should scroll + + uint32_t bytesPerLine = charHeight * gfxMode->bytesPerScanline; + uint32_t lines = terminal->height; + uint32_t vidmem = gfxMode->physicalBasePtr; + + for (uint32_t i = 1; i < lines; i++) { + uint32_t address = vidmem + i * bytesPerLine; + memcpy32((char*)address, (char*)(address - bytesPerLine), bytesPerLine); + } + + uint32_t color = convertColor(terminal->bg); + uint8_t* lastLine = (uint8_t*)(vidmem + (lines-1) * bytesPerLine); + uint8_t bytesPerPx = (gfxMode->bpp+1) / 8; + + for (uint32_t i = 0; i < bytesPerLine; i++) { + for (uint8_t j = 0; j < bytesPerPx; j++) { + lastLine[j] = (uint8_t)(color >> (j * 8)); + } + lastLine += bytesPerPx; + } + + terminal->y--; +} + +// TODO: Make this comply with the new terminal.h thing! +void clearScreen(uint32_t bgColor) { + uint8_t* vidmem = (uint8_t*)gfxMode->physicalBasePtr; + uint8_t bytesPerPx = (gfxMode->bpp+1) / 8; + + terminal->x = 0; + terminal->y = 0; + + uint32_t color = convertColor(bgColor); + + for (uint32_t i = 0; i < gfxMode->xRes; i++) { // Clear one line of pixels + for (uint8_t j = 0; j < bytesPerPx; j++) { + vidmem[j] = (uint8_t)(color >> (j * 8)); + } + vidmem += bytesPerPx; + } + + vidmem -= gfxMode->bytesPerScanline; + + for (uint32_t i = 0; i < gfxMode->yRes; i++) { // Copy that line to clear the entire screen (using memcpy32 is fast!) + memcpy32(vidmem, vidmem + gfxMode->bytesPerScanline, gfxMode->bytesPerScanline); + vidmem += gfxMode->bytesPerScanline; + } +} + diff --git a/libk/sound/pcspk.c b/libk/sound/pcspk.c new file mode 100644 index 0000000..d46bea9 --- /dev/null +++ b/libk/sound/pcspk.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include + +void enableSpeaker() { + uint8_t temp = inb(PC_SPEAKER); + outb(PC_SPEAKER, temp | 0x03); // Set first 2 bits +} + +void disableSpeaker() { + uint8_t temp = inb(PC_SPEAKER); + outb(PC_SPEAKER, temp & 0xfc); // Set first 2 bits +} + +void playNote(note_t note, uint32_t ms) { + setPitPhase(2, 3, note); + sleep(ms); +} + +void rest(uint32_t ms) { + setPitPhase(2, 3, 30000); // Unhearable noise + sleep(ms); +} + diff --git a/libk/terminal/terminal.c b/libk/terminal/terminal.c new file mode 100644 index 0000000..26c4176 --- /dev/null +++ b/libk/terminal/terminal.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +terminal_t* terminal = (terminal_t*)TERMINAL_INFO_LOC; + +int32_t terminalWrite(const void* buf, uint32_t len) { // TODO fix font size + terminal->width = gfxMode->xRes / 8;//*(uint8_t*)(FONT_LOC); + terminal->height = gfxMode->yRes / 16;//*(uint8_t*)(FONT_LOC+1); + + char* str = (char*)buf; + uint32_t i; + + // Do we need to check for NULL? Can we just skip it/ignore it? + for (i = 0; i < len && str[i] != '\0'; i++) { + if (str[i] == '\n') { + drawChar(' ', terminal->x, terminal->y, terminal->fg, terminal->bg); + terminal->y++; + terminal->x = 0; + } else if (str[i] == '\b') { + drawChar(' ', terminal->x, terminal->y, terminal->fg, terminal->bg); + if (terminal->x == 0) { + terminal->x = terminal->width - 1; + terminal->y--; // Y could be 0? + } else { + terminal->x--; + } + drawChar(' ', terminal->x, terminal->y, terminal->fg, terminal->bg); + } else if (str[i] == '\x1b') { // Escape sequence + if (str[++i] != '[') { // TODO: Support more types of escape sequences + i--; + continue; + } + + i++; + uint32_t args[8] = { 0 }; + uint8_t argc = 0; + while (1) { // I'm not 100% sure this works, but i'd like to imagine it does + if (argc > 8) break; // Max arg count? idk + + uint32_t value = atoi(&str[i]); + args[argc++] = value; + + while (value != 0) { // Skip by the number string + value /= 10; + i++; + } + + if (str[i] != ';') break; + i++; + } + + switch (str[i]) { // TODO: Add default values (see docs/escape.txt) + case 'A': // Cursor up + terminal->y -= args[0]; + break; + case 'B': // Cursor down + terminal->y += args[0]; + break; + case 'C': // Cursor left + terminal->x -= args[0]; + break; + case 'D': // Cursor right + terminal->x += args[0]; + break; + case 'E': // nth row + terminal->x = args[0]; + break; + case 'F': // nth col + terminal->y = args[0]; + break; + case 'G': // show/hide cursor + terminal->hideCursor = args[0] ? false : true; + break; + case 'H': // move cursor to (x,y) + terminal->x = args[0]; + terminal->y = args[1]; + break; + case 'I': // RESERVED + case 'J': // Erase screen + clearScreen(terminal->bg); + break; + case 'K': // Erase line + break; // TODO + case 'L': // Erase collumn + break; // TODO + case 'M': // Set FG + if (args[0] < 8) { + terminal->fg = codeToColor(args[0]); + } else if (args[0] == 8) { + terminal->fg = FG_COLOR; + } + break; + case 'N': // Set BG + if (args[0] < 8) { + terminal->bg = codeToColor(args[0]); + } else if (args[0] == 8) { + terminal->bg = BG_COLOR; + } + break; + default: break; + } + } else { + drawChar(str[i], terminal->x, terminal->y, terminal->fg, terminal->bg); + terminal->x++; + + if (terminal->x >= terminal->width) { // Go to next line + terminal->y++; + terminal->x = 0; + } + } + } + scroll(); + + return i; // Number of characters that were printed +} + +void toggleCursor() { + static bool visible = false; + visible = !visible; + + drawChar(visible ? 127 : ' ', terminal->x, terminal->y, terminal->fg, terminal->bg); +} + diff --git a/makedisk.c b/makedisk.c index 3820ca5..cc31123 100644 --- a/makedisk.c +++ b/makedisk.c @@ -30,8 +30,8 @@ fileInfo_t files[] = { // TODO: Not have to list all of the files, loop through { BIN_DIR"testfont.fnt" }, /* Userspace files */ { "./src/fs/test.txt" }, - { BIN_DIR"calc.bin" }, - { BIN_DIR"edit.bin" }, + //{ BIN_DIR"calc.bin" }, + //{ BIN_DIR"edit.bin" }, }; superblock_t superblock = { 0 }; diff --git a/src/kernel.c b/src/kernel.c index daa0d5c..1f86fbf 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -5,19 +5,20 @@ #include #include #include - #include #include #include #include #include #include +#include #include #include +#include +#include #include #include #include - #include #include #include @@ -29,9 +30,6 @@ // FS things char* cwd; -FILE* openFileTable = (FILE*)OPEN_FILE_TABLE_LOC; -uint32_t openFiles; - // Function declarations void listFiles(); void printRegs(); @@ -87,6 +85,7 @@ void main() { // Terminal setup terminal->fg = FG_COLOR; terminal->bg = BG_COLOR; + clear(); printf("kern.\n\n"); @@ -239,7 +238,7 @@ void main() { printf("Command not found: %s\n", fileName); continue; } - FILE* fp = openFileTable + _f->_file; + FILE* fp = fsInfo->openFileTable + _f->_file; printf("%d: 0x%x Bytes\n", fp->_file, fp->_size); for (size_t i = 0; i < fp->_size; i++) { @@ -368,24 +367,3 @@ void printPhysicalMemmap() { printf("Free blocks: %d\n\n", maxBlocks - usedBlocks); } -void initOpenFileTable() { - openFileTable = malloc(sizeof(FILE) * MAX_OPEN_FILES); - if (openFileTable == NULL) { printf("\e[1MFailed to init file table! Malloc() error.\e[8M"); } - memset(openFileTable, 0, sizeof(FILE) * MAX_OPEN_FILES); - - // offset and ptr are unused in these - stdin = openFileTable + 0; - stdin->_file = 0; - stdin->_flag = O_RDONLY; - - stdout = openFileTable + 1; - stdout->_file = 1; - stdout->_flag = O_WRONLY | O_APPEND; - - stderr = openFileTable + 2; - stderr->_file = 2; - stderr->_flag = O_WRONLY | O_APPEND; - - openFiles = 3; -} - diff --git a/src/stage3.c b/src/stage3.c index 65b40a5..4860862 100644 --- a/src/stage3.c +++ b/src/stage3.c @@ -1,15 +1,14 @@ #include #include #include +#include +#include +#include #include #include #include -#include -#include #include -void bigError(); - __attribute__ ((section("entry"))) void main() { // Physical memory manager setup @@ -34,7 +33,7 @@ void main() { superblock_t* sb = (superblock_t*)SUPERBLOCK_LOC; sb->rootInodePtr = BOOT_FIRST_INODE_LOC + sizeof(inode_t); inode_t* root = (inode_t*)sb->rootInodePtr; - diskRead(root->extent[0].block * 8, root->extent[0].length * 8, (void*)SCRATCH_BLOCK_LOC); + loadFile(root, (void*)SCRATCH_BLOCK_LOC); inode_t* inode; if ((inode = getInode("kernel.bin", (dirEntry_t*)SCRATCH_BLOCK_LOC)) == NULL) { @@ -42,10 +41,11 @@ void main() { bigError(0xDEAD); } else { loadFile(inode, (void*)KERNEL_LOC); } + font_t* font = (font_t*)FONT_LOC; if ((inode = getInode("term16n.fnt", (dirEntry_t*)SCRATCH_BLOCK_LOC)) != NULL) { - loadFile(inode, (void*)FONT_LOC); + loadFile(inode, font); } else if ((inode = getInode("testfont.fnt", (dirEntry_t*)SCRATCH_BLOCK_LOC)) != NULL) { - loadFile(inode, (void*)FONT_LOC); + loadFile(inode, font); } else { // No font found, bad. bigError(0xBeef);