Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: sebi2020 am 02. November 2009, 19:56
-
Hallo, ich habe mir dass Tutorial im Magazin ausgabe 1 durchgelesen. Habe ein kleines Problem mit qemu. So wie ich es im Tutorial gelesen habe, kann qemu immer nur Sektorenweise lesen (also 512 Byte)... Jetzt habe ich meinen Bootloader (der genau ein Sektor groß ist) und den kernel der nur 118 Byte umfasst. Wie schaffe ich es jetzt Die datei auf 512 Byte zu bringen, so dass qemu sie überhaupt lesen kann?
mfg Sebi
-
Wie erstellst du denn die kernel.bin?
-
mit nasm:
nasm -f bin -o kernel.bin kernel.asm
die times direktive wird komischerweise ignoriert, ich habe sie in die kernel.asm reinkopiert. aber anscheinend füllt nasm trotztdem den rest nicht mit nullen auf.
-
Hört sich eher komisch an, Quelltext wäre gut ;)
Ansonsten liegt das Problem nicht bei qemu, sondern schlichtergreifend daran, dass die Bootsignatur am Ende des ersten Sektors gesucht wird - und ein Sektor ist bei Disketten nunmal 512 Bytes lang ;)
-
Okay, ich schreib hier nochmal den ganzen Quelltext rein, also hier der vom Bootloader, der im ersten Sektor liegt und genau 512 Bytes lang ist (da funktioniert es komischwerweise mit den 512 Bytes.
Hier der Bootloader aus der ausgabe:
org 0x7C00 ; Unsere Startadresse
; -----------------------------------------
; Unser Bootloader
; -----------------------------------------
jmp 0x0000:start
start:
; Erst brauchen wir einen Stack.
cli ; Keine Interrupts!
mov ax, 0x9000 ; Stackadresse
mov ss, ax ; SS = 0x9000 (unser Stack)
mov sp, 0 ; SP = 0x0000 (der Stackpointer)
sti ; Interrupts zulassen
; Segmentregister initialisieren (für Zugriff auf bootdrv notwendig)
mov ax, 0x0000
mov es, ax
mov ds, ax
; Bootlaufwerk aus DL speichern
mov [bootdrv], dl
;Lade unseren Kernel
call load
;Springe zu diesem Kernel
mov ax, 0x1000 ; Die Adresse des Programms
mov es, ax ; Segmentregister updaten
mov ds, ax
jmp 0x1000:0x0000
; ----------------------------------------------
; Funktionen und Variablen
; ----------------------------------------------
bootdrv db 0 ;Das Bootlaufwerk
loadmsg db "Laden...",13,10,0
; Einen String ausgeben:
putstr:
lodsb ; Byte laden
or al,al
jz short putstrd ; 0-Byte? -> Ende!
mov ah,0x0E ; Funktion 0x0E
mov bx,0x0007 ; Attribut-Byte (wird nicht benötigt)
int 0x10 ; schreiben
jmp putstr ; Nächstes Byte
putstrd:
retn
; Lade den Kernel vom Bootlaufwerk
load:
; Diskdrive reset (Interrupt 13h, 0)
mov ax, 0 ; Die gewünschte Funktion (reset)
mov dl, [bootdrv] ; Dieses Laufwerk ist gewünscht
int 13h ; Den Interrupt ausführen
jc load ; Geht nicht? -> Noch mal!
load1:
mov ax,0x1000 ; ES:BX = 0x10000
mov es,ax
mov bx, 0
; Sektoren lesen (Interrupt 13h, 2)
mov ah, 2 ; Funktion 2 (Lesen)
mov al, 5 ; Lese 5 Sektoren
mov cx, 2 ; Cylinder=0, Sector=2
mov dh, 0 ; Head=0
mov dl, [bootdrv] ; Laufwerk aus Vorgabe
int 13h ; ES:BX = Daten vom Laufwerk
jc load1 ; Fehler? Noch mal!
mov si,loadmsg
call putstr ; Meldung ausgeben
retn
times 512-($-$$)-2 db 0 ; Dateilänge: 512 Bytes
dw 0AA55h ; Bootsignatur
Und hier der kernel:
mov ax, 0x1000 ; Segmentregister updaten
mov ds, ax
mov es, ax
start:
mov si, msg
call putstr
mov si,msg_boot
call putstr
call getkey ; Warte auf einen Tastendruck
jmp reboot ; Reboot
msg db "Herzlich Willkommen zu StupidOS 0.1",13,10,0
msg_boot db "Beliebige Taste druecken...",10,0
; Stringausgabe
putstr:
lodsb ; Byte laden
or al,al
jz short putstrd ; 0-Byte? -> Ende!
mov ah,0x0E ; Funktion 0x0E
mov bx,0x0007
int 0x10
jmp putstr
putstrd:
retn
getkey:
mov ah, 0 ; Funktion 0
int 0x16 ; Ausführen
ret
reboot:
jmp 0xffff:0x0000
times 512 db 0
(118 Bytes statt 512 Bytes)
habe dann alles zu einer datei verpackt (Windows):
copy /b bootloader.bin + kernel.bin myOS.img
-
Wenn ich deinen Kernel assembliere, bekomme ich aber 629 Bytes, nicht nur 118. Das ist auch ungefähr, was zu erwarten ist, denn du füllst am Ende nicht nur auf (vergleich den Code mit dem Bootsektor), sondern fügst einfach fest 512 Nullen ein.
Gibt es übrigens einen Grund, warum du das Tut aus dem Magazin benutzt und nicht die neueren Tutorials?
-
hm sehr komisch, selbst dieses "fest" anlegen bewirkt bei mir überhaupt nichts. er tut überhaupt garnichts bei mir. (Arbeitet mit Vista). naja und ich habe die aus dem magazin genommen, weil ich sie am verständlichsten fand. Ich habe im Wiki das Gefühl mich ständig hin und her klicken zu müssen, um an bestimmten stellen weiter zu machen. Naja, ich frage mich jetzt, warum er nicht mal die 0en fest einfügt. ich habe es noch mal versucht zu assemblieren und es kommt bei mir immer noch 118 Bytes raus. Sagt zumindest Vista.
EDIT:
Habe die Dateien noch mal in ein anderes Verzeichniss kopiert. Jetzt nicht mehr. Lag wahrscheinlich an der UAC.
-
Merkwürdig. Entweder nasm hat unter Vista ne Macke, oder es legt ohne zutun sparse-files an und gibt die benutzte Größe - was aber mehr sein sollte, bei Blockgrößen jenseits der 512 Bytes. Steht wenn du ins Eigenschaftenmenü der Datei gehst irgendwo eine andere Größe?
Zum Wiki, wir haben da einige sehr aktive Autoren, wenn man denen nur sagt was gewünscht ist oder besser gemacht werden könnte. Also, konkretisieren! :)
-
Genau. Wenn was hakt, einfach den Leuten, die hier (http://lowlevel.brainsware.org/wiki/index.php/Wikiteam) stehen sagen ;-)
-
Bei Eigenschafte steht der selbe Wert... aber ehrlich gesagt mach ich mir jetzt auch keine Gedanken mehr, habe die Datein einfach in einen Ordner kopiert, der nicht von der UAC überwacht wird. Wobei ich NASM eigentlich extra als Administrator gestartet hab... naja :-)
Also konkretisieren ist, schwer... Ich habe mir dass OS-Dev für Einsteiger durchgelesen. Naja und hier und da kam dann irgendwann GDT , IDT , IVA und ich musste mir dann halt auf den seiten zu GDT , und IDT noch mal alles durchlesen. Dann kam dort als Beispiel vielleicht zufällig was von IRQ, klickt man wieder auf den Link und dann kehrt man irgendwann zum eigentlichen Tutorial zurück und ist auch immer noch nicht viel schlauer. Dass Problem ist, dass ich finde, dass einige Sachen zu wenig beschrieben werden. Und wenn man dann durch mit dem Tutorial ist fragt man sich, wie gehts jetzt weiter?! Ich hab ehrlich gesagt keinen Anhaltspunkt. Kann natürlich auch an mir liegen. Ich meine ich habe z.B. auch schon in andren Programmiersprachen programmiert (C++,VB.net, Delphi und (PHP :-) )). Naja dann taucht dort make auf und Linker - Scripte und dann denkt man sich nur noch "Hilfe...". Weil ich kann zumindest nicht viel mit den Skripten (Linker Skripte und make-files) anfangen, und make soweit ich weiß gar nicht unter windows verwenden.
EDIT:
Und ich Frage mich warum die Kernels in C geschrieben werden , wenn es heißt LOWLEVEL ? oder darf ich C auch noch als LOWLEVEL verstehn?
-
Also die Grundpfeiler des Internets sind halt Hyperlinks. Im OS-Dev-für-Einsteiger-Tutorial sind die wichtigsten Infos gekapselt, um sich weiter in einen Bereich einzuarbeiten sind dann die Links da. Wenn man z.B. GDT, IDT usw. usf. komplett im Artikel 4 abhandeln würde, würde er nur unnötig groß und damit auf Anfänger abschreckend wirken. Denn beides sind nicht gerade triviale Themen.
Und Links zu Make und Linkerfiles haben wir auch ;-)
Und du kannst btw so ziemlich alles als "lowlevel" titulieren, was irgendwie schön hardware-nah ist ;-)
-
Hast du auch die Tutorialreihe zu OS-Dev für Einsteiger (http://lowlevel.brainsware.org/wiki/index.php/Kategorie:OS-Dev_für_Einsteiger) gelesen oder nur den Artikel? Der Artikel hat es noch nicht ganz geschafft, die Tutorials richtig einzubinden (oder überhaupt drauf zu verweisen), das sollte man mal ändern (Hallo Wiki-Team! ;))
Das zugehörige Beispiel-OS gibt es übrigens auch in komplett unter http://git.tyndur.org/?p=tutorial.git;a=summary
Und ich Frage mich warum die Kernels in C geschrieben werden , wenn es heißt LOWLEVEL ? oder darf ich C auch noch als LOWLEVEL verstehn?
Lowlevel hat in erster Linie nichts mit der Sprache zu tun. Ein Kernel ist lowlevel und man kann ihn mit sehr vielen Sprachen schreiben. Aber auch wenn man einmal davon absieht, ist C schon eine ziemlich lowlevelige Sprache.
-
zum teil habe ich mir diese schon durchgelesen, aber ich habe jetzt ein konkretes beispiel was ich sehr abschreckend finde:
Ich lese etwas von I/O Ports. Klicke ich auf den Link bekomme ich eine Seitenlange liste von Registern etc. aber keine Beschreibung davon was I/O Ports überhaupt sind. habe zumindest im Internet was zu Memory Mapped I/O was gefunden, aber so wie ich es verstanden habe wird bei so einem Prozessor Isolated I/O verwendet. Nun stellt sich für mich die Frage, wie spricht man diese Ports an?!, wie werden Sie adressiert, gibt es dafür spezielle Opcodes? und wenn ja , wie sehen dann die memorics (oder wie sie noch mal heißen) dafür aus?!
EDIT: Für mich stellt sich zumindest die Frage, macht es überhaupt sinn sich mit der OS Programmierung zu befassen, wenn ich bei solchen Sachen wie Peripherie nichts verstehe. Ich mein die schönen BIOS Interupts kann ich ja im Protected Mode nciht mehr verwenden, zumindest soweit ich dass verstanden habe. oO...
-
Mit IO-Ports sprichst du Hardware an. Du kannst es dir mal ganz grob als Speicher vorstellen, auf dem sowohl Hardware als auch dein Code arbeiten. Der Speicher ist 64k groß und ein Port ist ein Byte darin. Du kannst über in (von einem Port lesen) und out (schreiben) darauf zugreifen.
Memory Mapped I/O wäre, wenn du zum Zugriff auf die Hardware nicht die Ports benutzt, sondern die Geräte stattdessen einen Bereich in den normalen RAM einblenden.
-
@taljeth kennst du vielleicht einen Artikel oder ein Tutorial generell, was genauer auf dieses Thema eingeht?
Oder kennt vielleicht sonst jemand nen Artikel der genau auf die I/O Ports eingeht?
mfg Sebi
-
Mehr als in meinem Beitrag oben gibt es eigentlich dazu nicht zu sagen.
Du musst nur noch von der jeweiligen Hardware wissen, welche IO-Ports sie benutzt und was man dort hineinschreiben (bzw. daraus lesen) muss. Das hat aber nichts mit dem allgemeinen Konzept IO-Port zu tun, sondern ist in den Tutorials und Artikeln zu der jeweiligen Hardware beschrieben.
-
Hallo,
Mehr als in meinem Beitrag oben gibt es eigentlich dazu nicht zu sagen.
Naja, das stimmt nur oberflächlich betrachtet.
IO-Zugriffe sind deutlich langsamer, dafür könnten Memory-Mapped-IOs gecached werden. Jede Variante hat so ihre Vor- und Nachteile.
Zwei hintereinander folgende IO-Writes :mov dx,0x0370
mov al,11
out dx,al
out dx,al
werden immer beide komplett ausgeführt (nur so kann ein UART simpler funktionieren) wohingegen bei zwei hintereinander folgenden Speicherzugriffen wahrscheinlich der erste vom zweiten im CPU-Cache überschrieben wird und die Hardware deshalb nur den zweiten sieht. Bei Memory-Mapped-IO muss man mehr beachten dafür ists aber deutlich schneller, einer der Gründe warum moderne Hardware keine IO-Ports mehr hat.
Das der IO-Adress-Raum in Wirklichkeit 32Bit groß ist und nur der Befehlssatz der CPU das nicht unterstützt ist nur eine kleine Nebensächlichkeit am Rande.
Grüße
Erik
-
Bei Memory-Mapped-IO muss man mehr beachten dafür ists aber deutlich schneller, einer der Gründe warum moderne Hardware keine IO-Ports mehr hat.
Wie wird dann auf die Hardware zugegriffen, über Memory-Mapped-IO?
-
Hallo,
Wie wird dann auf die Hardware zugegriffen ....
So wie es im Datenblatt der betreffenden Hardware drin steht.
Ich wollte gestern Abend nur ein paar grundsätzliche Unterschiede (bzw. spezifische Eigenheiten) zwischen klassischem IO und Memory-Mapped-IO aufzeigen. Was Deine konkrete Hardware kann weis ich natürlich nicht.
Grüße
Erik