/* Simple Shell for CubeCactusOS
* Basic command-line interface
*/
extern int printf(const char* format, ...);
extern void putchar(char c);
extern char getchar_blocking();
extern void* memset(void* dest, int val, unsigned long count);
extern unsigned long strlen(const char* str);
extern int strcmp(const char* s1, const char* s2);
/* Serial port functions */
extern void serial_init();
extern char serial_getchar();
extern void serial_putchar(char c);
extern void serial_puts(const char* str);
extern int serial_available();
#define MAX_INPUT 128
#define MAX_ARGS 16
static char input_buffer[MAX_INPUT];
static int input_pos = 0;
/* String comparison */
int strcmp(const char* s1, const char* s2) {
while (*s1 && (*s1 == *s2)) {
s1++;
s2++;
}
return *(unsigned char*)s1 - *(unsigned char*)s2;
}
/* String starts with prefix */
int starts_with(const char* str, const char* prefix) {
while (*prefix) {
if (*str++ != *prefix++) return 0;
}
return 1;
}
/* Get a character from serial port */
char getchar_blocking() {
return serial_getchar();
}
/* Print shell prompt */
void print_prompt() {
printf("cubecactusos# ");
}
/* Clear input buffer */
void clear_input() {
memset(input_buffer, 0, MAX_INPUT);
input_pos = 0;
}
/* Execute command with serial output */
void execute_command_serial(const char* cmd) {
if (strlen(cmd) == 0) {
return;
}
if (strcmp(cmd, "help") == 0) {
serial_puts("\r\nCubeCactusOS Shell Commands:\r\n");
serial_puts(" help - Show this help message\r\n");
serial_puts(" about - Display OS information\r\n");
serial_puts(" mem - Display memory information\r\n");
serial_puts(" echo - Echo text to screen\r\n");
serial_puts(" shutdown - Shutdown the system\r\n");
serial_puts("\r\n");
}
else if (strcmp(cmd, "about") == 0) {
serial_puts("\r\nCubeCactusOS v0.1.0\r\n");
serial_puts("A microkernel-based operating system\r\n");
serial_puts("Based on MINIX3 architecture\r\n");
serial_puts("Built with: x86_64-elf-gcc\r\n\r\n");
}
else if (strcmp(cmd, "mem") == 0) {
serial_puts("\r\nMemory Information:\r\n");
serial_puts(" Total RAM: 512 MB\r\n");
serial_puts(" Kernel: ~10 KB\r\n");
serial_puts(" Available: ~512 MB\r\n\r\n");
}
else if (starts_with(cmd, "echo ")) {
serial_puts("\r\n");
serial_puts(cmd + 5);
serial_puts("\r\n\r\n");
}
else if (strcmp(cmd, "shutdown") == 0) {
serial_puts("\r\nShutting down...\r\n");
serial_puts("System halted.\r\n");
for(;;) {
__asm__ __volatile__("hlt");
}
}
else {
serial_puts("\r\nUnknown command: ");
serial_puts(cmd);
serial_puts("\r\nType 'help' for available commands.\r\n\r\n");
}
}
/* Execute command */
void execute_command(const char* cmd) {
if (strlen(cmd) == 0) {
return;
}
if (strcmp(cmd, "help") == 0) {
printf("\nCubeCactusOS Shell Commands:\n");
printf(" help - Show this help message\n");
printf(" about - Display OS information\n");
printf(" clear - Clear the screen (not implemented)\n");
printf(" echo - Echo text to screen\n");
printf(" mem - Display memory information\n");
printf(" uptime - Show system uptime (not implemented)\n");
printf(" reboot - Reboot the system (not implemented)\n");
printf(" shutdown - Shutdown the system (not implemented)\n");
printf("\n");
}
else if (strcmp(cmd, "about") == 0) {
printf("\nCubeCactusOS v0.1.0\n");
printf("A microkernel-based operating system\n");
printf("Based on MINIX3 architecture\n");
printf("Built with: x86_64-elf-gcc\n");
printf("\nComponents:\n");
printf(" - Microkernel (IPC, scheduling)\n");
printf(" - Process Manager (PM)\n");
printf(" - Virtual File System (VFS)\n");
printf(" - TTY Driver\n");
printf("\n");
}
else if (strcmp(cmd, "mem") == 0) {
printf("\nMemory Information:\n");
printf(" Total RAM: 512 MB (configured)\n");
printf(" Kernel Memory: ~10 KB\n");
printf(" Available: ~512 MB\n");
printf(" (Note: Memory management not fully implemented)\n");
printf("\n");
}
else if (starts_with(cmd, "echo ")) {
printf("\n%s\n\n", cmd + 5);
}
else if (strcmp(cmd, "clear") == 0) {
printf("\n(Clear screen not yet implemented)\n\n");
}
else if (strcmp(cmd, "uptime") == 0) {
printf("\nSystem uptime: (Not yet implemented)\n");
printf("Kernel has been running since boot.\n\n");
}
else if (strcmp(cmd, "reboot") == 0) {
printf("\nRebooting system...\n");
printf("(Reboot not yet implemented - please restart QEMU)\n\n");
}
else if (strcmp(cmd, "shutdown") == 0) {
printf("\nShutting down...\n");
printf("System halted. You can close QEMU now.\n");
for(;;) {
__asm__ __volatile__("hlt");
}
}
else {
printf("\nUnknown command: %s\n", cmd);
printf("Type 'help' for available commands.\n\n");
}
}
/* Read a line of input */
void read_line(char* buffer, int max_len) {
int pos = 0;
while (1) {
char c = getchar_blocking();
if (c == '\n') {
buffer[pos] = '\0';
putchar('\n');
break;
} else if (c == '\b') {
/* Backspace */
if (pos > 0) {
pos--;
/* Move cursor back, print space, move back again */
putchar('\b');
putchar(' ');
putchar('\b');
}
} else if (c >= 32 && c <= 126 && pos < max_len - 1) {
/* Printable character */
buffer[pos++] = c;
putchar(c);
}
}
}
/* Main shell loop */
void shell_main() {
char cmd_buffer[MAX_INPUT];
/* Initialize serial port */
serial_init();
/* Send welcome message to both VGA and serial */
printf("========================================\n");
printf(" CubeCactusOS v0.1.0\n");
printf("========================================\n\n");
serial_puts("\r\n========================================\r\n");
serial_puts(" Welcome to CubeCactusOS Shell!\r\n");
serial_puts("========================================\r\n");
serial_puts("Type 'help' for available commands.\r\n\r\n");
/* Interactive shell loop */
while (1) {
/* Print prompt to serial */
serial_puts("cubecactusos# ");
/* Read command from serial */
int pos = 0;
while (1) {
char c = serial_getchar();
/* Echo character back */
serial_putchar(c);
if (c == '\r' || c == '\n') {
cmd_buffer[pos] = '\0';
serial_puts("\r\n");
break;
} else if (c == '\b' || c == 127) {
/* Backspace */
if (pos > 0) {
pos--;
serial_puts(" \b"); /* Erase character */
}
} else if (c >= 32 && c <= 126 && pos < MAX_INPUT - 1) {
/* Printable character */
cmd_buffer[pos++] = c;
}
}
/* Execute command and send output to serial */
if (strlen(cmd_buffer) > 0) {
execute_command_serial(cmd_buffer);
}
}
}