diff --git a/.gitignore b/.gitignore index 1b646bc..6827c05 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.o build/ kernel.elf -blankos-fat.img +blankos.iso +iso/ i386-elf-7.5.0-Linux-x86_64/ i386-elf-7.5.0-Linux-x86_64.tar.xz diff --git a/README.md b/README.md index 78f8577..f37fb93 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ The long-term goal of this OS is to be capable of running user programs and havi Download the latest BlankOS disk image from the "Releases" tab, and start it using the QEMU emulator: ``` -qemu-system-i386 blankOS-i386-0.3.45.img +qemu-system-i386 blankOS-i386-0.3.55.iso ``` ## Building from source @@ -47,7 +47,7 @@ To run the OS on real hardware, you'll first need to have a BIOS-compatible comp Burn your image file onto a USB stick: ``` -sudo dd bs=4M if=blankos-fat.img of=/dev/sdX status=progress oflag=sync +sudo dd bs=4M if=blankos.iso of=/dev/sdX status=progress oflag=sync ``` Replace `sdX` with your USB drive name (you can find it by doing `sudo fdisk -l`). @@ -56,7 +56,7 @@ Tada! You now have a working BlankOS USB stick. Go ahead and try it out! ## Debugging (QEMU w/ GDB) ``` -qemu-system-i386 -s -S -drive file=blankos-fat.img,format=raw +qemu-system-i386 -s -S -drive file=blankos.iso,format=raw ``` In another shell: @@ -68,7 +68,7 @@ gdb kernel.elf ## Documentation -Two other documents are available to help you understand the project better. One is the User's Manual, labelled [USERS.md](USERS.md), and the other one is the Developer's Manual, labelled [DEVELOPERS.md](DEVELOPERS.md). They are full of useful resources around Blank OS. You'll learn how to use the system and how to contribute to it. +Two other documents are available to help you understand the project better. One is the User's Manual, labelled [USERS.md](docs/USERS.md), and the other one is the Developer's Manual, labelled [DEVELOPERS.md](docs/DEVELOPERS.md). They are full of useful resources around Blank OS. You'll learn how to use the system and how to contribute to it. ### Resources @@ -79,6 +79,7 @@ Two other documents are available to help you understand the project better. One - the Intel [64 and IA-32 Architectures Software Developer Manuals](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html) - [Bran's Kernel Development Tutorial](http://www.osdever.net/bkerndev/index.php) - Ralf Brown's Interrupt List +- the [little book about OS development](https://littleosbook.github.io/) by Erik Helin and Adam Renberg ### ⚠️ Disclaimer @@ -90,8 +91,9 @@ This is a hobbyist operating system kernel and it comes without any warranty wha - [X] Common basic structures (IDT, GDT, ISRs, IRQs) - [X] Common drivers (framebuffer, keyboard, serial, timer) - [X] Kernel-space utilities (shell, simple programs) -- [ ] FAT32 filesystem -- [ ] Paging/Page Frame Allocation +- [ ] Filesystem (FAT32 or VFS ramdisk) +- [ ] Changing the default VGA font +- [X] Paging/Page Frame Allocation - [ ] TCP/IP Network stack - [ ] Getting to Ring-3 (userspace) - [ ] Multitasking (via round robin scheduling) diff --git a/DEVELOPERS.md b/docs/DEVELOPERS.md similarity index 100% rename from DEVELOPERS.md rename to docs/DEVELOPERS.md diff --git a/USERS.md b/docs/USERS.md similarity index 100% rename from USERS.md rename to docs/USERS.md diff --git a/grub.cfg b/grub.cfg index 4543097..92cb693 100644 --- a/grub.cfg +++ b/grub.cfg @@ -1,4 +1,5 @@ menuentry "Blank OS" { - multiboot /boot/kernel.elf + set gfxpayload=1024x768x32 + multiboot2 /boot/kernel.elf boot } diff --git a/include/fonts/UniCyr_8x16.psf b/include/fonts/UniCyr_8x16.psf new file mode 100644 index 0000000..dcfd01d Binary files /dev/null and b/include/fonts/UniCyr_8x16.psf differ diff --git a/link.ld b/link.ld index bc9c8dd..f697fc2 100644 --- a/link.ld +++ b/link.ld @@ -1,30 +1,31 @@ ENTRY(loader) SECTIONS { - /* Address to load at; 1MB */ + /* Address to load at; 2MB */ - . = 0x00100000; + /*. = 2M;*/ - .__mbHeader : { - *(.__mbHeader) + .multiboot_header ALIGN(4K) : { + *(.multiboot_header) } - /* Align relevant sections at 4KB */ - .text ALIGN (0x1000) : + .text ALIGN (4K) : { *(.text) *(.rodata) } - .data ALIGN (0x1000) : + .data ALIGN (4K) : { *(.data) } - .bss ALIGN (0x1000) : + .bss ALIGN (4K) : { *(COMMON) *(.bss) } + + end = .; _end = .; __end = .; } diff --git a/makefile b/makefile index 2ea730b..918e65e 100644 --- a/makefile +++ b/makefile @@ -9,24 +9,29 @@ KERNEL_DIR = $(SRC_DIR)/kernel LIBC_DIR = $(SRC_DIR)/libc PROGRAMS_DIR = $(SRC_DIR)/programs DRIVERS_DIR = $(SRC_DIR)/drivers +INCLUDE_DIR = include +FONTS_DIR = $(INCLUDE_DIR)/fonts OBJ_DIR = build C_SOURCES = $(wildcard $(KERNEL_DIR)/*.c) $(wildcard $(LIBC_DIR)/*.c) $(wildcard $(PROGRAMS_DIR)/*.c) $(wildcard $(DRIVERS_DIR)/*.c) ASM_SOURCES = $(wildcard $(KERNEL_DIR)/*.s) $(wildcard $(LIBC_DIR)/*.s) $(wildcard $(PROGRAMS_DIR)/*.s) $(wildcard $(DRIVERS_DIR)/*.s) -OBJECTS = $(patsubst $(SRC_DIR)/%, $(OBJ_DIR)/%, $(C_SOURCES:.c=.o) $(ASM_SOURCES:.s=.o)) +OBJECTS = $(patsubst $(SRC_DIR)/%, $(OBJ_DIR)/%, $(C_SOURCES:.c=.o) $(ASM_SOURCES:.s=.o)) TOOLCHAIN_SRC = https://newos.org/toolchains/i386-elf-7.5.0-Linux-x86_64.tar.xz TOOLCHAIN_FILE = i386-elf-7.5.0-Linux-x86_64.tar.xz +FONT_OBJ = $(OBJ_DIR)/fonts/UniCyr_8x16.o +FONT_SRC = $(FONTS_DIR)/UniCyr_8x16.psf + all: $(OBJ_DIR) kernel.elf $(OBJ_DIR): mkdir -p $(OBJ_DIR) - mkdir -p $(OBJ_DIR)/kernel $(OBJ_DIR)/libc $(OBJ_DIR)/programs $(OBJ_DIR)/drivers + mkdir -p $(OBJ_DIR)/kernel $(OBJ_DIR)/libc $(OBJ_DIR)/programs $(OBJ_DIR)/drivers $(OBJ_DIR)/fonts -kernel.elf: $(OBJECTS) - ld $(LDFLAGS) $(OBJECTS) -o kernel.elf +kernel.elf: $(OBJECTS) $(FONT_OBJ) + ld $(LDFLAGS) $(OBJECTS) $(FONT_OBJ) -o kernel.elf $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(CC) $(CFLAGS) $< -o $@ @@ -34,18 +39,28 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(OBJ_DIR)/%.o: $(SRC_DIR)/%.s $(AS) $(ASFLAGS) $< -o $@ +$(FONT_OBJ): $(FONT_SRC) | $(OBJ_DIR)/fonts + objcopy -O elf32-i386 -B i386 -I binary $(FONT_SRC) $(FONT_OBJ) + +$(OBJ_DIR)/fonts: + mkdir -p $(OBJ_DIR)/fonts + toolchain: wget $(TOOLCHAIN_SRC) tar xf $(TOOLCHAIN_FILE) -blankos-fat.img: - sudo ./setup.sh +iso: kernel.elf + mkdir -p iso/boot/grub + cp kernel.elf iso/boot/kernel.elf + cp grub.cfg iso/boot/grub/grub.cfg + grub-mkrescue iso -o blankos.iso -run: blankos-fat.img - qemu-system-i386 -drive file=blankos-fat.img,format=raw +run: iso + qemu-system-i386 -drive file=blankos.iso,format=raw debug: - qemu-system-i386 -s -S -drive file=blankos-fat.img,format=raw + qemu-system-i386 -s -S -drive file=blankos.iso,format=raw clean: - rm -rf $(OBJ_DIR) kernel.elf blankos-fat.img $(TOOLCHAIN_FILE) + rm -rf $(OBJ_DIR) kernel.elf blankos.iso $(TOOLCHAIN_FILE) + diff --git a/setup.sh b/setup.sh deleted file mode 100755 index 2ae0904..0000000 --- a/setup.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash - -# A script to create a FAT32 loopback device, place a kernel onto it, and install GRUB. -# Inspired by JakeSteinburger's SpecOS setup script! - -if [ "$EUID" -ne 0 ]; then - echo "Please execute this script with root privileges." - exit -fi - -if [ -f "blankos-fat.img" ]; then - echo "Deleting previous disk image..." - rm blankos-fat.img -fi - -if [ -d "/mnt/blankos" ]; then - echo "Deleting previous mountpoint..." - rm -rf /mnt/blankos -fi - -echo "Creating new mountpoint..." -mkdir /mnt/blankos - -echo "Creating an empty disk image..." -dd if=/dev/zero of=blankos-fat.img bs=512 count=131072 - -echo "Appending a parition to disk image..." -fdisk blankos-fat.img << EOF -n -p -1 - - -a -w -EOF - -echo "Creating loopback devices..." -losetup -fP blankos-fat.img - -# Get first partition loopback -LOOP_DEVICE=$(losetup -l | grep blankos-fat.img | awk '{print $1}') -PARTITION="${LOOP_DEVICE}p1" - -echo "Creating FAT32 partition..." -mkfs.vfat -F 32 $PARTITION - -echo "Mounting partition..." -mount $PARTITION /mnt/blankos - -echo "Installing GRUB on $LOOP_DEVICE" -grub-install --root-directory=/mnt/blankos --target=i386-pc --no-floppy --modules="normal part_msdos fat multiboot" $LOOP_DEVICE - -echo "Copying kernel file and GRUB configuration file..." - -cp kernel.elf /mnt/blankos/boot/ -cp grub.cfg /mnt/blankos/boot/grub/ - -echo "Appending test files..." -mkdir /mnt/blankos/hello -echo "Hello, world from FAT32 text file." > /mnt/blankos/hello/testfile.txt - -# cp program.elf /mnt/blankos/programs/ -# In the future, when the OS can load programs and parse ELF - -echo "Unmounting partition..." -umount /mnt/blankos - -echo "Freeing loopback devices..." -losetup -d $LOOP_DEVICE - -echo "Fixing disk image permissions..." -sudo chmod 666 blankos-fat.img - -echo "The blankos-fat.img disk image is ready for use with QEMU or real hardware." diff --git a/src/drivers/ata.c b/src/drivers/ata.c new file mode 100644 index 0000000..4582d6a --- /dev/null +++ b/src/drivers/ata.c @@ -0,0 +1,77 @@ +#include "../libc/stdint.h" +#include "../kernel/io.h" +#include "../libc/stdio.h" + +#define ATA_PRIMARY_IO 0x1F0 +#define ATA_PRIMARY_CTRL 0x3F6 +#define ATA_CMD_READ_PIO 0x20 +#define ATA_CMD_WRITE_PIO 0x30 +#define ATA_IDENTIFY 0xEC + +#define ATA_REG_DATA 0x00 +#define ATA_REG_ERROR 0x01 +#define ATA_REG_SECCOUNT0 0x02 +#define ATA_REG_LBA0 0x03 +#define ATA_REG_LBA1 0x04 +#define ATA_REG_LBA2 0x05 +#define ATA_REG_HDDEVSEL 0x06 +#define ATA_REG_COMMAND 0x07 +#define ATA_REG_STATUS 0x07 + +#define ATA_SR_BSY 0x80 +#define ATA_SR_DRDY 0x40 +#define ATA_SR_DRQ 0x08 +#define ATA_SR_ERR 0x01 + +static inline uint16_t inw(uint16_t port) { + uint16_t result; + asm volatile("inw %1, %0" : "=a"(result) : "dN"(port)); + return result; +} + +static inline void outw(uint16_t port, uint16_t data) { + asm volatile("outw %1, %0" : : "dN"(port), "a"(data)); +} + +void ata_wait_bsy() { + while (inb(ATA_PRIMARY_IO + ATA_REG_STATUS) & ATA_SR_BSY); +} + +void ata_wait_drq() { + while (!(inb(ATA_PRIMARY_IO + ATA_REG_STATUS) & ATA_SR_DRQ)); +} + +void ata_select_drive(uint8_t drive) { + outb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xE0 | (drive << 4)); +} + +void ata_read_sector(uint32_t lba, uint8_t* buffer) { + ata_wait_bsy(); + ata_select_drive(0); + + outb(ATA_PRIMARY_IO + ATA_REG_SECCOUNT0, 1); + outb(ATA_PRIMARY_IO + ATA_REG_LBA0, (uint8_t)lba); + outb(ATA_PRIMARY_IO + ATA_REG_LBA1, (uint8_t)(lba >> 8)); + outb(ATA_PRIMARY_IO + ATA_REG_LBA2, (uint8_t)(lba >> 16)); + outb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xE0 | ((lba >> 24) & 0x0F)); + + outb(ATA_PRIMARY_IO + ATA_REG_COMMAND, ATA_CMD_READ_PIO); + + ata_wait_bsy(); + ata_wait_drq(); + + for (int i = 0; i < 256; i++) { + ((uint16_t*)buffer)[i] = inw(ATA_PRIMARY_IO + ATA_REG_DATA); + } +} + +// Works only w/o paging +void test_read_sector() { + uint8_t buffer[512]; + ata_read_sector(0, buffer); + + for (int i = 0; i < 512; i++) { + if (i%25==0) puts("\n"); + printf("%02x ", buffer[i]); + } +} diff --git a/src/drivers/ata.h b/src/drivers/ata.h new file mode 100644 index 0000000..550645c --- /dev/null +++ b/src/drivers/ata.h @@ -0,0 +1,7 @@ +#ifndef ATA_H +#define ATA_H + +void ata_read_sector(uint32_t lba, uint8_t* buffer); +void test_read_sector(); + +#endif diff --git a/src/drivers/framebuffer.c b/src/drivers/framebuffer.c new file mode 100644 index 0000000..528b0dd --- /dev/null +++ b/src/drivers/framebuffer.c @@ -0,0 +1,94 @@ +#include "../libc/stdint.h" +#include "framebuffer.h" +#include "serial.h" +#include "../kernel/system.h" + +//extern uint32_t *g_framebuffer; + +void putpixel(uint32_t* fb, int pitch, int bpp, int x, int y, uint32_t color) // framebuffer pointer, x, y, color +{ + if (bpp == 32) { + uint32_t* pixel_addr = (uint32_t*)((uint8_t*)fb + y * pitch + x *(bpp / 8)); + *pixel_addr = color; + } +} + +extern char* framebuffer; +extern int scanline; +extern char _binary_include_fonts_UniCyr_8x16_psf_start; +uint16_t* unicode; + +#define PIXEL uint32_t + +// Character, cursor X, cursor Y, foreground, background +void draw_char(unsigned short int c, int cx, int cy, uint32_t fg, uint32_t bg) +{ + PSF_font *font = (PSF_font*)&_binary_include_fonts_UniCyr_8x16_psf_start; + int bytesperline=(font->width+7)/8; + if (unicode != NULL) { + c = unicode[c]; + } + + unsigned char* glyph = (unsigned char*)&_binary_include_fonts_UniCyr_8x16_psf_start + font->headersize + (c>0&&cnumglyph?c:0)*font->bytesperglyph; + + int offs = + (cy * font->height * scanline) + + (cx * (font->width) * sizeof(PIXEL)); + + unsigned int x, y; + int line, mask; + + for (y=0; yheight; y++) + { + line=offs; + mask=1<<(font->width-1); + + for (x=0; xwidth; x++) + { + *((PIXEL*)(framebuffer + line)) = *((unsigned int*)glyph) & mask ? fg : bg; + mask >>= 1; + line += sizeof(PIXEL); + } + + glyph += bytesperline; + offs += scanline; + } +} + +void scroll() +{ + serial_printf(3, "Scrolling...\r"); + uint32_t bg_color = 0x00000000; + PSF_font *font = (PSF_font*)&_binary_include_fonts_UniCyr_8x16_psf_start; + + int line_size = font->height * scanline; + int framebuffer_size = scanline * font->height * (1080/font->height); + + // Erasing first line + for (uint32_t y=0; yheight; y++) + { + for (uint32_t x=0; xheight; y++) + { + for (uint32_t x=0; x +#include "paging.h" +#include "../drivers/ata.h" +#include "../libc/stdint.h" +#include "../drivers/framebuffer.h" -char* ascii_title = -"\n" -" oooooooooo o888 oooo ooooooo oooooooo8\n" -" 888 888 888 ooooooo oo oooooo 888 ooooo o888 888o 888 \n" -" 888oooo88 888 ooooo888 888 888 888o888 888 888 888oooooo \n" -" 888 888 888 888 888 888 888 8888 88o 888o o888 888\n" -" o888ooo888 o888o 88ooo88 8o o888o o888o o888o o888o 88ooo88 o88oooo888\n\n" -" --------------------------------- v0.3.55 --------------------------------\n\n"; +typedef struct { + uint32_t type; + uint32_t size; + uint64_t framebuffer_addr; + uint32_t framebuffer_pitch; + uint32_t framebuffer_width; + uint32_t framebuffer_height; + uint8_t framebuffer_bpp; + uint8_t framebuffer_type; + uint16_t reserved; +} multiboot2_tag_framebuffer; + +typedef struct { + uint32_t total_size; + uint32_t reserved; + uint8_t tags[0]; +} multiboot2_info; unsigned int g_multiboot_info_address; -void kmain(unsigned int multiboot_info_address) +uint32_t* framebuffer; +int scanline; + +// in characters, not pixels +uint32_t VGA_WIDTH; +uint32_t VGA_HEIGHT; + + +void kmain(multiboot2_info *mb_info) { - g_multiboot_info_address = multiboot_info_address; + + multiboot2_tag_framebuffer *fb_info = NULL; + +uint8_t *tags = mb_info->tags; + while (1) { + uint32_t tag_type = *((uint32_t*) tags); + uint32_t tag_size = *((uint32_t*) (tags + 4)); + + if (tag_type == 0) break; + if (tag_type == 8) { + fb_info = (multiboot2_tag_framebuffer*) tags; + } + + tags += ((tag_size + 7) & ~7); + } + + serial_printf(3, "Framebuffer Address: 0x%x\r", fb_info->framebuffer_addr); + serial_printf(3, "Framebuffer Width: %u\r\n", fb_info->framebuffer_width); + serial_printf(3, "Framebuffer Height: %u\r\n", fb_info->framebuffer_height); + serial_printf(3, "Framebuffer Pitch: %u\r\n", fb_info->framebuffer_pitch); + serial_printf(3, "Framebuffer BPP: %u\r\n", fb_info->framebuffer_bpp); + + + if (fb_info) { + framebuffer = (uint32_t *)(uintptr_t) fb_info->framebuffer_addr; + + uint32_t width = fb_info->framebuffer_width; + uint32_t height = fb_info->framebuffer_height; + //uint32_t pitch = fb_info->framebuffer_pitch; + uint32_t bpp = fb_info->framebuffer_bpp; + + + //8x16 font, not padded + VGA_WIDTH = width/8; + VGA_HEIGHT = height/16; + + scanline = width * (bpp/8); + + + /* TEST print charset + int y_offset = 2; + for (int i=0; i<512; i++) + { + if (i%(width/9)==0) y_offset++; + draw_char(0+i, 0+i, y_offset, white, black); + } + */ + } + + printf("[kernel] multiboot2 info at 0x%x, size=%u\n", mb_info, mb_info->total_size); + printf("[kernel] framebuffer discovered at 0x%x\n", fb_info->framebuffer_addr); + printf("[kernel] fb0: width=%u, height=%u, pitch=%u, bpp=%u\n", fb_info->framebuffer_width, fb_info->framebuffer_height, fb_info->framebuffer_pitch, fb_info->framebuffer_bpp); + init_serial(); - log("serial connection established\n", 3); gdt_install(); - log("initialized GDT entries\n", 2); idt_install(); - log("initialized IDT\n", 2); isr_install(); - log("initialized ISRs\n", 2); irq_install(); __asm__ __volatile__("sti"); - log("initialized IRQs\n", 2), - clear(); - colorputs(ascii_title, 10); - colorputs(" by @xamidev - star the repo for a cookie!\n\n", 14); + //init_paging(); + + //test_read_sector(); + + //uint32_t *ptr = (uint32_t*)0xA0000000; + //uint32_t do_page_fault = *ptr; timer_install(); - serial_printf(2, "%d\tinitialized timer handler", global_ticks); - keyboard_install(); - serial_printf(2, "%d\tinitialized keyboard handler", global_ticks); + keyboard_install(); + printf("[kernel] spawning shell...\n"); shell_install(); - serial_printf(2, "%d\tstarted system shell", global_ticks); + } diff --git a/src/kernel/loader.s b/src/kernel/loader.s index 2459695..36410ac 100644 --- a/src/kernel/loader.s +++ b/src/kernel/loader.s @@ -1,19 +1,45 @@ global loader -section .__mbHeader +section .multiboot_header -align 0x4 -section .text: +align 8 -MAGIC_NUMBER equ 0x1BADB002 ; multiboot magic -FLAGS equ 0x0 -CHECKSUM equ -MAGIC_NUMBER -KERNEL_STACK_SIZE equ 4096 +; ASM macros - dd MAGIC_NUMBER - dd FLAGS +MAGIC_NUMBER equ 0xe85250d6 ; multiboot2 magic +FLAGS equ 0x0 ; 32-bit protected mode for i386 +HEADER_LEN equ 44 ; Tags=2+2+4+4+4+4+2+2+4=28 +CHECKSUM equ -(MAGIC_NUMBER + FLAGS + HEADER_LEN) + +; Multiboot 2 header, according to specification (16bytes) + + dd MAGIC_NUMBER ; dd = 4 bytes = 32bits = u32 + dd FLAGS + dd HEADER_LEN dd CHECKSUM +; Tags? (28bytes) + +; Tag 1 : set graphics mode (only recommended, can be overriden by GRUB) + + dw 5 ; 2 + dw 0 ; 2 + dd 20 ; 4 + dd 1920 ; 4 + dd 1080 ; 4 + dd 32 ; 4 + +; End of tags + + dw 0 ; 2 + ;dw 0 ; 2 + dd 8 ; 4 + +; End of Multiboot 2 header + +section .text: + +KERNEL_STACK_SIZE equ 4096 extern kmain loader: @@ -49,225 +75,55 @@ idt_load: lidt [idtp] ret -global isr0 -global isr1 -global isr2 -global isr3 -global isr4 -global isr5 -global isr6 -global isr7 -global isr8 -global isr9 -global isr10 -global isr11 -global isr12 -global isr13 -global isr14 -global isr15 -global isr16 -global isr17 -global isr18 -global isr19 -global isr20 -global isr21 -global isr22 -global isr23 -global isr24 -global isr25 -global isr26 -global isr27 -global isr28 -global isr29 -global isr30 -global isr31 +%macro ISR_NOERRCODE 1 + global isr%1 + isr%1: + cli + push byte 0 + push byte %1 + jmp isr_common_stub +%endmacro -; Interrupt service routine exceptions -isr0: - cli - push byte 0 - push byte 0 - jmp isr_common_stub +%macro ISR_ERRCODE 1 + global isr%1 + isr%1: + cli + push byte %1 + jmp isr_common_stub +%endmacro -isr1: - cli - push byte 0 - push byte 1 - jmp isr_common_stub - -isr2: - cli - push byte 0 - push byte 2 - jmp isr_common_stub - -isr3: - cli - push byte 0 - push byte 3 - jmp isr_common_stub - -isr4: - cli - push byte 0 - push byte 4 - jmp isr_common_stub - -isr5: - cli - push byte 0 - push byte 5 - jmp isr_common_stub - -isr6: - cli - push byte 0 - push byte 6 - jmp isr_common_stub - -isr7: - cli - push byte 0 - push byte 7 - jmp isr_common_stub - -isr8: - cli - push byte 8 - jmp isr_common_stub - -isr9: - cli - push byte 0 - push byte 9 - jmp isr_common_stub - -isr10: - cli - push byte 10 - jmp isr_common_stub - -isr11: - cli - push byte 11 - jmp isr_common_stub - -isr12: - cli - push byte 12 - jmp isr_common_stub - -isr13: - cli - push byte 13 - jmp isr_common_stub - -isr14: - cli - push byte 14 - jmp isr_common_stub - -isr15: - cli - push byte 0 - push byte 15 - jmp isr_common_stub - -isr16: - cli - push byte 0 - push byte 16 - jmp isr_common_stub - -isr17: - cli - push byte 0 - push byte 17 - jmp isr_common_stub - -isr18: - cli - push byte 0 - push byte 18 - jmp isr_common_stub - -isr19: - cli - push byte 0 - push byte 19 - jmp isr_common_stub - -isr20: - cli - push byte 0 - push byte 20 - jmp isr_common_stub - -isr21: - cli - push byte 0 - push byte 21 - jmp isr_common_stub - -isr22: - cli - push byte 0 - push byte 22 - jmp isr_common_stub - -isr23: - cli - push byte 0 - push byte 23 - jmp isr_common_stub - -isr24: - cli - push byte 0 - push byte 24 - jmp isr_common_stub - -isr25: - cli - push byte 0 - push byte 25 - jmp isr_common_stub - -isr26: - cli - push byte 0 - push byte 26 - jmp isr_common_stub - -isr27: - cli - push byte 0 - push byte 27 - jmp isr_common_stub - -isr28: - cli - push byte 0 - push byte 28 - jmp isr_common_stub - -isr29: - cli - push byte 0 - push byte 29 - jmp isr_common_stub - -isr30: - cli - push byte 0 - push byte 30 - jmp isr_common_stub - -isr31: - cli - push byte 0 - push byte 31 - jmp isr_common_stub +ISR_NOERRCODE 0 +ISR_NOERRCODE 1 +ISR_NOERRCODE 2 +ISR_NOERRCODE 3 +ISR_NOERRCODE 4 +ISR_NOERRCODE 5 +ISR_NOERRCODE 6 +ISR_NOERRCODE 7 +ISR_ERRCODE 8 +ISR_NOERRCODE 9 +ISR_ERRCODE 10 +ISR_ERRCODE 11 +ISR_ERRCODE 12 +ISR_ERRCODE 13 +ISR_ERRCODE 14 +ISR_NOERRCODE 15 +ISR_NOERRCODE 16 +ISR_NOERRCODE 17 +ISR_NOERRCODE 18 +ISR_NOERRCODE 19 +ISR_NOERRCODE 20 +ISR_NOERRCODE 21 +ISR_NOERRCODE 22 +ISR_NOERRCODE 23 +ISR_NOERRCODE 24 +ISR_NOERRCODE 25 +ISR_NOERRCODE 26 +ISR_NOERRCODE 27 +ISR_NOERRCODE 28 +ISR_NOERRCODE 29 +ISR_NOERRCODE 30 +ISR_NOERRCODE 31 extern fault_handler @@ -295,118 +151,31 @@ isr_common_stub: add esp, 8 iret -global irq0 -global irq1 -global irq2 -global irq3 -global irq4 -global irq5 -global irq6 -global irq7 -global irq8 -global irq9 -global irq10 -global irq11 -global irq12 -global irq13 -global irq14 -global irq15 +%macro IRQ 2 + global irq%1 + irq%1: + cli + push byte 0 + push byte %2 + jmp irq_common_stub +%endmacro -irq0: - cli - push byte 0 - push byte 32 - jmp irq_common_stub - -irq1: - cli - push byte 0 - push byte 33 - jmp irq_common_stub - -irq2: - cli - push byte 0 - push byte 34 - jmp irq_common_stub - -irq3: - cli - push byte 0 - push byte 35 - jmp irq_common_stub - -irq4: - cli - push byte 0 - push byte 36 - jmp irq_common_stub - -irq5: - cli - push byte 0 - push byte 37 - jmp irq_common_stub - -irq6: - cli - push byte 0 - push byte 38 - jmp irq_common_stub - -irq7: - cli - push byte 0 - push byte 39 - jmp irq_common_stub - -irq8: - cli - push byte 0 - push byte 40 - jmp irq_common_stub - -irq9: - cli - push byte 0 - push byte 41 - jmp irq_common_stub - -irq10: - cli - push byte 0 - push byte 42 - jmp irq_common_stub - -irq11: - cli - push byte 0 - push byte 43 - jmp irq_common_stub - -irq12: - cli - push byte 0 - push byte 44 - jmp irq_common_stub - -irq13: - cli - push byte 0 - push byte 45 - jmp irq_common_stub - -irq14: - cli - push byte 0 - push byte 46 - jmp irq_common_stub - -irq15: - cli - push byte 0 - push byte 47 - jmp irq_common_stub +IRQ 0, 32 +IRQ 1, 33 +IRQ 2, 34 +IRQ 3, 35 +IRQ 4, 36 +IRQ 5, 37 +IRQ 6, 38 +IRQ 7, 39 +IRQ 8, 40 +IRQ 9, 41 +IRQ 10, 42 +IRQ 11, 43 +IRQ 12, 44 +IRQ 13, 45 +IRQ 14, 46 +IRQ 15, 47 extern irq_handler diff --git a/src/kernel/paging.c b/src/kernel/paging.c new file mode 100644 index 0000000..c49efa4 --- /dev/null +++ b/src/kernel/paging.c @@ -0,0 +1,150 @@ +#include "../libc/stdint.h" +#include "paging.h" +#include "../libc/stdio.h" +#include "system.h" +#include "kheap.h" + + +uint32_t *frames; +uint32_t nframes; + +extern uint32_t placement_address; + +#define INDEX_FROM_BIT(a) (a/(8*4)) +#define OFFSET_FROM_BIT(a) (a%(8*4)) + +static void set_frame(uint32_t frame_addr) +{ + uint32_t frame = frame_addr/0x1000; + uint32_t idx = INDEX_FROM_BIT(frame); + uint32_t off = OFFSET_FROM_BIT(frame); + frames[idx] |= (0x1 << off); +} + +static void clear_frame(uint32_t frame_addr) +{ + uint32_t frame = frame_addr/0x1000; + uint32_t idx = INDEX_FROM_BIT(frame); + uint32_t off = OFFSET_FROM_BIT(frame); + frames[idx] &= ~(0x1 << off); +} + +/* +static uint32_t test_frame(uint32_t frame_addr) +{ + uint32_t frame = frame_addr/0x1000; + uint32_t idx = INDEX_FROM_BIT(frame); + uint32_t off = OFFSET_FROM_BIT(frame); + return (frames[idx] & (0x1 << off)); +} +*/ + +static uint32_t first_frame() +{ + uint32_t i, j; + for (i=0; iframe != 0) + { + return; + } else { + uint32_t idx = first_frame(); + if (idx == (uint32_t)-1) + { + panic(); + } + set_frame(idx*0x1000); + page->present = 1; + page->rw = (is_writeable)?1:0; + page->user = (is_kernel)?0:1; + page->frame = idx; + } +} + +void free_frame(page_t *page) +{ + uint32_t frame; + if (!(frame=page->frame)) + { + return; + } else { + clear_frame(frame); + page->frame = 0x0; + } +} + +void init_paging() +{ + uint32_t mem_end_page = 0x10000000; + nframes = mem_end_page / 0x1000; + frames = (uint32_t*)kmalloc(INDEX_FROM_BIT(nframes)); + memset(frames, 0, INDEX_FROM_BIT(nframes)); + + page_directory_t* kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t)); + memset(kernel_directory, 0, sizeof(page_directory_t)); + //page_directory_t* current_directory = kernel_directory; + + unsigned int i = 0; + while (i < placement_address) + { + alloc_frame(get_page(i, 1, kernel_directory), 0, 0); + i += 0x1000; + } + + irq_install_handler(14, page_fault); + + switch_page_directory(kernel_directory); +} + +void switch_page_directory(page_directory_t *dir) +{ + //page_directory_t* current_directory = dir; + asm volatile("mov %0, %%cr3":: "r"(&dir->tablesPhysical)); + uint32_t cr0; + asm volatile("mov %%cr0, %0": "=r"(cr0)); + cr0 |= 0x80000000; + asm volatile("mov %0, %%cr0":: "r"(cr0)); +} + +page_t *get_page(uint32_t address, int make, page_directory_t *dir) +{ + address /= 0x1000; + uint32_t table_idx = address / 1024; + if (dir->tables[table_idx]) + { + return &dir->tables[table_idx]->pages[address%1024]; + } else if (make) + { + uint32_t tmp; + dir->tables[table_idx] = (page_table_t*)kmalloc_ap(sizeof(page_table_t), &tmp); + memset(dir->tables[table_idx], 0, 0x1000); + dir->tablesPhysical[table_idx] = tmp | 0x7; + return &dir->tables[table_idx]->pages[address%1024]; + } else { + return 0; + } + return 0; +} + +void page_fault() +{ + puts("Page fault"); + panic(); +} diff --git a/src/kernel/paging.h b/src/kernel/paging.h new file mode 100644 index 0000000..ee485ad --- /dev/null +++ b/src/kernel/paging.h @@ -0,0 +1,34 @@ +#ifndef PAGING_H +#define PAGING_H + +#include "system.h" +#include "../libc/stdint.h" +typedef struct +{ + uint32_t present : 1; + uint32_t rw : 1; + uint32_t user : 1; + uint32_t accessed : 1; + uint32_t dirty : 1; + uint32_t unused : 7; + uint32_t frame : 20; +} page_t; + +typedef struct +{ + page_t pages[1024]; +} page_table_t; + +typedef struct +{ + page_table_t *tables[1024]; + uint32_t tablesPhysical[1024]; + uint32_t physicalAsddr; +} page_directory_t; + +void init_paging(); +void switch_page_directory(page_directory_t *new); +page_t *get_page(uint32_t address, int make, page_directory_t *dir); +void page_fault(); + +#endif diff --git a/src/kernel/shell.c b/src/kernel/shell.c index 4dc49f1..fe3973e 100644 --- a/src/kernel/shell.c +++ b/src/kernel/shell.c @@ -8,6 +8,16 @@ #define MAX_COMMANDS 16 #define MAX_ARGS 64 + +char* ascii_title = +"\n" +"----------------------------------------------\n" +"Blank OS version 0.3.71-dev\n" +"Author: @xamidev - star the repo for a cookie!\n" +"----------------------------------------------\n" +"\n"; + + typedef void (*command_func_t)(int argc, char *argv[]); typedef struct @@ -53,7 +63,9 @@ int parse_input(char* input, char* argv[], int max_args) } void shell_install() -{ +{ + colorputs(ascii_title, yellow, black); + register_command("help", program_help); register_command("panic", program_panic); register_command("words", program_words); @@ -73,7 +85,13 @@ void shell_install() { char input_buffer[BUFFER_SIZE]; char* argv[MAX_ARGS]; - colorputs("blankos> ", 9); + + // Prompt + colorputs("root", blue, black); + colorputs("@", white, black); + colorputs("blankos", green, black); + colorputs("~$ ", white, black); + get_input(input_buffer, BUFFER_SIZE); puts("\n"); diff --git a/src/kernel/system.c b/src/kernel/system.c index 9ac43db..36594da 100644 --- a/src/kernel/system.c +++ b/src/kernel/system.c @@ -1,4 +1,5 @@ #include "system.h" +#include "../libc/stdint.h" void *memset(void *dest, char val, size_t count) { @@ -6,3 +7,29 @@ void *memset(void *dest, char val, size_t count) for(; count != 0; count--) *temp++ = val; return dest; } + +void *memmove(void* dest, const void* src, size_t n) +{ + unsigned char* d = (unsigned char*)dest; + const unsigned char* s = (const unsigned char*)src; + + if (d < s) + { + for (size_t i=0; i0; i--) + { + d[i-1] = s[i-1]; + } + } + + return dest; +} + +void panic() +{ + for (;;); +} diff --git a/src/kernel/system.h b/src/kernel/system.h index a2884c3..874cf19 100644 --- a/src/kernel/system.h +++ b/src/kernel/system.h @@ -1,9 +1,12 @@ #ifndef SYSTEM_H #define SYSTEM_H +#include "../libc/stdint.h" + typedef int size_t; void *memset(void *dest, char val, size_t count); +void *memmove(void* dest, const void* src, size_t n); struct regs { @@ -13,6 +16,7 @@ struct regs unsigned int eip, cs, eflags, useresp, ss; }; +void panic(); void isr_install(); void irq_install(); void irq_install_handler(int irq, void (*handler)(struct regs *r)); diff --git a/src/libc/stdint.h b/src/libc/stdint.h index 657cf76..fffbd7d 100644 --- a/src/libc/stdint.h +++ b/src/libc/stdint.h @@ -19,4 +19,6 @@ typedef uint8_t bool; #define NULL ((void*)0) +typedef unsigned int uintptr_t; + #endif diff --git a/src/libc/stdio.c b/src/libc/stdio.c index 31d1c7f..3ea1076 100644 --- a/src/libc/stdio.c +++ b/src/libc/stdio.c @@ -3,31 +3,46 @@ #include "string.h" #include "stdint.h" #include "../kernel/system.h" +#include "../drivers/framebuffer.h" +#include "../drivers/serial.h" -char* fb = (char *) 0x000B8000; -const unsigned VGA_WIDTH = 80; -const unsigned VGA_HEIGHT = 25; -const unsigned int COLOR = 0x7; +extern uint32_t* framebuffer; +extern uint32_t VGA_WIDTH; +extern uint32_t VGA_HEIGHT; unsigned int VGA_X = 0, VGA_Y = 0; +#define CURSOR_WIDTH 8 +#define CURSOR_HEIGHT 16 +extern int scanline; + +void draw_cursor(uint32_t color) +{ + for (int y=12; y> 8) & 0x00FF)); - outb(FB_CMD_PORT, FB_LOW_BYTE_CMD); - outb(FB_DATA_PORT, pos & 0x00FF); + erase_cursor(); + VGA_X = x; + VGA_Y = y; + draw_cursor(white); } -void putchar(int x, int y, char c) +// stdio wrapper for draw_char in graphics mode +void putchar(unsigned short int c, int x, int y, uint32_t fg, uint32_t bg) { - fb[2*(y*VGA_WIDTH+x)] = c; -} - -void putcolor(int x, int y, unsigned int color) -{ - fb[2*(y*VGA_WIDTH+x)+1] = color; + draw_char(c, x, y, fg, bg); } void clear(void) @@ -36,55 +51,15 @@ void clear(void) { for (unsigned int x=0; x= VGA_HEIGHT) return; - - for (unsigned int y = 0; y < VGA_HEIGHT-lines; y++) - { - for (unsigned int x = 0; x < VGA_WIDTH; x++) - { - putchar(x, y, getchar(x, y+lines)); - putcolor(x, y, getcolor(x, y+lines)); - } - } - - for (unsigned int y = VGA_HEIGHT-lines; y= VGA_HEIGHT) scroll(1); + if (VGA_Y >= VGA_HEIGHT) + { + serial_printf(3, "VGA_Y=%d, VGA_HEIGHT=%d: Scrolling...\r", VGA_Y, VGA_HEIGHT); + scroll(); + VGA_Y = VGA_HEIGHT - 1; + } move_cursor(VGA_X, VGA_Y); } -void colorputc(char c, unsigned int color) +void colorputc(char c, uint32_t fg, uint32_t bg) { + erase_cursor(); switch(c) { case '\n': @@ -143,8 +124,7 @@ void colorputc(char c, unsigned int color) VGA_X += 4; break; default: - putchar(VGA_X, VGA_Y, c); - putcolor(VGA_X, VGA_Y, color); + putchar(c, VGA_X, VGA_Y, fg, bg); VGA_X++; break; } @@ -154,7 +134,14 @@ void colorputc(char c, unsigned int color) VGA_Y++; VGA_X = 0; } - if (VGA_Y >= VGA_HEIGHT) scroll(1); + + if (VGA_Y >= VGA_HEIGHT) + { + serial_printf(3, "VGA_Y=%d, VGA_HEIGHT=%d: Scrolling...\r", VGA_Y, VGA_HEIGHT); + scroll(); + VGA_Y = VGA_HEIGHT - 1; + } + move_cursor(VGA_X, VGA_Y); } @@ -167,11 +154,11 @@ void puts(const char* str) } } -void colorputs(const char* str, unsigned int color) +void colorputs(const char* str, uint32_t fg, uint32_t bg) { while (*str) { - colorputc(*str, color); + colorputc(*str, fg, bg); str++; } } @@ -221,201 +208,247 @@ void dtostrf(double val, char *buffer, int precision) void printf(const char* fmt, ...) { - int* argp = (int*) &fmt; - int state = PRINTF_STATE_START; - int length = PRINTF_LENGTH_START; - int radix = 10; - bool sign = false; + int* argp = (int*)&fmt; + int state = PRINTF_STATE_START; + int length = PRINTF_LENGTH_START; + int radix = 10; + bool sign = false; + int width = 0; + char pad_char = ' '; - argp++; - while (*fmt) - { - switch(state) { - case PRINTF_STATE_START: - if (*fmt == '%') + argp++; + while (*fmt) + { + switch (state) { - state = PRINTF_STATE_LENGTH; - } - else { - putc(*fmt); - } - break; - case PRINTF_STATE_LENGTH: - if (*fmt == 'h') - { - length = PRINTF_LENGTH_SHORT; - state = PRINTF_STATE_SHORT; - } - else if (*fmt == 'l') - { - length = PRINTF_LENGTH_LONG; - state = PRINTF_STATE_LONG; - } - else { - goto PRINTF_STATE_SPEC_; - } - break; - case PRINTF_STATE_SHORT: - if (*fmt == 'h') - { - length = PRINTF_LENGTH_SHORT_SHORT; - state = PRINTF_STATE_SPEC; - } - else { - goto PRINTF_STATE_SPEC_; - } - break; - case PRINTF_STATE_LONG: - if (*fmt == 'l') - { - length = PRINTF_LENGTH_LONG_LONG; - state = PRINTF_STATE_SPEC; - } - else { - goto PRINTF_STATE_SPEC_; - } - break; - case PRINTF_STATE_SPEC: + case PRINTF_STATE_START: + if (*fmt == '%') + { + state = PRINTF_STATE_LENGTH; + width = 0; + pad_char = ' '; + } + else + { + putc(*fmt); + } + break; + + case PRINTF_STATE_LENGTH: + if (*fmt == '0') + { + pad_char = '0'; + state = PRINTF_STATE_WIDTH; + } + else if (*fmt >= '1' && *fmt <= '9') + { + width = *fmt - '0'; + state = PRINTF_STATE_WIDTH; + } + else if (*fmt == 'h') + { + length = PRINTF_LENGTH_SHORT; + state = PRINTF_STATE_SHORT; + } + else if (*fmt == 'l') + { + length = PRINTF_LENGTH_LONG; + state = PRINTF_STATE_LONG; + } + else + { + goto PRINTF_STATE_SPEC_; + } + break; + + case PRINTF_STATE_WIDTH: + if (*fmt >= '0' && *fmt <= '9') + { + width = width * 10 + (*fmt - '0'); + } + else + { + goto PRINTF_STATE_SPEC_; + } + break; + + case PRINTF_STATE_SHORT: + if (*fmt == 'h') + { + length = PRINTF_LENGTH_SHORT_SHORT; + state = PRINTF_STATE_SPEC; + } + else + { + goto PRINTF_STATE_SPEC_; + } + break; + + case PRINTF_STATE_LONG: + if (*fmt == 'l') + { + length = PRINTF_LENGTH_LONG_LONG; + state = PRINTF_STATE_SPEC; + } + else + { + goto PRINTF_STATE_SPEC_; + } + break; + + case PRINTF_STATE_SPEC: PRINTF_STATE_SPEC_: - switch(*fmt) - { - case 'c': - putc((char)*argp); - argp++; - break; - case 's': - puts(*(const char **)argp); - argp++; - break; - case '%': - putc('%'); - break; - case 'd': - case 'i': - radix = 10; - sign = true; - argp = printf_number(argp, length, sign, radix); - break; - case 'u': + switch (*fmt) + { + case 'c': + putc((char)*argp); + argp++; + break; + case 's': + puts(*(const char**)argp); + argp++; + break; + case '%': + putc('%'); + break; + case 'd': + case 'i': + radix = 10; + sign = true; + argp = printf_number(argp, length, sign, radix, width, pad_char); + break; + case 'u': + radix = 10; + sign = false; + argp = printf_number(argp, length, sign, radix, width, pad_char); + break; + case 'X': + case 'x': + case 'p': + radix = 16; + sign = false; + argp = printf_number(argp, length, sign, radix, width, pad_char); + break; + case 'o': + radix = 8; + sign = false; + argp = printf_number(argp, length, sign, radix, width, pad_char); + break; + case 'f': { + double* dargp = (double*)argp; + double d = *(double*)dargp; + char buffer[64]; + dtostrf(d, buffer, 6); + puts(buffer); + argp += 2; + break; + } + default: + break; + } + state = PRINTF_STATE_START; + length = PRINTF_LENGTH_START; radix = 10; sign = false; - argp = printf_number(argp, length, sign, radix); - break; - case 'X': - case 'x': - case 'p': - radix = 16; - sign = false; - argp = printf_number(argp, length, sign, radix); - break; - case 'o': - radix = 8; - sign = false; - argp = printf_number(argp, length, sign, radix); - break; - case 'f': { - // Handle floating-point numbers - double* dargp = (double*)argp; - double d = *(double*)dargp; - char buffer[64]; - dtostrf(d, buffer, 6); // Default precision: 6 - puts(buffer); - argp += 2; // Incrementing by 2 to move past the double argument - break; - } - default: + width = 0; + pad_char = ' '; break; } - state = PRINTF_STATE_START; - length = PRINTF_LENGTH_START; - radix = 10; - sign = false; - break; + fmt++; } - fmt++; - } } const char charset[] = "0123456789abcdef"; -int* printf_number(int* argp, int length, bool sign, int radix) +int* printf_number(int* argp, int length, bool sign, int radix, int width, char pad_char) { - char buffer[32]; - unsigned long long number; - int number_sign = 1; - int pos = 0; + char buffer[32]; + unsigned long long number; + int number_sign = 1; + int pos = 0; - switch(length) - { + switch (length) + { case PRINTF_LENGTH_SHORT_SHORT: case PRINTF_LENGTH_SHORT: case PRINTF_LENGTH_START: - if (sign) - { - int n = *argp; - if (n < 0) + if (sign) { - n = -n; - number_sign = -1; + int n = *argp; + if (n < 0) + { + n = -n; + number_sign = -1; + } + number = (unsigned long long)n; } - number = (unsigned long long) n; - } - else { - number = *(unsigned int*) argp; - } - argp++; - break; + else + { + number = *(unsigned int*)argp; + } + argp++; + break; case PRINTF_LENGTH_LONG: - if (sign) - { - long int n = *(long int*)argp; - if (n < 0) + if (sign) { - n = -n; - number_sign = -1; + long int n = *(long int*)argp; + if (n < 0) + { + n = -n; + number_sign = -1; + } + number = (unsigned long long)n; } - number = (unsigned long long) n; - } - else { - number = *(unsigned long int*) argp; - } - argp += 2; - break; + else + { + number = *(unsigned long int*)argp; + } + argp += 2; + break; case PRINTF_LENGTH_LONG_LONG: - if (sign) - { - long long int n = *(long long int*)argp; - if (n < 0) + if (sign) { - n = -n; - number_sign = -1; + long long int n = *(long long int*)argp; + if (n < 0) + { + n = -n; + number_sign = -1; + } + number = (unsigned long long)n; } - number = (unsigned long long) n; - } - else { - number = *(unsigned long long int*) argp; - } - argp += 4; - break; - } + else + { + number = *(unsigned long long int*)argp; + } + argp += 4; + break; + } - do { - uint32_t rem; - x86_div64_32(number, radix, &number, &rem); - buffer[pos++] = charset[rem]; - } while (number > 0); + do + { + uint32_t rem; + x86_div64_32(number, radix, &number, &rem); + buffer[pos++] = charset[rem]; + } while (number > 0); - if (sign && number_sign < 0) - { - buffer[pos++] = '-'; - } + if (sign && number_sign < 0) + { + buffer[pos++] = '-'; + } - while (--pos >= 0) - { - putc(buffer[pos]); - } + int padding = width - pos; - return argp; + while (padding-- > 0) + { + putc(pad_char); + } + + while (--pos >= 0) + { + putc(buffer[pos]); + } + + return argp; } int getch() diff --git a/src/libc/stdio.h b/src/libc/stdio.h index e7882fb..731eb87 100644 --- a/src/libc/stdio.h +++ b/src/libc/stdio.h @@ -11,35 +11,50 @@ #define FB_HIGH_BYTE_CMD 14 #define FB_LOW_BYTE_CMD 15 + +void draw_cursor(uint32_t color); +void erase_cursor(); + void move_cursor(int x, int y); -void putchar(int x, int y, char c); +void putchar(unsigned short int c, int x, int y, uint32_t fg, uint32_t bg); void puts(const char* str); -void colorputs(const char* str, unsigned int color); void clear(void); +void colorputs(const char* str, uint32_t fg, uint32_t bg); void putcolor(int x, int y, unsigned int color); char getchar(int x, int y); unsigned int getcolor(int x, int y); -void scroll(int lines); void putc(char c); -void colorputc(char c, unsigned int color); +void colorputc(char c, uint32_t fg, uint32_t bg); -#define PRINTF_STATE_START 0 -#define PRINTF_STATE_LENGTH 1 -#define PRINTF_STATE_SHORT 2 -#define PRINTF_STATE_LONG 3 -#define PRINTF_STATE_SPEC 4 +#define PRINTF_STATE_START 0 +#define PRINTF_STATE_LENGTH 1 +#define PRINTF_STATE_SHORT 2 +#define PRINTF_STATE_LONG 3 +#define PRINTF_STATE_SPEC 4 +#define PRINTF_STATE_WIDTH 5 -#define PRINTF_LENGTH_START 0 -#define PRINTF_LENGTH_SHORT_SHORT 1 -#define PRINTF_LENGTH_SHORT 2 -#define PRINTF_LENGTH_LONG 3 -#define PRINTF_LENGTH_LONG_LONG 4 +#define PRINTF_LENGTH_START 0 +#define PRINTF_LENGTH_SHORT_SHORT 1 +#define PRINTF_LENGTH_SHORT 2 +#define PRINTF_LENGTH_LONG 3 +#define PRINTF_LENGTH_LONG_LONG 4 void printf(const char* fmt, ...); -int* printf_number(int* argp, int length, bool sign, int radix); +int* printf_number(int* argp, int length, bool sign, int radix, int width, char pad_char); int getch(); void get_input(char *buffer, int size); void dtostrf(double val, char *buffer, int precision); +enum Colors +{ + // AARRGGBB? + white = 0xFFFFFFFF, + black = 0x00000000, + red = 0x00FF0000, + green = 0x0000FF00, + blue = 0x000000FF, + yellow = 0x00FFFF00, +}; + #endif diff --git a/src/programs/conway.c b/src/programs/conway.c index 703512d..93de491 100644 --- a/src/programs/conway.c +++ b/src/programs/conway.c @@ -15,7 +15,7 @@ void print_grid(const unsigned char grid[X][Y]) //(grid[i][j] == LIVE) ? putc(42) : putc(32); if (grid[i][j] == LIVE) { serial_printf(3, "alive"); - colorputc(32, 120); + //colorputc(32, 120); } else { putc(32); } diff --git a/src/programs/misc.c b/src/programs/misc.c index 25d9743..32b24c1 100644 --- a/src/programs/misc.c +++ b/src/programs/misc.c @@ -3,6 +3,7 @@ #include "../libc/stdio.h" #include "../kernel/system.h" #include "../libc/string.h" +#include "../drivers/framebuffer.h" // Print a rainbow colorful text for testing @@ -18,7 +19,7 @@ void program_rainbow() for (int i=0; i