diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e7eb16..0518c76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,11 +4,7 @@ project(CLeonOS NONE) # User-configurable toolchain and tool variables (Makefile-compatible defaults). set(NO_COLOR 0 CACHE STRING "Disable colored log output when set to 1") include("${CMAKE_SOURCE_DIR}/cmake/log.cmake") -if(NO_COLOR) - set(BUILD_LOG_COLOR_OPT --no-color) -else() - set(BUILD_LOG_COLOR_OPT) -endif() +set(CL_LOG_EMIT_SCRIPT "${CMAKE_SOURCE_DIR}/cmake/log_emit.cmake") set(CC "x86_64-elf-gcc" CACHE STRING "Kernel C compiler") set(LD "x86_64-elf-ld" CACHE STRING "Kernel linker") @@ -48,12 +44,12 @@ function(resolve_tool_with_fallback VAR_NAME) set(_requested "${${VAR_NAME}}") if("${_requested}" STREQUAL "") - message(FATAL_ERROR "[ERROR] empty tool variable: ${VAR_NAME}") + cl_log_error("empty tool variable: ${VAR_NAME}") endif() if(IS_ABSOLUTE "${_requested}") if(NOT EXISTS "${_requested}") - message(FATAL_ERROR "[ERROR] ${VAR_NAME} not found: ${_requested}") + cl_log_error("${VAR_NAME} not found: ${_requested}") endif() set(_resolved "${_requested}") else() @@ -71,7 +67,7 @@ function(resolve_tool_with_fallback VAR_NAME) endif() endforeach() if("${_resolved}" STREQUAL "") - message(FATAL_ERROR "[ERROR] ${VAR_NAME} tool not found: '${_requested}', fallbacks='${_fallbacks}'") + cl_log_error("${VAR_NAME} tool not found: '${_requested}', fallbacks='${_fallbacks}'") endif() endif() endif() @@ -175,7 +171,7 @@ set(KELF_LDFLAGS ) if(NOT CLKS_ARCH STREQUAL "x86_64") - message(FATAL_ERROR "[ERROR] CLKS_ARCH=${CLKS_ARCH} is not supported by this CMake build yet; use x86_64") + cl_log_error("CLKS_ARCH=${CLKS_ARCH} is not supported by this CMake build yet; use x86_64") endif() set(KERNEL_SOURCE_DIRS @@ -207,10 +203,10 @@ list(SORT C_SOURCES) list(SORT ASM_SOURCES) if(NOT C_SOURCES) - message(FATAL_ERROR "[ERROR] no kernel C sources found in clks/") + cl_log_error("no kernel C sources found in clks/") endif() if(NOT EXISTS "${LINKER_SCRIPT}") - message(FATAL_ERROR "[ERROR] missing linker script: ${LINKER_SCRIPT}") + cl_log_error("missing linker script: ${LINKER_SCRIPT}") endif() file(GLOB_RECURSE USER_COMMON_SOURCES_ABS CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/cleonos/c/src/*.c") @@ -238,13 +234,13 @@ list(SORT USER_APP_MAIN_SOURCES) list(SORT USER_APP_KMAIN_SOURCES) if(NOT USER_COMMON_SOURCES) - message(FATAL_ERROR "[ERROR] no user common sources found in cleonos/c/src/") + cl_log_error("no user common sources found in cleonos/c/src/") endif() if(NOT USER_APP_MAIN_SOURCES) - message(FATAL_ERROR "[ERROR] no user app *_main.c found in cleonos/c/apps/") + cl_log_error("no user app *_main.c found in cleonos/c/apps/") endif() if(NOT USER_APP_KMAIN_SOURCES) - message(FATAL_ERROR "[ERROR] no kernel app *_kmain.c found in cleonos/c/apps/") + cl_log_error("no kernel app *_kmain.c found in cleonos/c/apps/") endif() function(add_kernel_c_object SRC OUTPUT_LIST_VAR) @@ -353,7 +349,7 @@ foreach(SRC IN LISTS USER_APP_MAIN_SOURCES) list(FIND USER_APP_NAMES "${_app_name}" _dup_name_idx) if(NOT _dup_name_idx EQUAL -1) - message(FATAL_ERROR "[ERROR] duplicate user app name: ${_app_name}") + cl_log_error("duplicate user app name: ${_app_name}") endif() list(APPEND USER_APP_NAMES "${_app_name}") @@ -381,7 +377,7 @@ foreach(SRC IN LISTS USER_APP_KMAIN_SOURCES) list(FIND USER_APP_NAMES "${_app_name}" _dup_name_idx) if(NOT _dup_name_idx EQUAL -1) - message(FATAL_ERROR "[ERROR] duplicate user app name: ${_app_name}") + cl_log_error("duplicate user app name: ${_app_name}") endif() list(APPEND USER_APP_NAMES "${_app_name}") @@ -400,7 +396,7 @@ foreach(SRC IN LISTS USER_APP_KMAIN_SOURCES) endforeach() if(NOT USER_APP_OUTPUTS) - message(FATAL_ERROR "[ERROR] no user ELF apps were discovered") + cl_log_error("no user ELF apps were discovered") endif() add_custom_target(userapps DEPENDS ${USER_APP_OUTPUTS}) @@ -408,7 +404,11 @@ add_custom_target(userapps DEPENDS ${USER_APP_OUTPUTS}) add_custom_command( TARGET userapps POST_BUILD - COMMAND ${CMAKE_COMMAND} -E cmake_echo_color ${BUILD_LOG_COLOR_OPT} --cyan "[INFO] user elf apps ready" + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=INFO" + "-DLOG_TEXT=user elf apps ready" + -P "${CL_LOG_EMIT_SCRIPT}" ) file(GLOB_RECURSE RAMDISK_FILES CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/ramdisk/*") @@ -493,7 +493,15 @@ add_custom_target(setup-limine add_dependencies(setup-limine setup-tools) add_custom_target(setup DEPENDS setup-tools setup-limine) -add_custom_command(TARGET setup POST_BUILD COMMAND ${CMAKE_COMMAND} -E cmake_echo_color ${BUILD_LOG_COLOR_OPT} --cyan "[INFO] environment ready") +add_custom_command( + TARGET setup + POST_BUILD + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=INFO" + "-DLOG_TEXT=environment ready" + -P "${CL_LOG_EMIT_SCRIPT}" +) add_custom_command( OUTPUT "${ISO_IMAGE}" @@ -506,7 +514,11 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E copy "${LIMINE_BIN_DIR_ABS}/limine-bios-cd.bin" "${ISO_ROOT}/boot/limine/limine-bios-cd.bin" COMMAND ${CMAKE_COMMAND} -E copy "${LIMINE_BIN_DIR_ABS}/limine-uefi-cd.bin" "${ISO_ROOT}/boot/limine/limine-uefi-cd.bin" COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_SOURCE_DIR}/build" - COMMAND ${CMAKE_COMMAND} -E cmake_echo_color ${BUILD_LOG_COLOR_OPT} --magenta "[STEP] building iso -> ${ISO_IMAGE}" + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=STEP" + "-DLOG_TEXT=building iso -> ${ISO_IMAGE}" + -P "${CL_LOG_EMIT_SCRIPT}" COMMAND ${XORRISO} -as mkisofs -b boot/limine/limine-bios-cd.bin -no-emul-boot @@ -518,9 +530,17 @@ add_custom_command( --protective-msdos-label "${ISO_ROOT}" -o "${ISO_IMAGE}" - COMMAND ${CMAKE_COMMAND} -E cmake_echo_color ${BUILD_LOG_COLOR_OPT} --magenta "[STEP] installing limine boot sectors" + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=STEP" + "-DLOG_TEXT=installing limine boot sectors" + -P "${CL_LOG_EMIT_SCRIPT}" COMMAND "${LIMINE_BIN_DIR_ABS}/limine" bios-install "${ISO_IMAGE}" - COMMAND ${CMAKE_COMMAND} -E cmake_echo_color ${BUILD_LOG_COLOR_OPT} --cyan "[INFO] iso ready: ${ISO_IMAGE}" + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=INFO" + "-DLOG_TEXT=iso ready: ${ISO_IMAGE}" + -P "${CL_LOG_EMIT_SCRIPT}" DEPENDS "${KERNEL_ELF}" "${RAMDISK_IMAGE}" "${CMAKE_SOURCE_DIR}/configs/limine.conf" VERBATIM ) @@ -529,29 +549,53 @@ add_custom_target(iso ALL DEPENDS "${ISO_IMAGE}") add_dependencies(iso setup-tools setup-limine kernel ramdisk) add_custom_target(run - COMMAND ${CMAKE_COMMAND} -E cmake_echo_color ${BUILD_LOG_COLOR_OPT} --magenta "[STEP] launching qemu run" + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=STEP" + "-DLOG_TEXT=launching qemu run" + -P "${CL_LOG_EMIT_SCRIPT}" COMMAND ${QEMU_X86_64} -M q35 -m 1024M -cdrom "${ISO_IMAGE}" -serial stdio DEPENDS iso USES_TERMINAL ) add_custom_target(debug - COMMAND ${CMAKE_COMMAND} -E cmake_echo_color ${BUILD_LOG_COLOR_OPT} --magenta "[STEP] launching qemu debug (-s -S)" + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=STEP" + "-DLOG_TEXT=launching qemu debug (-s -S)" + -P "${CL_LOG_EMIT_SCRIPT}" COMMAND ${QEMU_X86_64} -M q35 -m 1024M -cdrom "${ISO_IMAGE}" -serial stdio -s -S DEPENDS iso USES_TERMINAL ) add_custom_target(clean-x86 - COMMAND ${CMAKE_COMMAND} -E cmake_echo_color ${BUILD_LOG_COLOR_OPT} --magenta "[STEP] cleaning ${BUILD_ROOT}" + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=STEP" + "-DLOG_TEXT=cleaning ${BUILD_ROOT}" + -P "${CL_LOG_EMIT_SCRIPT}" COMMAND ${CMAKE_COMMAND} -E rm -rf "${BUILD_ROOT}" - COMMAND ${CMAKE_COMMAND} -E cmake_echo_color ${BUILD_LOG_COLOR_OPT} --cyan "[INFO] clean done" + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=INFO" + "-DLOG_TEXT=clean done" + -P "${CL_LOG_EMIT_SCRIPT}" ) add_custom_target(clean-all - COMMAND ${CMAKE_COMMAND} -E cmake_echo_color ${BUILD_LOG_COLOR_OPT} --magenta "[STEP] cleaning build" + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=STEP" + "-DLOG_TEXT=cleaning build" + -P "${CL_LOG_EMIT_SCRIPT}" COMMAND ${CMAKE_COMMAND} -E rm -rf "${CMAKE_SOURCE_DIR}/build" - COMMAND ${CMAKE_COMMAND} -E cmake_echo_color ${BUILD_LOG_COLOR_OPT} --cyan "[INFO] clean-all done" + COMMAND ${CMAKE_COMMAND} + "-DNO_COLOR=${NO_COLOR}" + "-DLOG_LEVEL=INFO" + "-DLOG_TEXT=clean-all done" + -P "${CL_LOG_EMIT_SCRIPT}" ) add_custom_target(cleonos-help diff --git a/clks/drivers/video/framebuffer.c b/clks/drivers/video/framebuffer.c index d0de9f1..25f792d 100644 --- a/clks/drivers/video/framebuffer.c +++ b/clks/drivers/video/framebuffer.c @@ -1,21 +1,46 @@ #include -#include #include -#include "font8x8.h" +#include "psf_font.h" struct clks_fb_state { volatile u8 *address; struct clks_framebuffer_info info; + const struct clks_psf_font *font; + struct clks_psf_font external_font; + clks_bool external_font_active; + u32 glyph_width; + u32 glyph_height; clks_bool ready; }; static struct clks_fb_state clks_fb = { .address = CLKS_NULL, .info = {0, 0, 0, 0}, + .font = CLKS_NULL, + .external_font = {0, 0, 0, 0, CLKS_NULL}, + .external_font_active = CLKS_FALSE, + .glyph_width = 8U, + .glyph_height = 8U, .ready = CLKS_FALSE, }; +static void clks_fb_apply_font(const struct clks_psf_font *font) { + clks_fb.font = font; + clks_fb.glyph_width = 8U; + clks_fb.glyph_height = 8U; + + if (font != CLKS_NULL) { + if (font->width != 0U) { + clks_fb.glyph_width = font->width; + } + + if (font->height != 0U) { + clks_fb.glyph_height = font->height; + } + } +} + static void clks_fb_put_pixel(u32 x, u32 y, u32 rgb) { volatile u8 *row; volatile u32 *pixel; @@ -33,7 +58,7 @@ static void clks_fb_put_pixel(u32 x, u32 y, u32 rgb) { } row = clks_fb.address + ((usize)y * (usize)clks_fb.info.pitch); - pixel = (volatile u32 *)(row + ((usize)x * 4)); + pixel = (volatile u32 *)(row + ((usize)x * 4U)); *pixel = rgb; } @@ -48,6 +73,10 @@ void clks_fb_init(const struct limine_framebuffer *fb) { clks_fb.info.height = (u32)fb->height; clks_fb.info.pitch = (u32)fb->pitch; clks_fb.info.bpp = fb->bpp; + + clks_fb.external_font_active = CLKS_FALSE; + clks_fb_apply_font(clks_psf_default_font()); + clks_fb.ready = CLKS_TRUE; } @@ -67,8 +96,8 @@ void clks_fb_clear(u32 rgb) { return; } - for (y = 0; y < clks_fb.info.height; y++) { - for (x = 0; x < clks_fb.info.width; x++) { + for (y = 0U; y < clks_fb.info.height; y++) { + for (x = 0U; x < clks_fb.info.width; x++) { clks_fb_put_pixel(x, y, rgb); } } @@ -78,18 +107,58 @@ void clks_fb_draw_char(u32 x, u32 y, char ch, u32 fg_rgb, u32 bg_rgb) { const u8 *glyph; u32 row; u32 col; + u32 cols; + u32 rows; - if (clks_fb.ready == CLKS_FALSE) { + if (clks_fb.ready == CLKS_FALSE || clks_fb.font == CLKS_NULL) { return; } - glyph = clks_font8x8_get(ch); + glyph = clks_psf_glyph(clks_fb.font, (u32)(u8)ch); - for (row = 0; row < 8; row++) { - for (col = 0; col < 8; col++) { + cols = clks_fb.glyph_width; + rows = clks_fb.glyph_height; + + if (cols == 0U) { + cols = 8U; + } + + if (rows == 0U) { + rows = 8U; + } + + if (cols > 8U) { + cols = 8U; + } + + for (row = 0U; row < rows; row++) { + u8 bits = glyph[row]; + + for (col = 0U; col < cols; col++) { u8 mask = (u8)(1U << (7U - col)); - u32 color = (glyph[row] & mask) != 0 ? fg_rgb : bg_rgb; + u32 color = (bits & mask) != 0U ? fg_rgb : bg_rgb; clks_fb_put_pixel(x + col, y + row, color); } } +} + +clks_bool clks_fb_load_psf_font(const void *blob, u64 blob_size) { + struct clks_psf_font parsed = {0, 0, 0, 0, CLKS_NULL}; + + if (clks_psf_parse_font(blob, blob_size, &parsed) == CLKS_FALSE) { + return CLKS_FALSE; + } + + clks_fb.external_font = parsed; + clks_fb.external_font_active = CLKS_TRUE; + clks_fb_apply_font(&clks_fb.external_font); + return CLKS_TRUE; +} + +u32 clks_fb_cell_width(void) { + return clks_fb.glyph_width == 0U ? 8U : clks_fb.glyph_width; +} + +u32 clks_fb_cell_height(void) { + return clks_fb.glyph_height == 0U ? 8U : clks_fb.glyph_height; } \ No newline at end of file diff --git a/clks/drivers/video/psf_font.c b/clks/drivers/video/psf_font.c new file mode 100644 index 0000000..adc8597 --- /dev/null +++ b/clks/drivers/video/psf_font.c @@ -0,0 +1,193 @@ +#include "psf_font.h" + +#include +#include + +#define CLKS_PSF1_MAGIC0 0x36U +#define CLKS_PSF1_MAGIC1 0x04U +#define CLKS_PSF1_HEADER_SIZE 4U +#define CLKS_PSF1_GLYPH_COUNT 256U +#define CLKS_PSF1_GLYPH_BYTES 8U +#define CLKS_PSF1_BLOB_SIZE (CLKS_PSF1_HEADER_SIZE + (CLKS_PSF1_GLYPH_COUNT * CLKS_PSF1_GLYPH_BYTES)) + +struct clks_psf1_header { + u8 magic[2]; + u8 mode; + u8 charsize; +}; + +struct clks_psf_seed_glyph { + u8 code; + u8 rows[CLKS_PSF1_GLYPH_BYTES]; +}; + +static const u8 clks_psf_unknown[CLKS_PSF1_GLYPH_BYTES] = { + 0x3C, 0x42, 0x02, 0x0C, 0x10, 0x00, 0x10, 0x00 +}; + +static const struct clks_psf_seed_glyph clks_psf_seed_table[] = { + {' ', {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {'[', {0x1E, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1E, 0x00}}, + {']', {0x78, 0x08, 0x08, 0x08, 0x08, 0x08, 0x78, 0x00}}, + {':', {0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00}}, + {'.', {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00}}, + {'-', {0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}}, + {'/', {0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00}}, + {'_', {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00}}, + {'?', {0x3C, 0x42, 0x02, 0x0C, 0x10, 0x00, 0x10, 0x00}}, + {'0', {0x3C, 0x42, 0x46, 0x4A, 0x52, 0x62, 0x3C, 0x00}}, + {'1', {0x18, 0x28, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00}}, + {'2', {0x3C, 0x42, 0x02, 0x0C, 0x30, 0x40, 0x7E, 0x00}}, + {'3', {0x3C, 0x42, 0x02, 0x1C, 0x02, 0x42, 0x3C, 0x00}}, + {'4', {0x0C, 0x14, 0x24, 0x44, 0x7E, 0x04, 0x04, 0x00}}, + {'5', {0x7E, 0x40, 0x7C, 0x02, 0x02, 0x42, 0x3C, 0x00}}, + {'6', {0x1C, 0x20, 0x40, 0x7C, 0x42, 0x42, 0x3C, 0x00}}, + {'7', {0x7E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00}}, + {'8', {0x3C, 0x42, 0x42, 0x3C, 0x42, 0x42, 0x3C, 0x00}}, + {'9', {0x3C, 0x42, 0x42, 0x3E, 0x02, 0x04, 0x38, 0x00}}, + {'A', {0x18, 0x24, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}}, + {'B', {0x7C, 0x42, 0x42, 0x7C, 0x42, 0x42, 0x7C, 0x00}}, + {'C', {0x3C, 0x42, 0x40, 0x40, 0x40, 0x42, 0x3C, 0x00}}, + {'D', {0x78, 0x44, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00}}, + {'E', {0x7E, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x7E, 0x00}}, + {'F', {0x7E, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x40, 0x00}}, + {'G', {0x3C, 0x42, 0x40, 0x4E, 0x42, 0x42, 0x3C, 0x00}}, + {'H', {0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}}, + {'I', {0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00}}, + {'J', {0x1E, 0x04, 0x04, 0x04, 0x44, 0x44, 0x38, 0x00}}, + {'K', {0x42, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x00}}, + {'L', {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x00}}, + {'M', {0x42, 0x66, 0x5A, 0x5A, 0x42, 0x42, 0x42, 0x00}}, + {'N', {0x42, 0x62, 0x52, 0x4A, 0x46, 0x42, 0x42, 0x00}}, + {'O', {0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}}, + {'P', {0x7C, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x40, 0x00}}, + {'Q', {0x3C, 0x42, 0x42, 0x42, 0x4A, 0x44, 0x3A, 0x00}}, + {'R', {0x7C, 0x42, 0x42, 0x7C, 0x48, 0x44, 0x42, 0x00}}, + {'S', {0x3C, 0x42, 0x40, 0x3C, 0x02, 0x42, 0x3C, 0x00}}, + {'T', {0x7F, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00}}, + {'U', {0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}}, + {'V', {0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00}}, + {'W', {0x42, 0x42, 0x42, 0x5A, 0x5A, 0x66, 0x42, 0x00}}, + {'X', {0x42, 0x42, 0x24, 0x18, 0x24, 0x42, 0x42, 0x00}}, + {'Y', {0x42, 0x42, 0x24, 0x18, 0x08, 0x08, 0x08, 0x00}}, + {'Z', {0x7E, 0x02, 0x04, 0x18, 0x20, 0x40, 0x7E, 0x00}}, +}; + +static u8 clks_psf_default_blob[CLKS_PSF1_BLOB_SIZE]; +static struct clks_psf_font clks_psf_default = {8U, 8U, 0U, 0U, CLKS_NULL}; +static clks_bool clks_psf_default_ready = CLKS_FALSE; + +static clks_bool clks_psf_parse_psf1(const u8 *blob, usize blob_size, struct clks_psf_font *out_font) { + const struct clks_psf1_header *hdr; + u32 glyph_count; + u32 glyph_bytes; + usize payload_size; + + if (blob == CLKS_NULL || out_font == CLKS_NULL) { + return CLKS_FALSE; + } + + if (blob_size < CLKS_PSF1_HEADER_SIZE) { + return CLKS_FALSE; + } + + hdr = (const struct clks_psf1_header *)blob; + + if (hdr->magic[0] != CLKS_PSF1_MAGIC0 || hdr->magic[1] != CLKS_PSF1_MAGIC1) { + return CLKS_FALSE; + } + + glyph_count = (hdr->mode & 0x01U) != 0U ? 512U : 256U; + glyph_bytes = (u32)hdr->charsize; + + if (glyph_bytes == 0U) { + return CLKS_FALSE; + } + + payload_size = (usize)glyph_count * (usize)glyph_bytes; + + if (blob_size < (usize)CLKS_PSF1_HEADER_SIZE + payload_size) { + return CLKS_FALSE; + } + + out_font->width = 8U; + out_font->height = glyph_bytes; + out_font->glyph_count = glyph_count; + out_font->bytes_per_glyph = glyph_bytes; + out_font->glyphs = blob + CLKS_PSF1_HEADER_SIZE; + return CLKS_TRUE; +} + +static void clks_psf_seed_default_blob(void) { + struct clks_psf1_header *hdr; + u32 i; + + clks_memset(clks_psf_default_blob, 0, sizeof(clks_psf_default_blob)); + + hdr = (struct clks_psf1_header *)clks_psf_default_blob; + hdr->magic[0] = CLKS_PSF1_MAGIC0; + hdr->magic[1] = CLKS_PSF1_MAGIC1; + hdr->mode = 0x00U; + hdr->charsize = (u8)CLKS_PSF1_GLYPH_BYTES; + + for (i = 0U; i < CLKS_PSF1_GLYPH_COUNT; i++) { + u8 *dst = clks_psf_default_blob + CLKS_PSF1_HEADER_SIZE + ((usize)i * CLKS_PSF1_GLYPH_BYTES); + clks_memcpy(dst, clks_psf_unknown, CLKS_PSF1_GLYPH_BYTES); + } + + for (i = 0U; i < (u32)(sizeof(clks_psf_seed_table) / sizeof(clks_psf_seed_table[0])); i++) { + const struct clks_psf_seed_glyph *seed = &clks_psf_seed_table[i]; + u8 *dst = clks_psf_default_blob + CLKS_PSF1_HEADER_SIZE + ((usize)seed->code * CLKS_PSF1_GLYPH_BYTES); + clks_memcpy(dst, seed->rows, CLKS_PSF1_GLYPH_BYTES); + } + + for (i = (u32)'A'; i <= (u32)'Z'; i++) { + const u8 *upper = clks_psf_default_blob + CLKS_PSF1_HEADER_SIZE + ((usize)i * CLKS_PSF1_GLYPH_BYTES); + u8 *lower = clks_psf_default_blob + CLKS_PSF1_HEADER_SIZE + ((usize)(i + ('a' - 'A')) * CLKS_PSF1_GLYPH_BYTES); + clks_memcpy(lower, upper, CLKS_PSF1_GLYPH_BYTES); + } +} + +const struct clks_psf_font *clks_psf_default_font(void) { + if (clks_psf_default_ready == CLKS_FALSE) { + clks_psf_seed_default_blob(); + + if (clks_psf_parse_psf1(clks_psf_default_blob, sizeof(clks_psf_default_blob), &clks_psf_default) == CLKS_FALSE) { + clks_psf_default.width = 8U; + clks_psf_default.height = 8U; + clks_psf_default.glyph_count = 1U; + clks_psf_default.bytes_per_glyph = CLKS_PSF1_GLYPH_BYTES; + clks_psf_default.glyphs = clks_psf_unknown; + } + + clks_psf_default_ready = CLKS_TRUE; + } + + return &clks_psf_default; +} + +const u8 *clks_psf_glyph(const struct clks_psf_font *font, u32 codepoint) { + u32 index = codepoint; + + if (font == CLKS_NULL || font->glyphs == CLKS_NULL || font->bytes_per_glyph == 0U) { + return clks_psf_unknown; + } + + if (index >= font->glyph_count) { + index = (u32)'?'; + + if (index >= font->glyph_count) { + index = 0U; + } + } + + return font->glyphs + ((usize)index * (usize)font->bytes_per_glyph); +} + +clks_bool clks_psf_parse_font(const void *blob, u64 blob_size, struct clks_psf_font *out_font) { + if (blob_size == 0ULL) { + return CLKS_FALSE; + } + + return clks_psf_parse_psf1((const u8 *)blob, (usize)blob_size, out_font); +} diff --git a/clks/drivers/video/psf_font.h b/clks/drivers/video/psf_font.h new file mode 100644 index 0000000..8089f79 --- /dev/null +++ b/clks/drivers/video/psf_font.h @@ -0,0 +1,18 @@ +#ifndef CLKS_PSF_FONT_H +#define CLKS_PSF_FONT_H + +#include + +struct clks_psf_font { + u32 width; + u32 height; + u32 glyph_count; + u32 bytes_per_glyph; + const u8 *glyphs; +}; + +const struct clks_psf_font *clks_psf_default_font(void); +const u8 *clks_psf_glyph(const struct clks_psf_font *font, u32 codepoint); +clks_bool clks_psf_parse_font(const void *blob, u64 blob_size, struct clks_psf_font *out_font); + +#endif \ No newline at end of file diff --git a/clks/include/clks/framebuffer.h b/clks/include/clks/framebuffer.h index 6732793..18d4c73 100644 --- a/clks/include/clks/framebuffer.h +++ b/clks/include/clks/framebuffer.h @@ -16,5 +16,8 @@ clks_bool clks_fb_ready(void); struct clks_framebuffer_info clks_fb_info(void); void clks_fb_clear(u32 rgb); void clks_fb_draw_char(u32 x, u32 y, char ch, u32 fg_rgb, u32 bg_rgb); +clks_bool clks_fb_load_psf_font(const void *blob, u64 blob_size); +u32 clks_fb_cell_width(void); +u32 clks_fb_cell_height(void); #endif \ No newline at end of file diff --git a/clks/kernel/kmain.c b/clks/kernel/kmain.c index 4f6b565..69f9381 100644 --- a/clks/kernel/kmain.c +++ b/clks/kernel/kmain.c @@ -1,3 +1,5 @@ +// Kernel main function + #include #include #include @@ -76,6 +78,8 @@ void clks_kernel_main(void) { void *heap_probe = CLKS_NULL; u64 syscall_ticks; u64 fs_root_children; + const void *tty_psf_blob = CLKS_NULL; + u64 tty_psf_size = 0ULL; clks_serial_init(); @@ -153,6 +157,18 @@ void clks_kernel_main(void) { clks_cpu_halt_forever(); } + if (boot_fb != CLKS_NULL) { + tty_psf_blob = clks_fs_read_all("/system/tty.psf", &tty_psf_size); + + if (tty_psf_blob != CLKS_NULL && clks_fb_load_psf_font(tty_psf_blob, tty_psf_size) == CLKS_TRUE) { + clks_tty_init(); + clks_log(CLKS_LOG_INFO, "TTY", "EXTERNAL PSF LOADED /SYSTEM/TTY.PSF"); + clks_log_hex(CLKS_LOG_INFO, "TTY", "PSF_SIZE", tty_psf_size); + } else { + clks_log(CLKS_LOG_WARN, "TTY", "EXTERNAL PSF LOAD FAILED, USING BUILTIN"); + } + } + clks_exec_init(); clks_keyboard_init(); diff --git a/clks/kernel/tty.c b/clks/kernel/tty.c index 8044366..f5c97e8 100644 --- a/clks/kernel/tty.c +++ b/clks/kernel/tty.c @@ -17,6 +17,8 @@ static u32 clks_tty_cursor_col[CLKS_TTY_COUNT]; static u32 clks_tty_rows = 0; static u32 clks_tty_cols = 0; static u32 clks_tty_active_index = 0; +static u32 clks_tty_cell_width = 8U; +static u32 clks_tty_cell_height = 8U; static clks_bool clks_tty_is_ready = CLKS_FALSE; static void clks_tty_fill_row(u32 tty_index, u32 row, char ch) { @@ -28,7 +30,7 @@ static void clks_tty_fill_row(u32 tty_index, u32 row, char ch) { } static void clks_tty_draw_cell(u32 row, u32 col, char ch) { - clks_fb_draw_char(col * 8U, row * 8U, ch, CLKS_TTY_FG, CLKS_TTY_BG); + clks_fb_draw_char(col * clks_tty_cell_width, row * clks_tty_cell_height, ch, CLKS_TTY_FG, CLKS_TTY_BG); } static void clks_tty_redraw_active(void) { @@ -81,8 +83,19 @@ void clks_tty_init(void) { } info = clks_fb_info(); - clks_tty_rows = info.height / 8U; - clks_tty_cols = info.width / 8U; + clks_tty_cell_width = clks_fb_cell_width(); + clks_tty_cell_height = clks_fb_cell_height(); + + if (clks_tty_cell_width == 0U) { + clks_tty_cell_width = 8U; + } + + if (clks_tty_cell_height == 0U) { + clks_tty_cell_height = 8U; + } + + clks_tty_rows = info.height / clks_tty_cell_height; + clks_tty_cols = info.width / clks_tty_cell_width; if (clks_tty_rows > CLKS_TTY_MAX_ROWS) { clks_tty_rows = CLKS_TTY_MAX_ROWS; @@ -92,7 +105,7 @@ void clks_tty_init(void) { clks_tty_cols = CLKS_TTY_MAX_COLS; } - if (clks_tty_rows == 0 || clks_tty_cols == 0) { + if (clks_tty_rows == 0U || clks_tty_cols == 0U) { clks_tty_is_ready = CLKS_FALSE; return; } @@ -216,5 +229,4 @@ u32 clks_tty_count(void) { clks_bool clks_tty_ready(void) { return clks_tty_is_ready; -} - +} \ No newline at end of file diff --git a/cmake/log_emit.cmake b/cmake/log_emit.cmake new file mode 100644 index 0000000..b50b657 --- /dev/null +++ b/cmake/log_emit.cmake @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.20) + +if(NOT DEFINED NO_COLOR) + set(NO_COLOR 0) +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/log.cmake") + +if(NOT DEFINED LOG_LEVEL) + set(LOG_LEVEL "INFO") +endif() + +if(NOT DEFINED LOG_TEXT) + set(LOG_TEXT "") +endif() + +string(TOUPPER "${LOG_LEVEL}" _log_level) + +if(_log_level STREQUAL "STEP") + cl_log_step("${LOG_TEXT}") +elseif(_log_level STREQUAL "INFO") + cl_log_info("${LOG_TEXT}") +elseif(_log_level STREQUAL "WARN") + cl_log_warn("${LOG_TEXT}") +elseif(_log_level STREQUAL "ERROR") + cl_log_error("${LOG_TEXT}") +else() + cl_log_info("${LOG_TEXT}") +endif() \ No newline at end of file diff --git a/ramdisk/system/tty.psf b/ramdisk/system/tty.psf new file mode 100644 index 0000000..0a78e48 Binary files /dev/null and b/ramdisk/system/tty.psf differ