Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -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
17 changes: 17 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -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
Binary file removed build/boot.o
Binary file not shown.
Binary file removed build/kernel.bin
Binary file not shown.
Binary file removed build/kernel.o
Binary file not shown.
Binary file removed build/printf.o
Binary file not shown.
Binary file removed iso/boot/kernel.bin
Binary file not shown.
4 changes: 4 additions & 0 deletions kernel/boot.asm
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
; @lakladon: Bootloader for RetOS minimal shell
BITS 32

; @lakladon: Multiboot2 header section
section .multiboot
align 8
mb2_start:
Expand All @@ -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:
Expand Down
110 changes: 110 additions & 0 deletions kernel/kernel.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,120 @@
// @lakladon: Minimal shell implementation for RetOS
#include "printf.h"
#include <string.h>

// @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();

printf("*******************************\n");
printf(" RETOS \n");
printf(" COPYRIGHT: ANDY \n");
printf("*******************************\n");

printf("\nStarting minimal shell...\n");
shell_main_loop();
}
70 changes: 68 additions & 2 deletions kernel/printf.c
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@

#include "printf.h"
#include <stdarg.h>
#include <stddef.h>
#include <string.h>

// @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++;
Expand All @@ -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++) {
Expand All @@ -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');
Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions kernel/printf.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once

// @lakladon: Header file for printf functionality
void printf(const char* fmt, ...);
void clear_screen(void);
Binary file removed retos.iso
Binary file not shown.