/* * @author xamidev * @brief Framebuffer-based terminal driver * @license GPL-3.0-only */ // Terminal output /* There are a couple of bugs here and there but for now I don't care too much because this shitty implementation will be replaced one day by Flanterm (once memory management is okay: paging & kernel malloc) */ #include #include #include #include "term.h" #include "mem/misc/utils.h" #include "config.h" #include "flanterm.h" extern struct boot_context boot_ctx; // Importing the PSF object file extern unsigned char _binary_zap_light16_psf_start[]; extern unsigned char _binary_zap_light16_psf_end[]; PSF1_Header* font = (PSF1_Header*)_binary_zap_light16_psf_start; uint8_t* glyphs = _binary_zap_light16_psf_start + sizeof(PSF1_Header); #define FONT_WIDTH 8 #define FONT_HEIGHT font->characterSize extern struct flanterm_context* ft_ctx; // Character cursor typedef struct { size_t x; size_t y; } Cursor; static Cursor cursor = {0, 0}; static uint8_t* fb; static struct limine_framebuffer* framebuffer; uint8_t lines_length[TERM_HISTORY_MAX_LINES]; static inline size_t term_max_cols(void) { return framebuffer->width / FONT_WIDTH; } 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 } void term_scroll() { // Erase first text line memset(fb, 255, FONT_HEIGHT*framebuffer->pitch); // Move whole framebuffer up by one text line memmove(fb, fb+(FONT_HEIGHT*framebuffer->pitch), (framebuffer->height-FONT_HEIGHT)*framebuffer->pitch); // Clear last text line size_t clear_start = (framebuffer->height - FONT_HEIGHT) * framebuffer->pitch; memset(fb + clear_start, 255, FONT_HEIGHT * framebuffer->pitch); // Shift line lengths by 1 (for backspace handling) size_t max_lines = term_max_lines(); for (size_t i = 1; i < max_lines; i++) { lines_length[i - 1] = lines_length[i]; } lines_length[max_lines - 1] = 0; } // Overhead that could be avoided, right? (for printf) void _putchar(char character) { flanterm_write(ft_ctx, &character, 1); } // Debug-printing void kputs(const char* str) { size_t i=0; while (str[i] != 0) { _putchar(str[i]); i++; } }