Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: ehenkes am 05. July 2009, 22:35
-
; set parameters for reading function
; 8-bit-wise for better overview
mov dl,[bootdrive] ; select boot drive
mov al, 63 ; read n sectors (max. 63!!!)
mov ch, 0 ; cylinder = 0
mov cl, 2 ; sector = 2
mov dh, 0 ; head = 0
mov ah, 2 ; function "read"
int 0x13
jc load_kernel ; trouble? try again
Damit lassen sich maximal 63 Sektoren des Kernels, also 63*512 Byte = 0x7e00 Byte laden. Liegt das daran, dass der bootsektor bei 0x7c00 liegt. Wie kann man diese Grenze überkommen?
Kernel wird nach 0x8000 geladen.
-
per engl. Wikipedia (http://en.wikipedia.org/wiki/INT_13#INT_13h_AH.3D02h:_Read_Sectors_From_Drive) werden da nur 6 bit verwendet. Schonmal versucht einfach mehrmals den Code zu durchlaufen und eben bei höherem Sektor anzufangen?
-
Eigentlich normale BIOS Programmierung.
Du hast dir das ausgesucht. Wenn du dich damit nicht beschäftigen willst, steig auf GRUB um. :wink:
-
Also erstmal: Wenn du bei 63 Sektoren/Track bist, dann hast du eine Festplatte vorliegen und keine Diskette. Die haben in der Tat nur 18 Sektoren (oder eine andere Zahl, gibt ja unterschiedliche Disketten). Das heißt du musst bereits bei 18 den Head erhöhen.
Warum findet man eigentlich keinen Link auf einen brauchbaren Bootloader? Bin ich der Erste, der einen Kernel mit über 63*512 = 32256 Byte mit eigenem Bootloader laden will? :?
Du hast dir die API ausgesucht. Was kann das Internet dafür? Du musst einfach die nachfolgenden Sektoren lesen. Die Funktion ist hier dokumentiert: http://www.ctyme.com/intr/rb-0607.htm
-
Sag mir lieber, ob ich bei 63 Sectors anschließend die Heads von 0 auf 1 erhöhen muss oder die Cylinder?
Hi,
Kannst doch LBA 64 in CHS umwandeln. Hab dafür ne Funktion in Assembler geschrieben falls du die brauchst. Ansonsten gehts auch manuell.
http://lowlevel.brainsware.org/wiki/index.php/LBA
PS: Meine Funktion hat für Sektor 64 folgendes ausgerechnet:
C = 1
H = 1
S = 11
PPS: Also meine Funktion kann auch ohne Probleme Sektor 64 oder auch Sektor 80 auslesen :)
-
Most BIOSes support "multitrack" reads, where the value in AL exceeds the number of sectors remaining on the track, in which case any additional sectors are read beginning at sector 1 on the following head in the same cylinder;
Daher klappt das auch mit Werten über 18 (bis max. 63). BIOS rechnet das freundlicherweise um.
"most" bedeutet offensichtlich: Es existieren BIOSe, die das nicht tun. Keine Ahnung, ob die eine Rolle spielen, aber sicherer ist es wohl, sich selber drum zu kümmern.
-
Hi,
Also ich würde dir empfehlen die CHS Werte selbst auszurechnen und dem Interrupt direkt die richtigen Werte zu übergeben. Bei mir funktioniert das wunderbar.
Habe gerade versucht mit dieser Methode 70 Sektoren ab Sektor 1 (= 2. Sektor) zu lesen und das war kein Problem.
Lg
Cjreek
-
Ich bräuchte da mal ein Vorbild eines anderen Bootloaders, um zu sehen, ob ich das mit dem mehrfachen Floppy-Lesen richtig mache (verwende momentan allerdings nur Bochs, sollte also vom Prinzip her fehlerfrei klappen)
Entschulding, dass ich so dreist bin das zu sagen, aber da es Bootloader wie Sand am Meer gibt, wirst du mit google sicherlich einen finden der das tut.
-
Hi,
Falls ich dich richtig verstehe.. Du könntest dann halt immer 128 Sektoren auf einen Schlag lesen und dann die CHS werte für den 129. zu lesenden Sektor berechnen und dann ab da weitere 128 Sektoren lesen etc.
Oder hab ich dich falsch verstanden?
Gruß
Cjreek
-
Mh die Sache klingt interessant. Ich werd mich am Wochenende mal damit befassen. :-)
-
Warum liest du nicht einfach immer einen Sektor auf einmal?
-
Hi,
Also ich kopiers einfach mal hier rein. Vielleicht hilfts dir ja:
floppy_reset:
xor ax,ax
xor dl,dl
int 13h
jc floppy_reset ; wenns nicht geklappt hat nochmal versuchen
ret
;[DESC] Konvertiert eine LBA Sektorangabe in das CHS Format
; Siehe --> http://lowlevel.brainsware.org/wiki/index.php/LBA
;
; [IN] #1 = Linearer Sektor (#1 = 1. Stackparameter)
; [OUT] ax = Pointer zu einer CHS struktur
lba_to_chs:
push bp
mov bp, sp
mov ax, [bp+0x04]
xor dx,dx
mov cx,36
div cx
mov [0xD000],ax ; = C
mov ax,dx
xor dx,dx
mov cx,18
div cx
mov [0xD002],ax ; = H
inc dx
mov [0xD004],dx ; = S
mov ax,0xD000
pop bp
ret 2
; [IN] #1 = Startsektor (LBA Format => linear)
; #2 = Anzahl der zu lesenden Sektoren
;
; #3 = Zieldatensegment
; #4 = Offset
_floppy_read:
push bp
mov bp, sp
floppy_reset
lba_to_chs word [bp+0x04]
mov ch, byte [0xD000] ; Zylinder nach ch
mov dh, byte [0xD002] ; Kopf nach dh
mov cl, byte [0xD004] ; Sektor nach cl
mov al,byte [bp+0x06] ; Anzahl der Sektoren die gelesen werden sollen nach AH
mov dl, 0 ; Diskettenlaufwerk = 0
mov bx, word [bp+0x08]
mov es, bx
mov bx, word [bp+0x0A]
mov ah, 0x02
int 13h
pop bp
ret 8
Ich habe mir dann für floppy_read ein Makro definiert:
%macro floppy_read 4
push %4 ; Offset
push %3 ; Zielsegment
push %2 ; Count
push %1 ; Sektor (LBA)
call _floppy_read
%endmacro
Das ganze kann man dann so aufrufen:
floppy_read 0, 1, 0xFFFF, 0x0010 ; Sektor 0 an Adresse 0x100000 (1MB) lesen
das ganze kann man natürlich auch inne schleife packen.. muss halt immer den ersten parameter hochzählen und die Adresse um 512 Bytes erhöhen..
Lg
Cjreek
-
Nun fehlt nur noch der Super-Algo, der dies in einer Schleife sektorenweise erledigt.
; input:
; di - number of sectors
; bx - segment
; ch, dh, cl - cylinder, head, sector
read:
.next:
mov es, bx
xor bx, bx
.again:
mov dl, [bootdrive]
mov ax, 0x0201
int 0x13
jc .again
inc cl
cmp cl, 19
jl .foo
mov cl, 1
inc dh
cmp dh, 2
jl .foo
mov dh, 0
inc ch
cmp ch, 80
jae .error
.foo:
mov bx, es
add bx, 512/16
sub di, 1
jnz .next
.done:
ret
Das Label .foo ist vielleicht etwas blöd benannt, aber da kann man nix machen^^
-
Ich glaube, GRUB ist das herzlich egal. Es kostet nur dich selbst Zeit, gegen Windmühlen zu kämpfen.
-
Ich finde Assemblerprogrammieren sollte den Eliten vorbehalten sein. Der Code ist nicht genial, und er funktioniert nur in gewissen Grenzen. (Die nur ich und das liebe BIOS kennen.) Aber viel Spaß beim Bugs suchen, sobald der Code nicht mehr funktioniert ^_^
-
Ja, und warum kannst du deinen 64 KB Kernel nicht nach 0x8000 laden? Mein Code hat damit nichts zu tun. Ich will mal einen Tipp geben: Du kannst ihn auch nicht nach 0xfe00 laden ^^ Achja fairerweise noch ein Tipp: DMA hat damit nix zu tun.
Der schuldige Code ist natürlich in diesem Beitrag (http://lowlevel.brainsware.org/forum/index.php?topic=2219.msg25093#msg25093), sonst wärs ja gemein^^
btw: Wer sagt, dass ich nicht bei c-plusplus.de angemeldet bin?^^
-
Menno, du hast es ja schon raus ... 8-) Ich hatte extra schon etwas (http://jidder.de/stuff/galgenraten.php) vorbereitet um meine 1337ness allen unter die Nase zu reiben ^_^
Ja, ich denke da unten ist der Stack relativ gut aufgehoben. Die untere Grenze wäre dann das Ende der BDA also 0x0500. Wenn du da angekommen bist, hast du soviel Unfug auf den Stack gelegt, dass dir das hoffentlich selbst auffällt^^
Wenn du BDA und IDT mit dem Stack brutalst überschreibst, hast du übrigens wieder das selbe Problem ;)
-
Es kostet nur dich selbst Zeit, gegen Windmühlen zu kämpfen.
Das Thema "Kernel nachladen" ist doch nun erfolgreich abgehakt.
Nicht, wenn du den Bootloader ernsthaft benutzen willst. Du hast jetzt ein paar Sektoren von der Diskette gekratzt, mehr nicht.
Wie sieht es zum Beispiel aus mit... vernünftigen Binärformaten für den Kernel (flache Binaries machen nicht lang Spaß)? ...vom Bootloader geladenen Modulen (brauchst du für einen Mikrokernel)? ...Zugriff auf Dateisysteme (alles andere ist ziemlich doof zu benutzen, wenn du mal mehrere Dateien laden kannst)?
-
Also lass mich noch ein wenig im "Dreck" spielen. :-)
Klar. Aber wenn du von abgehakt redest, wollte ich dir nur mal zeigen, dass der Dreck noch lange nicht ausgeht. :)
-
fremdes Fertigprodukt
Bloß weil das BIOS wenig intuitiv und wenig konsistent ist, und nur einen geringen Umfang hat, ist es nichtsdestotrotz ein "fremdes Fertigprodukt".
-
Das ist dann aber immer noch nichts eigenes, sondern nur ein anderes fremdes Fertigprodukt.
-
tritt das problem auch mit "rawrite", oder "rawritewin" auf...? vieleicht löst sich das problem ja von selbst, wenn du einfach das programm zum schreiben der diskette wechselst...
-
Booten von USB geht im allgemeinen so, dass das BIOS ein großes Floppylaufwerk emuliert. Sollte sich also für einen Bootloader, der nur über BIOS-Funktionen drauf zugreift, genau gleich anfühlen. Sobald dein OS dann aber im PM ist, brauchst du natürlich wieder selber Treiber - und USB ist nicht ganz trivial.
-
Hi,
ich hab mal deine Version 73 runtergeladen und seziert. Allerdings meine Vermutung nicht getestet, weil ich dazu zu faul bin ^^
Die BSS-Sektion deines Kernels beginnt an Offset 0x8860. Deine Kernel Binary ist allerdings kleiner. Die BSS-Sektion ist also nicht in der Datei enthalten. Dein selbstgebauter Bootloader lädt aber einfach wie blöde die Sektoren, die zu diesem Bereich gehören.
An dieser Stelle können sich also je nach Art der Erstellung der Diskette/des Images beliebige Daten befinden. Der Kernel erwartet allerdings, dass die BSS-Sektion mit Nullen gefüllt ist.
Wenn sie das nicht ist, dann gehen so Abfragen wie vermutlich in diesem Fall in paging.c schief:
extern heap_t* kheap;
...
// kheap initialisiert?
if( kheap!=0 ) { kheap benutzen }
Den üblichen Kommentar kann ich mir nicht verkneifen: GRUB hätte die BSS-Sektion zuverlässig genullt.
-
Kann man das via Linkerskript einbeziehen und auf Null setzen?
Glaube nicht
Dann wäre bei mir wohl kernel.asm der richtige Ort für diese Aktion?
Jep. Weil dein Kernel eine flache Binary ist, ist das auch der einzige Ort.
Ich hab keine konkrete Dokumentation gefunden, in der genaues zu COMMON beschrieben ist. Im Prinzip gehört es wohl auch in die BSS-Sektion und damit mit Nullen gefüllt. In meinem Standard-Linker-Skript ist sieht der .bss-Block deswegen so aus
.bss :
{
*(.bss)
*(COMMON)
}
-
Booten von USB geht im allgemeinen so, dass das BIOS ein großes Floppylaufwerk emuliert.
Hast Du dazu einen Link, habe das bisher nicht gefunden, möchte nicht vom Regen in die Traufe kommen. :-)
Hm, ich wüsste da jetzt nichts spezielles dazu. Aber viel mehr gibt es da ja auch gar nicht zu wissen als dass das BIOS einfach das richtige macht.
Wenn deine Probleme aber nicht an kaputten Disketten liegen, sondern an deinem Code, wirst du mit USB-Sticks vermutlich auch nichts gewinnen. Außer eben, dass du im PM nicht mehr so leicht einen Treiber geschrieben bekommst wie für echte Floppys.
-
Hm, also eigentlich ist ein Floppytreiber im PM/LM viel lowleveliger als das BIOS-Interface im RM. Das BIOS ist ja letztendlich nur eine Bibliothek, die das für dich erledigt. Auch wenn ihre Schnittstellen teilweise so gestaltet sind, dass man sich tatsächlich eine Weile damit aufhalten kann, sie richtig anzusprechen. ;)
-
der Hinweis auf GRUB leider sinnvoll. Dennoch empfinde ich dies als Einengung, denn man wird praktisch auf einen Rechner gezwungen, der GRUB verwendet, damit zu Linux getrieben. :x
Das ist Blödsinn und wird durch Wiederholung nicht richtiger. GRUB ist ein Bootloader, der mit Linux nur zu tun hat, dass das eins der vielen Systeme ist, das er laden kann. Warum sagst du nicht, man wird zu Hurd getrieben, da kommt er ja schließlich her? Oder zu tyndur, Xen, NetBSD usw., die kann er ja auch alle laden?
EDIT: Problem momentan entschärft. Der Algorithmus von PorkChicken ist zum Glück o.k. Das Schlimme ist, dass man bei allen Problemen im Kernel, die nicht überall gleichermaßen auftreten, den eigenen Bootloader im Verdacht hat.
Naja, das sagt viel darüber aus, wie sehr du deinem Bootloader vertraust. In dem Fall solltest du vielleicht nochmal eine Weile dran arbeiten, bis du ihm genug vertraust. Keiner hier sagt dir, du musst GRUB nehmen. Aber wir sagen, wenn du es nicht tust, musst du ernsthaft Zeit in deinen eigenen Bootloader investieren, bevor du mit deinem OS richtig anfangen kannst. Ob du dazu bereit bist, ist deine eigene Entscheidung.
OS steht z.Z. absolut stabil. Fehler ist eindeutig im VFS/RAM-Disk-Code von JM (bei root->nodes). Nach Umgehung der VFS/RAM Disk läuft das OS stabil:
http://www.henkessoft.de/OS_Dev/Downloads/85.zip
Hättest du nicht vorher sagen können, dass das eine tar-Bombe im zip-Format ist? :|
Na gut, wie auch immer, gebaut bekommen habe ich es irgendwie. Ich nehme nur an, dass es nicht richtig ist, wenn nach "loading kernel" nur noch eine Zeile Sternchen kommt, oder? Wenn ich das Ding mal gebootet bekomme, würde ich mir vielleicht auch den PF anschauen. PFs debuggen ist aber sowieso die Alltagsarbeit in der OS-Entwicklung. Damit solltest du mit der Zeit selbst zurechtkommen.
Im Code sehe ich kein root->nodes, nur ein root_nodes. Wenn es tatsächlich daran liegen sollte, spricht das wohl für einen Fehler in deinem k_malloc. Möglicherweise ist der Fehler aber auch nur in diesem Block und kommt aber vom Zugriff auf eine andere Struktur. Da hilft nur Code disassemblieren und anschauen, was genau schiefgeht (oder einen gdb dranhängen und die einzelnen Werte ausgeben lassen).
Wer sich für OS-Entwicklung von Grund auf (also ohne GRUB) interessiert
Missverständnis. Bootloader-Entwicklung ist ein verwandtes Thema, aber kein Teilgebiet der OS-Entwicklung.
-
tyndur ist aufgrund der langen Entwicklungszeit für viele bereits zu weit fortgeschritten und daher zu komplex.
Naja, also wenn man ein wenig Zeit investiert und sich durch den Quellcode liest und dabei noch die doxygen-Dokumentation nutzt, blick tman doch durch tyndur durch (gut, nicht in jede kleinste Ecke :P).
Eine Einsteiger-Doku existiert nicht.
Das bringt mich auf eine Idee...man könnte doch den "alten" Soruce von ehemals LOST 0.1.0 nehmen und diesen "verdokumentieren", sodass für Einsteiger eine solide Basis vorhanden ist und man anhand von LOST lernen kann. Dann kann man sich in tyndur einlesen (was ja an und für sich kein Weltengroßer Unterschied ist (zumindest im kernel)).
Selbstverständlich gehört der Bootloader zum Betriebssystem dazu.
Das Betriebssystem braucht den Bootloader, damit es selbst geladen wird, dennoch sind Bootloader und OS (wie schon mehrfach in diesem Thread erwähnt) zwei verschiedene Baustellen mit völllig anderen Vorraussetzungen. Beispielsweise muss ein Bootloader nicht multithreading-fähig sein (wieso auch?) und braucht keinen Scheduler, keine 8oder keine vollständige) Hardwareabstraktionsschicht und auch kein großartiges Memory-Management. Wenn man sich den Source von GRUB2 ansieht, macht der Großteil des Source die Verarbeitung/Arbeit mit den unterschiedlichen Dateisystemen aus.
GRUB mag auch nicht jeder.
Gerade junge Leute wollen noch dazu ihr eigenes Ding durchziehen.
Gerade diesen jungen Leuten (womit ich mit mit meinem 18 Jahren einfach mal auch noch zuzähle *g*) sollte man klar machen, dass ein Bootloader nicht das ist was sie möchten, wenn sie ein OS entwickeln wollen. Einen Bootsektor-Kernel, der "Hallo Welt" ausgibt ist was feines für einen Anfänger. Doch spätestens wenn er seinen Kernel selbst laden muss, vergeht ihm die Freude. Da ist man doch erfraut, wenn der Kernel von GRUB geladen wird und man noch eine Menge Informationen (Multiboot sei dank) dazubekommt.
Soviel von meiner Seite, zurück in die angeschlossenen Funkhäuser.
-
Bootloader-Entwicklung ist ein verwandtes Thema, aber kein Teilgebiet der OS-Entwicklung.
Selbstverständlich gehört der Bootloader zum Betriebssystem dazu.
Nein. Das würde implizieren, dass zu jedem Bootloader genau ein Betriebssystem gehört und dass umgekehrt jedes Betriebssystem genau einen Bootloader hat. Dass ersteres nicht stimmt, sollte eigentlich jeder wissen, der hier mitbekommen, dass es mehr als einen gibt, der sein OS von GRUB booten lässt. Für letzteres nehme ich einfach mal Linux als Beispiel her - Lilo, GRUB, loadlin, syslinux und sicher noch ein paar mehr.
Wenn ich das Ding mal gebootet bekomme
Merkwürdig. PrettyOS verwendet inzwischen die von euch empfohlenen Cross-Tools. Linker-Skript und Makefile sind im zip-File dabei.
Ja, wie gesagt, kompiliert bekomme ich es. Zwar mit händischen Anpassungen der Makefile, aber das kriege ich grad noch hin. Es bootet nur nicht, wie ich mir das vorstelle (es sei denn, du sagst, eine Zeile voll Sterne ist alles, was passieren soll).
Der ist weg, seit ich das fehlerhafte Modul von JM umgehe. PFs kann ich inzwischen auch selbst finden. Das Problem war lediglich, dass er mit VFS/RAM Disk (83 er Version) nur auf manchen real PC aufgetreten ist, teilweise sogar auf dem selben PC verschiedene Reaktion.
Umgehen klingt aber nicht nach einem Fix. ;)
Hast du denn wenigstens die genaue Ursache herausgefunden oder ist es möglicherweise noch ein Bug in deinem Code, der jetzt nur nicht mehr ausgelöst wird?
tyndur ist aufgrund der langen Entwicklungszeit für viele bereits zu weit fortgeschritten und daher zu komplex. Eine Einsteiger-Doku existiert nicht. Gerade junge Leute wollen noch dazu ihr eigenes Ding durchziehen. Selbst PrettyOS ist für einen Anfänger (C, Assembler, OSDEV) nicht in einer Woche begreifbar.
Für wirklich komplex halte ich tyndur nicht. Gerade der Kernel ist ziemlich einfach gestrickt. Aber zugegeben, man könnte ihn wohl wesentlich besser erklären.
Dass es nicht möglich ist, OS-Dev in einer Woche zu meistern, sollte klar sein.
-
Naja, also wenn man ein wenig Zeit investiert und sich durch den Quellcode liest und dabei noch die doxygen-Dokumentation nutzt, blick tman doch durch tyndur durch (gut, nicht in jede kleinste Ecke :P).
Ich kenne auch nicht jede kleinste Ecke. Und bin eigentlich ganz froh darüber. ;)
Das bringt mich auf eine Idee...man könnte doch den "alten" Soruce von ehemals LOST 0.1.0 nehmen und diesen "verdokumentieren", sodass für Einsteiger eine solide Basis vorhanden ist und man anhand von LOST lernen kann. Dann kann man sich in tyndur einlesen (was ja an und für sich kein Weltengroßer Unterschied ist (zumindest im kernel)).
Nein, bitte nicht auf 0.1.0 aufsetzen. Entweder der Code ist im aktuellen Zustand noch der gleiche oder es gibt gute Gründe, warum der Code nicht mehr so ist, wie er war.
-
Was nun welche Zeile ist, wäre noch ganz gut zu wissen. Aber ich glaube, wenn du das selbst nachgeschaut hättest, würdest du diese Funktion nicht mit k_strcpy vergleichen.
Was macht die Zeile *dest = *dest++; denn deiner Meinung nach? Ich vermute mal das sollte dest++; heißen.
-
Ich nehme an, das Problem mit *dest = *dest++ ist, dass nicht definiert ist, ob beim Auswerten des linken *dest schon erhöht worden ist oder nicht.
Das mit dem '<--' finde ich aber schon übel. Da sollte ein Compiler laut aufschreien.
-
Ja, der Compiler hat meistens recht, wenn er warnt. ;)
-
Dann solltest du deinen Kernel fixen und die Headerdateien selbst bereitstellen. Headerdateien aus deinem Hostsystem zu nehmen, funktioniert höchstens zufällig.
-
typedef __builtin_va_list va_list;
#define va_start(ap, X) __builtin_va_start(ap, X)
#define va_arg(ap, type) __builtin_va_arg(ap, type)
#define va_end(ap) __builtin_va_end(ap)
Und schon ist stdarg.h fertig ;)
-
Zum Vergleich, in tyndur haben wir das:
LOST_TOOLS_GCC=$COMPILER_PREFIX"gcc -m32 -g -c -fno-stack-protector -nostdinc -fno-leading-underscore -fno-omit-frame-pointer -Wall -Werror -Wstrict-prototypes -fno-strict-aliasing -O2 -fno-builtin -I ."
Was du für wichtig hältst, ist natürlich ein Stück weit auch deine eigene Entscheidung.
-
Ja. Damit kannst du im Kernel aber eh nichts anfangen.
-
Und vor allem hast du sie nicht implementiert. Was gcc an der Stelle nämlich macht, ist dass er einfach nur Aufrufe an die Standardbibliothek einbaut, die dann Prüfungen durchführen soll. Und die Standardbibliothek ist im Kernel bekanntlich deine eigene.
-
Keine Ahnung, ob es damit was zu tun hat, aber du solltest dir angewöhnen, Rückgabewerte zu prüfen. fwrite garantiert dir nicht, dass es so viel schreibst wie du dir gewünscht hast, es kann auch weniger schreiben (oder gilt das nur für write ohne f?). Deswegen ruft man es normal in einer Schleife so lange auf, bis alles geschrieben ist.
-
Binäre Dateien unter Windows im Binärmodus öffnen. Also "wb" und "rb".
-
Erst im Textmodus lesen/schreiben, dann im Binärmodus weiter machen...
Finde nur ich das komisch?
Aber wenn's klappt ;)
-
Ich hab auch so meine Zweifel an der Dauerhaftigkeit dieser Lösung. Ich hoffe niemand schaut sich das ab ...