This commit is contained in:
2026-04-11 16:46:10 +08:00
parent 462f19f754
commit 48dc5e9857
7 changed files with 208 additions and 6 deletions

View File

@@ -1,4 +1,5 @@
#include <clks/framebuffer.h>
#include <clks/string.h>
#include <clks/types.h>
#include "psf_font.h"
@@ -103,6 +104,45 @@ void clks_fb_clear(u32 rgb) {
}
}
void clks_fb_scroll_up(u32 pixel_rows, u32 fill_rgb) {
usize row_bytes;
usize move_bytes;
u32 y;
u32 x;
if (clks_fb.ready == CLKS_FALSE) {
return;
}
if (clks_fb.info.bpp != 32) {
return;
}
if (pixel_rows == 0U) {
return;
}
if (pixel_rows >= clks_fb.info.height) {
clks_fb_clear(fill_rgb);
return;
}
row_bytes = (usize)clks_fb.info.pitch;
move_bytes = (usize)(clks_fb.info.height - pixel_rows) * row_bytes;
clks_memmove(
(void *)clks_fb.address,
(const void *)(clks_fb.address + ((usize)pixel_rows * row_bytes)),
move_bytes
);
for (y = clks_fb.info.height - pixel_rows; y < clks_fb.info.height; y++) {
for (x = 0U; x < clks_fb.info.width; x++) {
clks_fb_put_pixel(x, y, fill_rgb);
}
}
}
void clks_fb_draw_char(u32 x, u32 y, char ch, u32 fg_rgb, u32 bg_rgb) {
const u8 *glyph;
u32 row;

View File

@@ -15,6 +15,7 @@ void clks_fb_init(const struct limine_framebuffer *fb);
clks_bool clks_fb_ready(void);
struct clks_framebuffer_info clks_fb_info(void);
void clks_fb_clear(u32 rgb);
void clks_fb_scroll_up(u32 pixel_rows, u32 fill_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);

View File

@@ -95,7 +95,7 @@ void clks_kernel_main(void) {
clks_tty_init();
}
clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS STAGE16 START");
clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS STAGE18 START");
if (boot_fb == CLKS_NULL) {
clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE");
@@ -218,10 +218,12 @@ void clks_kernel_main(void) {
clks_log_hex(CLKS_LOG_INFO, "SYSCALL", "TICKS", syscall_ticks);
clks_shell_init();
clks_log(CLKS_LOG_INFO, "SHELL", "KERNEL SHELL ACTIVE");
clks_log_hex(CLKS_LOG_INFO, "TTY", "COUNT", (u64)clks_tty_count());
clks_log_hex(CLKS_LOG_INFO, "TTY", "ACTIVE", (u64)clks_tty_active());
clks_log(CLKS_LOG_INFO, "TTY", "VIRTUAL TTY0 READY");
clks_log(CLKS_LOG_INFO, "TTY", "CURSOR ENABLED");
clks_log(CLKS_LOG_DEBUG, "KERNEL", "IDLE LOOP ENTER");
clks_cpu_halt_forever();

View File

@@ -20,6 +20,7 @@ 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 clks_bool clks_tty_cursor_visible = CLKS_FALSE;
static void clks_tty_fill_row(u32 tty_index, u32 row, char ch) {
u32 col;
@@ -29,8 +30,57 @@ static void clks_tty_fill_row(u32 tty_index, u32 row, char ch) {
}
}
static void clks_tty_draw_cell_with_colors(u32 row, u32 col, char ch, u32 fg, u32 bg) {
clks_fb_draw_char(col * clks_tty_cell_width, row * clks_tty_cell_height, ch, fg, bg);
}
static void clks_tty_draw_cell(u32 row, u32 col, char ch) {
clks_fb_draw_char(col * clks_tty_cell_width, row * clks_tty_cell_height, ch, CLKS_TTY_FG, CLKS_TTY_BG);
clks_tty_draw_cell_with_colors(row, col, ch, CLKS_TTY_FG, CLKS_TTY_BG);
}
static void clks_tty_hide_cursor(void) {
u32 row;
u32 col;
if (clks_tty_is_ready == CLKS_FALSE || clks_tty_cursor_visible == CLKS_FALSE) {
return;
}
row = clks_tty_cursor_row[clks_tty_active_index];
col = clks_tty_cursor_col[clks_tty_active_index];
if (row < clks_tty_rows && col < clks_tty_cols) {
clks_tty_draw_cell(row, col, clks_tty_cells[clks_tty_active_index][row][col]);
}
clks_tty_cursor_visible = CLKS_FALSE;
}
static void clks_tty_draw_cursor(void) {
u32 row;
u32 col;
if (clks_tty_is_ready == CLKS_FALSE) {
return;
}
row = clks_tty_cursor_row[clks_tty_active_index];
col = clks_tty_cursor_col[clks_tty_active_index];
if (row >= clks_tty_rows || col >= clks_tty_cols) {
clks_tty_cursor_visible = CLKS_FALSE;
return;
}
clks_tty_draw_cell_with_colors(
row,
col,
clks_tty_cells[clks_tty_active_index][row][col],
CLKS_TTY_BG,
CLKS_TTY_FG
);
clks_tty_cursor_visible = CLKS_TRUE;
}
static void clks_tty_redraw_active(void) {
@@ -38,12 +88,15 @@ static void clks_tty_redraw_active(void) {
u32 col;
clks_fb_clear(CLKS_TTY_BG);
clks_tty_cursor_visible = CLKS_FALSE;
for (row = 0; row < clks_tty_rows; row++) {
for (col = 0; col < clks_tty_cols; col++) {
clks_tty_draw_cell(row, col, clks_tty_cells[clks_tty_active_index][row][col]);
}
}
clks_tty_draw_cursor();
}
static void clks_tty_scroll_up(u32 tty_index) {
@@ -60,7 +113,13 @@ static void clks_tty_scroll_up(u32 tty_index) {
clks_tty_fill_row(tty_index, clks_tty_rows - 1, ' ');
if (tty_index == clks_tty_active_index) {
clks_tty_redraw_active();
u32 col;
clks_fb_scroll_up(clks_tty_cell_height, CLKS_TTY_BG);
for (col = 0U; col < clks_tty_cols; col++) {
clks_tty_draw_cell(clks_tty_rows - 1U, col, clks_tty_cells[tty_index][clks_tty_rows - 1U][col]);
}
}
}
@@ -121,6 +180,7 @@ void clks_tty_init(void) {
clks_tty_active_index = 0;
clks_tty_is_ready = CLKS_TRUE;
clks_tty_cursor_visible = CLKS_FALSE;
clks_tty_redraw_active();
}
@@ -133,12 +193,15 @@ void clks_tty_write_char(char ch) {
return;
}
clks_tty_hide_cursor();
tty_index = clks_tty_active_index;
row = clks_tty_cursor_row[tty_index];
col = clks_tty_cursor_col[tty_index];
if (ch == '\r') {
clks_tty_cursor_col[tty_index] = 0;
clks_tty_draw_cursor();
return;
}
@@ -151,11 +214,13 @@ void clks_tty_write_char(char ch) {
clks_tty_cursor_row[tty_index] = clks_tty_rows - 1;
}
clks_tty_draw_cursor();
return;
}
if (ch == '\b') {
if (col == 0U && row == 0U) {
clks_tty_draw_cursor();
return;
}
@@ -169,6 +234,7 @@ void clks_tty_write_char(char ch) {
clks_tty_put_visible(tty_index, row, col, ' ');
clks_tty_cursor_row[tty_index] = row;
clks_tty_cursor_col[tty_index] = col;
clks_tty_draw_cursor();
return;
}
@@ -192,6 +258,8 @@ void clks_tty_write_char(char ch) {
clks_tty_cursor_row[tty_index] = clks_tty_rows - 1;
}
}
clks_tty_draw_cursor();
}
void clks_tty_write(const char *text) {
@@ -216,13 +284,16 @@ void clks_tty_switch(u32 tty_index) {
return;
}
clks_tty_hide_cursor();
clks_tty_active_index = tty_index;
clks_tty_cursor_visible = CLKS_FALSE;
clks_tty_redraw_active();
}
u32 clks_tty_active(void) {
return clks_tty_active_index;
}
u32 clks_tty_count(void) {
return CLKS_TTY_COUNT;
}

View File

@@ -9,6 +9,7 @@
static clks_bool clks_user_shell_ready = CLKS_FALSE;
static clks_bool clks_user_shell_exec_requested_flag = CLKS_FALSE;
static clks_bool clks_user_shell_exec_enabled = CLKS_FALSE;
static u64 clks_user_launch_attempt_count = 0ULL;
static u64 clks_user_launch_success_count = 0ULL;
static u64 clks_user_launch_fail_count = 0ULL;
@@ -82,6 +83,7 @@ clks_bool clks_userland_init(void) {
clks_user_shell_ready = CLKS_FALSE;
clks_user_shell_exec_requested_flag = CLKS_FALSE;
clks_user_shell_exec_enabled = CLKS_FALSE;
clks_user_launch_attempt_count = 0ULL;
clks_user_launch_success_count = 0ULL;
clks_user_launch_fail_count = 0ULL;
@@ -103,12 +105,14 @@ clks_bool clks_userland_init(void) {
return CLKS_FALSE;
}
(void)clks_userland_request_shell_exec();
clks_log(CLKS_LOG_INFO, "USER", "USER SHELL EXEC DISABLED (KERNEL SHELL MODE)");
return CLKS_TRUE;
}
void clks_userland_tick(u64 tick) {
if (clks_user_shell_ready == CLKS_FALSE || clks_user_shell_exec_requested_flag == CLKS_TRUE) {
if (clks_user_shell_exec_enabled == CLKS_FALSE ||
clks_user_shell_ready == CLKS_FALSE ||
clks_user_shell_exec_requested_flag == CLKS_TRUE) {
return;
}
@@ -138,4 +142,4 @@ u64 clks_userland_launch_success(void) {
u64 clks_userland_launch_failures(void) {
return clks_user_launch_fail_count;
}
}

Binary file not shown.

84
scripts/gen-tty-psf.ps1 Normal file
View File

@@ -0,0 +1,84 @@
param(
[string]$OutputPath = "ramdisk/system/tty.psf"
)
Add-Type -AssemblyName System.Drawing
$width = 8
$height = 16
$glyphCount = 256
$headerSize = 4
$bytesPerGlyph = $height
$totalSize = $headerSize + ($glyphCount * $bytesPerGlyph)
$fontCandidates = @("Consolas", "Lucida Console", "Courier New")
$font = $null
foreach ($name in $fontCandidates) {
try {
$font = New-Object System.Drawing.Font($name, 14, [System.Drawing.FontStyle]::Regular, [System.Drawing.GraphicsUnit]::Pixel)
if ($font.Name -eq $name) {
break
}
} catch {
$font = $null
}
}
if ($null -eq $font) {
throw "No usable monospace font found for PSF generation"
}
$bytes = New-Object byte[] $totalSize
$bytes[0] = 0x36
$bytes[1] = 0x04
$bytes[2] = 0x00
$bytes[3] = [byte]$bytesPerGlyph
# default all glyphs to blank, avoids noisy '?' for undefined chars.
for ($i = $headerSize; $i -lt $totalSize; $i++) {
$bytes[$i] = 0x00
}
$white = [System.Drawing.Brushes]::White
$black = [System.Drawing.Color]::Black
for ($code = 32; $code -le 126; $code++) {
$ch = [char]$code
$bmp = New-Object System.Drawing.Bitmap $width, $height
$g = [System.Drawing.Graphics]::FromImage($bmp)
$g.Clear($black)
$g.TextRenderingHint = [System.Drawing.Text.TextRenderingHint]::SingleBitPerPixelGridFit
# Small negative offset keeps glyph centered in 8x16 cell for common monospace fonts.
$g.DrawString([string]$ch, $font, $white, -1, -2)
$glyphOffset = $headerSize + ($code * $bytesPerGlyph)
for ($y = 0; $y -lt $height; $y++) {
[byte]$rowBits = 0
for ($x = 0; $x -lt $width; $x++) {
$p = $bmp.GetPixel($x, $y)
if (($p.R + $p.G + $p.B) -ge 384) {
$rowBits = [byte]($rowBits -bor (1 -shl (7 - $x)))
}
}
$bytes[$glyphOffset + $y] = $rowBits
}
$g.Dispose()
$bmp.Dispose()
}
$font.Dispose()
$dir = Split-Path -Parent $OutputPath
if (-not [string]::IsNullOrWhiteSpace($dir)) {
New-Item -ItemType Directory -Force -Path $dir | Out-Null
}
$fullOutput = Join-Path (Resolve-Path '.') $OutputPath
[System.IO.File]::WriteAllBytes($fullOutput, $bytes)
Write-Output "Generated $OutputPath ($($bytes.Length) bytes)"