Entwicklung eines monolithischen Unix-ähnlichen Betriebssystems - Kernel System Log (3)

Im vorherigen Artikel, dem zweiten in Folge, haben wir die erforderlichen Funktionen für die Arbeit mit Zeichenfolgen aus der C-Bibliothek entwickelt. In dieser Lektion implementieren wir eine vollständige Debugging-Ausgabe auf dem Bildschirm - das Kernel-Systemprotokoll.

Inhaltsverzeichnis


  1. Build-System (make, gcc, gas). Erster Start (Multiboot). Starten Sie (qemu). C-Bibliothek (strcpy, memcpy, strext).
  2. C-Bibliothek (sprintf, strcpy, strcmp, strtok, va_list ...). Erstellen der Bibliothek im Kernelmodus und im Benutzeranwendungsmodus.
  3. Das Kernel-Systemprotokoll. Videospeicher Ausgabe an das Terminal (kprintf, kpanic, kassert).
  4. Dynamischer Speicher, Heap (kmalloc, kfree).
  5. Organisation der Speicher- und Interrupt-Behandlung (GDT, IDT, PIC, Syscall). Ausnahmen
  6. Virtueller Speicher (Seitenverzeichnis und Seitentabelle).
  7. Prozess. Planer Multitasking. Systemaufrufe (kill, exit, ps).
  8. Das Dateisystem des Kernels (initrd), elf und seiner Interna. Systemaufrufe (exec).
  9. Zeichengerätetreiber. Systemaufrufe (ioctl, fopen, fread, fwrite). C-Bibliothek (fopen, fclose, fprintf, fscanf).
  10. Shell als komplettes Programm für den Kernel.
  11. Benutzerschutzmodus (Ring3). Aufgabenstatussegment (tss).

Kernel-Systemprotokoll


Bevor wir beginnen, müssen wir einige nützliche Funktionen für die Arbeit mit E / A-Ports einführen. E / A-Ports für einen Programmierer unterscheiden sich nicht von normalen Zellen im Speicher, außer dass es separate Befehle gibt, um sie zu bedienen. Geräte, die an diesen Ports arbeiten, sind mit dem Speicherbus verbunden. Es gibt auch einen eigenen Adressraum für sie. Wir benötigen zwei Assembler-Funktionen, um mit Eingabe- / Ausgabeports arbeiten zu können, da ich, wie Sie sich bereits erinnern, keine Assembler-Einfügungen toleriere.

extern u_char asm_read_port(u_char port); extern void asm_write_port(u_int port, u_char data); 

Ebenso zwei Befehle zum Steuern maskierter Prozessor-Interrupts.

 extern void asm_lock(); extern void asm_unlock(); 

Um nach schwerwiegenden Fehlern Energie zu sparen, benötigen Sie einen Prozessor-Stopp-Befehl.

 extern void asm_hlt(); 

Wie Sie sich erinnern, beginnt der Videospeicher bei 0xB8000, aber ich empfehle, zuerst Nachrichten im Nur-Text-Format in den Puffer zu schreiben. Und dann kopieren Sie diesen Puffer einfach unter Berücksichtigung der Farbattribute in den Videospeicher. Zu diesem Zweck habe ich mehrere Dienstprogramme für die Arbeit mit diesen Puffern implementiert. Ein Puffer ist für das Kernel-Syslog und der Rest für virtuelle Terminals. Das Scrollen des Bildschirms wird auch für den Puffer ausgeführt. Und nur die Funktion video_flush kopiert den Puffer in den Videospeicher und erweitert ihn um Attribute.

 extern void video_init(); extern void video_disable_cursor(); extern void* video_scroll(char const* video_buff, char* pos); extern char* video_clear(char const* video_buff); extern void video_flush(char const* video_buff); 

Jetzt ist es an der Zeit, die am häufigsten verwendeten Funktionen vorzustellen. Die letzten beiden werden zum Debuggen des Kernels verwendet, wenn Faulheit vom Debugger debuggt wird. Glauben Sie mir, ich habe noch nie einen Debugger verwendet, als ich diesen Kernel geschrieben habe.

 extern void kpanic(char* message, ...); extern void kassert(const char* file, u_int line, bool expr); extern void kunreachable(const char* file, u_int line); 

Nun, eigentlich Funktionen für die Arbeit mit dem Kernel-Systemprotokoll. Um zu steuern, was auf dem Bildschirm angezeigt wird, habe ich die kmode-Funktion im Systemprotokoll oder in der Benutzerkonsole eingegeben. Und um das Systemprotokoll in den Puffer einzulesen, benötigen Sie die Funktion klog, da Benutzerprozesse nur über Systemaufrufe Zugriff auf den Kernel haben.

 extern void kclear(); extern void kprintf(const char* format, ...); extern void kvprintf(const char* format, va_list list); extern void kmode(bool is_early); extern void klog(char* buf, u_int n); 

Ich gebe hier die interessantesten Funktionen:

 /* * Api - Scroll video buffer up * Returns new position */ extern void* video_scroll(char const* video_buff, char* pos) { char* ptr = (void*)video_buff; /* scroll up */ for (int i = 1; i < VIDEO_SCREEN_HEIGHT; ++i) { for (int j = 0; j < VIDEO_SCREEN_WIDTH; ++j) { ptr[(i - 1) * VIDEO_SCREEN_WIDTH + j] = ptr[i * VIDEO_SCREEN_WIDTH + j]; } } /* empty last line */ for (int j = 0; j < VIDEO_SCREEN_WIDTH; ++j) { ptr[(VIDEO_SCREEN_HEIGHT - 1) * VIDEO_SCREEN_WIDTH + j] = ' '; } /* move position up */ pos -= VIDEO_SCREEN_WIDTH; return pos; } 

 /* * Api - Print kernel message */ extern void kvprintf(const char* format, va_list list) { char buff[VIDEO_SCREEN_WIDTH]; int len = vsprintf(buff, format, list); for (int i = 0; i < len; ++i) { if (buff[i] != '\n') { kputc(buff[i]); } else { int line_pos = (syslog_pos - syslog) % VIDEO_SCREEN_WIDTH; for (int j = 0; j < VIDEO_SCREEN_WIDTH - line_pos; ++j) { kputc(' '); } } } kflush(); } 

 /* * Put character to syslog */ static void kputc(char ch) { if ((size_t)syslog_pos - (size_t)syslog + 1 < VIDEO_SCREEN_SIZE) { *syslog_pos++ = ch; } else { syslog_pos = video_scroll(syslog, syslog_pos); kputc(ch); } } 

Siehe das ausführliche Tutorial im Video-Tutorial.

Referenzen


Video-Tutorial zu diesem Artikel
Quellcode (Sie benötigen einen Lektion3-Zweig)

Referenzliste


  1. James Molloy. Rollen Sie Ihr eigenes UNIX-Klon-Betriebssystem.
  2. Zubkov. Assembler für DOS, Windows, Unix
  3. Kalaschnikow. Assembler ist einfach!
  4. Tanenbaum. Betriebssysteme. Implementierung und Entwicklung.
  5. Robert Love. Linux-Kernel Beschreibung des Entwicklungsprozesses.

Source: https://habr.com/ru/post/de466765/


All Articles