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 0d4121c..12bc63e 100644 Binary files a/kern.iso and b/kern.iso differ 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);