From 91039f0f367348b1a16c2859cd87383071c18872 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 7 Oct 2018 04:21:21 -0400 Subject: [PATCH] Working RGB VGA output, RGB text console & bitmap fonts --- assets/default8x16.psfu | Bin 0 -> 4969 bytes assets/drdos8x14.psfu | Bin 0 -> 7671 bytes assets/system.8x16.psf | Bin 0 -> 4680 bytes kernel/CMakeLists.txt | 1 + kernel/bmp.c | 67 ++++------- kernel/bmp.h | 47 ++++---- kernel/console.c | 9 +- kernel/drivers/vga.c | 242 +++++++++++++++++++++++++++++++--------- kernel/drivers/vga.h | 18 +-- kernel/main.c | 19 ++-- kernel/multiboot.c | 8 +- kernel/psf.c | 39 +++++++ kernel/psf.h | 18 +++ kernel/shell.c | 46 ++++++-- 14 files changed, 349 insertions(+), 165 deletions(-) create mode 100644 assets/default8x16.psfu create mode 100644 assets/drdos8x14.psfu create mode 100644 assets/system.8x16.psf create mode 100644 kernel/psf.c create mode 100644 kernel/psf.h diff --git a/assets/default8x16.psfu b/assets/default8x16.psfu new file mode 100644 index 0000000000000000000000000000000000000000..e789b77189b9c3e585075eeed5a5eba693f3c435 GIT binary patch literal 4969 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 literal 0 HcmV?d00001 diff --git a/assets/system.8x16.psf b/assets/system.8x16.psf new file mode 100644 index 0000000000000000000000000000000000000000..6d4ad735ed8d9b3882f813304fcb4a3ed602b86b GIT binary patch literal 4680 zcmXTg>ea@;z`&ruz`(!=VlXl=2rxh}2Z+zWz)Q2u`?4O0)3#zp_fC4nvu zH5c7}xci{;=;p!Q1C@tU=;o8bmr+ts_@SUs)I*$J0We@-5CA0;1_l)s6%|yCDk^m< zULkYQr7fd#&Sr!~*$WKme3zK|(4LbrML9;Nak>=YZJ;k_Tf62@Vd3lR-%uEQCTxNIi1ga*iZ4m&8{#)*lEg+o9AoIgNjvv9~TF)_i_v+#(h zxYV(*fL#xgcW|gdmX}d*aHw%Ym|q8V0L-yAAUP0*+vntD$Hc^f$Rl89aHw%`aDcf0#)pJ90|Q9Eo0F3gOg~6B z$T}yeemijJbHKx&2@DY7=j7rMkPzVE0#gri3<$&Qb4(8P^mKG|bcCAcloaIU2C@Xo z2Zc9?3yW{C-#`YS%d;?nMZoeNE>1A}>>L~vBv_c3YQVA#44||Kb~2O?G8=?p=7ZQy zDk|Ve11SMH&C}B}G#SKUU|?``R1)D3QG&Y{%m*0=m9K*)SE&EwAh`uZf?g) zSXh|A?yUf6gv6K0ha!m zz>1yV>KQ=tPIV3rQ2l%Y0(BtALdz47U3Ose?3kE9K?FA+8onGH3>IMLL-n(;Fvze# z0Vqp2I5@a?1QfvIAEKB8kzN=W%00mVWEB{LV$ca5e_;0^40t~SB0XWWBI8gZ#DyV!FG`;`_14?^=1&uGEf-0}1gvtliR!WMBm5Pc=pvs8B z$cF)?y&%8=N{^r_8yY zhlK-`FQJ0US3%>ma6sA<&`bxi1Je4efwp!*wV#WRlarH61V|FpJY+zr?^!rd_@IV2 zvb>QG1ByI@iV89x6#vM4upMTcmi`_d=3q96fVLk%@ei@z38}pRvLA^LwjYTPwhx&v zfZkp}<%9G?nh4PLgo+AE`+}2AicwbC(GgbMfc%HjUJ&45fV3FF@xj0VaUZ<>05Tt0 z9;6?c4|OkGJp%)%Ay@~YK!L%)z+?mNfY^ZI9~>Uw=!dl*;3)v&evo}A^6(S@kq5aC zDi3KtI5;@OBsn@dCdD{_lK?_JNdEt$Y1{rknl|Y_2prk~A|Fke@&D133I88W>G}U? z%9Q_)rtJCu|No;Y4PbK4|3_1n{C_lM%l}7H*8G1or3s|v|DnbI|111g{IB$1`M=74 z)&FY$)&Fb!*Zi;bU;Dq#f8GCj|MmYH{5Sk>^xycu$$!)TX8+CqTl}~DZ}s2$zs-N! z|91cF|2zD5{O|PN`M=A5*Z*$+-T!<1_x$hm-}}GMf8YOp|NZ|5{15ye^gsB2$p6s) zVgJMbNBoccAN4=_f6V{b|8f80|0n!U{Gaqc`G3m))c z`TyZ5{|`_7e|Xye!_)sCp7HRdH{XabW|KU0R56}I7c;5fR^Zy@S@c;0_|A!a- zKfL(=;U)hMFa3Xb+5f}K{~uoQ|M1HHhgbbSy!!v)HUAH<{eO7f|HJG5AKvi)@W%g# zH~l}n`TyZ9{||5de|X#f!`uHK-tqtN&i{vZ{Xe|>|KUCV5AXedc;ElS`~L#~T=(hf literal 0 HcmV?d00001 diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 392a516..9309988 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -35,6 +35,7 @@ set(SOURCE_FILES dwarf stdio_impl bmp + psf arch/x86/mmu drivers/ports drivers/timer diff --git a/kernel/bmp.c b/kernel/bmp.c index 6f5f5d5..eb40aa0 100644 --- a/kernel/bmp.c +++ b/kernel/bmp.c @@ -1,63 +1,40 @@ #include "bmp.h" #include #include +#include -uint8_t *LoadBitmapFile(char *filename, BITMAPINFOHEADER *bitmapInfoHeader) { - FILE *filePtr; //our file pointer - BITMAPFILEHEADER bitmapFileHeader; //our bitmap file header - unsigned char *bitmapImage; //store image data -// int imageIdx = 0; //image index counter -// unsigned char tempRGB; //our swap variable +uint8_t *bmp_read_image(const char *filename, bmp_info_header_t *bmp_info_header) { + FILE *bmp_file; + bmp_file_header_t header; + uint8_t *img_data; - //open filename in read binary mode - filePtr = fopen(filename, "r"); - if (ferror(filePtr)) + bmp_file = fopen(filename, "r"); + if (ferror(bmp_file)) return NULL; - //read the bitmap file header - fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr); - - //verify that this is a bmp file by check bitmap id - if (bitmapFileHeader.bfType != 0x4D42) { - fclose(filePtr); + fread(&header, sizeof(bmp_file_header_t), 1, bmp_file); + if (ferror(bmp_file) || header.type != 0x4D42) { + fclose(bmp_file); return NULL; } - //read the bitmap info header - fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr); + fread(bmp_info_header, sizeof(bmp_info_header_t), 1, bmp_file); + fseek(bmp_file, header.img_data_offset, SEEK_SET); - //move file point to the begging of bitmap data - fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET); - - printf("Image size: %Xh, offset: %Xh\n", bitmapInfoHeader->biSizeImage, bitmapFileHeader.bfOffBits); - - //allocate enough memory for the bitmap image data - bitmapImage = (unsigned char *) malloc(bitmapInfoHeader->biSizeImage); - - //verify memory allocation - if (!bitmapImage) { - free(bitmapImage); - fclose(filePtr); + img_data = malloc(bmp_info_header->img_data_size); + if (img_data == NULL) { + errno = ENOMEM; + free(img_data); + fclose(bmp_file); return NULL; } - //read in the bitmap image data - fread(bitmapImage, bitmapInfoHeader->biSizeImage, 1, filePtr); - - //make sure bitmap image data was read - if (ferror(filePtr)) { - fclose(filePtr); + fread(img_data, bmp_info_header->img_data_size, 1, bmp_file); + if (ferror(bmp_file)) { + fclose(bmp_file); return NULL; } - //swap the r and b values to get RGB (bitmap is BGR) -// for (imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx += 3) { -// tempRGB = bitmapImage[imageIdx]; -// bitmapImage[imageIdx] = bitmapImage[imageIdx + 2]; -// bitmapImage[imageIdx + 2] = tempRGB; -// } - - //close file and return bitmap iamge data - fclose(filePtr); - return bitmapImage; + fclose(bmp_file); + return img_data; } diff --git a/kernel/bmp.h b/kernel/bmp.h index bccbe09..2f6cec1 100644 --- a/kernel/bmp.h +++ b/kernel/bmp.h @@ -2,32 +2,25 @@ #include -typedef uint8_t BYTE; -typedef uint16_t WORD; -typedef uint32_t DWORD; -typedef uint64_t QWORD; -typedef long _LONG; +typedef struct _packed bmp_file_header { + uint16_t type; //specifies the file type + uint32_t size; //specifies the size in bytes of the bitmap file + uint32_t reserved; + uint32_t img_data_offset; //species the offset in bytes from the bitmapfileheader to the bitmap bits +} bmp_file_header_t; -typedef struct _packed tagBITMAPFILEHEADER { - WORD bfType; //specifies the file type - DWORD bfSize; //specifies the size in bytes of the bitmap file - WORD bfReserved1; //reserved; must be 0 - WORD bfReserved2; //reserved; must be 0 - DWORD bfOffBits; //species the offset in bytes from the bitmapfileheader to the bitmap bits -} BITMAPFILEHEADER; +typedef struct _packed bmp_info_header { + uint32_t header_size; //specifies the number of bytes required by the struct + uint32_t width; //specifies width in pixels + uint32_t height; //species height in pixels + uint16_t planes; //specifies the number of color planes, must be 1 + uint16_t bit_count; //specifies the number of bit per pixel + uint32_t compression;//spcifies the type of compression + uint32_t img_data_size; //size of image in bytes + uint32_t x_per_meter; //number of pixels per meter in x axis + uint32_t y_per_meter; //number of pixels per meter in y axis + uint32_t num_colors_used; //number of colors used by th ebitmap + uint32_t num_colors_important; //number of colors that are important +} bmp_info_header_t; -typedef struct _packed tagBITMAPINFOHEADER { - DWORD biSize; //specifies the number of bytes required by the struct - _LONG biWidth; //specifies width in pixels - _LONG biHeight; //species height in pixels - WORD biPlanes; //specifies the number of color planes, must be 1 - WORD biBitCount; //specifies the number of bit per pixel - DWORD biCompression;//spcifies the type of compression - DWORD biSizeImage; //size of image in bytes - _LONG biXPelsPerMeter; //number of pixels per meter in x axis - _LONG biYPelsPerMeter; //number of pixels per meter in y axis - DWORD biClrUsed; //number of colors used by th ebitmap - DWORD biClrImportant; //number of colors that are important -} BITMAPINFOHEADER; - -uint8_t *LoadBitmapFile(char *filename, BITMAPINFOHEADER *bitmapInfoHeader); \ No newline at end of file +uint8_t *bmp_read_image(const char *filename, bmp_info_header_t *bmp_info_header); \ No newline at end of file diff --git a/kernel/console.c b/kernel/console.c index 7f1958b..3911eeb 100644 --- a/kernel/console.c +++ b/kernel/console.c @@ -31,14 +31,9 @@ void console_set_serial_enabled(bool enabled) { */ static void knprint(const char *str, size_t len, uint8_t vga_color) { if (vga_enabled) { - int offset = vga_get_cursor_offset(); - int row = vga_get_offset_row(offset); - int col = vga_get_offset_col(offset); - + int offset = -1; for (size_t i = 0; i < len; ++i) { - offset = vga_print_char(str[i], col, row, vga_color); - row = vga_get_offset_row(offset); - col = vga_get_offset_col(offset); + offset = vga_print_char(str[i], offset, vga_color); } } diff --git a/kernel/drivers/vga.c b/kernel/drivers/vga.c index 93d7a57..e3a9c88 100644 --- a/kernel/drivers/vga.c +++ b/kernel/drivers/vga.c @@ -1,16 +1,38 @@ #include "vga.h" #include "ports.h" -#include "../arch/x86/mmu.h" +#include "../psf.h" +#include "../console.h" #include #include #include +#include +#include +// EGA text console uint16_t *console_fb_addr = NULL; +// RGB text console void *rgb_fb_addr = NULL; framebuffer_info_t rgb_fb_info = {}; +psf_font_t rgb_console_font = {}; +void *rgb_console_font_glyphs = NULL; + +unsigned int rgb_console_rows = 0; +unsigned int rgb_console_cols = 0; +int rgb_console_offset = 0; + +typedef struct rgb_console_buffer_entry { + char c; + vga_rgb_color_t fg_color; + vga_rgb_color_t bg_color; +} rgb_console_buffer_entry_t; + +rgb_console_buffer_entry_t *rgb_console_buffer = NULL; + +static void vga_console_repaint(); + void vga_init(void *fb_addr, uint8_t type, framebuffer_info_t *fb_info) { if (type == VGA_FB_TYPE_EGA_TEXT) { console_fb_addr = fb_addr; @@ -20,16 +42,59 @@ void vga_init(void *fb_addr, uint8_t type, framebuffer_info_t *fb_info) { } } +int vga_load_font(const char *filename) { + int prev_width = 0, prev_height = 0; + if (rgb_console_font_glyphs != NULL) { + prev_width = rgb_console_font.width; + prev_height = rgb_console_font.height; + free(rgb_console_font_glyphs); + } + + rgb_console_font_glyphs = psf_read_font(filename, &rgb_console_font); + if (rgb_console_font_glyphs == NULL) { + fprintf(stderr, "Failed to read font %s (err: %d)\n", filename, errno); + return -1; + } + rgb_console_cols = rgb_fb_info.width / rgb_console_font.width; + rgb_console_rows = rgb_fb_info.height / rgb_console_font.height; + + size_t buffer_size = rgb_console_rows * rgb_console_cols * sizeof(rgb_console_buffer_entry_t); + rgb_console_buffer_entry_t *new_buffer = malloc(buffer_size); + if (new_buffer == NULL) { + fprintf(stderr, "Failed to allocate memory for console buffer.\n"); + return -1; + } + memset(new_buffer, 0, buffer_size); + + if (rgb_console_buffer != NULL) { + size_t prev_size = (rgb_fb_info.width / prev_width) + * (rgb_fb_info.height / prev_height) + * sizeof(rgb_console_buffer_entry_t); + if (prev_size > buffer_size) { + size_t diff = prev_size - buffer_size; + memcpy(new_buffer, (void *) rgb_console_buffer + diff, buffer_size); + // FIXME refactor to avoid this kludgy division + rgb_console_offset -= diff / sizeof(rgb_console_buffer_entry_t); + } else { + memcpy(new_buffer, rgb_console_buffer, prev_size); + memset((void *) new_buffer + prev_size, 0, buffer_size - prev_size); + } + free(rgb_console_buffer); + } + rgb_console_buffer = new_buffer; + vga_console_repaint(); + return 0; +} + static inline void vga_set_pixel(int x, int y, uint32_t val) { *(uint32_t *) (rgb_fb_addr + x * 4 + rgb_fb_info.pitch * y) = val; } -void vga_fill_rect(int x1, int y1, int x2, int y2, vga_color_t *color) { +void vga_fill_rect(int x1, int y1, int x2, int y2, vga_rgb_color_t *color) { if (rgb_fb_addr == NULL || rgb_fb_info.bpp != 32) return; - uint32_t val = ((uint32_t) color->red << rgb_fb_info.red_field_position) - | ((uint32_t) color->green << rgb_fb_info.green_field_position) - | ((uint32_t) color->blue << rgb_fb_info.blue_field_position); + | ((uint32_t) color->green << rgb_fb_info.green_field_position) + | ((uint32_t) color->blue << rgb_fb_info.blue_field_position); int xmin = MAX(MIN(x1, x2), 0); int xmax = MIN(MAX(x1, x2), rgb_fb_info.width); @@ -42,45 +107,96 @@ void vga_fill_rect(int x1, int y1, int x2, int y2, vga_color_t *color) { } } -void vga_display_image_bgr(int x, int y, BITMAPINFOHEADER *header, uint8_t *image) { +void vga_display_image_bgra(int x, int y, bmp_info_header_t *header, uint8_t *image) { if (rgb_fb_addr == NULL || rgb_fb_info.bpp != 32) return; - int xmax = MIN(x + header->biWidth, rgb_fb_info.width); - int ymax = MIN(y + header->biHeight, rgb_fb_info.height); + int xmax = MIN(x + header->width, rgb_fb_info.width); + int ymax = MIN(y + header->height, rgb_fb_info.height); for (int y1 = y; y1 < ymax; y1++) { for (int x1 = x; x1 < xmax; x1++) { - uint8_t *pixel = image + (x1 * y1 * 4); // (header->biHeight - y1) - uint32_t val = (uint32_t) *(pixel) << rgb_fb_info.blue_field_position - | (uint32_t) *(pixel + 1) << rgb_fb_info.green_field_position - | (uint32_t) *(pixel + 2) << rgb_fb_info.red_field_position; - vga_set_pixel(x1, y1, val); + uint8_t *pixel = image + ((x1 + ((header->height - y1) * header->width)) * 4); + vga_set_pixel(x1, y1, (uint32_t) *pixel << rgb_fb_info.blue_field_position + | (uint32_t) *(pixel + 1) << rgb_fb_info.green_field_position + | (uint32_t) *(pixel + 2) << rgb_fb_info.red_field_position); } } } -int vga_print_char(char c, int col, int row, char attr) { - if (console_fb_addr == NULL) return 0; - if (!attr) attr = WHITE_ON_BLACK; +static void vga_print_glyph(int offset, char c, vga_rgb_color_t *fg_color, vga_rgb_color_t *bg_color) { + if (rgb_fb_addr == NULL || rgb_fb_info.bpp != 32) return; - /* Error control: print a red 'E' if the coords aren't right */ - if (col >= MAX_COLS || row >= MAX_ROWS) { - console_fb_addr[MAX_COLS * MAX_ROWS - 1] = vga_entry('E', RED_ON_WHITE); - return vga_get_offset(col, row); + int row = offset / rgb_console_cols; + int x = (offset % rgb_console_cols) * rgb_console_font.width; + int y = row * rgb_console_font.height; + + uint32_t fg_val = ((uint32_t) fg_color->red << rgb_fb_info.red_field_position) + | ((uint32_t) fg_color->green << rgb_fb_info.green_field_position) + | ((uint32_t) fg_color->blue << rgb_fb_info.blue_field_position); + uint32_t bg_val = ((uint32_t) bg_color->red << rgb_fb_info.red_field_position) + | ((uint32_t) bg_color->green << rgb_fb_info.green_field_position) + | ((uint32_t) bg_color->blue << rgb_fb_info.blue_field_position); + + int xmax = MIN(x + rgb_console_font.width, rgb_fb_info.width); + int ymax = MIN(y + rgb_console_font.height, rgb_fb_info.height); + uint8_t *glyph = rgb_console_font_glyphs + (rgb_console_font.bytes_per_glyph * (uint8_t) c); + + for (int y1 = y; y1 < ymax; y1++) { + for (int x1 = x; x1 < xmax; x1++) { + uint8_t gb = *(glyph + (y1 - y)); + vga_set_pixel(x1, y1, (gb >> (8 - (x1 - x))) & 1 ? fg_val : bg_val); + } + } +} + +int vga_print_char(char c, int offset, char attr) { + if (rgb_fb_addr != NULL) { + if (rgb_console_font_glyphs == NULL) return 0; + if (offset < 0) { + offset = rgb_console_offset; + } else if (offset >= rgb_console_rows * rgb_console_cols) { + return rgb_console_offset; + } + + if (c == '\b') { + offset--; + } else if (c == '\n') { + unsigned int row = offset / rgb_console_cols; + offset = (row + 1) * rgb_console_cols; + } else { + vga_rgb_color_t fg_color = {255, 255, 255}; + vga_rgb_color_t bg_color = {0, 0, 0}; + + // FIXME make more dynamic + if (attr == RED_ON_BLACK) { + fg_color = (vga_rgb_color_t) {255, 0, 0}; + bg_color = (vga_rgb_color_t) {0, 0, 0}; + } + + rgb_console_buffer[offset] = (rgb_console_buffer_entry_t) {c, fg_color, bg_color}; + if (!c) c = ' '; + vga_print_glyph(offset++, c, &fg_color, &bg_color); + } + rgb_console_offset = offset = vga_handle_scrolling(offset); + } else if (console_fb_addr != NULL) { + if (!attr) attr = WHITE_ON_BLACK; + + if (offset < 0) { + offset = vga_get_cursor_offset(); + } else if (offset >= MAX_ROWS * MAX_COLS) { + console_fb_addr[MAX_COLS * MAX_ROWS - 1] = vga_entry('E', RED_ON_WHITE); + return vga_get_cursor_offset(); + } + + if (c == '\b') { + offset--; + } else if (c == '\n') { + offset = vga_get_offset(0, vga_get_offset_row(offset) + 1); + } else { + console_fb_addr[offset++] = ((uint16_t) attr << 8 | c); + } + vga_set_cursor_offset(offset = vga_handle_scrolling(offset)); } - int offset; - if (col >= 0 && row >= 0) offset = vga_get_offset(col, row); - else offset = vga_get_cursor_offset(); - - if (c == '\b') { - offset--; - } else if (c == '\n') { - row = vga_get_offset_row(offset); - offset = vga_get_offset(0, row + 1); - } else { - console_fb_addr[offset++] = ((uint16_t) attr << 8 | c); - } - vga_set_cursor_offset(offset = vga_handle_scrolling(offset)); return offset; } @@ -102,28 +218,52 @@ void vga_set_cursor_offset(int offset) { } void vga_clear_screen() { - if (console_fb_addr == NULL) return; - memset((void *) console_fb_addr, 0, MAX_COLS * MAX_ROWS * sizeof(*console_fb_addr)); - vga_set_cursor_offset(vga_get_offset(0, 0)); + if (console_fb_addr != NULL) { + memset(console_fb_addr, 0, MAX_COLS * MAX_ROWS * sizeof(*console_fb_addr)); + vga_set_cursor_offset(vga_get_offset(0, 0)); + } else if (rgb_fb_addr != NULL) { + vga_fill_rect(0, 0, rgb_fb_info.width, rgb_fb_info.height, &(vga_rgb_color_t) {0, 0, 0}); + memset(rgb_console_buffer, 0, rgb_console_rows * rgb_console_cols); + rgb_console_offset = 0; + } } -/* Advance the text cursor, scrolling the video buffer if necessary. */ -int vga_handle_scrolling(int cursor_offset) { - if (console_fb_addr == NULL) return 0; - if (cursor_offset < MAX_ROWS * MAX_COLS) - return cursor_offset; +static void vga_console_repaint() { + for (size_t i = 0; i < rgb_console_rows * rgb_console_cols; ++i) { + rgb_console_buffer_entry_t *entry = &rgb_console_buffer[i]; + char c = entry->c; + if (!c) c = ' '; // FIXME improve + vga_print_glyph(i, c, &entry->fg_color, &entry->bg_color); + } +} - /* Shuffle the rows back one. */ - for (int i = 1; i < MAX_ROWS; i++) { - memcpy((void *) (console_fb_addr + vga_get_offset(0, i - 1)), - (void *) (console_fb_addr + vga_get_offset(0, i)), - MAX_COLS * sizeof(*console_fb_addr)); +// Advance the text cursor, scrolling the video buffer if necessary. +int vga_handle_scrolling(int cursor_offset) { + if (console_fb_addr != NULL) { + if (cursor_offset < MAX_ROWS * MAX_COLS) + return cursor_offset; + + for (int i = 1; i < MAX_ROWS; i++) { + memcpy(console_fb_addr + vga_get_offset(0, i - 1), + console_fb_addr + vga_get_offset(0, i), + MAX_COLS * sizeof(*console_fb_addr)); + } + + memset(console_fb_addr + vga_get_offset(0, MAX_ROWS - 1), + 0, MAX_COLS * sizeof(*console_fb_addr)); + + cursor_offset -= MAX_COLS; + } else if (rgb_fb_addr != NULL) { + if (cursor_offset < rgb_console_rows * rgb_console_cols) + return cursor_offset; + + size_t end_offset = (rgb_console_rows - 1) * rgb_console_cols; + memmove(rgb_console_buffer, rgb_console_buffer + rgb_console_cols, + end_offset * sizeof(rgb_console_buffer_entry_t)); + memset(rgb_console_buffer + end_offset, 0, rgb_console_cols * sizeof(rgb_console_buffer_entry_t)); + cursor_offset -= rgb_console_cols; + vga_console_repaint(); } - /* Blank the last line by setting all bytes to 0 */ - memset((void *) (console_fb_addr + vga_get_offset(0, MAX_ROWS - 1)), - 0, MAX_COLS * sizeof(*console_fb_addr)); - - cursor_offset -= MAX_COLS; return cursor_offset; } \ No newline at end of file diff --git a/kernel/drivers/vga.h b/kernel/drivers/vga.h index 3451800..4accb69 100644 --- a/kernel/drivers/vga.h +++ b/kernel/drivers/vga.h @@ -14,7 +14,7 @@ #define VGA_FB_TYPE_RGB 1 #define VGA_FB_TYPE_EGA_TEXT 2 -struct framebuffer_info { +typedef struct framebuffer_info { uint32_t pitch; uint32_t width; uint32_t height; @@ -27,25 +27,25 @@ struct framebuffer_info { uint8_t green_mask_size; uint8_t blue_field_position; uint8_t blue_mask_size; -}; -typedef struct framebuffer_info framebuffer_info_t; +} framebuffer_info_t; -struct vga_color { +typedef struct vga_rgb_color { uint8_t red; uint8_t green; uint8_t blue; -}; -typedef struct vga_color vga_color_t; +} vga_rgb_color_t; void vga_init(void *fb_addr, uint8_t type, framebuffer_info_t *fb_info); -void vga_fill_rect(int x1, int y1, int x2, int y2, vga_color_t *color); +int vga_load_font(const char *filename); -void vga_display_image_bgr(int x, int y, BITMAPINFOHEADER *header, uint8_t *image); +void vga_fill_rect(int x1, int y1, int x2, int y2, vga_rgb_color_t *color); + +void vga_display_image_bgra(int x, int y, bmp_info_header_t *header, uint8_t *image); // --- Console -int vga_print_char(char c, int col, int row, char attr); +int vga_print_char(char c, int offset, char attr); int vga_handle_scrolling(int cursor_offset); diff --git a/kernel/main.c b/kernel/main.c index 236be75..399486a 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -8,13 +8,12 @@ #include "drivers/pci.h" #include "drivers/ata.h" #include "fatfs/ff.h" - -#ifdef ENABLE_DWARF -#include "dwarf.h" #include "bmp.h" #include "drivers/vga.h" #include "arch/x86/mmu.h" +#ifdef ENABLE_DWARF +#include "dwarf.h" #endif #include @@ -51,18 +50,14 @@ void kernel_main(uint32_t multiboot_magic, void *multiboot_info) { // dwarf_find_debug_info(); #endif - console_set_vga_enabled(vga_enabled); + if (vga_enabled && !vga_load_font("assets/default8x16.psfu")) { + console_set_vga_enabled(vga_enabled); + } clear_screen(); + // FIXME add to malloc page_table_set(0x400000, 0xC0400000, 0x83); - BITMAPINFOHEADER bmpHeader; - uint8_t *bmp = LoadBitmapFile("assets/test.bmp", &bmpHeader); - if (bmp == NULL) { - fprintf(stderr, "Failed to read bitmap"); - } else { - printf("Displaying image...\n"); - vga_display_image_bgr(0, 0, &bmpHeader, bmp); - } + page_table_set(0x800000, 0xC0800000, 0x83); #ifdef KDEBUG kprint("Initializing timer...\n"); diff --git a/kernel/multiboot.c b/kernel/multiboot.c index 453e33b..d07e558 100644 --- a/kernel/multiboot.c +++ b/kernel/multiboot.c @@ -123,13 +123,7 @@ void multiboot_init(uint32_t magic, void *info_ptr) { break; case MULTIBOOT_FRAMEBUFFER_TYPE_RGB: - vga_fill_rect(0, 0, 100, 100, &(vga_color_t) {255, 255, 255}); - vga_fill_rect(100, 0, 200, 100, &(vga_color_t) {255, 0, 0}); - vga_fill_rect(200, 0, 300, 100, &(vga_color_t) {0, 255, 0}); - vga_fill_rect(300, 0, 400, 100, &(vga_color_t) {0, 0, 255}); - vga_fill_rect(0, 100, 100, 200, &(vga_color_t) {255, 0, 0}); - vga_fill_rect(100, 100, 200, 200, &(vga_color_t) {0, 255, 0}); - vga_fill_rect(200, 100, 300, 200, &(vga_color_t) {255, 255, 255}); + console_set_vga_enabled(true); break; default: diff --git a/kernel/psf.c b/kernel/psf.c new file mode 100644 index 0000000..8bf2b5a --- /dev/null +++ b/kernel/psf.c @@ -0,0 +1,39 @@ +#include "psf.h" +#include +#include +#include + +void *psf_read_font(const char *filename, psf_font_t *header) { + FILE *font_file; + void *glyphs_data; + + font_file = fopen(filename, "r"); + if (ferror(font_file)) + return NULL; + + fread(header, sizeof(psf_font_t), 1, font_file); + if (ferror(font_file) || header->magic != PSF_FONT_MAGIC) { + fclose(font_file); + return NULL; + } + + fseek(font_file, header->header_size, SEEK_SET); + + uint32_t glyphs_size = header->bytes_per_glyph * header->num_glyph; + glyphs_data = malloc(glyphs_size); + if (glyphs_data == NULL) { + errno = ENOMEM; + free(glyphs_data); + fclose(font_file); + return NULL; + } + + fread(glyphs_data, glyphs_size, 1, font_file); + if (ferror(font_file)) { + fclose(font_file); + return NULL; + } + + fclose(font_file); + return glyphs_data; +} \ No newline at end of file diff --git a/kernel/psf.h b/kernel/psf.h new file mode 100644 index 0000000..f0e06ef --- /dev/null +++ b/kernel/psf.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +#define PSF_FONT_MAGIC 0x864ab572 + +typedef struct psf_font { + uint32_t magic; // magic + uint32_t version; // zero + uint32_t header_size; // offset of bitmaps in file, 32 + uint32_t flags; // 0 if there's no unicode table + uint32_t num_glyph; // number of glyphs + uint32_t bytes_per_glyph; // size of each glyph + uint32_t height; // height in pixels + uint32_t width; // width in pixels +} psf_font_t; + +void *psf_read_font(const char *filename, psf_font_t *header); \ No newline at end of file diff --git a/kernel/shell.c b/kernel/shell.c index 14dd519..8cd7f9c 100644 --- a/kernel/shell.c +++ b/kernel/shell.c @@ -1,24 +1,26 @@ #include "shell.h" +#include "bmp.h" #include "console.h" #include "drivers/acpi.h" +#include "drivers/ata.h" #include "drivers/keyboard.h" -#include "drivers/ports.h" -#include "drivers/serial.h" -#include "tests/tests.h" #include "drivers/pci.h" #include "drivers/pci_registry.h" -#include "drivers/ata.h" +#include "drivers/ports.h" +#include "drivers/serial.h" +#include "drivers/vga.h" #include "elf.h" +#include "tests/tests.h" // FIXME #include "fatfs/ff.h" -#include +#include #include -#include #include #include -#include +#include +#include #define KEY_BUFFER_INITIAL_SIZE 0x100 static char *key_buffer; @@ -220,6 +222,32 @@ static int command_exec(const char *path) { return ret; } +static int command_display(const char* path) { + if (!_fs_mounted) return 255; + + char path_buf[512]; + path_append(path_buf, curr_path, path, sizeof(path_buf)); + + bmp_info_header_t header; + uint8_t *bmp = bmp_read_image(path_buf, &header); + if (bmp == NULL) { + fprintf(stderr, "Failed to read bitmap"); + return 1; + } else { + vga_display_image_bgra(0, 0, &header, bmp); + } + free(bmp); + + return 0; +} + +static int command_font(const char *path) { + if (!_fs_mounted) return 255; + char path_buf[512]; + path_append(path_buf, curr_path, path, sizeof(path_buf)); + return vga_load_font(path_buf) ? 1 : 0; +} + static void print_prompt(int ret) { if (_fs_mounted) { printf("%d %s # ", ret, curr_path); @@ -295,6 +323,10 @@ static void shell_callback(char *input) { ret = command_objdump(input + 8); } else if (strncmp(input, "cat ", 4) == 0) { ret = command_cat(input + 4); + } else if (strncmp(input, "display ", 8) == 0) { + ret = command_display(input + 8); + } else if (strncmp(input, "font ", 5) == 0) { + ret = command_font(input + 5); } else if (strncmp(input, "./", 2) == 0) { ret = command_exec(input + 2); } else {