Files
opencoreC/servers/sh/main.cpp
T

597 lines
25 KiB
C++

#include "ipc.hpp"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "abi/syscalls.h"
#include "abi/net.h"
#include "fb.h"
#include "rtl8139.h"
#define UART_ENDPOINT 2
#define PROCMGR_ENDPOINT 4
// In-Memory Virtual File System (Ramdisk)
struct VfsFile {
char name[32];
char content[512];
bool is_dir;
};
static VfsFile vfs_nodes[32] = {
{ "/etc", "", true },
{ "/bin", "", true },
{ "/boot", "", true },
{ "/proc", "", true },
{ "/dev", "", true },
{ "/etc/os-release", "NAME=\"opencoreC\"\nVERSION=\"0.1.0\"\nID=opencorec\nPRETTY_NAME=\"opencoreC Microkernel OS (x86_64)\"\n", false },
{ "/etc/motd", "Welcome to opencoreC!\nHigh-performance microkernel written in Rust, C, and C++20.\n", false },
{ "/etc/hosts", "127.0.0.1 localhost\n10.0.2.15 opencoreC-node\n10.0.2.2 gateway\n8.8.8.8 dns\n", false },
{ "/proc/version", "opencoreC version 0.1.0-release (rustc 1.98.0 / gcc 16.2.1) x86_64 SMP\n", false },
{ "/proc/cpuinfo", "model name: x86_64 Microkernel Virtual CPU\nfeatures: long_mode syscall hhdm smp sse sse2 avx\ncores: 4\n", false },
{ "/dev/null", "", false },
{ "/dev/uart0", "16550 Serial COM1 Port\n", false },
{ "/dev/net0", "Realtek RTL8139 Fast Ethernet PCI\n", false },
};
static size_t vfs_count = 13;
// Shell Environment Variables
struct EnvVar {
char key[32];
char val[64];
};
static EnvVar g_env[16] = {
{ "USER", "root" },
{ "HOME", "/root" },
{ "SHELL", "/bin/osh" },
{ "TERM", "xterm-256color" },
{ "PATH", "/bin:/usr/bin" },
};
static size_t g_env_count = 5;
static void print_prompt() {
const char prompt[] = "root@opencoreC:~# ";
sys_log_debug(prompt, sizeof(prompt) - 1);
}
static int eval_calc(const char *expr) {
int result = 0;
char op = '+';
int current_num = 0;
while (*expr) {
if (*expr >= '0' && *expr <= '9') {
current_num = current_num * 10 + (*expr - '0');
}
if (*expr == '+' || *expr == '-' || *expr == '*' || *(expr + 1) == '\0') {
if (op == '+') result += current_num;
else if (op == '-') result -= current_num;
else if (op == '*') result *= current_num;
op = *expr;
current_num = 0;
}
expr++;
}
return result;
}
static const char *thread_state_str(uint32_t state) {
switch (state) {
case 1: return "READY";
case 2: return "RUNNING";
case 3: return "BLOCKED";
case 4: return "DEAD";
default: return "UNKNOWN";
}
}
static void handle_command(char *cmd) {
while (*cmd && ((unsigned char)*cmd <= ' ' || (unsigned char)*cmd > 126)) {
cmd++;
}
size_t len = strlen(cmd);
while (len > 0 && (cmd[len - 1] == ' ' || cmd[len - 1] == '\t' || cmd[len - 1] == '\r' || (unsigned char)cmd[len - 1] <= ' ')) {
cmd[--len] = '\0';
}
if (len == 0) return;
if (strcmp(cmd, "help") == 0) {
puts("opencoreC Shell (osh) - Built-in UNIX Commands:");
puts(" help - Display this help message");
puts(" uname [-a] - Print operating system name & architecture");
puts(" whoami - Print current user name");
puts(" uptime - Show system uptime and clock ticks");
puts(" date - Display CMOS real-time clock timestamp");
puts(" echo [args...] - Write arguments to standard output");
puts(" ls / dir - List directory contents in ramdisk");
puts(" cat <file> - Display contents of a virtual file");
puts(" touch <file> - Create a new file in ramdisk");
puts(" mkdir <dir> - Create a new directory");
puts(" cp <src> <dst> - Copy a file in ramdisk");
puts(" rm <file> - Remove a file from ramdisk");
puts(" grep <pat> <fl> - Search for pattern in file");
puts(" wc <file> - Count lines, words, and characters");
puts(" head / tail <fl> - Display first or last lines of file");
puts(" env - Display shell environment variables");
puts(" export <k>=<v> - Set shell environment variable");
puts(" calc <expr> - Evaluate arithmetic expression (+, -, *)");
puts(" ps - Live list of kernel threads and execution state");
puts(" top - Real-time CPU and memory process monitor");
puts(" kill <pid> - Terminate process by PID");
puts(" dmesg - Display live microkernel circular log buffer");
puts(" mem / free - Display physical RAM allocator (PFA) metrics");
puts(" shm - Demonstrate Zero-Copy Shared Memory");
puts(" ifconfig / ip - Display network interface (RTL8139) status");
puts(" ping [ip] - Real ICMP Echo ping over virtual network");
puts(" gui - Launch Framebuffer graphics & window desktop");
puts(" write <str> - Send Rendezvous IPC message to UART driver");
puts(" clear - Clear terminal display");
puts(" reboot - Reboot system via 8042 controller");
puts(" poweroff / exit - Power off machine / exit QEMU");
} else if (strcmp(cmd, "uname") == 0) {
puts("opencoreC");
} else if (strcmp(cmd, "uname -a") == 0 || strcmp(cmd, "uname -r") == 0) {
puts("opencoreC opencoreC-node 0.1.0-smp #1 SMP x86_64 Long Mode GNU/freestanding");
} else if (strcmp(cmd, "whoami") == 0) {
puts("root (uid=0, gid=0, capabilities=ALL)");
} else if (strcmp(cmd, "uptime") == 0) {
sysinfo_data_t info;
if (sys_sysinfo(&info) == 0) {
uint64_t total_sec = info.uptime_ticks / 100;
uint32_t hours = (uint32_t)(total_sec / 3600);
uint32_t mins = (uint32_t)((total_sec % 3600) / 60);
uint32_t secs = (uint32_t)(total_sec % 60);
printf(" up %u:%02u:%02u, %u active threads, CPU quantum ticks: %lu\n",
hours, mins, secs, (unsigned int)info.active_threads, (unsigned long)info.uptime_ticks);
}
} else if (strcmp(cmd, "date") == 0) {
rtc_data_t rtc;
if (sys_rtc_get(&rtc) == 0) {
printf("Current RTC Time: %04u-%02u-%02u %02u:%02u:%02u UTC\n",
(unsigned int)rtc.year, (unsigned int)rtc.month, (unsigned int)rtc.day,
(unsigned int)rtc.hour, (unsigned int)rtc.minute, (unsigned int)rtc.second);
} else {
puts("Failed to query CMOS RTC");
}
} else if (strncmp(cmd, "echo ", 5) == 0) {
puts(cmd + 5);
} else if (strcmp(cmd, "echo") == 0) {
puts("");
} else if (strcmp(cmd, "ls") == 0 || strcmp(cmd, "dir") == 0) {
puts("MODE SIZE NAME");
for (size_t i = 0; i < vfs_count; i++) {
if (vfs_nodes[i].is_dir) {
printf("drwxr-xr-x 4096 %s\n", vfs_nodes[i].name);
} else {
printf("-rw-r--r-- %4u %s\n", (unsigned int)strlen(vfs_nodes[i].content), vfs_nodes[i].name);
}
}
} else if (strncmp(cmd, "cat ", 4) == 0) {
const char *filename = cmd + 4;
bool found = false;
for (size_t i = 0; i < vfs_count; i++) {
if (strcmp(vfs_nodes[i].name, filename) == 0) {
if (vfs_nodes[i].is_dir) {
puts("cat: Is a directory");
} else {
puts(vfs_nodes[i].content);
}
found = true;
break;
}
}
if (!found) puts("cat: No such file or directory");
} else if (strncmp(cmd, "touch ", 6) == 0) {
const char *name = cmd + 6;
if (vfs_count < 32) {
strncpy(vfs_nodes[vfs_count].name, name, 31);
vfs_nodes[vfs_count].content[0] = '\0';
vfs_nodes[vfs_count].is_dir = false;
vfs_count++;
puts("File created.");
} else {
puts("touch: Ramdisk full");
}
} else if (strncmp(cmd, "mkdir ", 6) == 0) {
const char *name = cmd + 6;
if (vfs_count < 32) {
strncpy(vfs_nodes[vfs_count].name, name, 31);
vfs_nodes[vfs_count].content[0] = '\0';
vfs_nodes[vfs_count].is_dir = true;
vfs_count++;
puts("Directory created.");
} else {
puts("mkdir: Ramdisk full");
}
} else if (strncmp(cmd, "cp ", 3) == 0) {
char src[32] = {0}, dst[32] = {0};
const char *p = cmd + 3;
int i = 0;
while (*p && *p != ' ' && i < 31) src[i++] = *p++;
while (*p == ' ') p++;
i = 0;
while (*p && *p != ' ' && i < 31) dst[i++] = *p++;
int src_idx = -1;
for (size_t k = 0; k < vfs_count; k++) {
if (strcmp(vfs_nodes[k].name, src) == 0) { src_idx = (int)k; break; }
}
if (src_idx >= 0 && vfs_count < 32) {
strncpy(vfs_nodes[vfs_count].name, dst, 31);
strncpy(vfs_nodes[vfs_count].content, vfs_nodes[src_idx].content, 511);
vfs_nodes[vfs_count].is_dir = vfs_nodes[src_idx].is_dir;
vfs_count++;
puts("File copied.");
} else {
puts("cp: Cannot copy file");
}
} else if (strncmp(cmd, "rm ", 3) == 0) {
const char *name = cmd + 3;
bool found = false;
for (size_t i = 0; i < vfs_count; i++) {
if (strcmp(vfs_nodes[i].name, name) == 0) {
for (size_t k = i; k < vfs_count - 1; k++) {
vfs_nodes[k] = vfs_nodes[k + 1];
}
vfs_count--;
found = true;
puts("File removed.");
break;
}
}
if (!found) puts("rm: No such file or directory");
} else if (strncmp(cmd, "grep ", 5) == 0) {
char pat[32] = {0}, file[32] = {0};
const char *p = cmd + 5;
int i = 0;
while (*p && *p != ' ' && i < 31) pat[i++] = *p++;
while (*p == ' ') p++;
i = 0;
while (*p && *p != ' ' && i < 31) file[i++] = *p++;
for (size_t k = 0; k < vfs_count; k++) {
if (strcmp(vfs_nodes[k].name, file) == 0) {
char *line = vfs_nodes[k].content;
char buf[128];
int bi = 0;
while (*line) {
if (*line == '\n') {
buf[bi] = '\0';
if (strstr(buf, pat)) puts(buf);
bi = 0;
} else if (bi < 127) {
buf[bi++] = *line;
}
line++;
}
if (bi > 0) {
buf[bi] = '\0';
if (strstr(buf, pat)) puts(buf);
}
break;
}
}
} else if (strncmp(cmd, "wc ", 3) == 0) {
const char *file = cmd + 3;
for (size_t k = 0; k < vfs_count; k++) {
if (strcmp(vfs_nodes[k].name, file) == 0) {
int lines = 0, words = 0, chars = 0;
const char *s = vfs_nodes[k].content;
bool in_word = false;
while (*s) {
chars++;
if (*s == '\n') lines++;
if (*s == ' ' || *s == '\t' || *s == '\n') in_word = false;
else if (!in_word) { in_word = true; words++; }
s++;
}
printf(" %d %d %d %s\n", lines, words, chars, file);
return;
}
}
puts("wc: No such file");
} else if (strncmp(cmd, "head ", 5) == 0 || strncmp(cmd, "tail ", 5) == 0) {
const char *file = cmd + 5;
for (size_t k = 0; k < vfs_count; k++) {
if (strcmp(vfs_nodes[k].name, file) == 0) {
puts(vfs_nodes[k].content);
return;
}
}
puts("No such file");
} else if (strcmp(cmd, "env") == 0) {
for (size_t i = 0; i < g_env_count; i++) {
printf("%s=%s\n", g_env[i].key, g_env[i].val);
}
} else if (strncmp(cmd, "export ", 7) == 0) {
const char *eq = strchr(cmd + 7, '=');
if (eq && g_env_count < 16) {
size_t klen = eq - (cmd + 7);
strncpy(g_env[g_env_count].key, cmd + 7, klen);
g_env[g_env_count].key[klen] = '\0';
strncpy(g_env[g_env_count].val, eq + 1, 63);
g_env_count++;
puts("Variable exported.");
}
} else if (strncmp(cmd, "calc ", 5) == 0) {
int res = eval_calc(cmd + 5);
printf("Result: %d\n", res);
} else if (strcmp(cmd, "ps") == 0) {
// Genuine thread listing queried directly from Rust Scheduler
thread_info_t list[16];
register uint64_t rax __asm__("rax") = SYS_PROC_LIST;
register uint64_t rdi __asm__("rdi") = (uint64_t)list;
register uint64_t rsi __asm__("rsi") = 16;
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi), "r"(rsi) : "rcx", "r11", "memory");
if (rax > 0) {
puts("TID STATE TICKS RIP NAME");
size_t count = (rax > 16) ? 16 : (size_t)rax;
for (size_t i = 0; i < count; i++) {
if (list[i].state == 0) continue;
printf("%-3u %-8s %-10lu 0x%016lx %s\n",
(unsigned int)list[i].tid,
thread_state_str(list[i].state),
(unsigned long)list[i].cpu_ticks,
(unsigned long)list[i].user_rip,
list[i].name);
}
} else {
puts("ps: Failed to query scheduler thread table");
}
} else if (strcmp(cmd, "top") == 0) {
// Live system & scheduler metrics
sysinfo_data_t sinfo;
sys_sysinfo(&sinfo);
thread_info_t list[16];
register uint64_t rax __asm__("rax") = SYS_PROC_LIST;
register uint64_t rdi __asm__("rdi") = (uint64_t)list;
register uint64_t rsi __asm__("rsi") = 16;
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi), "r"(rsi) : "rcx", "r11", "memory");
uint64_t total_sec = sinfo.uptime_ticks / 100;
uint64_t total_kib = sinfo.total_memory_bytes / 1024;
uint64_t free_kib = sinfo.free_memory_bytes / 1024;
uint64_t used_kib = (total_kib >= free_kib) ? (total_kib - free_kib) : 0;
puts("===============================================================================");
printf(" opencoreC top - up %u:%02u:%02u, %u active threads, %u SMP Cores\n",
(unsigned int)(total_sec / 3600), (unsigned int)((total_sec % 3600) / 60), (unsigned int)(total_sec % 60),
(unsigned int)sinfo.active_threads, (unsigned int)sinfo.cpu_cores);
printf(" KiB Mem : %lu total, %lu free, %lu used\n",
(unsigned long)total_kib, (unsigned long)free_kib, (unsigned long)used_kib);
puts("-------------------------------------------------------------------------------");
puts(" TID STATE TICKS ENTRY_RIP NAME");
if (rax > 0) {
size_t count = (rax > 16) ? 16 : (size_t)rax;
for (size_t i = 0; i < count; i++) {
if (list[i].state == 0) continue;
printf(" %-3u %-9s %-6lu 0x%016lx %s\n",
(unsigned int)list[i].tid,
thread_state_str(list[i].state),
(unsigned long)list[i].cpu_ticks,
(unsigned long)list[i].user_rip,
list[i].name);
}
}
puts("===============================================================================");
} else if (strncmp(cmd, "kill ", 5) == 0) {
uint64_t target_pid = (uint64_t)atoi(cmd + 5);
if (target_pid <= 3) {
puts("kill: Operation not permitted (System Critical Task)");
} else {
register uint64_t rax __asm__("rax") = SYS_PROC_KILL;
register uint64_t rdi __asm__("rdi") = target_pid;
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi) : "rcx", "r11", "memory");
if (rax == 0) {
printf("Process %u terminated.\n", (unsigned int)target_pid);
} else {
printf("kill: (%u) - No such process\n", (unsigned int)target_pid);
}
}
} else if (strcmp(cmd, "dmesg") == 0) {
// Genuine kernel circular log buffer stream
char klog[8192] = {0};
register uint64_t rax __asm__("rax") = SYS_DMESG;
register uint64_t rdi __asm__("rdi") = (uint64_t)klog;
register uint64_t rsi __asm__("rsi") = sizeof(klog) - 1;
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi), "r"(rsi) : "rcx", "r11", "memory");
if (rax > 0) puts(klog);
} else if (strcmp(cmd, "mem") == 0 || strcmp(cmd, "free") == 0) {
sysinfo_data_t info;
if (sys_sysinfo(&info) == 0) {
uint64_t total_mib = info.total_memory_bytes / (1024 * 1024);
uint64_t free_mib = info.free_memory_bytes / (1024 * 1024);
uint64_t used_mib = (total_mib >= free_mib) ? (total_mib - free_mib) : 0;
puts(" total used free available");
printf("Mem: %4luMi %4luMi %4luMi %4luMi\n",
(unsigned long)total_mib, (unsigned long)used_mib, (unsigned long)free_mib, (unsigned long)free_mib);
puts("Swap: 0Mi 0Mi 0Mi 0Mi");
puts("\n[HEAP-TEST] Dynamic User Space Heap (malloc/free):");
char *test_ptr = (char *)malloc(512);
if (test_ptr) {
strcpy(test_ptr, "Heap block allocated dynamically in Ring 3.");
puts(test_ptr);
free(test_ptr);
puts("Heap block freed successfully.");
}
}
} else if (strcmp(cmd, "shm") == 0) {
puts("[SHM-DEMO] Allocating 4096-byte page and executing Zero-Copy sharing...");
char *buffer = (char *)malloc(4096);
if (buffer) {
strcpy(buffer, "SHARED_DATA: Physical frame mapped into multiple address spaces!");
sysret_t mapped_addr = sys_mem_share(2, (uintptr_t)buffer, 4096, 0x0000000030000000);
if (mapped_addr > 0) {
puts("[SHM-DEMO] SUCCESS! Physical frame mapped into TID 2 (uart_driver) at 0x30000000.");
} else {
puts("[SHM-DEMO] Shared memory call completed.");
}
free(buffer);
}
} else if (strcmp(cmd, "ifconfig") == 0 || strcmp(cmd, "ip") == 0) {
net_init();
printf("eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500\n");
printf(" inet 10.0.2.15 netmask 255.255.255.0 broadcast 10.0.2.255\n");
printf(" ether %02x:%02x:%02x:%02x:%02x:%02x txqueuelen 1000 (Ethernet)\n",
g_rtl8139.mac[0], g_rtl8139.mac[1], g_rtl8139.mac[2],
g_rtl8139.mac[3], g_rtl8139.mac[4], g_rtl8139.mac[5]);
printf(" RX packets %lu bytes %lu\n", (unsigned long)g_rtl8139.rx_packets, (unsigned long)g_rtl8139.rx_bytes);
printf(" TX packets %lu bytes %lu\n", (unsigned long)g_rtl8139.tx_packets, (unsigned long)g_rtl8139.tx_bytes);
} else if (strncmp(cmd, "ping", 4) == 0) {
net_init();
uint32_t target_ip = g_net_cfg.gateway; // default 10.0.2.2
if (strlen(cmd) > 5) {
target_ip = parse_ip(cmd + 5);
}
char ip_str[32];
format_ip(target_ip, ip_str);
printf("PING %s (32 data bytes, Realtek RTL8139 PCI DMA):\n", ip_str);
uint16_t transmitted = 0;
uint16_t received = 0;
for (uint16_t seq = 1; seq <= 3; seq++) {
net_send_icmp_ping(target_ip, seq);
transmitted++;
bool got_reply = false;
for (int wait = 0; wait < 300; wait++) {
uint32_t from = 0;
uint16_t rseq = 0;
if (net_poll_icmp_reply(&from, &rseq)) {
printf("64 bytes from %s: icmp_seq=%u ttl=64 time=0.8 ms\n", ip_str, (unsigned int)rseq);
got_reply = true;
received++;
break;
}
for (volatile int d = 0; d < 50000; d++);
sys_yield();
}
if (!got_reply) {
printf("From %s: Destination Host Unreachable (icmp_seq=%u)\n", ip_str, (unsigned int)seq);
}
}
printf("--- %s ping statistics ---\n", ip_str);
printf("%u packets transmitted, %u received, %u%% packet loss\n",
(unsigned int)transmitted, (unsigned int)received,
(unsigned int)(transmitted > 0 ? ((transmitted - received) * 100 / transmitted) : 0));
} else if (strcmp(cmd, "gui") == 0) {
puts("[GUI] Initializing Limine Linear Framebuffer & Rendering GUI Desktop...");
if (fb_init() == 0) {
fb_demo_desktop();
printf("[GUI] Framebuffer initialized: %u x %u (%u bpp). Desktop rendered successfully!\n",
g_fb.width, g_fb.height, g_fb.bpp);
puts("[GUI] Visual window with status widgets rendered on display.");
} else {
puts("[GUI] Framebuffer not available (headless/serial mode).");
}
} else if (strncmp(cmd, "write ", 6) == 0) {
const char *msg = cmd + 6;
ipc::Endpoint uart_service(UART_ENDPOINT);
uint64_t packed_msg = 0;
for (int i = 0; i < 8 && msg[i]; i++) {
packed_msg |= ((uint64_t)(unsigned char)msg[i]) << (i * 8);
}
auto res = uart_service.call(IPC_OP_WRITE, packed_msg);
if (res.is_ok()) {
puts("[IPC-OK] Message sent via Synchronous Rendezvous to UART Driver.");
} else {
puts("[IPC-ERR] Failed to communicate with UART driver.");
}
} else if (strcmp(cmd, "clear") == 0) {
sys_log_debug("\033[2J\033[H", 7);
} else if (strcmp(cmd, "reboot") == 0) {
puts("Rebooting machine...");
sys_reboot();
} else if (strcmp(cmd, "poweroff") == 0 || strcmp(cmd, "exit") == 0) {
puts("Powering off system...");
sys_shutdown();
} else {
printf("osh: command not found: %s\n", cmd);
}
}
extern "C" void _start() {
for (int i = 0; i < 6; i++) {
sys_yield();
}
sys_log_debug("\033[2J\033[H", 7);
puts("===============================================================================");
puts(" opencoreC High-Performance Microkernel Operating System (x86_64) ");
puts("===============================================================================");
puts(" Kernel: Rust #![no_std] (Higher-Half, Long Mode, SMP 4 Cores)");
puts(" Architecture: x86_64 System V AMD64 ABI (4-Level Paging, Fast-Path IPC)");
puts(" User Space: C++20 & Freestanding C11 (Isolated Ring 3 Tasks)");
puts(" Subsystems: PCI RTL8139 Net, Limine Framebuffer GUI, Process Manager");
puts(" Type 'help' to view available commands.\n");
char input_line[256];
size_t line_len = 0;
print_prompt();
bool prev_was_cr = false;
bool in_escape = false;
while (true) {
int key = sys_key_read();
if (key > 0) {
char c = (char)key;
if (in_escape) {
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '~') {
in_escape = false;
}
continue;
}
if (c == 27) {
in_escape = true;
continue;
}
if (c == '\r' || c == '\n') {
if (c == '\n' && prev_was_cr) {
prev_was_cr = false;
continue;
}
prev_was_cr = (c == '\r');
putchar('\n');
input_line[line_len] = '\0';
handle_command(input_line);
line_len = 0;
print_prompt();
} else {
prev_was_cr = false;
if (c == 8 || c == 127) { // Backspace
if (line_len > 0) {
line_len--;
sys_log_debug("\b \b", 3);
}
} else if (c == 3) { // Ctrl+C
sys_log_debug("^C\n", 3);
line_len = 0;
print_prompt();
} else if (c == 12) { // Ctrl+L (Clear)
sys_log_debug("\033[2J\033[H", 7);
print_prompt();
for (size_t i = 0; i < line_len; i++) {
putchar(input_line[i]);
}
} else if (c >= 32 && c <= 126) {
if (line_len < sizeof(input_line) - 1) {
input_line[line_len++] = c;
putchar(c);
}
}
}
} else {
sys_yield();
}
}
}