Dies ist kein echtes Betriebssystem. Es ist nur ein einfaches Betriebssystem, das in Bildungszwecken erstellt wurde.
Das Hauptziel, das ich folge, ist zu erfahren, wie OS von Grund auf funktioniert. Ausgehend von dem eigenen Bootsektor, Hardware und Software -Interrupts, eigenen Treiber.
Das Repository ist mit GCC satt, weil ich vorhabe, ein anderes einfaches Betriebssystem mit Rost zu schreiben. Ich hoffe, es wird Ghaiklor-Os-GCC und Ghaiklor-Os-Rustc geben.
| Hallo Welt |
|---|
Ghaiklor-Os-GCC besteht aus zwei Dateien im Binärformat: Boot.bin und Kernel.bin . Sie befinden sich in Boot/Boot.bin und Kernel/Kernel.bin entsprechend nach dem Kompilieren.
Boot.bin wird über NASM kompiliert. Makefile nimmt Boot/boot.asm und nennt nasm boot/boot.asm -f bin -o boot/boot.bin . Die NASM -Griffe umfassen von Unterordnern selbst, sodass alle Montagedateien mit binär zusammengestellt werden. Nichts anderes, einfach.
Kernel.bin wird über Cross-Compiler GCC und LD zusammengestellt, die Sie installieren müssen. Schauen Sie sich den Abschnitt Entwicklungsumgebung an. Nach der Installation von Cross-Compiler können wir Quellen von CPU , Treiber , Kernel- und LIBC- Ordnern rekursiv nehmen. Alle .C -Dateien werden über gcc zusammengestellt. Kompilierte Objektdateien werden zum Kompilieren ld -o kernel/kernel.bin -Ttext 0x1000 <OBJ_FILES> --oformat binary Kernel verwendet.
Os-Image.bin ist zusammengestellt concattenate von boot.bin und kernel.bin . Leicht mit cat boot/boot.bin kernel/kernel.bin > os-image.bin .
Ich hatte bootstrap.sh -Skript geschrieben, das Sie ausführen können. Es wird alle erforderlichen Abhängigkeiten für Ihren Host -Computer installiert.
bash bootstrap.shWenn ein Computer eingeschaltet ist oder zurückgesetzt wird, wird eine Reihe von Diagnostika bezeichnet, die als Post-On-Selbst-Test bezeichnet werden. Diese Sequenz gipfelt bei der Lokalisierung eines bootfähigen Geräts wie Diskette, Cdrom oder Festplatte.
Ein Gerät ist bootfähig, wenn es einen Startsektor mit der Byte -Sequenz 0x55 , 0xAA in Bytes 511 bzw. 512 trägt. Wenn das BIOS einen solchen Startsektor findet, wird es bei 0x0000:0x7C00 in den Speicher geladen.
Eine einfache Implementierung von bootfähigem Gerät:
jmp $
times 510 - ($ - $$) db 0
dw 0xAA55 $ - $$ führt zu CURRENT_POINTER - START_POINTER . Auf diese Weise berechnen wir, wie lange unser Boot -Datensatz dauert. Anschließend sind wir Substract 510 davon und füllen mit Nullen, wobei der 512 -Bytes -Boot -Datensatz mit dem Startsektor Signature erhalten wird.
Zum Beispiel haben wir $ - $$ gleich 100. Also haben wir 510 - 100 = 410 freie Bytes. Wir füllen diese 410 Bytes mit Nullen. Und die letzten beiden Bytes 511 und 512 sind bootfähige Signatur, die wir mit dw 0xAA55 füllen.
Erledigt! Wir haben unser bootfähiges Gerät und können unseren jmp $ durch jeden Code ersetzen, den Sie mögen.
Bootsektor -Implementierung
Zu Beginn wird unser Code im realen Modus ausgeführt.
Der Real-Modus ist ein simpeler 16-Bit-Modus, der bei allen X86-Prozessoren vorhanden ist. Der Real -Modus war das erste X86 -Modus -Design und wurde von vielen frühen Betriebssystemen verwendet. Für Kompatibilitätszwecke beginnen alle X86 -Prozessoren im realen Modus auszuführen.
Was ist im realen Modus schlecht und gut?
Nachteile
Profis
Aufgrund der vielen Einschränkungen und Probleme, die der reale Modus hat, müssen wir in den geschützten Modus wechseln.
Der geschützte Modus ist der Hauptbetriebsmodus moderner Intel -Prozessoren seit dem 80286. Er ermöglicht die Arbeit mit mehreren virtuellen Adressräumen, von denen jedes maximal 4 GB adressierbares Speicher aufweist.
Da die vom BIOS initialisierte CPU im realen Modus beginnt, verhindert das Umschalten in den geschützten Modus die Verwendung der meisten BIOS -Interrupts. Bevor Sie in den geschützten Modus wechseln, müssen Sie Interrupts, einschließlich NMI, deaktivieren, die A20 -Zeile aktivieren und die globale Deskriptortabelle laden.
Algorithmus zum Umschalten in den geschützten Modus:
cli
lgdt [ gdt_descriptor ]
mov eax , cr0
or eax , 0x1
mov cr0 , eax
jmp CODE_SEG:init_pmImplementierung zum Wechsel zu PM
Globale Deskriptortabelle
Aber wir können weiter gehen ...
Was ist ein langer Modus und warum errichtet es?
Seit der Einführung der X86-64-Prozessoren wurde ebenfalls ein neuer Modus eingeführt, der als Long-Modus bezeichnet wird. Der Long-Modus besteht grundsätzlich aus zwei Sub-Modi, nämlich der tatsächliche 64-Bit-Modus und den Kompatibilitätsmodus (32-Bit).
Wir interessieren uns einfach im 64-Bit-Modus, da dieser Modus viele neue Funktionen bietet wie:
Vor dem Umschalten in den langen Modus müssen wir überprüfen, ob die CPU diesen Modus unterstützt. Falls CPU keinen Long -Modus unterstützt, müssen wir den geschützten Modus fallen.
Erkennen, ob der lange Modus unterstützt wird
Wenn ja, wechseln Sie in den langen Modus
Alle diese Modi sind großartig, aber wir können kein Betriebssystem in 512 Bytes schreiben. Unser Startsektor muss also wissen, wie wir unseren kompilierten Kernel von der Festplatte laden.
Wenn wir uns im realen Modus befinden, können wir BIOS -Interrupts zum Lesen von der Festplatte verwenden. In unserem Fall ist INT 13,2 - Read Disk Sectors .
Wie benutze ich es?
;; al = number of sectors to read (1 - 128)
;; ch = track/cylinder number
;; cl = sector number
;; dh = head number
;; dl = drive number
;; bx = pointer to buffer
mov ah , 0x02
mov al , 15
mov ch , 0x00
mov cl , 0x02
mov dh , 0x00
mov dl , 0
mov bx , KERNEL_OFFSET_IN_MEMORY
int 0x13 Dieser Code führt zu dem Lesen von Festplatten in die Adresse KERNEL_OFFSET_IN_MEMORY . Es liest 15 Sektoren aus dem zweiten und speichert es durch Adress KERNEL_OFFSET_IN_MEMORY .
Da unser kompiliertes OS -Bild eine Verkettung des Bootsektors und des Kernels ist und wir wissen, dass unser Bootsektor 512 Bytes ist, können wir sicher sein, dass unser Kernel im zweiten Sektor beginnt.
Wenn das Lesen erfolgreich abgeschlossen ist, können wir den Anweisungen unter unserem KERNEL_OFFSET_IN_MEMORY anrufen und dem Kernel Ausführung geben.
call KERNEL_OFFSET_IN_MEMORY
jmp $Implementierung für die Festplatte lesen
Wir können hier eine Linie über unseren Bootsektor ziehen. Der Fluss ist einfach:
call aus.In diesem Schritt beendete unser Bootsektor seine Arbeit und beginnt mit dem Kernel zu arbeiten.
Sie können durch Startquellen navigieren und versuchen, wie es funktioniert.
Wenn wir Anweisungen an der Adresse anrufen, können wir einige Probleme haben. Wir können uns nicht sicher, dass diese Anweisung per Adresse ein kernel_main() ist. Lösung ist einfach.
Wir können eine Unterroutine schreiben, die am Start des Kernelcodes beigefügt ist. Dieser Unterroutine -Aufruf externe Funktion unseres Kernel kernel_main() . Wenn Objektdateien miteinander verknüpft werden, wird dieser Anruf in den Anruf unseres kernel_main() übersetzt.
global _start
[bits 32]
[extern kernel_main]
_start:
call kernel_main
jmp $Implementierung des Kerneleintritts
Bei diesem Schritt haben wir einen Einstiegspunkt für unsere Methode kernel_main() . Und das ist unser Einstieg für den gesamten Kernel.
Ich denke, es ist langweilig zu erklären, wie #include funktioniert und was in unserem kernel_main() passiert. Sie können leicht den Methoden folgen, die ich daraus rufe.
Kerneleintrag in c
Das ist der einfachste Teil.
Wir müssen im RAW -Binärformat boot/boot.bin -Bild erstellen. Dazu nennen wir nasm Assembler mit speziellen Flaggen.
nasm boot/boot.asm -f bin -o boot/boot.binEs führt zu einem rohen Binärformat, das Sie über QEMU ausführen können.
In diesem Schritt haben wir den kompilierten Startsektor.
Wir müssen alle Quellen aus allen Ordnern rekursiv erstellen, mit Ausnahme des boot -Ordners.
Alle C -Dateien werden über gcc und Montagedateien über nasm mit Objektdateien kompiliert:
gcc -g -ffreestanding -Wall -Wextra -fno-exceptions -m32 -std=c11 -c < SOURCE > -o < OBJ_FILE >
nasm < SOURCE > -f elf -o < OBJ_FILE > Es führt zu allen benötigten Objektdateien für die Verknüpfung mit Binärformat. Alles, was noch zu tun ist, ist, sie über ld miteinander zu verknüpfen:
ld -o kernel/kernel.bin -Ttext 0x1000 kernel/kernel_entry.o < OBJ_FILES > --oformat binary Beachten Sie, dass kernel/kernel_entry.o zuerst, da wir ein Problem beim Aufrufen des kernel_main() haben. Auf diese Weise garantieren wir, dass die erste Anweisung aus unserem boot/kernel_entry.asm aufgerufen wird.
Immerhin haben wir das Kernelbild im rohen Binärformat zusammengestellt.
Da unser Stiefelsektor und unser Kernel rohe binäre Formate sind, können wir sie einfach verkettet.
cat boot/boot.bin kernel/kernel.bin > os-image.bin Jetzt können wir os-image.bin über qemu-system-i386 ausführen. BIOS versucht, den bootfähigen Sektor zu lokalisieren, finden Sie unseren boot/boot.bin heraus und sehen Sie die Signatur. Beginnt mit der Ausführung unseres Assemblercode bei boot/boot.bin , der unseren kernel/kernel.bin über int 13,2 in den Speicher lädt und ihn ausführt.
So funktioniert alles zusammen. Fühlen Sie sich frei, durch das Projekt zu navigieren, danke?
Die MIT -Lizenz (MIT)
Copyright (C) 2016 Eugene Obrezkov
Die Erlaubnis wird hiermit einer Person, die eine Kopie dieser Software und zugehörigen Dokumentationsdateien (der "Software") erhält, kostenlos erteilt, um die Software ohne Einschränkung zu behandeln, einschließlich ohne Einschränkung der Rechte, zu verwenden, zu kopieren, zu modifizieren, zusammenzufassen, zu veröffentlichen, zu veröffentlichen, zu verteilen, zu verteilt, und/oder Kopien der Software zu ermöglichen, um Personen zu beanstanden, an denen die Software zugänglich ist, um die folgenden Bedingungen zu beantragen.
Die oben genannte Copyright -Mitteilung und diese Erlaubnisbekanntmachung müssen in alle Kopien oder wesentlichen Teile der Software enthalten sein.
Die Software wird "wie es ist" ohne Garantie jeglicher Art, ausdrücklich oder stillschweigend bereitgestellt, einschließlich, aber nicht beschränkt auf die Gewährleistung der Handelsfähigkeit, die Eignung für einen bestimmten Zweck und die Nichtverletzung. In keinem Fall sind die Autoren oder Urheberrechtsinhaber für Ansprüche, Schäden oder andere Haftungen haftbar, sei es in einer Vertragsklage, unerbittlich oder auf andere Weise, die sich aus oder im Zusammenhang mit der Software oder anderen Geschäften in der Software ergeben.