Benutzer-Werkzeuge

Webseiten-Werkzeuge


start

Dies ist eine alte Version des Dokuments!


// kernel.c  (freestanding, 32-bit)
// Minimal "better kernel": VGA terminal + keyboard driver + tiny shell.
// You can split this later into vga.c/keyboard.c/shell.c.

#include <stddef.h>

// -------- types (if you already have uint8/uint16/uint32 in utils.h, remove these) -----
typedef unsigned char  uint8;
typedef unsigned short uint16;
typedef unsigned int   uint32;

// -------- port I/O ----------
static inline void outb(uint16_t port, uint8_t val) {
    asm volatile ("outb %b0, %w1"
                  :
                  : "a"(val), "Nd"(port));
}

static inline uint8_t inb(uint16_t port) {
    uint8_t ret;
    asm volatile ("inb %w1, %b0"
                  : "=a"(ret)
                  : "Nd"(port));
    return ret;
}

static inline void io_wait(void) {
    // 0x80 ist klassisch "slow" I/O port
    asm volatile ("outb %b0, %w1" : : "a"((uint8_t)0), "Nd"((uint16_t)0x80));
}

// -------- very small utils (no libc) ----------
static void *memset_(void *dst, int v, size_t n) {
    uint8 *p = (uint8*)dst;
    while (n--) *p++ = (uint8)v;
    return dst;
}
static void *memmove_(void *dst, const void *src, size_t n) {
    uint8 *d = (uint8*)dst;
    const uint8 *s = (const uint8*)src;
    if (d == s || n == 0) return dst;
    if (d < s) { while (n--) *d++ = *s++; }
    else { d += n; s += n; while (n--) *--d = *--s; }
    return dst;
}
static size_t strlen_(const char *s) {
    size_t n = 0;
    while (s && s[n]) n++;
    return n;
}
static int isspace_(char c) { return c==' ' || c=='\t' || c=='\n' || c=='\r'; }
static int tolower_(int c) { return (c>='A' && c<='Z') ? (c+32) : c; }
static int strcmpi_(const char *a, const char *b) {
    while (*a && *b) {
        int ca = tolower_(*a), cb = tolower_(*b);
        if (ca != cb) return ca - cb;
        a++; b++;
    }
    return tolower_(*a) - tolower_(*b);
}

// -------- VGA terminal ----------
#define VGA_ADDRESS     0xB8000
#define VGA_W           80
#define VGA_H           25
#define VGA_CRTC_INDEX  0x3D4
#define VGA_CRTC_DATA   0x3D5

enum vga_color {
    BLACK=0, BLUE=1, GREEN=2, CYAN=3, RED=4, MAGENTA=5, BROWN=6, LIGHT_GREY=7,
    DARK_GREY=8, LIGHT_BLUE=9, LIGHT_GREEN=10, LIGHT_CYAN=11, LIGHT_RED=12,
    LIGHT_MAGENTA=13, LIGHT_BROWN=14, WHITE=15
};

static volatile uint16 *g_vga = (volatile uint16*)VGA_ADDRESS;
static uint8 g_fg = WHITE, g_bg = BLUE;
static uint16 g_cursor = 0; // 0..(VGA_W*VGA_H-1)

static inline uint16 vga_entry(char ch, uint8 fg, uint8 bg) {
    uint8 attr = (uint8)((bg << 4) | (fg & 0x0F));
    return (uint16)((uint16)attr << 8) | (uint8)ch;
}
static void vga_set_cursor(uint16 pos) {
    outb(VGA_CRTC_INDEX, 0x0F);
    outb(VGA_CRTC_DATA, (uint8)(pos & 0xFF));
    outb(VGA_CRTC_INDEX, 0x0E);
    outb(VGA_CRTC_DATA, (uint8)((pos >> 8) & 0xFF));
}
static void term_set_color(uint8 fg, uint8 bg) { g_fg = fg; g_bg = bg; }

static void term_clear(void) {
    for (uint32 i=0; i < VGA_W*VGA_H; i++) g_vga[i] = vga_entry(' ', g_fg, g_bg);
    g_cursor = 0;
    vga_set_cursor(g_cursor);
}

static void term_scroll_if_needed(void) {
    uint32 row = g_cursor / VGA_W;
    if (row < VGA_H) return;

    // scroll up 1 row
    memmove_((void*)g_vga, (const void*)(g_vga + VGA_W), (VGA_H-1)*VGA_W*sizeof(uint16));
    // clear last row
    for (uint32 i=(VGA_H-1)*VGA_W; i < VGA_H*VGA_W; i++)
        g_vga[i] = vga_entry(' ', g_fg, g_bg);

    g_cursor = (VGA_H-1)*VGA_W;
}

static void term_putc(char c) {
    if (c == '\n') {
        g_cursor += VGA_W - (g_cursor % VGA_W);
        term_scroll_if_needed();
        vga_set_cursor(g_cursor);
        return;
    }
    if (c == '\r') return;

    g_vga[g_cursor++] = vga_entry(c, g_fg, g_bg);
    term_scroll_if_needed();
    vga_set_cursor(g_cursor);
}
static void term_write(const char *s) {
    for (size_t i=0; s && s[i]; i++) term_putc(s[i]);
}

// backspace within the current line (won't jump to prev line here)
static void term_backspace(void) {
    if (g_cursor == 0) return;
    // don't backspace over prompt " > " (simple guard: stop at col 2)
    uint16 col = g_cursor % VGA_W;
    if (col <= 2) return;

    g_cursor--;
    g_vga[g_cursor] = vga_entry(' ', g_fg, g_bg);
    vga_set_cursor(g_cursor);
}

// -------- Keyboard (polling, robust, no busy-wait bugs) ----------
#define KBD_DATA    0x60
#define KBD_STATUS  0x64

static inline uint8 kbd_has_data(void) { return (inb(KBD_STATUS) & 0x01); }
static inline uint8 kbd_read_scancode(void) { return inb(KBD_DATA); }

// simple typematic repeat filter (like your idea, but safe)
static uint8 key_down[128];
static uint8 e0_prefix;

// scancode set 1 maps
static const char map_norm[128] = {
    [0x02]='1',[0x03]='2',[0x04]='3',[0x05]='4',[0x06]='5',[0x07]='6',[0x08]='7',[0x09]='8',[0x0A]='9',[0x0B]='0',
    [0x0C]='-',[0x0D]='=',
    [0x10]='q',[0x11]='w',[0x12]='e',[0x13]='r',[0x14]='t',[0x15]='y',[0x16]='u',[0x17]='i',[0x18]='o',[0x19]='p',
    [0x1A]='[',[0x1B]=']',
    [0x1E]='a',[0x1F]='s',[0x20]='d',[0x21]='f',[0x22]='g',[0x23]='h',[0x24]='j',[0x25]='k',[0x26]='l',
    [0x27]=';',[0x28]='\'',[0x29]='`',
    [0x2B]='\\',
    [0x2C]='z',[0x2D]='x',[0x2E]='c',[0x2F]='v',[0x30]='b',[0x31]='n',[0x32]='m',
    [0x33]=',',[0x34]='.',[0x35]='/',
    [0x39]=' ',
};

static const char map_shift[128] = {
    [0x02]='!',[0x03]='@',[0x04]='#',[0x05]='$',[0x06]='%',[0x07]='^',[0x08]='&',[0x09]='*',[0x0A]='(',[0x0B]=')',
    [0x0C]='_',[0x0D]='+',
    [0x10]='Q',[0x11]='W',[0x12]='E',[0x13]='R',[0x14]='T',[0x15]='Y',[0x16]='U',[0x17]='I',[0x18]='O',[0x19]='P',
    [0x1A]='{',[0x1B]='}',
    [0x1E]='A',[0x1F]='S',[0x20]='D',[0x21]='F',[0x22]='G',[0x23]='H',[0x24]='J',[0x25]='K',[0x26]='L',
    [0x27]=':',[0x28]='"',[0x29]='~',
    [0x2B]='|',
    [0x2C]='Z',[0x2D]='X',[0x2E]='C',[0x2F]='V',[0x30]='B',[0x31]='N',[0x32]='M',
    [0x33]='<',[0x34]='>',[0x35]='?',
    [0x39]=' ',
};

static uint8 kbd_shift;
static uint8 kbd_caps;

static int kbd_get_scancode_once(uint8 *out_sc) {
    if (!kbd_has_data()) return 0;
    uint8 sc = kbd_read_scancode();

    if (sc == 0xE0) { e0_prefix = 1; return 0; }

    // break (release)
    if (sc & 0x80) {
        uint8 make = sc & 0x7F;
        if (!e0_prefix && make < 128) key_down[make] = 0;
        // handle shift release
        if (!e0_prefix && (make == 0x2A || make == 0x36)) kbd_shift = 0;
        e0_prefix = 0;
        return 0;
    }

    // make (press) - ignore typematic repeats
    if (!e0_prefix && sc < 128) {
        if (key_down[sc]) return 0;
        key_down[sc] = 1;
    }

    e0_prefix = 0;
    *out_sc = sc;
    return 1;
}

static char kbd_translate(uint8 sc) {
    // modifiers
    if (sc == 0x2A || sc == 0x36) { kbd_shift = 1; return 0; } // shift
    if (sc == 0x3A) { kbd_caps ^= 1; return 0; }               // caps lock

    // special keys
    if (sc == 0x1C) return '\n'; // enter
    if (sc == 0x0E) return '\b'; // backspace
    if (sc == 0x0F) return '\t'; // tab (optional)

    char c = kbd_shift ? map_shift[sc] : map_norm[sc];
    if (!c) return 0;

    // caps only affects letters (and only if shift isn't producing uppercase already)
    if (kbd_caps && !kbd_shift && (c >= 'a' && c <= 'z')) c = (char)(c - 32);
    return c;
}

// blocking getchar (polling). If you have timer IRQs enabled, you can use hlt to reduce CPU.
static char kbd_getchar(void) {
    for (;;) {
        uint8 sc;
        if (kbd_get_scancode_once(&sc)) {
            char c = kbd_translate(sc);
            if (c) return c;
        } else {
            // reduce busy loop a bit
            io_wait();
            // OPTIONAL (only if interrupts are enabled):
            // asm volatile("hlt");
        }
    }
}

// -------- tiny shell ----------
#define LINE_MAX 128

static void shell_prompt(void) {
    term_putc('\n');
    term_write("> ");
}

static void cmd_help(void) {
    term_write("Commands:\n");
    term_write("  help           - this help\n");
    term_write("  clear          - clear screen\n");
    term_write("  echo <text>    - print text\n");
    term_write("  color <fg> <bg>- set colors (0-15)\n");
    term_write("  reboot         - triple-fault/8042 reboot\n");
}

static int parse_u8_dec(const char *s, uint8 *out) {
    if (!s || !*s) return 0;
    uint32 v = 0;
    for (; *s; s++) {
        if (*s < '0' || *s > '9') return 0;
        v = v*10u + (uint32)(*s - '0');
        if (v > 255u) return 0;
    }
    *out = (uint8)v;
    return 1;
}

static void do_reboot(void) {
    // try 8042 reboot pulse
    outb(0x64, 0xFE);
    // fallback: halt
    for (;;) asm volatile("hlt");
}

static void shell_exec(char *line) {
    // tokenize in-place
    char *argv[8] = {0};
    int argc = 0;

    // skip leading spaces
    while (*line && isspace_(*line)) line++;

    while (*line && argc < 8) {
        argv[argc++] = line;
        while (*line && !isspace_(*line)) line++;
        if (!*line) break;
        *line++ = 0;
        while (*line && isspace_(*line)) line++;
    }
    if (argc == 0) return;

    if (strcmpi_(argv[0], "help") == 0) {
        cmd_help();
        return;
    }
    if (strcmpi_(argv[0], "clear") == 0) {
        term_clear();
        return;
    }
    if (strcmpi_(argv[0], "echo") == 0) {
        if (argc >= 2) {
            term_write(argv[1]);
            for (int i=2; i<argc; i++) { term_putc(' '); term_write(argv[i]); }
        }
        term_putc('\n');
        return;
    }
    if (strcmpi_(argv[0], "color") == 0) {
        uint8 fg, bg;
        if (argc == 3 && parse_u8_dec(argv[1], &fg) && parse_u8_dec(argv[2], &bg) && fg < 16 && bg < 16) {
            term_set_color(fg, bg);
            term_write("ok\n");
        } else {
            term_write("usage: color <fg 0-15> <bg 0-15>\n");
        }
        return;
    }
    if (strcmpi_(argv[0], "reboot") == 0) {
        term_write("rebooting...\n");
        do_reboot();
        return;
    }

    term_write("unknown command: ");
    term_write(argv[0]);
    term_putc('\n');
}

static void shell_run(void) {
    char line[LINE_MAX];
    size_t len = 0;
    memset_(line, 0, sizeof(line));

    term_write("Kernel-OS v2.0\n");
    term_write("(C) Manuel Zarat (improved)\n");
    term_write("Type 'help' for commands.\n");
    term_write("> ");

    for (;;) {
        char c = kbd_getchar();

        if (c == '\b') {
            if (len > 0) {
                len--;
                line[len] = 0;
                term_backspace();
            }
            continue;
        }

        if (c == '\n') {
            term_putc('\n');
            shell_exec(line);
            memset_(line, 0, sizeof(line));
            len = 0;
            term_write("> ");
            continue;
        }

        // printable range: keep it simple
        if (c >= 32 && c <= 126) {
            if (len < LINE_MAX - 1) {
                line[len++] = c;
                line[len] = 0;
                term_putc(c);
            }
        }
    }
}

// -------- entry ----------
void kernel_entry(void) {
    term_set_color(WHITE, BLUE);
    term_clear();
    shell_run();
}

Hallo Besucher! Willkommen in diesem kleinen Wiki rund um IT. Vieles ist noch unvollständig, unstrukturiert oder vielleicht sogar falsch bzw. irreführend.

Du kannst Artikel gerne ergänzen oder verbessern. Gerne mit so vielen Links wie nötig. Bitte keine Werbelinks und nur selbst verfasste oder lizenzfreie Texte! Copyright beachten!

Fehlende Verlinkungen

start.1765009997.txt.gz · Zuletzt geändert: 2025/12/06 09:33 von jango