diff --git a/Makefile b/Makefile index a94d962..486c919 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ SOURCES = src/mem/heap/kheap.c src/mem/paging/vmm.c src/mem/paging/paging.c src/ build: rm -f *.o - x86_64-elf-gcc -g -c -Isrc $(SOURCES) -Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fno-stack-protector -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections -mcmodel=kernel + x86_64-elf-gcc -g -c -Isrc $(SOURCES) -Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fno-stack-protector -fno-omit-frame-pointer -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections -mcmodel=kernel objcopy -O elf64-x86-64 -B i386 -I binary zap-light16.psf zap-light16.o nasm -f elf64 src/idt/idt.S -o idt_stub.o x86_64-elf-ld -o pepperk -T linker.ld *.o diff --git a/src/io/term/term.c b/src/io/term/term.c index 6ecb5b9..b6ea2da 100644 --- a/src/io/term/term.c +++ b/src/io/term/term.c @@ -26,68 +26,20 @@ uint8_t* glyphs = _binary_zap_light16_psf_start + sizeof(PSF1_Header); // Character cursor typedef struct { - unsigned int x; - unsigned int y; + size_t x; + size_t y; } Cursor; -Cursor cursor = {0}; +static Cursor cursor = {0, 0}; -unsigned char* fb; - -struct limine_framebuffer* framebuffer; +static uint8_t* fb; +static struct limine_framebuffer* framebuffer; uint8_t lines_length[MAX_LINES]; -int term_init() +static inline size_t term_max_cols(void) { - // Get framebuffer address from Limine struct - - if (boot_ctx.fb) - { - fb = boot_ctx.fb->address; - framebuffer = boot_ctx.fb; - DEBUG("terminal initialized, fb=0x%p (width=%u height=%u pitch=%u bpp=%u)", fb, framebuffer->width, framebuffer->height, framebuffer->pitch, framebuffer->bpp); - return 0; - } - return -ENOMEM; -} - -// These are marked "static" because we don't wanna expose them all around -// AKA they should just be seen here (kind of like private functions in cpp) -static void putpixel(int x, int y, int color) -{ - // Depth isn't part of limine_framebuffer attributes so it will be 4 - unsigned pos = x*4 + y*framebuffer->pitch; - fb[pos] = color & 255; // blue channel - fb[pos+1] = (color >> 8) & 255; // green - fb[pos+2] = (color >> 16) & 255; // blue -} - -static void draw_char(char c, int px, int py, int fg, int bg) -{ - uint8_t* glyph = glyphs + ((unsigned char)c * FONT_HEIGHT); - - for (size_t y=0; y> x)) ? fg : bg; - putpixel(px+x, py+y, color); - } - } -} - -static void erase_char(int px, int py) -{ - for (size_t y=0; ywidth / FONT_WIDTH; } static inline size_t term_max_lines(void) @@ -95,6 +47,69 @@ static inline size_t term_max_lines(void) return framebuffer->height / FONT_HEIGHT; } +int term_init() +{ + // Get framebuffer address from Limine struct + + if (!boot_ctx.fb) + { + return -ENOMEM; + } + + framebuffer = boot_ctx.fb; + fb = (uint8_t*)framebuffer->address; + + memset(lines_length, 0, sizeof(lines_length)); + + DEBUG("terminal initialized, fb=0x%p (width=%u height=%u pitch=%u bpp=%u)", fb, framebuffer->width, framebuffer->height, framebuffer->pitch, framebuffer->bpp); + return 0; +} + +// These are marked "static" because we don't wanna expose them all around +// AKA they should just be seen here (kind of like private functions in cpp) +static inline void putpixel(size_t x, size_t y, uint32_t color) +{ + // Guard so we don't write past fb boundaries + if (x >= framebuffer->width || y >= framebuffer->height) return; + // Depth isn't part of limine_framebuffer attributes so it will be 4 + size_t pos = x*4 + y*framebuffer->pitch; + fb[pos] = color & 255; // blue channel + fb[pos+1] = (color >> 8) & 255; // green + fb[pos+2] = (color >> 16) & 255; // blue +} + +static void draw_char(char c, size_t px, size_t py, uint32_t fg, uint32_t bg) +{ + // So we cannot write past fb + if (px+FONT_WIDTH > framebuffer->width || py+FONT_HEIGHT > framebuffer->height) return; + + uint8_t* glyph = glyphs + ((unsigned char)c * FONT_HEIGHT); + + for (size_t y=0; y> x)) ? fg : bg; + putpixel(px+x, py+y, color); + } + } +} + +static void erase_char(size_t px, size_t py) +{ + if (px+FONT_WIDTH > framebuffer->width || py+FONT_HEIGHT > framebuffer->height) return; + + for (size_t y=0; y 0) - { - cursor.y--; - } } void putchar(char c) { - if ((c == '\n') && ((cursor.y+1)*FONT_HEIGHT >= framebuffer->height)) - { - term_scroll(); - return; - } + const size_t max_cols = term_max_cols(); + const size_t max_lines = term_max_lines(); - if (c == '\n') - { + if (c == '\n') { lines_length[cursor.y] = cursor.x; cursor.x = 0; - cursor.y++; + + if (cursor.y + 1 >= max_lines) + { + term_scroll(); + } + else + { + cursor.y++; + } return; } - // TODO: Improperly handled. - // When we're on an empty line it should get to the upper line's last character - // NOT just the last position possible; we would need to track the last line's character amount for that - if (c == '\b') + if (c == '\b') { - if (cursor.x == 0 && cursor.y == 0) + if (cursor.x > 0) + { + cursor.x--; + } + else if (cursor.y > 0) + { + cursor.y--; + cursor.x = lines_length[cursor.y]; + } + else { - // Top-left corner return; } - if (cursor.x == 0) - { - cursor.y--; - // cursor.x = (framebuffer->width / FONT_WIDTH) -1; // here - cursor.x = lines_length[cursor.y]; - } - else { - cursor.x--; - } - - int px = cursor.x * FONT_WIDTH; - int py = cursor.y * FONT_HEIGHT; - erase_char(px, py); + erase_char(cursor.x * FONT_WIDTH, cursor.y * FONT_HEIGHT); return; } - if ((cursor.x+1)*FONT_WIDTH >= framebuffer->width) + if (cursor.x >= max_cols) { cursor.x = 0; - cursor.y++; + if (cursor.y + 1 >= max_lines) + { + term_scroll(); + } + else + { + cursor.y++; + } } - if ((cursor.y+1)*FONT_HEIGHT >= framebuffer->height) - { - term_scroll(); - } - - int px = cursor.x * FONT_WIDTH; - int py = cursor.y * FONT_HEIGHT; - draw_char(c, px, py, WHITE, BLACK); + draw_char(c, cursor.x * FONT_WIDTH, cursor.y * FONT_HEIGHT, WHITE, BLACK); cursor.x++; } @@ -198,7 +205,7 @@ void _putchar(char character) // Debug-printing void kputs(const char* str) { - unsigned int i=0; + size_t i=0; while (str[i] != 0) { putchar(str[i]);