diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..23b9c5a --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,42 @@ +name: Build and Deploy RetOS + +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install build dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + nasm \ + gcc \ + xorriso \ + grub-pc-bin \ + qemu-system-x86 + + - name: Build RetOS + run: | + make clean + make iso + + - name: Upload ISO artifact + uses: actions/upload-artifact@v4 + with: + name: retos.iso + path: build/retos.iso + + - name: Test boot with QEMU (optional) + run: | + # Test that the ISO can be created (QEMU not run in CI for performance) + ls -la build/retos.iso + file build/retos.iso \ No newline at end of file diff --git a/Makefile b/Makefile index e69de29..f183c4d 100644 --- a/Makefile +++ b/Makefile @@ -0,0 +1,17 @@ +make: + + nasm -f elf32 kernel/boot.asm -o build/boot.o + gcc -m32 -ffreestanding -c kernel/kernel.c -o build/kernel.o + gcc -m32 -ffreestanding -c kernel/printf.c -o build/printf.o + ld -m elf_i386 -T kernel/linker.ld -o build/kernel.bin \ + build/boot.o build/kernel.o build/printf.o + +iso: make + mkdir -p iso/boot/grub + cp build/kernel.bin iso/boot/ + cp boot/grub/grub.cfg iso/boot/grub/ + grub-mkrescue -o build/retos.iso iso/ + +clean: + rm -rf build/* + rm -rf iso/boot/kernel.bin diff --git a/build/boot.o b/build/boot.o deleted file mode 100644 index 8a2f8e4..0000000 Binary files a/build/boot.o and /dev/null differ diff --git a/build/kernel.bin b/build/kernel.bin deleted file mode 100644 index db3fa79..0000000 Binary files a/build/kernel.bin and /dev/null differ diff --git a/build/kernel.o b/build/kernel.o deleted file mode 100644 index 0f8471e..0000000 Binary files a/build/kernel.o and /dev/null differ diff --git a/build/printf.o b/build/printf.o deleted file mode 100644 index cb6188a..0000000 Binary files a/build/printf.o and /dev/null differ diff --git a/iso/boot/kernel.bin b/iso/boot/kernel.bin deleted file mode 100644 index db3fa79..0000000 Binary files a/iso/boot/kernel.bin and /dev/null differ diff --git a/kernel/boot.asm b/kernel/boot.asm index 873b085..1eff080 100644 --- a/kernel/boot.asm +++ b/kernel/boot.asm @@ -1,5 +1,7 @@ +; @lakladon: Bootloader for RetOS minimal shell BITS 32 +; @lakladon: Multiboot2 header section section .multiboot align 8 mb2_start: @@ -13,10 +15,12 @@ mb2_start: dd 8 mb2_end: +; @lakladon: Text section with entry point section .text global _start extern kernel_main +; @lakladon: Boot entry point _start: call kernel_main .hang: diff --git a/kernel/kernel.c b/kernel/kernel.c index c92baa3..2e6affe 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -1,5 +1,112 @@ +// @lakladon: Minimal shell implementation for RetOS #include "printf.h" +#include +// @lakladon: Shell configuration constants +#define MAX_CMD_LEN 128 +#define MAX_ARGS 8 + +// @lakladon: Command buffer and position tracking +static char cmd_buffer[MAX_CMD_LEN]; +static int cmd_pos = 0; + +// @lakladon: Print the shell prompt +static void shell_print_prompt(void) { + printf("\nretos> "); +} + +// @lakladon: Clear the command buffer +static void shell_clear_buffer(void) { + cmd_pos = 0; + cmd_buffer[0] = '\0'; +} + +// @lakladon: Add a character to the command buffer +static void shell_add_char(char c) { + if (cmd_pos < MAX_CMD_LEN - 1) { + cmd_buffer[cmd_pos++] = c; + cmd_buffer[cmd_pos] = '\0'; + vga_putc(c); + } +} + +// @lakladon: Handle backspace in command buffer +static void shell_backspace(void) { + if (cmd_pos > 0) { + cmd_pos--; + cmd_buffer[cmd_pos] = '\0'; + printf("\b \b"); + } +} + +// @lakladon: Tokenize command string into arguments +static int shell_tokenize(char* cmd, char** args) { + int argc = 0; + char* token = strtok(cmd, " "); + + while (token != NULL && argc < MAX_ARGS - 1) { + args[argc++] = token; + token = strtok(NULL, " "); + } + args[argc] = NULL; + return argc; +} + +// @lakladon: Execute shell commands +static void shell_execute_command(char** args, int argc) { + if (argc == 0) return; + + if (strcmp(args[0], "help") == 0) { + printf("\nAvailable commands:\n"); + printf(" help - Show this help message\n"); + printf(" clear - Clear the screen\n"); + printf(" echo - Echo text\n"); + printf(" exit - Exit shell\n"); + } + else if (strcmp(args[0], "clear") == 0) { + clear_screen(); + } + else if (strcmp(args[0], "echo") == 0) { + for (int i = 1; i < argc; i++) { + printf("%s ", args[i]); + } + printf("\n"); + } + else if (strcmp(args[0], "exit") == 0) { + printf("\nGoodbye!\n"); + while(1); // Halt + } + else { + printf("\nUnknown command: %s\n", args[0]); + printf("Type 'help' for available commands.\n"); + } +} + +// @lakladon: Main shell loop +static void shell_main_loop(void) { + shell_print_prompt(); + + while (1) { + // Wait for keyboard input (simplified polling) + // In a real implementation, this would use interrupts + char c = 0; + + // Simple polling for demonstration + // This is a placeholder - actual keyboard handling would be more complex + for (volatile int i = 0; i < 100000; i++); + + // For now, simulate a simple command processor + // In a real shell, this would read from keyboard buffer + + // This is a minimal implementation - normally you'd have proper + // keyboard interrupt handling and input buffering + printf("\nShell running (minimal implementation)\n"); + printf("Type 'help' for commands, 'exit' to quit\n"); + break; // Exit after one iteration for now + } +} + +// @lakladon: Main kernel entry point with shell void kernel_main(void) { clear_screen(); @@ -7,4 +114,7 @@ void kernel_main(void) { printf(" RETOS \n"); printf(" COPYRIGHT: ANDY \n"); printf("*******************************\n"); + + printf("\nStarting minimal shell...\n"); + shell_main_loop(); } diff --git a/kernel/printf.c b/kernel/printf.c index b4d0af1..149c874 100644 --- a/kernel/printf.c +++ b/kernel/printf.c @@ -1,19 +1,24 @@ #include "printf.h" #include +#include +#include +// @lakladon: VGA text mode constants #define VGA_WIDTH 80 #define VGA_HEIGHT 25 +// @lakladon: VGA memory address static volatile unsigned char* const VGA_MEMORY = (volatile unsigned char*)0xB8000; - +// @lakladon: Cursor position variables static int cursor_x = 0; static int cursor_y = 0; static char color = 0x0F; // white on black -static void vga_putc(char c) { +// @lakladon: Put a character to VGA memory +void vga_putc(char c) { if (c == '\n') { cursor_x = 0; cursor_y++; @@ -31,6 +36,7 @@ static void vga_putc(char c) { } } +// @lakladon: Clear the entire screen void clear_screen(void) { for (int y = 0; y < VGA_HEIGHT; y++) { for (int x = 0; x < VGA_WIDTH; x++) { @@ -43,6 +49,7 @@ void clear_screen(void) { cursor_y = 0; } +// @lakladon: Print decimal number to screen static void print_dec(int num) { if (num == 0) { vga_putc('0'); @@ -62,6 +69,65 @@ static void print_dec(int num) { } } +// @lakladon: String comparison function +int strcmp(const char* s1, const char* s2) { + while (*s1 && (*s1 == *s2)) { + s1++; + s2++; + } + return *(const unsigned char*)s1 - *(const unsigned char*)s2; +} + +// @lakladon: String tokenization function +char* strtok(char* str, const char* delimiters) { + static char* next_token = NULL; + char* token; + + if (str != NULL) { + next_token = str; + } + + if (next_token == NULL || *next_token == '\0') { + return NULL; + } + + // Skip leading delimiters + while (*next_token && strchr(delimiters, *next_token)) { + next_token++; + } + + if (*next_token == '\0') { + return NULL; + } + + token = next_token; + + // Find the end of the token + while (*next_token && !strchr(delimiters, *next_token)) { + next_token++; + } + + // Replace delimiter with null terminator and move past it + if (*next_token) { + *next_token = '\0'; + next_token++; + } + + return token; +} + +// @lakladon: Find character in string +char* strchr(const char* str, int c) { + while (*str != (char)c) { + if (*str == '\0') { + return NULL; + } + str++; + } + return (char*)str; +} + +// @lakladon: Formatted print function void printf(const char* fmt, ...) { va_list args; va_start(args, fmt); diff --git a/kernel/printf.h b/kernel/printf.h index 8add228..c5f4535 100644 --- a/kernel/printf.h +++ b/kernel/printf.h @@ -1,4 +1,5 @@ #pragma once +// @lakladon: Header file for printf functionality void printf(const char* fmt, ...); void clear_screen(void); diff --git a/retos.iso b/retos.iso deleted file mode 100644 index 3cc7675..0000000 Binary files a/retos.iso and /dev/null differ