feat(sh,gui): universalize binary execution, dynamic VFS, and hardware reporting

- Eliminate hardcoded program names (e.g. hello.opc) in shell hints, help, and VFS
- Automatically resolve and execute any binary by name (e.g. typing 'hello' or '<prog>')
- Dynamically populate VFS /bin from kernel module discovery (sys_module_list)
- Support path filtering in ls (e.g. 'ls /bin', 'ls /etc')
- Dynamically detect real CPU brand string via CPUID (leaf 0x80000002..0x80000004)
- Dynamically format network addresses in shell and GUI instead of hardcoded 10.0.2.15
This commit is contained in:
RarDog
2026-09-03 10:50:40 +03:00
parent de772a2de0
commit c18717539c
2 changed files with 267 additions and 44 deletions
+139 -28
View File
@@ -59,6 +59,35 @@ static lv_disp_draw_buf_t g_draw_buf;
static lv_color32_t g_cursor_map[CURSOR_W * CURSOR_H];
static lv_img_dsc_t g_cursor_dsc;
static void get_cpu_brand(char *brand, size_t max_len) {
memset(brand, 0, max_len);
uint32_t regs[4];
__asm__ volatile("cpuid" : "=a"(regs[0]), "=b"(regs[1]), "=c"(regs[2]), "=d"(regs[3]) : "a"(0x80000000));
if (regs[0] >= 0x80000004) {
char *p = brand;
for (uint32_t leaf = 0x80000002; leaf <= 0x80000004; leaf++) {
uint32_t b_regs[4];
__asm__ volatile("cpuid" : "=a"(b_regs[0]), "=b"(b_regs[1]), "=c"(b_regs[2]), "=d"(b_regs[3]) : "a"(leaf));
if (p - brand + 16 < (int)max_len) {
memcpy(p, b_regs, 16);
p += 16;
}
}
brand[max_len - 1] = '\0';
char *src = brand;
while (*src == ' ') src++;
if (src != brand) {
memmove(brand, src, strlen(src) + 1);
}
} else {
__asm__ volatile("cpuid" : "=a"(regs[0]), "=b"(regs[1]), "=c"(regs[2]), "=d"(regs[3]) : "a"(0));
memcpy(brand, &regs[1], 4);
memcpy(brand + 4, &regs[3], 4);
memcpy(brand + 8, &regs[2], 4);
brand[12] = '\0';
}
}
// Top-level Desktop UI Elements
static lv_obj_t *g_start_menu = NULL;
static lv_obj_t *g_win_console = NULL;
@@ -389,6 +418,11 @@ static void execute_console_command(const char *raw_cmd) {
uint64_t used_mb = (total_mb >= free_mb) ? (total_mb - free_mb) : 0;
uint32_t uptime_sec = (uint32_t)(info.uptime_ticks / 100);
char cpu_brand[64] = {0};
get_cpu_brand(cpu_brand, sizeof(cpu_brand));
char ip_str[32] = {0};
format_ip(g_net_cfg.ip, ip_str);
snprintf(buf, sizeof(buf),
" ___ root@opencoreC\n"
" / \\ -----------------\n"
@@ -396,17 +430,20 @@ static void execute_console_command(const char *raw_cmd) {
" | | / \\ Kernel: v0.1.0-release (Rust #![no_std])\n"
" \\ ___ / | (o) | Uptime: %u mins, %u secs\n"
" \\___/ Shell: osh (opencore shell)\n"
" [=== opencoreC ===] Display: 1280x800 @ 60Hz 32bpp (Limine FB)\n"
" [=== opencoreC ===] Display: %ux%u @ 60Hz 32bpp\n"
" x86_64 SMP DE/WM: LVGL Desktop Compositor (Ring 3)\n"
" Ring 3 Userspace CPU: QEMU Virtual CPU (4 Cores SMP)\n"
" Ring 3 Userspace CPU: %s (4 Cores SMP)\n"
" Fast-Path IPC Cap RAM: %u MiB / %u MiB (%u%%)\n"
" Network: RTL8139 Fast Ethernet (10.0.2.15)\n"
" ACPI: MADT 4 Cores, S5 Power, Hardware Reset\n"
" Network: PCI Ethernet (%s)\n"
" ACPI: S5 Power, Reset, MADT Active\n"
" Security: Ring 3 Fault Isolation (SIGSEGV)\n"
" RNG: Hardware RDRAND / RDSEED Active\n",
uptime_sec / 60, uptime_sec % 60,
(unsigned int)g_fb.width, (unsigned int)g_fb.height,
*cpu_brand ? cpu_brand : "x86_64 Processor",
(unsigned int)used_mb, (unsigned int)total_mb,
total_mb > 0 ? (unsigned int)(used_mb * 100 / total_mb) : 0);
total_mb > 0 ? (unsigned int)(used_mb * 100 / total_mb) : 0,
*ip_str ? ip_str : "Unconfigured");
lv_textarea_add_text(g_txt_term_output, buf);
} else if (strcmp(raw_cmd, "clear") == 0) {
lv_textarea_set_text(g_txt_term_output, "opencoreC Linux-compatible Terminal (osh)\nType 'help' for available commands.\n");
@@ -436,13 +473,22 @@ static void execute_console_command(const char *raw_cmd) {
(unsigned int)total_mb, (unsigned int)used_mb, (unsigned int)free_mb, (unsigned int)free_mb);
lv_textarea_add_text(g_txt_term_output, buf);
} else if (strcmp(raw_cmd, "ifconfig") == 0 || strcmp(raw_cmd, "ip") == 0) {
lv_textarea_add_text(g_txt_term_output,
char ip_str[32], mask_str[32], gw_str[32];
format_ip(g_net_cfg.ip, ip_str);
format_ip(g_net_cfg.netmask, mask_str);
format_ip(g_net_cfg.gateway, gw_str);
snprintf(buf, sizeof(buf),
"eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500\n"
" inet 10.0.2.15 netmask 255.255.255.0 broadcast 10.0.2.255\n"
" ether 52:54:00:12:34:56 txqueuelen 1000 (Realtek RTL8139 DMA)\n"
" gateway 10.0.2.2 (QEMU Virtual SLIRP NAT)\n");
" inet %s netmask %s broadcast 255.255.255.255\n"
" ether %02x:%02x:%02x:%02x:%02x:%02x txqueuelen 1000 (PCI Ethernet)\n"
" gateway %s\n",
ip_str, mask_str,
g_net_cfg.mac[0], g_net_cfg.mac[1], g_net_cfg.mac[2],
g_net_cfg.mac[3], g_net_cfg.mac[4], g_net_cfg.mac[5],
gw_str);
lv_textarea_add_text(g_txt_term_output, buf);
} else if (strncmp(raw_cmd, "ping", 4) == 0) {
uint32_t target_ip = (10) | (0 << 8) | (2 << 16) | (2 << 24); // default 10.0.2.2
uint32_t target_ip = g_net_cfg.gateway ? g_net_cfg.gateway : parse_ip("1.1.1.1");
if (strlen(raw_cmd) > 5) {
target_ip = parse_ip(raw_cmd + 5);
}
@@ -579,9 +625,54 @@ static void execute_console_command(const char *raw_cmd) {
lv_textarea_add_text(g_txt_term_output, "Powering off opencoreC...\n");
register uint64_t rax __asm__("rax") = SYS_SHUTDOWN;
__asm__ volatile("syscall" : "+r"(rax) : : "rcx", "r11", "memory");
} else if (strcmp(raw_cmd, "modules") == 0) {
char mbuf[512] = {0};
int len = sys_module_list(mbuf, sizeof(mbuf) - 1);
if (len > 0) {
lv_textarea_add_text(g_txt_term_output, "In-Memory Boot Modules:\n");
char *p = mbuf;
while (*p) {
char mod[64] = {0};
int mi = 0;
while (*p && *p != ' ' && mi < 63) {
mod[mi++] = *p++;
}
while (*p == ' ') p++;
snprintf(buf, sizeof(buf), " * %s\n", mod);
lv_textarea_add_text(g_txt_term_output, buf);
}
} else {
lv_textarea_add_text(g_txt_term_output, "modules: No modules detected.\n");
}
} else {
snprintf(buf, sizeof(buf), "osh: %s: command not found\n", raw_cmd);
lv_textarea_add_text(g_txt_term_output, buf);
char prog_name[64];
strncpy(prog_name, raw_cmd, sizeof(prog_name) - 1);
prog_name[sizeof(prog_name) - 1] = '\0';
const char *exec_target = prog_name;
while (*exec_target == '.' || *exec_target == '/') {
exec_target++;
}
int64_t tid = sys_module_exec(exec_target);
if (tid < 0 && !strstr(exec_target, ".")) {
char opc_name[70];
snprintf(opc_name, sizeof(opc_name), "%s.opc", exec_target);
tid = sys_module_exec(opc_name);
if (tid < 0) {
char elf_name[70];
snprintf(elf_name, sizeof(elf_name), "%s.elf", exec_target);
tid = sys_module_exec(elf_name);
}
}
if (tid >= 0) {
snprintf(buf, sizeof(buf), "[osh] Process spawned with TID %ld on Ring 3\n", (long)tid);
lv_textarea_add_text(g_txt_term_output, buf);
} else {
snprintf(buf, sizeof(buf), "osh: %s: command not found\n", raw_cmd);
lv_textarea_add_text(g_txt_term_output, buf);
}
}
}
@@ -607,15 +698,20 @@ static void start_item_event_cb(lv_event_t *e) {
// Ping button inside Network window
static void ping_btn_event_cb(lv_event_t *e) {
(void)e;
uint32_t target_ip = (10) | (0 << 8) | (2 << 16) | (2 << 24);
uint32_t target_ip = g_net_cfg.gateway ? g_net_cfg.gateway : parse_ip("1.1.1.1");
int res = net_send_icmp_ping(target_ip, 1);
char ip_str[32];
format_ip(target_ip, ip_str);
char res_buf[128];
if (g_lbl_net_ping_res) {
if (res == 0) {
lv_label_set_text(g_lbl_net_ping_res, "Ping: 10.0.2.2 OK! RTT=0.45ms | 0% Loss (RTL8139 DMA)");
snprintf(res_buf, sizeof(res_buf), "Ping: %s OK! 0%% Loss (PCI DMA)", ip_str);
lv_label_set_text(g_lbl_net_ping_res, res_buf);
lv_obj_set_style_text_color(g_lbl_net_ping_res, lv_color_hex(0x22c55e), 0);
} else {
lv_label_set_text(g_lbl_net_ping_res, "Ping: Transmit error.");
snprintf(res_buf, sizeof(res_buf), "Ping: %s Timeout / Unreachable", ip_str);
lv_label_set_text(g_lbl_net_ping_res, res_buf);
lv_obj_set_style_text_color(g_lbl_net_ping_res, lv_color_hex(0xef4444), 0);
}
}
@@ -624,7 +720,7 @@ static void ping_btn_event_cb(lv_event_t *e) {
static void browser_go_event_cb(lv_event_t *e) {
(void)e;
const char *url = lv_textarea_get_text(g_ta_browser_url);
if (!url || !*url) url = "http://10.0.2.2/index.html";
if (!url || !*url) url = "http://neverssl.com/";
char buf[128];
snprintf(buf, sizeof(buf), "Connecting to %s...", url);
@@ -839,13 +935,24 @@ static void create_desktop_environment() {
lv_obj_set_style_pad_all(net_content, 12, 0);
lv_obj_t *lbl_net_info = lv_label_create(net_content);
lv_label_set_text(lbl_net_info,
"Adapter: Realtek RTL8139 Fast Ethernet PCI\n"
"Mode: PCI Bus Master DMA (CMD: 0x107)\n"
"MAC: 52:54:00:12:34:56\n"
"IP: 10.0.2.15 / 255.255.255.0\n"
"Gateway: 10.0.2.2 (QEMU Virtual NAT)\n"
"DMA RX: 0x2176000 | DMA TX: 0x217a000");
char net_info[256];
char ip_str[32], mask_str[32], gw_str[32];
format_ip(g_net_cfg.ip, ip_str);
format_ip(g_net_cfg.netmask, mask_str);
format_ip(g_net_cfg.gateway, gw_str);
snprintf(net_info, sizeof(net_info),
"Adapter: PCI Fast Ethernet Network Adapter\n"
"Mode: PCI Bus Master DMA Link Active\n"
"MAC: %02x:%02x:%02x:%02x:%02x:%02x\n"
"IP: %s / %s\n"
"Gateway: %s\n"
"Status: Network Stack TCP/IPv4 Ready",
g_net_cfg.mac[0], g_net_cfg.mac[1], g_net_cfg.mac[2],
g_net_cfg.mac[3], g_net_cfg.mac[4], g_net_cfg.mac[5],
*ip_str ? ip_str : "0.0.0.0",
*mask_str ? mask_str : "0.0.0.0",
*gw_str ? gw_str : "None");
lv_label_set_text(lbl_net_info, net_info);
lv_obj_align(lbl_net_info, LV_ALIGN_TOP_LEFT, 0, 0);
lv_obj_set_style_text_color(lbl_net_info, lv_color_hex(0xe2e8f0), 0);
@@ -854,7 +961,7 @@ static void create_desktop_environment() {
lv_obj_align(btn_ping, LV_ALIGN_TOP_LEFT, 0, 150);
lv_obj_set_style_bg_color(btn_ping, lv_color_hex(0x0284c7), 0);
lv_obj_t *lbl_ping_text = lv_label_create(btn_ping);
lv_label_set_text(lbl_ping_text, "Ping Gateway (10.0.2.2)");
lv_label_set_text(lbl_ping_text, "Ping Default Gateway");
lv_obj_center(lbl_ping_text);
lv_obj_add_event_cb(btn_ping, ping_btn_event_cb, LV_EVENT_CLICKED, NULL);
@@ -912,7 +1019,7 @@ static void create_desktop_environment() {
lv_obj_set_size(g_ta_browser_url, 500, 32);
lv_obj_align(g_ta_browser_url, LV_ALIGN_LEFT_MID, 2, 0);
lv_textarea_set_one_line(g_ta_browser_url, true);
lv_textarea_set_text(g_ta_browser_url, "http://10.0.2.2/index.html");
lv_textarea_set_text(g_ta_browser_url, "http://neverssl.com/");
lv_obj_set_style_bg_color(g_ta_browser_url, lv_color_hex(0x0f141f), 0);
lv_obj_set_style_text_color(g_ta_browser_url, lv_color_hex(0xe2e8f0), 0);
lv_obj_set_style_border_color(g_ta_browser_url, lv_color_hex(0x38bdf8), 0);
@@ -932,7 +1039,7 @@ static void create_desktop_environment() {
// Status / HTTP Header Bar
g_lbl_browser_status = lv_label_create(b_content);
lv_label_set_text(g_lbl_browser_status, "Ready | Protocol: TCP/IPv4 | Gateway: 10.0.2.2");
lv_label_set_text(g_lbl_browser_status, "Ready | Protocol: TCP/IPv4");
lv_obj_align(g_lbl_browser_status, LV_ALIGN_TOP_LEFT, 0, 48);
lv_obj_set_style_text_color(g_lbl_browser_status, lv_color_hex(0x94a3b8), 0);
@@ -953,7 +1060,7 @@ static void create_desktop_environment() {
" <p>Network: Realtek RTL8139 Fast Ethernet PCI Bus Master</p>\n"
" <p>Stack: TCP/IPv4, ARP, ICMP, HTTP/1.1</p>\n"
" <hr/>\n"
" <h3>Click 'Go ->' to connect to gateway (10.0.2.2) via TCP!</h3>\n"
" <h3>Enter a URL or domain and click 'Go ->' to navigate via TCP/IPv4</h3>\n"
"</body>\n"
"</html>\n");
@@ -1046,8 +1153,12 @@ static void create_desktop_environment() {
lv_obj_set_flex_flow(tray, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(tray, LV_FLEX_ALIGN_END, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
char tray_lan_buf[32];
char lan_ip[32];
format_ip(g_net_cfg.ip, lan_ip);
snprintf(tray_lan_buf, sizeof(tray_lan_buf), "LAN: %s", *lan_ip ? lan_ip : "0.0.0.0");
g_lbl_tray_net = lv_label_create(tray);
lv_label_set_text(g_lbl_tray_net, "LAN: 10.0.2.15");
lv_label_set_text(g_lbl_tray_net, tray_lan_buf);
lv_obj_set_style_text_color(g_lbl_tray_net, lv_color_hex(0x38bdf8), 0);
lv_obj_set_style_pad_hor(g_lbl_tray_net, 8, 0);