diff --git a/assets/default8x16.psfu b/assets/default8x16.psfu new file mode 100644 index 0000000..e789b77 Binary files /dev/null and b/assets/default8x16.psfu differ diff --git a/assets/drdos8x14.psfu b/assets/drdos8x14.psfu new file mode 100644 index 0000000..a3dd35f Binary files /dev/null and b/assets/drdos8x14.psfu differ diff --git a/assets/system.8x16.psf b/assets/system.8x16.psf new file mode 100644 index 0000000..6d4ad73 Binary files /dev/null and b/assets/system.8x16.psf differ 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 {