mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-25 16:52:29 +00:00
feat(rust,gui): RLE compression codec + Rust Lab desktop app
Rust kernel expansion: - rust/src/compress/mod.rs (new): memory-safe PackBits-style run-length encoding codec (rle_compress / rle_decompress) with C-ABI shims, registered in lib.rs. C fallbacks added to rust_fallback.c so aarch64/armv8i match. - include/kernel/rust.h: FFI declarations for the codec. - LazyBox: new `rle <text>` applet that compresses, decompresses, prints the ratio and verifies the round-trip is lossless. GUI expansion: - gui/gui_apps.c: "Rust Lab" app -- a live dashboard for the Rust subsystem. Shows CRC-32C/Adler-32 of a sample, measured ChaCha20/SHA3-256/AES-128 throughput as scaled bars plus a composite score (benchmark run once at launch and cached), and a live ChaCha20 CSPRNG byte stream refreshed periodically. Per-window state freed on close. - Registered "Rust Lab" (info icon) in the desktop app table and on the desktop; desktop icon indices updated for the new entry. Verified: clean build on x86_64/aarch64/armv8i; boots through the SUB login to the desktop with the new Rust Lab icon rendering (screenshotted); checksum self-test prints, 0 panics / 0 OOM. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
This commit is contained in:
1 parent
e93b994469
commit
c414c20b44
8 files changed
+262
-2
No files matched your search
+103
@@ -546,3 +546,106 @@ void gui_app_life_launch(int x, int y, int w, int h) {
|
||||
win->handle_event = life_event;
|
||||
}
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// 8. Rust Kernel Lab -- showcases the memory-safe Rust subsystem
|
||||
// =================================================================
|
||||
typedef struct {
|
||||
rust_crypto_bench_result_t bench; // measured once at launch
|
||||
bool have_bench;
|
||||
uint32_t frame;
|
||||
uint8_t entropy[8]; // live CSPRNG sample
|
||||
} rustlab_data_t;
|
||||
|
||||
static void rustlab_bar(int x, int y, int w, const char* label, uint32_t value,
|
||||
uint32_t max_value, uint32_t color) {
|
||||
char buf[48];
|
||||
gui_gfx_draw_string(x, y, label, GUI_THEME_TEXT_MAIN);
|
||||
int bx = x + 96;
|
||||
int bw = w - 96 - 64;
|
||||
if (bw < 20) bw = 20;
|
||||
gui_gfx_fill_rect(bx, y, bw, 10, GUI_THEME_BG_DARK);
|
||||
uint32_t denom = (max_value > 0) ? max_value : 1;
|
||||
int fill = (int)(((uint64_t)value * (uint64_t)bw) / denom);
|
||||
if (fill > bw) fill = bw;
|
||||
gui_gfx_fill_rect(bx, y, fill, 10, color);
|
||||
gui_gfx_draw_rect(bx, y, bw, 10, GUI_THEME_BORDER);
|
||||
snprintf(buf, sizeof(buf), "%u MB/s", value);
|
||||
gui_gfx_draw_string(bx + bw + 6, y, buf, GUI_THEME_TEXT_MUTED);
|
||||
}
|
||||
|
||||
static void rustlab_paint(gui_window_t* win) {
|
||||
rustlab_data_t* rd = (rustlab_data_t*)win->user_data;
|
||||
if (!rd) return;
|
||||
|
||||
int cx = win->x + 14;
|
||||
int cy = win->y + GUI_TITLEBAR_HEIGHT + 12;
|
||||
int w = win->width - 28;
|
||||
|
||||
gui_gfx_draw_string_16_shadow(cx, cy, "Rust Kernel Subsystem (no_std)", GUI_THEME_PRIMARY, GUI_COLOR_BLACK);
|
||||
cy += 26;
|
||||
|
||||
// Checksum engine (recomputed live -- it is cheap)
|
||||
static const char sample[] = "SUB-OS";
|
||||
uint32_t crc = rust_crc32c((const uint8_t*)sample, 6);
|
||||
uint32_t adl = rust_adler32((const uint8_t*)sample, 6);
|
||||
char buf[80];
|
||||
gui_gfx_draw_string(cx, cy, "Checksums of \"SUB-OS\":", GUI_THEME_SUCCESS);
|
||||
cy += 14;
|
||||
snprintf(buf, sizeof(buf), "CRC-32C 0x%08X Adler-32 0x%08X", crc, adl);
|
||||
gui_gfx_draw_string(cx + 8, cy, buf, GUI_THEME_TEXT_MUTED);
|
||||
cy += 22;
|
||||
|
||||
// Crypto benchmark bars (measured once at launch)
|
||||
gui_gfx_draw_string(cx, cy, "Crypto throughput (measured):", GUI_THEME_SUCCESS);
|
||||
cy += 16;
|
||||
if (rd->have_bench) {
|
||||
uint32_t mx = rd->bench.chacha20_mbs;
|
||||
if (rd->bench.sha3_256_mbs > mx) mx = rd->bench.sha3_256_mbs;
|
||||
if (rd->bench.aes128_mbs > mx) mx = rd->bench.aes128_mbs;
|
||||
rustlab_bar(cx + 4, cy, w, "ChaCha20", rd->bench.chacha20_mbs, mx, GUI_THEME_ACCENT);
|
||||
cy += 16;
|
||||
rustlab_bar(cx + 4, cy, w, "SHA3-256", rd->bench.sha3_256_mbs, mx, GUI_THEME_SUCCESS);
|
||||
cy += 16;
|
||||
rustlab_bar(cx + 4, cy, w, "AES-128", rd->bench.aes128_mbs, mx, GUI_THEME_WARNING);
|
||||
cy += 16;
|
||||
snprintf(buf, sizeof(buf), "Composite score: %u", rd->bench.score);
|
||||
gui_gfx_draw_string(cx + 4, cy, buf, GUI_THEME_TEXT_DIM);
|
||||
cy += 22;
|
||||
} else {
|
||||
gui_gfx_draw_string(cx + 4, cy, "benchmark unavailable", GUI_THEME_TEXT_DIM);
|
||||
cy += 22;
|
||||
}
|
||||
|
||||
// Live CSPRNG entropy, refreshed periodically
|
||||
if ((rd->frame++ % 20) == 0) {
|
||||
rust_csprng_get_random(rd->entropy, sizeof(rd->entropy));
|
||||
}
|
||||
gui_gfx_draw_string(cx, cy, "ChaCha20 CSPRNG stream:", GUI_THEME_SUCCESS);
|
||||
cy += 14;
|
||||
snprintf(buf, sizeof(buf), "%02X %02X %02X %02X %02X %02X %02X %02X",
|
||||
rd->entropy[0], rd->entropy[1], rd->entropy[2], rd->entropy[3],
|
||||
rd->entropy[4], rd->entropy[5], rd->entropy[6], rd->entropy[7]);
|
||||
gui_gfx_draw_string(cx + 8, cy, buf, GUI_THEME_PRIMARY);
|
||||
}
|
||||
|
||||
static void rustlab_event(gui_window_t* win, const gui_event_t* ev) {
|
||||
if (ev->type == GUI_EVENT_CLOSE && win->user_data) {
|
||||
kfree(win->user_data);
|
||||
win->user_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void gui_app_rustlab_launch(int x, int y, int w, int h) {
|
||||
gui_window_t* win = gui_wm_create_window("Rust Lab", x, y, (w > 0) ? w : 420, (h > 0) ? h : 300);
|
||||
if (win) {
|
||||
rustlab_data_t* rd = (rustlab_data_t*)kzalloc(sizeof(rustlab_data_t));
|
||||
if (rd) {
|
||||
rd->have_bench = (rust_crypto_run_benchmark(&rd->bench) == 0);
|
||||
rust_csprng_get_random(rd->entropy, sizeof(rd->entropy));
|
||||
}
|
||||
win->user_data = rd;
|
||||
win->paint = rustlab_paint;
|
||||
win->handle_event = rustlab_event;
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -57,6 +57,7 @@ static const desktop_app_t g_apps[] = {
|
||||
{ "Calculator", GUI_ICON_CALC, gui_app_calc_launch, 260, 100, 220, 240 },
|
||||
{ "Paint", GUI_ICON_PAINT, gui_app_paint_launch, 200, 60, 360, 260 },
|
||||
{ "Life", GUI_ICON_FLASK, gui_app_life_launch, 240, 70, 480, 380 },
|
||||
{ "Rust Lab", GUI_ICON_INFO, gui_app_rustlab_launch, 300, 80, 420, 300 },
|
||||
{ "Clock", GUI_ICON_CLOCK, gui_app_clock_launch, 460, 120, 280, 260 },
|
||||
{ "Settings", GUI_ICON_SETTINGS, gui_app_settings_launch, 160, 60, 400, 320 },
|
||||
{ "About", GUI_ICON_INFO, gui_app_about_launch, 240, 140, 330, 170 },
|
||||
@@ -64,8 +65,9 @@ static const desktop_app_t g_apps[] = {
|
||||
#define APP_COUNT ((int)(sizeof(g_apps) / sizeof(g_apps[0])))
|
||||
|
||||
// Which of the above appear on the desktop itself.
|
||||
// Indices into g_apps[]: Terminal, Files, Monitor, Kernel Log, KTest, Life, Settings.
|
||||
static const int g_desktop_icons[] = { 0, 1, 2, 4, 5, 9, 11 };
|
||||
// Indices into g_apps[]: Terminal, Files, Monitor, Kernel Log, KTest, Life,
|
||||
// Rust Lab, Settings.
|
||||
static const int g_desktop_icons[] = { 0, 1, 2, 4, 5, 9, 10, 12 };
|
||||
#define DESKTOP_ICON_COUNT ((int)(sizeof(g_desktop_icons) / sizeof(g_desktop_icons[0])))
|
||||
|
||||
static bool g_start_menu_open = false;
|
||||
|
||||
@@ -10,5 +10,6 @@ void gui_app_calc_launch(int x, int y, int w, int h);
|
||||
void gui_app_paint_launch(int x, int y, int w, int h);
|
||||
void gui_app_about_launch(int x, int y, int w, int h);
|
||||
void gui_app_life_launch(int x, int y, int w, int h);
|
||||
void gui_app_rustlab_launch(int x, int y, int w, int h);
|
||||
|
||||
#endif // _GUI_APPS_H
|
||||
@@ -76,6 +76,10 @@ uint32_t rust_crc32c(const uint8_t* data, size_t len);
|
||||
uint32_t rust_adler32(const uint8_t* data, size_t len);
|
||||
uint64_t rust_fnv1a64(const uint8_t* data, size_t len);
|
||||
|
||||
// Run-Length Encoding Codec (Rust). Return bytes written, or -1.
|
||||
int rust_rle_compress(const uint8_t* in_buf, size_t in_len, uint8_t* out_buf, size_t max_out);
|
||||
int rust_rle_decompress(const uint8_t* in_buf, size_t in_len, uint8_t* out_buf, size_t max_out);
|
||||
|
||||
// Cryptography
|
||||
int rust_chacha20_crypt(const uint8_t* key, const uint8_t* nonce, uint32_t counter, uint8_t* data, size_t len);
|
||||
int rust_csprng_get_random(uint8_t* buffer, size_t len);
|
||||
|
||||
@@ -251,3 +251,33 @@ uint64_t rust_fnv1a64(const uint8_t* data, size_t len) {
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
// --- RLE codec (C fallback, mirrors rust/src/compress/mod.rs) ---
|
||||
int rust_rle_compress(const uint8_t* in_buf, size_t in_len, uint8_t* out_buf, size_t max_out) {
|
||||
if (!in_buf || !out_buf) return -1;
|
||||
size_t out = 0, i = 0;
|
||||
while (i < in_len) {
|
||||
uint8_t value = in_buf[i];
|
||||
size_t run = 1;
|
||||
while (i + run < in_len && in_buf[i + run] == value && run < 255) run++;
|
||||
if (out + 2 > max_out) return -1;
|
||||
out_buf[out++] = (uint8_t)run;
|
||||
out_buf[out++] = value;
|
||||
i += run;
|
||||
}
|
||||
return (int)out;
|
||||
}
|
||||
|
||||
int rust_rle_decompress(const uint8_t* in_buf, size_t in_len, uint8_t* out_buf, size_t max_out) {
|
||||
if (!in_buf || !out_buf) return -1;
|
||||
size_t out = 0, i = 0;
|
||||
while (i + 1 < in_len) {
|
||||
size_t run = in_buf[i];
|
||||
uint8_t value = in_buf[i + 1];
|
||||
if (run == 0) return -1;
|
||||
if (out + run > max_out) return -1;
|
||||
for (size_t k = 0; k < run; k++) out_buf[out++] = value;
|
||||
i += 2;
|
||||
}
|
||||
return (int)out;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
//! Memory-safe run-length encoding (RLE) codec for SUB-OS.
|
||||
//!
|
||||
//! A compact PackBits-style byte codec: the stream is a sequence of
|
||||
//! (count, value) pairs where `count` is 1..=255. It is intended for run-heavy
|
||||
//! data (framebuffer scanlines, zeroed pages, simple bitmaps) and is fully
|
||||
//! `no_std` with no allocation -- the caller owns both buffers.
|
||||
|
||||
/// Compress `input` into `output` as (count, value) pairs. Returns the number
|
||||
/// of bytes written, or -1 if `output` is too small.
|
||||
pub fn rle_compress(input: &[u8], output: &mut [u8]) -> isize {
|
||||
let mut out = 0usize;
|
||||
let mut i = 0usize;
|
||||
let len = input.len();
|
||||
|
||||
while i < len {
|
||||
let value = input[i];
|
||||
let mut run = 1usize;
|
||||
while i + run < len && input[i + run] == value && run < 255 {
|
||||
run += 1;
|
||||
}
|
||||
if out + 2 > output.len() {
|
||||
return -1;
|
||||
}
|
||||
output[out] = run as u8;
|
||||
output[out + 1] = value;
|
||||
out += 2;
|
||||
i += run;
|
||||
}
|
||||
out as isize
|
||||
}
|
||||
|
||||
/// Expand a (count, value) stream back into `output`. Returns the number of
|
||||
/// bytes written, or -1 on a malformed stream or an output overflow.
|
||||
pub fn rle_decompress(input: &[u8], output: &mut [u8]) -> isize {
|
||||
let mut out = 0usize;
|
||||
let mut i = 0usize;
|
||||
let len = input.len();
|
||||
|
||||
while i + 1 < len {
|
||||
let run = input[i] as usize;
|
||||
let value = input[i + 1];
|
||||
if run == 0 {
|
||||
return -1; // a zero run is never emitted by the compressor
|
||||
}
|
||||
if out + run > output.len() {
|
||||
return -1;
|
||||
}
|
||||
for _ in 0..run {
|
||||
output[out] = value;
|
||||
out += 1;
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
out as isize
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// C ABI shims
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_rle_compress(
|
||||
in_buf: *const u8,
|
||||
in_len: usize,
|
||||
out_buf: *mut u8,
|
||||
max_out: usize,
|
||||
) -> i32 {
|
||||
if in_buf.is_null() || out_buf.is_null() {
|
||||
return -1;
|
||||
}
|
||||
unsafe {
|
||||
let input = core::slice::from_raw_parts(in_buf, in_len);
|
||||
let output = core::slice::from_raw_parts_mut(out_buf, max_out);
|
||||
rle_compress(input, output) as i32
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_rle_decompress(
|
||||
in_buf: *const u8,
|
||||
in_len: usize,
|
||||
out_buf: *mut u8,
|
||||
max_out: usize,
|
||||
) -> i32 {
|
||||
if in_buf.is_null() || out_buf.is_null() {
|
||||
return -1;
|
||||
}
|
||||
unsafe {
|
||||
let input = core::slice::from_raw_parts(in_buf, in_len);
|
||||
let output = core::slice::from_raw_parts_mut(out_buf, max_out);
|
||||
rle_decompress(input, output) as i32
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ pub mod printk;
|
||||
pub mod drivers;
|
||||
pub mod crypto;
|
||||
pub mod checksum;
|
||||
pub mod compress;
|
||||
pub mod fs;
|
||||
pub mod kernel;
|
||||
pub mod storage;
|
||||
|
||||
@@ -482,6 +482,31 @@ static int applet_cksum(int argc, char** argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_rle(int argc, char** argv) {
|
||||
const char* str = (argc >= 2) ? argv[1] : "aaaaabbbccccccccd";
|
||||
size_t len = strlen(str);
|
||||
|
||||
uint8_t comp[512];
|
||||
uint8_t back[512];
|
||||
int clen = rust_rle_compress((const uint8_t*)str, len, comp, sizeof(comp));
|
||||
if (clen < 0) {
|
||||
printk(KERN_ERR "rle: input too large for the demo buffer\n");
|
||||
return 1;
|
||||
}
|
||||
int dlen = rust_rle_decompress(comp, (size_t)clen, back, sizeof(back));
|
||||
|
||||
bool ok = (dlen == (int)len) && (memcmp(back, str, len) == 0);
|
||||
int ratio = (len > 0) ? (clen * 100) / (int)len : 0;
|
||||
|
||||
printk(ANSI_BRIGHT_CYAN "Rust RLE codec" ANSI_RESET " (run-length encoding):\n");
|
||||
printk(" Input : \"%s\"\n", str);
|
||||
printk(" Original : %llu bytes\n", (unsigned long long)len);
|
||||
printk(" Compressed : %d bytes (%d%% of original)\n", clen, ratio);
|
||||
printk(" Round-trip : %s\n", ok ? ANSI_BRIGHT_GREEN "OK (lossless)" ANSI_RESET
|
||||
: ANSI_BRIGHT_RED "MISMATCH" ANSI_RESET);
|
||||
return ok ? 0 : 1;
|
||||
}
|
||||
|
||||
static int applet_rand(int argc, char** argv) {
|
||||
int count = (argc >= 2) ? atoi(argv[1]) : 4;
|
||||
printk("Random Integers: ");
|
||||
@@ -2190,6 +2215,7 @@ static const lazybox_applet_t applets[] = {
|
||||
{"sha256sum", applet_sha256sum, "sha256sum <file|text>", "Compute SHA-256 hash", "Crypto"},
|
||||
{"crc32", applet_crc32, "crc32 <text>", "Calculate CRC32 checksum", "Crypto"},
|
||||
{"cksum", applet_cksum, "cksum <text>", "Rust CRC-32C/Adler-32/FNV", "Crypto"},
|
||||
{"rle", applet_rle, "rle <text>", "Rust RLE compress round-trip","Crypto"},
|
||||
{"rand", applet_rand, "rand [count]", "Generate random numbers", "Crypto"},
|
||||
{"certcheck", applet_certcheck, "certcheck", "View X.509 kernel keyring", "Security"},
|
||||
{"capsh", applet_capsh, "capsh", "View process capabilities", "Security"},
|
||||
|
||||
Reference in new issue
Block a user