mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
CLI apps transfer to Userspace
This commit is contained in:
parent
8c6d751254
commit
304c2e1383
97 changed files with 1669 additions and 2398 deletions
BIN
.DS_Store
vendored
BIN
.DS_Store
vendored
Binary file not shown.
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -22,4 +22,7 @@ boredos.dump
|
|||
qemu-debug.log
|
||||
build/
|
||||
iso_root/
|
||||
limine
|
||||
limine/
|
||||
src/kernel/userland/bin/
|
||||
boredos.iso
|
||||
disk.img
|
||||
|
|
|
|||
15
Makefile
15
Makefile
|
|
@ -15,16 +15,15 @@ KERNEL_ELF = $(BUILD_DIR)/boredos.elf
|
|||
ISO_IMAGE = boredos.iso
|
||||
|
||||
C_SOURCES = $(wildcard $(SRC_DIR)/*.c)
|
||||
CLI_APP_SOURCES = $(wildcard $(SRC_DIR)/cli_apps/*.c)
|
||||
|
||||
ASM_SOURCES = $(wildcard $(SRC_DIR)/*.asm)
|
||||
OBJ_FILES = $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o, $(C_SOURCES)) \
|
||||
$(patsubst $(SRC_DIR)/cli_apps/%.c, $(BUILD_DIR)/cli_apps/%.o, $(CLI_APP_SOURCES)) \
|
||||
$(patsubst $(SRC_DIR)/%.asm, $(BUILD_DIR)/%.o, $(ASM_SOURCES))
|
||||
|
||||
CFLAGS = -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding \
|
||||
-fno-stack-protector -fno-stack-check -fno-lto -fPIE \
|
||||
-m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \
|
||||
-I$(SRC_DIR) -I$(SRC_DIR)/cli_apps
|
||||
-I$(SRC_DIR)
|
||||
|
||||
LDFLAGS = -m elf_x86_64 -nostdlib -static -pie --no-dynamic-linker \
|
||||
-z text -z max-page-size=0x1000 -T linker.ld
|
||||
|
|
@ -42,7 +41,7 @@ all: $(ISO_IMAGE)
|
|||
# Ensure build directories exist
|
||||
$(BUILD_DIR):
|
||||
mkdir -p $(BUILD_DIR)
|
||||
mkdir -p $(BUILD_DIR)/cli_apps
|
||||
mkdir -p $(BUILD_DIR)
|
||||
|
||||
# Download Limine Binaries via Git
|
||||
limine-setup:
|
||||
|
|
@ -62,9 +61,7 @@ limine-setup:
|
|||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR) limine-setup
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
# Compile CLI Apps C Sources
|
||||
$(BUILD_DIR)/cli_apps/%.o: $(SRC_DIR)/cli_apps/%.c | $(BUILD_DIR) limine-setup
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
|
||||
# Assemble ASM Sources
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.asm | $(BUILD_DIR)
|
||||
|
|
@ -96,7 +93,7 @@ $(ISO_IMAGE): $(KERNEL_ELF) limine.cfg limine-setup
|
|||
# Build ISO limine.cfg natively with modules
|
||||
cp limine.cfg $(ISO_DIR)/
|
||||
mkdir -p $(ISO_DIR)/bin
|
||||
@for f in $(SRC_DIR)/userland/*.elf; do \
|
||||
@for f in $(SRC_DIR)/userland/bin/*.elf; do \
|
||||
if [ -f "$$f" ]; then \
|
||||
basename=$$(basename "$$f"); \
|
||||
cp "$$f" $(ISO_DIR)/bin/; \
|
||||
|
|
@ -138,4 +135,4 @@ run: $(ISO_IMAGE)
|
|||
-audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0 \
|
||||
-netdev user,id=net0,hostfwd=udp::12345-:12345 -device e1000,netdev=net0 \
|
||||
-vga std -global VGA.xres=1920 -global VGA.yres=1080 \
|
||||
|
||||
-drive file=disk.img,format=raw,file.locking=off
|
||||
BIN
boredos.iso
BIN
boredos.iso
Binary file not shown.
BIN
build/cmd.o
BIN
build/cmd.o
Binary file not shown.
BIN
build/explorer.o
BIN
build/explorer.o
Binary file not shown.
BIN
build/idt.o
BIN
build/idt.o
Binary file not shown.
BIN
build/main.o
BIN
build/main.o
Binary file not shown.
BIN
build/ps2.o
BIN
build/ps2.o
Binary file not shown.
33
build_error.log
Normal file
33
build_error.log
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
src/kernel/wm.c: In function 'wm_handle_click':
|
||||
src/kernel/wm.c:1491:29: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
|
||||
1491 | if (col < 0) col = 0; if (row < 0) row = 0;
|
||||
| ^~
|
||||
src/kernel/wm.c:1491:51: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
|
||||
1491 | if (col < 0) col = 0; if (row < 0) row = 0;
|
||||
| ^~
|
||||
src/kernel/wm.c: In function 'wm_handle_mouse':
|
||||
src/kernel/wm.c:1884:17: error: implicit declaration of function 'cli_cmd_shutdown' [-Wimplicit-function-declaration]
|
||||
1884 | cli_cmd_shutdown(NULL);
|
||||
| ^~~~~~~~~~~~~~~~
|
||||
src/kernel/wm.c:1886:17: error: implicit declaration of function 'cli_cmd_reboot' [-Wimplicit-function-declaration]
|
||||
1886 | cli_cmd_reboot(NULL);
|
||||
| ^~~~~~~~~~~~~~
|
||||
src/kernel/wm.c:2083:41: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
|
||||
2083 | if (col < 0) col = 0; if (row < 0) row = 0;
|
||||
| ^~
|
||||
src/kernel/wm.c:2083:63: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
|
||||
2083 | if (col < 0) col = 0; if (row < 0) row = 0;
|
||||
| ^~
|
||||
src/kernel/wm.c: At top level:
|
||||
src/kernel/wm.c:1057:13: warning: 'erase_cursor' defined but not used [-Wunused-function]
|
||||
1057 | static void erase_cursor(int x, int y) {
|
||||
| ^~~~~~~~~~~~
|
||||
src/kernel/wm.c:976:13: warning: 'draw_dock_editor' defined but not used [-Wunused-function]
|
||||
976 | static void draw_dock_editor(int x, int y) {
|
||||
| ^~~~~~~~~~~~~~~~
|
||||
src/kernel/wm.c:82:13: warning: 'cursor_visible' defined but not used [-Wunused-variable]
|
||||
82 | static bool cursor_visible = true;
|
||||
| ^~~~~~~~~~~~~~
|
||||
src/kernel/wm.c:79:12: warning: 'desktop_refresh_timer' defined but not used [-Wunused-variable]
|
||||
79 | static int desktop_refresh_timer = 0;
|
||||
| ^~~~~~~~~~~~~~~~~~~~~
|
||||
BIN
disk.img
BIN
disk.img
Binary file not shown.
|
|
@ -1,16 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
#include "io.h"
|
||||
|
||||
void cli_cmd_beep(char *args) {
|
||||
(void)args;
|
||||
cli_write("BEEP!\n");
|
||||
outb(0x43, 0xB6);
|
||||
int freq = 1000;
|
||||
int div = 1193180 / freq;
|
||||
outb(0x42, div & 0xFF);
|
||||
outb(0x42, (div >> 8) & 0xFF);
|
||||
|
||||
outb(0x61, inb(0x61) | 0x03);
|
||||
cli_sleep(100);
|
||||
outb(0x61, inb(0x61) & 0xFC);
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
|
||||
void cli_cmd_blind(char *args) {
|
||||
(void)args;
|
||||
cli_write("Woah.. is this heaven?\n");
|
||||
cli_write("no.\n");
|
||||
cli_write("This isn't TempleOS you fucking retard.\n");
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
|
||||
void cli_cmd_boredver(char *args) {
|
||||
(void)args;
|
||||
cli_write("BoredOS v1.64\n");
|
||||
cli_write("BoredOS Kernel V3.0.0\n");
|
||||
}
|
||||
|
|
@ -1,738 +0,0 @@
|
|||
#include "cli_apps.h"
|
||||
#include "cli_utils.h"
|
||||
#include "../vm.h"
|
||||
#include "../fat32.h"
|
||||
#include "../memory_manager.h"
|
||||
#include "../cmd.h"
|
||||
|
||||
// --- Compiler Limits ---
|
||||
#define MAX_SOURCE 65536
|
||||
#define MAX_TOKENS 16384
|
||||
#define MAX_VARS 512
|
||||
#define CODE_SIZE 32768
|
||||
#define STR_POOL_SIZE 16384
|
||||
|
||||
static int compile_error = 0;
|
||||
|
||||
// --- Lexer ---
|
||||
typedef enum {
|
||||
TOK_EOF,
|
||||
TOK_INT, // 123, 0xFF
|
||||
TOK_STRING, // "hello"
|
||||
TOK_ID, // abc
|
||||
TOK_PLUS, // +
|
||||
TOK_MINUS, // -
|
||||
TOK_MUL, // *
|
||||
TOK_DIV, // /
|
||||
TOK_ASSIGN, // =
|
||||
TOK_LPAREN, // (
|
||||
TOK_RPAREN, // )
|
||||
TOK_LBRACKET, // [
|
||||
TOK_RBRACKET, // ]
|
||||
TOK_LBRACE, // {
|
||||
TOK_RBRACE, // }
|
||||
TOK_SEMI, // ;
|
||||
TOK_COMMA, // ,
|
||||
TOK_EQ, // ==
|
||||
TOK_NEQ, // !=
|
||||
TOK_LT, // <
|
||||
TOK_GT, // >
|
||||
TOK_LE, // <=
|
||||
TOK_GE, // >=
|
||||
TOK_IF, // if
|
||||
TOK_ELSE, // else
|
||||
TOK_WHILE, // while
|
||||
TOK_INT_TYPE, // int
|
||||
TOK_CHAR_TYPE,// char
|
||||
TOK_VOID_TYPE,// void
|
||||
TOK_MAIN // main
|
||||
} TokenType;
|
||||
|
||||
typedef struct {
|
||||
TokenType type;
|
||||
int int_val;
|
||||
char str_val[64]; // Identifier or String Content
|
||||
} Token;
|
||||
|
||||
static char *source_ptr;
|
||||
static Token tokens[MAX_TOKENS];
|
||||
static int token_count = 0;
|
||||
|
||||
static void lex_error(const char *msg) {
|
||||
cmd_write("Compiler Error: ");
|
||||
cmd_write(msg);
|
||||
cmd_write("\n");
|
||||
compile_error = 1;
|
||||
}
|
||||
|
||||
static void lexer(const char *source) {
|
||||
source_ptr = (char*)source;
|
||||
token_count = 0;
|
||||
compile_error = 0;
|
||||
|
||||
while (*source_ptr) {
|
||||
// Skip whitespace
|
||||
while (*source_ptr == ' ' || *source_ptr == '\n' || *source_ptr == '\t' || *source_ptr == '\r') source_ptr++;
|
||||
if (!*source_ptr) break;
|
||||
|
||||
// Skip comments //
|
||||
if (*source_ptr == '/' && *(source_ptr+1) == '/') {
|
||||
while (*source_ptr && *source_ptr != '\n') source_ptr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
Token *t = &tokens[token_count++];
|
||||
|
||||
// Hex Literals 0x...
|
||||
if (*source_ptr == '0' && (*(source_ptr+1) == 'x' || *(source_ptr+1) == 'X')) {
|
||||
source_ptr += 2; // Skip 0x
|
||||
t->type = TOK_INT;
|
||||
t->int_val = 0;
|
||||
int has_digits = 0;
|
||||
while ((*source_ptr >= '0' && *source_ptr <= '9') ||
|
||||
(*source_ptr >= 'a' && *source_ptr <= 'f') ||
|
||||
(*source_ptr >= 'A' && *source_ptr <= 'F')) {
|
||||
int digit = 0;
|
||||
if (*source_ptr >= '0' && *source_ptr <= '9') digit = *source_ptr - '0';
|
||||
else if (*source_ptr >= 'a' && *source_ptr <= 'f') digit = *source_ptr - 'a' + 10;
|
||||
else if (*source_ptr >= 'A' && *source_ptr <= 'F') digit = *source_ptr - 'A' + 10;
|
||||
|
||||
t->int_val = (t->int_val << 4) | digit;
|
||||
source_ptr++;
|
||||
has_digits = 1;
|
||||
}
|
||||
if (!has_digits) {
|
||||
lex_error("Invalid hex literal");
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Decimal Integers
|
||||
else if (*source_ptr >= '0' && *source_ptr <= '9') {
|
||||
t->type = TOK_INT;
|
||||
t->int_val = 0;
|
||||
while (*source_ptr >= '0' && *source_ptr <= '9') {
|
||||
t->int_val = t->int_val * 10 + (*source_ptr - '0');
|
||||
source_ptr++;
|
||||
}
|
||||
}
|
||||
// Strings
|
||||
else if (*source_ptr == '"') {
|
||||
t->type = TOK_STRING;
|
||||
source_ptr++; // Skip "
|
||||
int len = 0;
|
||||
while (*source_ptr && *source_ptr != '"') {
|
||||
if (*source_ptr == '\\' && *(source_ptr+1) == 'n') {
|
||||
if (len < 63) t->str_val[len++] = '\n';
|
||||
source_ptr += 2;
|
||||
} else {
|
||||
if (len < 63) t->str_val[len++] = *source_ptr;
|
||||
source_ptr++;
|
||||
}
|
||||
}
|
||||
t->str_val[len] = 0;
|
||||
if (*source_ptr == '"') source_ptr++;
|
||||
}
|
||||
// Character Literals
|
||||
else if (*source_ptr == '\'') {
|
||||
t->type = TOK_INT;
|
||||
source_ptr++; // Skip '
|
||||
char c = 0;
|
||||
if (*source_ptr == '\\') {
|
||||
source_ptr++;
|
||||
if (*source_ptr == 'n') c = '\n';
|
||||
else if (*source_ptr == 't') c = '\t';
|
||||
else if (*source_ptr == '0') c = '\0';
|
||||
else if (*source_ptr == '\\') c = '\\';
|
||||
else if (*source_ptr == '\'') c = '\'';
|
||||
else c = *source_ptr;
|
||||
source_ptr++;
|
||||
} else {
|
||||
c = *source_ptr;
|
||||
source_ptr++;
|
||||
}
|
||||
if (*source_ptr == '\'') source_ptr++;
|
||||
else { lex_error("Expected closing '"); return; }
|
||||
t->int_val = (int)c;
|
||||
}
|
||||
// Identifiers
|
||||
else if ((*source_ptr >= 'a' && *source_ptr <= 'z') || (*source_ptr >= 'A' && *source_ptr <= 'Z') || *source_ptr == '_') {
|
||||
int len = 0;
|
||||
while ((*source_ptr >= 'a' && *source_ptr <= 'z') || (*source_ptr >= 'A' && *source_ptr <= 'Z') || (*source_ptr >= '0' && *source_ptr <= '9') || *source_ptr == '_') {
|
||||
if (len < 63) t->str_val[len++] = *source_ptr;
|
||||
source_ptr++;
|
||||
}
|
||||
t->str_val[len] = 0;
|
||||
|
||||
if (cli_strcmp(t->str_val, "if") == 0) t->type = TOK_IF;
|
||||
else if (cli_strcmp(t->str_val, "else") == 0) t->type = TOK_ELSE;
|
||||
else if (cli_strcmp(t->str_val, "while") == 0) t->type = TOK_WHILE;
|
||||
else if (cli_strcmp(t->str_val, "int") == 0) t->type = TOK_INT_TYPE;
|
||||
else if (cli_strcmp(t->str_val, "char") == 0) t->type = TOK_CHAR_TYPE;
|
||||
else if (cli_strcmp(t->str_val, "void") == 0) t->type = TOK_VOID_TYPE;
|
||||
else if (cli_strcmp(t->str_val, "main") == 0) t->type = TOK_MAIN;
|
||||
else t->type = TOK_ID;
|
||||
} else {
|
||||
switch (*source_ptr) {
|
||||
case '+': t->type = TOK_PLUS; break;
|
||||
case '-': t->type = TOK_MINUS; break;
|
||||
case '*': t->type = TOK_MUL; break;
|
||||
case '/': t->type = TOK_DIV; break;
|
||||
case '(': t->type = TOK_LPAREN; break;
|
||||
case ')': t->type = TOK_RPAREN; break;
|
||||
case '[': t->type = TOK_LBRACKET; break;
|
||||
case ']': t->type = TOK_RBRACKET; break;
|
||||
case '{': t->type = TOK_LBRACE; break;
|
||||
case '}': t->type = TOK_RBRACE; break;
|
||||
case ';': t->type = TOK_SEMI; break;
|
||||
case ',': t->type = TOK_COMMA; break;
|
||||
case '=':
|
||||
if (*(source_ptr+1) == '=') { t->type = TOK_EQ; source_ptr++; }
|
||||
else t->type = TOK_ASSIGN;
|
||||
break;
|
||||
case '!':
|
||||
if (*(source_ptr+1) == '=') { t->type = TOK_NEQ; source_ptr++; }
|
||||
else { lex_error("Unexpected !"); return; }
|
||||
break;
|
||||
case '<':
|
||||
if (*(source_ptr+1) == '=') { t->type = TOK_LE; source_ptr++; }
|
||||
else t->type = TOK_LT;
|
||||
break;
|
||||
case '>':
|
||||
if (*(source_ptr+1) == '=') { t->type = TOK_GE; source_ptr++; }
|
||||
else t->type = TOK_GT;
|
||||
break;
|
||||
default:
|
||||
lex_error("Unknown char");
|
||||
return;
|
||||
}
|
||||
source_ptr++;
|
||||
}
|
||||
}
|
||||
tokens[token_count].type = TOK_EOF;
|
||||
}
|
||||
|
||||
// --- Builtins ---
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
int syscall_id;
|
||||
} Builtin;
|
||||
|
||||
static const Builtin builtins[] = {
|
||||
{"exit", SYS_EXIT},
|
||||
{"print_int", SYS_PRINT_INT},
|
||||
{"print_char", SYS_PRINT_CHAR},
|
||||
{"print_str", SYS_PRINT_STR}, // puts
|
||||
{"print", SYS_PRINT_INT}, // Alias
|
||||
{"pritc", SYS_PRINT_CHAR}, // Alias
|
||||
{"puts", SYS_PRINT_STR}, // Alias
|
||||
{"nl", SYS_NL},
|
||||
{"cls", SYS_CLS},
|
||||
{"getchar", SYS_GETCHAR},
|
||||
{"strlen", SYS_STRLEN},
|
||||
{"strcmp", SYS_STRCMP},
|
||||
{"strcpy", SYS_STRCPY},
|
||||
{"strcat", SYS_STRCAT},
|
||||
{"memset", SYS_MEMSET},
|
||||
{"memcpy", SYS_MEMCPY},
|
||||
{"malloc", SYS_MALLOC},
|
||||
{"free", SYS_FREE},
|
||||
{"rand", SYS_RAND},
|
||||
{"srand", SYS_SRAND},
|
||||
{"abs", SYS_ABS},
|
||||
{"min", SYS_MIN},
|
||||
{"max", SYS_MAX},
|
||||
{"pow", SYS_POW},
|
||||
{"sqrt", SYS_SQRT},
|
||||
{"sleep", SYS_SLEEP},
|
||||
{"fopen", SYS_FOPEN},
|
||||
{"fclose", SYS_FCLOSE},
|
||||
{"fread", SYS_FREAD},
|
||||
{"fwrite", SYS_FWRITE},
|
||||
{"fseek", SYS_FSEEK},
|
||||
{"remove", SYS_REMOVE},
|
||||
{"draw_pixel", SYS_DRAW_PIXEL},
|
||||
{"draw_rect", SYS_DRAW_RECT},
|
||||
{"draw_line", SYS_DRAW_LINE},
|
||||
{"draw_text", SYS_DRAW_TEXT},
|
||||
{"get_width", SYS_GET_WIDTH},
|
||||
{"get_height", SYS_GET_HEIGHT},
|
||||
{"get_time", SYS_GET_TIME},
|
||||
{"kb_hit", SYS_KB_HIT},
|
||||
{"mouse_x", SYS_MOUSE_X},
|
||||
{"mouse_y", SYS_MOUSE_Y},
|
||||
{"mouse_state", SYS_MOUSE_STATE},
|
||||
{"play_sound", SYS_PLAY_SOUND},
|
||||
{"atoi", SYS_ATOI},
|
||||
{"itoa", SYS_ITOA},
|
||||
{"peek", SYS_PEEK},
|
||||
{"poke", SYS_POKE},
|
||||
{"exec", SYS_EXEC},
|
||||
{"system", SYS_SYSTEM},
|
||||
{"strchr", SYS_STRCHR},
|
||||
{"memcmp", SYS_MEMCMP},
|
||||
{"isalnum", SYS_ISALNUM},
|
||||
{"isalpha", SYS_ISALPHA},
|
||||
{"isdigit", SYS_ISDIGIT},
|
||||
{"tolower", SYS_TOLOWER},
|
||||
{"toupper", SYS_TOUPPER},
|
||||
{"strncpy", SYS_STRNCPY},
|
||||
{"strncat", SYS_STRNCAT},
|
||||
{"strncmp", SYS_STRNCMP},
|
||||
{"strstr", SYS_STRSTR},
|
||||
{"strrchr", SYS_STRRCHR},
|
||||
{"memmove", SYS_MEMMOVE},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
static int find_builtin(const char *name) {
|
||||
for (int i = 0; builtins[i].name != NULL; i++) {
|
||||
if (cli_strcmp(builtins[i].name, name) == 0) {
|
||||
return builtins[i].syscall_id;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// --- Parser & CodeGen ---
|
||||
|
||||
static uint8_t code[CODE_SIZE];
|
||||
static int code_pos = 0;
|
||||
static int cur_token = 0;
|
||||
|
||||
static uint8_t str_pool[STR_POOL_SIZE];
|
||||
static int str_pool_pos = 0;
|
||||
|
||||
// Variables
|
||||
typedef struct {
|
||||
char name[32];
|
||||
int addr; // Address in VM memory
|
||||
} Symbol;
|
||||
|
||||
static Symbol symbols[MAX_VARS];
|
||||
static int symbol_count = 0;
|
||||
|
||||
static int next_var_addr = 32768;
|
||||
|
||||
static int find_symbol(const char *name) {
|
||||
for (int i = 0; i < symbol_count; i++) {
|
||||
if (cli_strcmp(symbols[i].name, name) == 0) return symbols[i].addr;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int add_symbol(const char *name) {
|
||||
if (find_symbol(name) != -1) return find_symbol(name);
|
||||
if (symbol_count >= MAX_VARS) return -1;
|
||||
cli_strcpy(symbols[symbol_count].name, name);
|
||||
symbols[symbol_count].addr = next_var_addr;
|
||||
next_var_addr += 4; // 32-bit int
|
||||
return symbol_count++;
|
||||
}
|
||||
|
||||
static void emit(uint8_t b) {
|
||||
if (code_pos < CODE_SIZE) code[code_pos++] = b;
|
||||
else {
|
||||
cmd_write("Error: Code buffer overflow\n");
|
||||
compile_error = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit32(int v) {
|
||||
emit(v & 0xFF);
|
||||
emit((v >> 8) & 0xFF);
|
||||
emit((v >> 16) & 0xFF);
|
||||
emit((v >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
static int add_string(const char *str) {
|
||||
int start = str_pool_pos;
|
||||
int len = cli_strlen(str);
|
||||
if (str_pool_pos + len + 1 >= STR_POOL_SIZE) {
|
||||
cmd_write("Error: String pool overflow\n");
|
||||
compile_error = 1;
|
||||
return 0;
|
||||
}
|
||||
for(int i=0; i<len; i++) str_pool[str_pool_pos++] = str[i];
|
||||
str_pool[str_pool_pos++] = 0;
|
||||
return start;
|
||||
}
|
||||
|
||||
static void match(TokenType t) {
|
||||
if (compile_error) return;
|
||||
if (tokens[cur_token].type == t) {
|
||||
cur_token++;
|
||||
} else {
|
||||
cmd_write("Syntax Error: Expected token ");
|
||||
// Debugging helper
|
||||
cmd_write_int(t);
|
||||
cmd_write(" got ");
|
||||
cmd_write_int(tokens[cur_token].type);
|
||||
cmd_write("\n");
|
||||
compile_error = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Forward decls
|
||||
static void expression();
|
||||
static void statement();
|
||||
static void block();
|
||||
|
||||
static void function_call(int syscall_id) {
|
||||
if (compile_error) return;
|
||||
cur_token++; // ID
|
||||
match(TOK_LPAREN);
|
||||
|
||||
if (tokens[cur_token].type != TOK_RPAREN) {
|
||||
expression();
|
||||
while (tokens[cur_token].type == TOK_COMMA) {
|
||||
cur_token++;
|
||||
expression();
|
||||
}
|
||||
}
|
||||
match(TOK_RPAREN);
|
||||
|
||||
emit(OP_SYSCALL);
|
||||
emit32(syscall_id);
|
||||
}
|
||||
|
||||
static void factor() {
|
||||
if (compile_error) return;
|
||||
if (tokens[cur_token].type == TOK_INT) {
|
||||
emit(OP_IMM);
|
||||
emit32(tokens[cur_token].int_val);
|
||||
cur_token++;
|
||||
} else if (tokens[cur_token].type == TOK_STRING) {
|
||||
int offset = add_string(tokens[cur_token].str_val);
|
||||
emit(OP_PUSH_PTR);
|
||||
emit32(offset);
|
||||
cur_token++;
|
||||
} else if (tokens[cur_token].type == TOK_ID) {
|
||||
int syscall = find_builtin(tokens[cur_token].str_val);
|
||||
if (syscall != -1 && tokens[cur_token+1].type == TOK_LPAREN) {
|
||||
function_call(syscall);
|
||||
} else {
|
||||
int addr = find_symbol(tokens[cur_token].str_val);
|
||||
if (addr == -1) {
|
||||
cmd_write("Error: Undefined variable: ");
|
||||
cmd_write(tokens[cur_token].str_val);
|
||||
cmd_write("\n");
|
||||
compile_error = 1;
|
||||
}
|
||||
emit(OP_LOAD);
|
||||
emit32(addr);
|
||||
cur_token++;
|
||||
}
|
||||
} else if (tokens[cur_token].type == TOK_LPAREN) {
|
||||
cur_token++;
|
||||
expression();
|
||||
match(TOK_RPAREN);
|
||||
} else {
|
||||
cmd_write("Syntax Error: Unexpected token in factor\n");
|
||||
compile_error = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void term() {
|
||||
if (compile_error) return;
|
||||
factor();
|
||||
while (tokens[cur_token].type == TOK_MUL || tokens[cur_token].type == TOK_DIV) {
|
||||
TokenType op = tokens[cur_token].type;
|
||||
cur_token++;
|
||||
factor();
|
||||
if (op == TOK_MUL) emit(OP_MUL);
|
||||
else emit(OP_DIV);
|
||||
}
|
||||
}
|
||||
|
||||
static void additive() {
|
||||
if (compile_error) return;
|
||||
term();
|
||||
while (tokens[cur_token].type == TOK_PLUS || tokens[cur_token].type == TOK_MINUS) {
|
||||
TokenType op = tokens[cur_token].type;
|
||||
cur_token++;
|
||||
term();
|
||||
if (op == TOK_PLUS) emit(OP_ADD);
|
||||
else emit(OP_SUB);
|
||||
}
|
||||
}
|
||||
|
||||
static void relation() {
|
||||
if (compile_error) return;
|
||||
additive();
|
||||
if (tokens[cur_token].type >= TOK_EQ && tokens[cur_token].type <= TOK_GE) {
|
||||
TokenType op = tokens[cur_token].type;
|
||||
cur_token++;
|
||||
additive();
|
||||
switch (op) {
|
||||
case TOK_EQ: emit(OP_EQ); break;
|
||||
case TOK_NEQ: emit(OP_NEQ); break;
|
||||
case TOK_LT: emit(OP_LT); break;
|
||||
case TOK_GT: emit(OP_GT); break;
|
||||
case TOK_LE: emit(OP_LE); break;
|
||||
case TOK_GE: emit(OP_GE); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void expression() {
|
||||
if (compile_error) return;
|
||||
relation();
|
||||
}
|
||||
|
||||
static void statement() {
|
||||
if (compile_error) return;
|
||||
if (tokens[cur_token].type == TOK_INT_TYPE || tokens[cur_token].type == TOK_CHAR_TYPE) {
|
||||
// Declaration
|
||||
cur_token++;
|
||||
while (tokens[cur_token].type == TOK_MUL) cur_token++; // Skip pointers *
|
||||
|
||||
if (tokens[cur_token].type == TOK_ID) {
|
||||
add_symbol(tokens[cur_token].str_val);
|
||||
cur_token++;
|
||||
|
||||
// Skip array size [INT]
|
||||
if (tokens[cur_token].type == TOK_LBRACKET) {
|
||||
cur_token++;
|
||||
if (tokens[cur_token].type == TOK_INT) cur_token++;
|
||||
if (tokens[cur_token].type == TOK_RBRACKET) cur_token++;
|
||||
else cmd_write("Error: Expected ]\n");
|
||||
}
|
||||
|
||||
if (tokens[cur_token].type == TOK_ASSIGN) { int addr = find_symbol(tokens[cur_token-1].str_val);
|
||||
cur_token++;
|
||||
expression();
|
||||
emit(OP_STORE);
|
||||
emit32(addr);
|
||||
}
|
||||
match(TOK_SEMI);
|
||||
} else {
|
||||
cmd_write("Syntax Error: Expected identifier\n");
|
||||
compile_error = 1;
|
||||
}
|
||||
} else if (tokens[cur_token].type == TOK_ID) {
|
||||
int syscall = find_builtin(tokens[cur_token].str_val);
|
||||
if (syscall != -1 && tokens[cur_token+1].type == TOK_LPAREN) {
|
||||
function_call(syscall);
|
||||
match(TOK_SEMI);
|
||||
// Drop return value (primitive)
|
||||
emit(OP_POP);
|
||||
} else {
|
||||
// Assignment: x = expr;
|
||||
int addr = find_symbol(tokens[cur_token].str_val);
|
||||
if (addr == -1) {
|
||||
cmd_write("Error: Undefined variable assignment: ");
|
||||
cmd_write(tokens[cur_token].str_val);
|
||||
cmd_write("\n");
|
||||
compile_error = 1;
|
||||
return;
|
||||
}
|
||||
cur_token++;
|
||||
match(TOK_ASSIGN);
|
||||
expression();
|
||||
match(TOK_SEMI);
|
||||
emit(OP_STORE);
|
||||
emit32(addr);
|
||||
}
|
||||
} else if (tokens[cur_token].type == TOK_IF) {
|
||||
cur_token++;
|
||||
match(TOK_LPAREN);
|
||||
expression();
|
||||
match(TOK_RPAREN);
|
||||
|
||||
emit(OP_JZ);
|
||||
int jz_addr_pos = code_pos;
|
||||
emit32(0);
|
||||
|
||||
block();
|
||||
|
||||
if (tokens[cur_token].type == TOK_ELSE) {
|
||||
emit(OP_JMP);
|
||||
int jmp_addr_pos = code_pos;
|
||||
emit32(0);
|
||||
|
||||
int else_start = code_pos;
|
||||
code[jz_addr_pos] = else_start & 0xFF;
|
||||
code[jz_addr_pos+1] = (else_start >> 8) & 0xFF;
|
||||
code[jz_addr_pos+2] = (else_start >> 16) & 0xFF;
|
||||
code[jz_addr_pos+3] = (else_start >> 24) & 0xFF;
|
||||
|
||||
cur_token++;
|
||||
block();
|
||||
|
||||
int end_addr = code_pos;
|
||||
code[jmp_addr_pos] = end_addr & 0xFF;
|
||||
code[jmp_addr_pos+1] = (end_addr >> 8) & 0xFF;
|
||||
code[jmp_addr_pos+2] = (end_addr >> 16) & 0xFF;
|
||||
code[jmp_addr_pos+3] = (end_addr >> 24) & 0xFF;
|
||||
} else {
|
||||
int end_addr = code_pos;
|
||||
code[jz_addr_pos] = end_addr & 0xFF;
|
||||
code[jz_addr_pos+1] = (end_addr >> 8) & 0xFF;
|
||||
code[jz_addr_pos+2] = (end_addr >> 16) & 0xFF;
|
||||
code[jz_addr_pos+3] = (end_addr >> 24) & 0xFF;
|
||||
}
|
||||
} else if (tokens[cur_token].type == TOK_WHILE) {
|
||||
int start_addr = code_pos;
|
||||
cur_token++;
|
||||
match(TOK_LPAREN);
|
||||
expression();
|
||||
match(TOK_RPAREN);
|
||||
|
||||
emit(OP_JZ);
|
||||
int jz_addr_pos = code_pos;
|
||||
emit32(0);
|
||||
|
||||
block();
|
||||
|
||||
emit(OP_JMP);
|
||||
emit32(start_addr);
|
||||
|
||||
int end_addr = code_pos;
|
||||
code[jz_addr_pos] = end_addr & 0xFF;
|
||||
code[jz_addr_pos+1] = (end_addr >> 8) & 0xFF;
|
||||
code[jz_addr_pos+2] = (end_addr >> 16) & 0xFF;
|
||||
code[jz_addr_pos+3] = (end_addr >> 24) & 0xFF;
|
||||
} else {
|
||||
cur_token++;
|
||||
}
|
||||
}
|
||||
|
||||
static void block() {
|
||||
if (compile_error) return;
|
||||
match(TOK_LBRACE);
|
||||
while (tokens[cur_token].type != TOK_RBRACE && tokens[cur_token].type != TOK_EOF && !compile_error) {
|
||||
statement();
|
||||
}
|
||||
match(TOK_RBRACE);
|
||||
}
|
||||
|
||||
static void program() {
|
||||
if (tokens[cur_token].type == TOK_INT_TYPE || tokens[cur_token].type == TOK_VOID_TYPE) cur_token++;
|
||||
if (tokens[cur_token].type == TOK_MAIN) cur_token++;
|
||||
match(TOK_LPAREN);
|
||||
match(TOK_RPAREN);
|
||||
block();
|
||||
emit(OP_HALT);
|
||||
}
|
||||
|
||||
void cli_cmd_cc(char *args) {
|
||||
if (!args || !*args) {
|
||||
cmd_write("Usage: cc <filename.c>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
FAT32_FileHandle *fh = fat32_open(args, "r");
|
||||
if (!fh) {
|
||||
cmd_write("Error: Cannot open source file.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char *source = (char*)kmalloc(MAX_SOURCE);
|
||||
if (!source) {
|
||||
cmd_write("Error: Out of memory for source buffer.\n");
|
||||
fat32_close(fh);
|
||||
return;
|
||||
}
|
||||
|
||||
int len = fat32_read(fh, source, MAX_SOURCE - 1);
|
||||
source[len] = 0;
|
||||
fat32_close(fh);
|
||||
|
||||
lexer(source);
|
||||
kfree(source);
|
||||
|
||||
if (compile_error) return;
|
||||
|
||||
code_pos = 0;
|
||||
symbol_count = 0;
|
||||
cur_token = 0;
|
||||
str_pool_pos = 0;
|
||||
next_var_addr = 32768;
|
||||
|
||||
const char* magic = VM_MAGIC;
|
||||
for(int i=0; i<7; i++) emit(magic[i]);
|
||||
emit(1);
|
||||
|
||||
program();
|
||||
|
||||
if (compile_error) {
|
||||
cmd_write("Compilation Failed.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Finalize Code
|
||||
int pool_start_addr = code_pos;
|
||||
for(int i=0; i<str_pool_pos; i++) {
|
||||
emit(str_pool[i]);
|
||||
}
|
||||
|
||||
// Fixup OP_PUSH_PTR
|
||||
int pc = 8;
|
||||
while (pc < pool_start_addr) {
|
||||
uint8_t op = code[pc++];
|
||||
switch (op) {
|
||||
case OP_HALT: break;
|
||||
case OP_IMM: pc += 4; break;
|
||||
case OP_LOAD: pc += 4; break;
|
||||
case OP_STORE: pc += 4; break;
|
||||
case OP_LOAD8: pc += 4; break;
|
||||
case OP_STORE8: pc += 4; break;
|
||||
case OP_ADD: break;
|
||||
case OP_SUB: break;
|
||||
case OP_MUL: break;
|
||||
case OP_DIV: break;
|
||||
case OP_PRINT: break;
|
||||
case OP_PRITC: break;
|
||||
case OP_JMP: pc += 4; break;
|
||||
case OP_JZ: pc += 4; break;
|
||||
case OP_EQ: break;
|
||||
case OP_NEQ: break;
|
||||
case OP_LT: break;
|
||||
case OP_GT: break;
|
||||
case OP_LE: break;
|
||||
case OP_GE: break;
|
||||
case OP_SYSCALL: pc += 4; break;
|
||||
case OP_POP: break;
|
||||
case OP_PUSH_PTR: {
|
||||
int offset = 0;
|
||||
offset |= code[pc];
|
||||
offset |= code[pc+1] << 8;
|
||||
offset |= code[pc+2] << 16;
|
||||
offset |= code[pc+3] << 24;
|
||||
|
||||
int abs_addr = pool_start_addr + offset;
|
||||
|
||||
code[pc] = abs_addr & 0xFF;
|
||||
code[pc+1] = (abs_addr >> 8) & 0xFF;
|
||||
code[pc+2] = (abs_addr >> 16) & 0xFF;
|
||||
code[pc+3] = (abs_addr >> 24) & 0xFF;
|
||||
|
||||
pc += 4;
|
||||
code[pc-5] = OP_IMM;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
char out_name[64];
|
||||
int i = 0;
|
||||
while(args[i] && args[i] != '.') {
|
||||
out_name[i] = args[i];
|
||||
i++;
|
||||
}
|
||||
out_name[i] = 0;
|
||||
|
||||
FAT32_FileHandle *out_fh = fat32_open(out_name, "w");
|
||||
if (out_fh) {
|
||||
fat32_write(out_fh, code, code_pos);
|
||||
fat32_close(out_fh);
|
||||
cmd_write("Compilation successful. Output: ");
|
||||
cmd_write(out_name);
|
||||
cmd_write("\n");
|
||||
} else {
|
||||
cmd_write("Error: Cannot write output file.\n");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
|
||||
// Public declaration from cmd.c
|
||||
extern void cmd_screen_clear(void);
|
||||
|
||||
void cli_cmd_clear(char *args) {
|
||||
(void)args;
|
||||
cmd_screen_clear();
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
#ifndef CLI_APPS_H
|
||||
#define CLI_APPS_H
|
||||
|
||||
// All CLI command function declarations
|
||||
void cli_cmd_help(char *args);
|
||||
void cli_cmd_date(char *args);
|
||||
void cli_cmd_math(char *args);
|
||||
void cli_cmd_beep(char *args);
|
||||
void cli_cmd_cowsay(char *args);
|
||||
void cli_cmd_reboot(char *args);
|
||||
void cli_cmd_shutdown(char *args);
|
||||
void cli_cmd_uptime(char *args);
|
||||
void cli_cmd_man(char *args);
|
||||
void cli_cmd_txtedit(char *args);
|
||||
void cli_cmd_blind(char *args);
|
||||
void cli_cmd_readtheman(char *args);
|
||||
void cli_cmd_boredver(char *args);
|
||||
void cli_cmd_clear(char *args);
|
||||
void cli_cmd_exit(char *args);
|
||||
|
||||
|
||||
// Filesystem commands
|
||||
void cli_cmd_cd(char *args);
|
||||
void cli_cmd_pwd(char *args);
|
||||
void cli_cmd_ls(char *args);
|
||||
void cli_cmd_mkdir(char *args);
|
||||
void cli_cmd_rm(char *args);
|
||||
void cli_cmd_echo(char *args);
|
||||
void cli_cmd_cat(char *args);
|
||||
void cli_cmd_touch(char *args);
|
||||
void cli_cmd_cp(char *args);
|
||||
void cli_cmd_mv(char *args);
|
||||
|
||||
// Memory management commands
|
||||
void cli_cmd_meminfo(char *args);
|
||||
void cli_cmd_malloc(char *args);
|
||||
void cli_cmd_free_mem(char *args);
|
||||
void cli_cmd_memblock(char *args);
|
||||
void cli_cmd_memvalid(char *args);
|
||||
void cli_cmd_memtest(char *args);
|
||||
|
||||
// Network commands
|
||||
void cli_cmd_netinit(char *args);
|
||||
void cli_cmd_netinfo(char *args);
|
||||
void cli_cmd_ipset(char *args);
|
||||
void cli_cmd_udpsend(char *args);
|
||||
void cli_cmd_udptest(char *args);
|
||||
void cli_cmd_msgrc(char *args);
|
||||
|
||||
// PCI commands
|
||||
void cli_cmd_pcilist(char *args);
|
||||
|
||||
// Compiler
|
||||
void cli_cmd_cc(char *args);
|
||||
|
||||
// Music
|
||||
void cli_cmd_minecraft(char *args);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
#ifndef CLI_COMMAND_H
|
||||
#define CLI_COMMAND_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
// Standard interface for CLI command output
|
||||
// Commands should call these functions to write to the terminal
|
||||
extern void cli_write(const char *str);
|
||||
extern void cli_write_int(int n);
|
||||
extern void cli_putchar(char c);
|
||||
|
||||
// Callback function type for command execution
|
||||
typedef void (*cmd_callback_t)(char *args);
|
||||
|
||||
// Command entry in dispatch table
|
||||
typedef struct {
|
||||
const char *name;
|
||||
cmd_callback_t callback;
|
||||
const char *help_text;
|
||||
} CLI_Command;
|
||||
|
||||
#endif
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
#ifndef CLI_UTILS_H
|
||||
#define CLI_UTILS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// String utilities
|
||||
void cli_memset(void *dest, int val, size_t len);
|
||||
size_t cli_strlen(const char *str);
|
||||
int cli_strcmp(const char *s1, const char *s2);
|
||||
void cli_strcpy(char *dest, const char *src);
|
||||
int cli_atoi(const char *str);
|
||||
void cli_itoa(int n, char *buf);
|
||||
|
||||
// IO utilities
|
||||
void cli_write(const char *str);
|
||||
void cli_write_int(int n);
|
||||
void cli_putchar(char c);
|
||||
|
||||
// Timing utility
|
||||
void cli_delay(int iterations);
|
||||
void cli_sleep(int ms);
|
||||
|
||||
// CLI Command declarations
|
||||
void cli_cmd_shutdown(char *args);
|
||||
void cli_cmd_reboot(char *args);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
|
||||
void cli_cmd_cowsay(char *args) {
|
||||
if (!args || !*args) args = (char*)"Bored!";
|
||||
size_t len = cli_strlen(args);
|
||||
|
||||
cli_write(" ");
|
||||
for(size_t i=0; i<len+2; i++) cli_write("_");
|
||||
cli_write("\n< "); cli_write(args); cli_write(" >\n ");
|
||||
for(size_t i=0; i<len+2; i++) cli_write("-");
|
||||
cli_write("\n");
|
||||
cli_write(" \\ ^__^\n");
|
||||
cli_write(" \\ (oo)\\_______\n");
|
||||
cli_write(" (__)\\ )\\/\\\n");
|
||||
cli_write(" ||----w |\n");
|
||||
cli_write(" || ||\n\n");
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
|
||||
// Forward declaration from cmd.c
|
||||
extern void rtc_get_datetime(int *y, int *m, int *d, int *h, int *min, int *s);
|
||||
|
||||
void cli_cmd_date(char *args) {
|
||||
(void)args;
|
||||
int y, m, d, h, min, s;
|
||||
rtc_get_datetime(&y, &m, &d, &h, &min, &s);
|
||||
cli_write("Current Date: ");
|
||||
cli_write_int(y); cli_write("-"); cli_write_int(m); cli_write("-"); cli_write_int(d);
|
||||
cli_write(" ");
|
||||
cli_write_int(h); cli_write(":"); cli_write_int(min); cli_write(":"); cli_write_int(s);
|
||||
cli_write("\n");
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
|
||||
// Public declaration from cmd.c
|
||||
extern void cmd_window_exit(void);
|
||||
|
||||
void cli_cmd_exit(char *args) {
|
||||
(void)args;
|
||||
cmd_window_exit();
|
||||
}
|
||||
|
|
@ -1,475 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
#include "fat32.h"
|
||||
#include "cmd.h"
|
||||
|
||||
void cli_cmd_cd(char *args) {
|
||||
if (!args || args[0] == 0) {
|
||||
// No argument - show current directory
|
||||
char cwd[256];
|
||||
fat32_get_current_dir(cwd, sizeof(cwd));
|
||||
cli_write("Current directory: ");
|
||||
cli_write(cwd);
|
||||
cli_write("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse argument
|
||||
char path[256];
|
||||
int i = 0;
|
||||
while (args[i] && args[i] != ' ' && args[i] != '\t') {
|
||||
path[i] = args[i];
|
||||
i++;
|
||||
}
|
||||
path[i] = 0;
|
||||
|
||||
if (fat32_chdir(path)) {
|
||||
char cwd[256];
|
||||
fat32_get_current_dir(cwd, sizeof(cwd));
|
||||
cli_write("Changed to: ");
|
||||
cli_write(cwd);
|
||||
cli_write("\n");
|
||||
} else {
|
||||
cli_write("Error: Cannot change to directory: ");
|
||||
cli_write(path);
|
||||
cli_write("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void cli_cmd_pwd(char *args) {
|
||||
(void)args;
|
||||
char cwd[256];
|
||||
fat32_get_current_dir(cwd, sizeof(cwd));
|
||||
cli_write(cwd);
|
||||
cli_write("\n");
|
||||
}
|
||||
|
||||
void cli_cmd_ls(char *args) {
|
||||
char path[256];
|
||||
|
||||
if (!args || args[0] == 0) {
|
||||
// List current directory
|
||||
fat32_get_current_dir(path, sizeof(path));
|
||||
} else {
|
||||
// Parse argument
|
||||
int i = 0;
|
||||
while (args[i] && args[i] != ' ' && args[i] != '\t') {
|
||||
path[i] = args[i];
|
||||
i++;
|
||||
}
|
||||
path[i] = 0;
|
||||
}
|
||||
|
||||
FAT32_FileInfo entries[256];
|
||||
int count = fat32_list_directory(path, entries, 256);
|
||||
|
||||
if (count < 0) {
|
||||
cli_write("Error: Cannot list directory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
cli_write(entries[i].name);
|
||||
if (entries[i].is_directory) {
|
||||
cli_write("/");
|
||||
}
|
||||
cli_write(" (");
|
||||
cli_write_int(entries[i].size);
|
||||
cli_write(" bytes)\n");
|
||||
}
|
||||
|
||||
cli_write("\n");
|
||||
cli_write("Total: ");
|
||||
cli_write_int(count);
|
||||
cli_write(" items\n");
|
||||
}
|
||||
|
||||
void cli_cmd_mkdir(char *args) {
|
||||
if (!args || args[0] == 0) {
|
||||
cli_write("Usage: mkdir <dirname>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char dirname[256];
|
||||
int i = 0;
|
||||
while (args[i] && args[i] != ' ' && args[i] != '\t') {
|
||||
dirname[i] = args[i];
|
||||
i++;
|
||||
}
|
||||
dirname[i] = 0;
|
||||
|
||||
if (fat32_mkdir(dirname)) {
|
||||
cli_write("Created directory: ");
|
||||
cli_write(dirname);
|
||||
cli_write("\n");
|
||||
} else {
|
||||
cli_write("Error: Cannot create directory\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Helper for recursive deletion
|
||||
static bool rm_recursive(const char *path) {
|
||||
if (fat32_exists(path) && !fat32_is_directory(path)) {
|
||||
return fat32_delete(path);
|
||||
}
|
||||
|
||||
if (!fat32_exists(path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// It's a directory: delete contents first
|
||||
while (1) {
|
||||
FAT32_FileInfo entries[10];
|
||||
int count = fat32_list_directory(path, entries, 10);
|
||||
if (count <= 0) break;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
// Construct child path
|
||||
char child_path[256];
|
||||
cli_strcpy(child_path, path);
|
||||
int len = cli_strlen(child_path);
|
||||
if (len > 0 && child_path[len-1] != '/') {
|
||||
child_path[len++] = '/';
|
||||
child_path[len] = 0;
|
||||
}
|
||||
|
||||
// Append name
|
||||
const char *name = entries[i].name;
|
||||
int j = 0;
|
||||
while (name[j] && len < 255) {
|
||||
child_path[len++] = name[j++];
|
||||
}
|
||||
child_path[len] = 0;
|
||||
|
||||
// Recurse
|
||||
if (!rm_recursive(child_path)) {
|
||||
cli_write("Error: Failed to delete ");
|
||||
cli_write(child_path);
|
||||
cli_write("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fat32_rmdir(path);
|
||||
}
|
||||
|
||||
void cli_cmd_rm(char *args) {
|
||||
if (!args || args[0] == 0) {
|
||||
cli_write("Usage: rm [-r] <path>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bool recursive = false;
|
||||
|
||||
// Check for -r flag
|
||||
int i = 0;
|
||||
while (args[i] == ' ' || args[i] == '\t') i++;
|
||||
|
||||
if (args[i] == '-' && args[i+1] == 'r' && (args[i+2] == ' ' || args[i+2] == '\t' || args[i+2] == 0)) {
|
||||
recursive = true;
|
||||
i += 2;
|
||||
while (args[i] == ' ' || args[i] == '\t') i++;
|
||||
}
|
||||
|
||||
char *path_start = args + i;
|
||||
if (path_start[0] == 0) {
|
||||
cli_write("Usage: rm [-r] <path>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char filename[256];
|
||||
int j = 0;
|
||||
while (path_start[j] && path_start[j] != ' ' && path_start[j] != '\t') {
|
||||
filename[j] = path_start[j];
|
||||
j++;
|
||||
}
|
||||
filename[j] = 0;
|
||||
|
||||
if (recursive) {
|
||||
if (rm_recursive(filename)) {
|
||||
cli_write("Deleted recursively: ");
|
||||
cli_write(filename);
|
||||
cli_write("\n");
|
||||
} else {
|
||||
cli_write("Error: Cannot delete ");
|
||||
cli_write(filename);
|
||||
cli_write("\n");
|
||||
}
|
||||
} else {
|
||||
if (fat32_is_directory(filename)) {
|
||||
cli_write("Error: Is a directory. Use -r to delete.\n");
|
||||
} else {
|
||||
if (fat32_delete(filename)) {
|
||||
cli_write("Deleted: ");
|
||||
cli_write(filename);
|
||||
cli_write("\n");
|
||||
} else {
|
||||
cli_write("Error: Cannot delete file\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cli_cmd_echo(char *args) {
|
||||
if (!args || args[0] == 0) {
|
||||
cli_write("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for redirection operators
|
||||
char *redirect_ptr = NULL;
|
||||
char redirect_mode = 0; // '>' for write, 'a' for append
|
||||
char output_file[256] = {0};
|
||||
char echo_text[512] = {0};
|
||||
|
||||
// Find > or >>
|
||||
for (int i = 0; args[i]; i++) {
|
||||
if (args[i] == '>' && args[i+1] == '>') {
|
||||
redirect_ptr = args + i + 2;
|
||||
redirect_mode = 'a'; // append
|
||||
// Copy text before redirection
|
||||
for (int j = 0; j < i; j++) {
|
||||
echo_text[j] = args[j];
|
||||
}
|
||||
echo_text[i] = 0;
|
||||
break;
|
||||
} else if (args[i] == '>') {
|
||||
redirect_ptr = args + i + 1;
|
||||
redirect_mode = '>'; // write
|
||||
// Copy text before redirection
|
||||
for (int j = 0; j < i; j++) {
|
||||
echo_text[j] = args[j];
|
||||
}
|
||||
echo_text[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If no redirection, just print the text
|
||||
if (!redirect_ptr) {
|
||||
cli_write(args);
|
||||
cli_write("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse output filename
|
||||
int i = 0;
|
||||
while (redirect_ptr[i] && (redirect_ptr[i] == ' ' || redirect_ptr[i] == '\t')) {
|
||||
i++;
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
while (redirect_ptr[i] && redirect_ptr[i] != ' ' && redirect_ptr[i] != '\t') {
|
||||
output_file[j++] = redirect_ptr[i++];
|
||||
}
|
||||
output_file[j] = 0;
|
||||
|
||||
if (!output_file[0]) {
|
||||
cli_write("Error: No output file specified\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Open file
|
||||
const char *mode = (redirect_mode == 'a') ? "a" : "w";
|
||||
FAT32_FileHandle *fh = fat32_open(output_file, mode);
|
||||
if (!fh) {
|
||||
cli_write("Error: Cannot open file for writing\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Write text
|
||||
int text_len = 0;
|
||||
while (echo_text[text_len]) text_len++;
|
||||
|
||||
fat32_write(fh, echo_text, text_len);
|
||||
fat32_write(fh, "\n", 1);
|
||||
fat32_close(fh);
|
||||
|
||||
cli_write("Wrote to: ");
|
||||
cli_write(output_file);
|
||||
cli_write("\n");
|
||||
}
|
||||
|
||||
void cli_cmd_cat(char *args) {
|
||||
if (!args || args[0] == 0) {
|
||||
cli_write("Usage: cat <filename>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char filename[256];
|
||||
int i = 0;
|
||||
while (args[i] && args[i] != ' ' && args[i] != '\t') {
|
||||
filename[i] = args[i];
|
||||
i++;
|
||||
}
|
||||
filename[i] = 0;
|
||||
|
||||
if (cli_strcmp(filename, "messages") == 0) {
|
||||
cmd_reset_msg_count();
|
||||
}
|
||||
|
||||
FAT32_FileHandle *fh = fat32_open(filename, "r");
|
||||
if (!fh) {
|
||||
cli_write("Error: Cannot open file\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Read and display file
|
||||
char buffer[4096];
|
||||
int bytes_read;
|
||||
while ((bytes_read = fat32_read(fh, buffer, sizeof(buffer))) > 0) {
|
||||
for (int j = 0; j < bytes_read; j++) {
|
||||
cli_putchar(buffer[j]);
|
||||
}
|
||||
}
|
||||
|
||||
fat32_close(fh);
|
||||
}
|
||||
|
||||
void cli_cmd_touch(char *args) {
|
||||
if (!args || args[0] == 0) {
|
||||
cli_write("Usage: touch <filename>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char filename[256];
|
||||
int i = 0;
|
||||
while (args[i] && args[i] != ' ' && args[i] != '\t') {
|
||||
filename[i] = args[i];
|
||||
i++;
|
||||
}
|
||||
filename[i] = 0;
|
||||
|
||||
// Check if file already exists
|
||||
if (fat32_exists(filename)) {
|
||||
cli_write("File already exists: ");
|
||||
cli_write(filename);
|
||||
cli_write("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Open file in write mode to create it
|
||||
FAT32_FileHandle *fh = fat32_open(filename, "w");
|
||||
if (!fh) {
|
||||
cli_write("Error: Cannot create file\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fat32_close(fh);
|
||||
|
||||
cli_write("Created: ");
|
||||
cli_write(filename);
|
||||
cli_write("\n");
|
||||
}
|
||||
|
||||
void cli_cmd_cp(char *args) {
|
||||
char *src = args;
|
||||
while (*src == ' ') src++;
|
||||
|
||||
char *dest = src;
|
||||
while (*dest && *dest != ' ') dest++;
|
||||
|
||||
if (*dest) {
|
||||
*dest = 0;
|
||||
dest++;
|
||||
while (*dest == ' ') dest++;
|
||||
}
|
||||
|
||||
if (!*src || !*dest) {
|
||||
cli_write("Usage: cp <source> <dest>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if dest is a directory
|
||||
char final_dest[256];
|
||||
cli_strcpy(final_dest, dest);
|
||||
|
||||
if (fat32_is_directory(dest)) {
|
||||
// Append filename from src to dest
|
||||
int len = cli_strlen(final_dest);
|
||||
if (len > 0 && final_dest[len-1] != '/') {
|
||||
final_dest[len++] = '/';
|
||||
final_dest[len] = 0;
|
||||
}
|
||||
|
||||
// Extract filename from src
|
||||
const char *fname = src;
|
||||
const char *p = src;
|
||||
while (*p) {
|
||||
if (*p == '/') fname = p + 1;
|
||||
p++;
|
||||
}
|
||||
|
||||
// Append
|
||||
int j = 0;
|
||||
while (fname[j]) {
|
||||
final_dest[len++] = fname[j++];
|
||||
}
|
||||
final_dest[len] = 0;
|
||||
}
|
||||
|
||||
FAT32_FileHandle *fh_in = fat32_open(src, "r");
|
||||
if (!fh_in) {
|
||||
cli_write("Error: Cannot open source file: ");
|
||||
cli_write(src);
|
||||
cli_write("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
FAT32_FileHandle *fh_out = fat32_open(final_dest, "w");
|
||||
if (!fh_out) {
|
||||
cli_write("Error: Cannot create destination file: ");
|
||||
cli_write(final_dest);
|
||||
cli_write("\n");
|
||||
fat32_close(fh_in);
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[4096];
|
||||
int bytes;
|
||||
while ((bytes = fat32_read(fh_in, buffer, sizeof(buffer))) > 0) {
|
||||
fat32_write(fh_out, buffer, bytes);
|
||||
}
|
||||
|
||||
fat32_close(fh_in);
|
||||
fat32_close(fh_out);
|
||||
|
||||
cli_write("Copied ");
|
||||
cli_write(src);
|
||||
cli_write(" to ");
|
||||
cli_write(final_dest);
|
||||
cli_write("\n");
|
||||
}
|
||||
|
||||
void cli_cmd_mv(char *args) {
|
||||
// Parse args similar to cp
|
||||
char *src = args;
|
||||
while (*src == ' ') src++;
|
||||
|
||||
char *dest = src;
|
||||
while (*dest && *dest != ' ') dest++;
|
||||
|
||||
if (*dest) {
|
||||
*dest = 0;
|
||||
dest++;
|
||||
while (*dest == ' ') dest++;
|
||||
}
|
||||
|
||||
if (!*src || !*dest) {
|
||||
cli_write("Usage: mv <source> <dest>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
char cp_args[512];
|
||||
int i = 0;
|
||||
const char *s = src;
|
||||
while (*s) cp_args[i++] = *s++;
|
||||
cp_args[i++] = ' ';
|
||||
const char *d = dest;
|
||||
while (*d) cp_args[i++] = *d++;
|
||||
cp_args[i] = 0;
|
||||
|
||||
cli_cmd_cp(cp_args);
|
||||
|
||||
fat32_delete(src);
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
|
||||
void cli_cmd_help(char *args) {
|
||||
(void)args;
|
||||
cli_write("Available commands:\n");
|
||||
cli_write(" HELP - Display this help message\n");
|
||||
cli_write(" DATE - Display current date and time\n");
|
||||
cli_write(" CLEAR - Clear the screen\n");
|
||||
cli_write(" BOREDVER - Gives version info\n");
|
||||
cli_write(" MATH - math <op> <a> <b> (e.g. math + 1 2)\n");
|
||||
cli_write(" MAN - Show user manual (interactive)\n");
|
||||
cli_write(" LICENSE - Show license (interactive)\n");
|
||||
cli_write(" UPTIME - System uptime\n");
|
||||
cli_write(" BEEP - Make a sound\n");
|
||||
cli_write(" COWSAY - cowsay <msg>\n");
|
||||
cli_write(" REBOOT - Reboot system\n");
|
||||
cli_write(" SHUTDOWN - Shutdown system\n");
|
||||
cli_write(" MEMINFO - Gives memory info\n");
|
||||
cli_write(" CC - C compiler\n");
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
|
||||
// Forward declaration from cmd.c
|
||||
extern void pager_wrap_content(const char **lines, int count);
|
||||
extern void pager_set_mode(void);
|
||||
|
||||
const char* manual_pages[] = {
|
||||
"No manual round here pal",
|
||||
|
||||
};
|
||||
const int manual_num_lines = sizeof(manual_pages) / sizeof(char*);
|
||||
|
||||
void cli_cmd_man(char *args) {
|
||||
(void)args;
|
||||
pager_wrap_content(manual_pages, manual_num_lines);
|
||||
pager_set_mode();
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
|
||||
void cli_cmd_math(char *args) {
|
||||
while (*args == ' ') args++;
|
||||
if (!*args) {
|
||||
cli_write("Usage: math <op> <n1> <n2>\n");
|
||||
return;
|
||||
}
|
||||
char op = *args;
|
||||
args++;
|
||||
while (*args == ' ') args++;
|
||||
|
||||
char *end = args;
|
||||
while (*end && *end != ' ') end++;
|
||||
int saved = *end;
|
||||
*end = 0;
|
||||
int n1 = cli_atoi(args);
|
||||
if (saved) *end = saved;
|
||||
|
||||
args = end;
|
||||
while (*args == ' ') args++;
|
||||
|
||||
int n2 = cli_atoi(args);
|
||||
|
||||
int res = 0;
|
||||
switch(op) {
|
||||
case '+': res = n1 + n2; break;
|
||||
case '-': res = n1 - n2; break;
|
||||
case '*': res = n1 * n2; break;
|
||||
case '/': if(n2!=0) res = n1/n2; else { cli_write("Div by zero\n"); return; } break;
|
||||
default: cli_write("Invalid op.\n"); return;
|
||||
}
|
||||
cli_write("Result: "); cli_write_int(res); cli_write("\n");
|
||||
}
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
#include "../memory_manager.h"
|
||||
|
||||
#define MAX_TEST_ALLOCS 64
|
||||
static void *test_allocs[MAX_TEST_ALLOCS];
|
||||
static int test_alloc_count = 0;
|
||||
|
||||
void cli_cmd_malloc(char *args) {
|
||||
if (!args || !args[0]) {
|
||||
cli_write("Usage: malloc <size_in_kb>\n");
|
||||
cli_write("Example: malloc 10\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse size in KB
|
||||
int size_kb = cli_atoi(args);
|
||||
if (size_kb <= 0 || size_kb > 1024) {
|
||||
cli_write("Invalid size. Use 1-1024 KB\n");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size = size_kb * 1024;
|
||||
void *ptr = kmalloc(size);
|
||||
|
||||
if (ptr == NULL) {
|
||||
cli_write("Allocation failed!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Track allocation for later freeing
|
||||
if (test_alloc_count < MAX_TEST_ALLOCS) {
|
||||
test_allocs[test_alloc_count++] = ptr;
|
||||
}
|
||||
|
||||
cli_write("Allocated ");
|
||||
cli_write_int(size_kb);
|
||||
cli_write("KB at address 0x");
|
||||
cli_write_int((uintptr_t)ptr / 1024);
|
||||
cli_write("\n");
|
||||
cli_write("Test allocation index: ");
|
||||
cli_write_int(test_alloc_count - 1);
|
||||
cli_write("\n");
|
||||
|
||||
memory_print_stats();
|
||||
}
|
||||
|
||||
void cli_cmd_free_mem(char *args) {
|
||||
if (!args || !args[0]) {
|
||||
cli_write("Usage: freemem <index>\n");
|
||||
cli_write("Specify the allocation index from malloc output\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int idx = cli_atoi(args);
|
||||
if (idx < 0 || idx >= test_alloc_count) {
|
||||
cli_write("Invalid index. Must be 0-");
|
||||
cli_write_int(test_alloc_count - 1);
|
||||
cli_write("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
void *ptr = test_allocs[idx];
|
||||
if (ptr == NULL) {
|
||||
cli_write("Allocation at index ");
|
||||
cli_write_int(idx);
|
||||
cli_write(" is NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
kfree(ptr);
|
||||
test_allocs[idx] = NULL;
|
||||
|
||||
cli_write("Freed allocation at index ");
|
||||
cli_write_int(idx);
|
||||
cli_write("\n");
|
||||
|
||||
memory_print_stats();
|
||||
}
|
||||
|
||||
void cli_cmd_memblock(char *args) {
|
||||
(void)args;
|
||||
|
||||
cli_write("Detailed block information:\n");
|
||||
memory_print_detailed();
|
||||
}
|
||||
|
||||
void cli_cmd_memvalid(char *args) {
|
||||
(void)args;
|
||||
|
||||
cli_write("Validating memory integrity...\n");
|
||||
memory_validate();
|
||||
}
|
||||
|
||||
void cli_cmd_memtest(char *args) {
|
||||
(void)args;
|
||||
|
||||
cli_write("\n=== MEMORY STRESS TEST ===\n");
|
||||
|
||||
// Allocate multiple blocks
|
||||
cli_write("Allocating 10 blocks of 256KB each...\n");
|
||||
void *test_ptrs[10];
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
test_ptrs[i] = kmalloc(256 * 1024);
|
||||
if (test_ptrs[i] == NULL) {
|
||||
cli_write("Allocation ");
|
||||
cli_write_int(i);
|
||||
cli_write(" failed\n");
|
||||
|
||||
// Free previous allocations
|
||||
for (int j = 0; j < i; j++) {
|
||||
kfree(test_ptrs[j]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
cli_write("Allocated block ");
|
||||
cli_write_int(i);
|
||||
cli_write("\n");
|
||||
}
|
||||
|
||||
memory_print_stats();
|
||||
|
||||
// Free every other block (create fragmentation)
|
||||
cli_write("\nFreeing alternate blocks to create fragmentation...\n");
|
||||
for (int i = 0; i < 10; i += 2) {
|
||||
kfree(test_ptrs[i]);
|
||||
cli_write("Freed block ");
|
||||
cli_write_int(i);
|
||||
cli_write("\n");
|
||||
}
|
||||
|
||||
memory_print_stats();
|
||||
|
||||
// Free remaining blocks
|
||||
cli_write("\nFreeing remaining blocks...\n");
|
||||
for (int i = 1; i < 10; i += 2) {
|
||||
kfree(test_ptrs[i]);
|
||||
}
|
||||
|
||||
memory_print_stats();
|
||||
|
||||
cli_write("=== TEST COMPLETE ===\n\n");
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
#include "../memory_manager.h"
|
||||
|
||||
void cli_cmd_meminfo(char *args) {
|
||||
(void)args;
|
||||
|
||||
// Print memory statistics
|
||||
memory_print_stats();
|
||||
}
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
#include "network.h"
|
||||
#include "fat32.h"
|
||||
#include "cmd.h"
|
||||
#include "memory_manager.h"
|
||||
|
||||
static void print_mac(const mac_address_t* mac){
|
||||
char buf[64];
|
||||
int p=0;
|
||||
for(int i=0;i<6;i++){
|
||||
int v=mac->bytes[i];
|
||||
int hi=(v>>4)&0xF, lo=v&0xF;
|
||||
buf[p++]= (hi<10)?('0'+hi):('A'+(hi-10));
|
||||
buf[p++]= (lo<10)?('0'+lo):('A'+(lo-10));
|
||||
if(i<5) buf[p++]=':';
|
||||
}
|
||||
buf[p]=0;
|
||||
cli_write(buf);
|
||||
}
|
||||
|
||||
void cli_cmd_netinit(char *args){
|
||||
(void)args;
|
||||
int r=network_init();
|
||||
if(r==0){
|
||||
cli_write("Network initialized\n");
|
||||
int d=network_dhcp_acquire();
|
||||
if(d==0){
|
||||
cli_write("DHCP acquired\n");
|
||||
} else {
|
||||
cli_write("DHCP failed\n");
|
||||
}
|
||||
} else {
|
||||
cli_write("Network init failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
void cli_cmd_netinfo(char *args){
|
||||
(void)args;
|
||||
mac_address_t mac;
|
||||
ipv4_address_t ip;
|
||||
if(network_get_mac_address(&mac)==0){
|
||||
cli_write("MAC: "); print_mac(&mac); cli_write("\n");
|
||||
}
|
||||
if(network_get_ipv4_address(&ip)==0){
|
||||
cli_write("IP: ");
|
||||
for(int i=0;i<4;i++){ cli_write_int(ip.bytes[i]); if(i<3) cli_write("."); }
|
||||
cli_write("\n");
|
||||
}
|
||||
cli_write("Frames: "); cli_write_int(network_get_frames_received()); cli_write("\n");
|
||||
cli_write("UDP packets: "); cli_write_int(network_get_udp_packets_received()); cli_write("\n");
|
||||
cli_write("UDP callbacks: "); cli_write_int(network_get_udp_callbacks_called()); cli_write("\n");
|
||||
cli_write("E1000 receive calls: "); cli_write_int(network_get_e1000_receive_calls()); cli_write("\n");
|
||||
cli_write("E1000 receive empty: "); cli_write_int(network_get_e1000_receive_empty()); cli_write("\n");
|
||||
cli_write("Process calls: "); cli_write_int(network_get_process_calls()); cli_write("\n");
|
||||
}
|
||||
|
||||
void cli_cmd_ipset(char *args){
|
||||
if(!args||!*args){ cli_write("Usage: IPSET a.b.c.d\n"); return; }
|
||||
ipv4_address_t ip={{0,0,0,0}};
|
||||
int part=0; int val=0; int i=0;
|
||||
while(args[i]){
|
||||
char ch=args[i++];
|
||||
if(ch>='0'&&ch<='9'){ val=val*10+(ch-'0'); if(val>255){ cli_write("Invalid IP\n"); return; } }
|
||||
else if(ch=='.'){ if(part>3){ cli_write("Invalid IP\n"); return; } ip.bytes[part++]=(uint8_t)val; val=0; }
|
||||
else { cli_write("Invalid IP\n"); return; }
|
||||
}
|
||||
if(part!=3){ cli_write("Invalid IP\n"); return; }
|
||||
ip.bytes[3]=(uint8_t)val;
|
||||
if(network_set_ipv4_address(&ip)==0){ cli_write("IP set\n"); } else { cli_write("IP set failed\n"); }
|
||||
}
|
||||
|
||||
void cli_cmd_udpsend(char *args){
|
||||
if(!args||!*args){ cli_write("Usage: UDPSEND ip port data\n"); return; }
|
||||
char ipstr[32]; int pos=0;
|
||||
while(args[pos] && args[pos]!=' '){ ipstr[pos]=args[pos]; pos++; }
|
||||
ipstr[pos]=0;
|
||||
while(args[pos]==' ') pos++;
|
||||
char portstr[16]; int p=0;
|
||||
while(args[pos] && args[pos]!=' '){ portstr[p++]=args[pos++]; }
|
||||
portstr[p]=0;
|
||||
while(args[pos]==' ') pos++;
|
||||
char* datastr = args+pos;
|
||||
ipv4_address_t ip={{0,0,0,0}};
|
||||
int idx=0; int val=0; int j=0;
|
||||
while(ipstr[j]){
|
||||
char ch=ipstr[j++];
|
||||
if(ch>='0'&&ch<='9'){ val=val*10+(ch-'0'); if(val>255){ cli_write("Invalid IP\n"); return; } }
|
||||
else if(ch=='.'){ if(idx>3){ cli_write("Invalid IP\n"); return; } ip.bytes[idx++]=(uint8_t)val; val=0; }
|
||||
else { cli_write("Invalid IP\n"); return; }
|
||||
}
|
||||
if(idx!=3){ cli_write("Invalid IP\n"); return; }
|
||||
ip.bytes[3]=(uint8_t)val;
|
||||
int port=0; int k=0; while(portstr[k]){ char ch=portstr[k++]; if(ch<'0'||ch>'9'){ cli_write("Invalid port\n"); return; } port=port*10+(ch-'0'); }
|
||||
if(port<=0||port>65535){ cli_write("Invalid port\n"); return; }
|
||||
int len=(int)cli_strlen(datastr);
|
||||
if(len<=0){ cli_write("No data\n"); return; }
|
||||
int r=udp_send_packet(&ip,(uint16_t)port,12345,datastr,(size_t)len);
|
||||
if(r==0) cli_write("Sent\n"); else cli_write("Send failed\n");
|
||||
}
|
||||
|
||||
static void udp_print_callback(const ipv4_address_t* src_ip,uint16_t src_port,const mac_address_t* src_mac,const void* data,size_t length){
|
||||
(void)src_mac;
|
||||
|
||||
FAT32_FileHandle *fh = fat32_open("messages", "a");
|
||||
if (fh) {
|
||||
char buf[32];
|
||||
fat32_write(fh, "UDP from ", 9);
|
||||
|
||||
// Write IP
|
||||
for(int i=0;i<4;i++){
|
||||
cli_itoa(src_ip->bytes[i], buf);
|
||||
fat32_write(fh, buf, cli_strlen(buf));
|
||||
if(i<3) fat32_write(fh, ".", 1);
|
||||
}
|
||||
|
||||
fat32_write(fh, ":", 1);
|
||||
|
||||
// Write Port
|
||||
cli_itoa(src_port, buf);
|
||||
fat32_write(fh, buf, cli_strlen(buf));
|
||||
|
||||
fat32_write(fh, " ", 1);
|
||||
|
||||
// Write Message
|
||||
fat32_write(fh, data, length);
|
||||
fat32_write(fh, "\n", 1);
|
||||
|
||||
fat32_close(fh);
|
||||
|
||||
cmd_increment_msg_count();
|
||||
}
|
||||
}
|
||||
|
||||
void cli_cmd_udptest(char *args){
|
||||
if(!args||!*args){ cli_write("Usage: UDPTEST port\n"); return; }
|
||||
int port=cli_atoi(args);
|
||||
if(port<=0||port>65535){ cli_write("Invalid port\n"); return; }
|
||||
if(udp_register_callback((uint16_t)port,udp_print_callback)==0) cli_write("UDP callback registered\n"); else cli_write("Register failed\n");
|
||||
}
|
||||
|
||||
void cli_cmd_msgrc(char *args) {
|
||||
(void)args;
|
||||
cmd_reset_msg_count();
|
||||
|
||||
FAT32_FileHandle *fh = fat32_open("messages", "r");
|
||||
if (!fh) {
|
||||
cli_write("No messages.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t size = fh->size;
|
||||
if (size == 0) {
|
||||
fat32_close(fh);
|
||||
cli_write("No messages.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char *buffer = (char*)kmalloc(size + 1);
|
||||
if (!buffer) {
|
||||
fat32_close(fh);
|
||||
cli_write("Error: Out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fat32_read(fh, buffer, size);
|
||||
buffer[size] = 0;
|
||||
fat32_close(fh);
|
||||
|
||||
int count = 0;
|
||||
int pos = size - 1;
|
||||
|
||||
while (count < 10 && pos >= 0) {
|
||||
// Skip trailing newlines/whitespace
|
||||
while (pos >= 0 && (buffer[pos] == '\n' || buffer[pos] == '\r')) {
|
||||
buffer[pos] = 0;
|
||||
pos--;
|
||||
}
|
||||
if (pos < 0) break;
|
||||
|
||||
// Find start of line
|
||||
while (pos >= 0 && buffer[pos] != '\n' && buffer[pos] != '\r') pos--;
|
||||
|
||||
cli_write(&buffer[pos + 1]);
|
||||
cli_write("\n");
|
||||
count++;
|
||||
}
|
||||
|
||||
kfree(buffer);
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
#include "pci.h"
|
||||
|
||||
static void print_hex16(uint16_t v){
|
||||
char buf[7]; buf[0]='0'; buf[1]='x';
|
||||
for(int i=0;i<4;i++){
|
||||
int nyb=(v >> ((3-i)*4)) & 0xF;
|
||||
buf[2+i]= nyb<10?('0'+nyb):('A'+(nyb-10));
|
||||
}
|
||||
buf[6]=0;
|
||||
cli_write(buf);
|
||||
}
|
||||
|
||||
static void print_hex8(uint8_t v){
|
||||
char buf[5]; buf[0]='0'; buf[1]='x';
|
||||
int hi=(v>>4)&0xF, lo=v&0xF;
|
||||
buf[2]= hi<10?('0'+hi):('A'+(hi-10));
|
||||
buf[3]= lo<10?('0'+lo):('A'+(lo-10));
|
||||
buf[4]=0;
|
||||
cli_write(buf);
|
||||
}
|
||||
|
||||
void cli_cmd_pcilist(char *args){
|
||||
(void)args;
|
||||
pci_device_t devs[64];
|
||||
int n=pci_enumerate_devices(devs,64);
|
||||
cli_write("PCI devices:\n");
|
||||
for(int i=0;i<n;i++){
|
||||
cli_write(" ");
|
||||
cli_write_int(devs[i].bus); cli_write(":");
|
||||
cli_write_int(devs[i].device); cli_write(".");
|
||||
cli_write_int(devs[i].function); cli_write(" ");
|
||||
cli_write("vendor="); print_hex16(devs[i].vendor_id); cli_write(" ");
|
||||
cli_write("device="); print_hex16(devs[i].device_id); cli_write(" ");
|
||||
cli_write("class="); print_hex8(devs[i].class_code); cli_write(" ");
|
||||
cli_write("subclass="); print_hex8(devs[i].subclass); cli_write(" ");
|
||||
cli_write("prog_if="); print_hex8(devs[i].prog_if);
|
||||
if(devs[i].vendor_id==0x8086 && devs[i].device_id==0x100E){
|
||||
cli_write(" [e1000]");
|
||||
}
|
||||
cli_write("\n");
|
||||
}
|
||||
cli_write_int(n); cli_write(" device(s)\n");
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
|
||||
// Forward declaration from cmd.c
|
||||
extern void cli_cmd_beep(char *args);
|
||||
|
||||
void cli_cmd_readtheman(char *args) {
|
||||
(void)args;
|
||||
cli_write("\nYou read the manual? NERD. you know what?\n");
|
||||
cli_write("Fuck you.\n");
|
||||
for(int i=0; i<3; i++) {
|
||||
cli_cmd_beep(NULL);
|
||||
cli_sleep(10);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
#include "io.h"
|
||||
|
||||
struct idtr_t {
|
||||
uint16_t limit;
|
||||
uint64_t base;
|
||||
} __attribute__((packed));
|
||||
|
||||
void cli_cmd_reboot(char *args) {
|
||||
(void)args;
|
||||
cli_write("Rebooting...\n");
|
||||
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
if ((inb(0x64) & 1) != 0) (void)inb(0x60);
|
||||
cli_delay(10000);
|
||||
}
|
||||
|
||||
// Pulse reset line
|
||||
for (int i = 0; i < 100; i++) {
|
||||
uint8_t temp = inb(0x64);
|
||||
if ((temp & 2) == 0) break;
|
||||
cli_delay(10000);
|
||||
}
|
||||
outb(0x64, 0xFE);
|
||||
cli_delay(5000000); // Wait for reset
|
||||
|
||||
|
||||
struct idtr_t idtr_invalid = { 0, 0 };
|
||||
|
||||
asm volatile ("cli");
|
||||
asm volatile ("lidt %0" : : "m"(idtr_invalid));
|
||||
asm volatile ("int $3");
|
||||
|
||||
while(1) {
|
||||
asm volatile ("hlt");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
#include "io.h"
|
||||
|
||||
void cli_cmd_shutdown(char *args) {
|
||||
(void)args;
|
||||
cli_write("Shutting down...\n");
|
||||
cli_delay(5000000);
|
||||
outb(0x64, 0xFE);
|
||||
outw(0x604, 0x2000);
|
||||
outw(0xB004, 0x2000);
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
#include "io.h"
|
||||
|
||||
void play_note(int freq, int duration_ms) {
|
||||
if (freq == 0) {
|
||||
outb(0x61, inb(0x61) & 0xFC);
|
||||
} else {
|
||||
int div = 1193180 / freq;
|
||||
outb(0x43, 0xB6);
|
||||
outb(0x42, div & 0xFF);
|
||||
outb(0x42, (div >> 8) & 0xFF);
|
||||
outb(0x61, inb(0x61) | 0x03);
|
||||
}
|
||||
|
||||
|
||||
cli_sleep(duration_ms);
|
||||
|
||||
outb(0x61, inb(0x61) & 0xFC);
|
||||
cli_sleep(20);
|
||||
}
|
||||
|
||||
void cli_cmd_minecraft(char *args) {
|
||||
(void)args;
|
||||
cli_write("Playing: Sweden - C418 (What a masterpiece)\n");
|
||||
|
||||
int melody[] = {
|
||||
196, 330, 294, 0, // G3, E4, D4, rest
|
||||
196, 262, 247, 220, 196, 0, // G3, C4, B3, A3, G3, rest
|
||||
|
||||
196, 330, 294, 392, 330, 0, // G3, E4, D4, G4, E4, rest
|
||||
|
||||
440, 330, 294, 0, // A4, E4, D4, rest
|
||||
262, 247, 220, 196, 147, 0, // C4, B3, A3, G3, D3, rest
|
||||
|
||||
196, 330, 294, 0, // Return to G3, E4, D4
|
||||
196, 262, 247, 220, 196 // Final resolution
|
||||
};
|
||||
|
||||
int rhythm[] = {
|
||||
1000, 1000, 2000, 500,
|
||||
1000, 1000, 1000, 1000, 2000, 500,
|
||||
|
||||
1000, 1000, 1000, 1000, 2000, 500,
|
||||
|
||||
1000, 1000, 2000, 500,
|
||||
1000, 1000, 1000, 1000, 2000, 500,
|
||||
|
||||
1000, 1000, 2000, 500,
|
||||
1000, 1000, 1000, 1000, 3000
|
||||
};
|
||||
|
||||
int song_length = sizeof(melody) / sizeof(melody[0]);
|
||||
|
||||
for (int i = 0; i < song_length; i++) {
|
||||
play_note(melody[i], rhythm[i]);
|
||||
}
|
||||
|
||||
outb(0x61, inb(0x61) & 0xFC);
|
||||
cli_write("Composition finished.\n");
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
#include "cli_utils.h"
|
||||
|
||||
// Forward declarations from cmd.c
|
||||
extern void rtc_get_datetime(int *y, int *m, int *d, int *h, int *min, int *s);
|
||||
extern int boot_time_init;
|
||||
extern int boot_year, boot_month, boot_day, boot_hour, boot_min, boot_sec;
|
||||
|
||||
void cli_cmd_uptime(char *args) {
|
||||
(void)args;
|
||||
int y, m, d, h, min, s;
|
||||
rtc_get_datetime(&y, &m, &d, &h, &min, &s);
|
||||
|
||||
int start_sec = boot_hour * 3600 + boot_min * 60 + boot_sec;
|
||||
int curr_sec = h * 3600 + min * 60 + s;
|
||||
if (curr_sec < start_sec) curr_sec += 24 * 3600;
|
||||
|
||||
int diff = curr_sec - start_sec;
|
||||
int up_h = diff / 3600;
|
||||
int up_m = (diff % 3600) / 60;
|
||||
int up_s = diff % 60;
|
||||
|
||||
cli_write("Uptime: ");
|
||||
cli_write_int(up_h); cli_write("h ");
|
||||
cli_write_int(up_m); cli_write("m ");
|
||||
cli_write_int(up_s); cli_write("s\n");
|
||||
}
|
||||
178
src/kernel/cmd.c
178
src/kernel/cmd.c
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "fat32.h"
|
||||
#include "disk.h"
|
||||
#include "cli_apps/cli_apps.h"
|
||||
#include "kutils.h"
|
||||
#include "licensewr.h"
|
||||
#include <stddef.h>
|
||||
#include "memory_manager.h"
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
#include "network.h"
|
||||
#include "vm.h"
|
||||
#include "net_defs.h"
|
||||
#include "man_entries.h"
|
||||
|
||||
#define CMD_COLS 116
|
||||
#define CMD_ROWS 41
|
||||
|
|
@ -376,22 +377,7 @@ void pager_set_mode(void) {
|
|||
// Internal LS command to avoid stack overflow in external module
|
||||
static void cmd_update_dir(const char *path); // Forward declaration
|
||||
|
||||
static void internal_cmd_pwd(char *args) {
|
||||
(void)args;
|
||||
if (cmd_state) {
|
||||
char drive_str[3];
|
||||
drive_str[0] = cmd_state->current_drive;
|
||||
drive_str[1] = ':';
|
||||
drive_str[2] = 0;
|
||||
cmd_write(drive_str);
|
||||
cmd_write(cmd_state->current_dir);
|
||||
} else {
|
||||
char cwd[256];
|
||||
fat32_get_current_dir(cwd, sizeof(cwd));
|
||||
cmd_write(cwd);
|
||||
}
|
||||
cmd_write("\n");
|
||||
}
|
||||
|
||||
|
||||
static void internal_cmd_cd(char *args) {
|
||||
// Handle cd with proper cmd_state context
|
||||
|
|
@ -533,46 +519,14 @@ static void internal_cmd_txtedit(char *args) {
|
|||
cmd_write("\n");
|
||||
|
||||
cmd_is_waiting_for_process = true;
|
||||
process_create_elf("A:/bin/txtedit.elf", normalized_path);
|
||||
process_t *proc = process_create_elf("A:/bin/txtedit.elf", normalized_path);
|
||||
if (proc) {
|
||||
proc->is_terminal_proc = true;
|
||||
proc->ui_window = &win_cmd;
|
||||
}
|
||||
}
|
||||
|
||||
static void internal_cmd_ls(char *args) {
|
||||
char path[256];
|
||||
if (args && *args) {
|
||||
int i=0;
|
||||
while(args[i] && i < 255) { path[i] = args[i]; i++; }
|
||||
path[i] = 0;
|
||||
} else {
|
||||
path[0] = '.'; path[1] = 0;
|
||||
}
|
||||
|
||||
int max_files = 64;
|
||||
FAT32_FileInfo *files = (FAT32_FileInfo*)kmalloc(max_files * sizeof(FAT32_FileInfo));
|
||||
if (!files) {
|
||||
cmd_write("Error: Out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int count = fat32_list_directory(path, files, max_files);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (files[i].is_directory) {
|
||||
cmd_write("[DIR] ");
|
||||
} else {
|
||||
cmd_write("[FILE] ");
|
||||
}
|
||||
|
||||
cmd_write(files[i].name);
|
||||
if (!files[i].is_directory) {
|
||||
cmd_write(" ");
|
||||
cmd_write_int(files[i].size);
|
||||
cmd_write("b");
|
||||
}
|
||||
cmd_write("\n");
|
||||
}
|
||||
|
||||
kfree(files);
|
||||
}
|
||||
|
||||
|
||||
void cmd_exec_elf(char *args) {
|
||||
|
|
@ -611,7 +565,11 @@ void cmd_exec_elf(char *args) {
|
|||
}
|
||||
|
||||
cmd_is_waiting_for_process = true;
|
||||
process_create_elf(full_exec_path, args);
|
||||
process_t *proc = process_create_elf(full_exec_path, args);
|
||||
if (proc) {
|
||||
proc->is_terminal_proc = true;
|
||||
proc->ui_window = &win_cmd;
|
||||
}
|
||||
}
|
||||
|
||||
// Public API for syscall exit
|
||||
|
|
@ -628,6 +586,11 @@ void cmd_process_finished(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void internal_cmd_exit(char *args) {
|
||||
(void)args;
|
||||
cmd_window_exit();
|
||||
}
|
||||
|
||||
// Command dispatch table
|
||||
typedef struct {
|
||||
const char *name;
|
||||
|
|
@ -637,101 +600,18 @@ typedef struct {
|
|||
static const CommandEntry commands[] = {
|
||||
{"EXEC", cmd_exec_elf},
|
||||
{"exec", cmd_exec_elf},
|
||||
{"HELP", cli_cmd_help},
|
||||
{"help", cli_cmd_help},
|
||||
{"DATE", cli_cmd_date},
|
||||
{"date", cli_cmd_date},
|
||||
{"CLEAR", cli_cmd_clear},
|
||||
{"clear", cli_cmd_clear},
|
||||
{"BOREDVER", cli_cmd_boredver},
|
||||
{"boredver", cli_cmd_boredver},
|
||||
{"MATH", cli_cmd_math},
|
||||
{"math", cli_cmd_math},
|
||||
{"MAN", cli_cmd_man},
|
||||
{"man", cli_cmd_man},
|
||||
{"TXTEDIT", internal_cmd_txtedit},
|
||||
{"txtedit", internal_cmd_txtedit},
|
||||
{"UPTIME", cli_cmd_uptime},
|
||||
{"uptime", cli_cmd_uptime},
|
||||
{"BEEP", cli_cmd_beep},
|
||||
{"beep", cli_cmd_beep},
|
||||
{"COWSAY", cli_cmd_cowsay},
|
||||
{"cowsay", cli_cmd_cowsay},
|
||||
{"REBOOT", cli_cmd_reboot},
|
||||
{"reboot", cli_cmd_reboot},
|
||||
{"SHUTDOWN", cli_cmd_shutdown},
|
||||
{"shutdown", cli_cmd_shutdown},
|
||||
{"IREADTHEMANUAL", cli_cmd_readtheman},
|
||||
{"ireadthemanual", cli_cmd_readtheman},
|
||||
{"BLIND", cli_cmd_blind},
|
||||
{"blind", cli_cmd_blind},
|
||||
{"EXIT", cli_cmd_exit},
|
||||
{"exit", cli_cmd_exit},
|
||||
// Filesystem Commands
|
||||
{"EXIT", internal_cmd_exit},
|
||||
{"exit", internal_cmd_exit},
|
||||
{"CD", internal_cmd_cd},
|
||||
{"cd", internal_cmd_cd},
|
||||
{"PWD", internal_cmd_pwd},
|
||||
{"pwd", internal_cmd_pwd},
|
||||
{"LS", internal_cmd_ls},
|
||||
{"ls", internal_cmd_ls},
|
||||
{"MKDIR", cli_cmd_mkdir},
|
||||
{"mkdir", cli_cmd_mkdir},
|
||||
{"RM", cli_cmd_rm},
|
||||
{"rm", cli_cmd_rm},
|
||||
{"ECHO", cli_cmd_echo},
|
||||
{"echo", cli_cmd_echo},
|
||||
{"CAT", cli_cmd_cat},
|
||||
{"cat", cli_cmd_cat},
|
||||
{"TOUCH", cli_cmd_touch},
|
||||
{"touch", cli_cmd_touch},
|
||||
{"CP", cli_cmd_cp},
|
||||
{"cp", cli_cmd_cp},
|
||||
{"MV", cli_cmd_mv},
|
||||
{"mv", cli_cmd_mv},
|
||||
// Memory Management Commands
|
||||
{"MEMINFO", cli_cmd_meminfo},
|
||||
{"meminfo", cli_cmd_meminfo},
|
||||
{"MALLOC", cli_cmd_malloc},
|
||||
{"malloc", cli_cmd_malloc},
|
||||
{"FREEMEM", cli_cmd_free_mem},
|
||||
{"freemem", cli_cmd_free_mem},
|
||||
{"MEMBLOCK", cli_cmd_memblock},
|
||||
{"memblock", cli_cmd_memblock},
|
||||
{"MEMVALID", cli_cmd_memvalid},
|
||||
{"memvalid", cli_cmd_memvalid},
|
||||
{"MEMTEST", cli_cmd_memtest},
|
||||
{"memtest", cli_cmd_memtest},
|
||||
// Network Commands
|
||||
{"NETINIT", cli_cmd_netinit},
|
||||
{"netinit", cli_cmd_netinit},
|
||||
{"NETINFO", cli_cmd_netinfo},
|
||||
{"netinfo", cli_cmd_netinfo},
|
||||
{"IPSET", cli_cmd_ipset},
|
||||
{"ipset", cli_cmd_ipset},
|
||||
{"UDPSEND", cli_cmd_udpsend},
|
||||
{"udpsend", cli_cmd_udpsend},
|
||||
{"UDPTEST", cli_cmd_udptest},
|
||||
{"udptest", cli_cmd_udptest},
|
||||
{"PING", cli_cmd_ping},
|
||||
{"ping", cli_cmd_ping},
|
||||
{"DNS", cli_cmd_dns},
|
||||
{"dns", cli_cmd_dns},
|
||||
{"HTTPGET", cli_cmd_httpget},
|
||||
{"httpget", cli_cmd_httpget},
|
||||
{"PCILIST", cli_cmd_pcilist},
|
||||
{"pcilist", cli_cmd_pcilist},
|
||||
{"MSGRC", cli_cmd_msgrc},
|
||||
{"msgrc", cli_cmd_msgrc},
|
||||
{"COMPC", cli_cmd_cc},
|
||||
{"compc", cli_cmd_cc},
|
||||
{"CC", cli_cmd_cc},
|
||||
{"cc", cli_cmd_cc},
|
||||
{"sweden", cli_cmd_minecraft},
|
||||
{"SWEDEN", cli_cmd_minecraft},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// Helper to sync cmd window directory after cd
|
||||
static void cmd_update_dir(const char *path) {
|
||||
if (!cmd_state || !path) return;
|
||||
|
|
@ -932,6 +812,7 @@ static void cmd_exec_single(char *cmd) {
|
|||
temp_args[j++] = args[i++];
|
||||
}
|
||||
}
|
||||
(void)in_redirect;
|
||||
temp_args[j] = 0;
|
||||
cmd_strcpy(full_path_arg, temp_args);
|
||||
args = full_path_arg;
|
||||
|
|
@ -1095,7 +976,11 @@ static void cmd_exec_single(char *cmd) {
|
|||
if (fh) {
|
||||
fat32_close(fh);
|
||||
cmd_is_waiting_for_process = true;
|
||||
process_create_elf(search_path, args);
|
||||
process_t *proc = process_create_elf(search_path, args);
|
||||
if (proc) {
|
||||
proc->is_terminal_proc = true;
|
||||
proc->ui_window = &win_cmd;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -1116,7 +1001,11 @@ static void cmd_exec_single(char *cmd) {
|
|||
if (fh) {
|
||||
fat32_close(fh);
|
||||
cmd_is_waiting_for_process = true;
|
||||
process_create_elf(search_path, args);
|
||||
process_t *proc = process_create_elf(search_path, args);
|
||||
if (proc) {
|
||||
proc->is_terminal_proc = true;
|
||||
proc->ui_window = &win_cmd;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -1705,6 +1594,7 @@ static void create_test_files(void) {
|
|||
|
||||
void cmd_init(void) {
|
||||
create_test_files();
|
||||
create_man_entries();
|
||||
|
||||
win_cmd.title = "Command Prompt";
|
||||
win_cmd.x = 50;
|
||||
|
|
|
|||
|
|
@ -724,8 +724,8 @@ static void explorer_load_directory(Window *win, const char *path) {
|
|||
|
||||
int count = fat32_list_directory(path, entries, EXPLORER_MAX_FILES);
|
||||
|
||||
state->item_count = 0;
|
||||
for (int i = 0; i < count && state->item_count < EXPLORER_MAX_FILES; i++) {
|
||||
int temp_count = 0;
|
||||
for (int i = 0; i < count && temp_count < EXPLORER_MAX_FILES; i++) {
|
||||
// Skip .color files
|
||||
if (explorer_strcmp(entries[i].name, ".color") == 0) {
|
||||
continue;
|
||||
|
|
@ -736,24 +736,26 @@ static void explorer_load_directory(Window *win, const char *path) {
|
|||
continue;
|
||||
}
|
||||
|
||||
explorer_strcpy(state->items[state->item_count].name, entries[i].name);
|
||||
state->items[state->item_count].is_directory = entries[i].is_directory;
|
||||
state->items[state->item_count].size = entries[i].size;
|
||||
explorer_strcpy(state->items[temp_count].name, entries[i].name);
|
||||
state->items[temp_count].is_directory = entries[i].is_directory;
|
||||
state->items[temp_count].size = entries[i].size;
|
||||
|
||||
if (state->items[state->item_count].is_directory) {
|
||||
if (state->items[temp_count].is_directory) {
|
||||
char subfolder_path[FAT32_MAX_PATH];
|
||||
explorer_strcpy(subfolder_path, path);
|
||||
if (subfolder_path[explorer_strlen(subfolder_path) - 1] != '/') {
|
||||
explorer_strcat(subfolder_path, "/");
|
||||
}
|
||||
explorer_strcat(subfolder_path, state->items[state->item_count].name);
|
||||
state->items[state->item_count].color = explorer_get_folder_color(subfolder_path);
|
||||
explorer_strcat(subfolder_path, state->items[temp_count].name);
|
||||
state->items[temp_count].color = explorer_get_folder_color(subfolder_path);
|
||||
} else {
|
||||
state->items[state->item_count].color = COLOR_APPLE_YELLOW;
|
||||
state->items[temp_count].color = COLOR_APPLE_YELLOW;
|
||||
}
|
||||
state->item_count++;
|
||||
temp_count++;
|
||||
}
|
||||
|
||||
state->item_count = temp_count;
|
||||
|
||||
kfree(entries);
|
||||
if (path_changed) {
|
||||
state->selected_item = -1;
|
||||
|
|
|
|||
|
|
@ -1,23 +1,25 @@
|
|||
#include "cli_utils.h"
|
||||
#include "kutils.h"
|
||||
#include "wm.h"
|
||||
#include "io.h"
|
||||
|
||||
// Forward declarations - these will be provided by cmd.c
|
||||
extern void cmd_putchar(char c);
|
||||
extern void cmd_write(const char *str);
|
||||
extern void cmd_write_int(int n);
|
||||
|
||||
void cli_memset(void *dest, int val, size_t len) {
|
||||
unsigned char *ptr = dest;
|
||||
while (len-- > 0) *ptr++ = val;
|
||||
void k_memset(void *dest, int val, size_t len) {
|
||||
unsigned char *ptr = (unsigned char *)dest;
|
||||
while (len-- > 0) *ptr++ = (unsigned char)val;
|
||||
}
|
||||
|
||||
size_t cli_strlen(const char *str) {
|
||||
void k_memcpy(void *dest, const void *src, size_t len) {
|
||||
unsigned char *d = (unsigned char *)dest;
|
||||
const unsigned char *s = (const unsigned char *)src;
|
||||
while (len-- > 0) *d++ = *s++;
|
||||
}
|
||||
|
||||
size_t k_strlen(const char *str) {
|
||||
size_t len = 0;
|
||||
while (str[len]) len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
int cli_strcmp(const char *s1, const char *s2) {
|
||||
int k_strcmp(const char *s1, const char *s2) {
|
||||
while (*s1 && (*s1 == *s2)) {
|
||||
s1++;
|
||||
s2++;
|
||||
|
|
@ -25,12 +27,12 @@ int cli_strcmp(const char *s1, const char *s2) {
|
|||
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
|
||||
}
|
||||
|
||||
void cli_strcpy(char *dest, const char *src) {
|
||||
void k_strcpy(char *dest, const char *src) {
|
||||
while (*src) *dest++ = *src++;
|
||||
*dest = 0;
|
||||
}
|
||||
|
||||
int cli_atoi(const char *str) {
|
||||
int k_atoi(const char *str) {
|
||||
int res = 0;
|
||||
int sign = 1;
|
||||
if (*str == '-') { sign = -1; str++; }
|
||||
|
|
@ -41,7 +43,7 @@ int cli_atoi(const char *str) {
|
|||
return res * sign;
|
||||
}
|
||||
|
||||
void cli_itoa(int n, char *buf) {
|
||||
void k_itoa(int n, char *buf) {
|
||||
if (n == 0) {
|
||||
buf[0] = '0'; buf[1] = 0; return;
|
||||
}
|
||||
|
|
@ -54,7 +56,6 @@ void cli_itoa(int n, char *buf) {
|
|||
}
|
||||
if (sign) buf[i++] = '-';
|
||||
buf[i] = 0;
|
||||
// Reverse
|
||||
for (int j = 0; j < i / 2; j++) {
|
||||
char t = buf[j];
|
||||
buf[j] = buf[i - 1 - j];
|
||||
|
|
@ -62,25 +63,13 @@ void cli_itoa(int n, char *buf) {
|
|||
}
|
||||
}
|
||||
|
||||
void cli_write(const char *str) {
|
||||
cmd_write(str);
|
||||
}
|
||||
|
||||
void cli_write_int(int n) {
|
||||
cmd_write_int(n);
|
||||
}
|
||||
|
||||
void cli_putchar(char c) {
|
||||
cmd_putchar(c);
|
||||
}
|
||||
|
||||
void cli_delay(int iterations) {
|
||||
void k_delay(int iterations) {
|
||||
for (volatile int i = 0; i < iterations; i++) {
|
||||
__asm__ __volatile__("nop");
|
||||
}
|
||||
}
|
||||
|
||||
void cli_sleep(int ms) {
|
||||
void k_sleep(int ms) {
|
||||
// Timer is ~60Hz, so 1 tick = 16.66ms
|
||||
uint32_t ticks = ms / 16;
|
||||
if (ticks == 0 && ms > 0) ticks = 1;
|
||||
|
|
@ -90,3 +79,11 @@ void cli_sleep(int ms) {
|
|||
__asm__ __volatile__("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
void k_reboot(void) {
|
||||
outb(0x64, 0xFE);
|
||||
}
|
||||
|
||||
void k_shutdown(void) {
|
||||
outw(0x604, 0x2000);
|
||||
}
|
||||
22
src/kernel/kutils.h
Normal file
22
src/kernel/kutils.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef KUTILS_H
|
||||
#define KUTILS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Kernel string utilities
|
||||
void k_memset(void *dest, int val, size_t len);
|
||||
void k_memcpy(void *dest, const void *src, size_t len);
|
||||
size_t k_strlen(const char *str);
|
||||
int k_strcmp(const char *s1, const char *s2);
|
||||
void k_strcpy(char *dest, const char *src);
|
||||
int k_atoi(const char *str);
|
||||
void k_itoa(int n, char *buf);
|
||||
|
||||
// Kernel timing utilities
|
||||
void k_delay(int iterations);
|
||||
void k_sleep(int ms);
|
||||
void k_reboot(void);
|
||||
void k_shutdown(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -46,6 +46,13 @@ static volatile struct limine_request *const requests_start_marker[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
__attribute__((used, section(".requests")))
|
||||
static volatile struct limine_stack_size_request stack_size_request = {
|
||||
.id = LIMINE_STACK_SIZE_REQUEST,
|
||||
.revision = 0,
|
||||
.stack_size = 1024 * 1024 // 1MB stack
|
||||
};
|
||||
|
||||
__attribute__((used, section(".requests_end")))
|
||||
static volatile struct limine_request *const requests_end_marker[] = {
|
||||
NULL
|
||||
|
|
|
|||
69
src/kernel/man_entries.h
Normal file
69
src/kernel/man_entries.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#ifndef MAN_ENTRIES_H
|
||||
#define MAN_ENTRIES_H
|
||||
|
||||
#include "fat32.h"
|
||||
#include <stddef.h>
|
||||
|
||||
static size_t man_strlen(const char *str) {
|
||||
size_t len = 0;
|
||||
while (str[len]) len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
static void write_man_file(const char *name, const char *content) {
|
||||
char path[128] = "A:/Library/man/";
|
||||
int i = 15;
|
||||
while (*name) path[i++] = *name++;
|
||||
path[i++] = '.';
|
||||
path[i++] = 't';
|
||||
path[i++] = 'x';
|
||||
path[i++] = 't';
|
||||
path[i] = 0;
|
||||
|
||||
FAT32_FileHandle *fh = fat32_open(path, "w");
|
||||
if (fh) {
|
||||
fat32_write(fh, (void *)content, man_strlen(content));
|
||||
fat32_close(fh);
|
||||
}
|
||||
}
|
||||
|
||||
void create_man_entries(void) {
|
||||
fat32_mkdir("A:/Library");
|
||||
fat32_mkdir("A:/Library/man");
|
||||
|
||||
write_man_file("ls", "LS - List directory contents\n\nUsage: ls [path]\n\nLists files and directories in the current or specified directory.");
|
||||
write_man_file("cat", "CAT - Concatenate and display file contents\n\nUsage: cat <filename>\n\nDisplays the text content of the specified file.");
|
||||
write_man_file("man", "MAN - Display manual pages\n\nUsage: man <command>\n\nDisplays help information for the specified command.");
|
||||
write_man_file("beep", "BEEP - Play system beep\n\nUsage: beep\n\nPlays a short tone through the PC speaker.");
|
||||
write_man_file("sweden", "SWEDEN - Play Swedish melody\n\nUsage: sweden\n\nPlays the Swedish national anthem through the PC speaker.");
|
||||
write_man_file("clear", "CLEAR - Clear terminal screen\n\nUsage: clear\n\nClears all text from the current terminal window.");
|
||||
write_man_file("date", "DATE - Show current date and time\n\nUsage: date\n\nDisplays the current system date and time from the RTC.");
|
||||
write_man_file("echo", "ECHO - Print text\n\nUsage: echo [text]\n\nPrints the specified text to the terminal.");
|
||||
write_man_file("hello", "HELLO - Hello World demo\n\nUsage: hello\n\nA simple demonstration program that prints a greeting.");
|
||||
write_man_file("help", "HELP - List available commands\n\nUsage: help\n\nLists all internal and external commands available in the shell.");
|
||||
write_man_file("uptime", "UPTIME - Show system uptime\n\nUsage: uptime\n\nDisplays how long BoredOS has been running since boot.");
|
||||
write_man_file("pwd", "PWD - Print working directory\n\nUsage: pwd\n\nDisplays the absolute path of the current working directory.");
|
||||
write_man_file("mkdir", "MKDIR - Create directory\n\nUsage: mkdir <dirname>\n\nCreates a new directory with the specified name.");
|
||||
write_man_file("rm", "RM - Remove file\n\nUsage: rm <filename>\n\nDeletes the specified file from the filesystem.");
|
||||
write_man_file("mv", "MV - Move or rename file\n\nUsage: mv <source> <dest>\n\nMoves or renames a file or directory.");
|
||||
write_man_file("cp", "CP - Copy file\n\nUsage: cp <source> <dest>\n\nCopies a file from the source path to the destination path.");
|
||||
write_man_file("touch", "TOUCH - Create empty file\n\nUsage: touch <filename>\n\nCreates a new empty file if it doesn't exist.");
|
||||
write_man_file("cc", "CC - C Compiler\n\nUsage: cc <file.c>\n\nThe BoredOS C Compiler. Compiles C source files into ELF executables.");
|
||||
write_man_file("crash", "CRASH - Trigger kernel exception\n\nUsage: crash\n\nIntentionally triggers a null pointer dereference to test handlers.");
|
||||
write_man_file("boredver", "BOREDVER - Show OS version\n\nUsage: boredver\n\nDisplays current BoredOS version and kernel build information.");
|
||||
write_man_file("meminfo", "MEMINFO - Memory usage stats\n\nUsage: meminfo\n\nDisplays current physical and virtual memory allocation statistics.");
|
||||
write_man_file("pci_list", "PCI_LIST - Scan PCI bus\n\nUsage: pci_list\n\nScans the PCI bus and lists all detected hardware devices.");
|
||||
write_man_file("reboot", "REBOOT - Restart system\n\nUsage: reboot\n\nRestarts the computer immediately.");
|
||||
write_man_file("shutdown", "SHUTDOWN - Power off\n\nUsage: shutdown\n\nPowers off the machine (requires ACPI support).");
|
||||
write_man_file("calculator", "CALCULATOR - Graphical calculator\n\nUsage: calculator\n\nOpens a simple calculator with a mouse interface.");
|
||||
write_man_file("notepad", "NOTEPAD - Desktop text editor\n\nUsage: notepad\n\nOpens a graphical text editor for the BoredOS desktop.");
|
||||
write_man_file("paint", "PAINT - Drawing application\n\nUsage: paint\n\nOpens a simple drawing program with various colors.");
|
||||
write_man_file("minesweeper", "MINESWEEPER - Classic game\n\nUsage: minesweeper\n\nPlays the classic minesweeper puzzle game.");
|
||||
write_man_file("markdown", "MARKDOWN - MD file viewer\n\nUsage: markdown <file.md>\n\nOpens a graphical viewer for formatted markdown files.");
|
||||
write_man_file("txtedit", "TXTEDIT - Terminal text editor\n\nUsage: txtedit <filename>\n\nOpens a CLI-based text editor within the terminal.");
|
||||
write_man_file("math", "MATH - Expression evaluator\n\nUsage: math <expression>\n\nEvaluates simple arithmetic expressions from the command line.");
|
||||
write_man_file("viewer", "VIEWER - Image viewer\n\nUsage: viewer <file.ppm>\n\nA graphical application for viewing image files.");
|
||||
write_man_file("settings", "SETTINGS - System settings\n\nUsage: settings\n\nOpens the graphical system configuration tool.");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -51,8 +51,8 @@ void process_create(void* entry_point, bool is_user) {
|
|||
if (!new_proc->pml4_phys) return;
|
||||
|
||||
// 2. Allocate aligned stack
|
||||
void* stack = kmalloc_aligned(4096, 4096);
|
||||
void* kernel_stack = kmalloc_aligned(16384, 16384); // Needed for when user interrupts to Ring 0
|
||||
void* stack = kmalloc_aligned(524288, 4096); // 512KB for kernel threads
|
||||
void* kernel_stack = kmalloc_aligned(126976, 16384); // 128KB for ringswitch
|
||||
|
||||
if (is_user) {
|
||||
// Map user stack to 0x800000
|
||||
|
|
@ -66,7 +66,7 @@ void process_create(void* entry_point, bool is_user) {
|
|||
|
||||
// Build initial stack frame for iretq
|
||||
// Stack grows down, start at top
|
||||
uint64_t* stack_ptr = (uint64_t*)((uint64_t)kernel_stack + 16384);
|
||||
uint64_t* stack_ptr = (uint64_t*)((uint64_t)kernel_stack + 126976);
|
||||
|
||||
*(--stack_ptr) = 0x1B; // SS (User Data)
|
||||
*(--stack_ptr) = 0x800000 + 4096; // RSP
|
||||
|
|
@ -79,11 +79,11 @@ void process_create(void* entry_point, bool is_user) {
|
|||
// Push 15 zeros for general purpose registers (r15 -> rax)
|
||||
for (int i = 0; i < 15; i++) *(--stack_ptr) = 0;
|
||||
|
||||
new_proc->kernel_stack = (uint64_t)kernel_stack + 16384;
|
||||
new_proc->kernel_stack = (uint64_t)kernel_stack + 126976;
|
||||
new_proc->rsp = (uint64_t)stack_ptr;
|
||||
} else {
|
||||
// Kernel thread
|
||||
uint64_t* stack_ptr = (uint64_t*)((uint64_t)stack + 4096);
|
||||
uint64_t* stack_ptr = (uint64_t*)((uint64_t)stack + 524288);
|
||||
*(--stack_ptr) = 0x10; // SS (Kernel Data)
|
||||
stack_ptr--;
|
||||
*stack_ptr = (uint64_t)stack_ptr; // RSP
|
||||
|
|
@ -104,8 +104,8 @@ void process_create(void* entry_point, bool is_user) {
|
|||
current_process->next = new_proc;
|
||||
}
|
||||
|
||||
void process_create_elf(const char* filepath, const char* args_str) {
|
||||
if (process_count >= MAX_PROCESSES) return;
|
||||
process_t* process_create_elf(const char* filepath, const char* args_str) {
|
||||
if (process_count >= MAX_PROCESSES) return NULL;
|
||||
|
||||
process_t *new_proc = &processes[process_count];
|
||||
new_proc->pid = next_pid++;
|
||||
|
|
@ -113,7 +113,7 @@ void process_create_elf(const char* filepath, const char* args_str) {
|
|||
|
||||
// 1. Setup Page Table
|
||||
new_proc->pml4_phys = paging_create_user_pml4_phys();
|
||||
if (!new_proc->pml4_phys) return;
|
||||
if (!new_proc->pml4_phys) return NULL;
|
||||
|
||||
for (int i = 0; i < MAX_PROCESS_FDS; i++) new_proc->fds[i] = NULL;
|
||||
new_proc->gui_event_head = 0;
|
||||
|
|
@ -121,6 +121,7 @@ void process_create_elf(const char* filepath, const char* args_str) {
|
|||
new_proc->ui_window = NULL;
|
||||
new_proc->heap_start = 0x20000000; // 512MB mark
|
||||
new_proc->heap_end = 0x20000000;
|
||||
new_proc->is_terminal_proc = false;
|
||||
|
||||
// 2. Load ELF executable
|
||||
uint64_t entry_point = elf_load(filepath, new_proc->pml4_phys);
|
||||
|
|
@ -129,21 +130,23 @@ void process_create_elf(const char* filepath, const char* args_str) {
|
|||
serial_write(filepath);
|
||||
serial_write("\n");
|
||||
// We technically leak the page table here, but let's ignore cleanup for now
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 3. Allocate generic User stack and Kernel stack for interrupts
|
||||
void* stack = kmalloc_aligned(4096, 4096);
|
||||
void* kernel_stack = kmalloc_aligned(16384, 16384);
|
||||
void* stack = kmalloc_aligned(2097152, 4096); // 2MB for user apps
|
||||
void* kernel_stack = kmalloc_aligned(126976, 16384); // 128KB for interrupts
|
||||
|
||||
// Map User stack to 0x800000
|
||||
paging_map_page(new_proc->pml4_phys, 0x800000, v2p((uint64_t)stack), PT_PRESENT | PT_RW | PT_USER);
|
||||
// Map User stack to 0x800000 (starting from 0x600000 for 2MB)
|
||||
for (uint64_t i = 0; i < 512; i++) {
|
||||
paging_map_page(new_proc->pml4_phys, 0x800000 - 2097152 + (i * 4096), v2p((uint64_t)stack + (i * 4096)), PT_PRESENT | PT_RW | PT_USER);
|
||||
}
|
||||
|
||||
// Parse arguments and push them to the user stack
|
||||
// We'll place the strings at the very high end of the user stack
|
||||
int argc = 1;
|
||||
char *args_buf = (char *)stack + 4096;
|
||||
uint64_t user_args_buf = 0x800000 + 4096;
|
||||
char *args_buf = (char *)stack + 2097152;
|
||||
uint64_t user_args_buf = 0x800000;
|
||||
|
||||
// Copy filepath as argv[0]
|
||||
int path_len = 0;
|
||||
|
|
@ -194,7 +197,7 @@ void process_create_elf(const char* filepath, const char* args_str) {
|
|||
// Align stack to 8 bytes before pushing argv array
|
||||
uint64_t current_user_sp = user_args_buf;
|
||||
current_user_sp &= ~7ULL;
|
||||
args_buf = (char *)((uint64_t)stack + (current_user_sp - 0x800000));
|
||||
args_buf = (char *)((uint64_t)stack + (current_user_sp - (0x800000 - 2097152)));
|
||||
|
||||
// Push argv array
|
||||
int argv_size = (argc + 1) * sizeof(uint64_t);
|
||||
|
|
@ -212,7 +215,7 @@ void process_create_elf(const char* filepath, const char* args_str) {
|
|||
current_user_sp &= ~15ULL;
|
||||
|
||||
// 4. Build Stack Frame for context switch via IRETQ
|
||||
uint64_t* stack_ptr = (uint64_t*)((uint64_t)kernel_stack + 16384);
|
||||
uint64_t* stack_ptr = (uint64_t*)((uint64_t)kernel_stack + 126976);
|
||||
*(--stack_ptr) = 0x1B; // SS (User Mode Data)
|
||||
*(--stack_ptr) = current_user_sp; // RSP (Updated user stack pointer)
|
||||
*(--stack_ptr) = 0x202; // RFLAGS (Interrupts Enabled)
|
||||
|
|
@ -253,6 +256,7 @@ void process_create_elf(const char* filepath, const char* args_str) {
|
|||
serial_write("[PROCESS] Spawned ELF Executable: ");
|
||||
serial_write(filepath);
|
||||
serial_write("\n");
|
||||
return new_proc;
|
||||
}
|
||||
|
||||
process_t* process_get_current(void) {
|
||||
|
|
@ -288,7 +292,7 @@ uint64_t process_terminate_current(void) {
|
|||
if (!current_process) return 0;
|
||||
|
||||
// 1. Cleanup side effects
|
||||
if (current_process->ui_window) {
|
||||
if (current_process->ui_window && !current_process->is_terminal_proc) {
|
||||
extern void serial_write(const char *str);
|
||||
serial_write("PROC: Terminating proc with window\n");
|
||||
wm_remove_window((Window *)current_process->ui_window);
|
||||
|
|
|
|||
|
|
@ -38,12 +38,14 @@ typedef struct process {
|
|||
void *kernel_stack_alloc; // Original pointer from kmalloc for freeing
|
||||
void *user_stack_alloc; // Original pointer from kmalloc for freeing
|
||||
|
||||
bool is_terminal_proc; // Was this process started from the shell?
|
||||
|
||||
struct process *next;
|
||||
} process_t;
|
||||
|
||||
void process_init(void);
|
||||
void process_create(void* entry_point, bool is_user);
|
||||
void process_create_elf(const char* filepath, const char* args_str);
|
||||
process_t* process_create_elf(const char* filepath, const char* args_str);
|
||||
process_t* process_get_current(void);
|
||||
uint64_t process_schedule(uint64_t current_rsp);
|
||||
uint64_t process_terminate_current(void);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ uint64_t timer_handler(registers_t *regs) {
|
|||
|
||||
// --- Keyboard ---
|
||||
static bool shift_pressed = false;
|
||||
static bool ctrl_pressed = false;
|
||||
static bool extended_scancode = false;
|
||||
|
||||
// Simple US QWERTY Scan Code Set 1 Map
|
||||
|
|
@ -50,6 +51,27 @@ uint64_t keyboard_handler(registers_t *regs) {
|
|||
return (uint64_t)regs;
|
||||
}
|
||||
|
||||
if (scancode == 0x1D) {
|
||||
ctrl_pressed = true;
|
||||
extended_scancode = false; // Reset if Ctrl is pressed (prevents E0 1D bug)
|
||||
} else if (scancode == 0x9D) {
|
||||
ctrl_pressed = false;
|
||||
extended_scancode = false;
|
||||
}
|
||||
|
||||
if (ctrl_pressed && scancode == 0x2E) {
|
||||
extern process_t* process_get_current(void);
|
||||
process_t* proc = process_get_current();
|
||||
if (proc && proc->is_user && proc->is_terminal_proc && proc->ui_window) {
|
||||
// Only kill if the associated terminal window is focused
|
||||
if (((Window*)proc->ui_window)->focused) {
|
||||
extern uint64_t process_terminate_current(void);
|
||||
outb(0x20, 0x20); // EOI before context switch
|
||||
return process_terminate_current();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (scancode == 0x2A || scancode == 0x36) { // Shift Down
|
||||
shift_pressed = true;
|
||||
} else if (scancode == 0xAA || scancode == 0xB6) { // Shift Up
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@
|
|||
#include "fat32.h"
|
||||
#include "paging.h"
|
||||
#include "platform.h"
|
||||
#include "io.h"
|
||||
#include "pci.h"
|
||||
#include "kutils.h"
|
||||
|
||||
// Read MSR
|
||||
static inline uint64_t rdmsr(uint32_t msr) {
|
||||
|
|
@ -130,7 +133,6 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
|
|||
if (syscall_num == 1) { // SYS_WRITE
|
||||
// arg2 is the buffer based on our user_test logic
|
||||
cmd_write((const char*)arg2);
|
||||
serial_write((const char*)arg2);
|
||||
} else if (syscall_num == 0 || syscall_num == 60) { // SYS_EXIT
|
||||
serial_write("Kernel: SYS_EXIT called\n");
|
||||
uint64_t next_rsp = process_terminate_current();
|
||||
|
|
@ -478,12 +480,28 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
|
|||
const char *path = (const char *)arg2;
|
||||
if (!path) return 0;
|
||||
return fat32_exists(path) ? 1 : 0;
|
||||
} else if (cmd == FS_CMD_GETCWD) {
|
||||
char *buf = (char *)arg2;
|
||||
int size = (int)arg3;
|
||||
if (!buf) return -1;
|
||||
fat32_get_current_dir(buf, size);
|
||||
return 0;
|
||||
} else if (cmd == FS_CMD_CHDIR) {
|
||||
const char *path = (const char *)arg2;
|
||||
if (!path) return -1;
|
||||
return fat32_chdir(path) ? 0 : -1;
|
||||
}
|
||||
return 0;
|
||||
} else if (syscall_num == 8) { // DEBUG_SERIAL_WRITE
|
||||
extern void serial_write(const char *str);
|
||||
serial_write((const char *)arg2);
|
||||
return 0;
|
||||
} else if (syscall_num == 10) { // SYS_KILL
|
||||
// Simplified kill: just terminate current for now
|
||||
uint64_t next_rsp = process_terminate_current();
|
||||
extern void context_switch_to(uint64_t rsp);
|
||||
context_switch_to(next_rsp);
|
||||
while(1);
|
||||
} else if (syscall_num == 9) { // SYS_SBRK
|
||||
int incr = (int)arg1;
|
||||
process_t *proc = process_get_current();
|
||||
|
|
@ -591,6 +609,68 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u
|
|||
if (!thumb) return -1;
|
||||
for (int i=0; i<100*60; i++) dest[i] = thumb[i];
|
||||
return 0;
|
||||
} else if (cmd == 10) { // SYSTEM_CMD_CLEAR_SCREEN
|
||||
extern void cmd_screen_clear(void);
|
||||
cmd_screen_clear();
|
||||
return 0;
|
||||
} else if (cmd == 11) { // SYSTEM_CMD_RTC_GET
|
||||
int *dt = (int *)arg2;
|
||||
if (!dt) return -1;
|
||||
extern void rtc_get_datetime(int *y, int *m, int *d, int *h, int *min, int *s);
|
||||
rtc_get_datetime(&dt[0], &dt[1], &dt[2], &dt[3], &dt[4], &dt[5]);
|
||||
return 0;
|
||||
} else if (cmd == 12) { // SYSTEM_CMD_REBOOT
|
||||
k_reboot();
|
||||
return 0;
|
||||
} else if (cmd == 13) { // SYSTEM_CMD_SHUTDOWN
|
||||
k_shutdown();
|
||||
return 0;
|
||||
} else if (cmd == 14) { // SYSTEM_CMD_BEEP
|
||||
int freq = (int)arg2;
|
||||
int ms = (int)arg3;
|
||||
if (freq > 0) {
|
||||
int div = 1193180 / freq;
|
||||
outb(0x43, 0xB6);
|
||||
outb(0x42, div & 0xFF);
|
||||
outb(0x42, (div >> 8) & 0xFF);
|
||||
outb(0x61, inb(0x61) | 0x03);
|
||||
}
|
||||
// Sleep - kernel side
|
||||
k_sleep(ms);
|
||||
outb(0x61, inb(0x61) & 0xFC);
|
||||
return 0;
|
||||
} else if (cmd == 15) { // SYSTEM_CMD_MEMINFO
|
||||
uint64_t *out = (uint64_t *)arg2;
|
||||
if (!out) return -1;
|
||||
MemStats stats = memory_get_stats();
|
||||
out[0] = stats.total_memory;
|
||||
out[1] = stats.used_memory;
|
||||
return 0;
|
||||
} else if (cmd == 16) { // SYSTEM_CMD_UPTIME
|
||||
return wm_get_ticks();
|
||||
} else if (cmd == 17) { // SYSTEM_CMD_PCI_LIST
|
||||
typedef struct {
|
||||
uint16_t vendor;
|
||||
uint16_t device;
|
||||
uint8_t class_code;
|
||||
uint8_t subclass;
|
||||
} pci_info_t;
|
||||
pci_info_t *info = (pci_info_t *)arg2;
|
||||
int idx = (int)arg3;
|
||||
if (!info) {
|
||||
pci_device_t pci_devs[128];
|
||||
return pci_enumerate_devices(pci_devs, 128);
|
||||
}
|
||||
pci_device_t pci_devs[128];
|
||||
int count = pci_enumerate_devices(pci_devs, 128);
|
||||
if (idx >= 0 && idx < count) {
|
||||
info->vendor = pci_devs[idx].vendor_id;
|
||||
info->device = pci_devs[idx].device_id;
|
||||
info->class_code = pci_devs[idx].class_code;
|
||||
info->subclass = pci_devs[idx].subclass;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ typedef struct Window Window;
|
|||
#define FS_CMD_SIZE 9
|
||||
#define FS_CMD_MKDIR 10
|
||||
#define FS_CMD_EXISTS 11
|
||||
#define FS_CMD_GETCWD 12
|
||||
#define FS_CMD_CHDIR 13
|
||||
|
||||
void syscall_init(void);
|
||||
uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5);
|
||||
|
|
|
|||
|
|
@ -48,7 +48,9 @@ syscall_entry:
|
|||
mov rdi, rax ; syscall_num
|
||||
|
||||
; 5. Call C handler
|
||||
sti
|
||||
call syscall_handler_c
|
||||
cli
|
||||
|
||||
; 6. Restore RCX and R11
|
||||
pop r11
|
||||
|
|
|
|||
|
|
@ -5,29 +5,36 @@ LD = x86_64-elf-ld
|
|||
CFLAGS = -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc
|
||||
LDFLAGS = -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start
|
||||
|
||||
BIN_DIR = bin
|
||||
|
||||
LIBC_SOURCES = $(wildcard libc/*.c)
|
||||
LIBC_OBJS = $(LIBC_SOURCES:.c=.o) crt0.o
|
||||
LIBC_OBJS = $(patsubst libc/%.c, $(BIN_DIR)/%.o, $(LIBC_SOURCES)) $(BIN_DIR)/crt0.o
|
||||
|
||||
APP_SOURCES = $(filter-out nanojpeg.c, $(wildcard *.c))
|
||||
APP_OBJS = $(APP_SOURCES:.c=.o)
|
||||
APP_ELFS = $(APP_SOURCES:.c=.elf)
|
||||
APP_ELFS = $(patsubst %.c, $(BIN_DIR)/%.elf, $(APP_SOURCES))
|
||||
|
||||
all: $(APP_ELFS)
|
||||
all: $(BIN_DIR) $(APP_ELFS)
|
||||
|
||||
crt0.o: crt0.asm
|
||||
$(BIN_DIR):
|
||||
mkdir -p $(BIN_DIR)
|
||||
|
||||
$(BIN_DIR)/crt0.o: crt0.asm
|
||||
$(AS) -f elf64 $< -o $@
|
||||
|
||||
libc/%.o: libc/%.c
|
||||
$(BIN_DIR)/%.o: libc/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
%.o: %.c
|
||||
$(BIN_DIR)/nanojpeg.o: nanojpeg.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
viewer.elf: $(LIBC_OBJS) viewer.o nanojpeg.o
|
||||
$(BIN_DIR)/%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BIN_DIR)/viewer.elf: $(LIBC_OBJS) $(BIN_DIR)/viewer.o $(BIN_DIR)/nanojpeg.o
|
||||
$(LD) $(LDFLAGS) $^ -o $@
|
||||
|
||||
%.elf: $(LIBC_OBJS) %.o
|
||||
$(BIN_DIR)/%.elf: $(LIBC_OBJS) $(BIN_DIR)/%.o
|
||||
$(LD) $(LDFLAGS) $^ -o $@
|
||||
|
||||
clean:
|
||||
rm -f *.o libc/*.o *.elf
|
||||
rm -rf $(BIN_DIR)
|
||||
|
|
|
|||
9
src/kernel/userland/beep.c
Normal file
9
src/kernel/userland/beep.c
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc; (void)argv;
|
||||
printf("BEEP!\n");
|
||||
sys_system(14, 1000, 100, 0, 0); // SYSTEM_CMD_BEEP (freq, ms)
|
||||
return 0;
|
||||
}
|
||||
9
src/kernel/userland/boredver.c
Normal file
9
src/kernel/userland/boredver.c
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc; (void)argv;
|
||||
printf("BoredOS v1.64\n");
|
||||
printf("BoredOS Kernel V3.0.0\n");
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
24
src/kernel/userland/cat.c
Normal file
24
src/kernel/userland/cat.c
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
printf("Usage: cat <filename>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fd = sys_open(argv[1], "r");
|
||||
if (fd < 0) {
|
||||
printf("Error: Cannot open %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char buffer[4096];
|
||||
int bytes;
|
||||
while ((bytes = sys_read(fd, buffer, sizeof(buffer))) > 0) {
|
||||
sys_write(1, buffer, bytes);
|
||||
}
|
||||
|
||||
sys_close(fd);
|
||||
return 0;
|
||||
}
|
||||
519
src/kernel/userland/cc.c
Normal file
519
src/kernel/userland/cc.c
Normal file
|
|
@ -0,0 +1,519 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
#include "../vm.h"
|
||||
|
||||
// --- Compiler Limits ---
|
||||
#define MAX_SOURCE 65536
|
||||
#define MAX_TOKENS 16384
|
||||
#define MAX_VARS 512
|
||||
#define CODE_SIZE 32768
|
||||
#define STR_POOL_SIZE 16384
|
||||
|
||||
static int compile_error = 0;
|
||||
|
||||
// --- Lexer ---
|
||||
typedef enum {
|
||||
TOK_EOF,
|
||||
TOK_INT, // 123, 0xFF
|
||||
TOK_STRING, // "hello"
|
||||
TOK_ID, // abc
|
||||
TOK_PLUS, // +
|
||||
TOK_MINUS, // -
|
||||
TOK_MUL, // *
|
||||
TOK_DIV, // /
|
||||
TOK_ASSIGN, // =
|
||||
TOK_LPAREN, // (
|
||||
TOK_RPAREN, // )
|
||||
TOK_LBRACKET, // [
|
||||
TOK_RBRACKET, // ]
|
||||
TOK_LBRACE, // {
|
||||
TOK_RBRACE, // }
|
||||
TOK_SEMI, // ;
|
||||
TOK_COMMA, // ,
|
||||
TOK_EQ, // ==
|
||||
TOK_NEQ, // !=
|
||||
TOK_LT, // <
|
||||
TOK_GT, // >
|
||||
TOK_LE, // <=
|
||||
TOK_GE, // >=
|
||||
TOK_IF, // if
|
||||
TOK_ELSE, // else
|
||||
TOK_WHILE, // while
|
||||
TOK_INT_TYPE, // int
|
||||
TOK_CHAR_TYPE,// char
|
||||
TOK_VOID_TYPE,// void
|
||||
TOK_MAIN // main
|
||||
} TokenType;
|
||||
|
||||
typedef struct {
|
||||
TokenType type;
|
||||
int int_val;
|
||||
char str_val[64]; // Identifier or String Content
|
||||
} Token;
|
||||
|
||||
static char *source_ptr;
|
||||
static Token tokens[MAX_TOKENS];
|
||||
static int token_count = 0;
|
||||
|
||||
static void lex_error(const char *msg) {
|
||||
printf("Compiler Error: %s\n", msg);
|
||||
compile_error = 1;
|
||||
}
|
||||
|
||||
static void lexer(const char *source) {
|
||||
source_ptr = (char*)source;
|
||||
token_count = 0;
|
||||
compile_error = 0;
|
||||
|
||||
while (*source_ptr) {
|
||||
while (*source_ptr == ' ' || *source_ptr == '\n' || *source_ptr == '\t' || *source_ptr == '\r') source_ptr++;
|
||||
if (!*source_ptr) break;
|
||||
|
||||
if (*source_ptr == '/' && *(source_ptr+1) == '/') {
|
||||
while (*source_ptr && *source_ptr != '\n') source_ptr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
Token *t = &tokens[token_count++];
|
||||
|
||||
if (*source_ptr == '0' && (*(source_ptr+1) == 'x' || *(source_ptr+1) == 'X')) {
|
||||
source_ptr += 2;
|
||||
t->type = TOK_INT;
|
||||
t->int_val = 0;
|
||||
int has_digits = 0;
|
||||
while ((*source_ptr >= '0' && *source_ptr <= '9') ||
|
||||
(*source_ptr >= 'a' && *source_ptr <= 'f') ||
|
||||
(*source_ptr >= 'A' && *source_ptr <= 'F')) {
|
||||
int digit = 0;
|
||||
if (*source_ptr >= '0' && *source_ptr <= '9') digit = *source_ptr - '0';
|
||||
else if (*source_ptr >= 'a' && *source_ptr <= 'f') digit = *source_ptr - 'a' + 10;
|
||||
else if (*source_ptr >= 'A' && *source_ptr <= 'F') digit = *source_ptr - 'A' + 10;
|
||||
t->int_val = (t->int_val << 4) | digit;
|
||||
source_ptr++;
|
||||
has_digits = 1;
|
||||
}
|
||||
if (!has_digits) { lex_error("Invalid hex literal"); return; }
|
||||
} else if (*source_ptr >= '0' && *source_ptr <= '9') {
|
||||
t->type = TOK_INT;
|
||||
t->int_val = 0;
|
||||
while (*source_ptr >= '0' && *source_ptr <= '9') {
|
||||
t->int_val = t->int_val * 10 + (*source_ptr - '0');
|
||||
source_ptr++;
|
||||
}
|
||||
} else if (*source_ptr == '"') {
|
||||
t->type = TOK_STRING;
|
||||
source_ptr++;
|
||||
int len = 0;
|
||||
while (*source_ptr && *source_ptr != '"') {
|
||||
if (*source_ptr == '\\' && *(source_ptr+1) == 'n') {
|
||||
if (len < 63) t->str_val[len++] = '\n';
|
||||
source_ptr += 2;
|
||||
} else {
|
||||
if (len < 63) t->str_val[len++] = *source_ptr;
|
||||
source_ptr++;
|
||||
}
|
||||
}
|
||||
t->str_val[len] = 0;
|
||||
if (*source_ptr == '"') source_ptr++;
|
||||
} else if (*source_ptr == '\'') {
|
||||
t->type = TOK_INT;
|
||||
source_ptr++;
|
||||
char c = 0;
|
||||
if (*source_ptr == '\\') {
|
||||
source_ptr++;
|
||||
if (*source_ptr == 'n') c = '\n';
|
||||
else if (*source_ptr == 't') c = '\t';
|
||||
else if (*source_ptr == '0') c = '\0';
|
||||
else if (*source_ptr == '\\') c = '\\';
|
||||
else if (*source_ptr == '\'') c = '\'';
|
||||
else c = *source_ptr;
|
||||
source_ptr++;
|
||||
} else {
|
||||
c = *source_ptr;
|
||||
source_ptr++;
|
||||
}
|
||||
if (*source_ptr == '\'') source_ptr++;
|
||||
else { lex_error("Expected closing '"); return; }
|
||||
t->int_val = (int)c;
|
||||
} else if ((*source_ptr >= 'a' && *source_ptr <= 'z') || (*source_ptr >= 'A' && *source_ptr <= 'Z') || *source_ptr == '_') {
|
||||
int len = 0;
|
||||
while ((*source_ptr >= 'a' && *source_ptr <= 'z') || (*source_ptr >= 'A' && *source_ptr <= 'Z') || (*source_ptr >= '0' && *source_ptr <= '9') || *source_ptr == '_') {
|
||||
if (len < 63) t->str_val[len++] = *source_ptr;
|
||||
source_ptr++;
|
||||
}
|
||||
t->str_val[len] = 0;
|
||||
if (strcmp(t->str_val, "if") == 0) t->type = TOK_IF;
|
||||
else if (strcmp(t->str_val, "else") == 0) t->type = TOK_ELSE;
|
||||
else if (strcmp(t->str_val, "while") == 0) t->type = TOK_WHILE;
|
||||
else if (strcmp(t->str_val, "int") == 0) t->type = TOK_INT_TYPE;
|
||||
else if (strcmp(t->str_val, "char") == 0) t->type = TOK_CHAR_TYPE;
|
||||
else if (strcmp(t->str_val, "void") == 0) t->type = TOK_VOID_TYPE;
|
||||
else if (strcmp(t->str_val, "main") == 0) t->type = TOK_MAIN;
|
||||
else t->type = TOK_ID;
|
||||
} else {
|
||||
switch (*source_ptr) {
|
||||
case '+': t->type = TOK_PLUS; break;
|
||||
case '-': t->type = TOK_MINUS; break;
|
||||
case '*': t->type = TOK_MUL; break;
|
||||
case '/': t->type = TOK_DIV; break;
|
||||
case '(': t->type = TOK_LPAREN; break;
|
||||
case ')': t->type = TOK_RPAREN; break;
|
||||
case '[': t->type = TOK_LBRACKET; break;
|
||||
case ']': t->type = TOK_RBRACKET; break;
|
||||
case '{': t->type = TOK_LBRACE; break;
|
||||
case '}': t->type = TOK_RBRACE; break;
|
||||
case ';': t->type = TOK_SEMI; break;
|
||||
case ',': t->type = TOK_COMMA; break;
|
||||
case '=':
|
||||
if (*(source_ptr+1) == '=') { t->type = TOK_EQ; source_ptr++; }
|
||||
else t->type = TOK_ASSIGN;
|
||||
break;
|
||||
case '!':
|
||||
if (*(source_ptr+1) == '=') { t->type = TOK_NEQ; source_ptr++; }
|
||||
else { lex_error("Unexpected !"); return; }
|
||||
break;
|
||||
case '<':
|
||||
if (*(source_ptr+1) == '=') { t->type = TOK_LE; source_ptr++; }
|
||||
else t->type = TOK_LT;
|
||||
break;
|
||||
case '>':
|
||||
if (*(source_ptr+1) == '=') { t->type = TOK_GE; source_ptr++; }
|
||||
else t->type = TOK_GT;
|
||||
break;
|
||||
default: lex_error("Unknown char"); return;
|
||||
}
|
||||
source_ptr++;
|
||||
}
|
||||
}
|
||||
tokens[token_count].type = TOK_EOF;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
int syscall_id;
|
||||
} Builtin;
|
||||
|
||||
static const Builtin builtins[] = {
|
||||
{"exit", VM_SYS_EXIT},
|
||||
{"print_int", VM_SYS_PRINT_INT},
|
||||
{"print_char", VM_SYS_PRINT_CHAR},
|
||||
{"print_str", VM_SYS_PRINT_STR},
|
||||
{"print", VM_SYS_PRINT_INT},
|
||||
{"pritc", VM_SYS_PRINT_CHAR},
|
||||
{"puts", VM_SYS_PRINT_STR},
|
||||
{"nl", VM_SYS_NL},
|
||||
{"cls", VM_SYS_CLS},
|
||||
{"getchar", VM_SYS_GETCHAR},
|
||||
{"strlen", VM_SYS_STRLEN},
|
||||
{"strcmp", VM_SYS_STRCMP},
|
||||
{"strcpy", VM_SYS_STRCPY},
|
||||
{"strcat", VM_SYS_STRCAT},
|
||||
{"memset", VM_SYS_MEMSET},
|
||||
{"memcpy", VM_SYS_MEMCPY},
|
||||
{"malloc", VM_SYS_MALLOC},
|
||||
{"free", VM_SYS_FREE},
|
||||
{"rand", VM_SYS_RAND},
|
||||
{"srand", VM_SYS_SRAND},
|
||||
{"abs", VM_SYS_ABS},
|
||||
{"min", VM_SYS_MIN},
|
||||
{"max", VM_SYS_MAX},
|
||||
{"pow", VM_SYS_POW},
|
||||
{"sqrt", VM_SYS_SQRT},
|
||||
{"sleep", VM_SYS_SLEEP},
|
||||
{"fopen", VM_SYS_FOPEN},
|
||||
{"fclose", VM_SYS_FCLOSE},
|
||||
{"fread", VM_SYS_FREAD},
|
||||
{"fwrite", VM_SYS_FWRITE},
|
||||
{"fseek", VM_SYS_FSEEK},
|
||||
{"remove", VM_SYS_REMOVE},
|
||||
{"draw_pixel", VM_SYS_DRAW_PIXEL},
|
||||
{"draw_rect", VM_SYS_DRAW_RECT},
|
||||
{"draw_line", VM_SYS_DRAW_LINE},
|
||||
{"draw_text", VM_SYS_DRAW_TEXT},
|
||||
{"get_width", VM_SYS_GET_WIDTH},
|
||||
{"get_height", VM_SYS_GET_HEIGHT},
|
||||
{"get_time", VM_SYS_GET_TIME},
|
||||
{"kb_hit", VM_SYS_KB_HIT},
|
||||
{"mouse_x", VM_SYS_MOUSE_X},
|
||||
{"mouse_y", VM_SYS_MOUSE_Y},
|
||||
{"mouse_state", VM_SYS_MOUSE_STATE},
|
||||
{"play_sound", VM_SYS_PLAY_SOUND},
|
||||
{"atoi", VM_SYS_ATOI},
|
||||
{"itoa", VM_SYS_ITOA},
|
||||
{"peek", VM_SYS_PEEK},
|
||||
{"poke", VM_SYS_POKE},
|
||||
{"exec", VM_SYS_EXEC},
|
||||
{"system", VM_SYS_SYSTEM},
|
||||
{"strchr", VM_SYS_STRCHR},
|
||||
{"memcmp", VM_SYS_MEMCMP},
|
||||
{"isalnum", VM_SYS_ISALNUM},
|
||||
{"isalpha", VM_SYS_ISALPHA},
|
||||
{"isdigit", VM_SYS_ISDIGIT},
|
||||
{"tolower", VM_SYS_TOLOWER},
|
||||
{"toupper", VM_SYS_TOUPPER},
|
||||
{"strncpy", VM_SYS_STRNCPY},
|
||||
{"strncat", VM_SYS_STRNCAT},
|
||||
{"strncmp", VM_SYS_STRNCMP},
|
||||
{"strstr", VM_SYS_STRSTR},
|
||||
{"strrchr", VM_SYS_STRRCHR},
|
||||
{"memmove", VM_SYS_MEMMOVE},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
static int find_builtin(const char *name) {
|
||||
for (int i = 0; builtins[i].name != NULL; i++) {
|
||||
if (strcmp(builtins[i].name, name) == 0) return builtins[i].syscall_id;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static uint8_t code[CODE_SIZE];
|
||||
static int code_pos = 0;
|
||||
static int cur_token = 0;
|
||||
static uint8_t str_pool[STR_POOL_SIZE];
|
||||
static int str_pool_pos = 0;
|
||||
|
||||
typedef struct {
|
||||
char name[32];
|
||||
int addr;
|
||||
} Symbol;
|
||||
|
||||
static Symbol symbols[MAX_VARS];
|
||||
static int symbol_count = 0;
|
||||
static int next_var_addr = 32768;
|
||||
|
||||
static int find_symbol(const char *name) {
|
||||
for (int i = 0; i < symbol_count; i++) {
|
||||
if (strcmp(symbols[i].name, name) == 0) return symbols[i].addr;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int add_symbol(const char *name) {
|
||||
int existing = find_symbol(name);
|
||||
if (existing != -1) return existing;
|
||||
if (symbol_count >= MAX_VARS) return -1;
|
||||
strcpy(symbols[symbol_count].name, name);
|
||||
symbols[symbol_count].addr = next_var_addr;
|
||||
next_var_addr += 4;
|
||||
return symbol_count++;
|
||||
}
|
||||
|
||||
static void emit(uint8_t b) {
|
||||
if (code_pos < CODE_SIZE) code[code_pos++] = b;
|
||||
else { printf("Error: Code buffer overflow\n"); compile_error = 1; }
|
||||
}
|
||||
|
||||
static void emit32(int v) {
|
||||
emit(v & 0xFF); emit((v >> 8) & 0xFF); emit((v >> 16) & 0xFF); emit((v >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
static int add_string(const char *str) {
|
||||
int start = str_pool_pos;
|
||||
int len = strlen(str);
|
||||
if (str_pool_pos + len + 1 >= STR_POOL_SIZE) { printf("Error: String pool overflow\n"); compile_error = 1; return 0; }
|
||||
for(int i=0; i<len; i++) str_pool[str_pool_pos++] = str[i];
|
||||
str_pool[str_pool_pos++] = 0;
|
||||
return start;
|
||||
}
|
||||
|
||||
static void match(TokenType t) {
|
||||
if (compile_error) return;
|
||||
if (tokens[cur_token].type == t) cur_token++;
|
||||
else { printf("Syntax Error: Expected token %d got %d\n", t, tokens[cur_token].type); compile_error = 1; }
|
||||
}
|
||||
|
||||
static void expression();
|
||||
static void statement();
|
||||
static void block();
|
||||
|
||||
static void function_call(int syscall_id) {
|
||||
if (compile_error) return;
|
||||
cur_token++;
|
||||
match(TOK_LPAREN);
|
||||
if (tokens[cur_token].type != TOK_RPAREN) {
|
||||
expression();
|
||||
while (tokens[cur_token].type == TOK_COMMA) { cur_token++; expression(); }
|
||||
}
|
||||
match(TOK_RPAREN);
|
||||
emit(OP_SYSCALL);
|
||||
emit32(syscall_id);
|
||||
}
|
||||
|
||||
static void factor() {
|
||||
if (compile_error) return;
|
||||
if (tokens[cur_token].type == TOK_INT) { emit(OP_IMM); emit32(tokens[cur_token].int_val); cur_token++; }
|
||||
else if (tokens[cur_token].type == TOK_STRING) { int offset = add_string(tokens[cur_token].str_val); emit(OP_PUSH_PTR); emit32(offset); cur_token++; }
|
||||
else if (tokens[cur_token].type == TOK_ID) {
|
||||
int syscall = find_builtin(tokens[cur_token].str_val);
|
||||
if (syscall != -1 && tokens[cur_token+1].type == TOK_LPAREN) function_call(syscall);
|
||||
else {
|
||||
int addr = find_symbol(tokens[cur_token].str_val);
|
||||
if (addr == -1) { printf("Error: Undefined variable: %s\n", tokens[cur_token].str_val); compile_error = 1; }
|
||||
emit(OP_LOAD); emit32(addr); cur_token++;
|
||||
}
|
||||
} else if (tokens[cur_token].type == TOK_LPAREN) { cur_token++; expression(); match(TOK_RPAREN); }
|
||||
else { printf("Syntax Error: Unexpected token in factor\n"); compile_error = 1; }
|
||||
}
|
||||
|
||||
static void term() {
|
||||
if (compile_error) return;
|
||||
factor();
|
||||
while (tokens[cur_token].type == TOK_MUL || tokens[cur_token].type == TOK_DIV) {
|
||||
TokenType op = tokens[cur_token].type; cur_token++; factor();
|
||||
if (op == TOK_MUL) emit(OP_MUL); else emit(OP_DIV);
|
||||
}
|
||||
}
|
||||
|
||||
static void additive() {
|
||||
if (compile_error) return;
|
||||
term();
|
||||
while (tokens[cur_token].type == TOK_PLUS || tokens[cur_token].type == TOK_MINUS) {
|
||||
TokenType op = tokens[cur_token].type; cur_token++; term();
|
||||
if (op == TOK_PLUS) emit(OP_ADD); else emit(OP_SUB);
|
||||
}
|
||||
}
|
||||
|
||||
static void relation() {
|
||||
if (compile_error) return;
|
||||
additive();
|
||||
if (tokens[cur_token].type >= TOK_EQ && tokens[cur_token].type <= TOK_GE) {
|
||||
TokenType op = tokens[cur_token].type; cur_token++; additive();
|
||||
switch (op) {
|
||||
case TOK_EQ: emit(OP_EQ); break;
|
||||
case TOK_NEQ: emit(OP_NEQ); break;
|
||||
case TOK_LT: emit(OP_LT); break;
|
||||
case TOK_GT: emit(OP_GT); break;
|
||||
case TOK_LE: emit(OP_LE); break;
|
||||
case TOK_GE: emit(OP_GE); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void expression() { if (compile_error) return; relation(); }
|
||||
|
||||
static void statement() {
|
||||
if (compile_error) return;
|
||||
if (tokens[cur_token].type == TOK_INT_TYPE || tokens[cur_token].type == TOK_CHAR_TYPE) {
|
||||
cur_token++;
|
||||
while (tokens[cur_token].type == TOK_MUL) cur_token++;
|
||||
if (tokens[cur_token].type == TOK_ID) {
|
||||
add_symbol(tokens[cur_token].str_val);
|
||||
cur_token++;
|
||||
if (tokens[cur_token].type == TOK_LBRACKET) {
|
||||
cur_token++; if (tokens[cur_token].type == TOK_INT) cur_token++;
|
||||
if (tokens[cur_token].type == TOK_RBRACKET) cur_token++;
|
||||
else printf("Error: Expected ]\n");
|
||||
}
|
||||
if (tokens[cur_token].type == TOK_ASSIGN) {
|
||||
int addr = find_symbol(tokens[cur_token-1].str_val);
|
||||
cur_token++; expression(); emit(OP_STORE); emit32(addr);
|
||||
}
|
||||
match(TOK_SEMI);
|
||||
} else { printf("Syntax Error: Expected identifier\n"); compile_error = 1; }
|
||||
} else if (tokens[cur_token].type == TOK_ID) {
|
||||
int syscall = find_builtin(tokens[cur_token].str_val);
|
||||
if (syscall != -1 && tokens[cur_token+1].type == TOK_LPAREN) {
|
||||
function_call(syscall); match(TOK_SEMI); emit(OP_POP);
|
||||
} else {
|
||||
int addr = find_symbol(tokens[cur_token].str_val);
|
||||
if (addr == -1) { printf("Error: Undefined variable assignment: %s\n", tokens[cur_token].str_val); compile_error = 1; return; }
|
||||
cur_token++; match(TOK_ASSIGN); expression(); match(TOK_SEMI); emit(OP_STORE); emit32(addr);
|
||||
}
|
||||
} else if (tokens[cur_token].type == TOK_IF) {
|
||||
cur_token++; match(TOK_LPAREN); expression(); match(TOK_RPAREN);
|
||||
emit(OP_JZ); int jz_addr_pos = code_pos; emit32(0); block();
|
||||
if (tokens[cur_token].type == TOK_ELSE) {
|
||||
emit(OP_JMP); int jmp_addr_pos = code_pos; emit32(0);
|
||||
int else_start = code_pos;
|
||||
code[jz_addr_pos] = else_start & 0xFF; code[jz_addr_pos+1] = (else_start >> 8) & 0xFF; code[jz_addr_pos+2] = (else_start >> 16) & 0xFF; code[jz_addr_pos+3] = (else_start >> 24) & 0xFF;
|
||||
cur_token++; block();
|
||||
int end_addr = code_pos;
|
||||
code[jmp_addr_pos] = end_addr & 0xFF; code[jmp_addr_pos+1] = (end_addr >> 8) & 0xFF; code[jmp_addr_pos+2] = (end_addr >> 16) & 0xFF; code[jmp_addr_pos+3] = (end_addr >> 24) & 0xFF;
|
||||
} else {
|
||||
int end_addr = code_pos;
|
||||
code[jz_addr_pos] = end_addr & 0xFF; code[jz_addr_pos+1] = (end_addr >> 8) & 0xFF; code[jz_addr_pos+2] = (end_addr >> 16) & 0xFF; code[jz_addr_pos+3] = (end_addr >> 24) & 0xFF;
|
||||
}
|
||||
} else if (tokens[cur_token].type == TOK_WHILE) {
|
||||
int start_addr = code_pos; cur_token++; match(TOK_LPAREN); expression(); match(TOK_RPAREN);
|
||||
emit(OP_JZ); int jz_addr_pos = code_pos; emit32(0); block();
|
||||
emit(OP_JMP); emit32(start_addr);
|
||||
int end_addr = code_pos;
|
||||
code[jz_addr_pos] = end_addr & 0xFF; code[jz_addr_pos+1] = (end_addr >> 8) & 0xFF; code[jz_addr_pos+2] = (end_addr >> 16) & 0xFF; code[jz_addr_pos+3] = (end_addr >> 24) & 0xFF;
|
||||
} else cur_token++;
|
||||
}
|
||||
|
||||
static void block() {
|
||||
if (compile_error) return;
|
||||
match(TOK_LBRACE);
|
||||
while (tokens[cur_token].type != TOK_RBRACE && tokens[cur_token].type != TOK_EOF && !compile_error) statement();
|
||||
match(TOK_RBRACE);
|
||||
}
|
||||
|
||||
static void program() {
|
||||
if (tokens[cur_token].type == TOK_INT_TYPE || tokens[cur_token].type == TOK_VOID_TYPE) cur_token++;
|
||||
if (tokens[cur_token].type == TOK_MAIN) cur_token++;
|
||||
match(TOK_LPAREN); match(TOK_RPAREN); block(); emit(OP_HALT);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) { printf("Usage: cc <filename.c>\n"); return 1; }
|
||||
|
||||
int fh = sys_open(argv[1], "r");
|
||||
if (fh < 0) { printf("Error: Cannot open source file.\n"); return 1; }
|
||||
|
||||
char *source = (char*)malloc(MAX_SOURCE);
|
||||
if (!source) { printf("Error: Out of memory for source buffer.\n"); sys_close(fh); return 1; }
|
||||
|
||||
int len = sys_read(fh, source, MAX_SOURCE - 1);
|
||||
source[len] = 0;
|
||||
sys_close(fh);
|
||||
|
||||
lexer(source);
|
||||
free(source);
|
||||
|
||||
if (compile_error) return 1;
|
||||
|
||||
code_pos = 0; symbol_count = 0; cur_token = 0; str_pool_pos = 0; next_var_addr = 32768;
|
||||
|
||||
const char* magic = VM_MAGIC;
|
||||
for(int i=0; i<7; i++) emit(magic[i]);
|
||||
emit(1);
|
||||
program();
|
||||
|
||||
if (compile_error) { printf("Compilation Failed.\n"); return 1; }
|
||||
|
||||
int pool_start_addr = code_pos;
|
||||
for(int i=0; i<str_pool_pos; i++) emit(str_pool[i]);
|
||||
|
||||
int pc = 8;
|
||||
while (pc < pool_start_addr) {
|
||||
uint8_t op = code[pc++];
|
||||
switch (op) {
|
||||
case OP_HALT: break; case OP_IMM: case OP_LOAD: case OP_STORE: case OP_LOAD8: case OP_STORE8: case OP_JMP: case OP_JZ: case OP_SYSCALL: pc += 4; break;
|
||||
case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_PRINT: case OP_PRITC: case OP_EQ: case OP_NEQ: case OP_LT: case OP_GT: case OP_LE: case OP_GE: case OP_POP: break;
|
||||
case OP_PUSH_PTR: {
|
||||
int offset = 0;
|
||||
offset |= code[pc]; offset |= code[pc+1] << 8; offset |= code[pc+2] << 16; offset |= code[pc+3] << 24;
|
||||
int abs_addr = pool_start_addr + offset;
|
||||
code[pc] = abs_addr & 0xFF; code[pc+1] = (abs_addr >> 8) & 0xFF; code[pc+2] = (abs_addr >> 16) & 0xFF; code[pc+3] = (abs_addr >> 24) & 0xFF;
|
||||
pc += 4; code[pc-5] = OP_IMM; break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
char out_name[64]; int i = 0;
|
||||
while(argv[1][i] && argv[1][i] != '.') { out_name[i] = argv[1][i]; i++; }
|
||||
out_name[i] = 0;
|
||||
|
||||
int out_fh = sys_open(out_name, "w");
|
||||
if (out_fh >= 0) {
|
||||
sys_write_fs(out_fh, code, code_pos);
|
||||
sys_close(out_fh);
|
||||
printf("Compilation successful. Output: %s\n", out_name);
|
||||
} else { printf("Error: Cannot write output file.\n"); }
|
||||
|
||||
return 0;
|
||||
}
|
||||
8
src/kernel/userland/clear.c
Normal file
8
src/kernel/userland/clear.c
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc; (void)argv;
|
||||
sys_system(10, 0, 0, 0, 0); // SYSTEM_CMD_CLEAR_SCREEN
|
||||
return 0;
|
||||
}
|
||||
26
src/kernel/userland/cowsay.c
Normal file
26
src/kernel/userland/cowsay.c
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *msg = (char*)"Bored!";
|
||||
if (argc > 1) {
|
||||
// Simple concatenation of args for now
|
||||
// For simplicity in this demo, just use the first arg
|
||||
msg = argv[1];
|
||||
}
|
||||
|
||||
size_t len = strlen(msg);
|
||||
|
||||
printf(" ");
|
||||
for(size_t i=0; i<len+2; i++) printf("_");
|
||||
printf("\n< %s >\n ", msg);
|
||||
for(size_t i=0; i<len+2; i++) printf("-");
|
||||
printf("\n");
|
||||
printf(" \\ ^__^\n");
|
||||
printf(" \\ (oo)\\_______\n");
|
||||
printf(" (__)\\ )\\/\\\n");
|
||||
printf(" ||----w |\n");
|
||||
printf(" || ||\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
33
src/kernel/userland/cp.c
Normal file
33
src/kernel/userland/cp.c
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 3) {
|
||||
printf("Usage: cp <source> <dest>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fd_in = sys_open(argv[1], "r");
|
||||
if (fd_in < 0) {
|
||||
printf("Error: Cannot open source %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fd_out = sys_open(argv[2], "w");
|
||||
if (fd_out < 0) {
|
||||
printf("Error: Cannot create destination %s\n", argv[2]);
|
||||
sys_close(fd_in);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char buffer[4096];
|
||||
int bytes;
|
||||
while ((bytes = sys_read(fd_in, buffer, sizeof(buffer))) > 0) {
|
||||
sys_write_fs(fd_out, buffer, bytes);
|
||||
}
|
||||
|
||||
sys_close(fd_in);
|
||||
sys_close(fd_out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
13
src/kernel/userland/date.c
Normal file
13
src/kernel/userland/date.c
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc; (void)argv;
|
||||
int dt[6];
|
||||
if (sys_system(11, (uint64_t)dt, 0, 0, 0) == 0) {
|
||||
printf("Current Date: %d-%d-%d %d:%d:%d\n", dt[0], dt[1], dt[2], dt[3], dt[4], dt[5]);
|
||||
} else {
|
||||
printf("Error: Could not retrieve date.\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
10
src/kernel/userland/echo.c
Normal file
10
src/kernel/userland/echo.c
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
printf("%s%s", argv[i], (i == argc - 1) ? "" : " ");
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,41 +1,13 @@
|
|||
#include "syscall.h"
|
||||
|
||||
int strlen(const char* str) {
|
||||
int len = 0;
|
||||
while(str[len]) len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
void print_int(int n) {
|
||||
char buf[16];
|
||||
if (n == 0) {
|
||||
sys_write(1, "0", 1);
|
||||
return;
|
||||
}
|
||||
int i = 0;
|
||||
while(n > 0) {
|
||||
buf[i++] = (n % 10) + '0';
|
||||
n /= 10;
|
||||
}
|
||||
for(int j = i - 1; j >= 0; j--) {
|
||||
sys_write(1, &buf[j], 1);
|
||||
}
|
||||
}
|
||||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char* msg = "Hello from Userland ELF!\n";
|
||||
sys_write(1, msg, 25);
|
||||
printf("Hello from Userland ELF!\n");
|
||||
|
||||
sys_write(1, "argc: ", 6);
|
||||
print_int(argc);
|
||||
sys_write(1, "\n", 1);
|
||||
printf("argc: %d\n", argc);
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
sys_write(1, "argv[", 5);
|
||||
print_int(i);
|
||||
sys_write(1, "]: ", 3);
|
||||
sys_write(1, argv[i], strlen(argv[i]));
|
||||
sys_write(1, "\n", 1);
|
||||
printf("argv[%d]: %s\n", i, argv[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
32
src/kernel/userland/help.c
Normal file
32
src/kernel/userland/help.c
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc; (void)argv;
|
||||
printf("BoredOS CLI Help (Userspace)\n");
|
||||
printf("---------------------------\n");
|
||||
printf("ls [path] - List directory contents\n");
|
||||
printf("cd <path> - Change current directory (built-in)\n");
|
||||
printf("pwd - Print current directory\n");
|
||||
printf("mkdir <dir> - Create directory\n");
|
||||
printf("rm <path> - Remove file or directory\n");
|
||||
printf("cat <file> - Print file contents\n");
|
||||
printf("echo [text] - Print text\n");
|
||||
printf("touch <file> - Create empty file\n");
|
||||
printf("cp <src> <dst> - Copy file\n");
|
||||
printf("mv <src> <dst> - Move file\n");
|
||||
printf("date - Print current date and time\n");
|
||||
printf("uptime - Print system uptime\n");
|
||||
printf("meminfo - Print memory information\n");
|
||||
printf("cowsay [msg] - Fun cow says something\n");
|
||||
printf("beep - Make a beep sound\n");
|
||||
printf("reboot - Reboot the system\n");
|
||||
printf("shutdown - Shutdown the system\n");
|
||||
printf("boredver - Show BoredOS version\n");
|
||||
printf("cc <file.c> - C Compiler\n");
|
||||
printf("man <cmd> - Show manual page\n");
|
||||
printf("clear - Clear the screen\n");
|
||||
printf("exit - Exit the terminal\n");
|
||||
printf("\nHint: Use Ctrl+C to force quit any running .elf app.\n");
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
|
|
@ -123,14 +123,142 @@ void *realloc(void *ptr, size_t size) {
|
|||
}
|
||||
|
||||
void *memset(void *s, int c, size_t n) {
|
||||
unsigned char *p = s;
|
||||
unsigned char *p = (unsigned char *)s;
|
||||
while (n--) *p++ = (unsigned char)c;
|
||||
return s;
|
||||
}
|
||||
|
||||
void *memcpy(void *dest, const void *src, size_t n) {
|
||||
unsigned char *d = dest;
|
||||
const unsigned char *s = src;
|
||||
unsigned char *d = (unsigned char *)dest;
|
||||
const unsigned char *s = (const unsigned char *)src;
|
||||
while (n--) *d++ = *s++;
|
||||
return dest;
|
||||
}
|
||||
|
||||
// String functions
|
||||
size_t strlen(const char *s) {
|
||||
size_t len = 0;
|
||||
while (s[len]) len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
int strcmp(const char *s1, const char *s2) {
|
||||
while (*s1 && (*s1 == *s2)) {
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
|
||||
}
|
||||
|
||||
char* strcpy(char *dest, const char *src) {
|
||||
char *ret = dest;
|
||||
while (*src) *dest++ = *src++;
|
||||
*dest = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* strcat(char *dest, const char *src) {
|
||||
char *ret = dest;
|
||||
while (*dest) dest++;
|
||||
while (*src) *dest++ = *src++;
|
||||
*dest = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int atoi(const char *nptr) {
|
||||
int res = 0;
|
||||
int sign = 1;
|
||||
if (*nptr == '-') {
|
||||
sign = -1;
|
||||
nptr++;
|
||||
}
|
||||
while (*nptr >= '0' && *nptr <= '9') {
|
||||
res = res * 10 + (*nptr - '0');
|
||||
nptr++;
|
||||
}
|
||||
return sign * res;
|
||||
}
|
||||
|
||||
void itoa(int n, char *buf) {
|
||||
if (n == 0) {
|
||||
buf[0] = '0'; buf[1] = 0; return;
|
||||
}
|
||||
int i = 0;
|
||||
int sign = n < 0;
|
||||
if (sign) n = -n;
|
||||
while (n > 0) {
|
||||
buf[i++] = (n % 10) + '0';
|
||||
n /= 10;
|
||||
}
|
||||
if (sign) buf[i++] = '-';
|
||||
buf[i] = 0;
|
||||
// Reverse
|
||||
for (int j = 0; j < i / 2; j++) {
|
||||
char t = buf[j];
|
||||
buf[j] = buf[i - 1 - j];
|
||||
buf[i - 1 - j] = t;
|
||||
}
|
||||
}
|
||||
|
||||
// IO functions
|
||||
void puts(const char *s) {
|
||||
sys_write(1, s, strlen(s));
|
||||
sys_write(1, "\n", 1);
|
||||
}
|
||||
|
||||
void printf(const char *fmt, ...) {
|
||||
// Simple printf implementation
|
||||
__builtin_va_list args;
|
||||
__builtin_va_start(args, fmt);
|
||||
char buf[1024];
|
||||
int buf_idx = 0;
|
||||
|
||||
while (*fmt) {
|
||||
if (*fmt == '%') {
|
||||
fmt++;
|
||||
if (*fmt == 's') {
|
||||
char *s = __builtin_va_arg(args, char *);
|
||||
while (*s) buf[buf_idx++] = *s++;
|
||||
} else if (*fmt == 'd') {
|
||||
int d = __builtin_va_arg(args, int);
|
||||
char ibuf[32];
|
||||
itoa(d, ibuf);
|
||||
char *s = ibuf;
|
||||
while (*s) buf[buf_idx++] = *s++;
|
||||
} else if (*fmt == 'c') {
|
||||
char c = (char)__builtin_va_arg(args, int);
|
||||
buf[buf_idx++] = c;
|
||||
} else if (*fmt == '%') {
|
||||
buf[buf_idx++] = '%';
|
||||
}
|
||||
} else {
|
||||
buf[buf_idx++] = *fmt;
|
||||
}
|
||||
fmt++;
|
||||
if (buf_idx >= 1022) break; // Simple overflow protection
|
||||
}
|
||||
buf[buf_idx] = 0;
|
||||
sys_write(1, buf, buf_idx);
|
||||
__builtin_va_end(args);
|
||||
}
|
||||
|
||||
// System/Process functions
|
||||
int chdir(const char *path) {
|
||||
return sys_chdir(path);
|
||||
}
|
||||
|
||||
char* getcwd(char *buf, int size) {
|
||||
if (sys_getcwd(buf, size) == 0) return buf;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sleep(int ms) {
|
||||
// We don't have a sleep syscall yet, so we'll just busy wait for now or skip
|
||||
// Actually, BoredOS doesn't seem to have a sleep syscall.
|
||||
// I'll add one if needed, but for now I'll just skip.
|
||||
(void)ms;
|
||||
}
|
||||
|
||||
void exit(int status) {
|
||||
sys_exit(status);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,4 +11,22 @@ void* realloc(void* ptr, size_t size);
|
|||
void *memset(void *s, int c, size_t n);
|
||||
void *memcpy(void *dest, const void *src, size_t n);
|
||||
|
||||
// String functions
|
||||
size_t strlen(const char *s);
|
||||
int strcmp(const char *s1, const char *s2);
|
||||
char* strcpy(char *dest, const char *src);
|
||||
char* strcat(char *dest, const char *src);
|
||||
int atoi(const char *nptr);
|
||||
void itoa(int n, char *buf);
|
||||
|
||||
// IO functions
|
||||
void puts(const char *s);
|
||||
void printf(const char *fmt, ...);
|
||||
|
||||
// System/Process functions
|
||||
int chdir(const char *path);
|
||||
char* getcwd(char *buf, int size);
|
||||
void sleep(int ms);
|
||||
void exit(int status);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -121,3 +121,15 @@ int sys_exists(const char *path) {
|
|||
return (int)syscall2(SYS_FS, FS_CMD_EXISTS, (uint64_t)path);
|
||||
}
|
||||
|
||||
int sys_getcwd(char *buf, int size) {
|
||||
return (int)syscall3(SYS_FS, FS_CMD_GETCWD, (uint64_t)buf, (uint64_t)size);
|
||||
}
|
||||
|
||||
int sys_chdir(const char *path) {
|
||||
return (int)syscall2(SYS_FS, FS_CMD_CHDIR, (uint64_t)path);
|
||||
}
|
||||
|
||||
void sys_kill(int pid) {
|
||||
syscall1(SYS_KILL, (uint64_t)pid);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#define SYS_GUI 3
|
||||
#define SYS_FS 4
|
||||
#define SYS_SYSTEM 5
|
||||
#define SYS_KILL 10
|
||||
#define SYS_SBRK 9
|
||||
|
||||
// FS Commands
|
||||
|
|
@ -23,6 +24,8 @@
|
|||
#define FS_CMD_SIZE 9
|
||||
#define FS_CMD_MKDIR 10
|
||||
#define FS_CMD_EXISTS 11
|
||||
#define FS_CMD_GETCWD 12
|
||||
#define FS_CMD_CHDIR 13
|
||||
|
||||
// Internal assembly entry into Ring 0
|
||||
extern uint64_t syscall0(uint64_t sys_num);
|
||||
|
|
@ -36,6 +39,7 @@ extern uint64_t syscall5(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_
|
|||
void sys_exit(int status);
|
||||
int sys_write(int fd, const char *buf, int len);
|
||||
void *sys_sbrk(int incr);
|
||||
void sys_kill(int pid);
|
||||
int sys_system(int cmd, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4);
|
||||
|
||||
// FS API
|
||||
|
|
@ -49,8 +53,18 @@ uint32_t sys_size(int fd);
|
|||
int sys_delete(const char *path);
|
||||
int sys_mkdir(const char *path);
|
||||
int sys_exists(const char *path);
|
||||
int sys_getcwd(char *buf, int size);
|
||||
int sys_chdir(const char *path);
|
||||
|
||||
struct FAT32_FileInfo;
|
||||
int sys_list(const char *path, struct FAT32_FileInfo *entries, int max_entries);
|
||||
typedef struct {
|
||||
char name[256];
|
||||
uint32_t size;
|
||||
uint8_t is_directory;
|
||||
uint32_t start_cluster;
|
||||
uint16_t write_date;
|
||||
uint16_t write_time;
|
||||
} FAT32_FileInfo;
|
||||
|
||||
int sys_list(const char *path, FAT32_FileInfo *entries, int max_entries);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Binary file not shown.
32
src/kernel/userland/ls.c
Normal file
32
src/kernel/userland/ls.c
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char path[256];
|
||||
if (argc > 1) {
|
||||
strcpy(path, argv[1]);
|
||||
} else {
|
||||
if (!getcwd(path, sizeof(path))) {
|
||||
strcpy(path, ".");
|
||||
}
|
||||
}
|
||||
|
||||
FAT32_FileInfo entries[128];
|
||||
int count = sys_list(path, entries, 128);
|
||||
|
||||
if (count < 0) {
|
||||
printf("Error: Cannot list directory %s\n", path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (entries[i].is_directory) {
|
||||
printf("[DIR] %s\n", entries[i].name);
|
||||
} else {
|
||||
printf("[FILE] %s (%d bytes)\n", entries[i].name, entries[i].size);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\nTotal: %d items\n", count);
|
||||
return 0;
|
||||
}
|
||||
33
src/kernel/userland/man.c
Normal file
33
src/kernel/userland/man.c
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
printf("What manual page do you want?\nExample: man ls\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
char path[128];
|
||||
printf("Manual for: %s\n", argv[1]);
|
||||
printf("---------------------------\n");
|
||||
|
||||
strcpy(path, "A:/Library/man/");
|
||||
strcat(path, argv[1]);
|
||||
strcat(path, ".txt");
|
||||
|
||||
int fd = sys_open(path, "r");
|
||||
if (fd < 0) {
|
||||
printf("No manual entry for %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char buffer[4096];
|
||||
int bytes;
|
||||
while ((bytes = sys_read(fd, buffer, sizeof(buffer))) > 0) {
|
||||
sys_write(1, buffer, bytes);
|
||||
}
|
||||
|
||||
sys_close(fd);
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
27
src/kernel/userland/math.c
Normal file
27
src/kernel/userland/math.c
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 4) {
|
||||
printf("Usage: math <num1> <op> <num2>\n");
|
||||
printf("Ops: + - * /\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int n1 = atoi(argv[1]);
|
||||
int n2 = atoi(argv[3]);
|
||||
char op = argv[2][0];
|
||||
int res = 0;
|
||||
|
||||
if (op == '+') res = n1 + n2;
|
||||
else if (op == '-') res = n1 - n2;
|
||||
else if (op == '*') res = n1 * n2;
|
||||
else if (op == '/') {
|
||||
if (n2 == 0) { printf("Error: Div by zero\n"); return 1; }
|
||||
res = n1 / n2;
|
||||
}
|
||||
else { printf("Error: Unknown op %c\n", op); return 1; }
|
||||
|
||||
printf("%d %c %d = %d\n", n1, op, n2, res);
|
||||
return 0;
|
||||
}
|
||||
16
src/kernel/userland/meminfo.c
Normal file
16
src/kernel/userland/meminfo.c
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc; (void)argv;
|
||||
uint64_t mem[2];
|
||||
if (sys_system(15, (uint64_t)mem, 0, 0, 0) == 0) {
|
||||
printf("Memory Info:\n");
|
||||
printf("Total: %d MB\n", (int)(mem[0] / 1024 / 1024));
|
||||
printf("Used: %d MB\n", (int)(mem[1] / 1024 / 1024));
|
||||
printf("Free: %d MB\n", (int)((mem[0] - mem[1]) / 1024 / 1024));
|
||||
} else {
|
||||
printf("Error: Could not retrieve memory info.\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
17
src/kernel/userland/mkdir.c
Normal file
17
src/kernel/userland/mkdir.c
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
printf("Usage: mkdir <dirname>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sys_mkdir(argv[1]) == 0) {
|
||||
printf("Created directory: %s\n", argv[1]);
|
||||
} else {
|
||||
printf("Error: Cannot create directory %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
38
src/kernel/userland/mv.c
Normal file
38
src/kernel/userland/mv.c
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 3) {
|
||||
printf("Usage: mv <source> <dest>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Simplification: use cp then rm
|
||||
int fd_in = sys_open(argv[1], "r");
|
||||
if (fd_in < 0) {
|
||||
printf("Error: Cannot open source %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fd_out = sys_open(argv[2], "w");
|
||||
if (fd_out < 0) {
|
||||
printf("Error: Cannot create destination %s\n", argv[2]);
|
||||
sys_close(fd_in);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char buffer[4096];
|
||||
int bytes;
|
||||
while ((bytes = sys_read(fd_in, buffer, sizeof(buffer))) > 0) {
|
||||
sys_write_fs(fd_out, buffer, bytes);
|
||||
}
|
||||
|
||||
sys_close(fd_in);
|
||||
sys_close(fd_out);
|
||||
|
||||
if (sys_delete(argv[1]) != 0) {
|
||||
printf("Warning: Failed to delete source %s after copy\n", argv[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
30
src/kernel/userland/pci_list.c
Normal file
30
src/kernel/userland/pci_list.c
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
typedef struct {
|
||||
uint16_t vendor;
|
||||
uint16_t device;
|
||||
uint8_t class_code;
|
||||
uint8_t subclass;
|
||||
} pci_info_t;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc; (void)argv;
|
||||
int count = sys_system(17, 0, 0, 0, 0); // Get count
|
||||
if (count < 0) {
|
||||
printf("Error: Could not retrieve PCI device count.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("PCI Devices (%d found):\n", count);
|
||||
printf("---------------------------\n");
|
||||
for (int i = 0; i < count; i++) {
|
||||
pci_info_t info;
|
||||
if (sys_system(17, (uint64_t)&info, i, 0, 0) == 0) {
|
||||
printf("[%d] Vendor:%04x Device:%04x Class:%02x Sub:%02x\n",
|
||||
i, info.vendor, info.device, info.class_code, info.subclass);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
14
src/kernel/userland/pwd.c
Normal file
14
src/kernel/userland/pwd.c
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc; (void)argv;
|
||||
char path[256];
|
||||
if (getcwd(path, sizeof(path))) {
|
||||
printf("%s\n", path);
|
||||
} else {
|
||||
printf("Error: Could not get current directory\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
9
src/kernel/userland/reboot.c
Normal file
9
src/kernel/userland/reboot.c
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc; (void)argv;
|
||||
printf("Rebooting...\n");
|
||||
sys_system(12, 0, 0, 0, 0); // SYSTEM_CMD_REBOOT
|
||||
return 0;
|
||||
}
|
||||
18
src/kernel/userland/rm.c
Normal file
18
src/kernel/userland/rm.c
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
printf("Usage: rm <path>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Simple rm (no recursive support yet for simplicity, but can be added)
|
||||
if (sys_delete(argv[1]) == 0) {
|
||||
printf("Deleted: %s\n", argv[1]);
|
||||
} else {
|
||||
printf("Error: Cannot delete %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
9
src/kernel/userland/shutdown.c
Normal file
9
src/kernel/userland/shutdown.c
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc; (void)argv;
|
||||
printf("Shutting down...\n");
|
||||
sys_system(13, 0, 0, 0, 0); // SYSTEM_CMD_SHUTDOWN
|
||||
return 0;
|
||||
}
|
||||
30
src/kernel/userland/sweden.c
Normal file
30
src/kernel/userland/sweden.c
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
static void beep(int freq, int ms) {
|
||||
sys_system(14, freq, ms, 0, 0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc; (void)argv;
|
||||
printf("Playing Sweden - C418 (Minecraft)...\n");
|
||||
|
||||
// Main melody (simplified pattern)
|
||||
beep(392, 400); // G4
|
||||
beep(440, 400); // A4
|
||||
beep(493, 800); // B4
|
||||
|
||||
beep(440, 400); // A4
|
||||
beep(392, 800); // G4
|
||||
beep(329, 800); // E4
|
||||
|
||||
beep(392, 400); // G4
|
||||
beep(440, 400); // A4
|
||||
beep(493, 800); // B4
|
||||
|
||||
beep(440, 400); // A4
|
||||
beep(392, 1200); // G4
|
||||
|
||||
printf("Done.\n");
|
||||
return 0;
|
||||
}
|
||||
24
src/kernel/userland/touch.c
Normal file
24
src/kernel/userland/touch.c
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
printf("Usage: touch <filename>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Check if file already exists
|
||||
if (sys_exists(argv[1])) {
|
||||
// Just return success if it exists (simplification)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fd = sys_open(argv[1], "w");
|
||||
if (fd < 0) {
|
||||
printf("Error: Cannot create %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sys_close(fd);
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
16
src/kernel/userland/uptime.c
Normal file
16
src/kernel/userland/uptime.c
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc; (void)argv;
|
||||
uint64_t ticks = sys_system(16, 0, 0, 0, 0); // SYSTEM_CMD_UPTIME
|
||||
uint64_t seconds = ticks / 100; // 100Hz timer assumed
|
||||
uint64_t minutes = seconds / 60;
|
||||
uint64_t hours = minutes / 60;
|
||||
uint64_t days = hours / 24;
|
||||
|
||||
printf("Uptime: %d days, %d hours, %d minutes, %d seconds\n",
|
||||
(int)days, (int)(hours % 24), (int)(minutes % 60), (int)(seconds % 60));
|
||||
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
122
src/kernel/vm.c
122
src/kernel/vm.c
|
|
@ -6,7 +6,7 @@
|
|||
#include "fat32.h"
|
||||
#include "rtc.h"
|
||||
#include "ps2.h"
|
||||
#include "cli_apps/cli_utils.h"
|
||||
#include "kutils.h"
|
||||
#include "io.h"
|
||||
|
||||
// --- Scancode Map (Set 1) ---
|
||||
|
|
@ -62,7 +62,7 @@ static void mem_write32(int addr, int val) {
|
|||
|
||||
static void vm_reset(void) {
|
||||
sp = 0;
|
||||
cli_memset(memory, 0, VM_MEMORY_SIZE);
|
||||
k_memset(memory, 0, VM_MEMORY_SIZE);
|
||||
vm_heap_ptr = 8192;
|
||||
}
|
||||
|
||||
|
|
@ -85,22 +85,22 @@ static int pop(void) {
|
|||
// Syscall Implementations
|
||||
static void vm_syscall(int id) {
|
||||
switch (id) {
|
||||
case SYS_EXIT:
|
||||
case VM_SYS_EXIT:
|
||||
// Handled by return code in main loop usually, but here just do nothing or treat as halt
|
||||
push(0);
|
||||
break;
|
||||
case SYS_PRINT_INT:
|
||||
case VM_SYS_PRINT_INT:
|
||||
cmd_write_int(pop());
|
||||
push(0);
|
||||
break;
|
||||
case SYS_PRINT_CHAR: {
|
||||
case VM_SYS_PRINT_CHAR: {
|
||||
char c = (char)pop();
|
||||
char s[2] = {c, 0};
|
||||
cmd_write(s);
|
||||
push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_PRINT_STR: {
|
||||
case VM_SYS_PRINT_STR: {
|
||||
int addr = pop();
|
||||
if (addr >= 0 && addr < VM_MEMORY_SIZE) {
|
||||
cmd_write((char*)&memory[addr]);
|
||||
|
|
@ -108,15 +108,15 @@ static void vm_syscall(int id) {
|
|||
push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_NL:
|
||||
case VM_SYS_NL:
|
||||
cmd_write("\n");
|
||||
push(0);
|
||||
break;
|
||||
case SYS_CLS:
|
||||
case VM_SYS_CLS:
|
||||
cmd_screen_clear();
|
||||
push(0);
|
||||
break;
|
||||
case SYS_GETCHAR: {
|
||||
case VM_SYS_GETCHAR: {
|
||||
int c = 0;
|
||||
// Blocking read for a valid key press
|
||||
while (1) {
|
||||
|
|
@ -133,50 +133,50 @@ static void vm_syscall(int id) {
|
|||
push(c);
|
||||
break;
|
||||
}
|
||||
case SYS_KB_HIT:
|
||||
case VM_SYS_KB_HIT:
|
||||
// Simple check if data is waiting in keyboard controller
|
||||
push((inb(0x64) & 1) ? 1 : 0);
|
||||
break;
|
||||
case SYS_STRLEN: {
|
||||
case VM_SYS_STRLEN: {
|
||||
int addr = pop();
|
||||
if (addr >= 0 && addr < VM_MEMORY_SIZE) {
|
||||
push(cli_strlen((char*)&memory[addr]));
|
||||
push(k_strlen((char*)&memory[addr]));
|
||||
} else push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_STRCMP: {
|
||||
case VM_SYS_STRCMP: {
|
||||
int a2 = pop();
|
||||
int a1 = pop();
|
||||
if (a1 >= 0 && a1 < VM_MEMORY_SIZE && a2 >= 0 && a2 < VM_MEMORY_SIZE) {
|
||||
push(cli_strcmp((char*)&memory[a1], (char*)&memory[a2]));
|
||||
push(k_strcmp((char*)&memory[a1], (char*)&memory[a2]));
|
||||
} else push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_STRCPY: {
|
||||
case VM_SYS_STRCPY: {
|
||||
int src = pop();
|
||||
int dest = pop();
|
||||
if (dest >= 0 && dest < VM_MEMORY_SIZE && src >= 0 && src < VM_MEMORY_SIZE) {
|
||||
cli_strcpy((char*)&memory[dest], (char*)&memory[src]);
|
||||
k_strcpy((char*)&memory[dest], (char*)&memory[src]);
|
||||
push(dest);
|
||||
} else push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_STRCAT: {
|
||||
case VM_SYS_STRCAT: {
|
||||
// Not implemented in cli_utils
|
||||
pop(); pop(); push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_MEMSET: {
|
||||
case VM_SYS_MEMSET: {
|
||||
int n = pop();
|
||||
int val = pop();
|
||||
int ptr = pop();
|
||||
if (ptr >= 0 && ptr + n <= VM_MEMORY_SIZE) {
|
||||
cli_memset(&memory[ptr], val, n);
|
||||
k_memset(&memory[ptr], val, n);
|
||||
push(ptr);
|
||||
} else push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_MEMCPY: {
|
||||
case VM_SYS_MEMCPY: {
|
||||
int n = pop();
|
||||
int src = pop();
|
||||
int dest = pop();
|
||||
|
|
@ -189,7 +189,7 @@ static void vm_syscall(int id) {
|
|||
// Simplified Heap (using top of memory growing down?)
|
||||
// For now, static allocation or mapped.
|
||||
// Dummy malloc that returns an index into memory starting at 1024
|
||||
case SYS_MALLOC: {
|
||||
case VM_SYS_MALLOC: {
|
||||
int size = pop();
|
||||
int res = vm_heap_ptr;
|
||||
vm_heap_ptr += size;
|
||||
|
|
@ -200,38 +200,38 @@ static void vm_syscall(int id) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case SYS_FREE:
|
||||
case VM_SYS_FREE:
|
||||
pop(); // No-op
|
||||
push(0);
|
||||
break;
|
||||
case SYS_RAND: {
|
||||
case VM_SYS_RAND: {
|
||||
rand_next = rand_next * 1103515245 + 12345;
|
||||
push((unsigned int)(rand_next/65536) % 32768);
|
||||
break;
|
||||
}
|
||||
case SYS_SRAND: {
|
||||
case VM_SYS_SRAND: {
|
||||
rand_next = pop();
|
||||
push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_ABS: {
|
||||
case VM_SYS_ABS: {
|
||||
int x = pop();
|
||||
push(x < 0 ? -x : x);
|
||||
break;
|
||||
}
|
||||
case SYS_MIN: {
|
||||
case VM_SYS_MIN: {
|
||||
int b = pop();
|
||||
int a = pop();
|
||||
push(a < b ? a : b);
|
||||
break;
|
||||
}
|
||||
case SYS_MAX: {
|
||||
case VM_SYS_MAX: {
|
||||
int b = pop();
|
||||
int a = pop();
|
||||
push(a > b ? a : b);
|
||||
break;
|
||||
}
|
||||
case SYS_POW: {
|
||||
case VM_SYS_POW: {
|
||||
int exp = pop();
|
||||
int base = pop();
|
||||
int res = 1;
|
||||
|
|
@ -239,26 +239,26 @@ static void vm_syscall(int id) {
|
|||
push(res);
|
||||
break;
|
||||
}
|
||||
case SYS_SQRT: {
|
||||
case VM_SYS_SQRT: {
|
||||
int n = pop();
|
||||
int res = 0;
|
||||
while ((res*res) <= n) res++;
|
||||
push(res - 1);
|
||||
break;
|
||||
}
|
||||
case SYS_SLEEP:
|
||||
cli_sleep(pop());
|
||||
case VM_SYS_SLEEP:
|
||||
k_sleep(pop());
|
||||
push(0);
|
||||
break;
|
||||
// File IO - Not supported yet as FILE* cannot be easily passed to VM
|
||||
case SYS_FOPEN: pop(); pop(); push(0); break;
|
||||
case SYS_FCLOSE: pop(); push(0); break;
|
||||
case SYS_FREAD: pop(); pop(); pop(); pop(); push(0); break;
|
||||
case SYS_FWRITE: pop(); pop(); pop(); pop(); push(0); break;
|
||||
case SYS_FSEEK: pop(); pop(); pop(); push(0); break;
|
||||
case SYS_REMOVE: pop(); push(0); break;
|
||||
case VM_SYS_FOPEN: pop(); pop(); push(0); break;
|
||||
case VM_SYS_FCLOSE: pop(); push(0); break;
|
||||
case VM_SYS_FREAD: pop(); pop(); pop(); pop(); push(0); break;
|
||||
case VM_SYS_FWRITE: pop(); pop(); pop(); pop(); push(0); break;
|
||||
case VM_SYS_FSEEK: pop(); pop(); pop(); push(0); break;
|
||||
case VM_SYS_REMOVE: pop(); push(0); break;
|
||||
|
||||
case SYS_DRAW_PIXEL: {
|
||||
case VM_SYS_DRAW_PIXEL: {
|
||||
int color = pop();
|
||||
int y = pop();
|
||||
int x = pop();
|
||||
|
|
@ -266,7 +266,7 @@ static void vm_syscall(int id) {
|
|||
push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_DRAW_RECT: {
|
||||
case VM_SYS_DRAW_RECT: {
|
||||
int color = pop();
|
||||
int h = pop();
|
||||
int w = pop();
|
||||
|
|
@ -289,65 +289,65 @@ static void vm_syscall(int id) {
|
|||
push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_GET_WIDTH: push(get_screen_width()); break;
|
||||
case SYS_GET_HEIGHT: push(get_screen_height()); break;
|
||||
case VM_SYS_GET_WIDTH: push(get_screen_width()); break;
|
||||
case VM_SYS_GET_HEIGHT: push(get_screen_height()); break;
|
||||
|
||||
case SYS_ATOI: {
|
||||
case VM_SYS_ATOI: {
|
||||
int addr = pop();
|
||||
if (addr >= 0 && addr < VM_MEMORY_SIZE) {
|
||||
push(cli_atoi((char*)&memory[addr]));
|
||||
push(k_atoi((char*)&memory[addr]));
|
||||
} else push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_ITOA: {
|
||||
case VM_SYS_ITOA: {
|
||||
int addr = pop();
|
||||
int val = pop();
|
||||
if (addr >= 0 && addr < VM_MEMORY_SIZE) {
|
||||
cli_itoa(val, (char*)&memory[addr]);
|
||||
k_itoa(val, (char*)&memory[addr]);
|
||||
}
|
||||
push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_PEEK: push(mem_read32(pop())); break;
|
||||
case SYS_POKE: {
|
||||
case VM_SYS_PEEK: push(mem_read32(pop())); break;
|
||||
case VM_SYS_POKE: {
|
||||
int val = pop();
|
||||
int addr = pop();
|
||||
mem_write32(addr, val);
|
||||
push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_EXEC: pop(); push(-1); break;
|
||||
case SYS_SYSTEM: pop(); push(-1); break;
|
||||
case VM_SYS_EXEC: pop(); push(-1); break;
|
||||
case VM_SYS_SYSTEM: pop(); push(-1); break;
|
||||
|
||||
// --- New Builtins ---
|
||||
case SYS_ISALNUM: {
|
||||
case VM_SYS_ISALNUM: {
|
||||
int c = pop();
|
||||
push(((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')));
|
||||
break;
|
||||
}
|
||||
case SYS_ISALPHA: {
|
||||
case VM_SYS_ISALPHA: {
|
||||
int c = pop();
|
||||
push(((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')));
|
||||
break;
|
||||
}
|
||||
case SYS_ISDIGIT: {
|
||||
case VM_SYS_ISDIGIT: {
|
||||
int c = pop();
|
||||
push((c >= '0' && c <= '9'));
|
||||
break;
|
||||
}
|
||||
case SYS_TOLOWER: {
|
||||
case VM_SYS_TOLOWER: {
|
||||
int c = pop();
|
||||
if (c >= 'A' && c <= 'Z') push(c + 32);
|
||||
else push(c);
|
||||
break;
|
||||
}
|
||||
case SYS_TOUPPER: {
|
||||
case VM_SYS_TOUPPER: {
|
||||
int c = pop();
|
||||
if (c >= 'a' && c <= 'z') push(c - 32);
|
||||
else push(c);
|
||||
break;
|
||||
}
|
||||
case SYS_STRNCPY: {
|
||||
case VM_SYS_STRNCPY: {
|
||||
int n = pop();
|
||||
int src = pop();
|
||||
int dest = pop();
|
||||
|
|
@ -361,7 +361,7 @@ static void vm_syscall(int id) {
|
|||
} else push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_STRNCAT: {
|
||||
case VM_SYS_STRNCAT: {
|
||||
int n = pop();
|
||||
int src = pop();
|
||||
int dest = pop();
|
||||
|
|
@ -378,7 +378,7 @@ static void vm_syscall(int id) {
|
|||
} else push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_STRNCMP: {
|
||||
case VM_SYS_STRNCMP: {
|
||||
int n = pop();
|
||||
int s2 = pop();
|
||||
int s1 = pop();
|
||||
|
|
@ -396,7 +396,7 @@ static void vm_syscall(int id) {
|
|||
} else push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_STRSTR: {
|
||||
case VM_SYS_STRSTR: {
|
||||
int needle = pop();
|
||||
int haystack = pop();
|
||||
if (haystack >= 0 && haystack < VM_MEMORY_SIZE && needle >= 0 && needle < VM_MEMORY_SIZE) {
|
||||
|
|
@ -416,7 +416,7 @@ static void vm_syscall(int id) {
|
|||
} else push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_STRRCHR: {
|
||||
case VM_SYS_STRRCHR: {
|
||||
int c = pop();
|
||||
int s = pop();
|
||||
if (s >= 0 && s < VM_MEMORY_SIZE) {
|
||||
|
|
@ -433,7 +433,7 @@ static void vm_syscall(int id) {
|
|||
} else push(0);
|
||||
break;
|
||||
}
|
||||
case SYS_MEMMOVE: {
|
||||
case VM_SYS_MEMMOVE: {
|
||||
int n = pop();
|
||||
int src = pop();
|
||||
int dest = pop();
|
||||
|
|
@ -476,7 +476,7 @@ int vm_exec(const uint8_t *code, int code_size) {
|
|||
}
|
||||
|
||||
// Load program into memory at address 0
|
||||
cli_memset(memory, 0, VM_MEMORY_SIZE);
|
||||
k_memset(memory, 0, VM_MEMORY_SIZE);
|
||||
for(int i=0; i<code_size; i++) memory[i] = code[i];
|
||||
|
||||
int pc = 8; // Skip header
|
||||
|
|
|
|||
122
src/kernel/vm.h
122
src/kernel/vm.h
|
|
@ -39,68 +39,68 @@ typedef enum {
|
|||
|
||||
// Syscall IDs
|
||||
typedef enum {
|
||||
SYS_EXIT = 0,
|
||||
SYS_PRINT_INT,
|
||||
SYS_PRINT_CHAR,
|
||||
SYS_PRINT_STR,
|
||||
SYS_NL,
|
||||
SYS_CLS,
|
||||
SYS_GETCHAR,
|
||||
SYS_STRLEN,
|
||||
SYS_STRCMP,
|
||||
SYS_STRCPY,
|
||||
SYS_STRCAT,
|
||||
SYS_MEMSET,
|
||||
SYS_MEMCPY,
|
||||
SYS_MALLOC,
|
||||
SYS_FREE,
|
||||
SYS_RAND,
|
||||
SYS_SRAND,
|
||||
SYS_ABS,
|
||||
SYS_MIN,
|
||||
SYS_MAX,
|
||||
SYS_POW,
|
||||
SYS_SQRT,
|
||||
SYS_SLEEP,
|
||||
SYS_FOPEN,
|
||||
SYS_FCLOSE,
|
||||
SYS_FREAD,
|
||||
SYS_FWRITE,
|
||||
SYS_FSEEK,
|
||||
SYS_REMOVE,
|
||||
SYS_DRAW_PIXEL,
|
||||
SYS_DRAW_RECT,
|
||||
SYS_DRAW_LINE,
|
||||
SYS_DRAW_TEXT,
|
||||
SYS_GET_WIDTH,
|
||||
SYS_GET_HEIGHT,
|
||||
SYS_GET_TIME,
|
||||
SYS_KB_HIT,
|
||||
SYS_MOUSE_X,
|
||||
SYS_MOUSE_Y,
|
||||
SYS_MOUSE_STATE,
|
||||
SYS_PLAY_SOUND,
|
||||
SYS_ATOI,
|
||||
SYS_ITOA,
|
||||
SYS_PEEK,
|
||||
SYS_POKE,
|
||||
SYS_EXEC,
|
||||
SYS_SYSTEM,
|
||||
SYS_STRCHR,
|
||||
SYS_MEMCMP,
|
||||
SYS_GET_DATE,
|
||||
VM_SYS_EXIT = 0,
|
||||
VM_SYS_PRINT_INT,
|
||||
VM_SYS_PRINT_CHAR,
|
||||
VM_SYS_PRINT_STR,
|
||||
VM_SYS_NL,
|
||||
VM_SYS_CLS,
|
||||
VM_SYS_GETCHAR,
|
||||
VM_SYS_STRLEN,
|
||||
VM_SYS_STRCMP,
|
||||
VM_SYS_STRCPY,
|
||||
VM_SYS_STRCAT,
|
||||
VM_SYS_MEMSET,
|
||||
VM_SYS_MEMCPY,
|
||||
VM_SYS_MALLOC,
|
||||
VM_SYS_FREE,
|
||||
VM_SYS_RAND,
|
||||
VM_SYS_SRAND,
|
||||
VM_SYS_ABS,
|
||||
VM_SYS_MIN,
|
||||
VM_SYS_MAX,
|
||||
VM_SYS_POW,
|
||||
VM_SYS_SQRT,
|
||||
VM_SYS_SLEEP,
|
||||
VM_SYS_FOPEN,
|
||||
VM_SYS_FCLOSE,
|
||||
VM_SYS_FREAD,
|
||||
VM_SYS_FWRITE,
|
||||
VM_SYS_FSEEK,
|
||||
VM_SYS_REMOVE,
|
||||
VM_SYS_DRAW_PIXEL,
|
||||
VM_SYS_DRAW_RECT,
|
||||
VM_SYS_DRAW_LINE,
|
||||
VM_SYS_DRAW_TEXT,
|
||||
VM_SYS_GET_WIDTH,
|
||||
VM_SYS_GET_HEIGHT,
|
||||
VM_SYS_GET_TIME,
|
||||
VM_SYS_KB_HIT,
|
||||
VM_SYS_MOUSE_X,
|
||||
VM_SYS_MOUSE_Y,
|
||||
VM_SYS_MOUSE_STATE,
|
||||
VM_SYS_PLAY_SOUND,
|
||||
VM_SYS_ATOI,
|
||||
VM_SYS_ITOA,
|
||||
VM_SYS_PEEK,
|
||||
VM_SYS_POKE,
|
||||
VM_SYS_EXEC,
|
||||
VM_SYS_SYSTEM,
|
||||
VM_SYS_STRCHR,
|
||||
VM_SYS_MEMCMP,
|
||||
VM_SYS_GET_DATE,
|
||||
// New Builtins
|
||||
SYS_ISALNUM,
|
||||
SYS_ISALPHA,
|
||||
SYS_ISDIGIT,
|
||||
SYS_TOLOWER,
|
||||
SYS_TOUPPER,
|
||||
SYS_STRNCPY,
|
||||
SYS_STRNCAT,
|
||||
SYS_STRNCMP,
|
||||
SYS_STRSTR,
|
||||
SYS_STRRCHR,
|
||||
SYS_MEMMOVE
|
||||
VM_SYS_ISALNUM,
|
||||
VM_SYS_ISALPHA,
|
||||
VM_SYS_ISDIGIT,
|
||||
VM_SYS_TOLOWER,
|
||||
VM_SYS_TOUPPER,
|
||||
VM_SYS_STRNCPY,
|
||||
VM_SYS_STRNCAT,
|
||||
VM_SYS_STRNCMP,
|
||||
VM_SYS_STRSTR,
|
||||
VM_SYS_STRRCHR,
|
||||
VM_SYS_MEMMOVE
|
||||
} SyscallID;
|
||||
|
||||
int vm_exec(const uint8_t *code, int code_size);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#include "cmd.h"
|
||||
#include "process.h"
|
||||
#include "syscall.h"
|
||||
#include "cli_apps/cli_utils.h"
|
||||
#include "kutils.h"
|
||||
#include "explorer.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
|
@ -1586,9 +1586,9 @@ void wm_handle_click(int x, int y) {
|
|||
if (existing) wm_bring_to_front(existing);
|
||||
else process_create_elf("/bin/settings.elf", NULL);
|
||||
} else if (item == 2) { // Shutdown
|
||||
cli_cmd_shutdown(NULL);
|
||||
k_shutdown();
|
||||
} else if (item == 3) { // Restart
|
||||
cli_cmd_reboot(NULL);
|
||||
k_reboot();
|
||||
}
|
||||
|
||||
start_menu_open = false;
|
||||
|
|
@ -1881,9 +1881,9 @@ void wm_handle_right_click(int x, int y) {
|
|||
} else if (str_starts_with(start_menu_pending_app, "About")) {
|
||||
wm_bring_to_front(&win_about);
|
||||
} else if (str_starts_with(start_menu_pending_app, "Shutdown")) {
|
||||
cli_cmd_shutdown(NULL);
|
||||
k_shutdown();
|
||||
} else if (str_starts_with(start_menu_pending_app, "Restart")) {
|
||||
cli_cmd_reboot(NULL);
|
||||
k_reboot();
|
||||
}
|
||||
|
||||
start_menu_pending_app = NULL;
|
||||
|
|
|
|||
Loading…
Reference in a new issue