Lowlevel

Lowlevel => Lowlevel-Coding => Thema gestartet von: Azi am 08. November 2005, 16:47

Titel: [Anfänger] Keine Ausgabe
Beitrag von: Azi am 08. November 2005, 16:47
Hab vor ca. einem halben Jahr entschieden, ein eigenes Betriebssystem zu schreiben. Jetzt wollte ich, erstmal zu Testzwecken, eine einfache Meldung ausgeben. Geht aber nicht.

;06.11.2005 21:56
;So, jetzt geht es los.
;Zuerst müssen wir die Adresse korregieren,
;damit wir auch alles an die richtige Stelle laden

org 07C00h

;Jetzt müssen wir unseren Stack anlegen
;Dazu müssen die Interrupts deaktiviert sein

cli
mov ax,0F000h
mov ss,ax
mov sp,0
sti

;So, da sind sie wieder
;Jetzt brauchen wir eine Ausgabe, um zu sehen, ob es gelappt hat

ausgabe db "boot gut",13,10,0

;Die wollen wir natürlich auch Ausgeben

mov si,ausgabe
sag:
lodsb
mov ah,0Eh
mov bx,07h
int 010h
or al,al
jz ende
jmp sag

;So, das wars.
;Jetzt noch eine kleine Endlosschleife

ende:
jmp ende

;Und zu guter letzt muss die Datei ja genau 512 Byte groß sein...

times 512-($-$$)-2 db 0

;...und natürlich die Boot-Signatur haben!

dw 0AA55h

Titel: [Anfänger] Keine Ausgabe
Beitrag von: bitmaster am 08. November 2005, 17:05
Also ich glaube das ich deinen Fehler gefunden habe. Hier ist er:

sti
ausgabe db "boot gut",13,10,0
mov si,ausgabe


Das kann nicht funktionieren. Die CPU soll doch nicht den Code von "boot gut" ausgeben. Das macht sie aber in diesem fall. Was daraus wird weis keiner so genau. So müsste es aussehen:

sti
jmp weiter
ausgabe db "boot gut",13,10,0
weiter:
mov si,ausgabe


Jetzt überspring er nämlich die Meldung. Ich würde die Meldung aber nach ganz unten setzten dann kannst du dir das überspringen ersparen (natürlich vor times 512 blabla, aber unter jmp ende).
Titel: [Anfänger] Keine Ausgabe
Beitrag von: bitmaster am 08. November 2005, 17:11
Ach ja noch etwas:

mov ax,0F000h
mov ss,ax
mov sp,0


Du darfst keine Daten/Code an dieser Adresse schreiben. Dort befindet sich die ROM. Versuche es mal so:

mov ax,0100h
mov ss,ax
mov sp,6C00h


Das müsste funktionieren.

EDIT: Ich habe noch was gefunden. Du musst glaube ich das Datensegment erst setzten. Mache das mal so:

cli
mov ax,cs
mov ds,ax
mov ax,0100h
mov ss,ax
mov sp,6C00h
sti

Und ändere "sag" so ab (also "or al,al jz ende" direkt unter lodsb)

sag:
lodsb
or al,al
jz ende
mov ah,0Eh
mov bx,07h
int 010h
jmp sag

Hoffe das es jetzt funktioniert.
Titel: [Anfänger] Keine Ausgabe
Beitrag von: Jidder am 08. November 2005, 20:22
Zitat von: bitmaster
Du musst glaube ich das Datensegment erst setzten. Mache das mal so:

cli
mov ax,cs
mov ds,ax
mov ax,0100h
mov ss,ax
mov sp,6C00h
sti

dem stimme ich grundsätzlich zu, ich würde ds aber nicht auf cs setzen, denn der code erfordert, dass ds gleich null ist (org 0x7c00), aber cs ist nicht unbedingt null. also:
xor ax, ax
mov ds, ax
Titel: [Anfänger] Keine Ausgabe
Beitrag von: bitmaster am 08. November 2005, 21:50
Zitat von: PorkChicken
aber cs ist nicht unbedingt null
Hä? das habe ich ja noch nie gehört. Beim starten ist cs doch immer NULL oder nicht?
Titel: [Anfänger] Keine Ausgabe
Beitrag von: WhiteDragon am 09. November 2005, 06:40
Zitat von: bitmaster
Zitat von: PorkChicken
aber cs ist nicht unbedingt null
Hä? das habe ich ja noch nie gehört. Beim starten ist cs doch immer NULL oder nicht?


Das denke ich aber auch - wer behauptet anderes?!
Titel: [Anfänger] Keine Ausgabe
Beitrag von: Azi am 09. November 2005, 21:22
Hui, danke. Bin im moment krank, deshalb war ich noch nicht solange vorm PC. Ich werds aber jetzt mal ausprobieren, falls ich vor Schwindel nicht zusammenklappe... :cry:

/EDIT: Es klappt! Vielen Dank!
/Edit 2: Wieso eigentlich das:

mov sp,6C00h
Titel: [Anfänger] Keine Ausgabe
Beitrag von: bitmaster am 09. November 2005, 23:15
Zitat von: Azi
Hui, danke. Bin im moment krank, deshalb war ich noch nicht solange vorm PC. Ich werds aber jetzt mal ausprobieren, falls ich vor Schwindel nicht zusammenklappe... :cry:

/EDIT: Es klappt! Vielen Dank!
/Edit 2: Wieso eigentlich das:

mov sp,6C00h
Wieso mov sp,6C00h? Hier die Erklärung:

Der stack wächst zur niedrigaren Adressen. Wenn du z.B. ein push ax machst dann wird das ax auf dem Stack gelegt und sp um 2 Subtrahiert. So kannst du also genau 6C00h/2 mal pushen (wenn du kein pushf oder pusha etc. benutzt). Warum genau 6C00h? Weil du ss auf 100h legst (was meiner Meinung nach das beste ist). Dann ist der Stack größtmöglich. Denn 100h * 10h + 6C00h ergeben 7C00h. Und ab da befinden wir uns ja im Bootsektor. Den (also uns selbst) dürfen wir ja nicht überschreiben. So dann viel spaß noch beim Programmieren.

PS: gute Besserung
Titel: [Anfänger] Keine Ausgabe
Beitrag von: Jidder am 10. November 2005, 13:24
Zitat von: bitmaster
Zitat von: PorkChicken
aber cs ist nicht unbedingt null
Hä? das habe ich ja noch nie gehört. Beim starten ist cs doch immer NULL oder nicht?

wo steht denn, dass cs = 0 ist?

cs:ip kann theoretisch 07c0:0000, 0000:7c00, 0123:69D0 oder ganz was anderes sein. hauptsache der code startet an der linearen adresse 0x7c00. natürlich tauchen abgefahrene werte wie 0123:69D0 nicht auf, aber die anderen beispiele gibt es definitiv, weil verbuggte BIOS das verpeilen, und ich habe dutzende bootsektoren gesehen, die darauf rücksicht nehmen.

es ist außerdem sauberer sich nicht unbedingt auf die werte der register zu verlassen. vor allem wenn es total unnötig ist, wie in diesem beispiel.
Titel: [Anfänger] Keine Ausgabe
Beitrag von: Roshl am 10. November 2005, 15:20
cs muss null sein, weil unser bootloader sonst wegen dem org 0x7c00 totalen mist bauen würde ganz einfach^^ und da das bios ja dort hin springt ist cs von anfang an null, nur ds muss man vielleicht setzen, das muss nicht unbedingt schon null sein.
Titel: [Anfänger] Keine Ausgabe
Beitrag von: Azi am 10. November 2005, 17:28
Zitat von: bitmaster
Denn 100h * 10h + 6C00h ergeben 7C00h. Und ab da befinden wir uns ja im Bootsektor. Den (also uns selbst) dürfen wir ja nicht überschreiben.

Wieso *10h?
Zitat von: bitmaster
PS: gute Besserung

Danke!

Und noch eine Entscheidungsfrage: Wohin soll ich meinen Kernel laden? Ich hätte gerne 00000h oder 01000h. Kann man den dahin laden? Und wo fängt der ROM-Teil an und wo hört er auf, falls er das tut?
Titel: [Anfänger] Keine Ausgabe
Beitrag von: WhiteDragon am 10. November 2005, 17:30
Viele legen den Kernel ab 0x10000, ich selbst ab 0x600. Auf jeden Fall nicht vor 0x400, wegen der Interrupt-Table.
Titel: [Anfänger] Keine Ausgabe
Beitrag von: Jidder am 10. November 2005, 18:37
Zitat von: Roshl
cs muss null sein, weil unser bootloader sonst wegen dem org 0x7c00 totalen mist bauen würde ganz einfach^^ und da das bios ja dort hin springt ist cs von anfang an null

das bios muss nicht nach 0000:7c00 springen, sondern kann auch nach 07c0:0000 springen. und manche tuns auch.
Titel: [Anfänger] Keine Ausgabe
Beitrag von: Azi am 10. November 2005, 18:55
Noch 2 Fragen:
Wie kann man den PC ausschalten?
Wie kann ich prüfen, ob [Enter] gedrückt wurde (bzw. Wie lautet der ASCII-Code?)
Titel: [Anfänger] Keine Ausgabe
Beitrag von: bitmaster am 10. November 2005, 19:08
Zitat von: Azi
Wieso *10h?
Weil 10h = 16 (dezimal) ist. Und im Real-Mode errechnet man ja die Adresse in dem man das Segment mal 16 nimmt und den Offset hinzuaddiert. Beispiel:

Du befindest dich im Segment 1000h und dort der Offset 100h. So das wäre dann 1000h * 10 = 10000h + 100h = 10100h. Das sind dann die 20 Bit die der Prozessor braucht.

Zitat von: Azi
Und noch eine Entscheidungsfrage: Wohin soll ich meinen Kernel laden? Ich hätte gerne 00000h oder 01000h. Kann man den dahin laden? Und wo fängt der ROM-Teil an und wo hört er auf, falls er das tut?
Also an Adresse 00000h kannst du ihn nicht laden, weil sich dort die Interrupttabelle befindet und danach die BIOS DATA AREA. Was meinst du mit 1000h? 100h * 10h = 1000h? Dort befindet sich dein Stack also kannst du den Kernel dort nicht laden. Meinst du aber 1000h * 10h = 10000h dann ist das sogar so wie ich das mache (also funktioniert). Ich habe eine gute Beschreibung über den Adressraum. Sprich wo sich die ROM, IVT, das Video Subsystem etc. befindet. Dann weis man genau was frei ist und was nicht. Gib mir deine E-Mail und ich schick sie dir.
Titel: [Anfänger] Keine Ausgabe
Beitrag von: bitmaster am 10. November 2005, 19:29
Zitat von: Azi
Noch 2 Fragen:
Wie kann man den PC ausschalten?
Das weis ich leider nicht. Aber neu starten kannst du ihn so (falls du dich noch im Real Mode befindest):

db 0EAh
dw 0000h
dw 0FFFFh

Dies ist ein Far jump der an Adresse FFFF:0000 also FFFF0h springt. Und dort liegt code der den Computer neu startet. Ich weis auch wie du den Computer im Real Mode neu bootest. Ein einfaches int 19h genügt.

Zitat von: Azi
Wie kann ich prüfen, ob [Enter] gedrückt wurde (bzw. Wie lautet der ASCII-Code?)
Das kannst du mit dem BIOS Interrupt 16h machen. Der ASCII Code von Enter lautet 0Dh und der Scancode lautet 1Ch. Also gibt es drei Möglichkeiten:

xor ah,ah
int 16h
cmp al,0Dh ;ASCII Code in al
je bzw. jne


oder

xor ah,ah
int 16h
cmp ah,1Ch ;Scancode in ah
je bzw. jne


oder

xor ah,ah
int 16h
cmp ax,1C0Dh ;ASCII-Code und Scancode in ax
je bzw. jne


Das wären dann die drei Möglichkeiten. Es gibt auch noch den:

mov ah,01h
int 16h
jz kein_zeichen
cmp ax,1C0Dh
je bzw. jne


Aber hier wird nicht auf einen Tastendruck gewartet sondern wenn das ZF gesetzt ist (also kein Tastendruck erfolgt ist) spring man irgendwo hin (oder auch nicht).

PS: Du kannst dir ja mal mein kleines Real Mode OS anschauen. Du findest es auf meiner Webseite unter: http://www.osm-page.de . Falls du es unter Microsoft Virtual PC nutzen willst musst du es hier runterladen: http://www.osm-page.de/test.img

Viel Spaß noch
Titel: [Anfänger] Keine Ausgabe
Beitrag von: Azi am 10. November 2005, 19:36
Super, dein OS kenne ich von Tutorials.de (http://www.tutorials.de/tutorials212951.html) und ich habs auch schon ausprobiert. Und zwar zuerst unter VirtualPC und dann auf meinem 2. Computer, da es unter MS VPC nicht geklappt hat. Jetzt bringst du mir sogar die Lösung dafür, eifach eine Versteckte Image-Datei. Die würde ich aber auch unter den Downloads stellen, da bestimmt mehrere es mit VirtualPC versuchen werden...
Den Neustart kannte ich auch schon, das ist die 2. Sache, die mein OS kann, nach Nachricht ausgeben.
/Edit: Hast du meine eMail-Adresse bekommen?
Titel: [Anfänger] Keine Ausgabe
Beitrag von: n3Ro am 10. November 2005, 19:48
Zitat von: Azi
Wie kann man den PC ausschalten?


Ganz einfach über den APM-BIOS ;-)
Titel: [Anfänger] Keine Ausgabe
Beitrag von: Azi am 10. November 2005, 19:49
Und was ist das?
Titel: [Anfänger] Keine Ausgabe
Beitrag von: n3Ro am 10. November 2005, 19:57
Ein Strommanagement Interface im BIOS:
http://freedos.sourceforge.net/freedos/news/technote/190.html

EDIT: oder schau mal in Lowlevel Ausgabe 3 ;-)
Titel: [Anfänger] Keine Ausgabe
Beitrag von: Azi am 11. November 2005, 09:29
So, jetzt möchte ich den Kernel laden. Ich könnte einfach den Code aus der Lowlevel 1 nehmen, aber ich möchte es wenigstens verstehen, was ich aber leider nicht tue. Also:

...
;Lade unseren Kernel
call load          ;Ok, das verstehe ich

;Springe zu diesem Kernel
mov ax, 0x1000 ; Die Adresse des Programms          ;Ist der Kernel jetzt da?
...
push ax          ;Gerettet
mov ax, 0          ;jetzt ist 0
push ax          ;Wiederhergestellt --> Was hat das jetzt gebracht?
retf
...
; Lade den Kernel vom Bootlaufwerk
load:

; Diskdrive reset (Interrupt 13h, 0)          ;Wieso?
push ds            ; Sichere DS          ;Wieso?
...
pop ds             ; DS wiederherstellen          ;Siehe Kommentar über diesem
jc load            ; Geht nicht? -> Noch mal!          ;Wieso sollte es dann plötzlich klappen?

load1:
...
; Sektoren lesen (Interrupt 13h, 2)          ;Was bringt das?
...
mov dx, 0       ; Head=0, Laufwerk=0          ;Wieso Laufwerk=0?
int 13h         ; ES:BX =  Daten vom Laufwerk          ;???
jc load1        ; Fehler? Noch mal!          ;Wieso sollte es dann plötzlich klappen?
...
Titel: [Anfänger] Keine Ausgabe
Beitrag von: Thoth am 11. November 2005, 12:41
mov ax, 0x1000 ; Die Adresse des Programms          ;Ist der Kernel jetzt da?

Jep, denn in load wird das als die Startadresse für den Kernel angegeben:


mov ax,0x1000 ; ES:BX = 10000



push ax          ;Gerettet
mov ax, 0          ;jetzt ist 0
push ax          ;Wiederhergestellt --> Was hat das jetzt gebracht?
retf


Es wird gar nichts wiederhergestellt, es wird nur einmal 0x1000 und dann 0 mit Hilfe des Registers ax auf den Stack gepusht, weil retf sowohl eine Segment- als auch eine Offsetadresse auf selbigem erwartet. Diese werden dann vom Stack genommen und dorthin gejumpt. Man "kehrt also zum Kernel zurück". Das mag etwas komisch klingeln, weil man da ja gar nicht herkam, aber solange die richtige Adresse auf dem Stack liegt ist das der CPU egal.


; Diskdrive reset (Interrupt 13h, 0)          ;Wieso?
push ds            ; Sichere DS          ;Wieso?
...
pop ds             ; DS wiederherstellen          ;Siehe Kommentar über diesem
jc load            ; Geht nicht? -> Noch mal!          ;Wieso sollte es dann plötzlich klappen?


Zum ersten Wieso: sicher ist sicher, also lieber mal resetten, denn dann weiß man genau in welchem Zustand sich das Laufwerk befindet.
Zum zweiten und dritten: Da bin ich mir nicht sicher, ich nehme aber einfach mal an, dass int 13 ds benötigt und man es deshalb woanders zwischenspeichern muss.
Zum dritten: Naja, vielleicht hatte das Laufwerk gerade wichtigeres zu tun und das BIOS konnte den Befehl deshalb nicht ausführen - dann muss man es einfach so lange weiter versuchen, bis das Laufwerk frei ist.


; Sektoren lesen (Interrupt 13h, 2)          ;Was bringt das?
...
mov dx, 0       ; Head=0, Laufwerk=0          ;Wieso Laufwerk=0?
int 13h         ; ES:BX =  Daten vom Laufwerk          ;???
jc load1        ; Fehler? Noch mal!          ;Wieso sollte es dann plötzlich klappen?
...


Zum Was: Naja, wir wollen doch den Kernel laden. Der ist aber noch nicht im Speicher, sondern nur auf der Floppy. Von der können wir den Kernel aber nicht direkt ausführen, also müssen wir ihn vom Floppy in den Speicher hauen. Und da ein Sektor die kleinste Einheit auf einer solchen Diskette ist, die man ansprechen kann machen wir das eben sektorweise.

Wieso Laufwerk=0: naja, das ist normalerweise das erste. Da ich mir hier aber auch gerade nicht so sicher bin verweise ich einfach mal hierauf (http://www.ctyme.com/intr/rb-0607.htm).

Daten vom Laufwerk ???: Nun, der Biosinterrupt liest ja brav Sektoren von der Diskette ein, aber irgendwo müssen die ja auch hin und das ist eben definitionsgemäß (so ist die Funktion halt aufgebaut) an dieser Stelle.

Wieso sollte es dann plötzlich klappen? siehe oben.



Da ich aber auch ein blutiger Anfänger in Sachen Systemprogrammierung bin und das meiste meines Wissens auch nur von dieser Seite hier habe empfehle ich dir zusätzlich eine zweite Meinung von jemandem, der sich auskennt einzuholen *g*[/code]
Titel: [Anfänger] Keine Ausgabe
Beitrag von: Azi am 11. November 2005, 12:53
Na, das soll nach einem blutigem Anfänger klingn? Anfänger mag sein (das kann ich nicht beurteilen), aber der blutige Anfänger hier bin wohl ich!

Zu den Sektoren-Einlese-Teil:
Woher soll man wissen, in welchem Sektor der Kernel liegt bzw. wieviele er belegt?

/Edit: Vielen Dank für die Mühe, die du dir gemacht hast, denn der Teil, den ich dir zeigte, war nicht ganz wenig.
Titel: [Anfänger] Keine Ausgabe
Beitrag von: Thoth am 11. November 2005, 15:33
Zitat
Na, das soll nach einem blutigem Anfänger klingn?


:oops: Ich fühle mich geehrt, aber alles was ich geschrieben habe findest du auch hier auf lowlevel, oder ist zumindest von hier verlinkt.

Wegen den Sektoren: bei den kleinen anfänglichen Projekten sollte es reichen, den Kernel einfach mit dem Bootsektor zusammenzukopieren und als eins auf die Diskette zu schreiben. In dem Fall liegt der Kernel logischerweise in den Sektoren genau hinter dem Bootsektor und wie viele das sind kann man ja an der Größe der Kerneldatei (ein Sektor = 512 Bytes, aber das ist  glaub ich eh klar *g*) leicht erkennen.
Wenn man dann später was größeres plant und auch ein Dateisystem (FAT12 zum Beispiel, oder auch ein selbsterdachtes) benutzen möchte, dann steht der Kernel normalerweise in einem vordefinierten Verzeichnis und hat einen vordefinierten Namen (oder zumindest existiert eine vordefinierte Datei mit diesen Informationen, wie z.B. boot.ini bei Windows NT) und dann muss der Bootloader halt auch das Dateisystem kennen und selbiges nach einer Datei mit diesem Namen durchsuchen. Und da im Dateisystem logischerweise auch die Sektoren stehen, kann man die dann genauso wie sonst auch einlesen.
Titel: [Anfänger] Keine Ausgabe
Beitrag von: Azi am 11. November 2005, 15:45
Hat mal einer einen Tipp? Was soll ich zuerst machen:
Einen Kernel oder ein Dateisystem reinbringen? Evtl. wäre es später einfacher, sofort mit dem Dateisystem zu beginnen...
Titel: [Anfänger] Keine Ausgabe
Beitrag von: DarkThing am 11. November 2005, 15:52
Du kannst jederzeit wechseln. Dem Kernel selbst ist es egal, wie er geladen wird. Das heißt du kannst sobald du Lust hast deinen Bootloader umschreiben und bis dahin die Methode ohne FS nehmen. Alternativ kannst du dir auch mal GRUB anschausen.
Titel: [Anfänger] Keine Ausgabe
Beitrag von: bitmaster am 11. November 2005, 17:10
Zitat von: Azi
Hat mal einer einen Tipp? Was soll ich zuerst machen:
Einen Kernel oder ein Dateisystem reinbringen? Evtl. wäre es später einfacher, sofort mit dem Dateisystem zu beginnen...
Also etwas zum laden brauchst du ja schon. Und das ist nun einmal der Kernel. Also ich habe mit dem Kernel angefangen. Am einfachsten ist es diesen auf den 2. Sektor der Diskette zu kopieren und ihn (den Kernel also) mit dem int 13h zu laden. Hier ein Beispielcode:

mov ax,1000h
mov es,ax ;Segment
mov ah,02h
mov al,01h ;anzahl der Sektoren, später vergrößern
xor bx,bx ;Offset
mov cx,0002h ;Spur=null, Sektor=2
xor dh,dh ;Seite=null
xor dl,dl ;laufwerk null=A:
int 13h
jc error ;falls fehler
mov ax,1000h
mov ds,ax
push 1000h
push 0000h
retf ;zum kernel springen


Dieser Code läd den zweiten Sektor einer Diskette an Adresse 1000:0000 = 10000h und springt dort hin. Also wenn du vorher deinen Kernel auf den 2. Sektor schreibtst kannst du so deinen Kernel laden. Später wenn du dann immer besser wirst kannst du ja ein Dateisystem intergrieren.
Titel: [Anfänger] Keine Ausgabe
Beitrag von: Azi am 11. November 2005, 17:45
Dann ist ja gut, jetzt mache ich mich an den Kernel!