Benutzer-Werkzeuge

Webseiten-Werkzeuge


start

Dies ist eine alte Version des Dokuments!


#include "kernel.h"
#include "utils.h"
#include "char.h"
#include "keyboard.h"

// Keyboard I/O
#define KBD_DATA   0x60
#define KBD_STATUS 0x64

// Cursor ports
#define VGA_CRTC_INDEX 0x3D4
#define VGA_CRTC_DATA  0x3D5

#define VGA_W 80
#define VGA_H (BUFSIZE / VGA_W)

uint32 vga_index;
static uint32 next_line_index = 1;
uint8 g_fore_color = WHITE, g_back_color = BLUE;

char str[128] = {0};
int  strc = 0;

uint8 inb(uint16 port)
{
  uint8 ret;
  asm volatile("inb %1, %0" : "=a"(ret) : "d"(port));
  return ret;
}

void outb(uint16 port, uint8 data)
{
  asm volatile("outb %0, %1" : : "a"(data), "d"(port));
}

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

static inline uint8 kbd_read_data(void)
{
  return inb(KBD_DATA);
}

// ---- tiny I/O wait (optional but useful) ----
static inline void io_wait(void)
{
  // klassischer "I/O wait" port
  asm volatile ("outb %0, %1" : : "a"(0), "Nd"(0x80));
}

// --- repeat filter state ---
static uint8 key_down[128] = {0};
static uint8 e0_prefix = 0;

// returns 1 if a NEW key press (make) should be processed, else 0
int get_keycode_once(uint8 *out_scancode)
{
  if (!kbd_has_data()) return 0;

  uint8 sc = kbd_read_data();

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

  // If we currently don't support E0 keys: discard next byte cleanly
  if (e0_prefix) { e0_prefix = 0; return 0; }

  // Break (release)
  if (sc & 0x80) {
    uint8 make = sc & 0x7F;
    if (make < 128) key_down[make] = 0;
    return 0;
  }

  // Make (press) - suppress repeats
  if (sc < 128) {
    if (key_down[sc]) return 0; // typematic repeat ignore
    key_down[sc] = 1;
  }

  *out_scancode = sc;
  return 1;
}

static inline 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));
}

uint16 vga_entry(unsigned char ch, uint8 fore_color, uint8 back_color)
{
  uint16 ax = 0;
  uint8 attr = (back_color << 4) | (fore_color & 0x0F);
  ax = ((uint16)attr << 8) | (uint16)ch;
  return ax;
}

void clear_vga_buffer(uint16 **buffer, uint8 fore_color, uint8 back_color)
{
  for (uint32 i = 0; i < BUFSIZE; i++)
    (*buffer)[i] = vga_entry(' ', fore_color, back_color);

  next_line_index = 1;
  vga_index = 0;
  vga_set_cursor((uint16)vga_index);
}

void init_vga(uint8 fore_color, uint8 back_color)
{
  vga_buffer = (uint16*)VGA_ADDRESS;
  clear_vga_buffer(&vga_buffer, fore_color, back_color);
  g_fore_color = fore_color;
  g_back_color = back_color;
}

// ---- SCROLL statt komplettes Löschen ----
static void vga_scroll_if_needed(void)
{
  if (vga_index < BUFSIZE) return;

  // scroll um 1 Zeile nach oben
  for (uint32 i = 0; i < (VGA_H - 1) * VGA_W; i++)
    vga_buffer[i] = vga_buffer[i + VGA_W];

  // letzte Zeile leeren
  for (uint32 i = (VGA_H - 1) * VGA_W; i < VGA_H * VGA_W; i++)
    vga_buffer[i] = vga_entry(' ', g_fore_color, g_back_color);

  vga_index = (VGA_H - 1) * VGA_W;
}

void print_new_line(void)
{
  // auf Zeilenanfang springen
  vga_index += VGA_W - (vga_index % VGA_W);
  vga_scroll_if_needed();
  vga_set_cursor((uint16)vga_index);

  // next_line_index ist jetzt eigentlich optional, aber falls du ihn weiter nutzt:
  next_line_index = (vga_index / VGA_W) + 1;
}

void print_char(char ch)
{
  if (ch == '\n') { print_new_line(); return; }

  vga_buffer[vga_index] = vga_entry(ch, g_fore_color, g_back_color);
  vga_index++;

  vga_scroll_if_needed();
  vga_set_cursor((uint16)vga_index);
}

void print_string(char *s)
{
  for (uint32 i = 0; s[i]; i++)
    print_char(s[i]);
}

// ---- FIX: wait_for_io Underflow bug ----
void wait_for_io(uint32 timer_count)
{
  while (timer_count--) {
    asm volatile("nop");
  }
}

void sleep(uint32 timer_count)
{
  wait_for_io(timer_count);
}

// ---- kleiner case-insensitive Vergleich ----
static int streq_ci(const char *a, const char *b)
{
  while (*a && *b) {
    char ca = *a, cb = *b;
    if (ca >= 'a' && ca <= 'z') ca -= 32;
    if (cb >= 'a' && cb <= 'z') cb -= 32;
    if (ca != cb) return 0;
    a++; b++;
  }
  return (*a == 0 && *b == 0);
}

static void reset_input_line(void)
{
  strc = 0;
  str[0] = 0;
}

static void append_char(char ch)
{
  if (strc >= (int)sizeof(str) - 1) return; // bounds check
  str[strc++] = ch;
  str[strc] = 0;
  print_char(ch);
}

void loop(void)
{
  uint8 keycode;

  while (1) {

    if (!get_keycode_once(&keycode)) {
      // CPU nicht verheizen: schlafen.
      // Achtung: hlt braucht Interrupts; falls die bei dir noch nicht an sind,
      // kannst du statt hlt ein kleines wait_for_io() nutzen.
      asm volatile("hlt");
      continue;
    }

    if (keycode == KEY_ENTER) {
      print_new_line();

      // Command ausführen
      if (strc > 0) {
        if (streq_ci(str, "HELP")) {
          print_string("Available commands:");
          print_new_line();
          print_string("    help - Prints this help");
          print_new_line();
        }
        // hier später weitere Commands...
      }

      // neues Prompt
      print_string("> ");
      reset_input_line();
      continue;
    }

    if (keycode == KEY_BACKSPACE) {
      // nur löschen, wenn wir nach dem Prompt sind und auch was im Buffer ist
      if (strc > 0 && vga_index > 0) {
        // optional: Schutz, dass du nicht ins Prompt reinlöschst
        uint32 prompt_start = (vga_index / VGA_W) * VGA_W + 2; // "> " = 2 chars
        if (vga_index > prompt_start) {
          vga_index--;
          strc--;
          str[strc] = 0;
          vga_buffer[vga_index] = vga_entry(' ', g_fore_color, g_back_color);
          vga_set_cursor((uint16)vga_index);
        }
      }
      continue;
    }

    if (keycode == KEY_SPACE) {
      append_char(' ');
      continue;
    }

    char ch = get_ascii_char(keycode);

    // Erlaubte Zeichen: A-Z, 0-9, '.', ' '
    if (ch == '.' || ch == ' ' ||
        (ch >= 'A' && ch <= 'Z') ||
        (ch >= '0' && ch <= '9')) {
      append_char(ch);
    }

    // kein riesiger busy-sleep mehr nötig
    io_wait();
  }
}

void kernel_entry(void)
{
  init_vga(WHITE, BLUE);
  print_string("Kernel-OS v1.0");
  print_new_line();
  print_string("(C) Manuel Zarat");
  print_new_line();
  print_string("Type \"HELP\" for help");
  print_new_line();
  print_string("> ");
  reset_input_line();
  loop();
}

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.1765010745.txt.gz · Zuletzt geändert: 2025/12/06 09:45 von jango