Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.de  
   
Forentreff 2012     
Bücher-Shop mit Amazon (Buchkategorien)C++ : Referenzen zu C++ : C++ Builder : Visual C++ : C# : Java : Spieleprogrammierung : Systemprogrammierung Linux : Software-Entwicklung : .NET : Compilertechnik : Algorithmen & Datenstrukturen : Objektorientierung : Entwurfsmuster : UML : eXtreme Programming : Scrum : Projektmanagement : Software-Testing : Datenbanken : Tom DeMarco : Dilbert : User Friendly
C/C++ Forum :: Projekt: OS-Development  ::  Eigenes OS?     Zeige alle Beiträge auf einer Seite Auf Beitrag antworten
Autor Nachricht
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:03:47 13.03.2009   Titel:   Eigenes OS?            Zitieren

Mich würde mal interessieren, wer alleine oder mit anderen an einem eigenen OS entwickelt, zu welchem Zweck und in welcher Sprache (ASS, C oder C++)? Links?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Kernel-Developer
Unregistrierter




Beitrag Kernel-Developer Unregistrierter 21:21:54 13.03.2009   Titel:   Re: Eigenes OS?            Zitieren

Erhard Henkes schrieb:
Mich würde mal interessieren, wer alleine oder mit anderen an einem eigenen OS entwickelt, zu welchem Zweck und in welcher Sprache (ASS, C oder C++)? Links?

Ich entwickel mit ein paar anderen zusammen ein eigenes OS, finden kannst du es hier. Ist in C geschrieben und der Zweck ist denke ich klar :???:
Kóyaánasqatsi
Mitglied

Benutzerprofil
Anmeldungsdatum: 03.10.2008
Beiträge: 3045
Beitrag Kóyaánasqatsi Mitglied 09:52:05 14.03.2009   Titel:              Zitieren

Hallo

Habe vor graumer Zeit mal angefangen, aber schon nach dem Multiboot Kernelloader aufgehört. War in C und Assembler...

Mfg.
way

_________________
xDelete('//tr[td/strong[text()="volkard"]]');, Hobby.
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 12:17:48 14.03.2009   Titel:   Re: Eigenes OS?            Zitieren

Erhard Henkes schrieb:
zu welchem Zweck und in welcher Sprache (ASS, C oder C++)?

Ich habe mich auch mal mit einem eigenen OS in Assembler beschäftigt zwecks endlich mal den Protected Mode der Intel CPUs zu verstehen. Habe aber diesbezüglich versagt und daraus wurde nichts. Hm, vertane Lebenszeit... hätte lieber in was anderes und sinnvolleres investieren sollen.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 15:19:50 14.03.2009   Titel:              Zitieren

Alleine ist sicher schwierig. Zu zweit oder dritt macht das mehr Sinn. Wichtig ist, dass man alles genau dokumentiert, wenn man zwischenzeitlich pausieren will/muss.

Ich denke, dass es auch teilweise an der mangelnden Erklärung der Vorbilder und an langatmigen Theorie-Erklärungen liegt, wenn es in der Praxis schief geht. Beim Einstieg haben die wenigsten den kompletten Durchstieg durch alle Facetten. Also ist es wichtig, die Dinge detailliert zu erklären und vor allem auch Anregungen für eigene Experimente zu geben, damit die Dinge wirklich "glasklar" werden.

Bevor man bei einem Hobby- oder Experimental-OS auf den Protected Mode umschaltet, sollte man erst den Real Mode didaktisch komplett ausloten, damit der PM nicht zur Belastung wird, sondern zur Bereicherung.

Ich habe mir vorgenommen, didaktisch den Einstieg in die OS-Entwicklung zu erleichtern, denn es hilft, sowohl Assembler, C und auch die Hardware richtig zu verstehen, zumindest dann, wenn man dies möchte. Daher bitte ich euch mit zu helfen.

Hier die Seite:
http://www.henkessoft.de/OS_Dev/OS_Dev1.htm

Bitte um konstruktive Kommentare/Ideen. Mir ist volles Verständnis und ein stufenweiser und leichter Einstieg wichtig. Kein blitzschnelles Voranhuschen einer Elite. Die brauchen solche Seiten nicht, sondern nur Datenblätter, Tabellen, ....

Wenn jemand mitmachen möchte, gerne. Bitte hier oder per mail. Im Kopf der Seite ist Platz für viele Namen. Hauptziel: Spaß und wirkliches Verständnis vermitteln. Ich möchte auch niemanden zwingen, zunächst Linux zu installieren, um zu beginnen.

Bisher haben sich für mich gvim [EDIT: notepad++ bringt mehr Komfort], nasm und bochs als wirklich brauchbar heraus kristallisiert. partcopy.exe kann sicher durch etwas anderes ersetzt werden. Wichtig ist, dass sich niemand die Festplatten "zerschießt".

Ich habe eine Floppy Disk zum Booten verwendet. Heutige PCs haben dies nicht mehr ohne weiteres. Viele haben aber noch alte PCs mit Floppy Disk und wollen wirklich "physisch booten". Didaktisch muss das einfach sein.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:52:55 11.07.2009, insgesamt 1-mal bearbeitet
asdca
Unregistrierter




Beitrag asdca Unregistrierter 17:07:06 14.03.2009   Titel:              Zitieren

Euer Problem ist, daß ihr immer nur in x86 denkt. x86 ist nicht unbedingt die optimale Plattform für einen Einsteiger mit dem ganzen 20 Jahre alten Schrott wie Realmode, Callgates, Segmentregistern und dem ganzen anderen Mist. Ich verstehe nicht, warum immer alle Welt sowas immer unbedingt für die x86 Architektur machen muss. Die ist nicht nur hässlich, sondern auch klobig und extrem Noobunfreundlich.
asdca
Unregistrierter




Beitrag asdca Unregistrierter 17:08:43 14.03.2009   Titel:              Zitieren

Gleicher Flame richtet sich natürlich auch an div. Buchautoren.
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 17:20:04 14.03.2009   Titel:              Zitieren

asdca schrieb:
Euer Problem ist, daß ihr immer nur in x86 denkt. x86 ist nicht unbedingt die optimale Plattform für einen Einsteiger mit dem ganzen 20 Jahre alten Schrott wie Realmode, Callgates, Segmentregistern und dem ganzen anderen Mist. Ich verstehe nicht, warum immer alle Welt sowas immer unbedingt für die x86 Architektur machen muss. Die ist nicht nur hässlich, sondern auch klobig und extrem Noobunfreundlich.

da bin ich voll bei dir. erhard: mach was für 'ne ARM-plattform. ich wette es gibt mehr ARM-basierte systeme auf der welt als PC(x86)-kisten.
:)
Verärgerter Gast
Unregistrierter




Beitrag Verärgerter Gast Unregistrierter 17:48:15 14.03.2009   Titel:              Zitieren

+fricky schrieb:
asdca schrieb:
Euer Problem ist, daß ihr immer nur in x86 denkt. x86 ist nicht unbedingt die optimale Plattform für einen Einsteiger mit dem ganzen 20 Jahre alten Schrott wie Realmode, Callgates, Segmentregistern und dem ganzen anderen Mist. Ich verstehe nicht, warum immer alle Welt sowas immer unbedingt für die x86 Architektur machen muss. Die ist nicht nur hässlich, sondern auch klobig und extrem Noobunfreundlich.

da bin ich voll bei dir. erhard: mach was für 'ne ARM-plattform. ich wette es gibt mehr ARM-basierte systeme auf der welt als PC(x86)-kisten.
:)

Ich könnt kotzen :mad:, da +fricky recht hat :D
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 18:16:27 14.03.2009   Titel:              Zitieren

Verärgerter Gast schrieb:

Ich könnt kotzen :mad:, da +fricky recht hat :D

wie jetzt?!?
ach ja, erhard: wie wär's mit 'nem OS für nintendo-DS? die plattform ist weit verbreitet, einigermaßen gut 'reverse engineered' und es gibt, meines wissens, bisher nur ein hobbyisten-OS dafür.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:15:16 14.03.2009   Titel:              Zitieren

ARM, Nintendo DS etc. ist sicher sehr interessant, leider hat nicht jeder so etwas greifbar, vom Programmieren mal abgesehen. Die 80i86 Historie hat uns wirklich einen monströsen Wirrwarr als Kellerfundament hinterlassen. Da habt ihr völlig Recht. Aber umso größer die didaktische Herausforderung. ;)

Ich versuche die Reihenfolge:

1) Werkzeuge bereit stellen
2) Praktisches Arbeiten
3) Notwendiges Backgroundwissen praxisnah vermitteln
4) Experimentieren, um Auswirkungen zu zeigen

einzuhalten.

Wenn man einsteigt, benötigt man z.B. zunächst nur das Wissen über CPU, Register und Interrupts. Das findet man heute alles ordentlich bei wiki ... :)

Das Mittel, das viele an der Hand haben, die am Internet hängen und Tutorials lesen, ist nun mal der 80i86 PC mit MS Windows.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 22:07:54 14.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Das Mittel, das viele an der Hand haben, die am Internet hängen und Tutorials lesen, ist nun mal der 80i86 PC mit MS Windows.

klar, aber du nutzt doch sowieso 'nen simulator (bochs) für deine experimente. dann könntest du auch 'nen simulator für eine interessante plattform verwenden, und nicht für dieses stokelige x86-gedöns.
:)
''
Unregistrierter




Beitrag '' Unregistrierter 22:27:21 14.03.2009   Titel:              Zitieren

das 'monströse Wirrwarr' machts aber gerade interessant.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:58:57 14.03.2009   Titel:              Zitieren

@+fricky: Gegen dieses Argument kann man nur einwenden, dass nach der Emulation auch noch die echte Anwendung kommen sollte. Bei ARM fallen mir sofort z.B. Roboter und sonstige Elektronikanwendungen ein, ein schönes Thema, aber man kann nicht alles gleichzeitig machen.
@": Ich denke, dass einige User, die mit dem PC unter MS Windows arbeiten, vielleicht einfach mal Lust haben, ein OS zum Ticken zu bringen. Das Entscheidende dabei ist die praktische Beherrschung des Themas, denn nur dann hat man die Kraft und Leidenschaft zum Experimentieren und Umsetzen von Ideen. Das ist der entscheidende Punkt, wo viele didaktische Ansätze stecken bleiben.

Im ersten praktischen Schritt habe ich den Mini-Kernel komplett bootbar in Sektor 1 geschrieben.

Im nächsten Schritt wird ein Bootloader in Sektor 1 vorgeschaltet, der den gleichen Mini-Kernel nun aus Sektor 2 lädt (BIOS INT für Floppy Disk) und im Speicher anspringt. Im Kernel wird dann lediglich die Boot-Signatur entfernt und die Segment-Adresse geändert.

Das ist technisch für den Ersteller einfach durchführbar:

nasm boot.asm -f bin -o boot.bin
nasm kernel.asm -f bin -o kernel.bin
copy /b boot.bin + kernel.bin myOS.img
partcopy myOS.img 0 400 -f0

siehe: http://www.henkessoft.de/OS_Dev/OS_Dev1.htm

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:16:44 15.03.2009, insgesamt 4-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 12:14:13 15.03.2009   Titel:              Zitieren

Zitat:
Bitte denken Sie daran, sich für solche Aufgaben entsprechende bat-Dateien zu schreiben, wenn Sie experimentieren.

Habe das Tutorial mal kurz überflogen und das ist der Satz, der mich persönlich "stört". Ich bin nämlich für den Einsatz von Makefiles. Man kann nämlich die Makefiles wie gewöhnliche Batch-Dateien schreiben mit dem Vorteil der "automatischen" Fehlerbehandlung:
Code:
all:
    nasm boot.asm -f bin -o boot.bin
    nasm kernel.asm -f bin -o kernel.bin
    copy /b boot.bin + kernel.bin myOS.img
    partcopy myOS.img 0 400 -f0
Code:
all:
nasm boot.asm -f bin -o boot.bin
nasm kernel.asm -f bin -o kernel.bin
copy /b boot.bin + kernel.bin myOS.img
partcopy myOS.img 0 400 -f0
Code:
all:
    nasm boot.asm -f bin -o boot.bin
    nasm kernel.asm -f bin -o kernel.bin
    copy /b boot.bin + kernel.bin myOS.img
    partcopy myOS.img 0 400 -f0

Sollte in der einen oder anderen Zeile ein Fehler auftreten, wird Makeprozess sofort abgebrochen... Bei Batch-Dateien müsste man mit unübersichtlichen goto's arbeiten, was dann schnell unübersichtlich wird.
/rant/
Mitglied

Benutzerprofil
Anmeldungsdatum: 18.10.2008
Beiträge: 1552
Beitrag /rant/ Mitglied 14:28:44 15.03.2009   Titel:              Zitieren

Ich habe ganz früher mal einige kleinere Dinge gebaut: Bootloader + Kommandozeile + FAT-Dateisystem + Interpreter (Sah aus wie Assembler, wurde aber interpretiert...). Alles nur 16-bit Assembler mit rawwrite auf Diskette und dann gebootet. Für 32-bit und PMode hatte ich weder die Zeit, noch die Nerven. Die Dokumentation hat mir seinerzeit schon gereicht um zu wissen, dass ich es gar nicht erst versuchen sollte. Warum ich das gemacht habe? Aus Eigeninteresse, und um etwas neues zu lernen. Inzwischen würde ich mich sehr für 64-bit OS-development interessieren, doch wie gesagt habe ich keine Zeit^^

_________________
MCPD, MCTS and more! | "It's 7:05am. I have not slept." | www.google.com
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 15:27:27 15.03.2009   Titel:              Zitieren

Zitat:
Ich bin nämlich für den Einsatz von Makefiles.

Danke für diesen wichtigen Hinweis! Ich denke, zu Beginn erleichtert dies die Sache für einen Einsteiger nicht wirklich. Da lässt man ihn besser die einzelnen Befehlszeilen immer wieder in die Konsole hacken, damit er sich daran gewöhnt. Welches make.exe ohne notwendige DLL würdest Du denn einsetzen? Download-Link? Wo wird der Einsatz möglichst einfach beschrieben? Vielleicht überzeugst Du mich doch noch.

Das waren die Gründe, warum ich mich - zumindest für die ersten Schritte - für bat-Dateien entschieden habe. Langfristig geht dies natürlich nicht, aber momentan habe ich noch keine C-Toolchain im Einsatz. Es gibt nur nasm.exe und partcopy.exe.

Ich habe auch das img gegen bin getauscht, um nicht zu verwirren:
Code:
nasm boot.asm   -f bin -o boot.bin
nasm kernel.asm -f bin -o kernel.bin
copy /b boot.bin + kernel.bin MyOS.bin
partcopy MyOS.bin 0 400 -f0
Code:
nasm boot.asm -f bin -o boot.bin
nasm kernel.asm -f bin -o kernel.bin
copy /b boot.bin + kernel.bin MyOS.bin
partcopy MyOS.bin 0 400 -f0
Code:
nasm boot.asm   -f bin -o boot.bin
nasm kernel.asm -f bin -o kernel.bin
copy /b boot.bin + kernel.bin MyOS.bin
partcopy MyOS.bin 0 400 -f0


EDIT: Habe doch noch ein einfaches make.exe ohne DLL gefunden:
http://www.steve.org.uk/Software/make/make.zip
EDIT1: Bei den Bin-Tools von gcc 2.03 ist auch ein alleinstehendes make.exe dabei: http://www.osdever.net/downloads/compilers/DJGPP-Installer-nocpp.exe

Ich werde dies im Tutorial abändern, weil der Einsatz von make.exe / makefile langfristig wirklich der richtige Weg ist. :live:

Ist als Alternative zu den bat-Dateien dargestellt, siehe
http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId748324 (Kapitel 4.5.3)
Praktisches Hindernis können die notwendigen Separatoren im makefile sein, aber gvim zeigt dies sehr gut durch fehlende bzw. vorhandene rote Schriftfarbe an.
Ein Einstieg in den make-Prozess muss auf jeden Fall erfolgen. Da führt wahrlich kein Weg beim OS Development vorbei.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 14:07:00 28.03.2009, insgesamt 5-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:40:51 15.03.2009   Titel:              Zitieren

Zitat:
Bootloader + Kommandozeile + FAT-Dateisystem + Interpreter (Sah aus wie Assembler, wurde aber interpretiert...).

bootloader + command-line interpreter ist nun vorhanden, zumindest im Real Mode. Einige Befehle und strcmp wurden bereits implementiert, damit man Experimente mit eigenen Befehlen leicht beginnen kann. Vielfach wird hier in Tutorials nur der Reboot eingebaut und man wird mit "Go wild!" oder "Viel Spaß!" alleine gelassen.
Den Reboot haben wir mit "exit" natürlich auch schon. Ich hoffe, dass ich bisher alles möglichst verständlich und zum praktischen Nachmachen einladend dargestellt habe, sonst kann ich gleich aufhören. Diesbezüglich bitte ich um ernsthaftes Feedback.

Der Tipp mit dem make-Prozess wurde inzwischen umgesetzt. Danke!

Vielleicht könnt ihr auch über den Code schauen, denn bei einem OS sollte alles möglichst performant laufen.

@/rant/: Wenn Du Lust hast, kannst Du mich gerne unterstützen, soweit Du kannst.
Hier steht nichts unter Zeitdruck. Didaktische Qualität und leichte Umsetzung ist wichtig und geht vor Quantität.

Die Umschaltung von RM nach PM übernehme ich gerne. Da knoble ich noch an der Didaktik.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 18:44:24 15.03.2009, insgesamt 1-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 22:18:35 15.03.2009   Titel:              Zitieren

Hallo,

habe mal aus Neugier das Tutorial "durchgearbeitet" (mit copy-paste natürlich ;)).
Habe mit bochs folgende Erfahrung gemacht: Booten funktioniert auch mit von nasm erzeugten Binärdateien. D.h. man benötigt nicht unbedingt ein Diskettenlaufwerk oder sonstiges. In der bochsrc.txt reicht z.B. folgendes:
Code:
floppya: 1_44=c:\BochsMyOS\MyOS.bin, status=inserted
Code:
floppya: 1_44=c:\BochsMyOS\MyOS.bin, status=inserted
Code:
floppya: 1_44=c:\BochsMyOS\MyOS.bin, status=inserted

Und die Datei MyOS.bin erzeugen wie immer:
Code:
nasm.exe kernel.asm -f bin -o MyOS.bin
Code:
nasm.exe kernel.asm -f bin -o MyOS.bin
Code:
nasm.exe kernel.asm -f bin -o MyOS.bin

Finde ich schön, weil wer hat denn heutzutage ein Diskettenlaufwerk...

Und ein Problem habe ich mit meinem Makefile gehabt. Folgende Zeile wollte make irgendwie nicht akzeptieren:
Code:
    ...
    copy /b bootloader.bin + kernel.bin MyOS.bin
Code:
...
copy /b bootloader.bin + kernel.bin MyOS.bin
Code:
    ...
    copy /b bootloader.bin + kernel.bin MyOS.bin

Da kommt bei mir immer folgende Fehlermeldung:
Code:
process_begin: CreateProcess(NULL, copy /b bootloader.bin + kernel.bin MyOS.bin, ...) failed.
make (e=2): Das System kann die angegebene Datei nicht finden.
mingw32-make: *** [OS3] Error 2
Code:
process_begin: CreateProcess(NULL, copy /b bootloader.bin + kernel.bin MyOS.bin, ...) failed.
make (e=2): Das System kann die angegebene Datei nicht finden.
mingw32-make: *** [OS3] Error 2
Code:
process_begin: CreateProcess(NULL, copy /b bootloader.bin + kernel.bin MyOS.bin, ...) failed.
make (e=2): Das System kann die angegebene Datei nicht finden.
mingw32-make: *** [OS3] Error 2

Und hier ein "Workaround":
Code:
...
    cmd /c copy /b bootloader.bin + kernel.bin MyOS.bin
Code:
...
cmd /c copy /b bootloader.bin + kernel.bin MyOS.bin
Code:
...
    cmd /c copy /b bootloader.bin + kernel.bin MyOS.bin

Man muss also eine neue Instanz der Windows Befehlsinterpreters cmd starten und das eine Kommando übergeben. Warum auch immer. Aber wie dem auch sei, mein Makefile sieht jetzt so aus:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
all:
    @echo Please select target: OS1 or OS2 or OS3

OS1:
    @echo OS1 selected.
    rm -fv kernel.bin bootloader.bin MyOS.bin
    c:\nasm-2.06rc6\nasm.exe kernel.asm -f bin -o MyOS.bin
    @echo Ready.

OS2:
    @echo OS2 selected.
    rm -fv kernel.bin bootloader.bin MyOS.bin
    c:\nasm-2.06rc6\nasm.exe kernel2.asm -f bin -o MyOS.bin
    @echo Ready.

OS3:
    @echo OS3 selected.
    rm -fv kernel.bin bootloader.bin MyOS.bin
    c:\nasm-2.06rc6\nasm.exe bootloader.asm -f bin -o bootloader.bin
    c:\nasm-2.06rc6\nasm.exe kernel3.asm -f bin -o kernel.bin
    cmd /c copy /b bootloader.bin + kernel.bin MyOS.bin
    @echo Ready.

clean:
    rm -fv kernel.bin bootloader.bin MyOS.bin
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
all:
@echo Please select target: OS1 or OS2 or OS3

OS1:
@echo OS1 selected.
rm -fv kernel.bin bootloader.bin MyOS.bin
c:\nasm-2.06rc6\nasm.exe kernel.asm -f bin -o MyOS.bin
@echo Ready.

OS2:
@echo OS2 selected.
rm -fv kernel.bin bootloader.bin MyOS.bin
c:\nasm-2.06rc6\nasm.exe kernel2.asm -f bin -o MyOS.bin
@echo Ready.

OS3:
@echo OS3 selected.
rm -fv kernel.bin bootloader.bin MyOS.bin
c:\nasm-2.06rc6\nasm.exe bootloader.asm -f bin -o bootloader.bin
c:\nasm-2.06rc6\nasm.exe kernel3.asm -f bin -o kernel.bin
cmd /c copy /b bootloader.bin + kernel.bin MyOS.bin
@echo Ready.

clean:
rm -fv kernel.bin bootloader.bin MyOS.bin
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
all:
    @echo Please select target: OS1 or OS2 or OS3

OS1:
    @echo OS1 selected.
    rm -fv kernel.bin bootloader.bin MyOS.bin
    c:\nasm-2.06rc6\nasm.exe kernel.asm -f bin -o MyOS.bin
    @echo Ready.

OS2:
    @echo OS2 selected.
    rm -fv kernel.bin bootloader.bin MyOS.bin
    c:\nasm-2.06rc6\nasm.exe kernel2.asm -f bin -o MyOS.bin
    @echo Ready.

OS3:
    @echo OS3 selected.
    rm -fv kernel.bin bootloader.bin MyOS.bin
    c:\nasm-2.06rc6\nasm.exe bootloader.asm -f bin -o bootloader.bin
    c:\nasm-2.06rc6\nasm.exe kernel3.asm -f bin -o kernel.bin
    cmd /c copy /b bootloader.bin + kernel.bin MyOS.bin
    @echo Ready.

clean:
    rm -fv kernel.bin bootloader.bin MyOS.bin

Man kann also mit make OS1 oder make OS2 oder make OS3 das eine oder andere assemblieren lassen...
Ansonsten hat alles wunderbar funktioniert (unter bochs) ;) Bin gespannt auf Protected Mode.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:49:48 15.03.2009   Titel:              Zitieren

Zitat:
habe mal aus Neugier das Tutorial "durchgearbeitet"

Danke für den Test und das positive Feedback.

Zitat:
floppya: 1_44=c:\BochsMyOS\MyOS.bin, status=inserted

Darauf habe ich sofort im Tutorial als Alternative für das config-File hingewiesen.
Heute gibt es wirklich kaum noch Floppy Disk Laufwerke. Aber es ist für viele Coder einfach ein tolles Gefühl, wenn man einen (alten) PC mit einem selbst gebastelten OS physisch von einer Floppy booten lassen kann. :D
Da ich selbst noch eines an meinem PC eingebaut habe, verwende ich es natürlich. Ich mag einfach dieses Klack-Geräusch und das aufleuchtende Lämpchen, wenn die Floppy angesprungen wird. Aber man muss mit der Zeit gehen. :D

Danke für den "Workaround" bezüglich copy. Ich verwende noch Win XP. Vielleicht klappt es deshalb. Weiß eigentlich jemand wo dieses copy heutzutage auf der Platte steckt? In win/system32 habe ich es nicht gefunden.

Das ausgefeilte makefile wird sicher auch noch Verwendung finden, ich möchte aber nicht zu früh vom eigentlichen OS ablenken. Die Tools sind vor allem Mittel zum Zweck, und gerade beim Thema makefile blicken viele - durch die IDEs - nicht mehr durch.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:56:04 15.03.2009, insgesamt 1-mal bearbeitet
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 13:36:08 16.03.2009   Titel:              Zitieren

Hab's mal ueberflogen ... besonders die Codes:

1. Beispiel:
Z. 19 (mov si, ...) ist ueberfluessig
(Auf Kosten der Uebersicht haette man das und evtl. einiges Andere nat. insgesamt auch effizienter loesen koennen...)

Z. 103, 104 (mov ah, ...; mov al, ...) ist uebelste x86-Suende: sowas schreibt man wenn irgendwie moeglich immer auf einmal in das uebergeordnete Register (hier ax)

Z. 119, 120 das gleiche

Das strcmp koennte man IMHO nun aber wirklich effizienter machen:
Z. 130 ist ueberfluessig. Vergleiche besser direkt al mit [di]
"cmp reg, 0" kannst du gegen "or al, al" o.Ae. tauschen (wie du es schon in print_string machst)
ich bevorzuge da "test reg, reg", AFAIR belegt das weniger Platz... Zumindest solltest du dich mal fuer eins entscheiden. ;)
Es waere auch sinnvoller, das Ergebnis im Z-Flag zurueck zu geben. Das ist naemlich bei deinem Code so wie so schon 0, wenn eq und 1, wenn nicht eq... -> Kram mit CF weg und nur ein Ruecksprung-Label. :)

Z. 96 wieder der 0-Vergleich...

Es waere uebrigens sinnvoll, die Initialisierung des Stacks nicht unter den Tisch fallen zu lassen.
Ich bin mir nicht mal sicher, wo das BIOS den Stack anfangs hinzaubert. AFAIK gilt das als undefiniert. Da sollte man eigentlich nicht so einfach reinschreiben. Ein ueberwaeltigender Aufwand ist das nun wirklich auch nicht. Um dem Vorzubeugen: um das mov ss,.. und mov sp,.. gehoeren keine cli/sti, da man bei Intel so schlau war, bei "mov ss, ... " automatisch die Interrupts fuer die naechste Instruktion zu unterdruecken.

Den "buffer" haette man um Platz zu sparen zB. auch auf den Stack packen koennen.


Beispiel "Bootloader":
Z. 30: xor ax, ax waere kuerzer... (Z. 37 dito)
Z. 41-45: Wieder direkt hintereinander 8Bit-Register mit Konstanten geladen: Boese!

insgesamt ist das nat. ein *sehr* rudimentaerer BL, aber ich gehe mal davon aus, das war beabsichtigt...


Beispiel in 4.5.2:
IMHO wenig sinnvoll, es und ds in BL und Kern direkt hintereinander auf den selben Wert zu setzen. Das im Kern wuerde reichen.

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
Unregistrierter





Beitrag Unregistrierter 15:26:31 16.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Weiß eigentlich jemand wo dieses copy heutzutage auf der Platte steckt? In win/system32 habe ich es nicht gefunden.

COPY ist als "Funktion" in der cmd.exe integriert. Ist deshalb nur verfügbar in einer Konsole.
rapso
Moderator

Benutzerprofil
Anmeldungsdatum: 17.06.2002
Beiträge: 7282
Beitrag rapso Moderator 18:34:32 16.03.2009   Titel:   Re: Eigenes OS?            Zitieren

Erhard Henkes schrieb:
Mich würde mal interessieren, wer alleine oder mit anderen an einem eigenen OS entwickelt, zu welchem Zweck und in welcher Sprache (ASS, C oder C++)? Links?

hab auf dos einen multitasking aufsatz gecodet, damit konnte ich dann unter dos mehrere programme gleichzeitig laufen lassen (und ein TSR was im hintergrund per timer interrupt 92mal in 5sekunden die tasks gewechselt hat, wenn ich das noch recht im kopf habe.
hab ein game os in flat-memory-mode geschrieben, darin funktionierten die 16bit treiber usw. leider nicht, war damit man auf den ganzen speicher zugreifen konnte ohne XMM usw.
fuer gameboy ein simples OS das mir noch erlaubt hat primitiv den speicher zu begutachten nach nem absturz.
fuer ps3 hab ich nen simples OS erweitert damit ich andere aufloesungen und den zweiten ppu-thread nutzen kann. hab dann noch ein lightweith task system geschrieben. :)

_________________
Kilo Byte=1000,Kilobyte=1024 ANSI/IEEE Standard 1084-1986
rapso
-Mod im Spiele-/Grafikprogrammierung| rapsoo@hotmail.com | #dionysos irc.quakenet.org | amazon stole my PS3 :(
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:27:05 16.03.2009   Titel:              Zitieren

Zitat:
Es waere uebrigens sinnvoll, die Initialisierung des Stacks nicht unter den Tisch fallen zu lassen.
Ich hatte einen geschrieben, selbstverständlich ohne cli/sti, habe ihn aber im Tutorial gelöscht, weil es auch so lief (Didaktik ;)).
Reicht es, wenn man den Stack erst im Kernel implementiert? Im BL (bewusst primitiv gehalten, weil ansonsten immer zu GRUB geraten wird) hat der Stack m.E. noch nichts zu suchen.

Die al/ah vs. ax Geschichte macht Sinn (werde ich abändern auf ax), weil wir auf jeden Fall nicht unter 16 bit anfangen müssen.

Welche Speicheradressen würdet ihr verwenden?
0x0000:0x07C0 für den Bootloader ist klar
0x1000:0x0000 für den Kernel?
0x9000:0x0000 für den noch einzurichtenden Stack?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 21:49:08 17.03.2009, insgesamt 3-mal bearbeitet
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 20:36:09 16.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zitat:
Es waere uebrigens sinnvoll, die Initialisierung des Stacks nicht unter den Tisch fallen zu lassen.
Ich hatte einen geschrieben, selbstverständlich ohne cli/sti, habe ihn aber im Tutorial gelöscht, weil es auch so lief (Didaktik ;)).
Reicht es, wenn man den Stack erst im Kernel implementiert? Im BL (bewusst primitiv gehalten, weil ansonsten immer zu GRUB geraten wird) hat der Stack m.E. noch nichts zu suchen.

Dafuer, dass er im BL "noch nichts zu suchen hat", machst du aber doch regen Gebrauch davon. ;)
Wenn du es ganz sauber haben willst, kannst du ihn im Kern nochmal an eine ausgekluegeltere Stelle verfrachten.

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:49:46 16.03.2009   Titel:              Zitieren

Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
    ; set parameters for reading function
    ; 8-bit-wise for better overview
    mov dl,[bootdrive] ; select boot drive
    mov al,10          ; read 10 sectors
    mov ch, 0          ; cylinder = 0
    mov cl, 2          ; sector   = 2
    mov dh, 0          ; head     = 0
    mov ah, 2          ; function "read"  
Code:
1
2
3
4
5
6
7
8
; set parameters for reading function
; 8-bit-wise for better overview
mov dl,[bootdrive] ; select boot drive
mov al,10 ; read 10 sectors
mov ch, 0 ; cylinder = 0
mov cl, 2 ; sector = 2
mov dh, 0 ; head = 0
mov ah, 2 ; function "read"
Code:
1
2
3
4
5
6
7
8
    ; set parameters for reading function
    ; 8-bit-wise for better overview
    mov dl,[bootdrive] ; select boot drive
    mov al,10          ; read 10 sectors
    mov ch, 0          ; cylinder = 0
    mov cl, 2          ; sector   = 2
    mov dh, 0          ; head     = 0
    mov ah, 2          ; function "read"  

Das bleibt! Hier geht die Didaktik vor. :)
Ansonsten danke für die Tipps!
Ich habe alle Helfer bereits "namentlich" im Tutorial erwähnt. :live:

http://www.henkessoft.de/OS_Dev/OS_Dev1.htm

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:09:24 16.03.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:21:42 17.03.2009   Titel:              Zitieren

Zitat:
Dafuer, dass er im BL "noch nichts zu suchen hat", machst du aber doch regen Gebrauch davon. ;)
OK, ich sehe es ein:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
     org 0x7C00  ; set up start address

    ; setup a stack
    mov ax, 0x9000  ; address of the stack
    mov ss, ax      ; SS = 0x9000
    xor sp, sp      ; SP = 0x0000

    ; start
    mov [bootdrive], dl ; boot drive from DL
    call load_kernel    ; load kernel
 
    ; jump to kernel
    jmp 0x1000:0x0000   ; address of kernel
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
org 0x7C00 ; set up start address

; setup a stack
mov ax, 0x9000 ; address of the stack
mov ss, ax ; SS = 0x9000
xor sp, sp ; SP = 0x0000

; start
mov [bootdrive], dl ; boot drive from DL
call load_kernel ; load kernel

; jump to kernel
jmp 0x1000:0x0000 ; address of kernel
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
     org 0x7C00  ; set up start address

    ; setup a stack
    mov ax, 0x9000  ; address of the stack
    mov ss, ax      ; SS = 0x9000
    xor sp, sp      ; SP = 0x0000

    ; start
    mov [bootdrive], dl ; boot drive from DL
    call load_kernel    ; load kernel
 
    ; jump to kernel
    jmp 0x1000:0x0000   ; address of kernel

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 10:59:02 17.03.2009   Titel:              Zitieren

mit einem "OS" hat dieses x86er-bootloader gefrickel noch nicht viel zu tun. wann geht's denn endlich los mit multitasking, betriebsmittelverwaltung, hal, etc.
:)
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 13:38:02 17.03.2009   Titel:              Zitieren

:o)
Im Prinzip richtig. Nur duerfte es sehr schwierig werden, dieses weite, eher theorielastige Themengebiet geschickt mit Erhards praktisch ausgerichteter Didaktik unter einen Hut zu bringen.

Erhard Henkes schrieb:
Das bleibt! Hier geht die Didaktik vor. :)

Ok, aber vielleicht kann ich dich noch ueberzeugen, der Sache einen kleinen Kommentar zur Effizienz beizufuegen. Ich kriege jedes Mal einen Krampf, wenn ich sowas sehe (zuletzt sogar in einem kommerziellen BL). :D

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908


Zuletzt bearbeitet von Nobuo T am 13:39:20 17.03.2009, insgesamt 1-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 14:30:39 17.03.2009   Titel:              Zitieren

Ins Kapitel "4.5.1 Bootloader" passt ev. noch einiges zur relativen (segmentierten) Schreibweise von Adressen:
Code:
Relative Adresse -> Segment:Offset
Absolute Adresse -> (Segment * 0x10) + Offset
Code:
Relative Adresse -> Segment:Offset
Absolute Adresse -> (Segment * 0x10) + Offset
Code:
Relative Adresse -> Segment:Offset
Absolute Adresse -> (Segment * 0x10) + Offset
Assembler Code:
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
org 0x7C00 ; set up start address  

; setup a stack
mov ax, 0x9000  ; address of the stack
mov ss, ax      ; SS = 0x9000
xor sp, sp      ; SP = 0x0000
(...)
; jump to kernel
jmp 0x1000:0x0000   ; address of kernel
Assembler Code:
1
2
3
4
5
6
7
8
9
org 0x7C00 ; set up start address

; setup a stack
mov ax, 0x9000 ; address of the stack
mov ss, ax ; SS = 0x9000
xor sp, sp ; SP = 0x0000
(...)
; jump to kernel
jmp 0x1000:0x0000 ; address of kernel
Assembler Code:
1
2
3
4
5
6
7
8
9
org 0x7C00 ; set up start address  

; setup a stack
mov ax, 0x9000  ; address of the stack
mov ss, ax      ; SS = 0x9000
xor sp, sp      ; SP = 0x0000
(...)
; jump to kernel
jmp 0x1000:0x0000   ; address of kernel
Zitat:
Das Programm startet bei 0x7C00, legt einen Stack an bei 0x9000, lädt den Kernel nach 0x1000 und springt dorthin.
Das Programm startet relativ bei 0000:7c00, absolut bei (0000*0x10)+7c00 = 0x7c00.
Aber der Stack liegt relativ bei 9000:0000, absolut bei (9000*0x10)+0 = 0x90000.
Der Kernel liegt somit absolut bei 0x10000, weshalb der Bootloader alleine locker (0x10000 - 0x7c00 = 0x8400) über 33 KB groß sein kann.
Prinzipiell eine nicht akzeptable Verschwendung von (einstmals) wertvollen Speicherplatz. :)
Aber das sollte vorerst keine Rolle spielen. Didaktik geht vor! :live:
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:25:08 17.03.2009   Titel:              Zitieren

Zitat:
... weshalb der Bootloader alleine locker (0x10000 - 0x7c00 = 0x8400) über 33 KB groß sein kann.

Guter Hinweis! Ich erkläre jetzt mal, warum mir die Didaktik und ein umfassendes Verständnis wichtiger ist als ein schnelles Vorwärtsschreiten, bei dem man viele verliert und wichtige Details auf der Strecke bleiben.

So findet man dies nun im Tutorial:
Code:
0h *  16^4 + 8h * 16^3 + 4h * 16^2 + 0h * 16^1 + 0h * 16^0  =
0  * 65536 + 8  * 4096 + 4  * 256  + 0  * 16   + 0  * 1     =
             32768     + 1024                               =  33792
Code:
0h * 16^4 + 8h * 16^3 + 4h * 16^2 + 0h * 16^1 + 0h * 16^0 =
0 * 65536 + 8 * 4096 + 4 * 256 + 0 * 16 + 0 * 1 =
32768 + 1024 = 33792
Code:
0h *  16^4 + 8h * 16^3 + 4h * 16^2 + 0h * 16^1 + 0h * 16^0  =
0  * 65536 + 8  * 4096 + 4  * 256  + 0  * 16   + 0  * 1     =
             32768     + 1024                               =  33792


33792 Byte / 1024 = 33 KByte

Korrekt ist also:
Der Bootloader darf höchstens 33 KB groß sein.

Würdet ihr den Kernel auf 7E00h setzen? Dann passt kein Byte mehr dazwischen.
Eigentlich könnte man sogar die beiden Boot-Signatur-Bytes überschreiben?
Also 7DFEh als Minimum? Didaktisch interessante Frage, finde ich.

Experiment mit 7DFEh: Absturz (bleibt "hängen", lädt keinen Kernel)
Experiment mit 7E00h: läuft ständig im Kreis (Bootloader Message erscheint und wird wieder gelöscht)
Also: Wieviel Abstand wird genau benötigt und warum?

Zitat:
Ins Kapitel "4.5.1 Bootloader" passt ev. noch einiges zur relativen (segmentierten) Schreibweise von Adressen

Ich habe ein Kap. 4.5.4 "Background-Wissen: Speicheradressierung im Real Mode (RM)" aufgenommen und in 4.5.1 darauf verwiesen:
Zitat:
Das Programm startet bei 07C00h, legt einen Stack an bei 90000h, lädt den Kernel nach 10000h und springt dorthin.
Adressierung im Real Mode siehe Abschnitt 4.5.4

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:49:17 17.03.2009, insgesamt 5-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:17:29 17.03.2009   Titel:              Zitieren

Zitat:
vielleicht kann ich dich noch ueberzeugen, der Sache einen kleinen Kommentar zur Effizienz beizufuegen. Ich kriege jedes Mal einen Krampf, wenn ich sowas sehe


@Nobuo T:
Das möchte ich nicht, dass Dir schlecht wird bei dem Code. :D
Wir brauchen Dich noch zum Überprüfen/Optimieren.
Ich habe auf Deinen Wunsch hin folgende Passage ergänzt:
Zitat:

Hinweis: Die Verwendung des High und Low Byte eines Registers in Verbindung mit dem Befehl mov, wenn genau so gut das gesamte 16-Bit-Register mit einem Befehl bedient werden könnte, ist eine Verschwendung von Prozessortakten! Dies geschieht in obigem Fall nur der besseren Übersicht wegen. Performanter Programmierstil ist dies nicht.

Also anstelle

mov al,10 (mov al, 0x0A)
mov ah, 2

verwendet man performant

mov ax, 0x020A

Nun wollte ich schreiben, wieviele Takte man oben und unten benötigt, habe aber keine Übersichtslisten gefunden. Kennt sich da jemand aus? Link?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:19:47 17.03.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:04:03 18.03.2009   Titel:              Zitieren

Muss man eigentlich auch auf das Little Endian-Format bei Intel Prozessoren ("Lowest Byte first") eingehen? Ich denke ja, denn bereits, wenn man
Code:
times 510-($-$$) db 0
dw 0xAA55
Code:
times 510-($-$$) db 0
dw 0xAA55
Code:
times 510-($-$$) db 0
dw 0xAA55

schreiben wollte, anstelle
Code:
times 510-($-$$) db 0
db 0x55
db 0xAA
Code:
times 510-($-$$) db 0
db 0x55
db 0xAA
Code:
times 510-($-$$) db 0
db 0x55
db 0xAA

Dann muss man die veränderte Reihenfolge erklären. Im Hexeditor sieht man ja auch:
aus dw 0xAA55 wird im Speicher 55AA

Zur Vermeidung habe ich zwei Mal db verwendet. :D

Zitat:
wann geht's denn endlich los mit multitasking, betriebsmittelverwaltung, hal, etc.
Hoffentlich bist Du noch jung. Das kann noch etwas dauern. :D Nein, im Ernst. Ich möchte jeden Schritt genau ausloten, niemand verlieren.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:24:38 18.03.2009, insgesamt 3-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 10:21:05 18.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Muss man eigentlich auch auf das Little Endian-Format bei Intel Prozessoren ("Lowest Byte first") eingehen? Ich denke ja

das solltest du unbedingt tun, mit begründung, warum die x86'er sowas machen. und dann nicht nur für 2-byte werte.

Erhard Henkes schrieb:

Zitat:
wann geht's denn endlich los mit multitasking, betriebsmittelverwaltung, hal, etc.
Hoffentlich bist Du noch jung. Das kann noch etwas dauern. :D

hoffentlich bist du noch jung. bei den themen kannste dir 'nen wolf schreiben.
:)
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 14:10:04 18.03.2009   Titel:              Zitieren

Also wenn schon, denn schon:
Zitat:

Hinweis: Die Verwendung des High und Low Byte eines Registers in Verbindung mit dem Befehl mov, wenn genau so gut das gesamte 16-Bit-Register mit einem Befehl bedient werden könnte, ist eine Verschwendung von Speicherplatz und Prozessortakten (in diesem Fall 1 Byte und max. z.B. auf einem 486 1 Takt zusätzlich)! Dies geschieht in obigem Fall nur der besseren Übersicht wegen. Performanter Programmierstil ist dies nicht.

Also anstelle

mov al,10 (mov al, 0x0A)
mov ah, 2

verwendet man performant

mov ax, 0x020A



Erhard Henkes schrieb:

Nun wollte ich schreiben, wieviele Takte man oben und unten benötigt, habe aber keine Übersichtslisten gefunden. Kennt sich da jemand aus? Link?

Ist alles ziemlich undurchsichtig. Quellen waeren Docs aktueller CPU von den Herstellern. Wie aber bereits erwaehnt, braucht schon der 486 max. 1 Takt fuer so ein mov - auf neueren CPU werden das vermutlich nicht mehr sein.
Zumindest AMDs fruehere 64Bitter liessen sich von sowas AFAIR auch gern mal die Pipeline durcheinander bringen, also wahrscheinlich dann auch 2 Takte.

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:07:09 18.03.2009   Titel:              Zitieren

Zitat:
Also wenn schon, denn schon:
Was meinst Du damit?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 19:03:06 18.03.2009   Titel:              Zitieren

Ich habe mir erlaubt, deinen Text hauptsaechlich um die Erwaehnung des zusaetzlichen Speicherplatzverbrauchs zu erweitern (was in einem BL wichtiger sein duerfte als 1 verpulverter CPU-Takt), falls das nicht aufgefallen sein sollte... :)

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 20:06:14 18.03.2009   Titel:              Zitieren

Bezüglich Takte gibt es hier http://www.agner.org/optimize/ unter "4. Instruction tables: Lists of instruction latencies, throughputs and micro-operation breakdowns for Intel and AMD CPU's" eine schöne Übersicht über die ganzen Befehle und deren Takte, uOps und was weiss der Teufel noch was... falls es jemand genauer wissen möchte.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:45:04 18.03.2009   Titel:              Zitieren

Zitat:
Ich habe mir erlaubt, deinen Text hauptsaechlich um die Erwaehnung des zusaetzlichen Speicherplatzverbrauchs zu erweitern (was in einem BL wichtiger sein duerfte als 1 verpulverter CPU-Takt), falls das nicht aufgefallen sein sollte... :)
Sorry! Danke für die Ergänzung. Jedes Byte im ersten Sektor ist wertvoll.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:17:22 19.03.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:16:42 19.03.2009   Titel:              Zitieren

Ich wollte mal auf die Schnelle in den PM umschalten, macht aber einen Reset. Ich finde momentan den Fehler einfach nicht. Liegt es an GDTR/GDT, am fehlenden IDT oder am far jump?

Vielleicht sollte ich doch auf C umsatteln? Mir gefällt Assembler aber didaktisch besser, weil es klarer ist. Kann bitte jemand nachhelfen?

Hier die kernel.asm:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  mov ax, 0x1000  ; set up segments
  mov ds, ax
  mov es, ax

  mov si, welcome
  call print_string

loop:
  mov si, prompt
  call print_string

  mov di, buffer
  call get_string

  mov si, buffer
  cmp byte [si], 0  ; blank line?
  je loop           ; yes, ignore it

  mov di, cmd_hi    ; "hi" command
  call strcmp
  jc .helloworld

  mov si, buffer
  mov di, cmd_help  ; "help" command
  call strcmp
  jc .help

  mov si, buffer
  mov di, cmd_questionmark  ; "?" command
  call strcmp
  jc .help
 
  mov si, buffer
  mov di, cmd_exit  ; "exit" command
  call strcmp
  jc .exit

  mov si, buffer
  mov di, cmd_pm  ; "pm (protected mode)" command
  call strcmp
  jc .pm

  mov si,badcommand
  call print_string
  jmp loop

.helloworld:
  mov si, msg_helloworld
  call print_string

  jmp loop

.help:
  mov si, msg_help
  call print_string

  jmp loop

.exit:
  mov si, msg_exit
  call print_string
  jmp 0xffff:0x0000  ; Reboot

.pm:
  mov si, msg_pm
  call print_string
  cli
  lgdt [gdtr]
  mov eax, cr0
  or al, 1
  mov cr0, eax  
  jmp code_gdt:do_pm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; global descriptor table (GDT) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
gdtr:
      dw gdt_end - gdt - 1 ; lenght of GDT
      dd gdt

gdt:                       
      dw 0           ; (0h) Null Segment
      dw 0                   
      db 0                   
      db 0                   
      db 0                   
      db 0

code_gdt:
      dw 0x0FFFF
      dw 0x0000
      db 0x00
      db 0x9A
      db 0xCF
      db 0x00

data_gdt:
      dw 0x0FFFF
      dw 0x0000
      db 0x00
      db 0x92
      db 0xCF
      db 0x00

video_gdt:
      dw 3999 ; Limit 80*25*2-1
      dw 0x8000
      db 0x0B ; Base 0xB8000
      db 0x92
      db 0x00
      db 0x00

gdt_end:  


welcome db 'HenkesSoft 0.02 (version from Mar 18, 2009)', 13, 10, 0
msg_helloworld db 'Hello World!', 13, 10, 0
badcommand db 'Command unknown.', 13, 10, 0
prompt db '>', 0
cmd_hi db 'hi', 0
cmd_help db 'help', 0
cmd_questionmark db '?', 0
cmd_exit db 'exit', 0
cmd_pm db 'pm', 0
msg_help db 'Commands: hi, help, ?, pm, exit', 13, 10, 0
msg_exit db 'Reboot starts now.', 13, 10, 0
msg_pm db 'Switch-over to Protected Mode.', 13, 10, 0

buffer times 32 db 0

; ================
; calls start here
; ================

print_string:
  lodsb        ; grab a byte from SI

  or al, al    ; logical or AL by itself
  jz .done     ; if the result is zero, get out

  mov ah, 0x0E
  int 0x10       ; otherwise, print out the character!

  jmp print_string

.done:
  ret

get_string:
  xor cl, cl

.loop:
  mov ah, 0x00
  int 0x16      ; wait for keypress

  cmp al, 8     ; backspace pressed?
  je .backspace ; yes, handle it

  cmp al, 13    ; enter pressed?
  je .done      ; yes, we're done

  cmp cl, 31    ; 31 chars inputted?
  je .loop      ; yes, only let in backspace and enter

  mov ah, 0x0E
  int 0x10      ; print out character

  stosb  ; put character in buffer
  inc cl
  jmp .loop

.backspace:
  or cl, cl     ; zero? (start of the string)
  jz .loop      ; if yes, ignore the key

  dec di
  mov byte [di], 0  ; delete character
  dec cl        ; decrement counter as well

  mov ax, 0x0E08
  int 0x10      ; backspace on the screen

  mov al, ' '
  int 0x10      ; blank character out

  mov al, 8
  int 0x10      ; backspace again

  jmp .loop     ; go to the main loop

.done:
  mov al, 0     ; null terminator
  stosb

  mov ax, 0x0E0D
  int 0x10
  mov al, 0x0A
  int 0x10      ; newline

  ret

strcmp:
.loop:
  mov al, [si]   ; grab a byte from SI
  cmp al, [di]   ; are SI and DI equal?
  jne .notequal  ; nope, we're done.

  or al, al  ; zero?
  jz .done   ; yes, we're done.

  inc di         ; increment DI
  inc si         ; increment SI
  jmp .loop      ; loop!

.notequal:
  clc            ; not equal, clear the carry flag
  ret

.done:    
  stc            ; equal, set the carry flag
  ret

bits 32

do_pm:
  mov ax, data_gdt
  mov ds,ax
  mov ax, video_gdt
  mov gs, ax
  mov word [gs:0],0x741
.endlessloop:
  jmp .endlessloop

PutStr_32:      
  .nextchar:
    lodsb
    or al, al          
    jz .end      
    mov byte [ds:ecx], al
    inc ecx
    mov byte [ds:ecx], dl
    inc ecx  
    jmp .nextchar  
  .end:
    ret  
; You load the address you want to output to in ecx(0x0B8000), the address of the string (has to be null terminated)
; you want to print in esi and the attributes in dl (personally 0x04, red char on black background) ,
; the lodsb, loads one byte from esi into al then increments esi, then it checks for a null terminator
; then it moves the char into the write position in vid mem and then increments ecx and writes the attributes,
; the loops until it finds a null pointer at which point it breaks....

times 1024-($-$$) db 0
 
;clrscr:
;  mov ax, 0x0600
;  xor cx, cx
;  mov dx, 0x174F
;  xor bh, bh
;  int 0x10
;  ret
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
mov ax, 0x1000 ; set up segments
mov ds, ax
mov es, ax

mov si, welcome
call print_string

loop:
mov si, prompt
call print_string

mov di, buffer
call get_string

mov si, buffer
cmp byte [si], 0 ; blank line?
je loop ; yes, ignore it

mov di, cmd_hi ; "hi" command
call strcmp
jc .helloworld

mov si, buffer
mov di, cmd_help ; "help" command
call strcmp
jc .help

mov si, buffer
mov di, cmd_questionmark ; "?" command
call strcmp
jc .help

mov si, buffer
mov di, cmd_exit ; "exit" command
call strcmp
jc .exit

mov si, buffer
mov di, cmd_pm ; "pm (protected mode)" command
call strcmp
jc .pm

mov si,badcommand
call print_string
jmp loop

.helloworld:
mov si, msg_helloworld
call print_string

jmp loop

.help:
mov si, msg_help
call print_string

jmp loop

.exit:
mov si, msg_exit
call print_string
jmp 0xffff:0x0000 ; Reboot

.pm:
mov si, msg_pm
call print_string
cli
lgdt [gdtr]
mov eax, cr0
or al, 1
mov cr0, eax
jmp code_gdt:do_pm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; global descriptor table (GDT) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
gdtr:
dw gdt_end - gdt - 1 ; lenght of GDT
dd gdt

gdt:
dw 0 ; (0h) Null Segment
dw 0
db 0
db 0
db 0
db 0

code_gdt:
dw 0x0FFFF
dw 0x0000
db 0x00
db 0x9A
db 0xCF
db 0x00

data_gdt:
dw 0x0FFFF
dw 0x0000
db 0x00
db 0x92
db 0xCF
db 0x00

video_gdt:
dw 3999 ; Limit 80*25*2-1
dw 0x8000
db 0x0B ; Base 0xB8000
db 0x92
db 0x00
db 0x00

gdt_end:


welcome db 'HenkesSoft 0.02 (version from Mar 18, 2009)', 13, 10, 0
msg_helloworld db 'Hello World!', 13, 10, 0
badcommand db 'Command unknown.', 13, 10, 0
prompt db '>', 0
cmd_hi db 'hi', 0
cmd_help db 'help', 0
cmd_questionmark db '?', 0
cmd_exit db 'exit', 0
cmd_pm db 'pm', 0
msg_help db 'Commands: hi, help, ?, pm, exit', 13, 10, 0
msg_exit db 'Reboot starts now.', 13, 10, 0
msg_pm db 'Switch-over to Protected Mode.', 13, 10, 0

buffer times 32 db 0

; ================
; calls start here
; ================

print_string:
lodsb ; grab a byte from SI

or al, al ; logical or AL by itself
jz .done ; if the result is zero, get out

mov ah, 0x0E
int 0x10 ; otherwise, print out the character!

jmp print_string

.done:
ret

get_string:
xor cl, cl

.loop:
mov ah, 0x00
int 0x16 ; wait for keypress

cmp al, 8 ; backspace pressed?
je .backspace ; yes, handle it

cmp al, 13 ; enter pressed?
je .done ; yes, we're done

cmp cl, 31 ; 31 chars inputted?
je .loop ; yes, only let in backspace and enter

mov ah, 0x0E
int 0x10 ; print out character

stosb ; put character in buffer
inc cl
jmp .loop

.backspace:
or cl, cl ; zero? (start of the string)
jz .loop ; if yes, ignore the key

dec di
mov byte [di], 0 ; delete character
dec cl ; decrement counter as well

mov ax, 0x0E08
int 0x10 ; backspace on the screen

mov al, ' '
int 0x10 ; blank character out

mov al, 8
int 0x10 ; backspace again

jmp .loop ; go to the main loop

.done:
mov al, 0 ; null terminator
stosb

mov ax, 0x0E0D
int 0x10
mov al, 0x0A
int 0x10 ; newline

ret

strcmp:
.loop:
mov al, [si] ; grab a byte from SI
cmp al, [di] ; are SI and DI equal?
jne .notequal ; nope, we're done.

or al, al ; zero?
jz .done ; yes, we're done.

inc di ; increment DI
inc si ; increment SI
jmp .loop ; loop!

.notequal:
clc ; not equal, clear the carry flag
ret

.done:
stc ; equal, set the carry flag
ret

bits 32

do_pm:
mov ax, data_gdt
mov ds,ax
mov ax, video_gdt
mov gs, ax
mov word [gs:0],0x741
.endlessloop:
jmp .endlessloop

PutStr_32:
.nextchar:
lodsb
or al, al
jz .end
mov byte [ds:ecx], al
inc ecx
mov byte [ds:ecx], dl
inc ecx
jmp .nextchar
.end:
ret
; You load the address you want to output to in ecx(0x0B8000), the address of the string (has to be null terminated)
; you want to print in esi and the attributes in dl (personally 0x04, red char on black background) ,
; the lodsb, loads one byte from esi into al then increments esi, then it checks for a null terminator
; then it moves the char into the write position in vid mem and then increments ecx and writes the attributes,
; the loops until it finds a null pointer at which point it breaks....

times 1024-($-$$) db 0

;clrscr:
; mov ax, 0x0600
; xor cx, cx
; mov dx, 0x174F
; xor bh, bh
; int 0x10
; ret
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  mov ax, 0x1000  ; set up segments
  mov ds, ax
  mov es, ax

  mov si, welcome
  call print_string

loop:
  mov si, prompt
  call print_string

  mov di, buffer
  call get_string

  mov si, buffer
  cmp byte [si], 0  ; blank line?
  je loop           ; yes, ignore it

  mov di, cmd_hi    ; "hi" command
  call strcmp
  jc .helloworld

  mov si, buffer
  mov di, cmd_help  ; "help" command
  call strcmp
  jc .help

  mov si, buffer
  mov di, cmd_questionmark  ; "?" command
  call strcmp
  jc .help
 
  mov si, buffer
  mov di, cmd_exit  ; "exit" command
  call strcmp
  jc .exit

  mov si, buffer
  mov di, cmd_pm  ; "pm (protected mode)" command
  call strcmp
  jc .pm

  mov si,badcommand
  call print_string
  jmp loop

.helloworld:
  mov si, msg_helloworld
  call print_string

  jmp loop

.help:
  mov si, msg_help
  call print_string

  jmp loop

.exit:
  mov si, msg_exit
  call print_string
  jmp 0xffff:0x0000  ; Reboot

.pm:
  mov si, msg_pm
  call print_string
  cli
  lgdt [gdtr]
  mov eax, cr0
  or al, 1
  mov cr0, eax  
  jmp code_gdt:do_pm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; global descriptor table (GDT) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
gdtr:
      dw gdt_end - gdt - 1 ; lenght of GDT
      dd gdt

gdt:                       
      dw 0           ; (0h) Null Segment
      dw 0                   
      db 0                   
      db 0                   
      db 0                   
      db 0

code_gdt:
      dw 0x0FFFF
      dw 0x0000
      db 0x00
      db 0x9A
      db 0xCF
      db 0x00

data_gdt:
      dw 0x0FFFF
      dw 0x0000
      db 0x00
      db 0x92
      db 0xCF
      db 0x00

video_gdt:
      dw 3999 ; Limit 80*25*2-1
      dw 0x8000
      db 0x0B ; Base 0xB8000
      db 0x92
      db 0x00
      db 0x00

gdt_end:  


welcome db 'HenkesSoft 0.02 (version from Mar 18, 2009)', 13, 10, 0
msg_helloworld db 'Hello World!', 13, 10, 0
badcommand db 'Command unknown.', 13, 10, 0
prompt db '>', 0
cmd_hi db 'hi', 0
cmd_help db 'help', 0
cmd_questionmark db '?', 0
cmd_exit db 'exit', 0
cmd_pm db 'pm', 0
msg_help db 'Commands: hi, help, ?, pm, exit', 13, 10, 0
msg_exit db 'Reboot starts now.', 13, 10, 0
msg_pm db 'Switch-over to Protected Mode.', 13, 10, 0

buffer times 32 db 0

; ================
; calls start here
; ================

print_string:
  lodsb        ; grab a byte from SI

  or al, al    ; logical or AL by itself
  jz .done     ; if the result is zero, get out

  mov ah, 0x0E
  int 0x10       ; otherwise, print out the character!

  jmp print_string

.done:
  ret

get_string:
  xor cl, cl

.loop:
  mov ah, 0x00
  int 0x16      ; wait for keypress

  cmp al, 8     ; backspace pressed?
  je .backspace ; yes, handle it

  cmp al, 13    ; enter pressed?
  je .done      ; yes, we're done

  cmp cl, 31    ; 31 chars inputted?
  je .loop      ; yes, only let in backspace and enter

  mov ah, 0x0E
  int 0x10      ; print out character

  stosb  ; put character in buffer
  inc cl
  jmp .loop

.backspace:
  or cl, cl     ; zero? (start of the string)
  jz .loop      ; if yes, ignore the key

  dec di
  mov byte [di], 0  ; delete character
  dec cl        ; decrement counter as well

  mov ax, 0x0E08
  int 0x10      ; backspace on the screen

  mov al, ' '
  int 0x10      ; blank character out

  mov al, 8
  int 0x10      ; backspace again

  jmp .loop     ; go to the main loop

.done:
  mov al, 0     ; null terminator
  stosb

  mov ax, 0x0E0D
  int 0x10
  mov al, 0x0A
  int 0x10      ; newline

  ret

strcmp:
.loop:
  mov al, [si]   ; grab a byte from SI
  cmp al, [di]   ; are SI and DI equal?
  jne .notequal  ; nope, we're done.

  or al, al  ; zero?
  jz .done   ; yes, we're done.

  inc di         ; increment DI
  inc si         ; increment SI
  jmp .loop      ; loop!

.notequal:
  clc            ; not equal, clear the carry flag
  ret

.done:    
  stc            ; equal, set the carry flag
  ret

bits 32

do_pm:
  mov ax, data_gdt
  mov ds,ax
  mov ax, video_gdt
  mov gs, ax
  mov word [gs:0],0x741
.endlessloop:
  jmp .endlessloop

PutStr_32:      
  .nextchar:
    lodsb
    or al, al          
    jz .end      
    mov byte [ds:ecx], al
    inc ecx
    mov byte [ds:ecx], dl
    inc ecx  
    jmp .nextchar  
  .end:
    ret  
; You load the address you want to output to in ecx(0x0B8000), the address of the string (has to be null terminated)
; you want to print in esi and the attributes in dl (personally 0x04, red char on black background) ,
; the lodsb, loads one byte from esi into al then increments esi, then it checks for a null terminator
; then it moves the char into the write position in vid mem and then increments ecx and writes the attributes,
; the loops until it finds a null pointer at which point it breaks....

times 1024-($-$$) db 0
 
;clrscr:
;  mov ax, 0x0600
;  xor cx, cx
;  mov dx, 0x174F
;  xor bh, bh
;  int 0x10
;  ret

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:24:05 19.03.2009, insgesamt 2-mal bearbeitet
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 00:55:19 19.03.2009   Titel:              Zitieren

Ich wuerde spontan auf deine GDT, bzw. GDTR tippen. Bist du dir zB. sicher, dass die Basisadresse im GDTR auch stimmt?

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:03:12 19.03.2009   Titel:              Zitieren

Nein, ich habe da zu viel aus verschiedenen Ecken zusammen geflickt. Das funktioniert leider auch nicht, denke aber, dass es so richtig ist:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
gdtr:
      dw gdt_end - gdt - 1 ; lenght of GDT
      dd gdt

gdt:                       
      dw 0           ; (0h) Null Segment
      dw 0                   
      db 0                   
      db 0                   
      db 0                   
      db 0

code_gdt equ $-gdt
      dw 0x0FFFF
      dw 0x0000
      db 0x00
      db 0x9A
      db 0xCF
      db 0x00

data_gdt equ $-gdt
      dw 0x0FFFF
      dw 0x0000
      db 0x00
      db 0x92
      db 0xCF
      db 0x00

video_gdt equ $-gdt
      dw 3999 ; Limit 80*25*2-1
      dw 0x8000
      db 0x0B ; Base 0xB8000
      db 0x92
      db 0x00
      db 0x00

gdt_end:  
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
gdtr:
dw gdt_end - gdt - 1 ; lenght of GDT
dd gdt

gdt:
dw 0 ; (0h) Null Segment
dw 0
db 0
db 0
db 0
db 0

code_gdt equ $-gdt
dw 0x0FFFF
dw 0x0000
db 0x00
db 0x9A
db 0xCF
db 0x00

data_gdt equ $-gdt
dw 0x0FFFF
dw 0x0000
db 0x00
db 0x92
db 0xCF
db 0x00

video_gdt equ $-gdt
dw 3999 ; Limit 80*25*2-1
dw 0x8000
db 0x0B ; Base 0xB8000
db 0x92
db 0x00
db 0x00

gdt_end:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
gdtr:
      dw gdt_end - gdt - 1 ; lenght of GDT
      dd gdt

gdt:                       
      dw 0           ; (0h) Null Segment
      dw 0                   
      db 0                   
      db 0                   
      db 0                   
      db 0

code_gdt equ $-gdt
      dw 0x0FFFF
      dw 0x0000
      db 0x00
      db 0x9A
      db 0xCF
      db 0x00

data_gdt equ $-gdt
      dw 0x0FFFF
      dw 0x0000
      db 0x00
      db 0x92
      db 0xCF
      db 0x00

video_gdt equ $-gdt
      dw 3999 ; Limit 80*25*2-1
      dw 0x8000
      db 0x0B ; Base 0xB8000
      db 0x92
      db 0x00
      db 0x00

gdt_end:  

Die Basis-Adresse ist doch das Label gdt?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:07:51 19.03.2009   Titel:              Zitieren

Habe gerade mal bei uns im Forum recherchiert:
http://www.c-plusplus.de/forum/viewtopic-var-t-is-219332.html
Da klagt auch jemand über Neustart. Da lag es am far jump. :rolleyes:
Naja, aus Fehler kann man ja auch lernen. Da scheitern die meisten. :D

Wenn ich org 0x10000 vorne rein setze, funktionieren die normalen Befehle im Real Mode. Bei PM stürzt er aber sofort ab.

Wenn ich org 0x7c00 vorne rein setze, funktionieren die normalen Befehle im Real Mode natürlich nicht mehr. Bei PM stürzt er aber nicht mehr ab, aber er zeigt auch nichts an (z.B. 'A'). Man kann dann noch Zeichen eingeben, Puffer von 31 Zeichen läuft noch.

org 0x10000 ist richtig. Wie muss ich den far jump schreiben?

Was ist hier der richtige Selektor für den Jump?

Code:
 db 0xea    ;instruction for FAR JUMP
  dw do_pm      ;Offset for jump
  dw 0x8    ;selector of the segment for the jump

 ; jmp code_gdt:do_pm does not work?!
Code:
db 0xea ;instruction for FAR JUMP
dw do_pm ;Offset for jump
dw 0x8 ;selector of the segment for the jump

; jmp code_gdt:do_pm does not work?!
Code:
 db 0xea    ;instruction for FAR JUMP
  dw do_pm      ;Offset for jump
  dw 0x8    ;selector of the segment for the jump

 ; jmp code_gdt:do_pm does not work?!

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:41:08 19.03.2009, insgesamt 5-mal bearbeitet
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 01:36:04 19.03.2009   Titel:              Zitieren

Tja, das ist eben so eine Sache mit den Labels in Asm. Praktisch sind das ja beim x86 eigentlich immer offsets. Da muss auch jeweils die Basis-Adresse zu stimmen (wird auch beim nasm mittels org festgelegt).

Kurze Ueberlegung:
Wenn du deinen Code nach 0x10000 laedst und die Segmentregister dann mit 0x1000 laedst, klappt das ohne, bzw. mit org 0 natuerlich erstmal im RM problemlos, da dein Code an Offset 0 des Segments direkt beginnt. Im GDTR muss dann aber die physikalische mit absoluter Basis 0 stehen! Das selbe beim far jump zum PM - der offset-Teil muss dort dann relativ zur Basisadresse, die im angegebenen Code-Selector steht, passen.
Wenn du stattdessen einfach so die labels da rein schreibst, ohne zu beruecksichtigen, dass sich deren Adresse so ohne Weiteres nur auf das RM-Segment 0x1000 beziehen, geht die Sache schief.

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908


Zuletzt bearbeitet von Nobuo T am 01:39:41 19.03.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:46:52 19.03.2009   Titel:              Zitieren

<< Zwischenstand gelöscht >>

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:06:23 21.03.2009, insgesamt 1-mal bearbeitet
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 02:00:55 19.03.2009   Titel:              Zitieren

Sorry, ich bin gerade auch zu bematscht in der Birne, um konkreter zu werden. Da kann ich mich erst nach einer Muetze Schlaf konzentriert mit befassen...

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 02:08:07 19.03.2009   Titel:              Zitieren

Ich zeige mal einen analogen Ansatz von
http://lowlevel.brainsware.org/wiki/index.php/Protected_Mode

Der "Kernel" bzw. "PM-Umschalter" sitzt auch bei 0x10000. Er verwendet keine org-Direktive, sondern setzt die GTD ganz vorne hin und springt drüber.
Beim far jump kommt aber auch so ein merkwürdiger Kunstgriff (NASM-Problem?).

Geht das nicht einfacher als unten im Code?
Ist schwierig zu verstehen.

Ich möchte da im Tut etwas richtig Glasklares zusammen basteln, dass diese Verständnishürde verschwindet. Please help towards excellence. ;)

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
[BITS 16]                ;16 Bit Code erstellen
    jmp        start        ;GDT überspringen
   
NULL_Desc:
    dd        0
    dd        0
   
CODE_Desc:
    dw        0xFFFF        ;Segmentgröße Byte 0/1
    dw        0            ;Segmentbasisadresse Byte 0/1
    db        0            ;Segmentbasisadresse Byte 2
    db        10011010b    ;Zugriffsberechtigungen
    db        11001111b    ;Zusatz + Segmentgröße Bits 16 - 19
    db        0            ;Segmentbasisadresse Byte 3
   

DATA_Desc:
    dw        0xFFFF
    dw        0
    db        0
    db        0x92
    db        0xCF
    db        0

gdt:
Limit    dw    0            ;Größe der GDT (wird später eingetragen)
Base    dd    0            ;Adresse der GDT (wird später eingetragen)


start:                   
   
    cli                    ;Interrupts ausschalten

    mov        eax, cs        ;EAX auf derzeitiges Codesegment setzen
    mov        ds, ax        ;DS auf Codesegment setzen
       
    shl        eax, 4                ;EAX mit 16 multiplizieren (Lineare Adresse
                                ;des Codesegments errechnen)
    mov        [CODE_Desc+2], ax    ;Lineare Adresse des Codesegmentes als
    mov        [DATA_Desc+2], ax    ;Startadresse des Code- und Datendeskriptors
    shr        eax, 16                ;eintragen
    mov        [CODE_Desc+4], al
    mov        [DATA_Desc+4], al

    mov        eax, cs                ;Startadresse der GDT errechnen
    shl        eax, 4
    add        eax, NULL_Desc

    mov        [Base], eax            ;Startadresse der GDT eintragen
    mov        [Limit], WORD gdt - NULL_Desc -1    ;Größe der GDT errechnen und eintragen

    lgdt    [gdt]                ;GDT laden

    mov        eax, cr0            ;In den Protected Mode schalten,
    or        eax, 1                ;indem Bit 0 des CR0 Registers auf 1
    mov        cr0, eax            ;gesetzt wird
   
    db        0xea                ;FAR-JUMP zum Codesegment
    dw        PMODE
    dw        0x8
   

[BITS 32]                        ;32 Bit Code erstellen

PMODE:
    mov        WORD [CODE_Desc+2], 0    ;Code Segmentstartaddresse auf 0 setzen
    mov        WORD [DATA_Desc+2], 0    ;Daten Segmentstartadresse auf 0 setzen
    mov        BYTE [CODE_Desc+4], 0    ;Code Segmentstartaddresse auf 0 setzen
    mov        BYTE [DATA_Desc+4], 0    ;Daten Segmentstartadresse auf 0 setzen
   
    mov        eax, 2                ;Selektor für das Datensegment erstellen
    shl        eax, 3
   
    mov        ds, ax                ;Daten- Stack- und Extrasegment mit
    mov        ss, ax                ;Datensegmentdeskriptor laden
    mov        es, ax
    mov        eax, 0                ;FS und GS mit Null-Deskriptor laden
    mov        fs, ax
    mov        gs, ax
    mov        esp, 0x1FFFFF        ;Stack auf unterhalb der 2 MB Grenze setzen
   
    jmp        0x8:0x10000 + PMODE2    ;Sprung in das "neue" Codesegment
           
PMODE2:   
    jmp        END                        ;Zum Ende Springen
   
times 512-($-$$)    db    0;            ;Da der Linker sich nicht mit ungeraden
                                    ;Dateigrößen verträgt, wird diese Datei auf 512
                                    ;gepaddet.

END:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
[BITS 16] ;16 Bit Code erstellen
jmp start ;GDT überspringen

NULL_Desc:
dd 0
dd 0

CODE_Desc:
dw 0xFFFF ;Segmentgröße Byte 0/1
dw 0 ;Segmentbasisadresse Byte 0/1
db 0 ;Segmentbasisadresse Byte 2
db 10011010b ;Zugriffsberechtigungen
db 11001111b ;Zusatz + Segmentgröße Bits 16 - 19
db 0 ;Segmentbasisadresse Byte 3


DATA_Desc:
dw 0xFFFF
dw 0
db 0
db 0x92
db 0xCF
db 0

gdt:
Limit dw 0 ;Größe der GDT (wird später eingetragen)
Base dd 0 ;Adresse der GDT (wird später eingetragen)


start:

cli ;Interrupts ausschalten

mov eax, cs ;EAX auf derzeitiges Codesegment setzen
mov ds, ax ;DS auf Codesegment setzen

shl eax, 4 ;EAX mit 16 multiplizieren (Lineare Adresse
;des Codesegments errechnen)
mov [CODE_Desc+2], ax ;Lineare Adresse des Codesegmentes als
mov [DATA_Desc+2], ax ;Startadresse des Code- und Datendeskriptors
shr eax, 16 ;eintragen
mov [CODE_Desc+4], al
mov [DATA_Desc+4], al

mov eax, cs ;Startadresse der GDT errechnen
shl eax, 4
add eax, NULL_Desc

mov [Base], eax ;Startadresse der GDT eintragen
mov [Limit], WORD gdt - NULL_Desc -1 ;Größe der GDT errechnen und eintragen

lgdt [gdt] ;GDT laden

mov eax, cr0 ;In den Protected Mode schalten,
or eax, 1 ;indem Bit 0 des CR0 Registers auf 1
mov cr0, eax ;gesetzt wird

db 0xea ;FAR-JUMP zum Codesegment
dw PMODE
dw 0x8


[BITS 32] ;32 Bit Code erstellen

PMODE:
mov WORD [CODE_Desc+2], 0 ;Code Segmentstartaddresse auf 0 setzen
mov WORD [DATA_Desc+2], 0 ;Daten Segmentstartadresse auf 0 setzen
mov BYTE [CODE_Desc+4], 0 ;Code Segmentstartaddresse auf 0 setzen
mov BYTE [DATA_Desc+4], 0 ;Daten Segmentstartadresse auf 0 setzen

mov eax, 2 ;Selektor für das Datensegment erstellen
shl eax, 3

mov ds, ax ;Daten- Stack- und Extrasegment mit
mov ss, ax ;Datensegmentdeskriptor laden
mov es, ax
mov eax, 0 ;FS und GS mit Null-Deskriptor laden
mov fs, ax
mov gs, ax
mov esp, 0x1FFFFF ;Stack auf unterhalb der 2 MB Grenze setzen

jmp 0x8:0x10000 + PMODE2 ;Sprung in das "neue" Codesegment

PMODE2:
jmp END ;Zum Ende Springen

times 512-($-$$) db 0; ;Da der Linker sich nicht mit ungeraden
;Dateigrößen verträgt, wird diese Datei auf 512
;gepaddet.

END:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
[BITS 16]                ;16 Bit Code erstellen
    jmp        start        ;GDT überspringen
   
NULL_Desc:
    dd        0
    dd        0
   
CODE_Desc:
    dw        0xFFFF        ;Segmentgröße Byte 0/1
    dw        0            ;Segmentbasisadresse Byte 0/1
    db        0            ;Segmentbasisadresse Byte 2
    db        10011010b    ;Zugriffsberechtigungen
    db        11001111b    ;Zusatz + Segmentgröße Bits 16 - 19
    db        0            ;Segmentbasisadresse Byte 3
   

DATA_Desc:
    dw        0xFFFF
    dw        0
    db        0
    db        0x92
    db        0xCF
    db        0

gdt:
Limit    dw    0            ;Größe der GDT (wird später eingetragen)
Base    dd    0            ;Adresse der GDT (wird später eingetragen)


start:                   
   
    cli                    ;Interrupts ausschalten

    mov        eax, cs        ;EAX auf derzeitiges Codesegment setzen
    mov        ds, ax        ;DS auf Codesegment setzen
       
    shl        eax, 4                ;EAX mit 16 multiplizieren (Lineare Adresse
                                ;des Codesegments errechnen)
    mov        [CODE_Desc+2], ax    ;Lineare Adresse des Codesegmentes als
    mov        [DATA_Desc+2], ax    ;Startadresse des Code- und Datendeskriptors
    shr        eax, 16                ;eintragen
    mov        [CODE_Desc+4], al
    mov        [DATA_Desc+4], al

    mov        eax, cs                ;Startadresse der GDT errechnen
    shl        eax, 4
    add        eax, NULL_Desc

    mov        [Base], eax            ;Startadresse der GDT eintragen
    mov        [Limit], WORD gdt - NULL_Desc -1    ;Größe der GDT errechnen und eintragen

    lgdt    [gdt]                ;GDT laden

    mov        eax, cr0            ;In den Protected Mode schalten,
    or        eax, 1                ;indem Bit 0 des CR0 Registers auf 1
    mov        cr0, eax            ;gesetzt wird
   
    db        0xea                ;FAR-JUMP zum Codesegment
    dw        PMODE
    dw        0x8
   

[BITS 32]                        ;32 Bit Code erstellen

PMODE:
    mov        WORD [CODE_Desc+2], 0    ;Code Segmentstartaddresse auf 0 setzen
    mov        WORD [DATA_Desc+2], 0    ;Daten Segmentstartadresse auf 0 setzen
    mov        BYTE [CODE_Desc+4], 0    ;Code Segmentstartaddresse auf 0 setzen
    mov        BYTE [DATA_Desc+4], 0    ;Daten Segmentstartadresse auf 0 setzen
   
    mov        eax, 2                ;Selektor für das Datensegment erstellen
    shl        eax, 3
   
    mov        ds, ax                ;Daten- Stack- und Extrasegment mit
    mov        ss, ax                ;Datensegmentdeskriptor laden
    mov        es, ax
    mov        eax, 0                ;FS und GS mit Null-Deskriptor laden
    mov        fs, ax
    mov        gs, ax
    mov        esp, 0x1FFFFF        ;Stack auf unterhalb der 2 MB Grenze setzen
   
    jmp        0x8:0x10000 + PMODE2    ;Sprung in das "neue" Codesegment
           
PMODE2:   
    jmp        END                        ;Zum Ende Springen
   
times 512-($-$$)    db    0;            ;Da der Linker sich nicht mit ungeraden
                                    ;Dateigrößen verträgt, wird diese Datei auf 512
                                    ;gepaddet.

END:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:35:25 19.03.2009, insgesamt 2-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 11:34:55 19.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Geht das nicht einfacher als unten im Code?

wahrscheinlich nicht.
Erhard Henkes schrieb:

Ist schwierig zu verstehen.

du wolltest doch unbedingt das x86-flickwerk nehmen. jetzt musst da wohl durch.
:)
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 13:51:39 19.03.2009   Titel:              Zitieren

Das ist nicht unbedingt ein Problem von NASM (bzw. mir faellt kein Assembler ein, mit dem das wirklich geschickter ginge), sondern eine Eigenart des x86, dass hier in einem Code einfach verschiedene Adressierungsmechanismen zum Zugriff auf die selben Labels benutzt werden.
Am saubersten waere es IMHO, wenn du dafuer sorgst, dass dieses Phaenomen der unterschiedlichen Basisadressen gar nicht erst auftritt. Dazu musst du in diesem Code-Abschnitt immer die Segment-Basis 0 benutzen (im RM also alle Segmentregister auf 0 setzen, dh. der Code muss auch in den ersten 64K Speicher liegen, im PM die Basisadresse fuer Zugriffe auf diesen Code auch 0) und an den Anfang des Codes entsprechend eine org-Anweisung mit dem Start-Offset des Codes zur Basis 0 (also das Offset innerhalb der ersten 64k, wo der Code anfaengt).
32Bit-Segmente mit Basis 0 und bis zu 4GB Groesse zu verwenden, bietet sich dann im PM spaeter natuerlich so oder so auch an...
So kannst du dir dann auch zB. den extra-Descriptor fuer die Textausgabe sparen und hast einen leichteren Uebergang zu C-Code (wie wuerde man direkt aus c heraus ueberhaupt mit verschiedenen Selectoren umgehen?).
So solltest du keine Probleme mit irgendwelchen "org"ien oder "Kunstgriffen" mit addierten Basisadressen o.Ae. bekommen.

Falls du deinen Code unbedingt im Segment 1000 lassen willst, kommst du um einiges Gebastel mit Addition der phys. Basisadresse (10000) zur Adresse der GDT und evtl. die Differenz der Basisadressen der Code-Segmente in RM und PM zum Far-Jump in den PM wahrscheinlich nicht umhin.
Das waere dann immerhin evtl. eine gute Gelegenheit, die Adressierungsmechanismen des RM, rein physikalischer Adressen und PM ohne paging genauer zu beleuchten... wenn du das wirklich sauber kommentierst und erklaerst.


Noch zu etwas Anderem:
In meinem letzten OS-Projekt in der Uni, und nun in deinem Code, wurde mir mal wieder deutlich vor Augen gefuehrt, dass es nicht "cool", sondern hoechstens verwirrend ist, irgendwelche weitgehend unkommentierten Zahlen zur Darstellung von Bit-flags hinzuklatschen. Du tust deinen Lesern sicher einen Gefallen, wenn du flags in den Deskriptoren genauer kommentierst.

Mich wuerde auch interessieren, weshalb du meinen Tipp zu deinem strcmp nicht uebernummen hast?

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:49:23 19.03.2009   Titel:              Zitieren

Zitat:
Mich wuerde auch interessieren, weshalb du meinen Tipp zu deinem strcmp nicht uebernummen hast?


@Nobuo T:
Sorry, hatte vergessen, es auch im Tutorial einzutippen. Dein Tipp ist hervorragend! Code ist jetzt kürzer: Carry-Flag weg und nur noch eine Rücksprungadresse '.done'

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
loop:
  mov si, prompt
  call print_string

  mov di, buffer
  call get_string

  mov si, buffer
  cmp byte [si], 0  ; blank line?
  je loop           ; yes, ignore it

  mov di, cmd_hi    ; "hi" command
  call strcmp
  jz .helloworld

  mov si, buffer
  mov di, cmd_help  ; "help" command
  call strcmp
  jz .help

  mov si, buffer
  mov di, cmd_questionmark  ; "?" command
  call strcmp
  jz .help
 
  mov si, buffer
  mov di, cmd_exit  ; "exit" command
  call strcmp
  jz .exit

  mov si,badcommand
  call print_string
  jmp loop
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
loop:
mov si, prompt
call print_string

mov di, buffer
call get_string

mov si, buffer
cmp byte [si], 0 ; blank line?
je loop ; yes, ignore it

mov di, cmd_hi ; "hi" command
call strcmp
jz .helloworld

mov si, buffer
mov di, cmd_help ; "help" command
call strcmp
jz .help

mov si, buffer
mov di, cmd_questionmark ; "?" command
call strcmp
jz .help

mov si, buffer
mov di, cmd_exit ; "exit" command
call strcmp
jz .exit

mov si,badcommand
call print_string
jmp loop
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
loop:
  mov si, prompt
  call print_string

  mov di, buffer
  call get_string

  mov si, buffer
  cmp byte [si], 0  ; blank line?
  je loop           ; yes, ignore it

  mov di, cmd_hi    ; "hi" command
  call strcmp
  jz .helloworld

  mov si, buffer
  mov di, cmd_help  ; "help" command
  call strcmp
  jz .help

  mov si, buffer
  mov di, cmd_questionmark  ; "?" command
  call strcmp
  jz .help
 
  mov si, buffer
  mov di, cmd_exit  ; "exit" command
  call strcmp
  jz .exit

  mov si,badcommand
  call print_string
  jmp loop


Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
strcmp:
.loop:
  mov al, [si]   ; fetch a byte from SI
  cmp al, [di]   ; are SI and DI equal?
  jne .done      ; if no, we're done.

  or al, al      ; zero?
  jz .done       ; if yes, we're done.

  inc di         ; increment DI
  inc si         ; increment SI
  jmp .loop      ; goto .loop

.done:    
  ret
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
strcmp:
.loop:
mov al, [si] ; fetch a byte from SI
cmp al, [di] ; are SI and DI equal?
jne .done ; if no, we're done.

or al, al ; zero?
jz .done ; if yes, we're done.

inc di ; increment DI
inc si ; increment SI
jmp .loop ; goto .loop

.done:
ret
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
strcmp:
.loop:
  mov al, [si]   ; fetch a byte from SI
  cmp al, [di]   ; are SI and DI equal?
  jne .done      ; if no, we're done.

  or al, al      ; zero?
  jz .done       ; if yes, we're done.

  inc di         ; increment DI
  inc si         ; increment SI
  jmp .loop      ; goto .loop

.done:    
  ret

http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId847697

Ich hoffe zumindest, dass ich Dich so richtig verstanden habe.
Wie hättest Du dies mit 'test op,op' (AND-Verknüpfung ohne Speicherung, nur Flags setzen) gemacht? Das nimmt man doch eher, um zu testen, ob ein bestimmtes Bit gesetzt ist? z.B. test AL, 64 (check auf Bit 6)

Bezüglich RM -> PM bin ich noch am Grübeln. da muss ich noch einige Hobby-OS analysieren. Vielleicht kann man die besten Ideen aus allen heraus kristallisieren. Die Idee von Nobuo T ist auf jeden Fall bedenkenswert. Welchen offset würde man da mittels org wählen und warum? Mir ist noch nicht klar, warum die meisten den Kernel (oder ersten Teil des Kernels) nach 10000h setzen.

Zitat:
... dass es nicht "cool", sondern hoechstens verwirrend ist, irgendwelche weitgehend unkommentierten Zahlen zur Darstellung von Bit-flags hinzuklatschen. Du tust deinen Lesern sicher einen Gefallen, wenn du flags in den Deskriptoren genauer kommentierst.

Völlig richtig! So darf man das auch nicht machen, war nur Test.
Besser: binäre Darstellung im Assemblercode mit Kommentar, der die einzelnen Bits bezüglich ihrer Aufgabe beschreibt/erklärt. :live:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:22:12 19.03.2009, insgesamt 3-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:24:05 19.03.2009   Titel:              Zitieren

Zunächst mal vielen Dank an alle, die mich bisher nicht entmutigten, sondern mich mit Rat und Tat unterstützen. IMHO ein wirklich konstruktives Subforum.

Für die Ungeduldigen:
Nun wollen wir mal versuchsweise von RM nach PM schalten (ist noch nicht im Tutorial, weil didaktisch noch nicht klar genug), indem man den Befehl "pm" eingibt.

Ich habe zunächst die Methode der Kalkulation für die GDTR-Werte nach dem Umschalten verwendet, um zu sehen, ob das alles gut klappt. Funktioniert wirklich. Didaktisch ist dieser Weg nicht perfekt, lässt sich aber dennoch erklären. Vielleicht kann Nobuo T seine Idee daneben stellen zum Vergleich.

Nun fehlt didaktisch nur noch ein Command Line Interpreter und ein Befehl "RM" im Protected Mode, der den Rücksprung nach Real Mode gewährt.

In Zeile 277 steht noch nichts Sinnvolles als Zieladresse (zur Zeit wird der Code "gedumpt", ich habe mal in DL mit den Farben gespielt). Hat jemand eine kleine gute Idee für den Einstieg?

Typisch wäre jetzt ein Sprung in einen C-Kernel. Aber inzwischen gefällt mir Assembler viel besser. Man gewöhnt sich an alles. ;)

Code für kernel.asm, der binär via bootloader nach 10000h geladen wird:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TEST RM -> PM  vers. 0.01     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 [BITS 16]     ; 16 Bit Code
  jmp RealMode     ; jump behind GDT

;;;;;;;;;;;;;
;; Strings ;;
;;;;;;;;;;;;;

welcome db 'HenkesSoft 0.02 (version from Mar 19, 2009)', 13, 10, 0
msg_helloworld db 'Hello World!', 13, 10, 0
badcommand db 'Command unknown.', 13, 10, 0
prompt db '>', 0
cmd_hi db 'hi', 0
cmd_help db 'help', 0
cmd_questionmark db '?', 0
cmd_exit db 'exit', 0
cmd_pm db 'pm', 0
msg_help db 'Commands: hi, help, ?, pm, exit', 13, 10, 0
msg_exit db 'Reboot starts now.', 13, 10, 0
msg_pm db 'Switch-over to Protected Mode.', 13, 10, 0
msg_pm2 db 'OS currently uses Protected Mode.', 13, 10, 0
buffer times 32 db 0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; global descriptor table (GDT) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   
NULL_Desc:
    dd    0
    dd    0
   
CODE_Desc:
    dw    0xFFFF        ; segment length  bits 0-15 ("limit")    
    dw    0        ; segment base    byte 0,1      
    db    0        ; segment base    byte 2    
    db    10011010b    ; access rights
    db    11001111b    ; bit 7-4: 4 flag bits:    granularity, default operation size bit, 2 bits available for OS
                ; bit 3-0: segment length  bits 16-19 ("limit")
    db    0        ; segment base    byte 3    

DATA_Desc:
    dw    0xFFFF        ; segment length  bits 0-15
    dw    0        ; segment base    byte 0,1
    db    0        ; segment base    byte 2
    db    10010010b    ; access rights
    db    11001111b    ; bit 7-4: 4 flag bits:    granularity, big bit (0=USE16-Segm., 1=USE32-Segm.), 2 bits avail.
                ; bit 3-0: segment length  bits 16-19
    db    0        ; segment base    byte 3       

gdt:
Limit    dw    0        ; length of GDT
Base    dd    0        ; base of GDT

;;;;;;;;;;;;;;;
;; Real Mode ;;
;;;;;;;;;;;;;;;

RealMode:
  mov ax, 0x1000  ; set up segments
  mov ds, ax
  mov es, ax
  mov si, welcome
  call print_string

loop:
  mov si, prompt
  call print_string

  mov di, buffer
  call get_string

  mov si, buffer
  cmp byte [si], 0  ; blank line?
  je loop           ; yes, ignore it

  mov di, cmd_hi    ; "hi" command
  call strcmp
  jz .helloworld

  mov si, buffer
  mov di, cmd_help  ; "help" command
  call strcmp
  jz .help

  mov si, buffer
  mov di, cmd_questionmark  ; "?" command
  call strcmp
  jz .help
 
  mov si, buffer
  mov di, cmd_exit  ; "exit" command
  call strcmp
  jz .exit

  mov si, buffer
  mov di, cmd_pm  ; "pm (protected mode)" command
  call strcmp
  jz .pm

  mov si,badcommand
  call print_string
  jmp loop

.helloworld:
  mov si, msg_helloworld
  call print_string

  jmp loop

.help:
  mov si, msg_help
  call print_string

  jmp loop

.exit:
  mov si, msg_exit
  call print_string
  jmp 0xffff:0x0000  ; Reboot

.pm:
  mov si, msg_pm
  call print_string

  cli                ; clear interrupts
  mov    eax, cs            ; CS ---> EAX
  mov    ds, ax            ; CS ---> DS
  shl     eax, 4            ; CS * 0x10 = linear address
  mov    [CODE_Desc+2], ax    ; linear address ---> base of code descriptor
  mov    [DATA_Desc+2], ax    ; linear address ---> base of data descriptor
  shr    eax, 16            ;    
  mov    [CODE_Desc+4], al       ;
  mov    [DATA_Desc+4], al       ;

  mov    eax, cs            ; base of GDT
  shl    eax, 4
  add    eax, NULL_Desc

  mov    [Base], eax                ; base of GDT  ---> GDTR
  mov    [Limit], WORD gdt - NULL_Desc - 1    ; limit of GDT ---> GDTR
  lgdt    [gdt]                    ; load GDT

  mov    eax, cr0        ; switch-over to Protected Mode
  or    eax, 1            ; set bit 0 of CR0 register
  mov    cr0, eax        ;

  db    0xea            ; instruction code for FAR JUMP
  dw    ProtectedMode        ; offset for jump
  dw    0x8            ; selector of the segment for the jump
 


;;;;;;;;;;;
;; Calls ;;
;;;;;;;;;;;

print_string:
  lodsb        ; grab a byte from SI

  or al, al    ; logical or AL by itself
  jz .done     ; if the result is zero, get out

  mov ah, 0x0E
  int 0x10       ; otherwise, print out the character!

  jmp print_string

.done:
  ret

get_string:
  xor cl, cl

.loop:
  mov ah, 0x00
  int 0x16      ; wait for keypress

  cmp al, 8     ; backspace pressed?
  je .backspace ; yes, handle it

  cmp al, 13    ; enter pressed?
  je .done      ; yes, we're done

  cmp cl, 31    ; 31 chars inputted?
  je .loop      ; yes, only let in backspace and enter

  mov ah, 0x0E
  int 0x10      ; print out character

  stosb  ; put character in buffer
  inc cl
  jmp .loop

.backspace:
  or cl, cl     ; zero? (start of the string)
  jz .loop      ; if yes, ignore the key

  dec di
  mov byte [di], 0  ; delete character
  dec cl        ; decrement counter as well

  mov ax, 0x0E08
  int 0x10      ; backspace on the screen

  mov al, ' '
  int 0x10      ; blank character out

  mov al, 8
  int 0x10      ; backspace again

  jmp .loop     ; go to the main loop

.done:
  mov al, 0     ; null terminator
  stosb

  mov ax, 0x0E0D
  int 0x10
  mov al, 0x0A
  int 0x10      ; newline

  ret

strcmp:
.loop:
  mov al, [si]   ; grab a byte from SI
  cmp al, [di]   ; are SI and DI equal?
  jne .done      ; nope, we're done.

  or al, al      ; zero?
  jz .done       ; yes, we're done.

  inc di         ; increment DI
  inc si         ; increment SI
  jmp .loop      ; loop!

.done:    
  ret

clrscr:
  mov ax, 0x0600
  xor cx, cx
  mov dx, 0x174F
  xor bh, bh
  int 0x10
  ret

;;;;;;;;;;;;;;;;;;;;
;; Protected Mode ;;
;;;;;;;;;;;;;;;;;;;;

[Bits 32]

ProtectedMode:
  mov    WORD [CODE_Desc+2], 0    ; code segment base address = 0
  mov    WORD [DATA_Desc+2], 0    ; data segment base address = 0
  mov    BYTE [CODE_Desc+4], 0    ; code segment base address = 0
  mov    BYTE [DATA_Desc+4], 0    ; data segment base address = 0

  mov    eax, 2            ; create selector for data segment
  shl    eax, 3
  mov    ds, ax            ; data descriptor --> data, stack and extra segment
  mov    ss, ax             
  mov    es, ax
  xor    eax, eax            ; null desriptor --> FS and GS
  mov    fs, ax
  mov    gs, ax
  mov    esp, 0x1FFFFF        ; set stack below 2 MB limit

  jmp    0x8:0x10000 + ProtectedMode2    ; jump to the new code segment
           
ProtectedMode2:
  mov ecx, 0x0B8000
  mov esi, 0x10000 ; >>>> ??? Idee ??? <<<<
  mov dl,  0x01
.endlessloop:
  inc dl
  cmp dl, 0x15
  jz .resetcolor
  call PutStr_32
  jmp .endlessloop
.resetcolor:
  xor dl, dl
  jmp .endlessloop

PutStr_32:      
  .nextchar:
    lodsb
    or al, al          
    jz .end      
    mov byte [ds:ecx], al
    inc ecx
    mov byte [ds:ecx], dl
    inc ecx  
    jmp .nextchar  
  .end:
    ret  
; You load the address you want to output to in ecx(0x0B8000), the address of the string (has to be null terminated)
; you want to print in esi and the attributes in dl (personally 0x04, red char on black background) ,
; the lodsb, loads one byte from esi into al then increments esi, then it checks for a null terminator
; then it moves the char into the write position in vid mem and then increments ecx and writes the attributes,
; the loops until it finds a null pointer at which point it breaks....

times 1024-($-$$) db 0
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TEST RM -> PM vers. 0.01 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

[BITS 16] ; 16 Bit Code
jmp RealMode ; jump behind GDT

;;;;;;;;;;;;;
;; Strings ;;
;;;;;;;;;;;;;

welcome db 'HenkesSoft 0.02 (version from Mar 19, 2009)', 13, 10, 0
msg_helloworld db 'Hello World!', 13, 10, 0
badcommand db 'Command unknown.', 13, 10, 0
prompt db '>', 0
cmd_hi db 'hi', 0
cmd_help db 'help', 0
cmd_questionmark db '?', 0
cmd_exit db 'exit', 0
cmd_pm db 'pm', 0
msg_help db 'Commands: hi, help, ?, pm, exit', 13, 10, 0
msg_exit db 'Reboot starts now.', 13, 10, 0
msg_pm db 'Switch-over to Protected Mode.', 13, 10, 0
msg_pm2 db 'OS currently uses Protected Mode.', 13, 10, 0
buffer times 32 db 0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; global descriptor table (GDT) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

NULL_Desc:
dd 0
dd 0

CODE_Desc:
dw 0xFFFF ; segment length bits 0-15 ("limit")
dw 0 ; segment base byte 0,1
db 0 ; segment base byte 2
db 10011010b ; access rights
db 11001111b ; bit 7-4: 4 flag bits: granularity, default operation size bit, 2 bits available for OS
; bit 3-0: segment length bits 16-19 ("limit")
db 0 ; segment base byte 3

DATA_Desc:
dw 0xFFFF ; segment length bits 0-15
dw 0 ; segment base byte 0,1
db 0 ; segment base byte 2
db 10010010b ; access rights
db 11001111b ; bit 7-4: 4 flag bits: granularity, big bit (0=USE16-Segm., 1=USE32-Segm.), 2 bits avail.
; bit 3-0: segment length bits 16-19
db 0 ; segment base byte 3

gdt:
Limit dw 0 ; length of GDT
Base dd 0 ; base of GDT

;;;;;;;;;;;;;;;
;; Real Mode ;;
;;;;;;;;;;;;;;;

RealMode:
mov ax, 0x1000 ; set up segments
mov ds, ax
mov es, ax
mov si, welcome
call print_string

loop:
mov si, prompt
call print_string

mov di, buffer
call get_string

mov si, buffer
cmp byte [si], 0 ; blank line?
je loop ; yes, ignore it

mov di, cmd_hi ; "hi" command
call strcmp
jz .helloworld

mov si, buffer
mov di, cmd_help ; "help" command
call strcmp
jz .help

mov si, buffer
mov di, cmd_questionmark ; "?" command
call strcmp
jz .help

mov si, buffer
mov di, cmd_exit ; "exit" command
call strcmp
jz .exit

mov si, buffer
mov di, cmd_pm ; "pm (protected mode)" command
call strcmp
jz .pm

mov si,badcommand
call print_string
jmp loop

.helloworld:
mov si, msg_helloworld
call print_string

jmp loop

.help:
mov si, msg_help
call print_string

jmp loop

.exit:
mov si, msg_exit
call print_string
jmp 0xffff:0x0000 ; Reboot

.pm:
mov si, msg_pm
call print_string

cli ; clear interrupts
mov eax, cs ; CS ---> EAX
mov ds, ax ; CS ---> DS
shl eax, 4 ; CS * 0x10 = linear address
mov [CODE_Desc+2], ax ; linear address ---> base of code descriptor
mov [DATA_Desc+2], ax ; linear address ---> base of data descriptor
shr eax, 16 ;
mov [CODE_Desc+4], al ;
mov [DATA_Desc+4], al ;

mov eax, cs ; base of GDT
shl eax, 4
add eax, NULL_Desc

mov [Base], eax ; base of GDT ---> GDTR
mov [Limit], WORD gdt - NULL_Desc - 1 ; limit of GDT ---> GDTR
lgdt [gdt] ; load GDT

mov eax, cr0 ; switch-over to Protected Mode
or eax, 1 ; set bit 0 of CR0 register
mov cr0, eax ;

db 0xea ; instruction code for FAR JUMP
dw ProtectedMode ; offset for jump
dw 0x8 ; selector of the segment for the jump



;;;;;;;;;;;
;; Calls ;;
;;;;;;;;;;;

print_string:
lodsb ; grab a byte from SI

or al, al ; logical or AL by itself
jz .done ; if the result is zero, get out

mov ah, 0x0E
int 0x10 ; otherwise, print out the character!

jmp print_string

.done:
ret

get_string:
xor cl, cl

.loop:
mov ah, 0x00
int 0x16 ; wait for keypress

cmp al, 8 ; backspace pressed?
je .backspace ; yes, handle it

cmp al, 13 ; enter pressed?
je .done ; yes, we're done

cmp cl, 31 ; 31 chars inputted?
je .loop ; yes, only let in backspace and enter

mov ah, 0x0E
int 0x10 ; print out character

stosb ; put character in buffer
inc cl
jmp .loop

.backspace:
or cl, cl ; zero? (start of the string)
jz .loop ; if yes, ignore the key

dec di
mov byte [di], 0 ; delete character
dec cl ; decrement counter as well

mov ax, 0x0E08
int 0x10 ; backspace on the screen

mov al, ' '
int 0x10 ; blank character out

mov al, 8
int 0x10 ; backspace again

jmp .loop ; go to the main loop

.done:
mov al, 0 ; null terminator
stosb

mov ax, 0x0E0D
int 0x10
mov al, 0x0A
int 0x10 ; newline

ret

strcmp:
.loop:
mov al, [si] ; grab a byte from SI
cmp al, [di] ; are SI and DI equal?
jne .done ; nope, we're done.

or al, al ; zero?
jz .done ; yes, we're done.

inc di ; increment DI
inc si ; increment SI
jmp .loop ; loop!

.done:
ret

clrscr:
mov ax, 0x0600
xor cx, cx
mov dx, 0x174F
xor bh, bh
int 0x10
ret

;;;;;;;;;;;;;;;;;;;;
;; Protected Mode ;;
;;;;;;;;;;;;;;;;;;;;

[Bits 32]

ProtectedMode:
mov WORD [CODE_Desc+2], 0 ; code segment base address = 0
mov WORD [DATA_Desc+2], 0 ; data segment base address = 0
mov BYTE [CODE_Desc+4], 0 ; code segment base address = 0
mov BYTE [DATA_Desc+4], 0 ; data segment base address = 0

mov eax, 2 ; create selector for data segment
shl eax, 3
mov ds, ax ; data descriptor --> data, stack and extra segment
mov ss, ax
mov es, ax
xor eax, eax ; null desriptor --> FS and GS
mov fs, ax
mov gs, ax
mov esp, 0x1FFFFF ; set stack below 2 MB limit

jmp 0x8:0x10000 + ProtectedMode2 ; jump to the new code segment

ProtectedMode2:
mov ecx, 0x0B8000
mov esi, 0x10000 ; >>>> ??? Idee ??? <<<<
mov dl, 0x01
.endlessloop:
inc dl
cmp dl, 0x15
jz .resetcolor
call PutStr_32
jmp .endlessloop
.resetcolor:
xor dl, dl
jmp .endlessloop

PutStr_32:
.nextchar:
lodsb
or al, al
jz .end
mov byte [ds:ecx], al
inc ecx
mov byte [ds:ecx], dl
inc ecx
jmp .nextchar
.end:
ret
; You load the address you want to output to in ecx(0x0B8000), the address of the string (has to be null terminated)
; you want to print in esi and the attributes in dl (personally 0x04, red char on black background) ,
; the lodsb, loads one byte from esi into al then increments esi, then it checks for a null terminator
; then it moves the char into the write position in vid mem and then increments ecx and writes the attributes,
; the loops until it finds a null pointer at which point it breaks....

times 1024-($-$$) db 0
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TEST RM -> PM  vers. 0.01     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 [BITS 16]     ; 16 Bit Code
  jmp RealMode     ; jump behind GDT

;;;;;;;;;;;;;
;; Strings ;;
;;;;;;;;;;;;;

welcome db 'HenkesSoft 0.02 (version from Mar 19, 2009)', 13, 10, 0
msg_helloworld db 'Hello World!', 13, 10, 0
badcommand db 'Command unknown.', 13, 10, 0
prompt db '>', 0
cmd_hi db 'hi', 0
cmd_help db 'help', 0
cmd_questionmark db '?', 0
cmd_exit db 'exit', 0
cmd_pm db 'pm', 0
msg_help db 'Commands: hi, help, ?, pm, exit', 13, 10, 0
msg_exit db 'Reboot starts now.', 13, 10, 0
msg_pm db 'Switch-over to Protected Mode.', 13, 10, 0
msg_pm2 db 'OS currently uses Protected Mode.', 13, 10, 0
buffer times 32 db 0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; global descriptor table (GDT) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   
NULL_Desc:
    dd    0
    dd    0
   
CODE_Desc:
    dw    0xFFFF        ; segment length  bits 0-15 ("limit")    
    dw    0        ; segment base    byte 0,1      
    db    0        ; segment base    byte 2    
    db    10011010b    ; access rights
    db    11001111b    ; bit 7-4: 4 flag bits:    granularity, default operation size bit, 2 bits available for OS
                ; bit 3-0: segment length  bits 16-19 ("limit")
    db    0        ; segment base    byte 3    

DATA_Desc:
    dw    0xFFFF        ; segment length  bits 0-15
    dw    0        ; segment base    byte 0,1
    db    0        ; segment base    byte 2
    db    10010010b    ; access rights
    db    11001111b    ; bit 7-4: 4 flag bits:    granularity, big bit (0=USE16-Segm., 1=USE32-Segm.), 2 bits avail.
                ; bit 3-0: segment length  bits 16-19
    db    0        ; segment base    byte 3       

gdt:
Limit    dw    0        ; length of GDT
Base    dd    0        ; base of GDT

;;;;;;;;;;;;;;;
;; Real Mode ;;
;;;;;;;;;;;;;;;

RealMode:
  mov ax, 0x1000  ; set up segments
  mov ds, ax
  mov es, ax
  mov si, welcome
  call print_string

loop:
  mov si, prompt
  call print_string

  mov di, buffer
  call get_string

  mov si, buffer
  cmp byte [si], 0  ; blank line?
  je loop           ; yes, ignore it

  mov di, cmd_hi    ; "hi" command
  call strcmp
  jz .helloworld

  mov si, buffer
  mov di, cmd_help  ; "help" command
  call strcmp
  jz .help

  mov si, buffer
  mov di, cmd_questionmark  ; "?" command
  call strcmp
  jz .help
 
  mov si, buffer
  mov di, cmd_exit  ; "exit" command
  call strcmp
  jz .exit

  mov si, buffer
  mov di, cmd_pm  ; "pm (protected mode)" command
  call strcmp
  jz .pm

  mov si,badcommand
  call print_string
  jmp loop

.helloworld:
  mov si, msg_helloworld
  call print_string

  jmp loop

.help:
  mov si, msg_help
  call print_string

  jmp loop

.exit:
  mov si, msg_exit
  call print_string
  jmp 0xffff:0x0000  ; Reboot

.pm:
  mov si, msg_pm
  call print_string

  cli                ; clear interrupts
  mov    eax, cs            ; CS ---> EAX
  mov    ds, ax            ; CS ---> DS
  shl     eax, 4            ; CS * 0x10 = linear address
  mov    [CODE_Desc+2], ax    ; linear address ---> base of code descriptor
  mov    [DATA_Desc+2], ax    ; linear address ---> base of data descriptor
  shr    eax, 16            ;    
  mov    [CODE_Desc+4], al       ;
  mov    [DATA_Desc+4], al       ;

  mov    eax, cs            ; base of GDT
  shl    eax, 4
  add    eax, NULL_Desc

  mov    [Base], eax                ; base of GDT  ---> GDTR
  mov    [Limit], WORD gdt - NULL_Desc - 1    ; limit of GDT ---> GDTR
  lgdt    [gdt]                    ; load GDT

  mov    eax, cr0        ; switch-over to Protected Mode
  or    eax, 1            ; set bit 0 of CR0 register
  mov    cr0, eax        ;

  db    0xea            ; instruction code for FAR JUMP
  dw    ProtectedMode        ; offset for jump
  dw    0x8            ; selector of the segment for the jump
 


;;;;;;;;;;;
;; Calls ;;
;;;;;;;;;;;

print_string:
  lodsb        ; grab a byte from SI

  or al, al    ; logical or AL by itself
  jz .done     ; if the result is zero, get out

  mov ah, 0x0E
  int 0x10       ; otherwise, print out the character!

  jmp print_string

.done:
  ret

get_string:
  xor cl, cl

.loop:
  mov ah, 0x00
  int 0x16      ; wait for keypress

  cmp al, 8     ; backspace pressed?
  je .backspace ; yes, handle it

  cmp al, 13    ; enter pressed?
  je .done      ; yes, we're done

  cmp cl, 31    ; 31 chars inputted?
  je .loop      ; yes, only let in backspace and enter

  mov ah, 0x0E
  int 0x10      ; print out character

  stosb  ; put character in buffer
  inc cl
  jmp .loop

.backspace:
  or cl, cl     ; zero? (start of the string)
  jz .loop      ; if yes, ignore the key

  dec di
  mov byte [di], 0  ; delete character
  dec cl        ; decrement counter as well

  mov ax, 0x0E08
  int 0x10      ; backspace on the screen

  mov al, ' '
  int 0x10      ; blank character out

  mov al, 8
  int 0x10      ; backspace again

  jmp .loop     ; go to the main loop

.done:
  mov al, 0     ; null terminator
  stosb

  mov ax, 0x0E0D
  int 0x10
  mov al, 0x0A
  int 0x10      ; newline

  ret

strcmp:
.loop:
  mov al, [si]   ; grab a byte from SI
  cmp al, [di]   ; are SI and DI equal?
  jne .done      ; nope, we're done.

  or al, al      ; zero?
  jz .done       ; yes, we're done.

  inc di         ; increment DI
  inc si         ; increment SI
  jmp .loop      ; loop!

.done:    
  ret

clrscr:
  mov ax, 0x0600
  xor cx, cx
  mov dx, 0x174F
  xor bh, bh
  int 0x10
  ret

;;;;;;;;;;;;;;;;;;;;
;; Protected Mode ;;
;;;;;;;;;;;;;;;;;;;;

[Bits 32]

ProtectedMode:
  mov    WORD [CODE_Desc+2], 0    ; code segment base address = 0
  mov    WORD [DATA_Desc+2], 0    ; data segment base address = 0
  mov    BYTE [CODE_Desc+4], 0    ; code segment base address = 0
  mov    BYTE [DATA_Desc+4], 0    ; data segment base address = 0

  mov    eax, 2            ; create selector for data segment
  shl    eax, 3
  mov    ds, ax            ; data descriptor --> data, stack and extra segment
  mov    ss, ax             
  mov    es, ax
  xor    eax, eax            ; null desriptor --> FS and GS
  mov    fs, ax
  mov    gs, ax
  mov    esp, 0x1FFFFF        ; set stack below 2 MB limit

  jmp    0x8:0x10000 + ProtectedMode2    ; jump to the new code segment
           
ProtectedMode2:
  mov ecx, 0x0B8000
  mov esi, 0x10000 ; >>>> ??? Idee ??? <<<<
  mov dl,  0x01
.endlessloop:
  inc dl
  cmp dl, 0x15
  jz .resetcolor
  call PutStr_32
  jmp .endlessloop
.resetcolor:
  xor dl, dl
  jmp .endlessloop

PutStr_32:      
  .nextchar:
    lodsb
    or al, al          
    jz .end      
    mov byte [ds:ecx], al
    inc ecx
    mov byte [ds:ecx], dl
    inc ecx  
    jmp .nextchar  
  .end:
    ret  
; You load the address you want to output to in ecx(0x0B8000), the address of the string (has to be null terminated)
; you want to print in esi and the attributes in dl (personally 0x04, red char on black background) ,
; the lodsb, loads one byte from esi into al then increments esi, then it checks for a null terminator
; then it moves the char into the write position in vid mem and then increments ecx and writes the attributes,
; the loops until it finds a null pointer at which point it breaks....

times 1024-($-$$) db 0


GDT: http://book.opensourceproject.org.cn/kernel/kernel3rd/opensource/0596005652/images/understandlk_0203.jpg

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:48:26 19.03.2009, insgesamt 3-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 00:03:35 20.03.2009   Titel:              Zitieren

Hallo,

habe mal den Code in bochs ausprobiert, weiss nicht, ist es normal, dass nach dem Kommando pm lauter farbiger Zeichen erscheinen... ;)
Bezüglich der drei Zeilen:
Code:
  db    0xea            ; instruction code for FAR JUMP
  dw    ProtectedMode        ; offset for jump
  dw    0x8            ; selector of the segment for the jump
Code:
db 0xea ; instruction code for FAR JUMP
dw ProtectedMode ; offset for jump
dw 0x8 ; selector of the segment for the jump
Code:
  db    0xea            ; instruction code for FAR JUMP
  dw    ProtectedMode        ; offset for jump
  dw    0x8            ; selector of the segment for the jump

Man kann sich die Binärdatei mit dem Programm ndisasm, das mit nasm mit dabei ist, disassemblieren lassen, z.B. so:
Code:
c:\nasm-2.06rc6\ndisasm.exe -b 16 kernel.bin
Code:
c:\nasm-2.06rc6\ndisasm.exe -b 16 kernel.bin
Code:
c:\nasm-2.06rc6\ndisasm.exe -b 16 kernel.bin

Dann sieht man, wie ndisasm es interpretiert:
Code:
000001E4  EA57020800        jmp word 0x8:0x257
Code:
000001E4 EA57020800 jmp word 0x8:0x257
Code:
000001E4  EA57020800        jmp word 0x8:0x257

Also kann man die oberen 3 Zeilen durch eine ersetzen:
Code:
  jmp word 0x8:ProtectedMode
Code:
jmp word 0x8:ProtectedMode
Code:
  jmp word 0x8:ProtectedMode

Damit wird scheinbar auch ein FAR JUMP generiert. Man kann es auch hier nachlesen: http://www.nasm.us/doc/nasmdo10.html#section-10.1
Ich hab es mal ausprobiert und es kommen immer noch die farbigen Zeichen - also wahrscheinlich funktioniert es wie vorher. Und die ndisasm Ausgabe stimmt auch mit der vorherigen überein.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:04:56 20.03.2009   Titel:              Zitieren

Zitat:
habe mal den Code in bochs ausprobiert, weiss nicht, ist es normal, dass nach dem Kommando pm lauter farbiger Zeichen erscheinen... ;)

Das Progrämmchen war nur Spaß zum Testen, lief durch die Strings und wechselte die Farbe bei jedem 'NUL'. Ich bräuchte das hier:

Hat jemand einen ASM-Code für '.clearScreen' (ab 0xB0000) und '.eineSekundePause' in PM?
Dann könnte man dies hier machen:

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ProtectedMode2:
  mov ecx, 0x0B8000
  mov esi, 0x10000 + msg_pm2 ; 'OS currently uses Protected Mode.'
  mov dl,  0x01
.endlessloop:
  call .eineSekundePause
  call .clearScreen
  inc dl
  cmp dl, 0x15
  jz .resetcolor
  call PutStr_32
  jmp .endlessloop
.resetcolor:
  xor dl, dl
  jmp .endlessloop
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ProtectedMode2:
mov ecx, 0x0B8000
mov esi, 0x10000 + msg_pm2 ; 'OS currently uses Protected Mode.'
mov dl, 0x01
.endlessloop:
call .eineSekundePause
call .clearScreen
inc dl
cmp dl, 0x15
jz .resetcolor
call PutStr_32
jmp .endlessloop
.resetcolor:
xor dl, dl
jmp .endlessloop
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ProtectedMode2:
  mov ecx, 0x0B8000
  mov esi, 0x10000 + msg_pm2 ; 'OS currently uses Protected Mode.'
  mov dl,  0x01
.endlessloop:
  call .eineSekundePause
  call .clearScreen
  inc dl
  cmp dl, 0x15
  jz .resetcolor
  call PutStr_32
  jmp .endlessloop
.resetcolor:
  xor dl, dl
  jmp .endlessloop

Bestimmt nicht schlecht für den Anfang. ;)

Code:
  jmp word 0x8:ProtectedMode
  ;db    0xea            ; instruction code for FAR JUMP
  ;dw    ProtectedMode        ; offset for jump
  ;dw    0x8            ; selector of the segment for the jump
Code:
jmp word 0x8:ProtectedMode
;db 0xea ; instruction code for FAR JUMP
;dw ProtectedMode ; offset for jump
;dw 0x8 ; selector of the segment for the jump
Code:
  jmp word 0x8:ProtectedMode
  ;db    0xea            ; instruction code for FAR JUMP
  ;dw    ProtectedMode        ; offset for jump
  ;dw    0x8            ; selector of the segment for the jump

Ja, geht! Offenbar gibt es bei manchen Compilerversionen Probleme, sonst würden nicht viele sich zu diesem Kunstgriff retten.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:20:37 20.03.2009, insgesamt 4-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 02:46:20 20.03.2009   Titel:              Zitieren

Die Subroutine ClrScr32 bewirkt einen Reboot. Kommentiert man den Befehl aus, läuft der String 'OS currently uses Protected Mode.' oben links in 16 Farben durch. Ich möchte nur jeweils vorher den Bildschirm löschen. Code macht aber Probleme. Vielleicht hat jemand eine Idee?
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
ProtectedMode2:
  mov ecx, 0x0B8000
  mov esi, 0x10000 + msg_pm2 ; 'OS currently uses Protected Mode.'
  mov dl,  0x01
.endlessloop:
  call Waitingloop
  call ClrScr32 ; bewirkt Reboot
  inc dl
  cmp dl, 0x15
  jz .resetcolor
  call PutStr_32
  jmp .endlessloop
.resetcolor:
  xor dl, dl
  jmp .endlessloop

Waitingloop:                    
  pushad
  mov ebx,0x3FFFF
.loop:
  dec ebx      
  jnz .loop
  popad
  ret          

ClrScr32:   ; noch nicht o.k. ?
  pushad
  cld
  mov    edi, 0xB8000
  mov    cx, 2000
  mov    ah, 0x0
  mov    al, ' '   
  rep    stosw  
  popad
  ret

PutStr_32:      
  pushad
  .nextchar:
    lodsb
    or al, al          
    jz .end      
    mov byte [ds:ecx], al
    inc ecx
    mov byte [ds:ecx], dl
    inc ecx  
    jmp .nextchar  
  .end:
    popad
    ret  
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
ProtectedMode2:
mov ecx, 0x0B8000
mov esi, 0x10000 + msg_pm2 ; 'OS currently uses Protected Mode.'
mov dl, 0x01
.endlessloop:
call Waitingloop
call ClrScr32 ; bewirkt Reboot
inc dl
cmp dl, 0x15
jz .resetcolor
call PutStr_32
jmp .endlessloop
.resetcolor:
xor dl, dl
jmp .endlessloop

Waitingloop:
pushad
mov ebx,0x3FFFF
.loop:
dec ebx
jnz .loop
popad
ret

ClrScr32: ; noch nicht o.k. ?
pushad
cld
mov edi, 0xB8000
mov cx, 2000
mov ah, 0x0
mov al, ' '
rep stosw
popad
ret

PutStr_32:
pushad
.nextchar:
lodsb
or al, al
jz .end
mov byte [ds:ecx], al
inc ecx
mov byte [ds:ecx], dl
inc ecx
jmp .nextchar
.end:
popad
ret
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
ProtectedMode2:
  mov ecx, 0x0B8000
  mov esi, 0x10000 + msg_pm2 ; 'OS currently uses Protected Mode.'
  mov dl,  0x01
.endlessloop:
  call Waitingloop
  call ClrScr32 ; bewirkt Reboot
  inc dl
  cmp dl, 0x15
  jz .resetcolor
  call PutStr_32
  jmp .endlessloop
.resetcolor:
  xor dl, dl
  jmp .endlessloop

Waitingloop:                    
  pushad
  mov ebx,0x3FFFF
.loop:
  dec ebx      
  jnz .loop
  popad
  ret          

ClrScr32:   ; noch nicht o.k. ?
  pushad
  cld
  mov    edi, 0xB8000
  mov    cx, 2000
  mov    ah, 0x0
  mov    al, ' '   
  rep    stosw  
  popad
  ret

PutStr_32:      
  pushad
  .nextchar:
    lodsb
    or al, al          
    jz .end      
    mov byte [ds:ecx], al
    inc ecx
    mov byte [ds:ecx], dl
    inc ecx  
    jmp .nextchar  
  .end:
    popad
    ret  

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:25:42 20.03.2009   Titel:              Zitieren

Im Tutorial könnte man den clrscr zunächst noch im RM ausführen. GDT habe ich
nach gdt.inc ausgelagert. Inzwischen alles schon ganz schön unübersichtlich.
So sieht momentan eine zumindest in Bochs binär von Platte funktionierende Version (von floppy im PC booten klappt momentan nicht?) aus:

gdt.inc
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; global descriptor table (GDT) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

NULL_Desc:
    dd    0
    dd    0
   
CODE_Desc:
    dw    0xFFFF        ; segment length  bits 0-15 ("limit")    
    dw    0        ; segment base    byte 0,1      
    db    0        ; segment base    byte 2    
    db    10011010b    ; access rights
    db    11001111b    ; bit 7-4: 4 flag bits:    granularity, default operation size bit, 2 bits available for OS
                ; bit 3-0: segment length  bits 16-19 ("limit")
    db    0        ; segment base    byte 3    

DATA_Desc:
    dw    0xFFFF        ; segment length  bits 0-15
    dw    0        ; segment base    byte 0,1
    db    0        ; segment base    byte 2
    db    10010010b    ; access rights
    db    11001111b    ; bit 7-4: 4 flag bits:    granularity, big bit (0=USE16-Segm., 1=USE32-Segm.), 2 bits avail.
                ; bit 3-0: segment length  bits 16-19
    db    0        ; segment base    byte 3       

gdtr:
Limit    dw    0        ; length of GDT
Base    dd    0        ; base of GDT
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; global descriptor table (GDT) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

NULL_Desc:
dd 0
dd 0

CODE_Desc:
dw 0xFFFF ; segment length bits 0-15 ("limit")
dw 0 ; segment base byte 0,1
db 0 ; segment base byte 2
db 10011010b ; access rights
db 11001111b ; bit 7-4: 4 flag bits: granularity, default operation size bit, 2 bits available for OS
; bit 3-0: segment length bits 16-19 ("limit")
db 0 ; segment base byte 3

DATA_Desc:
dw 0xFFFF ; segment length bits 0-15
dw 0 ; segment base byte 0,1
db 0 ; segment base byte 2
db 10010010b ; access rights
db 11001111b ; bit 7-4: 4 flag bits: granularity, big bit (0=USE16-Segm., 1=USE32-Segm.), 2 bits avail.
; bit 3-0: segment length bits 16-19
db 0 ; segment base byte 3

gdtr:
Limit dw 0 ; length of GDT
Base dd 0 ; base of GDT
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; global descriptor table (GDT) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

NULL_Desc:
    dd    0
    dd    0
   
CODE_Desc:
    dw    0xFFFF        ; segment length  bits 0-15 ("limit")    
    dw    0        ; segment base    byte 0,1      
    db    0        ; segment base    byte 2    
    db    10011010b    ; access rights
    db    11001111b    ; bit 7-4: 4 flag bits:    granularity, default operation size bit, 2 bits available for OS
                ; bit 3-0: segment length  bits 16-19 ("limit")
    db    0        ; segment base    byte 3    

DATA_Desc:
    dw    0xFFFF        ; segment length  bits 0-15
    dw    0        ; segment base    byte 0,1
    db    0        ; segment base    byte 2
    db    10010010b    ; access rights
    db    11001111b    ; bit 7-4: 4 flag bits:    granularity, big bit (0=USE16-Segm., 1=USE32-Segm.), 2 bits avail.
                ; bit 3-0: segment length  bits 16-19
    db    0        ; segment base    byte 3       

gdtr:
Limit    dw    0        ; length of GDT
Base    dd    0        ; base of GDT


kernel.asm
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TEST RM -> PM  vers. 0.01     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 [BITS 16]     ; 16 Bit Code
  jmp RealMode     ; jump behind GDT

%include "gdt.inc"

;;;;;;;;;;;;;
;; Strings ;;
;;;;;;;;;;;;;

welcome db 'HenkesSoft 0.02 (version from Mar 19, 2009)', 13, 10, 0
msg_helloworld db 'Hello World!', 13, 10, 0
badcommand db 'Command unknown.', 13, 10, 0
prompt db '>', 0
cmd_hi db 'hi', 0
cmd_help db 'help', 0
cmd_questionmark db '?', 0
cmd_exit db 'exit', 0
cmd_pm db 'pm', 0
msg_help db 'Commands: hi, help, ?, pm, exit', 13, 10, 0
msg_exit db 'Reboot starts now.', 13, 10, 0
msg_pm db 'Switch-over to Protected Mode.', 13, 10, 0
msg_pm2 db 'OS currently uses Protected Mode.', 13, 10, 0

buffer times 32 db 0

;;;;;;;;;;;;;;;
;; Real Mode ;;
;;;;;;;;;;;;;;;

RealMode:
  mov ax, 0x1000  ; set up segments
  mov ds, ax
  mov es, ax
  mov si, welcome
  call print_string

loop:
  mov si, prompt
  call print_string

  mov di, buffer
  call get_string

  mov si, buffer
  cmp byte [si], 0  ; blank line?
  je loop           ; yes, ignore it

  mov di, cmd_hi    ; "hi" command
  call strcmp
  jz .helloworld

  mov si, buffer
  mov di, cmd_help  ; "help" command
  call strcmp
  jz .help

  mov si, buffer
  mov di, cmd_questionmark  ; "?" command
  call strcmp
  jz .help
 
  mov si, buffer
  mov di, cmd_exit  ; "exit" command
  call strcmp
  jz .exit

  mov si, buffer
  mov di, cmd_pm  ; "pm (protected mode)" command
  call strcmp
  jz .pm

  mov si,badcommand
  call print_string
  jmp loop

.helloworld:
  mov si, msg_helloworld
  call print_string

  jmp loop

.help:
  mov si, msg_help
  call print_string

  jmp loop

.exit:
  mov si, msg_exit
  call print_string
  jmp 0xffff:0x0000  ; Reboot

.pm:
  call clrscr
  mov si, msg_pm
  call print_string
  call Waitingloop

  cli                ; clear interrupts
  mov    eax, cs            ; CS ---> EAX
  mov    ds, ax            ; CS ---> DS
  shl     eax, 4            ; CS * 0x10 = linear address
  mov    [CODE_Desc+2], ax    ; linear address ---> base of code descriptor
  mov    [DATA_Desc+2], ax    ; linear address ---> base of data descriptor
  shr    eax, 16            ;    
  mov    [CODE_Desc+4], al       ;
  mov    [DATA_Desc+4], al       ;

  mov    eax, cs            ; base of GDT
  shl    eax, 4
  add    eax, NULL_Desc

  mov    [Base], eax                ; base of GDT  ---> GDTR
  mov    [Limit], WORD gdtr - NULL_Desc - 1    ; limit of GDT ---> GDTR
  lgdt    [gdtr]                    ; load GDT via GDTR

  mov    eax, cr0        ; switch-over to Protected Mode
  or    eax, 1            ; set bit 0 of CR0 register
  mov    cr0, eax        ;

  jmp word 0x8:ProtectedMode
  ; db    0xea            ; instruction code for FAR JUMP
  ; dw    ProtectedMode        ; offset for jump
  ; dw    0x8            ; selector of the segment for the jump
  ; http://www.nasm.us/doc/nasmdo10.html#section-10.1


;;;;;;;;;;;
;; Calls ;;
;;;;;;;;;;;

print_string:
  lodsb        ; grab a byte from SI

  or al, al    ; logical or AL by itself
  jz .done     ; if the result is zero, get out

  mov ah, 0x0E
  int 0x10       ; otherwise, print out the character!

  jmp print_string

.done:
  ret

get_string:
  xor cl, cl

.loop:
  mov ah, 0x00
  int 0x16      ; wait for keypress

  cmp al, 8     ; backspace pressed?
  je .backspace ; yes, handle it

  cmp al, 13    ; enter pressed?
  je .done      ; yes, we're done

  cmp cl, 31    ; 31 chars inputted?
  je .loop      ; yes, only let in backspace and enter

  mov ah, 0x0E
  int 0x10      ; print out character

  stosb  ; put character in buffer
  inc cl
  jmp .loop

.backspace:
  or cl, cl     ; zero? (start of the string)
  jz .loop      ; if yes, ignore the key

  dec di
  mov byte [di], 0  ; delete character
  dec cl        ; decrement counter as well

  mov ax, 0x0E08
  int 0x10      ; backspace on the screen

  mov al, ' '
  int 0x10      ; blank character out

  mov al, 8
  int 0x10      ; backspace again

  jmp .loop     ; go to the main loop

.done:
  mov al, 0     ; null terminator
  stosb

  mov ax, 0x0E0D
  int 0x10
  mov al, 0x0A
  int 0x10      ; newline

  ret

strcmp:
.loop:
  mov al, [si]   ; grab a byte from SI
  cmp al, [di]   ; are SI and DI equal?
  jne .done      ; nope, we're done.

  or al, al      ; zero?
  jz .done       ; yes, we're done.

  inc di         ; increment DI
  inc si         ; increment SI
  jmp .loop      ; loop!

.done:    
  ret

clrscr:
  mov ax, 0x0600
  xor cx, cx
  mov dx, 0x174F
  xor bh, bh
  int 0x10
  ret

;;;;;;;;;;;;;;;;;;;;
;; Protected Mode ;;
;;;;;;;;;;;;;;;;;;;;

[Bits 32]

ProtectedMode:
  mov    WORD [CODE_Desc+2], 0    ; code segment base address = 0
  mov    WORD [DATA_Desc+2], 0    ; data segment base address = 0
  mov    BYTE [CODE_Desc+4], 0    ; code segment base address = 0
  mov    BYTE [DATA_Desc+4], 0    ; data segment base address = 0

  mov    eax, 2            ; create selector for data segment
  shl    eax, 3
  mov    ds, ax            ; data descriptor --> data, stack and extra segment
  mov    ss, ax             
  mov    es, ax
  xor    eax, eax        ; null desriptor --> FS and GS
  mov    fs, ax
  mov    gs, ax
  mov    esp, 0x1FFFFF        ; set stack below 2 MB limit

  jmp    0x8:0x10000 + ProtectedMode2    ; jump to the new code segment
           
ProtectedMode2:
  mov ecx, 0x0B8000
  mov esi, 0x10000 + msg_pm2 ; 'OS currently uses Protected Mode.'
  mov dl,  0x01
.endlessloop:
  call Waitingloop
  inc dl
  cmp dl, 0x15
  jz .resetcolor
  call PutStr_32
  jmp .endlessloop
.resetcolor:
  xor dl, dl
  jmp .endlessloop

Waitingloop:                    
  pushad
  mov ebx,0x9FFFF
.loop:
  dec ebx      
  jnz .loop
  popad
  ret          

PutStr_32:      
  pushad
  .nextchar:
    lodsb
    or al, al          
    jz .end      
    mov byte [ds:ecx], al
    inc ecx
    mov byte [ds:ecx], dl
    inc ecx  
    jmp .nextchar  
  .end:
    popad
    ret  
; You load the address you want to output to in ecx(0x0B8000), the address of the string (has to be null terminated)
; you want to print in esi and the attributes in dl (personally 0x04, red char on black background) ,
; the lodsb, loads one byte from esi into al then increments esi, then it checks for a null terminator
; then it moves the char into the write position in vid mem and then increments ecx and writes the attributes,
; the loops until it finds a null pointer at which point it breaks....
 
times 1024-($-$$) db 0
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TEST RM -> PM vers. 0.01 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

[BITS 16] ; 16 Bit Code
jmp RealMode ; jump behind GDT

%include "gdt.inc"

;;;;;;;;;;;;;
;; Strings ;;
;;;;;;;;;;;;;

welcome db 'HenkesSoft 0.02 (version from Mar 19, 2009)', 13, 10, 0
msg_helloworld db 'Hello World!', 13, 10, 0
badcommand db 'Command unknown.', 13, 10, 0
prompt db '>', 0
cmd_hi db 'hi', 0
cmd_help db 'help', 0
cmd_questionmark db '?', 0
cmd_exit db 'exit', 0
cmd_pm db 'pm', 0
msg_help db 'Commands: hi, help, ?, pm, exit', 13, 10, 0
msg_exit db 'Reboot starts now.', 13, 10, 0
msg_pm db 'Switch-over to Protected Mode.', 13, 10, 0
msg_pm2 db 'OS currently uses Protected Mode.', 13, 10, 0

buffer times 32 db 0

;;;;;;;;;;;;;;;
;; Real Mode ;;
;;;;;;;;;;;;;;;

RealMode:
mov ax, 0x1000 ; set up segments
mov ds, ax
mov es, ax
mov si, welcome
call print_string

loop:
mov si, prompt
call print_string

mov di, buffer
call get_string

mov si, buffer
cmp byte [si], 0 ; blank line?
je loop ; yes, ignore it

mov di, cmd_hi ; "hi" command
call strcmp
jz .helloworld

mov si, buffer
mov di, cmd_help ; "help" command
call strcmp
jz .help

mov si, buffer
mov di, cmd_questionmark ; "?" command
call strcmp
jz .help

mov si, buffer
mov di, cmd_exit ; "exit" command
call strcmp
jz .exit

mov si, buffer
mov di, cmd_pm ; "pm (protected mode)" command
call strcmp
jz .pm

mov si,badcommand
call print_string
jmp loop

.helloworld:
mov si, msg_helloworld
call print_string

jmp loop

.help:
mov si, msg_help
call print_string

jmp loop

.exit:
mov si, msg_exit
call print_string
jmp 0xffff:0x0000 ; Reboot

.pm:
call clrscr
mov si, msg_pm
call print_string
call Waitingloop

cli ; clear interrupts
mov eax, cs ; CS ---> EAX
mov ds, ax ; CS ---> DS
shl eax, 4 ; CS * 0x10 = linear address
mov [CODE_Desc+2], ax ; linear address ---> base of code descriptor
mov [DATA_Desc+2], ax ; linear address ---> base of data descriptor
shr eax, 16 ;
mov [CODE_Desc+4], al ;
mov [DATA_Desc+4], al ;

mov eax, cs ; base of GDT
shl eax, 4
add eax, NULL_Desc

mov [Base], eax ; base of GDT ---> GDTR
mov [Limit], WORD gdtr - NULL_Desc - 1 ; limit of GDT ---> GDTR
lgdt [gdtr] ; load GDT via GDTR

mov eax, cr0 ; switch-over to Protected Mode
or eax, 1 ; set bit 0 of CR0 register
mov cr0, eax ;

jmp word 0x8:ProtectedMode
; db 0xea ; instruction code for FAR JUMP
; dw ProtectedMode ; offset for jump
; dw 0x8 ; selector of the segment for the jump
; http://www.nasm.us/doc/nasmdo10.html#section-10.1


;;;;;;;;;;;
;; Calls ;;
;;;;;;;;;;;

print_string:
lodsb ; grab a byte from SI

or al, al ; logical or AL by itself
jz .done ; if the result is zero, get out

mov ah, 0x0E
int 0x10 ; otherwise, print out the character!

jmp print_string

.done:
ret

get_string:
xor cl, cl

.loop:
mov ah, 0x00
int 0x16 ; wait for keypress

cmp al, 8 ; backspace pressed?
je .backspace ; yes, handle it

cmp al, 13 ; enter pressed?
je .done ; yes, we're done

cmp cl, 31 ; 31 chars inputted?
je .loop ; yes, only let in backspace and enter

mov ah, 0x0E
int 0x10 ; print out character

stosb ; put character in buffer
inc cl
jmp .loop

.backspace:
or cl, cl ; zero? (start of the string)
jz .loop ; if yes, ignore the key

dec di
mov byte [di], 0 ; delete character
dec cl ; decrement counter as well

mov ax, 0x0E08
int 0x10 ; backspace on the screen

mov al, ' '
int 0x10 ; blank character out

mov al, 8
int 0x10 ; backspace again

jmp .loop ; go to the main loop

.done:
mov al, 0 ; null terminator
stosb

mov ax, 0x0E0D
int 0x10
mov al, 0x0A
int 0x10 ; newline

ret

strcmp:
.loop:
mov al, [si] ; grab a byte from SI
cmp al, [di] ; are SI and DI equal?
jne .done ; nope, we're done.

or al, al ; zero?
jz .done ; yes, we're done.

inc di ; increment DI
inc si ; increment SI
jmp .loop ; loop!

.done:
ret

clrscr:
mov ax, 0x0600
xor cx, cx
mov dx, 0x174F
xor bh, bh
int 0x10
ret

;;;;;;;;;;;;;;;;;;;;
;; Protected Mode ;;
;;;;;;;;;;;;;;;;;;;;

[Bits 32]

ProtectedMode:
mov WORD [CODE_Desc+2], 0 ; code segment base address = 0
mov WORD [DATA_Desc+2], 0 ; data segment base address = 0
mov BYTE [CODE_Desc+4], 0 ; code segment base address = 0
mov BYTE [DATA_Desc+4], 0 ; data segment base address = 0

mov eax, 2 ; create selector for data segment
shl eax, 3
mov ds, ax ; data descriptor --> data, stack and extra segment
mov ss, ax
mov es, ax
xor eax, eax ; null desriptor --> FS and GS
mov fs, ax
mov gs, ax
mov esp, 0x1FFFFF ; set stack below 2 MB limit

jmp 0x8:0x10000 + ProtectedMode2 ; jump to the new code segment

ProtectedMode2:
mov ecx, 0x0B8000
mov esi, 0x10000 + msg_pm2 ; 'OS currently uses Protected Mode.'
mov dl, 0x01
.endlessloop:
call Waitingloop
inc dl
cmp dl, 0x15
jz .resetcolor
call PutStr_32
jmp .endlessloop
.resetcolor:
xor dl, dl
jmp .endlessloop

Waitingloop:
pushad
mov ebx,0x9FFFF
.loop:
dec ebx
jnz .loop
popad
ret

PutStr_32:
pushad
.nextchar:
lodsb
or al, al
jz .end
mov byte [ds:ecx], al
inc ecx
mov byte [ds:ecx], dl
inc ecx
jmp .nextchar
.end:
popad
ret
; You load the address you want to output to in ecx(0x0B8000), the address of the string (has to be null terminated)
; you want to print in esi and the attributes in dl (personally 0x04, red char on black background) ,
; the lodsb, loads one byte from esi into al then increments esi, then it checks for a null terminator
; then it moves the char into the write position in vid mem and then increments ecx and writes the attributes,
; the loops until it finds a null pointer at which point it breaks....

times 1024-($-$$) db 0
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TEST RM -> PM  vers. 0.01     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 [BITS 16]     ; 16 Bit Code
  jmp RealMode     ; jump behind GDT

%include "gdt.inc"

;;;;;;;;;;;;;
;; Strings ;;
;;;;;;;;;;;;;

welcome db 'HenkesSoft 0.02 (version from Mar 19, 2009)', 13, 10, 0
msg_helloworld db 'Hello World!', 13, 10, 0
badcommand db 'Command unknown.', 13, 10, 0
prompt db '>', 0
cmd_hi db 'hi', 0
cmd_help db 'help', 0
cmd_questionmark db '?', 0
cmd_exit db 'exit', 0
cmd_pm db 'pm', 0
msg_help db 'Commands: hi, help, ?, pm, exit', 13, 10, 0
msg_exit db 'Reboot starts now.', 13, 10, 0
msg_pm db 'Switch-over to Protected Mode.', 13, 10, 0
msg_pm2 db 'OS currently uses Protected Mode.', 13, 10, 0

buffer times 32 db 0

;;;;;;;;;;;;;;;
;; Real Mode ;;
;;;;;;;;;;;;;;;

RealMode:
  mov ax, 0x1000  ; set up segments
  mov ds, ax
  mov es, ax
  mov si, welcome
  call print_string

loop:
  mov si, prompt
  call print_string

  mov di, buffer
  call get_string

  mov si, buffer
  cmp byte [si], 0  ; blank line?
  je loop           ; yes, ignore it

  mov di, cmd_hi    ; "hi" command
  call strcmp
  jz .helloworld

  mov si, buffer
  mov di, cmd_help  ; "help" command
  call strcmp
  jz .help

  mov si, buffer
  mov di, cmd_questionmark  ; "?" command
  call strcmp
  jz .help
 
  mov si, buffer
  mov di, cmd_exit  ; "exit" command
  call strcmp
  jz .exit

  mov si, buffer
  mov di, cmd_pm  ; "pm (protected mode)" command
  call strcmp
  jz .pm

  mov si,badcommand
  call print_string
  jmp loop

.helloworld:
  mov si, msg_helloworld
  call print_string

  jmp loop

.help:
  mov si, msg_help
  call print_string

  jmp loop

.exit:
  mov si, msg_exit
  call print_string
  jmp 0xffff:0x0000  ; Reboot

.pm:
  call clrscr
  mov si, msg_pm
  call print_string
  call Waitingloop

  cli                ; clear interrupts
  mov    eax, cs            ; CS ---> EAX
  mov    ds, ax            ; CS ---> DS
  shl     eax, 4            ; CS * 0x10 = linear address
  mov    [CODE_Desc+2], ax    ; linear address ---> base of code descriptor
  mov    [DATA_Desc+2], ax    ; linear address ---> base of data descriptor
  shr    eax, 16            ;    
  mov    [CODE_Desc+4], al       ;
  mov    [DATA_Desc+4], al       ;

  mov    eax, cs            ; base of GDT
  shl    eax, 4
  add    eax, NULL_Desc

  mov    [Base], eax                ; base of GDT  ---> GDTR
  mov    [Limit], WORD gdtr - NULL_Desc - 1    ; limit of GDT ---> GDTR
  lgdt    [gdtr]                    ; load GDT via GDTR

  mov    eax, cr0        ; switch-over to Protected Mode
  or    eax, 1            ; set bit 0 of CR0 register
  mov    cr0, eax        ;

  jmp word 0x8:ProtectedMode
  ; db    0xea            ; instruction code for FAR JUMP
  ; dw    ProtectedMode        ; offset for jump
  ; dw    0x8            ; selector of the segment for the jump
  ; http://www.nasm.us/doc/nasmdo10.html#section-10.1


;;;;;;;;;;;
;; Calls ;;
;;;;;;;;;;;

print_string:
  lodsb        ; grab a byte from SI

  or al, al    ; logical or AL by itself
  jz .done     ; if the result is zero, get out

  mov ah, 0x0E
  int 0x10       ; otherwise, print out the character!

  jmp print_string

.done:
  ret

get_string:
  xor cl, cl

.loop:
  mov ah, 0x00
  int 0x16      ; wait for keypress

  cmp al, 8     ; backspace pressed?
  je .backspace ; yes, handle it

  cmp al, 13    ; enter pressed?
  je .done      ; yes, we're done

  cmp cl, 31    ; 31 chars inputted?
  je .loop      ; yes, only let in backspace and enter

  mov ah, 0x0E
  int 0x10      ; print out character

  stosb  ; put character in buffer
  inc cl
  jmp .loop

.backspace:
  or cl, cl     ; zero? (start of the string)
  jz .loop      ; if yes, ignore the key

  dec di
  mov byte [di], 0  ; delete character
  dec cl        ; decrement counter as well

  mov ax, 0x0E08
  int 0x10      ; backspace on the screen

  mov al, ' '
  int 0x10      ; blank character out

  mov al, 8
  int 0x10      ; backspace again

  jmp .loop     ; go to the main loop

.done:
  mov al, 0     ; null terminator
  stosb

  mov ax, 0x0E0D
  int 0x10
  mov al, 0x0A
  int 0x10      ; newline

  ret

strcmp:
.loop:
  mov al, [si]   ; grab a byte from SI
  cmp al, [di]   ; are SI and DI equal?
  jne .done      ; nope, we're done.

  or al, al      ; zero?
  jz .done       ; yes, we're done.

  inc di         ; increment DI
  inc si         ; increment SI
  jmp .loop      ; loop!

.done:    
  ret

clrscr:
  mov ax, 0x0600
  xor cx, cx
  mov dx, 0x174F
  xor bh, bh
  int 0x10
  ret

;;;;;;;;;;;;;;;;;;;;
;; Protected Mode ;;
;;;;;;;;;;;;;;;;;;;;

[Bits 32]

ProtectedMode:
  mov    WORD [CODE_Desc+2], 0    ; code segment base address = 0
  mov    WORD [DATA_Desc+2], 0    ; data segment base address = 0
  mov    BYTE [CODE_Desc+4], 0    ; code segment base address = 0
  mov    BYTE [DATA_Desc+4], 0    ; data segment base address = 0

  mov    eax, 2            ; create selector for data segment
  shl    eax, 3
  mov    ds, ax            ; data descriptor --> data, stack and extra segment
  mov    ss, ax             
  mov    es, ax
  xor    eax, eax        ; null desriptor --> FS and GS
  mov    fs, ax
  mov    gs, ax
  mov    esp, 0x1FFFFF        ; set stack below 2 MB limit

  jmp    0x8:0x10000 + ProtectedMode2    ; jump to the new code segment
           
ProtectedMode2:
  mov ecx, 0x0B8000
  mov esi, 0x10000 + msg_pm2 ; 'OS currently uses Protected Mode.'
  mov dl,  0x01
.endlessloop:
  call Waitingloop
  inc dl
  cmp dl, 0x15
  jz .resetcolor
  call PutStr_32
  jmp .endlessloop
.resetcolor:
  xor dl, dl
  jmp .endlessloop

Waitingloop:                    
  pushad
  mov ebx,0x9FFFF
.loop:
  dec ebx      
  jnz .loop
  popad
  ret          

PutStr_32:      
  pushad
  .nextchar:
    lodsb
    or al, al          
    jz .end      
    mov byte [ds:ecx], al
    inc ecx
    mov byte [ds:ecx], dl
    inc ecx  
    jmp .nextchar  
  .end:
    popad
    ret  
; You load the address you want to output to in ecx(0x0B8000), the address of the string (has to be null terminated)
; you want to print in esi and the attributes in dl (personally 0x04, red char on black background) ,
; the lodsb, loads one byte from esi into al then increments esi, then it checks for a null terminator
; then it moves the char into the write position in vid mem and then increments ecx and writes the attributes,
; the loops until it finds a null pointer at which point it breaks....
 
times 1024-($-$$) db 0

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 13:16:24 20.03.2009, insgesamt 5-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 12:57:07 20.03.2009   Titel:              Zitieren

Ich habe das OS auf einem alten PC (AMD 1400 MHz) getestet. Dort rebootet er bei Eingabe "pm", während bochs das OS brav von Diskette schluckt. Weiß jemand, wo der "real wirksame" Fehler liegt?

Didaktisch steckt das "OS" momentan im Schlamm, da ich momentan nicht sicher bin, wie man das Ganze am besten in kleine Häppchen verpacken kann. Was würdet ihr in welche inc-Dateien packen? Man kann das ja auch kaum noch sinnvoll hier posten (warum gibt es keine scroll-Funktion für solche Dateien wie in anderen Foren?).

lgdt [gdt] findet man in google 216 mal.
lgdt [gdtr] findet man in google 740 mal.
Letzteres ist ja auch richtiger, werde das anpassen.

Jemand hatte auch nach Einstieg in x86-64 gefragt. Hier sind Links dazu:
http://wiki.osdev.org/Entering_Long_Mode_Directly
http://en.wikipedia.org/wiki/Long_mode

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 13:29:51 20.03.2009, insgesamt 3-mal bearbeitet
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 16:50:03 20.03.2009   Titel:              Zitieren

Ok, mal der Reihe nach abarbeiten...

Erhard Henkes schrieb:

Ich hoffe zumindest, dass ich Dich so richtig verstanden habe.
Wie hättest Du dies mit 'test op,op' (AND-Verknüpfung ohne Speicherung, nur Flags setzen) gemacht? Das nimmt man doch eher, um zu testen, ob ein bestimmtes Bit gesetzt ist? z.B. test AL, 64 (check auf Bit 6)

Ja, so war das gedacht, sieht ok. :)
"test" kannst du sowohl, wie du schreibst, benutzen, um einzelne Bits zu testen, allerdings erzielst du mit "test al, al" praktisch das gleiche Ergebnis wie mit "or al, al" (oder wohl auch "and al, al", wenn wir schon dabei sind), ist aber IMHO zumindest konsequenter. :)

Erhard Henkes schrieb:
Welchen offset würde man da mittels org wählen und warum?

Das offset, an den du den Code im RAM bzgl. Segment 0 kopierst. Da bietet sich IMHO zB. 8000h an...

Erhard Henkes schrieb:
Mir ist noch nicht klar, warum die meisten den Kernel (oder ersten Teil des Kernels) nach 10000h setzen.

...aus dem selben Grund, aus dem wohl auch viele Frickler ihren Code nach 10000h laden: Es ist einfach eine schoene runde Adresse. Und bei 10000h laeuft man praktisch auch keine Gefahr mehr, irgendwo mit den Untiefen der BDA in Konflikt zu geraten. 8000h sollte da AFAIK aber auch sicher und "rund" genug sein.

Erhard Henkes schrieb:
Ich habe das OS auf einem alten PC (AMD 1400 MHz) getestet. Dort rebootet er bei Eingabe "pm", während bochs das OS brav von Diskette schluckt. Weiß jemand, wo der "real wirksame" Fehler liegt?

Ohne zu testen, kommt mir folgendes eigenartig vor:
Assembler Code:
;z234-237, kernel.asm
  mov    WORD [CODE_Desc+2], 0    ; code segment base address = 0
  mov    WORD [DATA_Desc+2], 0    ; data segment base address = 0
  mov    BYTE [CODE_Desc+4], 0    ; code segment base address = 0
  mov    BYTE [DATA_Desc+4], 0    ; data segment base address = 0
Assembler Code:
;z234-237, kernel.asm
mov WORD [CODE_Desc+2], 0 ; code segment base address = 0
mov WORD [DATA_Desc+2], 0 ; data segment base address = 0
mov BYTE [CODE_Desc+4], 0 ; code segment base address = 0
mov BYTE [DATA_Desc+4], 0 ; data segment base address = 0
Assembler Code:
;z234-237, kernel.asm
  mov    WORD [CODE_Desc+2], 0    ; code segment base address = 0
  mov    WORD [DATA_Desc+2], 0    ; data segment base address = 0
  mov    BYTE [CODE_Desc+4], 0    ; code segment base address = 0
  mov    BYTE [DATA_Desc+4], 0    ; data segment base address = 0

Halte ich durchaus fuer problematisch, mit den RM-Segmenten im PM auf den Speicher zuzugreifen. -> Mein Tipp waere, das Ganze als initialisierte Daten anzulegen, dann kannst du dir diesen Code (wie die restliche Initialisierung in z 104 eigentlich auch) sparen.

Ausserdem bekommst du potentiell Probleme, wenn du auf Speicher >1MB zugreifst (stack), ohne die A20 eingeschaltet zu haben.

...
Erhard Henkes schrieb:
Vielleicht kann Nobuo T seine Idee daneben stellen zum Vergleich.

...seufz... Das wuerde einiges an Arbeit, da ich deinen Code erst recht nicht ohne Testen umfangreich umschreiben und hier einstellen will. Mal sehen, ob ich heute Abend Zeit und Nerv finde.


Zu deinem clearscreen32:
32Bit loop und rep benutzen ecx... Vielleicht liegt es daran.

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908


Zuletzt bearbeitet von Nobuo T am 16:51:58 20.03.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:43:42 20.03.2009   Titel:              Zitieren

Zu test op,op:
Ich dachte, Du würdest dies als Ersatz für cmp op,op einsetzen wollen.

Ich habe leider noch nicht genau verstanden, wie Du das mit den initialisierten Daten als Vereinfachung meinst. Ein konkreter Vorschlag würde hier echt helfen.

Wie kann man in Bochs eigentlich die Belegung des Speichers visualisieren?
Kenne bisher nur den Bochs Debugger mit der Register-Visualisierung.
Ist das biedere Bochs eigentlich das ideale Tool bezüglich Visualisierung oder hat jemand bessere Erfahrung mit anderen Emulationen gemacht? Einer der didaktischen Probleme ist ja, dass man überhaupt nicht "sieht", in welchem Mode (RM, PM) man sich befindet, ob A20 aktiviert ist, usw. Da ist eines der Probleme beim Einstieg in die OS-Entwicklung.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:46:51 20.03.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:03:42 21.03.2009   Titel:              Zitieren

Zitat:
...seufz... Das wuerde einiges an Arbeit, da ich deinen Code erst recht nicht ohne Testen umfangreich umschreiben und hier einstellen will. Mal sehen, ob ich heute Abend Zeit und Nerv finde.

Hier ist noch eine andere ältere (Okt. 1996) Quelle für dieses Vorgehen:
http://www.fh-zwickau.de/doc/prmo/pmtutor/code/pmode/pm_01.asm (einfach)
http://www.fh-zwickau.de/doc/prmo/pmtutor/code/pmode/pm_07_03.asm (komplex mit multitasking)

Dies war wahrscheinlich auch Vorbild für die bereits o.g. Vorgehensweise, die Dir nicht sonderlich gefällt:
http://lowlevel.brainsware.org/wiki/index.php/Protected_Mode

Erklärbar ist es auf jeden Fall ganz gut.
Mich irritiert momentan, dass es in Bochs läuft, aber auf einem alten PC von Floppy nicht bootet. :rolleyes:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 17:04:25 21.03.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 14:55:51 21.03.2009   Titel:              Zitieren

Ich habe als Vorbereitung etwas zu RM und PM geschrieben:
http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId362977

Es ist wichtig, dass man die Erklärungen und Zeichnungen möglichst einfach und richtig versteht. Ansonsten versteht man die praktische Abfolge hinterher falsch. Könnt ihr das bitte mal checken?

Die nächste geistige Reihefolge wäre dann z.B.:

1) Selektor (hier kommen GDT und LDT sowie die Privilege Levels 0-3 ins Spiel)
2) Aufbau GDT
3) Welche Deskriptoren gibt es noch?
4) Interrupts
5) Programmablauf in PM
6) Multitasking

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 17:02:19 21.03.2009, insgesamt 1-mal bearbeitet
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 17:33:22 21.03.2009   Titel:              Zitieren

Ich habe deine Quellcodes mal etwas umgebaut. Um die Scrollerei einzudaemmen, habe ich die Dateien mal hier hochgeladen.
Waere praktisch, wenn du die Quellcodes in deinem Tutorial auch direkt als Downloads haettest (habe sie zumindest nicht gefunden).
Eine aufschlussreiche Seite zum A20-Kram ist zB. hier zu finden.

Zu deinem Text:
Begriffe im Deutschen werden meist ziemlich nach Lust und Laune verwendet, aber
lineare und physikalische Adresse ist AFAIK nicht das Gleiche. Spaetestens beim Paging nicht: Da wird aus der linearen (zT. dann auch logische Adresse genannt) Adresse mit der PageTable erst die physikalische Adresse gewurstet.

IMHO koenntest du noch etwas ausfuehrlicher darauf eingehen, warum fuer Multitasking nun auf einmal Schutzmechanismen noetig sind, und warum fuer DOS nicht, bzw. was unter Multitasking grob zu verstehen ist.

Ansonsten bin ich mir nicht sicher, ob das so schon "leicht verstaendlich" ist.
IMHO ist dein Fazit noch etwas verwirrend und deinen "5)" in der praktischen Umsetzung kann nicht mal ich so nachvollziehen.

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:21:40 21.03.2009   Titel:              Zitieren

Zitat:
lineare und physikalische Adresse ist AFAIK nicht das Gleiche.

Ja, da hast Du ab dem 386er völlig Recht. Man findet in der Literatur ständig einen Mischmasch aus 286er 16-Bit-Protected-Mode und 386er 32-Bit-Protected-Mode. Beim 286er ist die "lineare" Adresse identisch mit der physikalischen Adresse, beim 386er muss letztere aus der ersten wegen des Pagings berechnet werden. Auch die Deskriptoren sind beim Sprung vom 286er zum 386er von sechs auf acht Byte gewachsen. Erst durch direkten Vergleich beider Systeme versteht man, warum das heute so chaotisch angeordnet ist.

Nobuo, vielen Dank für Deinen Quellcode! Ich werde eine Seite mit Download-Links einbauen. Dort wird es dann auch einen Bereich "Erlkönig" geben, wo wir alphas und betas ablegen können.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 18:24:36 21.03.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:25:52 21.03.2009   Titel:              Zitieren

Zitat:
IMHO koenntest du noch etwas ausfuehrlicher darauf eingehen, warum fuer Multitasking nun auf einmal Schutzmechanismen noetig sind, und warum fuer DOS nicht, bzw. was unter Multitasking grob zu verstehen ist.
Akzeptiert.

Das "Fazit" werde ich ebenfalls überdenken.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:44:37 21.03.2009   Titel:              Zitieren

Feedback bezüglich Code von Nobuo T:

Test 1: Auf Floppy schreiben und "echt" booten.
Resultat: Perfekt! :live:

Erstes Code-Studium:
Kernel auf 0x08000 gesetzt wie diskutiert,
buffer weg,
A20 eingeschaltet (die berühmte 21. Adressleitung),
ansprechende Ausgabe der Meldung im PM

@Nobuo T: Danke für die fundierte Unterstützung! :)

@all: bitte den Code checken, gute Ideen werden sofort angenommen. Vielleicht kann man auch im Real Mode noch etwas Interessantes ergänzen, z.B. den CPUID-Befehl?!

Zitat:
Waere praktisch, wenn du die Quellcodes in deinem Tutorial auch direkt als Downloads haettest (habe sie zumindest nicht gefunden).

http://www.henkessoft.de/OS_Dev/Downloads/20090321_eh_os.zip

Ich werde diesen m.E. gelungenen Einstieg in den PM nun didaktisch aufarbeiten, damit das Tutorial Einsteigern das Leben so leicht wie möglich macht. Da fehlen noch einige gute Abbildungen. Die Unterscheidung zwischen 16-Bit- und 32-Bit-Protected Mode ist didaktisch wichtig. Paging, Unterschied lineare/phys. Adresse ebenso.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 21:19:48 22.03.2009, insgesamt 6-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 01:17:07 22.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Vielleicht kann man auch im Real Mode noch etwas Interessantes ergänzen
Vielleicht folgendes:

Wenn man im PM ein Segmentregister initialisiert und dann wieder in den RM wechselt, bleibt die Segmentgröße des Selektors für das initialisierte Segmentregister erhalten. Dadurch hat man über dieses Segmentregister Zugriff auf die gesamte Segmentgröße auch im RM.

Was heißt, die Begrenzung auf 1MB RAM im RM kann relativ einfach außer Kraft gesetzt werden. Das Segmentregister darf nur nicht im RM wieder verändert werden. Sonst ist der Spaß vorbei. Aber man ja beliebig oft hin und her wechseln. :)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:15:02 23.03.2009   Titel:              Zitieren

@+gjm+:
Das klingt ja echt abenteuerlich! :D
Findet man dazu bereits einen Link im Internet oder ist das Geheimwissen?
Wie läuft denn da die genaue Adressierung im zurück geschalteten RM ab?

@abc.w: Hast Du den neuen Code bereits ausprobiert?
http://www.henkessoft.de/OS_Dev/Downloads/20090321_eh_os.zip

@Nobuo T: Deine konstruktiven Vorschläge wurden aufgenommen und hoffentlich weitgehend umgesetzt. Multitasking und A20 Gate wird jetzt auch breiter besprochen. Das ist schon ganz schön viel Text, hoffentlich brauchbare Abbildungen und ziemlich viele Zeilen Assembler, nur um die Basis PM zu erreichen. Didaktisch ist es wirklich nicht ganz einfach die x86 Historie verständlich zu erklären, ohne allzu langatmig zu werden. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:26:05 23.03.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:31:35 23.03.2009   Titel:              Zitieren

Eine Frage zum Bootloader-Code:
http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId80121

Wir schreiben den Offset der Sprung-Adresse des Kernels nachs BX.
Später springen wir ohne Verwendung dieses Registers.
Code:
mov bx, 0x8000     ; set up start address of kernel
;...
jmp 0x0000:0x8000   ; address of kernel
Code:
mov bx, 0x8000 ; set up start address of kernel
;...
jmp 0x0000:0x8000 ; address of kernel
Code:
mov bx, 0x8000     ; set up start address of kernel
;...
jmp 0x0000:0x8000   ; address of kernel

ES:BX ist notwendig für int 0x13 als "Buffer Address Pointer".
So läuft es auf jeden Fall auch:
Code:
mov bx, 0x8000     ; set up start address of kernel
;...
jmp bx   ; address of kernel
Code:
mov bx, 0x8000 ; set up start address of kernel
;...
jmp bx ; address of kernel
Code:
mov bx, 0x8000     ; set up start address of kernel
;...
jmp bx   ; address of kernel

Wäre letzteres o.k.? Ist das didaktisch nicht besser? Man verwendet BX auch im Sprungbefehl sofort sofort.

Das erscheint ja auch etwas merkwürdig:
Code:
mov [bootdrive], dl ; boot drive from DL
...
mov dl,[bootdrive] ; select boot drive
Code:
mov [bootdrive], dl ; boot drive from DL
...
mov dl,[bootdrive] ; select boot drive
Code:
mov [bootdrive], dl ; boot drive from DL
...
mov dl,[bootdrive] ; select boot drive

Man könnte den Kernel wohl auch von anderer Stelle laden?
Da unser System dies nicht macht, könnte man [bootdrive] doch auch völlig weg lassen?

Label load_kernel1 kann jetzt ja auch entfallen nach Nobuos Änderung?

Gekürzt würde der Bootloader dann so aussehen:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
org 0x7C00  ; set up start address of bootloader

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; setup a stack and segment regs ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, ax
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; read kernel from floppy disk ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

load_kernel:
    xor ax, ax         ; mov ax, 0  => function "reset"
    int 0x13          
    jc load_kernel     ; trouble? try again

    mov bx, 0x8000     ; set up start address of kernel
 
    ; set parameters for reading function
    ; 8-bit-wise for better overview
    mov al,10          ; read 10 sectors
    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

    ; show loading message
    mov si,loadmsg
    call print_string

;;;;;;;;;;;;;;;;;;
; jump to kernel ;
;;;;;;;;;;;;;;;;;;

    jmp bx   ; address of kernel

;;;;;;;;;
; calls ;
;;;;;;;;;
 
    ; print string
print_string:
    mov ah, 0x0E      ; VGA BIOS fnct. 0x0E: teletype
.loop:    
    lodsb             ; grab a byte from SI
    test al, al       ; NUL?
    jz .done          ; if the result is zero, get out
    int 0x10          ; otherwise, print out the character!
    jmp .loop
.done:
    ret

;;;;;;;;;;;;;
; constants ;
;;;;;;;;;;;;;

    loadmsg db "bootloader message: loading kernel ...",13,10,0
   
    times 510-($-$$) db 0  
    db 0x55
    db 0xAA
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
org 0x7C00 ; set up start address of bootloader

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; setup a stack and segment regs ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, ax

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; read kernel from floppy disk ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

load_kernel:
xor ax, ax ; mov ax, 0 => function "reset"
int 0x13
jc load_kernel ; trouble? try again

mov bx, 0x8000 ; set up start address of kernel

; set parameters for reading function
; 8-bit-wise for better overview
mov al,10 ; read 10 sectors
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

; show loading message
mov si,loadmsg
call print_string

;;;;;;;;;;;;;;;;;;
; jump to kernel ;
;;;;;;;;;;;;;;;;;;

jmp bx ; address of kernel

;;;;;;;;;
; calls ;
;;;;;;;;;

; print string
print_string:
mov ah, 0x0E ; VGA BIOS fnct. 0x0E: teletype
.loop:
lodsb ; grab a byte from SI
test al, al ; NUL?
jz .done ; if the result is zero, get out
int 0x10 ; otherwise, print out the character!
jmp .loop
.done:
ret

;;;;;;;;;;;;;
; constants ;
;;;;;;;;;;;;;

loadmsg db "bootloader message: loading kernel ...",13,10,0

times 510-($-$$) db 0
db 0x55
db 0xAA
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
org 0x7C00  ; set up start address of bootloader

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; setup a stack and segment regs ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, ax
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; read kernel from floppy disk ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

load_kernel:
    xor ax, ax         ; mov ax, 0  => function "reset"
    int 0x13          
    jc load_kernel     ; trouble? try again

    mov bx, 0x8000     ; set up start address of kernel
 
    ; set parameters for reading function
    ; 8-bit-wise for better overview
    mov al,10          ; read 10 sectors
    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

    ; show loading message
    mov si,loadmsg
    call print_string

;;;;;;;;;;;;;;;;;;
; jump to kernel ;
;;;;;;;;;;;;;;;;;;

    jmp bx   ; address of kernel

;;;;;;;;;
; calls ;
;;;;;;;;;
 
    ; print string
print_string:
    mov ah, 0x0E      ; VGA BIOS fnct. 0x0E: teletype
.loop:    
    lodsb             ; grab a byte from SI
    test al, al       ; NUL?
    jz .done          ; if the result is zero, get out
    int 0x10          ; otherwise, print out the character!
    jmp .loop
.done:
    ret

;;;;;;;;;;;;;
; constants ;
;;;;;;;;;;;;;

    loadmsg db "bootloader message: loading kernel ...",13,10,0
   
    times 510-($-$$) db 0  
    db 0x55
    db 0xAA

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:19:24 23.03.2009, insgesamt 5-mal bearbeitet
Cortex-M3 Fan
Unregistrierter




Beitrag Cortex-M3 Fan Unregistrierter 10:04:23 23.03.2009   Titel:              Zitieren

^^mannomann. ist das ein grausames gefrickel hier!
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:11:08 23.03.2009   Titel:              Zitieren

Zitat:
ist das ein grausames gefrickel hier!

Destruktive (Troll-)Beiträge werden mich nicht aufhalten oder irritieren. :D
Bessere Ideen bezüglich der Umsetzung oder Gesasmtkonstruktion sind dennoch gerne gesehen. :)
Begründe mir lieber mal jemand, warum IBM das Boot-Programm genau nach 7C00h gesendet hat. Die exakte Erklärung habe ich bisher noch nirgends gefunden.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 11:26:12 23.03.2009   Titel:              Zitieren

Naja, mit dem Wegoptimieren muss man immer aufpassen. Das ist sehr oft auch ein Kompromiss zwischen Stabilitaet, Kompatibilitaet und Optimierung, der einen gewisser "Verhaeltnisbereich" IMHO nicht verlassen sollte.

Erhard Henkes schrieb:

Wir schreiben den Offset der Sprung-Adresse des Kernels nachs BX.
Später springen wir ohne Verwendung dieses Registers.
Code:
mov bx, 0x8000     ; set up start address of kernel
;...
jmp 0x0000:0x8000   ; address of kernel
Code:
mov bx, 0x8000 ; set up start address of kernel
;...
jmp 0x0000:0x8000 ; address of kernel
Code:
mov bx, 0x8000     ; set up start address of kernel
;...
jmp 0x0000:0x8000   ; address of kernel

ES:BX ist notwendig für int 0x13 als "Buffer Address Pointer".
So läuft es auf jeden Fall auch:
Code:
mov bx, 0x8000     ; set up start address of kernel
;...
jmp bx   ; address of kernel
Code:
mov bx, 0x8000 ; set up start address of kernel
;...
jmp bx ; address of kernel
Code:
mov bx, 0x8000     ; set up start address of kernel
;...
jmp bx   ; address of kernel

Wäre letzteres o.k.? Ist das didaktisch nicht besser? Man verwendet BX auch im Sprungbefehl sofort sofort.


Im Code vor dem long jump zum Kern, kommen wir ganz gut zurecht, ohne genau zu wissen, welchen Wert cs hat, da alle Spruenge etc. nur relativ zum aktuellen Offset (IP) adressieren. Wenn du aber den Sprung ueber bx machst, hast du ein absolutes Offset zu CS und musst dir daher sicher sein, dass cs auch 0 ist. Sonst schiesst du am Ziel vorbei. ;)
Kann also sein, dass das funktioniert. Die Chancen stehen aber auch nicht schlecht, dass es das auf anderen PCs nicht tut.

Erhard Henkes schrieb:

Das erscheint ja auch etwas merkwürdig:
Code:
mov [bootdrive], dl ; boot drive from DL
...
mov dl,[bootdrive] ; select boot drive
Code:
mov [bootdrive], dl ; boot drive from DL
...
mov dl,[bootdrive] ; select boot drive
Code:
mov [bootdrive], dl ; boot drive from DL
...
mov dl,[bootdrive] ; select boot drive

Man könnte den Kernel wohl auch von anderer Stelle laden?
Da unser System dies nicht macht, könnte man [bootdrive] doch auch völlig weg lassen?

Bei der ersten Verwendung hatte ich die Sache in deinem alten Code auch auskommentiert (z. 16). Beim 2. Mal bin ich nicht sicher, ob dl vom Interrupt nicht geschrottet wird.

Ansonsten ist das wieder eine Kompatibilitaetsfrage. Du kannst natuerlich die Info des BIOS wegschmeissen, dl einfach immer auf 0 (fdd A:) setzen und damit ausschliessen, dass jemand den Code jemals von was Anderem (2. Floppy, USB oder was auch immer) startet, aber IMHO sind es diese 2 Zeilen irgendwie nicht wert.
Deshalb habe ich sie drin gelassen.

Erhard Henkes schrieb:

Label load_kernel1 kann jetzt ja auch entfallen nach Nobuos Änderung?

Da hast du allerdings recht.


Erhard Henkes schrieb:

@+gjm+:
Das klingt ja echt abenteuerlich! :D
Findet man dazu bereits einen Link im Internet oder ist das Geheimwissen?
Wie läuft denn da die genaue Adressierung im zurück geschalteten RM ab?

Nunja, IMHO eher ein glitch denn ein echtes feature. Gelegentlich findet man die Sache als "Flat Real Mode", "Unreal Mode" oder auch "Voodoo Mode" bezeichnet und in alten, frickeligen DOS-Spielen oder Demos verwendet.
Hier gibt es etwas darueber zu lesen.

Erhard Henkes schrieb:

Begründe mir lieber mal jemand, warum IBM das Boot-Programm genau nach 7C00h gesendet hat. Die exakte Erklärung habe ich bisher noch nirgends gefunden.

Vermutung:
Historische Ursachen. Es war einfach das obere Ende des RAMs (32kb).

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908


Zuletzt bearbeitet von Nobuo T am 11:28:24 23.03.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 12:09:58 23.03.2009   Titel:              Zitieren

Hallo Nobuo T, danke für deine Antwort. Bei mir wurde DL nicht geschrottet (sind die BIOS-Interrupts nicht gleich realisiert?), der Sprung mit BX alleine klappte ebenfalls. OK, ich werde auf Dich hören und das nur als Kommentar angeben. Load_kernel1 wird gestrichen. Danke für die Links! Voodoo ... :D

So sieht der bootloader nun (endgültig) aus:
http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId80121

Ich bitte um Check des Kernels:
http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId412221
(@Nobuo T: Abfrage eines Keystroke vor Reboot bei 'exit' wurde bereits eingebaut. Danke für den Hinweis!)

Noch eine andere didaktische Frage: Die Bezeichnungen KB, MB etc. sind ja inzwischen nicht mehr eindeutig, vor allem bei MB, GB. Würdet ihr auf KiB, MiB, GiB etc. umsteigen? Die Akzeptanz dieses neuen Vorschlages ist ja noch gering.
http://de.wikipedia.org/wiki/Kibibyte#IEC-Pr.C3.A4fixe_zur_Basis_2

Als kleine Belohnung für die, die hier mitlesen:
http://bazonline.ch/digital/games/bildstrecke.html?id=18752&pageID=1&n=1
(sehr schöne nostalgische Fotostrecke zum Thema Computer und Werbung)
Foto 12/23: IBM PC ca. 1982
Foto 19/23: Bill Gates ca. 1980

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 14:37:29 23.03.2009, insgesamt 5-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 16:50:49 23.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Als kleine Belohnung für die, die hier mitlesen:
http://bazonline.ch/digital/games/bildstrecke.html?id=18752&pageID=1&n=1
(sehr schöne nostalgische Fotostrecke zum Thema Computer und Werbung)

hihi, uralt-computer passen schon irgendwie zu diesem thread.
hier gibts übrigens noch mehr davon: http://www.computerhistory.org/collections/marketingbrochures/
:)
Mr X
Mitglied

Benutzerprofil
Anmeldungsdatum: 18.09.2007
Beiträge: 1073
Beitrag Mr X Mitglied 18:06:48 23.03.2009   Titel:              Zitieren

Hallo,
Das Tutorial gefällt mir sehr gut :)

Als Alternative zu Bochs und VirtualPC kann ich noch VirtualBox empfehlen (kostenlos).
Funktionierte bei mir auf Anhieb. Um die Bootdiskette einzubinden muss diese nochnichtmal in ein Image verpackt sein...

mfg
Mr X
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:37:26 23.03.2009   Titel:              Zitieren

Mr X schrieb:
... Das Tutorial gefällt mir sehr gut :) ... Als Alternative zu Bochs und VirtualPC kann ich noch VirtualBox empfehlen (kostenlos). Funktionierte bei mir auf Anhieb. Um die Bootdiskette einzubinden muss diese noch nicht mal in ein Image verpackt sein ...

Danke für das positive Feedback :) und den Tipp mit VirtualBox. Das werde ich mir anschauen. Denn gerade diese Dinge sind didaktisch wichtig, denn jedes Emulations-Programm hat seine Schwächen und Stärken. Nur wenn Theorie, Praxis und Tools Hand in Hand gehen, macht die Sache Freude und treibt die Kreativität vorwärts.

Nun habe ich auch die gtd.inc beschrieben, ein echtes Bit-Gefrickel.
http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId398766
Bitte schaut mal drüber, ob ich keinen Fehler gemacht habe.

Jetzt fehlt noch die Erklärung des Kernel-Codes.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:49:50 23.03.2009   Titel:              Zitieren

@Nobuo T: An dem Punkt bin ich auch schon ins Grübeln gekommen, weil dies alles andere als intuitiv ist. Hier kam genau dazu eine Frage aus einem anderen internationalen Forum:
http://forum.osdev.org/viewtopic.php?f=1&t=19451&p=152668#p152668
Zitat:

One thing that caught my eye is this:

Code:
xor ax, ax
[...]
mov ss, ax
mov sp, ax
[...]
call print_string

You zero SS and SP and then you use the stack (implicitly by CALL). That looked strange first. It's not broken, but it is not very intuitive. Maybe you want to consider to note this in your text (I didn't see anything about that, maybe I just missed it) and explain why and how that works.

Vielleicht kannst Du da noch etwas zu Deiner Idee erläutern. Da klafft noch eine "didaktische Lücke". :D
Das Thema Stack würde ich gerne auch noch beschreiben (Prinzip, SS, SP, Nutzung durch call, ...). Ich war allerdings über deine Lösung so verblüfft, dass ich erst mal genauer hinschauen wollte.

Auch diese Zeile wirkt auf den ersten Blick merkwürdig.
add sp, -0x40 ; make room for input buffer (64 chars)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:33:49 23.03.2009, insgesamt 1-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 22:22:18 23.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Auch diese Zeile wirkt auf den ersten Blick merkwürdig.
add sp, -0x40 ; make room for input buffer (64 chars)

na, so machste platz auf'm stack. macht ein c-compiler z.b auch so ähnlich, wenn du ein lokales array aus 64 bytes anlegst.
:)
Mr X
Mitglied

Benutzerprofil
Anmeldungsdatum: 18.09.2007
Beiträge: 1073
Beitrag Mr X Mitglied 23:07:22 23.03.2009   Titel:              Zitieren

Zum Thema Emulatoren könntest Du doch ein eigenes Kapitel machen, indem kurz beschrieben wird, wie man damit das OS zum laufen kriegt und welche Vor-/Nachteile das Programm hat, anstatt gelegentlich zwischendurch weitere Emulatoren vorzustellen...
Piscu
Unregistrierter




Beitrag Piscu Unregistrierter 23:16:10 23.03.2009   Titel:              Zitieren

@fricky: SP dürfte aber zu dem zeitpunkt auf 0 sein, weshalb das subtrahieren von 40h (= addieren von -40h?) komisch ist.
Zumindestens kommt es mir komisch vor, wo liegt der (mein) denkfehler?
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:35:25 23.03.2009   Titel:              Zitieren

Zitat:
Zum Thema Emulatoren könntest Du doch ein eigenes Kapitel machen, indem kurz beschrieben wird, wie man damit das OS zum laufen kriegt und welche Vor-/Nachteile das Programm hat, anstatt gelegentlich zwischendurch weitere Emulatoren vorzustellen...
Ja, ist mir auch aufgefallen. Ursprünglich wollte ich nur Bochs verwenden, allerdings sind die Emulatoren so wichtig, dass man alle vorstellen sollte. Werde das konzentrieren. Allerdings erst hinten, denn vorne lenkt das doch stark ab. Nicht jeder arbeitet gerne gleichzeitg mit 10-15 Tools. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:39:42 23.03.2009   Titel:              Zitieren

Zitat:
na, so machste platz auf'm stack.
Das man den Stackpointer nach "unten" wandern lässt, um Platz zu schaffen, ist klar. Aber wie gesagt, ist der Wert vorher bei 0, wenn ich nicht irre. Also hinterher -40. Warten wir auf den Kommentar von Nobuo T. Das hat er genial "verbrochen". Vorher hatten wir den Stack bei 0x90000 (http://www.henkessoft.de/OS_Dev/Bilder/Speicherbelegung.JPG), wo viele ihn hin knallen. Unten bei 0 ist doch auch die IVT. Aber es läuft, das ist die Hauptsache, die theor. Erklärung kommt sicher noch. Vielleicht ein genialer "wrap" :D

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:50:03 23.03.2009, insgesamt 6-mal bearbeitet
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 23:39:59 23.03.2009   Titel:              Zitieren

Richtig, +fricky. Push macht Platz auf dem Stack, indem 2 (oder 4, oder wie gross der Operand auch immer ist) Byte von (e)sp subtrahiert werden und schreibt dann den Operand dann nach ss:(e)sp.
Hier wird halt nur Platz auf dem Stack reserviert, erstmal ohne was rein zu schreiben.

Zu ss und sp mit 0 initialisieren:
Ist vielleicht nicht sofort intuitiv, aber hier IMHO ziemlich praktisch.
Wie gesagt hat man es beim x86 mit einem full descending stack zu tun. Wenn also bei sp=0 etwas auf den Stack gepackt wird, gibt es beim Subtrahieren von sp erstmal einen schoenen Ueberlauf, bzw. wrap-arround: zB. 0 - 2 = 0xFFFE. Genau da landet dann der erste Wert.

Der Code sieht ansonsten beim ersten drueber schauen ganz gut aus. Aber meine msg00 haettest du eigentlich auch gleich ganz loeschen koennen, statt sie nur zu verschieben. War da nur zu debug-zwecken. Die Ausgabe habe ich wie es aussieht auch wieder entfernt, aber den Text vergessen. :D

Und zum Teil ueber die A20 zunaechst noch: Ueber die Ports 60h und 64h sprichst du erstmal nur mit dem Controller auf dem Mainboard. Darueber kannst du dann (seriell) etwas an die Tastatur schicken. Und D1 an 64h ist einfach ein Kommando, das bewirkt, dass das naechste Byte auf Port 60h beim outputport landet, statt bei der Tastatur.

edit: Hui, haette nicht gedacht, dass einfache Integer-Arithmetik (signed/unsigned Addition vs. Subtraktion und Ueberlaeufe) hier fuer solche Verwirrung sorgt. :confused:
Oder hat das damit zu tun, dass da der Stack involviert ist? Das spielt wie gesagt in dem Zusammenhang ueberhaupt keine Rolle.

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908


Zuletzt bearbeitet von Nobuo T am 23:44:38 23.03.2009, insgesamt 2-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 23:43:51 23.03.2009   Titel:              Zitieren

Habe mal die zip Datei 20090321_eh_os.zip runtergeladen, Makefile ein wenig angepasst (wegen meiner nasm Installation), das ganze mit meinen Werkzeugen gebaut und mit den binär Dateien in der zip-Datei verglichen. Alles gleich :)
Unter bochs ausprobiert - es läuft.
Nun wollte ich mal mit ndisasm ein wenig disassemblieren, hie und da mal schauen und schon gibt es ein kleines "Problem" mit kernel.bin. In der kernel.asm gibt es ja mal 16-Bit, mal 32-Bit Code, was mit [Bits 32] und [BITS 16] "umgeschaltet" wird. Nun, ndisasm kommt damit nicht klar oder ich kenne noch nicht die Möglichkeit, wie man es hinkriegt, dass alles zusammen sauber disassembliert wird... Wäre vielleicht ein Splittern der kernel.asm in zwei Dateien sinnvoll? Eine mit [BITS 16], die andere mit [BITS 32]?
Eine Sache bezüglich Disassemblieren noch: Am Ende des Bootloaders und des Kernels wird mit Nullen aufgefüllt (X ist 510 oder 1024):
Code:
times X-($-$$) db 0
Code:
times X-($-$$) db 0
Code:
times X-($-$$) db 0

Was würde gegen z.B. so was sprechen:
Code:
times X-($-$$) hlt
Code:
times X-($-$$) hlt
Code:
times X-($-$$) hlt

Also Auffüllen mit HLT-Befehlen... Ist nur ein Vorschlag, aber ich persönlich sehe ein Paar Vorteile:
- beim Disassemblieren sieht man sofort, wo das Ende ist (ok, mit Nullen sieht man es auch, aber man hat lauter add [bx+si],al stehen, was irgendwie unschön ist)
- zumindest psychologische Wirkung, man fühlt sich ruhiger, weil, wenn die CPU dort warum auch immer ankommt, bleibt sie dort stehen und es passiert nichts :)
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 00:03:36 24.03.2009   Titel:              Zitieren

abc.w schrieb:

Nun wollte ich mal mit ndisasm ein wenig disassemblieren, hie und da mal schauen und schon gibt es ein kleines "Problem" mit kernel.bin. In der kernel.asm gibt es ja mal 16-Bit, mal 32-Bit Code, was mit [Bits 32] und [BITS 16] "umgeschaltet" wird. Nun, ndisasm kommt damit nicht klar oder ich kenne noch nicht die Möglichkeit, wie man es hinkriegt, dass alles zusammen sauber disassembliert wird...

Ja, ist ein Problem. Die Situation hat man auch nicht all zu haeufig, dass man 16- und 32-Bit code in einem binary hat.
Ehrlich gesagt bin ich in die Verlegenheit auch noch nicht wirklich gekommen, bzw. hoechstens in einem Debugger - den kann man oft bei Bedarf umschalten.

abc.w schrieb:

Wäre vielleicht ein Splittern der kernel.asm in zwei Dateien sinnvoll? Eine mit [BITS 16], die andere mit [BITS 32]?

Problem beim Aufteilen waere, dass man entweder beim 2. Teil mit dem Start-Offet (org) aufpassen muesste, oder Verschnitt haette, wenn man es an eine groessere, festgelegte Adresse packt.
Da ist die uebersichtliche Disassemblierbarkeit mit einem einfachen disasm IMHO irgendwie nachrangig.

abc.w schrieb:

Eine Sache bezüglich Disassemblieren noch: Am Ende des Bootloaders und des Kernels wird mit Nullen aufgefüllt (X ist 510 oder 1024):
Code:
times X-($-$$) db 0
Code:
times X-($-$$) db 0
Code:
times X-($-$$) db 0

Was würde gegen z.B. so was sprechen:
Code:
times X-($-$$) hlt
Code:
times X-($-$$) hlt
Code:
times X-($-$$) hlt

Also Auffüllen mit HLT-Befehlen... Ist nur ein Vorschlag, aber ich persönlich sehe ein Paar Vorteile:
- beim Disassemblieren sieht man sofort, wo das Ende ist (ok, mit Nullen sieht man es auch, aber man hat lauter add [bx+si],al stehen, was irgendwie unschön ist)
- zumindest psychologische Wirkung, man fühlt sich ruhiger, weil, wenn die CPU dort warum auch immer ankommt, bleibt sie dort stehen und es passiert nichts :)

Naja, grundsaetzlich vielleicht nicht schlecht, was die Uebersicht beim Disassemblieren betrifft, hat aber ansonsten nicht viel Zweck. Ob der Rechner nun stehen bleibt bis zum naechsten IRQ oder gleich ein wenig dummes Zeug rechnet ist bei so einem gravierenden Problem dann wohl auch ein wenig egal. :p

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:10:46 24.03.2009   Titel:              Zitieren

Jungs, ihr seid richtig kreativ! Macht richtig Spaß mit euch. Der eine baut einen Wrap in den Stack, dass den Profis vom osdev.org der Verstand stehen bleibt und ein anderer schlägt "times X-($-$$) hlt" vor. :D

Das mit dem Stack auf 0 habe ich bisher noch nicht gesehen, finde es aber richtig gut. Ich habe es mir einfach als wrap vorgestellt, wie damals beim A20-Gate.

Ich habe mal "times X-($-$$) hlt" in Google eingegeben. Null Fundstellen!
Das ist doch echt ein Grund, dies zu verwenden. ;) Die massenweise F4 im Hex-Editor sehen richtig lustig aus: http://www.henkessoft.de/OS_Dev/Bilder/boot_bin_hex.JPG

@abc.w: die "hlt" sind schon im Tut eingebaut und hochgeladen. :live:

Die msg00 ist schon entfernt (ich hatte sie mal aufgehoben, weil ich dachte vielleicht bauen wir sie didaktisch noch ein, so mit keystroke und weiter ...). :D

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:28:32 24.03.2009, insgesamt 3-mal bearbeitet
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 00:22:38 24.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Jungs, ihr seid richtig kreativ! Macht richtig Spaß mit euch. Der eine baut einen Wrap in den Stack, dass den Profis vom osdev.org der Verstand stehen bleibt und ein anderer schlägt "times X-($-$$) hlt" vor. :D

Tja, in der Tat. :D So viel war hier schon laenger nicht mehr los. Ist AFAIR uebrigens inzwischen auch der laengste Thread in diesem Forum. :live:

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:55:45 24.03.2009   Titel:              Zitieren

Zitat:
Ich habe mal "times X-($-$$) hlt" in Google eingegeben. Null Fundstellen!
Das X muss man natürlich ersetzen:
"times 510-($-$$) db 0" 380 Fundstellen (auch nicht gerade viel, wir sind schon dabei)
"times 510-($-$$) hlt" 1 Fundstelle: http://kldp.org/node/89199 (leider sind wir nicht Erster! :rolleyes: )

"times 1024-($-$$) db 0" 20 Fundstellen
"times 1024-($-$$) hlt" 0 Fundstellen

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:00:21 24.03.2009   Titel:              Zitieren

Zitat:
Und zum Teil ueber die A20 zunaechst noch: Ueber die Ports 60h und 64h sprichst du erstmal nur mit dem Controller auf dem Mainboard. Darueber kannst du dann (seriell) etwas an die Tastatur schicken. Und D1 an 64h ist einfach ein Kommando, das bewirkt, dass das naechste Byte auf Port 60h beim outputport landet, statt bei der Tastatur.


Ich habe das nun hoffentlich klar genug dargestellt:
http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId13510

Hier würde ein Bild helfen. Muss mal nachdenken.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Unregistrierter





Beitrag Unregistrierter 01:19:17 24.03.2009   Titel:              Zitieren

Hier ein kleiner Hinweis zur Übersicht:
Assembler Code:
loop:

(...)

 jmp loop :confused:
Assembler Code:
loop:

(...)

jmp loop :confused:
Assembler Code:
loop:

(...)

 jmp loop :confused:
Es verwirrt beim Lesen wenn ein Labelname wie ein Opcode klingt. Es wäre vielleicht besser, Opcodenamen wie "Reservierte Worte" nicht als Bezeichner zu verwenden.

Noch was zum "Voodoo-Mode": :)
Drauf verlassen kann man sich ja, solange eben nichts und niemand die Segmentregister verändert. Das wäre z.B. der Fall, wenn man vorhat, ein RM-OS zu schreiben *wegduck* und dann das Format für ausführbare Programme selbst festlegt. Oder (viel einfacher) bei bootfähigen Programmen, die die Hardware testen, oder wirklich schnell mal eine Zahl ausrechnen sollen.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:21:27 24.03.2009   Titel:              Zitieren

Zitat:
Es verwirrt beim Lesen wenn ein Labelname wie ein Opcode klingt. Es wäre vielleicht besser, Opcodenamen wie "Reservierte Worte" nicht als Bezeichner zu verwenden.
Sehr guter Hinweis. Wird geändert.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Christoph
Moderator

Benutzerprofil
Anmeldungsdatum: 30.04.2001
Beiträge: 5710
Beitrag Christoph Moderator 01:24:57 24.03.2009   Titel:              Zitieren

@Erhard Henkes:
Die Screenshots auf deiner Webseite würde ich eher im PNG-Format abspeichern und nicht als JPEG. Das hätte folgende Vorteile gegenüber JPEG:
1) Keine unscharfen Kanten, Text bleibt daher gut lesbar.
2) Oft kleinere Dateigröße.

_________________
Wenn Word für Längeres geeignet wäre, würde es nicht Word, sondern Sentence, Page oder Article heißen.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 02:25:08 24.03.2009   Titel:              Zitieren

Zitat:
Die Screenshots auf deiner Webseite würde ich eher im PNG-Format abspeichern und nicht als JPEG
Danke für den Tipp :live:
EDIT: Ist deutlich performanter als JPG. Werde mich wohl umgewöhnen müssen. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:20:40 24.03.2009, insgesamt 1-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 03:27:52 24.03.2009   Titel:              Zitieren

Noch etwas zur Integer-Arithmetik (signed/unsigned Addition vs. Subtraktion).
Weitergeführt bis zum "Ende" würde die "RealMode" dann in etwa aussehen wie folgt:
Assembler Code:
RealMode:
 add sp, -0x40     ; space for input buffer (64 chars)
(...)
 add sp,  0x40     ; clean it, please
 ret
Assembler Code:
RealMode:
add sp, -0x40 ; space for input buffer (64 chars)
(...)
add sp, 0x40 ; clean it, please
ret
Assembler Code:
RealMode:
 add sp, -0x40     ; space for input buffer (64 chars)
(...)
 add sp,  0x40     ; clean it, please
 ret
Besser wäre da die "klassische" (und verständliche) Logik:
Assembler Code:
RealMode:
 sub sp,  0x40     ; space for input buffer (64 chars)
(...)
 add sp,  0x40     ; clean it, please
 ret
Assembler Code:
RealMode:
sub sp, 0x40 ; space for input buffer (64 chars)
(...)
add sp, 0x40 ; clean it, please
ret
Assembler Code:
RealMode:
 sub sp,  0x40     ; space for input buffer (64 chars)
(...)
 add sp,  0x40     ; clean it, please
 ret
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 14:49:19 24.03.2009   Titel:              Zitieren

Ob nun sub oder add ist in diesem Fall wohl reine Geschmackssache. Ich versuche sub wenn moeglich aus dem Weg zu gehen, da ich das uebersichtlicher finde (es gehen auch Mythen ueber einen Geschwindigkeitsvorteil um...).
Und wer nicht erkennt, dass
+(-40) == -(+40)
ist, hat noch andere Probleme als sich mit OS-Entwicklung zu befassen. :D
Was hat das mit "klassischer Logik" zu tun?

Was das "clean please" betrifft: Hast natuerlich prinzipiell recht. So wuerde/koennte man das sauber in einer Prozedur mit lokalen Variablen loesen. Evtl. koennte man einen entsprechenden Kommentar platzieren.
Der Code fuer den Prompt (was du wohl "RealMode" nennst?) ist allerdings keine klassische Prozedur und hat deshalb auch keinen Ausgang, bei dem das irgendwie sinnvoll unterzubringen waere. Anders ausgedrueckt: Wenn der Prompt verlassen und der angelegte Puffer damit nicht mehr gebraucht wird, also freigegeben werden koennte, wird jedes Mal der RM-Stack unmittelbar danach eh eingestampft.
Assembler ist in der Hinsicht nun mal einfach keine Sprache fuer Sauberkeitsfanatiker. :D

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 15:27:59 24.03.2009   Titel:              Zitieren

wann geht's denn nun endlich mit dem OS los?
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 16:08:12 24.03.2009   Titel:              Zitieren

Zitat:
wann geht's denn nun endlich mit dem OS los?

Zunächst habe ich die Code-Abschnitte erklärt, z.B. die "Zeigermechanik" bezüglich des Selektors auf die Deskriptoren-Tabelle. In vielen anderen Artikeln findet man
Code:
jmp 0x8:ProtectedMode
Code:
jmp 0x8:ProtectedMode
Code:
jmp 0x8:ProtectedMode
und
Code:
mov    ax, 0x10
    mov    ds, ax      ; data descriptor --> data, stack and extra segment
    mov    ss, ax            
    mov    es, ax
Code:
mov ax, 0x10
mov ds, ax ; data descriptor --> data, stack and extra segment
mov ss, ax
mov es, ax
Code:
mov    ax, 0x10
    mov    ds, ax      ; data descriptor --> data, stack and extra segment
    mov    ss, ax            
    mov    es, ax
, und niemand erklärt, woher die 0x8 oder 0x10 eigentlich kommen, fallen einfach vom Himmel. Die Berechnung habe ich mittels Abbildung zum Selektoraufbau und Linksshift mit dem wissenschaftlichen "Calculator" nun hoffentlich klar genug dargestellt.
http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId533818 please check ;)

Didaktisch bin ich noch nicht völlig zufrieden, da muss noch einiges klarer gezeichnet und umgestellt werden.
Von dieser Seite ( http://forum.osdev.org/viewtopic.php?f=1&t=19451 ) kommen auch noch einge Randbemerkungen.

Nun ist aber immerhin eine ansprechende Basis mit eingeschaltetem A20 Gate und Protected Mode entstanden, die sich allerdings noch völlig autistisch verhält. :D
Die nächsten Schritte werden dem Kernel die Innen- und Außenwelt systematisch öffnen. Ich denke hier gerade über das Was, Wie, Wann und ASM vs C und die Aufgliederung der Module nach. Auf jeden Fall möchte ich den didaktischen Aspekt ganz vorne sehen. Daher würde mich interessieren, wie Einsteiger ohne Erfahrungen in OS Development das Tutorial bisher einschätzen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 16:59:20 24.03.2009, insgesamt 4-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 17:08:37 24.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Die nächsten Schritte werden dem Kernel die Innen- und Außenwelt systematisch öffnen. Ich denke hier gerade über das Was, Wie, Wann und ASM vs C und die Aufgliederung der Module nach.

ok, als faustformel: alles was in C nicht so toll geht, machste in asm (z.b. umschaltung der tasks), alles andere in C. weil du ja x86 benutzt, sollteste dann auch auf die 'task state segmente' eingehen.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:22:16 24.03.2009   Titel:              Zitieren

@+fricky: Danke für Deine Ratschläge. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 21:39:49 24.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:
@+fricky: Danke für Deine Ratschläge.

keine ursache. es gibt übrigens auch kernels, die ganz ohne asm auskommen. such mal nach protothreads/contiki und das hier:
http://www.nilsenelektronikk.no/nenesos.html
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:32:31 24.03.2009   Titel:              Zitieren

Zitat:
Contiki is designed for microcontrollers with small amounts of memory. A typical Contiki configuration is 2 kilobytes of RAM and 40 kilobytes of ROM.
Ist mir schon klar, wo ich mich bei dem x86-Gerödel befinde. Das Programm oder OS wird dann eben ins EEPROM geflasht (mache ich beim Asuro oder Nibo auch: http://www.henkessoft.de/Roboter/Bilder/Nibo_mit_STK500_flashen_Ausschnitt_small.jpg ) anstelle von Floppy oder Hard Disk gebootet. Übrigens sehe ich ASM nicht als Nachteil für den bisherigen OS Start.

Mal eine andere Frage: Kennt sich jemand mit Qemu aus? Ich habe es bisher nicht geschafft, das OS damit zu booten. Lohnt es sich, sich damit herum zu quälen?

Zum Debuggen erscheint mir der Bochs Debugger momentan ideal.
@Nobuo T: Wie debuggst Du bei solchen Entwicklungen genau?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:08:16 24.03.2009, insgesamt 3-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 02:38:32 25.03.2009   Titel:              Zitieren

Im Abschnitt über die A20-Leitung ist mir folgendes aufgefallen:

Es fehlt der definitive Grund, warum sie unbedingt im PM aktiviert sein muß. Ich will es mal so formulieren: Im PM kann ich auf die paar Byte, die die A20-Leitung adressiert, auch gerne verzichten. Aber warum sollte ich das lieber nicht? :)
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 10:54:38 25.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zitat:
Contiki is designed for microcontrollers with small amounts of memory. A typical Contiki configuration is 2 kilobytes of RAM and 40 kilobytes of ROM.
Ist mir schon klar, wo ich mich bei dem x86-Gerödel befinde. Das Programm oder OS wird dann eben ins EEPROM geflasht (mache ich beim Asuro oder Nibo auch: http://www.henkessoft.de/Roboter/Bilder/Nibo_mit_STK500_flashen_Ausschnitt_small.jpg ) anstelle von Floppy oder Hard Disk gebootet.

naja, das waren ja nur beispiele, für nicht-preemptive kernels, die entweder continuations oder state machines für's task-switching benutzen. sowas muss nicht unbedingt ins flash, man kann's auch vom laufwerk booten.

Zitat:
Übrigens sehe ich ASM nicht als Nachteil für den bisherigen OS Start.

nachteil ist, je mehr asm du einsetzt, desto mehr nagelst du dein OS auf einen spezifischen prozessor fest. und wenn du so, wie bis jetzt, weiter machst, kannste dein tutorial bald in 'die geheimen tricks der x86-assembler gurus' umtaufen.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:58:37 25.03.2009   Titel:              Zitieren

Zitat:
Es fehlt der definitive Grund, warum sie unbedingt im PM aktiviert sein muß. Ich will es mal so formulieren: Im PM kann ich auf die paar Byte, die die A20-Leitung adressiert, auch gerne verzichten. Aber warum sollte ich das lieber nicht?


Im Protected Mode kann man problemlos mit 32 Bit arbeiten. Daher muss man das A20-Gate wieder aktivieren, da ansonsten bei bestimmten Speicherzugriffen Fehler auftreten, da die 21. Adressleitung deaktiviert ist. Das bedeutet, das man auf eine andere Speicherstelle zugreifen kann als beabsichtigt. Daher schaltet man A20 ein, bevor man den Kernel und weitere Programmteile startet. Ist das so o.k.?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:59:59 25.03.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:59:24 25.03.2009   Titel:              Zitieren

Zitat:
wenn du so, wie bis jetzt, weiter machst, kannste dein tutorial bald in 'die geheimen tricks der x86-assembler gurus' umtaufen.
Ja, da hast Du evtl. Recht.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Mr X
Mitglied

Benutzerprofil
Anmeldungsdatum: 18.09.2007
Beiträge: 1073
Beitrag Mr X Mitglied 22:49:21 25.03.2009   Titel:              Zitieren

@Erhard Henkes: Inwiefern nervt Sund VirtualBox eigentlich bei dir mit Werbung?
Bei mir erscheinen nur gelegentlich Tipps und Hinweise auf Updates, ich finde diese Passage zur Werbung daher etwas übertrieben...
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 00:01:45 26.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zitat:
wenn du so, wie bis jetzt, weiter machst, kannste dein tutorial bald in 'die geheimen tricks der x86-assembler gurus' umtaufen.
Ja, da hast Du evtl. Recht.

Ich denke, jeder verfolgt beim Programmieren seine eigene Philosophie. Und in Assembler ist es irgendwie so, je länger man sich damit beschäftigt, desto verschwommener wird die Grenze "tricks" und "normal".
Zum Beispiel einfache Zeile aus kernel.asm:
Code:
    xor cx, cx
Code:
xor cx, cx
Code:
    xor cx, cx

Warum nicht einfach:
Code:
    mov cx, 0
Code:
mov cx, 0
Code:
    mov cx, 0

Oder noch eine Zeile:
Code:
  or cl, cl     ; zero? (start of the string)
Code:
or cl, cl ; zero? (start of the string)
Code:
  or cl, cl     ; zero? (start of the string)

Warum nicht einfach:
Code:
    cmp cl, 0
Code:
cmp cl, 0
Code:
    cmp cl, 0

Und man braucht nicht einmal ein Kommentar dazu. Jeder, der es liest, sieht sofort: compare irgendwas mit Null.
Ich habe bei mir persönlich festgestellt, je "idiotensicherer" der Code geschrieben, desto weniger Kommentare und noch weniger Zeit beim Debuggen. Aber das ist wiederum meine "Philosophie".
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 01:39:24 26.03.2009   Titel:              Zitieren

IMHO, wer mit so einer Philosophie anfaengt (x86)Asm zu programmieren, kann irgendwo nicht wirkliche viel Ahnung von der Plattform haben, fuer die er da programmiert und ist daher wohl besser beraten, es bleiben zu lassen und auf eine abstrakte Hochsprache umzusteigen, in der derart "idiotensichererer Code" in der Performance nicht so kontraproduktiv, und auch allgemein viel effektiver uebersichtlicher zu gestalten ist.
So ist das doch einfach eine billige Ausrede fuer schlechten Code.

edit: Ack volkard. Auch ein guter Vergleich. :)

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908


Zuletzt bearbeitet von Nobuo T am 01:52:16 26.03.2009, insgesamt 2-mal bearbeitet
volkard
Moderator

Benutzerprofil
Anmeldungsdatum: 06.04.2000
Beiträge: 24349
Beitrag volkard Moderator 01:47:49 26.03.2009   Titel:              Zitieren

wer
Code:
xor cx, cx
Code:
xor cx, cx
Code:
xor cx, cx

verschmäht, weil es angeblich unleserlich wäre, und
Code:
mov cx, 0
Code:
mov cx, 0
Code:
mov cx, 0

vorzieht, der muß in der hochsprache auch
Code:
++c;
Code:
++c;
Code:
++c;

meiden und immer brav
Code:
c = c + 1;
Code:
c = c + 1;
Code:
c = c + 1;

schreiben.

_________________
http://www.venganza.info/
plonk fürs Forum v1.02
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 02:29:05 26.03.2009   Titel:              Zitieren

Zitat:
Bei mir erscheinen nur gelegentlich Tipps und Hinweise auf Updates, ich finde diese Passage zur Werbung daher etwas übertrieben...
Akzeptiert, werde dies abmildern. Möchte sachlich bleiben, hat mich aber schon ziemlich genervt.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 03:16:33 26.03.2009   Titel:              Zitieren

Wir haben einen noch etwas ausbaubaren Real Mode, auch im PM könnte man in Assembler noch etwas machen, aber ich denke, nun ist es an der Zeit, zu einem in C geschriebenen Kernel zu wechseln.

Als Compiler unter Windows verwende ich den allseits bekannten Compiler DJGPP (2.03 ohne C++). Ist dies das richtige Werkzeug? (Download bei Bona Fide OS Dev.) http://www.osdever.net/downloads/compilers/DJGPP-Installer-nocpp.exe

Dazu habe ich eine technische Frage:

Ich habe boot.bin (aufgefüllt auf 512 Byte mit Bootsignatur) und kernel.bin (aufgefüllt auf 1024 Byte).

Dann habe ich ein k(ernel)_entry.asm und ckernel.asm, das via k_entry.o und ckernel.o mittels linker ld zu ckernel.bin gelinkt wird.

Dann packe ich alles zu einer einzigen Binärdatei zusammen, die dann auf Floppy geschrieben wird: copy /b boot.bin + kernel.bin + ckernel.bin MyOS.bin

Der Bootloader lädt sich selbst nach 0x7C00 und den Rest nach 0x8000. Der gelinkte Part mit dem C-Kernel fängt durch die HLT-Auffüllung ab 0x8400 an.

so sieht k_entry.asm aus:
Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
[BITS 32]

[global start]
[extern _main] ; this is in the c file
hlt
hlt
hlt
start:
  call _main
  jmp $
Code:
1
2
3
4
5
6
7
8
9
10
[BITS 32]

[global start]
[extern _main] ; this is in the c file
hlt
hlt
hlt
start:
call _main
jmp $
Code:
1
2
3
4
5
6
7
8
9
10
[BITS 32]

[global start]
[extern _main] ; this is in the c file
hlt
hlt
hlt
start:
  call _main
  jmp $

Ich kann im bin-Format nicht [extern start] angeben und dann nach start springen: jmp 0x8:0x8000+start

Daher habe ich mir erst mal die drei HLT vor start gebaut, dann kann ich die Startadresse im Hexeditor hinter den "f4f4f4" leicht finden :D und direkt anspringen, z.B.: jmp 0x8:0x86e3; goto C-Kernel (0x8400 + 0x02e3 ist natürlich eine variable Zielscheibe).
Finde das didaktisch interessant, weil man hier zeigen kann, wie die Zusammenhänge im Speicher ganz genau sind und warum man eine Objektdatei benötigt, denn "start" kann man nur dort als externes Label verwenden.

Was ist hier eurer Meinung nach der sauberste Weg?
Benötigt man überhaupt noch eine Zwischen-Datei k(ernel)_entry.asm? (16/32-Bit-Problematik beim ersten Kernel? Außerdem haben wir im ersten Kernel "org 0x8000" verwendet, was wiederum nur im Binär-Format geht)

Gibt es irgendwie einen Trick (außer dem Spicken nach einer optischen Erkennungsmarke in der Binärdatei), dass man aus kernel.bin nach "start" springen kann, also wie gesagt "extern start" klappt nicht im Binär-Format.

Der Sprung von _main nach _main() {...} innerhalb der Objektdateien ist natürlich problemlos.

Wie überwindet man die Grenze bin -> obj mit einem Sprung am saubersten?

EDIT: Inzwischen über Linker und Linkerscript gelöst.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 14:42:29 28.03.2009, insgesamt 6-mal bearbeitet
rapso
Moderator

Benutzerprofil
Anmeldungsdatum: 17.06.2002
Beiträge: 7282
Beitrag rapso Moderator 08:09:46 26.03.2009   Titel:              Zitieren

abc.w schrieb:

Code:
    xor cx, cx
Code:
xor cx, cx
Code:
    xor cx, cx

Warum nicht einfach:
Code:
    mov cx, 0
Code:
mov cx, 0
Code:
    mov cx, 0

Oder noch eine Zeile:
Code:
  or cl, cl     ; zero? (start of the string)
Code:
or cl, cl ; zero? (start of the string)
Code:
  or cl, cl     ; zero? (start of the string)

Warum nicht einfach:
Code:
    cmp cl, 0
Code:
cmp cl, 0
Code:
    cmp cl, 0


das hat nichts mit philosophie zu tun, es generiert anderen code, der andere laufzeit und performance eigenschaften hat. das ist eben der unterschied zwischen cisc und risc.
wenn man diese nicht kennt, macht es nicht soviel sinn etwas in assembler zu schreiben, und das ist kein ding der sprache, sondern der hardware.

auf nem cell sieht du vielleicht
Code:
NOP
OR R1,R1,R1
OR R2,R2,R2
Code:
NOP
OR R1,R1,R1
OR R2,R2,R2
Code:
NOP
OR R1,R1,R1
OR R2,R2,R2

und wunderst dich, wieso nicht einfach immer NOP? Philosophie? vielleicht sogar im gcc?

(und nein, ist kein CISC, ich hab mir das ja auch nicht ausgedacht es so zu machen :P)

_________________
Kilo Byte=1000,Kilobyte=1024 ANSI/IEEE Standard 1084-1986
rapso
-Mod im Spiele-/Grafikprogrammierung| rapsoo@hotmail.com | #dionysos irc.quakenet.org | amazon stole my PS3 :(
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 09:30:55 26.03.2009   Titel:              Zitieren

abc.w schrieb:

Zum Beispiel einfache Zeile aus kernel.asm:
Code:
    xor cx, cx
Code:
xor cx, cx
Code:
    xor cx, cx

Warum nicht einfach:
Code:
    mov cx, 0
Code:
mov cx, 0
Code:
    mov cx, 0


weil der erste befehl keinen operanden braucht -> kürzer/schneller
das gehört zum guten ton der assemblerprogrammierung. meistens will man möglichst wenig und möglichst schnellen code haben. na gut, bei den heutigen giga-Hz und -byte x86ern ist sowas natürlich alles egal.
:)
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 21:17:21 26.03.2009   Titel:              Zitieren

volkard schrieb:
wer
Code:
xor cx, cx
Code:
xor cx, cx
Code:
xor cx, cx

verschmäht, weil es angeblich unleserlich wäre, und
Code:
mov cx, 0
Code:
mov cx, 0
Code:
mov cx, 0

vorzieht, der muß in der hochsprache auch
Code:
++c;
Code:
++c;
Code:
++c;

meiden und immer brav
Code:
c = c + 1;
Code:
c = c + 1;
Code:
c = c + 1;

schreiben.

volkard, vielleicht war es gestern spät bei Dir, oder, nach deiner Schlussvorlgerung zu urteilen, hast Du den Unterschied zwischen Assembler und Compiler nicht verstanden...
rapso schrieb:
auf nem cell sieht du vielleicht
Code:
NOP
OR R1,R1,R1
OR R2,R2,R2
Code:
NOP
OR R1,R1,R1
OR R2,R2,R2
Code:
NOP
OR R1,R1,R1
OR R2,R2,R2

und wunderst dich, wieso nicht einfach immer NOP? Philosophie? vielleicht sogar im gcc?
rapso, wahrscheinlich war es bei Dir auch spät gestern. Ich kenne mich mit ner Cell CPU natürlich nicht aus und finde diese drei Befehle, so wie sie da stehen, hm, ja, hübsch. Ich vermute aber, da es keinen Sinn macht, diese drei Befehle einfach so aus dem Kontext zu entreissen und ohne "Vorgeschichte" und "Nachgeschichte" einfach so zu posten, dass Du deren Bedeutung auch nicht verstanden hast...
Wie dem auch sei, interessant, wie es abgeht, wenn man anfängt, beim Assembler-Gefrickel mal auf den einen oder den anderen Umstand hinzuweisen. Und ich habe mich noch nicht in den ganzen Code eingelesen...
Trotzdem unverständlich, oder vielleicht übersehe ich irgendwas? Nehmen wir den Bootloader z.B., der Zugriff auf die Festplatte ist im ms-Bereich. Sagen wir mal 10 ms. Bei einer 1 GHz CPU entsprechen die 10 ms 10 Millionen Takte. Nehmen wir an, ein CPU Takt entspricht 1 Sekunde, 10 Millionen Takte sind also 10 Millionen Sekunden. Ergibt etwa 115 Tage... Ihr habt jetzt also mit xor ax, ax einen Takt gespart. Also eine Sekunde gespart, um dann 115 Tage zu warten... Kann mich bitte jemand aufklären?
volkard
Moderator

Benutzerprofil
Anmeldungsdatum: 06.04.2000
Beiträge: 24349
Beitrag volkard Moderator 21:45:38 26.03.2009   Titel:              Zitieren

abc.w schrieb:
volkard schrieb:
wer
Code:
xor cx, cx
Code:
xor cx, cx
Code:
xor cx, cx

verschmäht, weil es angeblich unleserlich wäre, und
Code:
mov cx, 0
Code:
mov cx, 0
Code:
mov cx, 0

vorzieht, der muß in der hochsprache auch
Code:
++c;
Code:
++c;
Code:
++c;

meiden und immer brav
Code:
c = c + 1;
Code:
c = c + 1;
Code:
c = c + 1;

schreiben.

volkard, vielleicht war es gestern spät bei Dir, oder, nach deiner Schlussvorlgerung zu urteilen, hast Du den Unterschied zwischen Assembler und Compiler nicht verstanden...

ach, da ist ein unterschied? bestimmt nur philosophischer natur.
zur sache:
xor reg,reg ist einfach ein festes idiom, das sich mit ein wenig übung sogar schneller liest, als mov reg,0
++var ist einfach ein festes idiom, das sich mit ein wenig übung sogar schneller liest, als var=var+1
diese parallele versuchte ich aufzuzeigen.

_________________
http://www.venganza.info/
plonk fürs Forum v1.02
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:22:47 26.03.2009   Titel:              Zitieren

Volkard hat im abstrakten Sinne Recht. Es kann nicht sein, dass man performant Assembler schreiben will und dann die Lesbarkeit in den Vordergrund rückt.

Bezüglich der Linker-Geschichte habe ich es jetzt auch endlich geschafft. Ich hatte die Reihenfolge hinter ld falsch angegeben. Konnte auch weiter vereinfachen. Nun ist alles zu meiner Zufriedenheit.

Jetzt gibt es nur noch: bootloader, (asm)kernel and ckernel.
asm- und C-kernel werden zusammen gelinkt. Wichtig ist, dass der asm-kernel binär vorne bei 0x8000 zu liegen kommt. Daher die Reihenfolge ld ... kernel.o ckernel.o Anders hängen die ganzen Strings vorne bei 0x8000 herum.

linker script:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
SECTIONS
{
  .text  0x8000 : {
    *(.text)
  }
  .data  : {
    *(.data)
  }
  .bss  :  {                
    *(.bss)
  }
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
SECTIONS
{
.text 0x8000 : {
*(.text)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
SECTIONS
{
  .text  0x8000 : {
    *(.text)
  }
  .data  : {
    *(.data)
  }
  .bss  :  {                
    *(.bss)
  }
}



makefile:
Code:
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
all:
   nasmw -O32 -f bin boot.asm -o boot.bin
   nasmw -O32 -f aout kernel.asm -o kernel.o
   gcc -c ckernel.c -o ckernel.o
   ld -T kernel.ld kernel.o ckernel.o
   rename a.out ckernel.bin
     
   cmd /c copy /b boot.bin + ckernel.bin MyOS.bin
   partcopy MyOS.bin 0 1000 -f0
Code:
1
2
3
4
5
6
7
8
9
all:
nasmw -O32 -f bin boot.asm -o boot.bin
nasmw -O32 -f aout kernel.asm -o kernel.o
gcc -c ckernel.c -o ckernel.o
ld -T kernel.ld kernel.o ckernel.o
rename a.out ckernel.bin

cmd /c copy /b boot.bin + ckernel.bin MyOS.bin
partcopy MyOS.bin 0 1000 -f0
Code:
1
2
3
4
5
6
7
8
9
all:
   nasmw -O32 -f bin boot.asm -o boot.bin
   nasmw -O32 -f aout kernel.asm -o kernel.o
   gcc -c ckernel.c -o ckernel.o
   ld -T kernel.ld kernel.o ckernel.o
   rename a.out ckernel.bin
     
   cmd /c copy /b boot.bin + ckernel.bin MyOS.bin
   partcopy MyOS.bin 0 1000 -f0

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:36:44 27.03.2009, insgesamt 1-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 22:52:52 26.03.2009   Titel:              Zitieren

abc.w schrieb:

Wie dem auch sei, interessant, wie es abgeht, wenn man anfängt, beim Assembler-Gefrickel mal auf den einen oder den anderen Umstand hinzuweisen.

das nennt man 'best practices' der asm-programmierung, keine umstände. genau so, wie der c++-frickler lieber ++x statt x++ verwendet, obwohl es in vielen fällen keinen unterschied macht.
:)
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 23:32:54 26.03.2009   Titel:              Zitieren

+fricky schrieb:

das nennt man 'best practices' der asm-programmierung, keine umstände. genau so, wie der c++-frickler lieber ++x statt x++ verwendet, obwohl es in vielen fällen keinen unterschied macht.
:)

Best practices... Lese grade das hier http://www.win.tue.nl/~aeb/linux/kbd/A20.html
Zitat:
...However, it failed to do this address truncation (a bug), and people found that there existed programs that actually depended on this truncation.

Bestimmt hat einer damals beim Programmieren der 8086er gedacht, wozu in meinem Programm explizit eine Abfrage einbauen, wenn die CPU von selbst eine "address truncation" macht und ich so Takte sparen und dabei perfomant auf die unteren Adressen zugreifen kann... Gängige Praxis, eine Funktion nutzen, die irgendwas vollkommen anderes macht, das eine oder andere Zwischenergebnis in einem ganz bestimmten Sonderfall erzeugt, an den man normalerweise nicht denkt, dessen Zwischenergebnis ich dann doch in meinem Programm benutze und mich darauf verlasse.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:40:41 27.03.2009   Titel:              Zitieren

Also langsam wird's mir unheimlich mit Assembler. :D
Ich habe den Sprung zum "rettenden" C-Kernel nun mit einer rudimentären Ausgabe realisiert:

http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId397878 (Text)
http://www.henkessoft.de/OS_Dev/Downloads/20090326_eh_os.zip (Dateien; gcc/ld voraus gesetzt)
Download DJGPP: http://www.osdever.net/downloads/compilers/DJGPP-Installer-nocpp.exe

Nun haben wir bootloader, real mode (asm), protected mode (asm) und C als bare bone Gerüst. In C fühle ich mich doch gleich wohler. ;) Erstmal vielen Dank, dass ihr mich bis hierher begleitet habt. Die weitere Entwicklung in C, die natürlich noch signifikant mit Assembler durchsetzt sein wird, passt eigentlich nicht in dieses Sub-Forum. :confused:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:59:20 27.03.2009, insgesamt 3-mal bearbeitet
Professionelle Meinung
Unregistrierter




Beitrag Professionelle Meinung Unregistrierter 01:59:09 27.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Die weitere Entwicklung in C, die natürlich noch signifikant mit Assembler durchsetzt sein wird, passt eigentlich nicht in dieses Sub-Forum. :confused:



Das wird dir niemand übel nehmen, dieser Thread ist das Beste seit langem. Weitermachen!
volkard
Moderator

Benutzerprofil
Anmeldungsdatum: 06.04.2000
Beiträge: 24349
Beitrag volkard Moderator 02:06:50 27.03.2009   Titel:              Zitieren

Professionelle Meinung schrieb:
Das wird dir niemand übel nehmen, dieser Thread ist das Beste seit langem. Weitermachen!

jup. muß ich auch mal sagen.
gut.

_________________
http://www.venganza.info/
plonk fürs Forum v1.02
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 09:25:41 27.03.2009   Titel:              Zitieren

volkard schrieb:
Professionelle Meinung schrieb:
Das wird dir niemand übel nehmen, dieser Thread ist das Beste seit langem. Weitermachen!

jup. muß ich auch mal sagen.
gut.

^^ich schliesse mich dem an, obwohl ich bisher nur am lästern war.
:)
rapso
Moderator

Benutzerprofil
Anmeldungsdatum: 17.06.2002
Beiträge: 7282
Beitrag rapso Moderator 10:33:31 27.03.2009   Titel:              Zitieren

abc.w schrieb:
rapso, wahrscheinlich war es bei Dir auch spät gestern.

waere es nicht einfacher und auch zielgenauer den fehler bei sich selbst statt bei allen anderen zu suchen?

Zitat:

Ich kenne mich mit ner Cell CPU natürlich nicht aus und finde diese drei Befehle, so wie sie da stehen, hm, ja, hübsch.
jap, genau das wollte ich damit verdeutlichen. du scheinst wenig ahnung zu haben und deswegen weichst du in philosophie aus, wie jemand der zum ersten mal in der schule von zahlen hoert und sich fragt, ob es nicht einfacher waere mit einem 8ter system, statt die daumen mit zu nutzen.

Zitat:

Ich vermute aber, da es keinen Sinn macht, diese drei Befehle einfach so aus dem Kontext zu entreissen und ohne "Vorgeschichte" und "Nachgeschichte" einfach so zu posten, dass Du deren Bedeutung auch nicht verstanden hast...

Es ist fast lustig dass du erst zugibst nicht zu wissen was diese befehle an sich haben, somit nichtmal weisst, dass jeder einzelne schon den ganzen kontext hat den man braucht um zu verstehen wozu sie dienen, aber vermutungen anstellst dass ich das nicht verstehe.

Zitat:
Wie dem auch sei, interessant, wie es abgeht, wenn man anfängt, beim Assembler-Gefrickel mal auf den einen oder den anderen Umstand hinzuweisen. Und ich habe mich noch nicht in den ganzen Code eingelesen...

klar, jemand der scheinbar nicht viel erfahrung hat wird natuerlich erstmal verwundert schauen was das alles soll und dass es nicht so laeuft wie es in seinem unerfahrenen und unbefangenen dasein als ideal gilt.
jemand mit ahnung, der ein mox eax,0 statt xor eax,eax sieht, wird sich dagegen wundern und feststellen, entweder
1. wurde das von nem anfaenger programmiert
2. es hat einen trifftigen grund nicht der normalen vorgehensweise zu folgen, wollte er flags nicht veraendern? wollte er ein spezielles code allignment? wollte er eine spezielle code groesse? ueberschreibt er den code spaeter mit was anderem und schreibt deswegen erstmal 0 rein?

es passiert also genau das gegenteil was du eigentlich bezwecken wolltest, statt es leserlicher zu machen, wirst du jedem erfahrenen programmierer einen stolperstein stellen.

_________________
Kilo Byte=1000,Kilobyte=1024 ANSI/IEEE Standard 1084-1986
rapso
-Mod im Spiele-/Grafikprogrammierung| rapsoo@hotmail.com | #dionysos irc.quakenet.org | amazon stole my PS3 :(
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:07:15 27.03.2009   Titel:              Zitieren

@ Professionelle Meinung, volkard, +fricky:
Danke für das positive Feedback. Das wird mich sicher beflügeln, das bisherige Mini-OS nun mit C weiter auszubauen und bei entscheidenden Punkten hier nachzufragen. :)

Didaktisch wird der Video-RAM erklärt:
http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId483279

und anschleißend die Funktionen des C-Kernels zerpflückt, damit herum gespielt und dann optimiert.
http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId958376

Mich würde auch eure Meinung zum kurzen Abschnitt "Gerätetreiber" interessieren:
http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId220571

Eine Design-Frage ist, was man "funktionell" in C-Module zusammen packt und welche Funktionen man in der Erstausbau-Stufe benötigt. Ich möchte nichts übertreiben, damit niemand den Überblick verliert, sonst kann ich meine Leser gleich zu Linux 0.01 schicken.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 00:03:02 28.03.2009   Titel:              Zitieren

@rapso: Wollte an dieser Stelle ein Paar Kommentare abgeben, ich denke, ich lasse es lieber sein. Wir haben unsere Meinungen gesagt und jeder kann sich über das Gesagte eigene Meinung bilden.

Ich versuche grade verzweifelt, mit meinen Werkzeugen mingw-gcc und dem Linker, der dabei ist, den Kernel zu kompilieren. Es geht leider nicht. Bekomme Fehlermeldung (habe --verbose beim Linker angegeben, damit die Ausgabe ausführlicher wird):
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
C:\BochsMyOS\20090326_eh_os>make
c:\nasm-2.06rc6\nasm.exe -O32 -f bin boot.asm -o boot.bin
c:\nasm-2.06rc6\nasm.exe -O32 -f aout kernel.asm -o kernel.o
gcc -c ckernel.c -o ckernel.o
ld -T kernel.ld kernel.o ckernel.o --verbose
GNU ld version 2.17.50 20060824
  Supported emulations:
   i386pe
using external linker script:
==================================================
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
SECTIONS
{
  .text  0x8000 : {
    *(.text)
  }
  .data  : {
    *(.data)
  }
  .bss  :  {
    *(.bss)
  }
}

==================================================
attempt to open kernel.o succeeded
opened script file kernel.o
kernel.o: file not recognized: File format not recognized
make: *** [all] Error 1
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
C:\BochsMyOS\20090326_eh_os>make
c:\nasm-2.06rc6\nasm.exe -O32 -f bin boot.asm -o boot.bin
c:\nasm-2.06rc6\nasm.exe -O32 -f aout kernel.asm -o kernel.o
gcc -c ckernel.c -o ckernel.o
ld -T kernel.ld kernel.o ckernel.o --verbose
GNU ld version 2.17.50 20060824
Supported emulations:
i386pe
using external linker script:
==================================================
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
SECTIONS
{
.text 0x8000 : {
*(.text)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
}

==================================================
attempt to open kernel.o succeeded
opened script file kernel.o
kernel.o: file not recognized: File format not recognized
make: *** [all] Error 1
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
C:\BochsMyOS\20090326_eh_os>make
c:\nasm-2.06rc6\nasm.exe -O32 -f bin boot.asm -o boot.bin
c:\nasm-2.06rc6\nasm.exe -O32 -f aout kernel.asm -o kernel.o
gcc -c ckernel.c -o ckernel.o
ld -T kernel.ld kernel.o ckernel.o --verbose
GNU ld version 2.17.50 20060824
  Supported emulations:
   i386pe
using external linker script:
==================================================
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
SECTIONS
{
  .text  0x8000 : {
    *(.text)
  }
  .data  : {
    *(.data)
  }
  .bss  :  {
    *(.bss)
  }
}

==================================================
attempt to open kernel.o succeeded
opened script file kernel.o
kernel.o: file not recognized: File format not recognized
make: *** [all] Error 1

Anscheinend kennt der mingw Linker den aout Format nicht. :(
Kennt jemand einen Workaround?
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:52:53 28.03.2009   Titel:              Zitieren

Zitat:
Anscheinend kennt der mingw Linker den aout Format nicht. :( Kennt jemand einen Workaround?
Guter Hinweis. Ich verwende gcc 3.1 (im DJGPP-Paket)
http://www.osdever.net/downloads/compilers/DJGPP-Installer-nocpp.exe , weil diese Version bei Bona Fide zum Download angeboten wird.

Ich wusste, dass mit C das Gewurschtel mit den Tools los geht, aber dafür ist das Programmieren jetzt deutlich einfacher.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:28:05 07.05.2009, insgesamt 4-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:54:19 28.03.2009   Titel:              Zitieren

Wie kann man den gcc umstellen auf Intel Syntax? War das -masm=intel beim gcc?

Wie heisst das dann korrekt in Intel Syntax? :D
C/C++ Code:
inline void outportb(unsigned int port,unsigned char value)
{
    asm volatile ("outb %%al,%%dx"::"d" (port), "a" (value));
};
C/C++ Code:
inline void outportb(unsigned int port,unsigned char value)
{
asm volatile ("outb %%al,%%dx"::"d" (port), "a" (value));
};
C/C++ Code:
inline void outportb(unsigned int port,unsigned char value)
{
    asm volatile ("outb %%al,%%dx"::"d" (port), "a" (value));
};

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:57:02 28.03.2009, insgesamt 1-mal bearbeitet
Bitsy
Mitglied

Benutzerprofil
Anmeldungsdatum: 01.05.2001
Beiträge: 499
Beitrag Bitsy Mitglied 06:41:43 28.03.2009   Titel:              Zitieren

Ich glaube so einfach geht das nicht.
Allerdings sollte der NASM mit aout zurechtkommen (fette Zeile).

Aus der DJGPP-FAQ:
Unter Punkt 17.1 werden einige Problembehandlungen aufgezeigt. Dann:

17.2 Converting between Intel ASM syntax and AT&T syntax

Q: Where can I find an automated conversion tool to convert my Intel-style assembly code into a code acceptable by Gas?
Q: Where can I find a converter from AT&T assembly to Intel style?
A: A SED script which should do most of the conversion was posted to the {DJGPP news group}.

A program called TA2AS which can convert TASM assembly source to AT&T style can be found {on the DJGPP server} and {on Oulu}. TA2AS was written by Frank van Dijk of the Spirit group; if you have questions about this tool, you may contact {Jan Oonk}. The authors say that the program is far from finished, but the sources are available with the package so you can fix whatever is broken for your needs.

Another similar converter is Intel2Gas, available from its {Web page}.

Beginning with Binutils 2.10, Gas has an option that causes it to accept the Intel syntax, so you can use Gas to assembly Intel-style code.

Alternatively, here is what you can do to make your code linkable with DJGPP programs:
* Get and install NASM, a portable x86 assembler which supports most of the Intel syntax and can generate DJGPP-compatible COFF object files (as well as lots of other formats, such as Microsoft 16-bit OBJ and Win32, a.out, and ELF). It also supports Pentium and Pentium Pro opcodes, and MMX. NASM is free for non-commercial use (see the docs for commercial use restrictions) and can be compiled with DJGPP. NASM can be found {on NASM Web site}, which has links to official download sites. The maintainers of NASM are {Jules} and {H. Peter Anvin}.

Be warned that NASM is not 100% identical to MASM or TASM. Even experienced assembly programmers might need some time to adapt to the slightly different flavor of NASM. If you want something much more similar to TASM, get JAS. JAS is available {from OULU}.

Also note that NASM, or at least some of its versions, doesn't produce debug info in the format understood by GDB, which makes debugging NASM-assemblied code tedious (you might not be able to display source lines and refer to local symbols by name). Latest versions of NASM might correct this deficiency.
* For a small number of relatively short files, consider converting them with a smart editor (like Emacs or its work-alikes).
* Obtain a copy of Microsoft MASM 6.11. It has a -coff option to generate object code in COFF format which can be submitted to GCC, so you can compile your original source. You can also use the LIB32 librarian from Microsoft C8 to convert object files to COFF by putting them into a .lib library, then extracting them as COFF files. {28} Note that, unless you link the MASM-generated object files with DJGPP's ld (as opposed to Microsoft's LINK /CO command), you won't be able to debug the resulting program, because the debug info is not in correct format. I'm also told that masm doesn't produce sections named ".text" and ".data", so you might need to hex-edit the section names in the object file manually.
* Use a disassembler to disassemble the object code, then convert it to the AT&T format either by hand or using TA2AS. One place to look for such a disassembler is {on SimTel.NET mirrors}.
Keep in mind that syntax is only one of the aspects of converting code written for DOS to DJGPP. You should also make sure your code doesn't violate any of the rules for protected-mode programming (see {GPF in asm code}).

If you need to perform the opposite conversion, from the AT&T style to the Intel style, try the Att2Intl converter written by {Gregory Velichansky}. Its output is intended for NASM or TASM. Att2Intl is available {from Greg's home page}.

Der komplette Punkt 18 der FAQ mit Informationen über low-level-programming könnte auch noch die eine oder andere wertvolle Information beinhalten.
Wenn da noch die eine oder andere Komponente vom DJGPP fehlt, ich hab da noch Unmengen von Resourcen rumliegen.


Zuletzt bearbeitet von Bitsy am 06:57:44 28.03.2009, insgesamt 4-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 12:10:28 28.03.2009   Titel:              Zitieren

-- verbose ist ein guter Hinweis. Bei mir sieht dies so aus, noch ein problem mit partcopy.exe, aber es läuft alles:

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
G:\OSDev\Test\13 C>make
nasmw -O32 -f bin boot.asm -o boot.bin
nasmw -O32 -f aout kernel.asm -o kernel.o
gcc -c ckernel.c -o ckernel.o
ld -T kernel.ld kernel.o ckernel.o --verbose
GNU ld version 2.13
  Supported emulations:
   i386go32
using external linker script:
==================================================
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
SECTIONS
{
  .text  0x8000 : {
    *(.text)
  }
  .data  : {
    *(.data)
  }
  .bss  :  {
    *(.bss)
  }
}

==================================================
attempt to open kernel.o succeeded
kernel.o
attempt to open ckernel.o succeeded
ckernel.o
rename a.out ckernel.bin
cmd /c copy /b boot.bin + ckernel.bin MyOS.bin
boot.bin
CKERNEL.BIN
        1 Datei(en) kopiert.
partcopy MyOS.bin 0 1000 -f0
Failed to read source at offset 800make.exe: *** [all] Error -1
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
G:\OSDev\Test\13 C>make
nasmw -O32 -f bin boot.asm -o boot.bin
nasmw -O32 -f aout kernel.asm -o kernel.o
gcc -c ckernel.c -o ckernel.o
ld -T kernel.ld kernel.o ckernel.o --verbose
GNU ld version 2.13
Supported emulations:
i386go32
using external linker script:
==================================================
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
SECTIONS
{
.text 0x8000 : {
*(.text)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
}

==================================================
attempt to open kernel.o succeeded
kernel.o
attempt to open ckernel.o succeeded
ckernel.o
rename a.out ckernel.bin
cmd /c copy /b boot.bin + ckernel.bin MyOS.bin
boot.bin
CKERNEL.BIN
1 Datei(en) kopiert.
partcopy MyOS.bin 0 1000 -f0
Failed to read source at offset 800make.exe: *** [all] Error -1
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
G:\OSDev\Test\13 C>make
nasmw -O32 -f bin boot.asm -o boot.bin
nasmw -O32 -f aout kernel.asm -o kernel.o
gcc -c ckernel.c -o ckernel.o
ld -T kernel.ld kernel.o ckernel.o --verbose
GNU ld version 2.13
  Supported emulations:
   i386go32
using external linker script:
==================================================
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
SECTIONS
{
  .text  0x8000 : {
    *(.text)
  }
  .data  : {
    *(.data)
  }
  .bss  :  {
    *(.bss)
  }
}

==================================================
attempt to open kernel.o succeeded
kernel.o
attempt to open ckernel.o succeeded
ckernel.o
rename a.out ckernel.bin
cmd /c copy /b boot.bin + ckernel.bin MyOS.bin
boot.bin
CKERNEL.BIN
        1 Datei(en) kopiert.
partcopy MyOS.bin 0 1000 -f0
Failed to read source at offset 800make.exe: *** [all] Error -1

Schwachstellen: letzte Zeile (jemand eine Idee?), und ich müsste ckernel.bin vorher löschen, damit a.out umbenannt werden kann. Gibt es da einen Parameter für rename, das auf jeden Fall zu machen, auch, wenn ckernel.bin existiert?

Für das Problem von abc.w habe ich momentan keine Lösung, ich war schon froh, dass ich selbst das Linken geschafft habe. Aber vielleicht schaffen wir es gemeinsam, eine möglichst allgemeingültige Lösung zu finden.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 12:12:22 28.03.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 12:14:19 28.03.2009   Titel:              Zitieren

bei abc.w: i386pe
bei mir: i386go32

Ich habe nochmal genau geschaut (also nicht Version (war wohl DJGPP) 2.03, sondern 3.1): GCC 3.1 C compiler binaries for DJGPP

Zitat:
ld --version
GNU ld version 2.13

gcc --version
gcc.exe (GCC) 3.1


Das att2intl Tool findet man übrigens hier:
http://www.bumba.net/~hmaon/a2i/ :)
@Bitsy: Danke für den Hinweis!

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 18:17:31 28.03.2009, insgesamt 4-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 14:02:17 28.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Mich würde auch eure Meinung zum kurzen Abschnitt "Gerätetreiber" interessieren:
http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId220571

Zitat:
In unserem OS müssen wir uns nun zumindest auf die rudimentärsten Operationen konzentrieren, nämlich Videoausgabe (monochrome/farbige Text/Grafik-Ausgabe), Dateneingabe über Tastatur und Daten lesen/schreiben von/auf formatierte(r) Floppy Disk. Maus, Drucker, Festplatte könnten später folgen, wenn notwendig.

ich würde schon mal versuchen, das ganze modular aufzubauen, so dass z.b. die text-ein/ausgabe, gerätesteuerung usw. über einheitliche schnittstellen gehen, also funktionen wie 'putchar()' und 'getchar()' umgeleitet werden können, indem man z.b. intern pointer auf strukturen umsetzen kann. dazu könntest du dir eine generische 'driver' struktur definieren, die bestandteil spezialisierter strukturen ist (objektorientierung also (nein, nicht c++ benutzen!!), so dass später leicht andere geräte eingehängt werden können). bewährt hat sich auch ein 'handle'-konzept, sowas wie stdin, stdout, file, raw, etc. der bastelfreudigkeit sind keine grenzen gesetzt.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 15:23:54 28.03.2009   Titel:              Zitieren

Ich habe mal dieses "halbfertige" Tool att2intl.exe eingesetzt:
man gibt z.B. asmcode.s (ATT) ein und erhält asmcode.asm.

Beispiel:
Code:
"outb %%al,%%dx"::"d" (port), "a" (value)
Code:
"outb %%al,%%dx"::"d" (port), "a" (value)
Code:
"outb %%al,%%dx"::"d" (port), "a" (value)
==>
Code:
"out BYTE ["a" +value], BYTE %dx":[:"d" +port], %al
Code:
"out BYTE ["a" +value], BYTE %dx":[:"d" +port], %al
Code:
"out BYTE ["a" +value], BYTE %dx":[:"d" +port], %al


allerdings funktioniert
C/C++ Code:
inline void outportb(unsigned int port,unsigned char value)
{
    asm volatile ("out BYTE ["a" +value], BYTE %dx":[:"d" +port], %al);
};
C/C++ Code:
inline void outportb(unsigned int port,unsigned char value)
{
asm volatile ("out BYTE ["a" +value], BYTE %dx":[:"d" +port], %al);
};
C/C++ Code:
inline void outportb(unsigned int port,unsigned char value)
{
    asm volatile ("out BYTE ["a" +value], BYTE %dx":[:"d" +port], %al);
};

mit gcc -c ckernel.c -o ckernel.o -masm=intel nicht.
Zitat:
ckernel.c: In function `outportb':
ckernel.c:39: parse error before "a"

Kann da jemand bitte etwas nachhelfen? Ansonsten bleibt es eben bei der AT&T-Sysntax.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 15:29:36 28.03.2009   Titel:              Zitieren

@abc.w: Konntest Du das Problem lösen? Möchte niemanden verlieren.
Zitat:
The other main snag concerns object-file formats. There are two variants of the 32-bit COFF format: one used by Microsoft Win32 tools, and one by the rest of the world. They are only subtly different, and linkers which expect one format will happily link the other. The difference comes in the relocations: if you write code in, say, NASM, and link it using the Microsoft linker along with some modules compiled using Visual C++, the addresses in the final output will come out wrongly. There’s no real workaround for this, but luckily most tools that work with the PE format will allow you to emit files in the Win32 format: NASM has its -f win32 option, and Cygwin has the pei-i386 output format.


Zitat:
For LD (the linker that is most often used with DJGPP and gcc) use the option --oformat binary.


EDIT: delete (gelöst): del (anstelle delete; einer meiner Uraltfehler) u. -o beim Linker

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:01:14 29.03.2009, insgesamt 3-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 15:31:30 28.03.2009   Titel:              Zitieren

@+fricky:
Zitat:
generische 'driver' struktur definieren, die bestandteil spezialisierter strukturen ist
hast du einen Link oder ein beispiel-OS vor Augen. würde mir das gerne mal an einem konkreten beispiel anschauen. thema passt momentan genau, bin da dran.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Swordfish
Mitglied

Benutzerprofil
Anmeldungsdatum: 27.03.2005
Beiträge: 2806
Beitrag Swordfish Mitglied 15:36:20 28.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Was nimmt man da bei Win XP? delete ging nicht. Oder kann man bei rename einen Parameter angeben, der bestehende files überschreibt.

Nimm copy /Y rename a.out ckernel.bin.

cheers, Swordfish

PS: toller Thread! :live:

_________________
Thou shall not fflush stdin!
Thou shall not cast void pointers! And therefore
Thou shall not cast the result of malloc!
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 16:23:04 28.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:
@+fricky:
Zitat:
generische 'driver' struktur definieren, die bestandteil spezialisierter strukturen ist
hast du einen Link oder ein beispiel-OS vor Augen. würde mir das gerne mal an einem konkreten beispiel anschauen. thema passt momentan genau, bin da dran.

was konkretes wüsste ich jetzt auch nicht. such mal im internet nach 'i/o model' oder so ähnlich. z.b. in der linux doku müsste sowas zu finden sein und in irgendwelchen büchern über betriebssysteme natürlich auch.
ach, vielleicht hilft das:
http://cespc1.kumoh.ac.kr/~juyoon/lecture/osd/2006/osd08.pdf
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 17:31:14 28.03.2009   Titel:              Zitieren

Zitat:
Nimm copy /Y rename a.out ckernel.bin.

Komischerweise wird das /Y im makefile nicht akzeptiert (unter MS-DOS sollte es gehen). Ich habe mich nun an die -o Option beim Linker erinnert. Die macht alles platt.

So geht es, zumindest bei mir mit gcc 3.1:

Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
all:
    nasmw -O32 -f bin boot.asm -o boot.bin            
    nasmw -O32 -f aout kernel.asm -o kernel.o          
    gcc -c ckernel.c -o ckernel.o                      
    ld -T kernel.ld kernel.o ckernel.o -o ckernel.bin  
    cmd /c copy /b boot.bin + ckernel.bin MyOS.bin    
    partcopy MyOS.bin 0 800 -f0
    del kernel.o
    del ckernel.o
    del ckernel.bin
    del boot.bin   
Code:
1
2
3
4
5
6
7
8
9
10
11
all:
nasmw -O32 -f bin boot.asm -o boot.bin
nasmw -O32 -f aout kernel.asm -o kernel.o
gcc -c ckernel.c -o ckernel.o
ld -T kernel.ld kernel.o ckernel.o -o ckernel.bin
cmd /c copy /b boot.bin + ckernel.bin MyOS.bin
partcopy MyOS.bin 0 800 -f0
del kernel.o
del ckernel.o
del ckernel.bin
del boot.bin
Code:
1
2
3
4
5
6
7
8
9
10
11
all:
    nasmw -O32 -f bin boot.asm -o boot.bin            
    nasmw -O32 -f aout kernel.asm -o kernel.o          
    gcc -c ckernel.c -o ckernel.o                      
    ld -T kernel.ld kernel.o ckernel.o -o ckernel.bin  
    cmd /c copy /b boot.bin + ckernel.bin MyOS.bin    
    partcopy MyOS.bin 0 800 -f0
    del kernel.o
    del ckernel.o
    del ckernel.bin
    del boot.bin   


Ich habe versucht, den Prozess auch grafisch (inzwischen mit video.c) darzustellen: http://www.henkessoft.de/OS_Dev/Bilder/make_process.PNG

Linker Script:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
SECTIONS
{
  .text  0x8000 : {
    *(.text)
  }
  .data  : {
    *(.data)
  }
  .bss  :  {                    
    *(.bss)
  }
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
SECTIONS
{
.text 0x8000 : {
*(.text)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
SECTIONS
{
  .text  0x8000 : {
    *(.text)
  }
  .data  : {
    *(.data)
  }
  .bss  :  {                    
    *(.bss)
  }
}


In einem anderen Thread hier habe ich brauchbare Mischung aus Hexeditor+Disassembler+Rechner gefunden:
http://members.inode.at/anton.zechner/az/Disassembler.htm
Echt interessantes Teil.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 21:59:58 28.03.2009, insgesamt 4-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:59:25 28.03.2009   Titel:              Zitieren

@+fricky: Danke für den Link. Hier ist auch eine interessante Architekturübersicht (kompakt): http://www.samueldotj.com/Ace/Architecture.asp

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 22:09:17 28.03.2009   Titel:              Zitieren

hier haste noch'n paar interessante slides zu dem thema
http://www.minix3.ru/docs/slides/Ch3.pdf
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:25:56 29.03.2009   Titel:              Zitieren

@+Fricky: danke für die Links, aber teilweise schon etwas weit in den Details, dafür aber wieder zu komplex und gleichzeitg theoretisch. Das verwirrt momentan mehr als es beim Design hilft.

Zur Zielsetzung ist eine abstrakte theoretische Diskussion auf der Meta-Ebene notwendig. Die Herausforderung besteht darin, dass es keine Übereinstimmung darin gibt, wie man ein OS optimal aufsetzt (cf. Tanenbaum, Modern Operating Systems, 2nd Ed., Chap. 12: Operating System Design). Das finde ich nach diesen vielen Jahren schon interessant.

Einige Dinge weiß man aber inzwischen:
Monolithische Kernel (Windows, Linux) sind erfolgreicher als Micro Kernels. Das hat aber lediglich Effizienzgründe und keine strukturelle Basis, kann uns also egal sein.
Präemptives Multitasking (Modernes Windows) ist aus Sicht eines Prozesses besser als kooperatives (klassisches Windows).

Tanenbaum sieht vor allem vier Aufgabenfelder eines OS:
1) Abstraktion schaffen (schwierigste Aufgabe)
2) Primitive Operationen bereit stellen
3) Isolation sicher stellen
4) Hardware Management

Files, Prozesse, Synchronisation, Speichermodelle, I/O System, System calls, Fehlerseparation durch voneinander unabhängige Systeme, ... da stehen wir ja praktisch nicht mehr am Anfang, aber ob wir bereits im Optimum sind, das ist noch offen. Die Kontrolle der Hardware ist eher eine Fleissaufgabe.

Ein OS ist ein gigantisches Software-Paket. Unix hat mehr als 1 Mio., Linux 2.6 ca. 5,7 Mio., Win 2000 ca. 29 Mio., Win XP ca. 35 Mio. und MS Vista ca. 50 Mio. Zeilen Sourcecode. So etwas kann also keinesfalls in der Zielgeraden liegen. Daher muss man sich von diesen Systemen als Zielbild lösen.

Das Entscheidende dabei ist, dass niemand in wenigen Monaten ein neues OS schreiben kann. Diese Illusion sollte man rasch aufgeben. Bei einem Hobby-/Lehr-Projekt geht es also vor allem darum - didaktisch möglichst klar dargestellt - ein Verständnis für die Zusammenhänge und Möglichkeiten auf der untersten Ebene zu schaffen.

Es macht m.E. mehr Sinn, zunächst in der Historie anzuknüpfen und von dort aus neue Wege zu suchen. Das Original MS-DOS 1.0 (1981) besteht z.B. aus rund 4.000 Zeilen Assembler-Code (nicht offen gelegt). Die grundlegenden Funktionen dieses Systems lassen sich leicht nachvollziehen und verstehen. Es gibt inzwischen freie Clones.

MS DOS hatte vier Bereiche und arbeitete nur im RM:
1) Bootcode
2) io.sys = Geräteroutinen (Monitor, Tastatur, Festplatte, Schnittstellen)
3) command.com = Befehlsinterpreter
4) Ausführung von Programmen (COM, EXE)

Befehle:

"intern":
del, erase - Dateien löschen
rd, rmdir - Verzeichnis löschen
dir - Verzeichnisinhalt anzeigen
cd, chdir - Verzeichnis wechseln
cls - löscht den Bildschirminhalt
md, mkdir - Verzeichnis erstellen
copy - Kopieren einer oder mehrerer Dateien
ren, rename - Umbenennen von Dateien oder Verzeichnissen
type - Anzeigen von Textdateien
set - zeigt DOS Umgebungsvariablen oder legt eine neue fest
ver - zeigt die DOS Versionsnummer
vol - zeigt die Datenträgerbezeichnung an

"extern":
attrib - Zeigt Attribute von Dateien oder legt diese fest
fdisk - Partitionierung der Festplatte erstellen oder verändern
move - Verschieben von Dateien
mem - Anzeigen der Belegung des Arbeitsspeicher
tree - Zeigt die Verzeichnisstruktur an
format - Formatieren eines Datenträger

EDIT: MS-DOS hatte auch einige Systemaufrufe wie den berühmten int 21h... (Anmerkung von abc.w)

http://www.operating-system.org/betriebssystem/bsgfx/microsoft/msdos_211-scr-.gif

Tanenbaum empfiehlt folgende drei Punkte für das Design:
Einfachheit, Vollständigkeit und Effizienz. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:52:07 29.03.2009, insgesamt 3-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 01:59:22 29.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Es macht m.E. mehr Sinn, zunächst in der Historie anzuknüpfen und von dort aus neue Wege zu suchen.
Meine Rede! :live: Man muß sich nur trennen von der Ansicht, daß im RM nur 1 MB RAM adressierbar sind. Dann müssten die Ideen eigentlich nur so hervorsprudeln. Vorausgesetzt natürlich, das Ziel ist nicht, DOS einfach nur zu kopieren.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 02:22:29 29.03.2009   Titel:              Zitieren

Zitat:
Man muß sich nur trennen von der Ansicht, daß im RM nur 1 MB RAM adressierbar sind.
Gibt es hierzu bereits ein stabiles Hobby-/Lehr-OS, das man sich mal anschauen könnte?

Ich denke nicht, dass der Protected Mode das zentrale Problem ist, eher was daraus gemacht wurde. Die Adressierung ist beherrschbar (eine Zeigerebene mehr und Paging, dafür hat man flat Speicher-Adr.). Multitasking mit allen Problemen muss ja z.B. nicht sein. Es geht doch eher darum, die enorme Leistung eines heutigen PC, die unter Windows (und inzwischen auch Linux) verschüttet wird, frei zu legen und Programmen bereit zu stellen.
Zitat:
perfection is reached not when there is no longer anything to add, but when there is no longer anything to take away.
Antoine de St. Exupéry.

Zitat:
Protected Mode has several advantages over Real Mode:
1. Protected Mode has Protection, the ability to keep programs from messing around and crashing each other(this is how Proctected Mode got its name).
2. You may only have several tasks (like Windows and Linux).
3. You have 4GB of address space (A20-Gate enabled).
4. You can use paging to access memory.
http://www.osdever.net/tutorials/gettingstarted.php

Wichtig ist nach Tanenbaum eine Abstraktionsidee, Beispiele:
alles ist ein Tape (Fortran)
alles ist ein File (Unix)
alles ist ein Objekt (W2K)
alles ist ein Dokument (www)

A.S.Tanenbaum ist ja immer einer der Verfechter des aus seiner Sicht "eleganten" Microkernel-Prinzips gewesen, das er im OS Minix umsetzte.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 11:30:42 29.03.2009, insgesamt 6-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 10:55:08 29.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:

MS DOS hatte vier Bereiche und arbeitete nur im RM:
...
Befehle:
...
"intern":
...
"extern":
...

Vorsicht... vorsicht... MS-DOS hatte auch einige Systemaufrufe wie den berühmten int 21h... ;)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:47:32 29.03.2009   Titel:              Zitieren

@abc.w: ja, das ist richtig. Hat das mit dem Compilieren/Linken nun geklappt, oder gibt es da noch ein Grundsatzproblem?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 12:01:29 29.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:
@abc.w: ja, das ist richtig. Hat das mit dem Compilieren/Linken nun geklappt, oder gibt es da noch ein Grundsatzproblem?

Das habe ich noch nicht hingekriegt...
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 12:20:13 29.03.2009   Titel:              Zitieren

@abc.w: Schade, dass wir nicht wissen, woran es exakt liegt. Probiere doch mal parallel den DJGPP: http://www.osdever.net/downloads/compilers/DJGPP-Installer-nocpp.exe

Vielleicht erkennst Du dann, woran es genau liegt. Wenn ich es richtig verstanden habe, macht der Linker Probleme.
http://www.henkessoft.de/OS_Dev/Bilder/make_process.PNG (gelb)

Ich hatte hier noch einiges zusammen getragen:
http://www.c-plusplus.de/forum/viewtopic-var-t-is- ....... ys-is-0-and-postorder-is-asc-and-start-is-130.html

NASM has its -f win32 option,
and Cygwin has the pei-i386 output format.

For LD use the option --oformat=binary.
http://lists.zerezo.com/mingw-users/msg00383.html

Keine Ahnung, ob das die richtige Spur ist.

Zur Erinnerung:
bei abc.w: i386pe
bei mir: i386go32

Vielleicht kann jemand anderes hier zielgenau helfen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 12:44:17 29.03.2009, insgesamt 4-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 12:52:23 29.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:
@+Fricky: danke für die Links, aber teilweise schon etwas weit in den Details, dafür aber wieder zu komplex und gleichzeitg theoretisch. Das verwirrt momentan mehr als es beim Design hilft.

schau es dir einfach in ruhe an und lass dich davon inspirieren. du musst ja kein OS strikt nach lehrbuchmeinung basteln (das wäre auch langweilig), aber z.b. in den tanenbaum-slides sind prinzipien erwähnt, von denen man als os-designer mal was gehört haben sollte. was du davon verwertest und was nicht, bleibt dir überlassen. ich würde zumindest leichte erweiterbarkeit und austauschbarkeit von komponenten von vorn herein einplanen. nicht dass du später mal alles umbauen musst, wenn ausgaben statt auf dem bildschirm, in einer datei landen sollen.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 13:45:57 29.03.2009   Titel:              Zitieren

Zitat:
ich würde zumindest leichte erweiterbarkeit und austauschbarkeit von komponenten von vorn herein einplanen. nicht dass du später mal alles umbauen musst, wenn ausgaben statt auf dem bildschirm, in einer datei landen sollen.
Das ist richtig. Abstraktion ist der entscheidende Punkt. Momentan schmökere ich gerade im Buch von Richard A. Burgess "Developing Your Own 32 Bit Computer Operating System" (MMURTL V1.0). Er hatte sich bei seinem Operating System folgende Ziele gesetzt:

- True Multitasking
- Real-time operation (react to outside events in real time ==> message based OS)
- Client/Server design (share services with multiple client applications)
- Common affordable hardware platform with minimal hardware requirements
- Flat 32-Bit Virtual Memory Model
- Easy programming (procedural interface into OS with no intermediate library)
- Protection from other programs - But not the programmer
- Use the CPU Instruction Set as Designed (heute zählt Portabilität mehr)
- Simplicity

==>
Zitat:
"MMURTL (pronounced like the girl’s name Myrtle) is a 32-bit, Message based, Multitasking, Real-Time, operating system designed around the Intel 80386 and 80486 processors on the PC Industry Standard Architecture (ISA) platforms. The name is an acronym for Message based MUltitasking, Real-Time, kerneL."


Folgende Punkte sehe ich bisher für mein "PrettyOS" (Deckname):
- Common affordable hardware platform (Standard PC ab 80386)
- Flat 32-Bit Virtual Memory Model (das bedeutet PM bei x86)
- Easy programming
- Simplicity (KISS Prinzip gilt in einer komplexen Welt immer mehr)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 16:01:08 29.03.2009, insgesamt 4-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 18:52:48 29.03.2009   Titel:              Zitieren

Habe mit mingw-Linker & Co ein wenig rumexperimentiert. Es funktioniert immer noch nicht und ich glaube nicht, dass es funktionieren wird...
Der mingw-Linker unterstützt folgende Formate:
Code:
C:\BochsMyOS\20090327_eh_os>ld --help
Usage: ld [options] file...
...
ld: supported targets: pe-i386 pei-i386 elf32-i386 elf32-little elf32-big srec symbolsrec tekhex binary ihex
ld: supported emulations: i386pe
...
Code:
C:\BochsMyOS\20090327_eh_os>ld --help
Usage: ld [options] file...
...
ld: supported targets: pe-i386 pei-i386 elf32-i386 elf32-little elf32-big srec symbolsrec tekhex binary ihex
ld: supported emulations: i386pe
...
Code:
C:\BochsMyOS\20090327_eh_os>ld --help
Usage: ld [options] file...
...
ld: supported targets: pe-i386 pei-i386 elf32-i386 elf32-little elf32-big srec symbolsrec tekhex binary ihex
ld: supported emulations: i386pe
...

Der nasm Assembler unterstützt folgende Formate:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
C:\BochsMyOS\20090327_eh_os>c:\nasm-2.06rc6\nasm -hf
...
valid output formats for -f are (`*' denotes default):
  * bin       flat-form binary files (e.g. DOS .COM, .SYS)
    aout      Linux a.out object files
    aoutb     NetBSD/FreeBSD a.out object files
    coff      COFF (i386) object files (e.g. DJGPP for DOS)
    elf32     ELF32 (i386) object files (e.g. Linux)
    elf       ELF (short name for ELF32)
    elf64     ELF64 (x86_64) object files (e.g. Linux)
    as86      Linux as86 (bin86 version 0.3) object files
    obj       MS-DOS 16-bit/32-bit OMF object files
    win32     Microsoft Win32 (i386) object files
    win64     Microsoft Win64 (x86-64) object files
    rdf       Relocatable Dynamic Object File Format v2.0
    ieee      IEEE-695 (LADsoft variant) object file format
    macho     NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X object files
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
C:\BochsMyOS\20090327_eh_os>c:\nasm-2.06rc6\nasm -hf
...
valid output formats for -f are (`*' denotes default):
* bin flat-form binary files (e.g. DOS .COM, .SYS)
aout Linux a.out object files
aoutb NetBSD/FreeBSD a.out object files
coff COFF (i386) object files (e.g. DJGPP for DOS)
elf32 ELF32 (i386) object files (e.g. Linux)
elf ELF (short name for ELF32)
elf64 ELF64 (x86_64) object files (e.g. Linux)
as86 Linux as86 (bin86 version 0.3) object files
obj MS-DOS 16-bit/32-bit OMF object files
win32 Microsoft Win32 (i386) object files
win64 Microsoft Win64 (x86-64) object files
rdf Relocatable Dynamic Object File Format v2.0
ieee IEEE-695 (LADsoft variant) object file format
macho NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X object files
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
C:\BochsMyOS\20090327_eh_os>c:\nasm-2.06rc6\nasm -hf
...
valid output formats for -f are (`*' denotes default):
  * bin       flat-form binary files (e.g. DOS .COM, .SYS)
    aout      Linux a.out object files
    aoutb     NetBSD/FreeBSD a.out object files
    coff      COFF (i386) object files (e.g. DJGPP for DOS)
    elf32     ELF32 (i386) object files (e.g. Linux)
    elf       ELF (short name for ELF32)
    elf64     ELF64 (x86_64) object files (e.g. Linux)
    as86      Linux as86 (bin86 version 0.3) object files
    obj       MS-DOS 16-bit/32-bit OMF object files
    win32     Microsoft Win32 (i386) object files
    win64     Microsoft Win64 (x86-64) object files
    rdf       Relocatable Dynamic Object File Format v2.0
    ieee      IEEE-695 (LADsoft variant) object file format
    macho     NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X object files

D.h. der nasm Assembler kann Objektdateien erzeugen, die der mingw-Linker nicht kennt. Ausserdem scheint es problematisch zu sein, dass die Datei kernel.asm 16-Bit und 32-Bit Code enthält. Wenn man mit nasm versucht, z.B. win32 Format zu generieren, bekommt man zahlreiche Fehlermeldungen:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
C:\nasm-2.06rc6\nasm -O32 -f win32 kernel.asm -o kernel.o
kernel.asm:21: error: COFF format does not support non-32-bit relocations
kernel.asm:27: error: COFF format does not support non-32-bit relocations
kernel.asm:35: error: COFF format does not support non-32-bit relocations
kernel.asm:40: error: COFF format does not support non-32-bit relocations
kernel.asm:45: error: COFF format does not support non-32-bit relocations
kernel.asm:50: error: COFF format does not support non-32-bit relocations
kernel.asm:55: error: COFF format does not support non-32-bit relocations
kernel.asm:59: error: COFF format does not support non-32-bit relocations
kernel.asm:64: error: COFF format does not support non-32-bit relocations
kernel.asm:69: error: COFF format does not support non-32-bit relocations
kernel.asm:74: error: COFF format does not support non-32-bit relocations
kernel.asm:82: error: COFF format does not support non-32-bit relocations
kernel.asm:88: error: COFF format does not support non-32-bit relocations
kernel.asm:117: error: COFF format does not support non-32-bit relocations
make: *** [all] Error 1
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
C:\nasm-2.06rc6\nasm -O32 -f win32 kernel.asm -o kernel.o
kernel.asm:21: error: COFF format does not support non-32-bit relocations
kernel.asm:27: error: COFF format does not support non-32-bit relocations
kernel.asm:35: error: COFF format does not support non-32-bit relocations
kernel.asm:40: error: COFF format does not support non-32-bit relocations
kernel.asm:45: error: COFF format does not support non-32-bit relocations
kernel.asm:50: error: COFF format does not support non-32-bit relocations
kernel.asm:55: error: COFF format does not support non-32-bit relocations
kernel.asm:59: error: COFF format does not support non-32-bit relocations
kernel.asm:64: error: COFF format does not support non-32-bit relocations
kernel.asm:69: error: COFF format does not support non-32-bit relocations
kernel.asm:74: error: COFF format does not support non-32-bit relocations
kernel.asm:82: error: COFF format does not support non-32-bit relocations
kernel.asm:88: error: COFF format does not support non-32-bit relocations
kernel.asm:117: error: COFF format does not support non-32-bit relocations
make: *** [all] Error 1
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
C:\nasm-2.06rc6\nasm -O32 -f win32 kernel.asm -o kernel.o
kernel.asm:21: error: COFF format does not support non-32-bit relocations
kernel.asm:27: error: COFF format does not support non-32-bit relocations
kernel.asm:35: error: COFF format does not support non-32-bit relocations
kernel.asm:40: error: COFF format does not support non-32-bit relocations
kernel.asm:45: error: COFF format does not support non-32-bit relocations
kernel.asm:50: error: COFF format does not support non-32-bit relocations
kernel.asm:55: error: COFF format does not support non-32-bit relocations
kernel.asm:59: error: COFF format does not support non-32-bit relocations
kernel.asm:64: error: COFF format does not support non-32-bit relocations
kernel.asm:69: error: COFF format does not support non-32-bit relocations
kernel.asm:74: error: COFF format does not support non-32-bit relocations
kernel.asm:82: error: COFF format does not support non-32-bit relocations
kernel.asm:88: error: COFF format does not support non-32-bit relocations
kernel.asm:117: error: COFF format does not support non-32-bit relocations
make: *** [all] Error 1

Was COFF mit win32 Format zu tun hat, weiss ich jetzt nicht...
Dann habe ich mit ELF Format ausprobiert (scheint der kleinste gemeinsame Nenner zu sein, mingw-Linker und nasm können es beide und man kann die ckernel.o mit objcopy nach ELF konvertieren). Es kommt ungefähr folgende Fehlermeldung:
Code:
C:\BochsMyOS\20090327_eh_os>ld -T kernel.ld kernel32.o ckernel_elf.o
ld: cannot perform PE operations on non PE output file 'a.exe'.
Code:
C:\BochsMyOS\20090327_eh_os>ld -T kernel.ld kernel32.o ckernel_elf.o
ld: cannot perform PE operations on non PE output file 'a.exe'.
Code:
C:\BochsMyOS\20090327_eh_os>ld -T kernel.ld kernel32.o ckernel_elf.o
ld: cannot perform PE operations on non PE output file 'a.exe'.

Mit kernel32.o habe ich versucht, 16-Bit Code von 32-Bit Code zu trennen und die Datei ckernel_elf.o ist die ckernel.o konvertiert nach ELF.
Wie es aussieht, es geht mit mingw Tools nicht. :( Oder ich mache irgendwas falsch.

Werde mir wohl den weisshaarigen DJGPP runterladen...
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:48:46 29.03.2009   Titel:              Zitieren

Zitat:
Werde mir wohl den weisshaarigen DJGPP runterladen...

DJGPP (gcc 3.1, ld 2.13):
ld.exe: supported targets: coff-go32 coff-go32-exe a.out-i386 srec symbolsrec tekhex binary ihex
ld.exe: supported emulations: i386go32

mingw (ld 2.17.50 20060824 )
ld: supported targets: pe-i386 pei-i386 elf32-i386 elf32-little elf32-big srec symbolsrec tekhex binary ihex
ld: supported emulations: i386pe

Hat da jemand die Lösung für den ASM-Kernel (16 u. 32 Bit) bezüglich Kopplung von NASM output file und Linker (ld 2.17) input file?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:18:54 29.03.2009, insgesamt 3-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 20:03:53 29.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Momentan schmökere ich gerade im Buch von Richard A. Burgess "Developing Your Own 32 Bit Computer Operating System" (MMURTL V1.0). Er hatte sich bei seinem Operating System folgende Ziele gesetzt:

ah, ich glaub' das hatte ich mal in den fingern. ist schon ziemlich alt und er hat sein OS komplett in asm programmiert, ne?

Erhard Henkes schrieb:

The name is an acronym for Message based MUltitasking, Real-Time, kerneL."

'message based' bedeutet, dass kein timer-gesteuerter scheduler drin ist, sondern context-switches werden durch versenden von messages herbeigeführt, oder? finde ich gut. präemptives, gewaltsames multitasking nach zeitscheiben ist manchmal gar nicht so toll.

Erhard Henkes schrieb:

Folgende Punkte sehe ich bisher für mein "PrettyOS" (Deckname):
- Flat 32-Bit Virtual Memory Model (das bedeutet PM bei x86)
- Easy programming
- Simplicity (KISS Prinzip gilt in einer komplexen Welt immer mehr)

ja, pretty-OS hört sich auch besser an, als der bisherige name.
flat memory model: was denn sonst? segment/offset-gedöns ist einfach nur übel.
easy programming: muss schon sein. keine übertriebenen schutzmechanismen, vertrau dem programmierer, denn er weiss, was er tut.
KISS: sehr vernünftig.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:23:26 29.03.2009   Titel:              Zitieren

PrettyOS nicht pretty-os oder pretty-OS :D

Zunächst müssen wir erstmal das NASM/Linker-Problem bei mingw (siehe post von abc.w) lösen, damit wir niemanden verlieren.

Multitasking/Singletasking? Da bin ich mir noch nicht sicher, ob Multitasking am Anfang nicht zuviel des Guten ist. Vorbereitet sind wir ja via PM. Mal sehen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 20:34:53 29.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Da bin ich mir noch nicht sicher, ob Multitasking am Anfang nicht zuviel des Guten ist. Vorbereitet sind wir ja via PM. Mal sehen.

multitasking oder nicht, hängt nicht davon ab, ob du den protected mode verwendest.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:14:46 29.03.2009   Titel:              Zitieren

Ja, das ist richtig. Als PC-Betriebssystem kenne ich bisher noch kein Multitasking OS im Real Address Mode (=Real Mode), muss irgendwie an mir vorbei gegangen sein. Kannst Du mir da mal auf die Sprünge helfen?

Prinzipiell ist task switching / context switching unabhängig von der Adressierungstechnik (direkt gekoppelt mit der physikalischen Adresse oder indirekt über Zeigertabellen). Auch Protected oder Unprotected hängt damit nicht zwingend zusammen.

Kannst Du mir Beispiele nennen für folgende Kombinationen:
Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
Real Address Mode (0)    Unprotected (0) Singletasking (0)  Example
Virtual Address Mode (1) Protected (1)   Multitasking  (1)  Operating System
---------------------------------------------------------------------------------------------
          0                  0                  0          MS-DOS
          0                  0                  1            ?
          0                  1                  0            ?
          0                  1                  1            ?
          1                  0                  0            ?
          1                  0                  1            ?  
          1                  1                  0            ?
          1                  1                  1          Linux, MS Windows NT, ...    
Code:
1
2
3
4
5
6
7
8
9
10
11
Real Address Mode (0) Unprotected (0) Singletasking (0) Example
Virtual Address Mode (1) Protected (1) Multitasking (1) Operating System
---------------------------------------------------------------------------------------------
0 0 0 MS-DOS
0 0 1 ?
0 1 0 ?
0 1 1 ?
1 0 0 ?
1 0 1 ?
1 1 0 ?
1 1 1 Linux, MS Windows NT, ...
Code:
1
2
3
4
5
6
7
8
9
10
11
Real Address Mode (0)    Unprotected (0) Singletasking (0)  Example
Virtual Address Mode (1) Protected (1)   Multitasking  (1)  Operating System
---------------------------------------------------------------------------------------------
          0                  0                  0          MS-DOS
          0                  0                  1            ?
          0                  1                  0            ?
          0                  1                  1            ?
          1                  0                  0            ?
          1                  0                  1            ?  
          1                  1                  0            ?
          1                  1                  1          Linux, MS Windows NT, ...    

Ist die Systematik so richtig? Alles wirklich unabhängig voneinander?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:58:25 29.03.2009, insgesamt 2-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 22:28:37 29.03.2009   Titel:              Zitieren

Habe mir DJGPP heruntergeladen und konnte 20090327_eh_os erfolgreich kompilieren, linken, zusammenkopieren. Ein ähnliches Problem wie mit copy wieder gehabt, diesmal mit rename:
Code:
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
C:\BochsMyOS\20090327_eh_os>make
C:\nasm-2.06rc6\nasm -O32 -f bin boot.asm -o boot.bin
C:\nasm-2.06rc6\nasm -O32 -f aout kernel.asm -o kernel.o
c:\djgpp\bin\gcc -c ckernel.c -o ckernel.o
c:\djgpp\bin\ld -T kernel.ld kernel.o ckernel.o
rename a.out ckernel.bin
process_begin: CreateProcess(NULL, rename a.out ckernel.bin, ...) failed.
make (e=2): Das System kann die angegebene Datei nicht finden.
make: *** [all] Error 2
Code:
1
2
3
4
5
6
7
8
9
C:\BochsMyOS\20090327_eh_os>make
C:\nasm-2.06rc6\nasm -O32 -f bin boot.asm -o boot.bin
C:\nasm-2.06rc6\nasm -O32 -f aout kernel.asm -o kernel.o
c:\djgpp\bin\gcc -c ckernel.c -o ckernel.o
c:\djgpp\bin\ld -T kernel.ld kernel.o ckernel.o
rename a.out ckernel.bin
process_begin: CreateProcess(NULL, rename a.out ckernel.bin, ...) failed.
make (e=2): Das System kann die angegebene Datei nicht finden.
make: *** [all] Error 2
Code:
1
2
3
4
5
6
7
8
9
C:\BochsMyOS\20090327_eh_os>make
C:\nasm-2.06rc6\nasm -O32 -f bin boot.asm -o boot.bin
C:\nasm-2.06rc6\nasm -O32 -f aout kernel.asm -o kernel.o
c:\djgpp\bin\gcc -c ckernel.c -o ckernel.o
c:\djgpp\bin\ld -T kernel.ld kernel.o ckernel.o
rename a.out ckernel.bin
process_begin: CreateProcess(NULL, rename a.out ckernel.bin, ...) failed.
make (e=2): Das System kann die angegebene Datei nicht finden.
make: *** [all] Error 2

Dann habe ich mein Makefile umgebaut:
Code:
all:
    ...
    cmd /c rename a.out ckernel.bin
    ...
Code:
all:
...
cmd /c rename a.out ckernel.bin
...
Code:
all:
    ...
    cmd /c rename a.out ckernel.bin
    ...

Und so funktioniert es bei mir wieder...
Eine Sache vielleicht noch: Die Funktion outportb() im C-Kernel ist ja als inline gekennzeichnet, "inlinen" tut der GCC anscheinend aber ab Optimierungsstufe -O1:
Code:
all:
    ...
    gcc -c ckernel.c -o ckernel.o -O1
    ...
Code:
all:
...
gcc -c ckernel.c -o ckernel.o -O1
...
Code:
all:
    ...
    gcc -c ckernel.c -o ckernel.o -O1
    ...

Man kann sich die Objektdatei ckernel.o mit objdump anschauen, einmal ohne Optimierungsstufe und einmal mit, z.B. so:
Code:
c:\djgpp\bin\objdump.exe -D ckernel.o
Code:
c:\djgpp\bin\objdump.exe -D ckernel.o
Code:
c:\djgpp\bin\objdump.exe -D ckernel.o


Wofür steht eigentlich -O32 beim Aufruf von nasm? -O steht für Optimierung, aber 32... finde grade nichts über Optimierungsstufe 32 in der nasm Doku...
Code:
C:\nasm-2.06rc6\nasm -O32 -f bin boot.asm -o boot.bin
Code:
C:\nasm-2.06rc6\nasm -O32 -f bin boot.asm -o boot.bin
Code:
C:\nasm-2.06rc6\nasm -O32 -f bin boot.asm -o boot.bin


Erhard Henkes schrieb:
Zunächst müssen wir erstmal das NASM/Linker-Problem bei mingw (siehe post von abc.w) lösen, damit wir niemanden verlieren.

Nur aus Neugier, wie viele Leute sind noch dabei ? :) Ich bin aus persönlichem Interesse dabei, weil ich u.a. vorhabe, hobbymässig einen echten 80386 auf einer Lochrasterplatine zum Laufen zu bekommen. Ein PC ist mir zu langweilig ;) Überlege gerade, wie ich die RAM Bausteine 8 Stück je 32 kByte anschliesse. Eins weiss ich inzwischen genau: Auf keinen Fall A20 Gate ;)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:43:26 29.03.2009   Titel:              Zitieren

Zitat:
Habe mir DJGPP heruntergeladen und konnte 20090327_eh_os erfolgreich kompilieren, linken, zusammenkopieren.
Super! Freut mich, dass es bei Dir nun auch klappt. Eigentlich ein Hammer, dass das alte Teil mehr kann als das neue ;) Allerdings hätte mich auch die wirkliche Lösung für den mingw interessiert, aber Hauptsache es geht. Kann man den alten ld vom DJGPP bei den Dateien vom neueren mingw einsetzen?

Zitat:
Ein ähnliches Problem wie mit copy wieder gehabt, diesmal mit rename

Das habe ich inzwischen über Bord geworfen, weil es das ckernel.bin nicht überschrieben hat, hätte man aber vorher mit del löschen können. So sieht es momentan aus (video.c ausgelagert), es wird einfach die Option -o ckernel.bin beim Linker ld angegeben:
http://www.henkessoft.de/OS_Dev/Bilder/make_process.PNG
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
all:
    nasmw -O32 -f bin boot.asm -o boot.bin            
    nasmw -O32 -f aout kernel.asm -o kernel.o        
    gcc -c ckernel.c -o ckernel.o                    
    gcc -c video.c -o video.o            
    ld -T kernel.ld kernel.o ckernel.o video.o -o ckernel.bin --verbose
    cmd /c copy /b boot.bin + ckernel.bin MyOS.bin    
    del video.o
    del kernel.o
    del ckernel.o
    del ckernel.bin
    del boot.bin  
    partcopy MyOS.bin 0 800 -f0
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
all:
nasmw -O32 -f bin boot.asm -o boot.bin
nasmw -O32 -f aout kernel.asm -o kernel.o
gcc -c ckernel.c -o ckernel.o
gcc -c video.c -o video.o
ld -T kernel.ld kernel.o ckernel.o video.o -o ckernel.bin --verbose
cmd /c copy /b boot.bin + ckernel.bin MyOS.bin
del video.o
del kernel.o
del ckernel.o
del ckernel.bin
del boot.bin
partcopy MyOS.bin 0 800 -f0
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
all:
    nasmw -O32 -f bin boot.asm -o boot.bin            
    nasmw -O32 -f aout kernel.asm -o kernel.o        
    gcc -c ckernel.c -o ckernel.o                    
    gcc -c video.c -o video.o            
    ld -T kernel.ld kernel.o ckernel.o video.o -o ckernel.bin --verbose
    cmd /c copy /b boot.bin + ckernel.bin MyOS.bin    
    del video.o
    del kernel.o
    del ckernel.o
    del ckernel.bin
    del boot.bin  
    partcopy MyOS.bin 0 800 -f0


Zitat:
Ich bin aus persönlichem Interesse dabei, weil ich u.a. vorhabe, hobbymässig einen echten 80386 auf einer Lochrasterplatine zum Laufen zu bekommen. Ein PC ist mir zu langweilig ;) Überlege gerade, wie ich die RAM Bausteine 8 Stück je 32 kByte anschliesse. Eins weiss ich inzwischen genau: Auf keinen Fall A20 Gate ;)
:live:
Falls Du das nicht selbst auf einer Homepage verarbeiten willst, sollten wir ein Kapitel über dein Projekt einbauen (natürlich mit Fotos deines Konstrukts, bitte denke an die VDE und Funkabschirmung :D ).


Gibt man "-O32" nasm (das habe ich von Nobuo T übernommen) bei Google ein, so kommen wir hier mit diesem Thread auf Platz eins heraus. :)

namsw -help liefert Folgendes:
Zitat:
-O<digit> optimize branch offsets (-O0 disables, default)


Danke für den Hinweis mit der Optimierungsstufe und den Tipp bezüglich objdump (man kann die Leser eines solchen OS-Tutorials bezüglich Tools gar nicht genug fit machen). ;) Das werde ich ins Tutorial einbauen.

Ohne Optimierung:

Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
000000be <_outportb>:
  be:    55                       push   %ebp
  bf:    89 e5                    mov    %esp,%ebp
  c1:    83 ec 04                 sub    $0x4,%esp
  c4:    8b 45 0c                 mov    0xc(%ebp),%eax
  c7:    88 45 ff                 mov    %al,0xffffffff(%ebp)
  ca:    8b 55 08                 mov    0x8(%ebp),%edx
  cd:    8a 45 ff                 mov    0xffffffff(%ebp),%al
  d0:    ee                       out    %al,(%dx)
  d1:    c9                       leave
  d2:    c3                       ret  
Code:
1
2
3
4
5
6
7
8
9
10
11
000000be <_outportb>:
be: 55 push %ebp
bf: 89 e5 mov %esp,%ebp
c1: 83 ec 04 sub $0x4,%esp
c4: 8b 45 0c mov 0xc(%ebp),%eax
c7: 88 45 ff mov %al,0xffffffff(%ebp)
ca: 8b 55 08 mov 0x8(%ebp),%edx
cd: 8a 45 ff mov 0xffffffff(%ebp),%al
d0: ee out %al,(%dx)
d1: c9 leave
d2: c3 ret
Code:
1
2
3
4
5
6
7
8
9
10
11
000000be <_outportb>:
  be:    55                       push   %ebp
  bf:    89 e5                    mov    %esp,%ebp
  c1:    83 ec 04                 sub    $0x4,%esp
  c4:    8b 45 0c                 mov    0xc(%ebp),%eax
  c7:    88 45 ff                 mov    %al,0xffffffff(%ebp)
  ca:    8b 55 08                 mov    0x8(%ebp),%edx
  cd:    8a 45 ff                 mov    0xffffffff(%ebp),%al
  d0:    ee                       out    %al,(%dx)
  d1:    c9                       leave
  d2:    c3                       ret  


Mit Optimierung -O1:

Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
000000ac <_outportb>:
  ac:    55                       push   %ebp
  ad:    89 e5                    mov    %esp,%ebp
  af:    8b 55 08                 mov    0x8(%ebp),%edx
  b2:    8a 45 0c                 mov    0xc(%ebp),%al
  b5:    ee                       out    %al,(%dx)
  b6:    5d                       pop    %ebp
  b7:    c3                       ret  
Code:
1
2
3
4
5
6
7
8
000000ac <_outportb>:
ac: 55 push %ebp
ad: 89 e5 mov %esp,%ebp
af: 8b 55 08 mov 0x8(%ebp),%edx
b2: 8a 45 0c mov 0xc(%ebp),%al
b5: ee out %al,(%dx)
b6: 5d pop %ebp
b7: c3 ret
Code:
1
2
3
4
5
6
7
8
000000ac <_outportb>:
  ac:    55                       push   %ebp
  ad:    89 e5                    mov    %esp,%ebp
  af:    8b 55 08                 mov    0x8(%ebp),%edx
  b2:    8a 45 0c                 mov    0xc(%ebp),%al
  b5:    ee                       out    %al,(%dx)
  b6:    5d                       pop    %ebp
  b7:    c3                       ret  

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:36:20 30.03.2009, insgesamt 11-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 04:09:48 30.03.2009   Titel:              Zitieren

Zur Zeit schlage ich mich in C mit dem Keyboard Driver herum. Nicht gerade einfach die ganze Thematik, auch didaktisch.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
jenz
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.06.2005
Beiträge: 227
Beitrag jenz Mitglied 09:31:55 30.03.2009   Titel:              Zitieren

Hallo Erhard,

finde ich sehr cool, wie du hier eine mini-OS bastelst, habe ich auch mal versucht und bin irgendwann bis zu einer minigrafischen Oberfäche gekommen.
Ich werde das noch mal rauskramen.

Ich finde, dass du, bevor du den Keyboardtreiber schreibst, dir ein geeignetes Konzept zur Interruptbehandlung zulegst und das auch schon mal Schablonenartig implementierst.

Ich finde diese Prolog/Epilog Konzept sehr gut. Mit entsprechenden Tricks und Hirnschmalz kann man es dann auch schaffen, dass die Interrupts _nie_ ausgestellt werden müssen.

http://www-ivs.cs.uni-magdeburg.de/bs/lehre/sose97/bs1/seminare/seminar8.shtml

Viel Erfolg noch.
Jens
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 09:40:25 30.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Als PC-Betriebssystem kenne ich bisher noch kein Multitasking OS im Real Address Mode (=Real Mode), muss irgendwie an mir vorbei gegangen sein. Kannst Du mir da mal auf die Sprünge helfen?

z.b. von cmx-rtx, embOS, freeRTOS, proc, usw, gibts auch versionen für x86-boards (das sind systeme für den embedded-bereich, machen alle timer-gesteuertes multitasking). die meisten davon laufen im real mode.
:)
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 09:45:52 30.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zur Zeit schlage ich mich in C mit dem Keyboard Driver herum. Nicht gerade einfach die ganze Thematik, auch didaktisch.

http://www.computer-engineering.org/ps2protocol/
http://maven.smith.edu/~thiebaut/ArtOfAssembly/CH20/CH20-1.html
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:04:27 30.03.2009   Titel:              Zitieren

Ein ganz anderer Punkt sind die mathematischen und sonstigen Routinen, die man ständig benötigt, und die aber nicht von einer library abhängig sein dürfen.
Beispiel: Will man eine char-, integer- oder float-Zahl auf dem Bildschirm ausgeben, so muss man zunächst diese in einen "string" umwandeln. Man benötigt also ein "frei schwebendes" k_itoa ohne Routinen aus string.h etc. Selbst im alten K&R wurde ich da nicht fündig, da verweist ständig eine Funktion auf die nächste, wie bei einem russischen Püppchen :D

So geht es aber, verwendet nur limits.h von gcc includes:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <limits.h>

void k_itoa(int n, char* s)
{
  int tenth, min_flag;
  char swap, *p;
  min_flag = 0;
  if (0 > n)
  {
    *s++ = '-';
    n = -INT_MAX > n ? min_flag = INT_MAX : -n;
  }
  p = s;
  do
  {
    tenth = n / 10;
    *p++ = (char)(n - 10 * tenth + '0');
    n = tenth;
  }
  while (n != 0);

  if (min_flag != 0)
  {
    ++*s;
  }
  *p-- = '\0';
  while (p > s)
  {
    swap = *s;
    *s++ = *p;
    *p-- = swap;
  }
}

void float2string(float value, int decimal, char* valuestring)
{
    int neg = 0;    char tempstr[20];
   int i = 0;   int j = 0;   int c;    long int val1, val2;
   char* tempstring;
   tempstring = valuestring;
   if (value < 0){   neg = 1; value = -value; }
     for (j=0; j < decimal; j++)   {value = value * 10;}
    val1 = (value * 2);
    val2 = (val1 / 2) + (val1 % 2);
    while (val2 !=0){
       if ((decimal > 0) && (i == decimal)){
          tempstr[i] = (char)(0x2E);
          i++;
       }
       else{
          c = (val2 % 10);
          tempstr[i] = (char) (c + 0x30);
          val2 = val2 / 10;
          i++;
       }
    }
    if (neg){
       *tempstring = '-';
       tempstring++;
    }
    i--;
    for (;i > -1;i--){
       *tempstring = tempstr[i];
       tempstring++;
    }
    *tempstring = '\0';
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <limits.h>

void k_itoa(int n, char* s)
{
int tenth, min_flag;
char swap, *p;
min_flag = 0;
if (0 > n)
{
*s++ = '-';
n = -INT_MAX > n ? min_flag = INT_MAX : -n;
}
p = s;
do
{
tenth = n / 10;
*p++ = (char)(n - 10 * tenth + '0');
n = tenth;
}
while (n != 0);

if (min_flag != 0)
{
++*s;
}
*p-- = '\0';
while (p > s)
{
swap = *s;
*s++ = *p;
*p-- = swap;
}
}

void float2string(float value, int decimal, char* valuestring)
{
int neg = 0; char tempstr[20];
int i = 0; int j = 0; int c; long int val1, val2;
char* tempstring;
tempstring = valuestring;
if (value < 0){ neg = 1; value = -value; }
for (j=0; j < decimal; j++) {value = value * 10;}
val1 = (value * 2);
val2 = (val1 / 2) + (val1 % 2);
while (val2 !=0){
if ((decimal > 0) && (i == decimal)){
tempstr[i] = (char)(0x2E);
i++;
}
else{
c = (val2 % 10);
tempstr[i] = (char) (c + 0x30);
val2 = val2 / 10;
i++;
}
}
if (neg){
*tempstring = '-';
tempstring++;
}
i--;
for (;i > -1;i--){
*tempstring = tempstr[i];
tempstring++;
}
*tempstring = '\0';
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <limits.h>

void k_itoa(int n, char* s)
{
  int tenth, min_flag;
  char swap, *p;
  min_flag = 0;
  if (0 > n)
  {
    *s++ = '-';
    n = -INT_MAX > n ? min_flag = INT_MAX : -n;
  }
  p = s;
  do
  {
    tenth = n / 10;
    *p++ = (char)(n - 10 * tenth + '0');
    n = tenth;
  }
  while (n != 0);

  if (min_flag != 0)
  {
    ++*s;
  }
  *p-- = '\0';
  while (p > s)
  {
    swap = *s;
    *s++ = *p;
    *p-- = swap;
  }
}

void float2string(float value, int decimal, char* valuestring)
{
    int neg = 0;    char tempstr[20];
   int i = 0;   int j = 0;   int c;    long int val1, val2;
   char* tempstring;
   tempstring = valuestring;
   if (value < 0){   neg = 1; value = -value; }
     for (j=0; j < decimal; j++)   {value = value * 10;}
    val1 = (value * 2);
    val2 = (val1 / 2) + (val1 % 2);
    while (val2 !=0){
       if ((decimal > 0) && (i == decimal)){
          tempstr[i] = (char)(0x2E);
          i++;
       }
       else{
          c = (val2 % 10);
          tempstr[i] = (char) (c + 0x30);
          val2 = val2 / 10;
          i++;
       }
    }
    if (neg){
       *tempstring = '-';
       tempstring++;
    }
    i--;
    for (;i > -1;i--){
       *tempstring = tempstr[i];
       tempstring++;
    }
    *tempstring = '\0';
}


oder Matheroutinen, z.B. Potenz:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
int power(int base,int n)
{
    int i,p;
    if (n == 0)
        return 1;
    p=1;
    for (i=1;i<=n;++i)
        p=p*base;
    return p;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
int power(int base,int n)
{
int i,p;
if (n == 0)
return 1;
p=1;
for (i=1;i<=n;++i)
p=p*base;
return p;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
int power(int base,int n)
{
    int i,p;
    if (n == 0)
        return 1;
    p=1;
    for (i=1;i<=n;++i)
        p=p*base;
    return p;
}

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 18:14:55 30.03.2009, insgesamt 3-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:32:57 30.03.2009   Titel:              Zitieren

Zitat:
Ich finde, dass du, bevor du den Keyboardtreiber schreibst, dir ein geeignetes Konzept zur Interruptbehandlung zulegst und das auch schon mal Schablonenartig implementierst.

Ich möchte es zunächst erstmal ohne Interrupts probieren, bin nicht sicher, ob das vernünftig geht, wird dann aber logischerweise der nächste Schritt.

Zitat:
Ich finde diese Prolog/Epilog Konzept sehr gut. Mit entsprechenden Tricks und Hirnschmalz kann man es dann auch schaffen, dass die Interrupts _nie_ ausgestellt werden müssen.

Danke an alle für die tollen Links. Das hilft mir sehr.

Momentan ist mein Hauptproblem, dass ich zwei Rechner benötige, weil ich nicht ständig Windows booten will, wenn das liebe PrettyOS selbst "aus Bochs heraus" meine Tastatur abgeschossen hat. :D

EDIT:
Problem gelöst, Keyboard-Treiber funktioniert, zur Zeit noch ohne Interrupts, wie ich es wollte.
OS fragt die Tastatur in einer Schleife ab, löscht den Bildschirm und druckt in Zeile 0 das ASCII-Zeichen und in Zeile 1 den ASCII-Code (dank k_itoa). Zur Zeichendarstellung benötigt man bereits zwei Keymaps (eine mit und eine ohne Shift-Taste, zur Zeit International US-Tastatur).
http://www.henkessoft.de/OS_Dev/Bilder/KeyboardDriver_funktioniert.PNG :live:
Gefällt mir didaktisch gut, vor allem noch alles in C außer den Funktionen outportb(...) und inportb(...).

Nun muss ich den Sourcecode noch didaktisch optimieren, sieht teilweise improvisiert ziemlich unordentlich aus, kann man so nicht uploaden. :rolleyes:

Module:

ckernel.c:
main()

video.c:
k_clear_screen()
k_printf(char* message, unsigned int line, char attribute)
void update_cursor(int row, int col)

util.c (wollte es nicht stdlib nennen):
void k_itoa(int value, char* valuestring)
void k_i2hex(unsigned int val, unsigned char* dest, int len)
void float2string(float value, int decimal, char* valuestring)

math.c:
int power(int base,int n)

keyboard.c:
...
...
k_getch()

Wohin gehören outportb, inportb?
Wie würdet ihr überhaupt die Module anordnen?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:30:17 30.03.2009, insgesamt 8-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 21:05:37 30.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zitat:
Ich bin aus persönlichem Interesse dabei, weil ich u.a. vorhabe, hobbymässig einen echten 80386 auf einer Lochrasterplatine zum Laufen zu bekommen. Ein PC ist mir zu langweilig ;) Überlege gerade, wie ich die RAM Bausteine 8 Stück je 32 kByte anschliesse. Eins weiss ich inzwischen genau: Auf keinen Fall A20 Gate ;)
:live:
Falls Du das nicht selbst auf einer Homepage verarbeiten willst, sollten wir ein Kapitel über dein Projekt einbauen (natürlich mit Fotos deines Konstrukts, bitte denke an die VDE und Funkabschirmung :D ).

Eine Homepage habe ich nicht... und hätte auch nichts gegen ein Kapitel mit ein Paar Fotos von meinem Board ;) Ein Kapitel, der heissen soll "So nicht" ;) Es ist nämlich so, dass ich inzwischen 20 ICs auf der Platine habe und wenn ich so überlege, noch ziemlich am Anfang stehe. Diese 20 ICs habe ich nicht draufgemacht, weil ich mir Gedanken gemacht habe, wie die Schaltung optimal oder am Besten wäre, sondern, ich hatte sie zufällig in meiner Bastelkiste... Meine Idee ist, vom PC aus ein binäres Programm auf die Platine "runterladen" und dieses Programm vom 80386 ausführen lassen. Die Kommunikation mit dem PC soll über eine UART gehen und die Steuerung soll ein ATmega644 übernehmen. Sprich, ein 8-Bit Mikrocontroller soll volle Kontrolle über eine 32-Bit CPU haben. Der ATmega soll den 80386 im Reset halten, wenn ein Programm über UART gesendet wird und, dieses Programm ins RAM schreiben. Danach soll der 80386 "freigelassen" werden :) Also nicht gerage sinnvoll das Ganze. Nicht, dass jemand denkt, boah, der baut einen PC nach... Ich habe noch nicht mal irgendwelche I/O Bausteine für den 386er. Mein Ziel ist also wirklich "nur" 386er soll ein Programm aus dem RAM ausführen und wenn die Spannung weg ist, dann ist auch das Programm weg. Das Programm könnte natürlich alles Mögliche sein, auch ein kleines OS... nur man müsste dann irgendeine Form von I/O dazubauen und Platz dafür wäre auf der Platine da.
Ich kann Dir gerne ein Paar Fotos von dem Board im jetzigen Stand zuschicken, die RAM Bausteine und der 386er sind aber noch nicht drauf...
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:21:31 30.03.2009   Titel:              Zitieren

Zitat:
man müsste dann irgendeine Form von I/O dazubauen

Irgendwie erinnert mich das an diese Robotik-/Elektronik-Boards mit ihren Interfaces nach außen, z.B. I2C-Bus. Vielleicht erhältst Du dort Anregungen.
http://www.roboternetz.de/wissen/index.php/RN-Control

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 21:55:58 30.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Irgendwie erinnert mich das an diese Robotik-/Elektronik-Boards mit ihren Interfaces nach außen, z.B. I2C-Bus. Vielleicht erhältst Du dort Anregungen. http://www.roboternetz.de/wissen/index.php/RN-Control

Dazu ist noch ein weiter Weg, zuerst muss RAM mit seinem 32-Bit Datenbus funktionieren. Die Funktion der 19 ICs besteht im Prinzip darinm, dass der 20. IC, der ATmega, wie ein Master mit 20-Bit Adressbus und 32-Bit Datenbus erscheint plus ein Paar Steuersignale... Die Funktion dieser 19 ICs muss ich noch überprüfen :)
PS: Ups, die UART realisiert mit MAX232 läuft bereits, also sind es nur noch 18 ICs... :)


Zuletzt bearbeitet von abc.w am 21:57:35 30.03.2009, insgesamt 1-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 22:08:41 30.03.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Ein ganz anderer Punkt sind die mathematischen und sonstigen Routinen, die man ständig benötigt, und die aber nicht von einer library abhängig sein dürfen.

such dir was aus: http://penguinppc.org/embedded/howto/library.html

abc.w schrieb:

Es ist nämlich so, dass ich inzwischen 20 ICs auf der Platine habe und wenn ich so überlege, noch ziemlich am Anfang stehe. Diese 20 ICs habe ich nicht draufgemacht, weil ich mir Gedanken gemacht habe, wie die Schaltung optimal oder am Besten wäre, sondern, ich hatte sie zufällig in meiner Bastelkiste...

das ist nicht dein ernst?!

abc.w schrieb:

Meine Idee ist, vom PC aus ein binäres Programm auf die Platine "runterladen" und dieses Programm vom 80386 ausführen lassen.

na, dann wäre vielleicht das hier was für dich: http://www.amd.com/epd/processors/4.32bitcont/14.lan5xxfam/24.lansc520/index.html
(x86-kompatibel und so)

aber wenn du mehr auf basteln stehst (was ich vermute, siehe oben), dann vielleicht doch eher sowas: http://www.mycpu.eu/
:)
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 22:42:20 30.03.2009   Titel:              Zitieren

+fricky schrieb:
abc.w schrieb:

Es ist nämlich so, dass ich inzwischen 20 ICs auf der Platine habe und wenn ich so überlege, noch ziemlich am Anfang stehe. Diese 20 ICs habe ich nicht draufgemacht, weil ich mir Gedanken gemacht habe, wie die Schaltung optimal oder am Besten wäre, sondern, ich hatte sie zufällig in meiner Bastelkiste...
das ist nicht dein ernst?!

Also, es ist nicht so kompliziert, 12 davon sind 74HC244, Tristate Treiber, ein ATmega, ein Paar Schieberegister, Zähler, 3zu8 Dekoder... Würde sagen, lauter Standard-Bausteine.
+fricky schrieb:
na, dann wäre vielleicht das hier was für dich: http://www.amd.com/epd/processors/4.32bitcont/14.lan5xxfam/24.lansc520/index.html
(x86-kompatibel und so)

Package Pin Count and Type 388 PBGA
das ist nicht dein ernst?! :) Nix für meinen "Schlitz"-Lötkolben. :)
+fricky schrieb:

aber wenn du mehr auf basteln stehst (was ich vermute, siehe oben), dann vielleicht doch eher sowas: http://www.mycpu.eu/
:)
Genau, ich stehe auf Basteln. MyCPU ist interessant, wenn man aber bereits mal mit FPGAs in Berührung gekommen ist und zufällig ein FPGA-Board besitzt, dann, nun ja, 8-Bit CPU, hm, hm... :)
Und wenn man zufällig ein Paar alte 80386 CPUs besitzt, wo man an die Pins auch noch mit nem "Schlitz"-Lötkolben drankommt, warum nicht irgendwas damit bauen. x86 Assembler-Programmierung kann man zwar am PC schön erlernen und vielleicht sogar irgendwie irgendwo anwenden, aber so richtiges Verständnis für die "Physik" fehlt einem irgendwo. Wie ist es mit dem Datenbus, mit dem Adressbus, wie sieht Adressbus aus, welche Steuersignale sind da, was bedeuten sie, was kann man damit machen usw. Eine selbstgebastelte funktioniernde Platine wäre für mich, dass ich u.a. auch diese "Physik"-Ebene verstanden habe...
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:09:13 30.03.2009   Titel:              Zitieren

Ich sehe es schon vor mir: Anleitung von abc.w und mir: "Do-it-yourself-PC&OS": Wir basteln uns unseren PC und anschließend coden wir unser OS. :D ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:36:32 30.03.2009   Titel:              Zitieren

Mit der Bitte um Feedback bezüglich Design:
HTML Code:
http://www.henkessoft.de/OS_Dev/Downloads/13 C.zip
HTML Code:
http://www.henkessoft.de/OS_Dev/Downloads/13 C.zip
HTML Code:
http://www.henkessoft.de/OS_Dev/Downloads/13 C.zip

(enthält eine Testvariante mit funktionierendem keyboard driver in C, noch nicht im Tutorial veröffentlicht)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:37:51 30.03.2009, insgesamt 2-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 09:17:28 31.03.2009   Titel:              Zitieren

abc.w schrieb:

Package Pin Count and Type 388 PBGA
das ist nicht dein ernst?! :) Nix für meinen "Schlitz"-Lötkolben. :)

ach, du hast doch bestimmt irgendwo 'nen backofen rumstehen.

abc.w schrieb:

Genau, ich stehe auf Basteln. MyCPU ist interessant, wenn man aber bereits mal mit FPGAs in Berührung gekommen ist und zufällig ein FPGA-Board besitzt, dann, nun ja, 8-Bit CPU, hm, hm... :)
Und wenn man zufällig ein Paar alte 80386 CPUs besitzt, wo man an die Pins auch noch mit nem "Schlitz"-Lötkolben drankommt, warum nicht irgendwas damit bauen.

datenbusbreite ist doch nicht wichtig. 8-bitter können auch schnell sein. wenn du sowieso mit FPGA's rumfummelst, musste dir auch keine schaltung aus alten schrott-ICs basteln. mach dir 'nen x86-core und etwas peripherie in deinen FPGA rein, und fertig.
:)
u_ser-l
Unregistrierter




Beitrag u_ser-l Unregistrierter 12:30:08 31.03.2009   Titel:   re            Zitieren

was ist eigentlich aus f-cpu geworden ?
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 23:17:51 31.03.2009   Titel:              Zitieren

Hab die 13 C.zip bei mir mal ausprobiert und hatte schon wieder diese komische Fehlermeldung von mingw make (möchte aus welchen Gründen auch immer MinGW Tools verwenden :), habe auch noch die Verzeichnisse in PATH für nasm und DJGPP gar nicht angepasst und benutze im Makefile absolute Pfadangaben):
Code:
del kernel.o
process_begin: CreateProcess(NULL, del kernel.o, ...) failed.
make (e=2): Das System kann die angegebene Datei nicht finden.
make: *** [all] Error 2
Code:
del kernel.o
process_begin: CreateProcess(NULL, del kernel.o, ...) failed.
make (e=2): Das System kann die angegebene Datei nicht finden.
make: *** [all] Error 2
Code:
del kernel.o
process_begin: CreateProcess(NULL, del kernel.o, ...) failed.
make (e=2): Das System kann die angegebene Datei nicht finden.
make: *** [all] Error 2

Dann im makefile die Aufrufe von del wie den Aufruf von copy geändert:
Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
    cmd /c del kernel.o
   
    cmd /c del ckernel.o
    cmd /c del video.o
    cmd /c del keyboard.o
    cmd /c del math.o
    cmd /c del util.o
   
    cmd /c del ckernel.bin
    cmd /c del boot.bin  
Code:
1
2
3
4
5
6
7
8
9
10
cmd /c del kernel.o

cmd /c del ckernel.o
cmd /c del video.o
cmd /c del keyboard.o
cmd /c del math.o
cmd /c del util.o

cmd /c del ckernel.bin
cmd /c del boot.bin
Code:
1
2
3
4
5
6
7
8
9
10
    cmd /c del kernel.o
   
    cmd /c del ckernel.o
    cmd /c del video.o
    cmd /c del keyboard.o
    cmd /c del math.o
    cmd /c del util.o
   
    cmd /c del ckernel.bin
    cmd /c del boot.bin  
Und es funktioniert auch mit dem mingw make...
Mit der make.exe, die in der zip-Datei mit dabei ist, funktioniert es auch ohne zusätzliches "cmd /c ". Ich sehe grade, dass die make.exe aus der zip-Datei die gleiche ist wie die c:\djgpp\bin\make.exe.
Hm, mingw scheint irgendwie eigenwilliger als DJGPP zu sein. Kleine Inkompatibilitäten und so was...
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 23:39:09 31.03.2009   Titel:              Zitieren

+fricky schrieb:
datenbusbreite ist doch nicht wichtig. 8-bitter können auch schnell sein. wenn du sowieso mit FPGA's rumfummelst, musste dir auch keine schaltung aus alten schrott-ICs basteln. mach dir 'nen x86-core und etwas peripherie in deinen FPGA rein, und fertig.

Bezüglich x86 Core habe ich mir mal echt darüber Gedanken gemacht, einen in VHDL zu implementieren. Die "Komplexität" hat mich abgeschreckt, Real Mode, Protected Mode, elf Adressierungsarten, Anzahl der Befehle, Codierung der Befehle wie irgendwelche Präfixe, die mal auf die Berechnung der Adresse, mal auf die Operandenbitbreite Auswirkung haben usw... Ich habe auch mal darüber nachgedacht, eine Art Untermenge von 386 zu "implementieren", einen Core, der bereits im Protected Mode ist, nur wenige Befehle kann usw. Und dann ist noch die Sache bezüglich "lad mal nen Core", man muss ja noch das Programm irgendwie mitladen, wenn denn auf dem FPGA Platz dafür ist...
Gibt es irgendwo einen freien x86 IP ab 80386, am Besten in VHDL?
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:32:01 01.04.2009   Titel:              Zitieren

@abc.w: danke für deine Tests mit mingw. Geht denn jetzt auch das Linken? Wie hast Du das geschafft?

Den Code zum Keyboard Driver habe ich hoffentlich noch etwas klarer gemacht. Vielleicht schaffe ich noch eine vereinfachte Variante mit nur einer Keymap und ohne Shift-Abfrage. Muss mir mal andere keymaps anschauen, ob diese einem allgemeinen Standard folgen, denn wir wollen ja auch unsere deutsche Tastatur durch einfaches Übernehmen anderer keymaps nutzen.

Kapitel zum Keyboard Driver im Tutorial:
http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId185043
(dort ist auch der Sourcecode zum Download bereit)

Ich hoffe, dass man es noch versteht, was ich da von mir gebe.
Die Grundideen sind ziemlich einfach:
Man holt den Scancode von Port 0x60, analysiert Bit7 (key pressed or released?),
filtriert (=unterdrückt) den Shift-Tasten Scancode, speichert das Ergebnis in einer Variable ShiftKeyDown
und gibt dann den Scancode der nachfolgenden Taste zurück.
Damit steigt man dann in die richtige Keymap (Shift oder Non-Shift) und gibt mittels k_getch() das zum Scancode passende Zeichen zurück.
Das ganze geht sicher auch einfacher, aber ich möchte die Bildung des Scancodes aus Pressed/Released-Bit und 7-Bit-Tasten-Nummerierung klar machen. Da fehlt noch ein Bild.

Dieser kleine ohne Schnörkel daher kommende Text im Internet hat mir am besten geholfen, das Thema Scancode zu verstehen: :)
http://www.qzx.com/pc-gpe/keyboard.txt

Das nächste logische Thema wären dann wohl Interrupts, was denkt ihr? :confused:

@abc.w:
Zitat:
Ich habe mich auch mal mit einem eigenen OS in Assembler beschäftigt zwecks endlich mal den Protected Mode der Intel CPUs zu verstehen. Habe aber diesbezüglich versagt und daraus wurde nichts. Hm, vertane Lebenszeit... hätte lieber in was anderes und sinnvolleres investieren sollen.
Ich hoffe, Du bist dem Protected Mode schon etwas näher gekommen. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 21:56:44 01.04.2009, insgesamt 8-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 09:15:10 01.04.2009   Titel:              Zitieren

abc.w schrieb:

Gibt es irgendwo einen freien x86 IP ab 80386, am Besten in VHDL?

http://www.opencores.org/?do=project&who=zet86
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:14:44 01.04.2009   Titel:              Zitieren

Beim Recherchieren habe ich eine ausführliche neue Tutorial-Serie (bisher 19 Teile) gefunden, didaktisch allerdings nicht geschickt gemacht, dafür in englisch und vollgestopft mit Detail-Infos:
http://brokenthorn.com/Resources/OSDev1.html

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 23:10:06 01.04.2009   Titel:              Zitieren

@Erhard: Bezüglich Linken mit mingw hab ich es leider nicht hingegriegt. Benutze nun DJGPP. Es ist nur so, dass meine Pfade auf mingw Verzeichnisse eingestellt sind und wenn ich make in der Eingabeaufforderung aufrufe, mingw make ausgeführt wird. Und da kamen wieder die komischen Fehlermeldungen. Und ich wollte wissen, woran es liegt...

Bezüglich des nächsten logischen Themas über Interrupts: Ich halte grade ein älteres Buch von Klaus-Dieter Thies "Die Innovativen 80286/80386 Architekturen" Teil 2. Im ersten Kapitel Basis-Programmier-Modell gibt es einen Unterkapitel "Ausnahmen und Interrupts". Vielleicht wäre das nächste logische Thema nicht nur über Interrupts alleine (als asynchrone Ereignisse), sondern auch über Ausnahmen (als synchrone Ereignisse) sinnvoll...

Erhard Henkes schrieb:
@abc.w:
Zitat:
Ich habe mich auch mal mit einem eigenen OS in Assembler beschäftigt zwecks endlich mal den Protected Mode der Intel CPUs zu verstehen. Habe aber diesbezüglich versagt und daraus wurde nichts. Hm, vertane Lebenszeit... hätte lieber in was anderes und sinnvolleres investieren sollen.
Ich hoffe, Du bist dem Protected Mode schon etwas näher gekommen. ;)
Hm, ja, bisschen :) Aber noch weit davon entfernt, mal aus dem Stegreif eigene Tasks anlegen zu können, die sich nicht gegenseitig kaputtmachen könnten :)

+fricky schrieb:
abc.w schrieb:

Gibt es irgendwo einen freien x86 IP ab 80386, am Besten in VHDL?

http://www.opencores.org/?do=project&who=zet86
16 bit Zet processor equivalent to an Intel 80186. Ich hätte gerne einen ab 80386... :) Ich hatte auch mal danach recherchiert, es gibt irgendwie keine, nicht mal "kostenpflichtige", warum auch immer.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:30:48 01.04.2009   Titel:              Zitieren

Zitat:
Vielleicht wäre das nächste logische Thema nicht nur über Interrupts alleine (als asynchrone Ereignisse), sondern auch über Ausnahmen (als synchrone Ereignisse) sinnvoll...

Ja, das gehört zusammen: Gates, Interrupts, Traps, Exceptions.
Ich bin am nachdenken, wie man dieses Kapitel am besten anpackt.
Mir war es nur wichtig zu zeigen, dass man auch ohne Interrupts Daten per Polling aus dem Tastaturpuffer abholen kann. Das ist aber, als würde man ständig an der Tür stehen, um zu öffnen, falls jemand kommt (eben weitgehend unnötiger Aufwand). Nun wird nach dem Umzug nach PM wieder die "Klingel" eingeführt, damit wir asynchron auf "echten" Bedarf reagieren können. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:44:59 02.04.2009, insgesamt 2-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 09:54:51 02.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Ja, das gehört zusammen: Gates, Interrupts, Traps, Exceptions.
Ich bin am nachdenken, wie man dieses Kapitel am besten anpackt.

diese 'call gates' sind eine x86-spezialität. die würde ich getrennt erwähnen.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:33:37 02.04.2009   Titel:              Zitieren

Ich habe eine Nomenklatur-Frage. Man benötigt in den verschiedenen C-Modulen immer wieder eine ganze Menge extern definierter Funktionen. Dies erfolgt oft durch Inkludieren einer Header-Datei namens "system.h", in der man dann alle "externen" Funktionen und einiges andere deklariert/definiert. Mir gefällt der Name "system.h" nicht besonders, weil er nicht wirklich verständlich ist. System kann alles und nichts sein. :rolleyes:

Folgende Ideen habe ich bisher:

functions.h
function_prototypes.h
kernel.h
operating_system.h
os.h

Wie würdet ihr diesen Header nennen, der dann fast in jedem Modul am Anfang zu finden ist? Mein Favorit ist bisher "os.h". Lässt man geistig das "o" weg, landet man tatsächlich bei "system.h".
Vielleicht hat jemand eine viel bessere Idee. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 20:39:48 02.04.2009   Titel:              Zitieren

#include <PrettyOS.h> ?
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:26:52 03.04.2009   Titel:              Zitieren

Die Idee ist o.k. Ich wollte den Namen aber noch ändern können, ist nur der Entwicklungs-Deckname. ;)
Habe mich vorerst für os.h entschieden.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:27:25 04.04.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:11:14 04.04.2009   Titel:              Zitieren

Ich benötige eure Unterstützung, weil ich die Lücke nicht finde. :rolleyes:

Exceptions und Timer Interrupt IRQ 0 gehen.
Wenn ich den keyboard_handler (polling geht ja bestens) zum Testen auf den IRQ0 (18,222 Ticks/sec) umlege, funktioniert er wie beabsichtigt.

Allerdings kommt der Keyboard Interrupt IRQ1 nicht an. :confused: EDIT: Er wird nicht ausgelöst, weil der Tastatur-Puffer nicht leer ist (das berühmte "flushen" hat mich wieder eingeholt).

Hier der gesamte - noch nicht funktionierende - Sourcecode: http://www.henkessoft.de/OS_Dev/Downloads/14%20C%20Test%20IRQ1%20funktioniert%20nicht.zip

Ich denke, dass der C-Code für die Interrupt-Behandlung in Ordnung ist, habe ihn mehrfach gecheckt. Vielleicht liegt es am Assemblercode isr.asm (Stack?) oder am Linker-Script? Hier ein Screenshot vom OS (timer IRQ geht, habe ihn auf eine Minute im Bildschirm-Ausdruck eingestellt, Zeit stimmt unter Bochs aber nicht): http://www.henkessoft.de/OS_Dev/Downloads/IRQ_Test.PNG

Ich hoffe, das jemand den blöden Fehler bezüglich IRQ1 und vielleicht auch der anderen (welchen kann man am einfachsten testen?) findet, damit wir rasch weiter kommen. Wie gesagt, IRQ0 geht bestens (einfach mal auf key_handler umlegen).
Wenn man mit
Code:
__asm__("int $0x21");
Code:
__asm__("int $0x21");
Code:
__asm__("int $0x21");
im Kernel Programm main()
den IRQ1 (--> 33 = 0x21) selbst auslöst, kommt auch der keyboard_handler ins Spiel.

Das heißt, warum wird der IRQ1 nicht weiter geleitet? (IDT Problem?)

@Nobuo T, abc.w, Bitsy, +fricky et.al.:
Lasst mich bitte nicht hängen! Wer diesen Mist-Fehler findet, wird im Tutorial extrem gelobt. EDIT: Hauptproblem inzwischen gelöst, aber ich würde mich freuen, wenn ihr trotzdem mal über den Code schaut. Das Thema IDT, IDTR, ISR, Exceptions, ... ist wichtig.



EDIT: In einem anderen Forum habe ich erfahren, dass man den Tastatur-Puffer leeren muss, damit neue Interrupts gesendet werden. Klingt logisch. Daher habe ich einfach folgendes gemacht:

Ein einmaliges
Code:
__asm__("int $0x21");
Code:
__asm__("int $0x21");
Code:
__asm__("int $0x21");

reicht bereits aus, um den Prozess zu starten.
Soll ich ein
Code:
keyboard_init(){__asm__("int $0x21");}
Code:
keyboard_init(){__asm__("int $0x21");}
Code:
keyboard_init(){__asm__("int $0x21");}

schreiben, das ich einmal zu Beginn der main() aufrufe??

Es gibt noch eine zweite - evtl. bessere - Lösung:
Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
void keyboard_init()
{
    /* Wait until buffer is empty */
    while (inportb(0x64) & 0x01)
      inportb(0x60);

    // __asm__("int $0x21"); // ?
};
Code:
1
2
3
4
5
6
7
8
void keyboard_init()
{
/* Wait until buffer is empty */
while (inportb(0x64) & 0x01)
inportb(0x60);

// __asm__("int $0x21"); // ?
};
Code:
1
2
3
4
5
6
7
8
void keyboard_init()
{
    /* Wait until buffer is empty */
    while (inportb(0x64) & 0x01)
      inportb(0x60);

    // __asm__("int $0x21"); // ?
};


Hier ist jetzt der funktionierende Code, allerdings alles noch im Experimentierstadium:

http://www.henkessoft.de/OS_Dev/Downloads/14_C_Test_IRQ1_funktioniert.zip

Welchen Interrupt würdet ihr nach IRQ0 (Zeit-Ticks) und IRQ1 (Tastatur) als nächstes probieren?

Speichermanagement, Multitasking, ... warten. Allerdings muss ich zugeben, dass das gesamte Thema OSDEV ziemlich knifflig ist und man die Tools wirklich beherrschen muss. meine Tool-Schwachpunkte sind AT&T Syntax und Linker-Skript. Der verwendete DJGPP mit gcc 3.1 ist auf jeden Fall die richtige Wahl.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:43:04 04.04.2009, insgesamt 14-mal bearbeitet
Bitsy
Mitglied

Benutzerprofil
Anmeldungsdatum: 01.05.2001
Beiträge: 499
Beitrag Bitsy Mitglied 05:22:46 04.04.2009   Titel:              Zitieren

Probiere mal irgendeinen von 3-8, wobei man das anzusteuernde Device auch auf einen der oberen Interrupts legen können sollte, und dann kümmere Dich um den 2er, weil Du den brauchst, wenn Du an die oberen 8 ran willst. Wenn das Gerät dann auch z.B. mit dem 10er ansprechbar ist, stehen überhaupt erst mal alle IRQs zur Verfügung! Also - erst eine einfache Interruptgeschichte 'unten', und dann schauen, dass sie auch 'oben' läuft.

Wenn der 2er Probleme macht - ich sollte noch einen Sourcecode haben, bei dem ich eine vierfache Serielle angesteuert habe, wobei der letzte Kanal eben nur über IRQ 10 erreichbar war. Die waren damals sehr dankbar, dass es überhaupt mal ein Stück Software gab, mit dem man den überhaupt ansprechen konnte ;)

Freut mich übrigens, dass der 3er DJGPP soweit funktioniert - hatte Dir ja in der Mail die Problematik erklärt.


Zuletzt bearbeitet von Bitsy am 05:32:46 04.04.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 12:18:15 04.04.2009   Titel:              Zitieren

@Bitsy:
Das sind die Mechanismen, die versuchsweise eingebaut sind, muss aber noch prüfen, ob alles wirklich funktioniert, bisher wurden ja nur IRQ0 (clock) und IRQ1 (keyboard) behandelt:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
struct idt_entry
{
    unsigned short base_lo;
    unsigned short sel;
    unsigned char always0;
    unsigned char flags;
    unsigned short base_hi;
}__attribute__((packed)); //prevent compiler optimization

struct idt_entry idt[256];

void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags)
{
    idt[num].base_lo = (base        & 0xFFFF);
    idt[num].base_hi = (base >> 16) & 0xFFFF;
    idt[num].sel     =   sel;
    idt[num].always0 =     0;
    idt[num].flags   = flags;
}

/* Remap: IRQ0 to IRQ15 have to be remapped to IDT entries 32 to 47 */
void irq_remap(void)
{
    outportb(0x20, 0x11); outportb(0xA0, 0x11); outportb(0x21, 0x20); outportb(0xA1, 0x28); outportb(0x21, 0x04);
    outportb(0xA1, 0x02); outportb(0x21, 0x01); outportb(0xA1, 0x01); outportb(0x21, 0x00); outportb(0xA1, 0x00);
}

/* After remap of the interrupt controllers the appropriate ISRs are connected to the correct entries in the IDT. */
void irq_install()
{
    irq_remap();
    idt_set_gate(32, (unsigned) irq0,  0x08, 0x8E);   idt_set_gate(33, (unsigned) irq1,  0x08, 0x8E);
    idt_set_gate(34, (unsigned) irq2,  0x08, 0x8E);   idt_set_gate(35, (unsigned) irq3,  0x08, 0x8E);
    idt_set_gate(36, (unsigned) irq4,  0x08, 0x8E);   idt_set_gate(37, (unsigned) irq5,  0x08, 0x8E);
    idt_set_gate(38, (unsigned) irq6,  0x08, 0x8E);   idt_set_gate(39, (unsigned) irq7,  0x08, 0x8E);
    idt_set_gate(40, (unsigned) irq8,  0x08, 0x8E);   idt_set_gate(41, (unsigned) irq9,  0x08, 0x8E);
    idt_set_gate(42, (unsigned) irq10, 0x08, 0x8E);   idt_set_gate(43, (unsigned) irq11, 0x08, 0x8E);
    idt_set_gate(44, (unsigned) irq12, 0x08, 0x8E);   idt_set_gate(45, (unsigned) irq13, 0x08, 0x8E);
    idt_set_gate(46, (unsigned) irq14, 0x08, 0x8E);   idt_set_gate(47, (unsigned) irq15, 0x08, 0x8E);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
struct idt_entry
{
unsigned short base_lo;
unsigned short sel;
unsigned char always0;
unsigned char flags;
unsigned short base_hi;
}__attribute__((packed)); //prevent compiler optimization

struct idt_entry idt[256];

void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags)
{
idt[num].base_lo = (base & 0xFFFF);
idt[num].base_hi = (base >> 16) & 0xFFFF;
idt[num].sel = sel;
idt[num].always0 = 0;
idt[num].flags = flags;
}

/* Remap: IRQ0 to IRQ15 have to be remapped to IDT entries 32 to 47 */
void irq_remap(void)
{
outportb(0x20, 0x11); outportb(0xA0, 0x11); outportb(0x21, 0x20); outportb(0xA1, 0x28); outportb(0x21, 0x04);
outportb(0xA1, 0x02); outportb(0x21, 0x01); outportb(0xA1, 0x01); outportb(0x21, 0x00); outportb(0xA1, 0x00);
}

/* After remap of the interrupt controllers the appropriate ISRs are connected to the correct entries in the IDT. */
void irq_install()
{
irq_remap();
idt_set_gate(32, (unsigned) irq0, 0x08, 0x8E); idt_set_gate(33, (unsigned) irq1, 0x08, 0x8E);
idt_set_gate(34, (unsigned) irq2, 0x08, 0x8E); idt_set_gate(35, (unsigned) irq3, 0x08, 0x8E);
idt_set_gate(36, (unsigned) irq4, 0x08, 0x8E); idt_set_gate(37, (unsigned) irq5, 0x08, 0x8E);
idt_set_gate(38, (unsigned) irq6, 0x08, 0x8E); idt_set_gate(39, (unsigned) irq7, 0x08, 0x8E);
idt_set_gate(40, (unsigned) irq8, 0x08, 0x8E); idt_set_gate(41, (unsigned) irq9, 0x08, 0x8E);
idt_set_gate(42, (unsigned) irq10, 0x08, 0x8E); idt_set_gate(43, (unsigned) irq11, 0x08, 0x8E);
idt_set_gate(44, (unsigned) irq12, 0x08, 0x8E); idt_set_gate(45, (unsigned) irq13, 0x08, 0x8E);
idt_set_gate(46, (unsigned) irq14, 0x08, 0x8E); idt_set_gate(47, (unsigned) irq15, 0x08, 0x8E);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
struct idt_entry
{
    unsigned short base_lo;
    unsigned short sel;
    unsigned char always0;
    unsigned char flags;
    unsigned short base_hi;
}__attribute__((packed)); //prevent compiler optimization

struct idt_entry idt[256];

void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags)
{
    idt[num].base_lo = (base        & 0xFFFF);
    idt[num].base_hi = (base >> 16) & 0xFFFF;
    idt[num].sel     =   sel;
    idt[num].always0 =     0;
    idt[num].flags   = flags;
}

/* Remap: IRQ0 to IRQ15 have to be remapped to IDT entries 32 to 47 */
void irq_remap(void)
{
    outportb(0x20, 0x11); outportb(0xA0, 0x11); outportb(0x21, 0x20); outportb(0xA1, 0x28); outportb(0x21, 0x04);
    outportb(0xA1, 0x02); outportb(0x21, 0x01); outportb(0xA1, 0x01); outportb(0x21, 0x00); outportb(0xA1, 0x00);
}

/* After remap of the interrupt controllers the appropriate ISRs are connected to the correct entries in the IDT. */
void irq_install()
{
    irq_remap();
    idt_set_gate(32, (unsigned) irq0,  0x08, 0x8E);   idt_set_gate(33, (unsigned) irq1,  0x08, 0x8E);
    idt_set_gate(34, (unsigned) irq2,  0x08, 0x8E);   idt_set_gate(35, (unsigned) irq3,  0x08, 0x8E);
    idt_set_gate(36, (unsigned) irq4,  0x08, 0x8E);   idt_set_gate(37, (unsigned) irq5,  0x08, 0x8E);
    idt_set_gate(38, (unsigned) irq6,  0x08, 0x8E);   idt_set_gate(39, (unsigned) irq7,  0x08, 0x8E);
    idt_set_gate(40, (unsigned) irq8,  0x08, 0x8E);   idt_set_gate(41, (unsigned) irq9,  0x08, 0x8E);
    idt_set_gate(42, (unsigned) irq10, 0x08, 0x8E);   idt_set_gate(43, (unsigned) irq11, 0x08, 0x8E);
    idt_set_gate(44, (unsigned) irq12, 0x08, 0x8E);   idt_set_gate(45, (unsigned) irq13, 0x08, 0x8E);
    idt_set_gate(46, (unsigned) irq14, 0x08, 0x8E);   idt_set_gate(47, (unsigned) irq15, 0x08, 0x8E);
}

Daher kann ich mit
C/C++ Code:
__asm__("int $0x21"); // 0x21 = 33, gemappt auf IRQ1 (Keyboard)
C/C++ Code:
__asm__("int $0x21"); // 0x21 = 33, gemappt auf IRQ1 (Keyboard)
C/C++ Code:
__asm__("int $0x21"); // 0x21 = 33, gemappt auf IRQ1 (Keyboard)

den Keyboard-Interrupt selbst anstoßen.

Das mit den Interrupts finde ich ganz lustig. Die Keyboard-Ports und der Keyboard-Puffer haben mich fast aus der OS-Kreisbahn geworfen, weil man diesbezüglich viel unausgegorenes und verwirrendes Zeug im Internet findet.

@Bitsy: Hast Du eine Idee, wie man das Linker-Problem (mit dem a.out Format) des mingw überwinden könnte? abc.w präferiert diese Toolchain. :confused:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 12:35:04 04.04.2009, insgesamt 8-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 13:11:30 04.04.2009   Titel:              Zitieren

Bezüglich Linker-Problem mit mingw würde mich zwar interessieren, wie man es irgendwie hinkriegen könnte. Aber, wenn es nicht geht, aus welchen Gründen auch immer, ist auch nicht schlimm. Ich habe ja noch DJGPP.
Ich habe mir den Quellcode 14_C_Test_IRQ1_funktioniert geholt und ausprobiert. Eines stört mich jetzt ein wenig. Zunächst, auf der einen Seite haben wir Assembler-Dateien, die mit nasm assembliert werden. Auf der anderen Seite gibt es c-Dateien, die aber hie und da eine Funktion mit Assembler Inline-Code enthalten. Das ist irgendwie nicht konsistent. Einmal nasm, dann gcc, dann inline-gcc. Wäre vielleicht sinnvoll, wenn c-Datei, dann C, wenn Assembler-Datei, dann Assembler nasm. Und die Funktionen mit Assembler Inline-Code rein in Assembler implementieren? Nur als Vorschlag. Optimal wäre natürlich, statt nasm GNU as zu verwenden, weiss aber jetzt nicht genau, ob man 16-Bit Assembler Quellcode mit as assemblieren kann. Vorteil davon wäre noch, dass man nur ein Tool bräuchte: DJGGP. GNU as ist nämlich in DJGPP mitenthalten.
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 13:38:24 04.04.2009   Titel:              Zitieren

Eine andere Sache, wollte ein Paar Ausnahmen provozieren mit diesem Code:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.global _k_zero_divide
.global _k_undefined_op
.global _k_null_pointer

.section .text

_k_zero_divide:
    movl $0, %eax
    div %eax
    ret

_k_undefined_op:
    ud2
    ret

_k_null_pointer:
    movl $0, %eax
    movl %eax, (%eax)
    ret
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.global _k_zero_divide
.global _k_undefined_op
.global _k_null_pointer

.section .text

_k_zero_divide:
movl $0, %eax
div %eax
ret

_k_undefined_op:
ud2
ret

_k_null_pointer:
movl $0, %eax
movl %eax, (%eax)
ret
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.global _k_zero_divide
.global _k_undefined_op
.global _k_null_pointer

.section .text

_k_zero_divide:
    movl $0, %eax
    div %eax
    ret

_k_undefined_op:
    ud2
    ret

_k_null_pointer:
    movl $0, %eax
    movl %eax, (%eax)
    ret

Division durch 0 und undefinierter Op :live:
Die Funktion k_null_pointer() wir aber ausgeführt und das System läuft :confused: Oder ist Zugriff mit Offset Null ok :confused:
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 15:01:46 04.04.2009   Titel:              Zitieren

Erhard:
Irgendwie habe ich inzwischen ein wenig den Ueberblick verloren. Kannst du mal irgendwie ein Verzeichnis oder eine Seite einrichten, wo man waehrend der Entwicklung immer mal die aktuellen Codes runterladen kann?

Bei deinem ersten KB-Polling hat mich ehrlich gesagt schon etwas gewundert, dass das ueberhaupt funktionierte. Klassischerweise macht man das AFAIR so, dass man einen Handler fuer IRQ 1 installiert. Dort checkt man erstmal, ob etwas im input buffer ist (port 64h, Bit0). Falls was dran liegt, port 60h auslesen und irgendwie verarbeiten (scancodes oder evtl. sonstige spezial-codes).
Zum Abschluss immer ACK an das keyboard, indem ein reset ausgefuehrt wird: Kurz aus- und wieder einschalten ueber Port 61h, Bit7. Zum Ende natuerlich noch EOI an den PIC. Ist dann zwar immer noch ziemlich primitiv, sollte so aber zumindest keine Probleme geben...

abc.w:
Ich kann nur vermuten, dass einfach (noch?) kein Paging aktiviert ist, mit dem eine Ausnahme beim Zugriff auf einen 0-Pointer ausgeloest wuerde. An der physikalischen Adresse 0 ist nun mal einfach normaler RAM, also an sich kein Problem.

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 15:51:46 04.04.2009   Titel:              Zitieren

Zitat:
nasm, dann gcc, dann inline-gcc. Wäre vielleicht sinnvoll, wenn c-Datei, dann C, wenn Assembler-Datei, dann Assembler nasm. Und die Funktionen mit Assembler Inline-Code rein in Assembler implementieren?

Du hast völlig Recht. Die bisherige "gemischte" Lösung liegt an meinen Problemen mit der AT&T Syntax. Auf der einen Seite ist es wichtig, dass Einsteiger sehen, wie einfach man zwischen C- und ASM-Code hin und her springen kann. Man benötigt nur global, extern und den führenden Unterstrich. Auf der anderen Seite führt dies zu einem Hin- und Hergehüpfe. Ich werde daher versuchen, Deine Idee aufzunehmen. Vielleicht kann Nobuo T da etwas unterstützen. :)

Zitat:
... statt nasm GNU as zu verwenden, weiss aber jetzt nicht genau, ob man 16-Bit Assembler Quellcode mit as assemblieren kann. Vorteil davon wäre noch, dass man nur ein Tool bräuchte: DJGGP. GNU as ist nämlich in DJGPP mitenthalten.

Habe mir die Syntax von as bisher noch nicht angeschaut. AT&T?

Zitat:
Kannst du mal irgendwie ein Verzeichnis oder eine Seite einrichten, wo man waehrend der Entwicklung immer mal die aktuellen Codes runterladen kann?

@Nobuo T:
Ja, wird sofort gemacht: Den letzten Code erhält man ab jetzt immer unter diesem Link (wurde aber im Tutorial noch nicht beschrieben, weil er sich im Entwicklungs-/Testzustand befindet; daher sind gute Ideen - wie oben von abc.w zum Thema Exception - immer gerne gesehen. Bitte ausreichend kommentieren.):

:arrow: :arrow: :arrow: Link zur jeweils aktuellsten Test-Version:
http://www.henkessoft.de/OS_Dev/Downloads/PrettyOS_last_version.zip

Was abc.w anspricht ist mein Hin- und Herhüpfen zwischen C-Code (vor allem zum Thema Interrupts) und isr.asm.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 16:03:15 04.04.2009, insgesamt 4-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 16:22:42 04.04.2009   Titel:              Zitieren

Zitat:
Die Funktion k_null_pointer() wird aber ausgeführt und das System läuft :confused: Oder ist Zugriff mit Offset Null ok :confused:
Zitat:
Ich kann nur vermuten, dass einfach (noch?) kein Paging aktiviert ist, mit dem eine Ausnahme beim Zugriff auf einen 0-Pointer ausgeloest wuerde. An der physikalischen Adresse 0 ist nun mal einfach normaler RAM, also an sich kein Problem.
Stimmt, Paging wurde noch nicht aktiviert. Das gehört sinnvollerweise als Vorteil zu Multitasking, wenn ich das richtig sehe.

Zitat:
Klassischerweise macht man das AFAIR so, dass man einen Handler fuer IRQ 1 installiert.
Richtig, klassischerweise. Aber es geht eben auch ohne Interrupt. Dieses ineffiziente Polling wollte ich zuerst zeigen, damit die Notwendigkeit der Interrupts verständlich wird.

Diese beiden Punkte bestätigen mich in meiner Vorgehensweise. Ich versuche die didaktische Reihenfolge im Tutorial so aufzubauen, wie man Funktionen/Strukturen in ASM oder C für die beabsichtigte Umsetzung wirklich benötigt. Also pyramidal.

Die bisherige Reihenfolge war deshalb:

- Bootbarer Minikernel
- Bootloader + nachgeladenem Kernel
- Auf Instruktionen im RM reagieren (dank BIOS einfache Handhabung)
- A20-Gate und PM aktivieren, GDT/GDTR (das gehört wohl als Minimum zusammen)
- Sprung vom ASM- zum C-Kernel
- Rudimentäre Textausgabe auf Bildschirm
- Rudimentäre Texteingabe mit Tastatur
- IDT/IDTR, Interrupts, Exceptions allgemein
- IRQ 0 (System Clock Tick jede 18,22 sec)
- IRQ 1 (Keyboard, durch Port 0x60 u. 0x64 etwas komplizierter)
- ... (immer spannend halten) ;)

Ich kann nur hoffen, dass dieses Konzept sinnvoll ist. :confused:

Was würdet ihr als notwendige nächste "Blöcke" auf die Pyramide wuchten?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 16:58:45 04.04.2009, insgesamt 2-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 22:21:11 04.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Zitat:
Klassischerweise macht man das AFAIR so, dass man einen Handler fuer IRQ 1 installiert.
Richtig, klassischerweise. Aber es geht eben auch ohne Interrupt. Dieses ineffiziente Polling wollte ich zuerst zeigen, damit die Notwendigkeit der Interrupts verständlich wird.

ehrlich gesagt, würde ich als noob nicht einsehen, wozu man einen dedizierten keyboard-interrupt braucht, wenn man die tastatur auch pollen kann (auch wenn ich verstanden habe, wie interrupts funktionieren). warum sollte polling ineffizient sein? so lange ich die tastatur häufig genug polle, so daß ich mit der tastenfrequenz eines schnellschreibers klar komme, ist die welt doch in ordnung. und wenn mir einer erzählen würde, dass die cpu beim pollen sinnlos zyklen verballert, würde ich antworten: "na und? dann polle ich eben in der timer-isr. ca. 18 anschläge/s als samplingrate sollte doch reichen".
:)
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 22:34:11 04.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Was würdet ihr als notwendige nächste "Blöcke" auf die Pyramide wuchten?

schwer zu sagen. der vollständigkeit halber vielleicht weitere hardwarekomponenten eines 0815-pc's behandeln, wie z.b. ansteuerung/benutzung der RTC, des piezo-piepsers, bustreiber bauen usw. allerdings besteht die gefahr, dass das alles langwierig, kompliziert und langweilig werden kann. vielleicht, um die spannung zu erhalten, das os soweit ausbauen, dass die erste, einfache anwendung laufen kann, z.b ein tetris clone oder so.
:)
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 23:57:46 04.04.2009   Titel:              Zitieren

Naja, PIT (und damit auch den speaker) und PIC vielleicht mal kurz anschneiden. Das sollte zur Standard-Peripherie IMHO dann aber wirklich erstmal reichen. Was die OS-Thematik betrifft hast du ja bis jetzt eigentlich wirklich nur ganz vorsichtig an der Oberflaeche gekratzt, weitere Nebensaechlichkeiten wie die RTC oder irgendwelche BUS-Geschichten sollte man da IMHO vermeiden.

Mein Vorschlag waere als Anschluss an deine Pyramide dann mal langsam in die abstrakteren, eigentlich interessanten Gefilde des OS-Designs einzusteigen. Da ist das Grundlegenste als naechstes vermutlich die dynamische Verwaltung des RAM: Knappe Einfuehrung in die Problematik und Vorstellung einfacher Loesungsansaetze wie Unterteilung des Speichers in Bloecke statischer Groesse (vielleicht praktischerweise gleich 4KB gross ;) ) und Verwaltung in statischen Arrays, Bitmaps oder dynamischen Free-Lists, Reservierungsstrategie next fit, evtl. ganz knapp noch Wiedereingliederungsproblematik (das weiter auszuwaelzen waere dann IMHO wirklich eher Stoff fuer ein richtiges Buch).
Weitermachen kannst du dann evtl. mit einer knappen Einfuehrung in Paging. Das spielt schliesslich eigentlich auf fast jeder Multitaskingmaschine eine Rolle.

Danach koenntest du dich dann vorsichtig an den Komplex Programme, Prozesse und Multitasking herantasten, mit einem knappen Ueberblick zum Thema Prozesserzeugung und Kontextwechsel, Scheduling und Verdraengung.
Dann vielleicht quasi zum Abschluss noch einen Abstecher zu Privilegien, Adressraumtrennung/Schutzmechanismen und Micro- vs Macro-Kern sowie IPC.

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908


Zuletzt bearbeitet von Nobuo T am 00:08:20 05.04.2009, insgesamt 3-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:43:29 05.04.2009   Titel:              Zitieren

Zitat:
"na und? dann polle ich eben in der timer-isr. ca. 18 anschläge/s als samplingrate sollte doch reichen".


EDIT: Die korrekte Frequenz wurde eingefügt, um keinen Verwirrung zu stiften. (thanks to +fricky)
Der Timer "feuert" mit einer Frequenz von 1193182 Hz / 65536 = 18,2065 Hz. Wenn man nichts anderes machen will als Tippen, ist das Polling sicher o.k. :D
Dann stößt man den Keyboard_handler einfach beim Timer_handler mit an. Ich habe das in der Tat genau so gemacht, als ich blöderweise den Tastaturpuffer nicht gelöscht hatte und dadurch kein IRQ1 kam, um zu sehen, ob der Keyboard_handler korrekt funktioniert. Ging tadellos. Von daher könnte man ein IRQ0-gesteuertes Keyboard-Polling als Alternative in Betracht ziehen.
Wirklichen Sinn macht es aber keinen, weil der Interrupt am Master PIC bereits fest vergeben ist. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 18:35:41 06.04.2009, insgesamt 3-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:01:01 05.04.2009   Titel:              Zitieren

Ich fasse mal die wirklich interessante Taskliste von Nobuo T zusammen:

- PIC (die beiden PICs wurden bereits beim remapping von IRQ 0-15 verarbeitet)
- PIT (programmable interval timer)
- Speaker (ja, BEEP (frequence)! Seit Win NT kaputt wegen Behinderung.)
- (video.c vernünftig ausbauen, bisher nur rudimentär)
- OS-Thematik (generell)
- Dynamische RAM Verwaltung:
- Unterteilung des Speichers in Blöcke statischer Groesse (4KB)
- Verwaltung (stat. Arrays, Bitmaps, dynam. Free-Lists)
- Reservierungsstrategie next fit
- Wiedereingliederungsproblematik
- Paging
- Programme & Prozesse
- Multitasking vs Singletasking
- Prozesserzeugung, Kontextwechsel, Scheduling, Verdrängung
- Privilegien / Schutzmechanismen / Adressraumtrennung
- Micro- vs Macro-Kernel
- inter-process communication

Das wird aber noch einige Zeit brauchen, denn ich möchte dies ja auch praktisch fassbar machen.

Kleines Übersichtsbild aus Internet:
http://ezs.kr.hs-niederrhein.de/TreiberBuch/html/os_aufbau.png

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:24:33 05.04.2009, insgesamt 3-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:09:25 05.04.2009   Titel:              Zitieren

@Nobuo T: Könnte man die isr.asm komplett in die C-Module packen? Ich schaffe das leider syntax-mäßig nicht. Mir gefällt es eigentlich auch so, hier wurde aber mehr Ordnung verlangt. Wie siehst Du das?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:14:25 05.04.2009, insgesamt 1-mal bearbeitet
Bitsy
Mitglied

Benutzerprofil
Anmeldungsdatum: 01.05.2001
Beiträge: 499
Beitrag Bitsy Mitglied 10:49:58 05.04.2009   Titel:              Zitieren

Ich glaube, der vorrangigste Punkt wäre nun eine Diskussion über die Architektur des OS an sich - und ob und wie solch ein 'Wunsch-OS' auf dem PC realisierbar ist.

Ich erinnere dabei an den absolut linearen Speicher eines guten alten 68000er-Systems, bei dem z.B. dem Videochip (des Atari) einfach zwei Adressen für den physikalischen und den logischen Bildschirmspeicher mitgeteilt wurden.
Da gibt es einen massiven Unterschied zum Realmode-PC.
(Über die Wichtigkeit eines VBL-interrupts möchte ich mich hier gar nicht auslassen - scheinen einige Grafikkartenhersteller immer noch nicht begriffen zu haben.)

An dieser Stelle spielt nämlich durchaus bereits DMA mit rein.

Ich möchte die Komplexität an einem kleinen Beispiel festmachen:
Nehmen wir mal an, ich möchte einen virtuellen Synthesizer mit dem Rechner realisieren. (Etwas, was auf dem Atari kein Problem war, unter DOS gerade noch ging, und unter Windows schon unter die höheren Künste der Programmierung fällt).
Da gibt es nämlich ein kleines Latenzproblem, dass je nach OS immer größer wird.
Wir haben einmal ein MIDI IN (könnte ja auch was anderes sein), also einen seriellen Stream, der mir Daten über gewünschte Änderungen (im Sound) liefert.
Die Software muss nun hingehen, und das Sample berechnen - und diese Daten so schnell wie möglich in den Speicher schreiben, und zwar - und nun kommt's - unmittelbar vor den derzeitigen Lesepunkt des Sound-DMAs!
Wenn ich - wie ab dem XP - eine 'geschützte' Hardware habe, bin ich auf ein OS angewiesen, was mir entsprechende Funktionen zur Verfügung stellt, die mir solche Aktionen erlauben. Fehlt sowas, kann der Rechner vielleicht wunderbar zig Medien abspielen, aber für diese Anwendung ist er unbrauchbar.

Oder nehmen wir den Fall Robotik:
Da wäre es sinnvoller der Applikation die Masse der Rechenzeit zu geben, weil es einfach wichtig ist, dass nichts durch die Lichtschranke flutscht, anstatt nachzuschauen, was gerade im Internet los ist... Also - dynamische konfigurierbare Prioritäten? Sollten vielleicht auch schon im OS stecken.


Zuletzt bearbeitet von Bitsy am 10:59:36 05.04.2009, insgesamt 3-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 11:10:31 05.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Könnte man die isr.asm komplett in die C-Module packen?

musstu die doku deines compilers lesen. oft muss man isr's mit einem pseudo-keyword '__interrupt' beginnen. machmal geht's mit einer #pragma-anweisung. ist halt compiler-abhängig.
:)

Bitsy schrieb:

Da gibt es nämlich ein kleines Latenzproblem, dass je nach OS immer größer wird.
Wir haben einmal ein MIDI IN (könnte ja auch was anderes sein), also einen seriellen Stream, der mir Daten über gewünschte Änderungen (im Sound) liefert.
Die Software muss nun hingehen, und das Sample berechnen - und diese Daten so schnell wie möglich in den Speicher schreiben...

MIDI ist doch ein sau-langsamer bus (32 kbits/s oder so), da kann der computer kaum die bremse sein. eher haste delays, weil der bus selber zu lahm ist. gibt's nicht schon was aktuelleres, als dieses steinzeit-protokoll?
:)
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 11:14:59 05.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zitat:
"na und? dann polle ich eben in der timer-isr. ca. 18 anschläge/s als samplingrate sollte doch reichen".
Da der Timer alle 18,2 ms mit IRQ0 Alarm schlägt

wieso haste ihn so schnell eingestellt? normerweise tickert der mit 18.2Hz, nicht kHz.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 12:30:21 05.04.2009   Titel:              Zitieren

@+fricky: Ja, Du hast völlig Recht, das habe ich durcheinander gebracht:
Zitat:
By default, this channel of the timer is set to generate an IRQ0 18.222 times per second.

Habe das oben korrigiert, um niemanden zu verwirren.

Im Sourcecode timer.c läuft das zur Zeit so (muss in Bochs nicht exakt stimmen):
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include "os.h"

int timer_ticks = 0;

/* timer fires 18.222 times per second.*/
void timer_handler(struct regs* r)
{
    ++timer_ticks;
    static int z=10;
    if ((timer_ticks % 1093) == 0) // 1093 = 60*18.222
    {
        k_printf("One minute has passed", ++z, 0x0B);
    }
}

void timer_wait(int ticks)
{
    unsigned long eticks;
    eticks = timer_ticks + ticks;
    while(timer_ticks < eticks);
}

void timer_install()
{
    /* Installs 'timer_handler' to IRQ0 */
    irq_install_handler(0, timer_handler);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include "os.h"

int timer_ticks = 0;

/* timer fires 18.222 times per second.*/
void timer_handler(struct regs* r)
{
++timer_ticks;
static int z=10;
if ((timer_ticks % 1093) == 0) // 1093 = 60*18.222
{
k_printf("One minute has passed", ++z, 0x0B);
}
}

void timer_wait(int ticks)
{
unsigned long eticks;
eticks = timer_ticks + ticks;
while(timer_ticks < eticks);
}

void timer_install()
{
/* Installs 'timer_handler' to IRQ0 */
irq_install_handler(0, timer_handler);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include "os.h"

int timer_ticks = 0;

/* timer fires 18.222 times per second.*/
void timer_handler(struct regs* r)
{
    ++timer_ticks;
    static int z=10;
    if ((timer_ticks % 1093) == 0) // 1093 = 60*18.222
    {
        k_printf("One minute has passed", ++z, 0x0B);
    }
}

void timer_wait(int ticks)
{
    unsigned long eticks;
    eticks = timer_ticks + ticks;
    while(timer_ticks < eticks);
}

void timer_install()
{
    /* Installs 'timer_handler' to IRQ0 */
    irq_install_handler(0, timer_handler);
}

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 12:38:06 05.04.2009, insgesamt 4-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 12:43:50 05.04.2009   Titel:              Zitieren

Zitat:
dynamische konfigurierbare Prioritäten?
Das ist ein interessantes Thema. Aber da wird noch viel Code den Compiler durchfließen, bevor ich da anlange.

Momentan denke ich darüber nach, welche völlig neuen Impulse man setzen könnte, aber zuerst muss man das alte praktisch nachempfinden, sonst fehlt das Verständnis. Die Verschaltung der Hardware macht ja auch gewisse Vorgaben, die man leider akzeptieren muss.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 14:14:29 05.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

C/C++ Code:
void timer_wait(int ticks)
{
    unsigned long eticks;
    eticks = timer_ticks + ticks;
    while(timer_ticks < eticks);
}
C/C++ Code:
void timer_wait(int ticks)
{
unsigned long eticks;
eticks = timer_ticks + ticks;
while(timer_ticks < eticks);
}
C/C++ Code:
void timer_wait(int ticks)
{
    unsigned long eticks;
    eticks = timer_ticks + ticks;
    while(timer_ticks < eticks);
}

^^das sieht nicht überlauffest aus
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 14:38:36 05.04.2009   Titel:              Zitieren

Was ist schon "überlauffest" auf der Welt?

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "os.h"

unsigned long timer_ticks = 0;

/* timer fires 18.222 times per second.*/
void timer_handler(struct regs* r)
{
    ++timer_ticks;
    static unsigned long z=10;
    const unsigned long N = 109; // 109 = 60/10*18.222
    if (!(timer_ticks % N))
        k_printf("10 seconds have passed", ++z, 0x0B);
}

void timer_wait(unsigned long ticks)
{
    unsigned long eticks;
    eticks = timer_ticks + ticks;
    while(timer_ticks < eticks);
}

void timer_install()
{
    /* Installs 'timer_handler' to IRQ0 */
    irq_install_handler(0, timer_handler);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "os.h"

unsigned long timer_ticks = 0;

/* timer fires 18.222 times per second.*/
void timer_handler(struct regs* r)
{
++timer_ticks;
static unsigned long z=10;
const unsigned long N = 109; // 109 = 60/10*18.222
if (!(timer_ticks % N))
k_printf("10 seconds have passed", ++z, 0x0B);
}

void timer_wait(unsigned long ticks)
{
unsigned long eticks;
eticks = timer_ticks + ticks;
while(timer_ticks < eticks);
}

void timer_install()
{
/* Installs 'timer_handler' to IRQ0 */
irq_install_handler(0, timer_handler);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "os.h"

unsigned long timer_ticks = 0;

/* timer fires 18.222 times per second.*/
void timer_handler(struct regs* r)
{
    ++timer_ticks;
    static unsigned long z=10;
    const unsigned long N = 109; // 109 = 60/10*18.222
    if (!(timer_ticks % N))
        k_printf("10 seconds have passed", ++z, 0x0B);
}

void timer_wait(unsigned long ticks)
{
    unsigned long eticks;
    eticks = timer_ticks + ticks;
    while(timer_ticks < eticks);
}

void timer_install()
{
    /* Installs 'timer_handler' to IRQ0 */
    irq_install_handler(0, timer_handler);
}

Besser?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 14:47:28 05.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Besser?

ist doch immer noch das selbe.
so z.b:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
unsigned long eticks;

void timer_handler(struct regs* r)
{
  ...
  if (eticks)
    eticks--;
}

void timer_wait (unsigned long ticks)
{
    disable_timer_interrupt();
    eticks = ticks;
    enable_timer_interrupt();
   
    // busy wait...
    while (eticks)
      ;
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
unsigned long eticks;

void timer_handler(struct regs* r)
{
...
if (eticks)
eticks--;
}

void timer_wait (unsigned long ticks)
{
disable_timer_interrupt();
eticks = ticks;
enable_timer_interrupt();

// busy wait...
while (eticks)
;
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
unsigned long eticks;

void timer_handler(struct regs* r)
{
  ...
  if (eticks)
    eticks--;
}

void timer_wait (unsigned long ticks)
{
    disable_timer_interrupt();
    eticks = ticks;
    enable_timer_interrupt();
   
    // busy wait...
    while (eticks)
      ;
}

:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 17:19:21 05.04.2009   Titel:              Zitieren

Ja, gute Idee, habe es umgesetzt. Thanks @ +fricky.

So sieht momentan timer.c aus:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "os.h"

unsigned long timer_ticks = 0;
unsigned long eticks;

void timer_handler(struct regs* r)
{
    ++timer_ticks;
    if (eticks)
        --eticks;

    //TEST
    char bufferTimerticks[20];            k_itoa (timer_ticks, bufferTimerticks);
    k_printf("             ",  6, 0x0B);  k_printf(bufferTimerticks, 6, 0x0B);
    char bufferWaitticks[20];               k_itoa (eticks, bufferWaitticks);
    k_printf("             ",  7, 0x0B);  k_printf(bufferWaitticks,  7, 0x0B);
    //TEST
}

void timer_wait (unsigned long ticks)
{
    timer_uninstall();
    eticks = ticks;
    timer_install();

    // busy wait...
    while (eticks)
    {
        k_printf("waiting time runs",   8, 0x0B);
        /* do nothing */;
    };
    k_printf("waiting time has passed", 9, 0x0B);
}

void sleepSeconds (unsigned long seconds)
{
    // based upon timer tick frequence of 18.222 Hz
    timer_wait((unsigned long)18.222*seconds);
}

void timer_install()
{
    /* Installs 'timer_handler' to IRQ0 */
    irq_install_handler(0, timer_handler);
}

void timer_uninstall()
{
    /* Uninstalls IRQ0 */
    irq_uninstall_handler(0);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "os.h"

unsigned long timer_ticks = 0;
unsigned long eticks;

void timer_handler(struct regs* r)
{
++timer_ticks;
if (eticks)
--eticks;

//TEST
char bufferTimerticks[20]; k_itoa (timer_ticks, bufferTimerticks);
k_printf(" ", 6, 0x0B); k_printf(bufferTimerticks, 6, 0x0B);
char bufferWaitticks[20]; k_itoa (eticks, bufferWaitticks);
k_printf(" ", 7, 0x0B); k_printf(bufferWaitticks, 7, 0x0B);
//TEST
}

void timer_wait (unsigned long ticks)
{
timer_uninstall();
eticks = ticks;
timer_install();

// busy wait...
while (eticks)
{
k_printf("waiting time runs", 8, 0x0B);
/* do nothing */;
};
k_printf("waiting time has passed", 9, 0x0B);
}

void sleepSeconds (unsigned long seconds)
{
// based upon timer tick frequence of 18.222 Hz
timer_wait((unsigned long)18.222*seconds);
}

void timer_install()
{
/* Installs 'timer_handler' to IRQ0 */
irq_install_handler(0, timer_handler);
}

void timer_uninstall()
{
/* Uninstalls IRQ0 */
irq_uninstall_handler(0);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "os.h"

unsigned long timer_ticks = 0;
unsigned long eticks;

void timer_handler(struct regs* r)
{
    ++timer_ticks;
    if (eticks)
        --eticks;

    //TEST
    char bufferTimerticks[20];            k_itoa (timer_ticks, bufferTimerticks);
    k_printf("             ",  6, 0x0B);  k_printf(bufferTimerticks, 6, 0x0B);
    char bufferWaitticks[20];               k_itoa (eticks, bufferWaitticks);
    k_printf("             ",  7, 0x0B);  k_printf(bufferWaitticks,  7, 0x0B);
    //TEST
}

void timer_wait (unsigned long ticks)
{
    timer_uninstall();
    eticks = ticks;
    timer_install();

    // busy wait...
    while (eticks)
    {
        k_printf("waiting time runs",   8, 0x0B);
        /* do nothing */;
    };
    k_printf("waiting time has passed", 9, 0x0B);
}

void sleepSeconds (unsigned long seconds)
{
    // based upon timer tick frequence of 18.222 Hz
    timer_wait((unsigned long)18.222*seconds);
}

void timer_install()
{
    /* Installs 'timer_handler' to IRQ0 */
    irq_install_handler(0, timer_handler);
}

void timer_uninstall()
{
    /* Uninstalls IRQ0 */
    irq_uninstall_handler(0);
}


ckernel.c:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include "os.h"

int main()
{
    k_clear_screen();

    // GDT, IDT, ISRS, IRQ, timer, keyboard
    gdt_install();
    idt_install();
    isrs_install();
    irq_install();
    timer_install();
    keyboard_install();

    k_printf("   ************************************************", 0, 0xA);
    k_printf("   *                                              *", 1, 0xA);
    k_printf("   *          Welcome to PrettyOS 0.05            *", 2, 0xA);
    k_printf("   *                                              *", 3, 0xA);
    k_printf("   *        The C kernel has been loaded.         *", 4, 0xA);
    k_printf("   *                                              *", 5, 0xA);
    k_printf("   ************************************************", 6, 0xA);

    update_cursor(8, 0);
        sti();
    while(TRUE)
    {
        static int zz=10;
        sleepSeconds(20);
        k_printf("20 sec have passed", ++zz, 0x0B);
    };
    return 0;
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include "os.h"

int main()
{
k_clear_screen();

// GDT, IDT, ISRS, IRQ, timer, keyboard
gdt_install();
idt_install();
isrs_install();
irq_install();
timer_install();
keyboard_install();

k_printf(" ************************************************", 0, 0xA);
k_printf(" * *", 1, 0xA);
k_printf(" * Welcome to PrettyOS 0.05 *", 2, 0xA);
k_printf(" * *", 3, 0xA);
k_printf(" * The C kernel has been loaded. *", 4, 0xA);
k_printf(" * *", 5, 0xA);
k_printf(" ************************************************", 6, 0xA);

update_cursor(8, 0);
sti();
while(TRUE)
{
static int zz=10;
sleepSeconds(20);
k_printf("20 sec have passed", ++zz, 0x0B);
};
return 0;
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include "os.h"

int main()
{
    k_clear_screen();

    // GDT, IDT, ISRS, IRQ, timer, keyboard
    gdt_install();
    idt_install();
    isrs_install();
    irq_install();
    timer_install();
    keyboard_install();

    k_printf("   ************************************************", 0, 0xA);
    k_printf("   *                                              *", 1, 0xA);
    k_printf("   *          Welcome to PrettyOS 0.05            *", 2, 0xA);
    k_printf("   *                                              *", 3, 0xA);
    k_printf("   *        The C kernel has been loaded.         *", 4, 0xA);
    k_printf("   *                                              *", 5, 0xA);
    k_printf("   ************************************************", 6, 0xA);

    update_cursor(8, 0);
        sti();
    while(TRUE)
    {
        static int zz=10;
        sleepSeconds(20);
        k_printf("20 sec have passed", ++zz, 0x0B);
    };
    return 0;
};


Es gibt ein offenbar bisher unerkanntes Problem:
Solange man die Finger vom Keyboard lässt läuft der timer_handler. Sobald man aber die erste Taste nach dem Drücken los lässt, bleibt der Timer (die gezählten timer_ticks) stehen. Nur bei gedrückter Taste läuft er wieder weiter. Rattenscharfer Effekt. :D

Allerdings blicke ich momentan nicht durch, warum das passiert. Da fehlt noch einiges im Keyboard-Bereich. Ich habe den Code hoch geladen, damit ihr euch das mal anschauen könnt. :)
http://www.henkessoft.de/OS_Dev/Downloads/PrettyOS_last_version.zip

Bei Keyboard Port 0x60 u. 0x64 muss ich noch mal richtig lesen. Da klafft noch eine echte Wissenslücke bei mir.

@Nobuo T: Würdest Du Dir bitte keyboard.c anschauen. Da muss ja der Wurm lauern. Deine konkreten Vorschläge von oben zum Thema Keyboard Controller wurden noch nicht umgesetzt. Mich würde interessieren, was genau den IRQ0 beim Taste-Loslassen "outknockt" und beim Taste-Drücken wieder aktiviert. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 18:11:36 05.04.2009, insgesamt 2-mal bearbeitet
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 18:30:25 05.04.2009   Titel:              Zitieren

Ok, mal wieder der Reihe nach:

Bitsy schrieb:
Ich glaube, der vorrangigste Punkt wäre nun eine Diskussion über die Architektur des OS an sich - und ob und wie solch ein 'Wunsch-OS' auf dem PC realisierbar ist.

Ich gehe mal davon aus, dass Erhard sich da schon einen groben Plan gemacht hat, was fuer eine Art von OS er fabrizieren will. Das ob ist da wohl keine Frage, das wie wird hier aktuell diskutiert. ;)

Was du da weiter anfuehrst, sind doch eher Spezialfaelle und Teilgebiete, des Themenbereichs Scheduling (Echtzeit-Prozesse). Solche Ansaetze wie Prioritaetensteuerung oder verschiedene Ansaetze fairer Ressourcenverteilung mit verschiedensten abgefahrenen queue-Konstrukten (da gibt es wirklich eine Menge weit komplizierteres als einfache Prioritaetensteuerung) kann man da vielleicht in einem Ueberblick kurz anschneiden, aber um den Rahmen nicht zu sprengen, waere mein Vorschlag, sich schliesslich einfach auf Round Robin zu beschraenken.

Und DMA-Gefrickel ist ja nun voellig abgehoben. Immer im Hinterkopf behalten, dass das ein Internet-Tutorial und kein Kompendium zur OS-Entwicklung werden soll - das wird wie ich das sehe schon so eine ordentliche Portion Stoff. :D

[OT]BTW ist das Basteln eines Synths auch auf dem PC selbst unter Windows kein groesseres Problem als unter DOS - solange man gute Hardware (am besten mit HW Wavetable Synth) oder zumindest sehr gute Treiber (zumindest directX) hat.[/OT]

Erhard Henkes schrieb:
Würdest Du Dir bitte keyboard.c anschauen. Da muss ja der Wurm lauern. Deine konkreten Vorschläge von oben zum Thema Keyboard Controller wurden noch nicht umgesetzt. Mich würde interessieren, was genau den IRQ0 beim Taste-Loslassen "outknockt" und beim Taste-Drücken wieder aktiviert. ;)

Scharfer Effekt -> reichlich daemlicher Fehler, wenn ich mich nicht verschielt habe:
FetchAndAnalyzeScancode landet in einer Endlosschleife, wenn eine Taste losgelassen wird. Mal abgesehen von dem fehlenden EOI an den PIC duerfte das geloeschte IF wohl ausschlaggebend dafuer sein, dass sich in diesem Fall dann so lange nichts mehr tut, bis du wieder eine Taste drueckst.

Kurz: Die Endlosschleife hat in FetchAndAnalyzeScancode nichts zu suchen.


BTW: Ich hatte in meiner Auflistung noch vergessen, sich mal mit der Kernel-API (und einem HW-Abstraktions/Treiber-Prinzip) deines OS zu befasssen. Alle Kernel-Funktionen, Treiber etc. einfach nur ueber C-Funktionen und header zur Verfuegung zu stellen ist sicher nicht das Wahre. :)
Ich wuerde die Einrichtung eines kleinen Sets der wichtigsten Funktionen zum I/O und spaeter dann Speicher- und Prozessverwaltung ueber Interrupts aehnlich DOS oder Linux vorschlagen.

Je nachdem, was fuer einen Kern du basteln willst (Micro oder Monolith), waere es evtl. sinnvoll, das schon ganz am Anfang beim Aufbauen der ersten abstrakteren OS-Funktionen wie RAM-Verwaltung zu diskutieren, statt erst bei Adressraumtrennung, Privilegien und IPC. Evtl. mit Verweis auf diese spaeteren Themen zur Begruendung.

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908


Zuletzt bearbeitet von Nobuo T am 18:46:36 05.04.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:49:16 05.04.2009   Titel:              Zitieren

Zitat:
FetchAndAnalyzeScancode landet in einer Endlosschleife, wenn eine Taste losgelassen wird. ...
Kurz: Die Endlosschleife hat in FetchAndAnalyzeScancode nichts zu suchen.

Uups, stimmt. Ich dachte, es wäre etwas komplizierteres. :rolleyes:
Da wimmelt es ja nur so von Endlosschleifen. Shit Polling! :D

Zitat:
Mal abgesehen von dem fehlenden EOI an den PIC duerfte das geloeschte IF wohl ausschlaggebend dafuer sein, dass sich in diesem Fall dann so lange nichts mehr tut, bis du wieder eine Taste drueckst.
Thanks.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:32:22 05.04.2009, insgesamt 1-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 19:06:39 05.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zitat:
... statt nasm GNU as zu verwenden, weiss aber jetzt nicht genau, ob man 16-Bit Assembler Quellcode mit as assemblieren kann. Vorteil davon wäre noch, dass man nur ein Tool bräuchte: DJGGP. GNU as ist nämlich in DJGPP mitenthalten.

Habe mir die Syntax von as bisher noch nicht angeschaut. AT&T?

Ja, AT&T Syntax mit dem Nachteil von links nach rechts Lesen, so wie man es normalerweise jahrelange macht, und dem Haufen Intel-Doku, wo man von rechts nach links lesen muss. Aber Lesbarkeit scheint ja sowieso der Punkt zu sein, auf den ich hier alleine bestehe.

Ich habe mal aus Neugier die Assembler-Dateien boot.asm, kernel.asm und isr.asm nach AT&T umgesetzt und erfolgreich versucht, einmal allein mit DJGPP (im Sinne ohne nasm) und einmal mit mingw Tools eine funktionierende MyOS.bin zu bauen. Nicht, dass ich darauf bestehe, vollständig auf diese Tools umzusteigen. Ist nur "Machbarkeitsstudie". Mein Makefile dazu sieht so aus:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
all:
    @echo Select target: mingw or djgpp.
    @echo Exit.

djgpp:
    @echo Building with djgpp:
    c:\djgpp\bin\as boot.s -o boot.o
    c:\djgpp\bin\ld boot.o -Ttext 0x7C00 -e _start -o boot.exe
    c:\djgpp\bin\objcopy --strip-all --only-section .text --output-target binary boot.exe boot.bin
    c:\djgpp\bin\as kernel.s -o kernel.o
    c:\djgpp\bin\as isr.s -o isr.o
   
    c:\djgpp\bin\gcc -Wall -c ckernel.c -o ckernel.o -O1  
    c:\djgpp\bin\gcc -Wall -c video.c -o video.o -O1
    c:\djgpp\bin\gcc -Wall -c math.c -o math.o -O1
    c:\djgpp\bin\gcc -Wall -c util.c -o util.o -O1
    c:\djgpp\bin\gcc -Wall -c gdt.c -o gdt.o
    c:\djgpp\bin\gcc -Wall -c idt.c -o idt.o
    c:\djgpp\bin\gcc -Wall -c isrs.c -o isrs.o
    c:\djgpp\bin\gcc -Wall -c irq.c -o irq.o
    c:\djgpp\bin\gcc -Wall -c timer.c -o timer.o
    c:\djgpp\bin\gcc -Wall -c keyboard.c -o keyboard.o
    c:\djgpp\bin\ld -T kernel.ld kernel.o isr.o ckernel.o video.o gdt.o idt.o isrs.o irq.o util.o math.o timer.o keyboard.o -o ckernel.bin
   
    cmd /c copy /b boot.bin + ckernel.bin MyOS    
   
    cmd /c del MyOS.bin
    cmd /c rename MyOS MyOS.bin
    cmd /c erase ..\MyOS.bin
    cmd /c copy MyOS.bin ..\MyOS.bin

mingw:
    @echo Building with mingw:
    as boot.s -o boot.o
    ld boot.o -Ttext 0x7C00 -e _start -o boot.exe
    objcopy --strip-all --only-section .text --output-target binary boot.exe boot2.bin
    dd if=boot2.bin of=boot.bin bs=512 count=1
    as kernel.s -o kernel.o
    as isr.s -o isr.o
   
    gcc -Wall -c ckernel.c -o ckernel.o -O1 -s
    gcc -Wall -c video.c -o video.o -O1 -s
    gcc -Wall -c math.c -o math.o -O1 -s
    gcc -Wall -c util.c -o util.o -O1 -s
    gcc -Wall -c gdt.c -o gdt.o -s
    gcc -Wall -c idt.c -o idt.o -s
    gcc -Wall -c isrs.c -o isrs.o -s
    gcc -Wall -c irq.c -o irq.o -s
    gcc -Wall -c timer.c -o timer.o -s
    gcc -Wall -c keyboard.c -o keyboard.o -s
    ld -Ttext 0x8000 -e _start kernel.o isr.o ckernel.o video.o gdt.o idt.o isrs.o irq.o util.o math.o timer.o keyboard.o -o ckernel.exe
    objcopy --strip-all --output-target binary ckernel.exe ckernel.bin
    cmd /c copy /b boot.bin + ckernel.bin MyOS    
   
    cmd /c del MyOS.bin
    cmd /c rename MyOS MyOS.bin
    cmd /c erase ..\MyOS.bin
    cmd /c copy MyOS.bin ..\MyOS.bin
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
all:
@echo Select target: mingw or djgpp.
@echo Exit.

djgpp:
@echo Building with djgpp:
c:\djgpp\bin\as boot.s -o boot.o
c:\djgpp\bin\ld boot.o -Ttext 0x7C00 -e _start -o boot.exe
c:\djgpp\bin\objcopy --strip-all --only-section .text --output-target binary boot.exe boot.bin
c:\djgpp\bin\as kernel.s -o kernel.o
c:\djgpp\bin\as isr.s -o isr.o

c:\djgpp\bin\gcc -Wall -c ckernel.c -o ckernel.o -O1
c:\djgpp\bin\gcc -Wall -c video.c -o video.o -O1
c:\djgpp\bin\gcc -Wall -c math.c -o math.o -O1
c:\djgpp\bin\gcc -Wall -c util.c -o util.o -O1
c:\djgpp\bin\gcc -Wall -c gdt.c -o gdt.o
c:\djgpp\bin\gcc -Wall -c idt.c -o idt.o
c:\djgpp\bin\gcc -Wall -c isrs.c -o isrs.o
c:\djgpp\bin\gcc -Wall -c irq.c -o irq.o
c:\djgpp\bin\gcc -Wall -c timer.c -o timer.o
c:\djgpp\bin\gcc -Wall -c keyboard.c -o keyboard.o
c:\djgpp\bin\ld -T kernel.ld kernel.o isr.o ckernel.o video.o gdt.o idt.o isrs.o irq.o util.o math.o timer.o keyboard.o -o ckernel.bin

cmd /c copy /b boot.bin + ckernel.bin MyOS

cmd /c del MyOS.bin
cmd /c rename MyOS MyOS.bin
cmd /c erase ..\MyOS.bin
cmd /c copy MyOS.bin ..\MyOS.bin

mingw:
@echo Building with mingw:
as boot.s -o boot.o
ld boot.o -Ttext 0x7C00 -e _start -o boot.exe
objcopy --strip-all --only-section .text --output-target binary boot.exe boot2.bin
dd if=boot2.bin of=boot.bin bs=512 count=1
as kernel.s -o kernel.o
as isr.s -o isr.o

gcc -Wall -c ckernel.c -o ckernel.o -O1 -s
gcc -Wall -c video.c -o video.o -O1 -s
gcc -Wall -c math.c -o math.o -O1 -s
gcc -Wall -c util.c -o util.o -O1 -s
gcc -Wall -c gdt.c -o gdt.o -s
gcc -Wall -c idt.c -o idt.o -s
gcc -Wall -c isrs.c -o isrs.o -s
gcc -Wall -c irq.c -o irq.o -s
gcc -Wall -c timer.c -o timer.o -s
gcc -Wall -c keyboard.c -o keyboard.o -s
ld -Ttext 0x8000 -e _start kernel.o isr.o ckernel.o video.o gdt.o idt.o isrs.o irq.o util.o math.o timer.o keyboard.o -o ckernel.exe
objcopy --strip-all --output-target binary ckernel.exe ckernel.bin
cmd /c copy /b boot.bin + ckernel.bin MyOS

cmd /c del MyOS.bin
cmd /c rename MyOS MyOS.bin
cmd /c erase ..\MyOS.bin
cmd /c copy MyOS.bin ..\MyOS.bin
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
all:
    @echo Select target: mingw or djgpp.
    @echo Exit.

djgpp:
    @echo Building with djgpp:
    c:\djgpp\bin\as boot.s -o boot.o
    c:\djgpp\bin\ld boot.o -Ttext 0x7C00 -e _start -o boot.exe
    c:\djgpp\bin\objcopy --strip-all --only-section .text --output-target binary boot.exe boot.bin
    c:\djgpp\bin\as kernel.s -o kernel.o
    c:\djgpp\bin\as isr.s -o isr.o
   
    c:\djgpp\bin\gcc -Wall -c ckernel.c -o ckernel.o -O1  
    c:\djgpp\bin\gcc -Wall -c video.c -o video.o -O1
    c:\djgpp\bin\gcc -Wall -c math.c -o math.o -O1
    c:\djgpp\bin\gcc -Wall -c util.c -o util.o -O1
    c:\djgpp\bin\gcc -Wall -c gdt.c -o gdt.o
    c:\djgpp\bin\gcc -Wall -c idt.c -o idt.o
    c:\djgpp\bin\gcc -Wall -c isrs.c -o isrs.o
    c:\djgpp\bin\gcc -Wall -c irq.c -o irq.o
    c:\djgpp\bin\gcc -Wall -c timer.c -o timer.o
    c:\djgpp\bin\gcc -Wall -c keyboard.c -o keyboard.o
    c:\djgpp\bin\ld -T kernel.ld kernel.o isr.o ckernel.o video.o gdt.o idt.o isrs.o irq.o util.o math.o timer.o keyboard.o -o ckernel.bin
   
    cmd /c copy /b boot.bin + ckernel.bin MyOS    
   
    cmd /c del MyOS.bin
    cmd /c rename MyOS MyOS.bin
    cmd /c erase ..\MyOS.bin
    cmd /c copy MyOS.bin ..\MyOS.bin

mingw:
    @echo Building with mingw:
    as boot.s -o boot.o
    ld boot.o -Ttext 0x7C00 -e _start -o boot.exe
    objcopy --strip-all --only-section .text --output-target binary boot.exe boot2.bin
    dd if=boot2.bin of=boot.bin bs=512 count=1
    as kernel.s -o kernel.o
    as isr.s -o isr.o
   
    gcc -Wall -c ckernel.c -o ckernel.o -O1 -s
    gcc -Wall -c video.c -o video.o -O1 -s
    gcc -Wall -c math.c -o math.o -O1 -s
    gcc -Wall -c util.c -o util.o -O1 -s
    gcc -Wall -c gdt.c -o gdt.o -s
    gcc -Wall -c idt.c -o idt.o -s
    gcc -Wall -c isrs.c -o isrs.o -s
    gcc -Wall -c irq.c -o irq.o -s
    gcc -Wall -c timer.c -o timer.o -s
    gcc -Wall -c keyboard.c -o keyboard.o -s
    ld -Ttext 0x8000 -e _start kernel.o isr.o ckernel.o video.o gdt.o idt.o isrs.o irq.o util.o math.o timer.o keyboard.o -o ckernel.exe
    objcopy --strip-all --output-target binary ckernel.exe ckernel.bin
    cmd /c copy /b boot.bin + ckernel.bin MyOS    
   
    cmd /c del MyOS.bin
    cmd /c rename MyOS MyOS.bin
    cmd /c erase ..\MyOS.bin
    cmd /c copy MyOS.bin ..\MyOS.bin

Das einzige Programm, das nicht Teil von DJGPP und mingw ist, ist dd. Ich weiss nicht, wie man unter WinXP eine fest definierte Anzahl von Bytes aus einer Datei in eine andere kopieren kann, also habe ich dd benutzt, was ja von *nix stammt. Wie dem auch sei, so scheint zu gehen, ohne nasm...
Ein Nachteil bezüglich mingw ist noch, dass AntiVir bei von mingw as erzeugten Dateien meckert, sind angeblich irgendwelche Trojanische Pferde :D

Erhard Henkes schrieb:

Was abc.w anspricht ist mein Hin- und Herhüpfen zwischen C-Code (vor allem zum Thema Interrupts) und isr.asm.

Genauer meine ich, dass der gcc spezifische inline-Code in den c-Dateien nicht schön ist, weil, nun, sehr gcc spezifisch...
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 19:23:48 05.04.2009   Titel:              Zitieren

Kann GAS nicht inzwischen auch Intel-Syntax? Das wuerde die Sache sicher vereinfachen.

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 19:36:54 05.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Ja, gute Idee, habe es umgesetzt. Thanks @ +fricky.

keine ursache. später aber, wenn du mal multitasking machen willst, kannste die funktion so nicht mehr verwenden. dann besser einen counter in den 'task control block' (der struct, die den zustand einer task kontrolliert) einbauen, und beim warten nicht einfach rechenzeit verbraten, sondern zur nächten task weiterschalten (plus einer möglichkeit, den 'wait' abbrechen zu können, z.b. von einer anderen task oder aus einem interrupt).
:)
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 19:38:56 05.04.2009   Titel:              Zitieren

Nobuo T schrieb:
Kann GAS nicht inzwischen auch Intel-Syntax? Das wuerde die Sache sicher vereinfachen.

echt, ne? diese bescheuerte at&t-syntax würde mich auch völlig nerven. welcher gehirnamputierte hat sich das bloss ausgedacht?
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:44:37 05.04.2009   Titel:              Zitieren

Zitat:
boot.asm, kernel.asm und isr.asm nach AT&T umgesetzt

Würdest Du mir diese Files bitte schicken oder - noch besser - hier posten? Damit ich die AT&T Syntax endlich besser lerne, denn isr.asm könnte man vielleicht auch weitgehend oder völlig in den C-Modulen aufgehen lassen, falls das bezüglich Ordnung mehr Sinn macht. Für mich ist z.B. die Intel Syntax eindeutig besser lesbar.

Das sieht doch irgendwie unnötig kompliziert aus:
C/C++ Code:
static void idt_load(){ asm volatile("lidt %0" : "=m" (idt_register)); } // load IDT register (IDTR)
C/C++ Code:
static void idt_load(){ asm volatile("lidt %0" : "=m" (idt_register)); } // load IDT register (IDTR)
C/C++ Code:
static void idt_load(){ asm volatile("lidt %0" : "=m" (idt_register)); } // load IDT register (IDTR)


Zitat:
Das einzige Programm, das nicht Teil von DJGPP und mingw ist, ist dd. Ich weiss nicht, wie man unter WinXP eine fest definierte Anzahl von Bytes aus einer Datei in eine andere kopieren kann.

Nicht-Linux-User kennen dd nicht, verwenden partcopy (das ist, was Du anstelle dd suchst) oder rawwrite.

Ich bin da aber flexibel, nur möchte ich alles auf MS Windows ermöglichen, was ja bisher keinerlei Problem ist.

Ich möchte auch den Hinweis auf gvim (am Anfang fand ich das nicht uninteressant , weil OSDEV bezüglich des Flairs eher archaische Instrumente benötigt. :D ) verwerfen, weil notepad++ besser aussieht und weniger störrisch ist. Seht ihr das ähnlich? :confused:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:51:58 05.04.2009, insgesamt 2-mal bearbeitet
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 19:52:13 05.04.2009   Titel:              Zitieren

+fricky schrieb:
Nobuo T schrieb:
Kann GAS nicht inzwischen auch Intel-Syntax? Das wuerde die Sache sicher vereinfachen.

echt, ne? diese bescheuerte at&t-syntax würde mich auch völlig nerven. welcher gehirnamputierte hat sich das bloss ausgedacht?
:)

Total! :D :live:
Wahrscheinlich irgendein weltfremder, idealistischer, langhaariger Linux-Frickler mit Strick-Polunder und Taxischein. :cool:


Erhard Henkes schrieb:
Ich möchte auch den Hinweis auf gvim (am Anfang fand ich das nicht uninteressant , weil OSDEV bezüglich des Flairs eher archaische Instrumente benötigt. :D ) verwerfen, weil notepad++ besser aussieht und weniger störrisch ist. Seht ihr das ähnlich? :confused:

Wie ich das sehe, kann man sich vielleicht denken. :)

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908


Zuletzt bearbeitet von Nobuo T am 19:55:55 05.04.2009, insgesamt 1-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 19:54:59 05.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Ich möchte auch den Hinweis auf gvim (am Anfang fand ich das nicht uninteressant , weil OSDEV bezüglich des Flairs eher archaische Instrumente benötigt. :D ) verwerfen, weil notepad++ besser aussieht und weniger störrisch ist. Seht ihr das ähnlich?

klar, wenn man assembler-code auf tiefster low-level ebene schreibt, muss man noch lange keine prähistorischen tools verwenden.
:)
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 20:10:32 05.04.2009   Titel:              Zitieren

Bezüglich der Assembler-Dateien in AT&T, die Kommentare sind alle unverändert. boot.s (hier habe ich, glaube, nur die Anzahl der Sektoren auf 40 geändert):
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
.global _start
.section .text
.code16

.equ kernel_start, _start + 1024

##################################
# setup a stack and segment regs #
##################################

_start:
    xorw %ax, %ax
    movw %ax, %ds
    movw %ax, %es
    movw %ax, %ss
    movw %ax, %sp

################################
# read kernel from floppy disk #
################################

    movb %dl, bootdrive # boot drive stored by BIOS in DL.
                        # we save it to [bootdrive] to play for safety.

load_kernel:
    xorw %ax, %ax       # mov ax, 0  => function "reset"
    int $0x13        
    jc load_kernel      # trouble? try again

    mov $0x8000, %bx    # set up start address of kernel

    # set parameters for reading function
    # 8-bit-wise for better overview
    movb bootdrive, %dl # select boot drive
    mov $40, %al        # read 40 sectors
    mov $0, %ch         # cylinder = 0
    mov $2, %cl         # sector   = 2
    mov $0, %dh         # head     = 0
    mov $2, %ah         # function "read"
    int $0x13        
    jc load_kernel      # trouble? try again

    # show loading message
    mov $loadmsg, %si
    call print_string

##################
# jump to kernel #
##################

    jmp kernel_start    # address of kernel. "jmp bx" might also work.

#######################
# call "print_string" #
#######################
 
print_string:
    mov $0x0E, %ah    # VGA BIOS fnct. 0x0E: teletype
1:  
    lodsb             # grab a byte from SI
    testb %al, %al    # NUL?
    jz 2f             # if the result is zero, get out
    int $0x10         # otherwise, print out the character!
    jmp 1b
2:
    ret

########
# data #
########

bootdrive: .byte 0    # boot drive
loadmsg: .asciz "bootloader message: loading kernel ...\n\r"

. = _start + 510

.byte 0x55
.byte 0xAA

.end
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
.global _start
.section .text
.code16

.equ kernel_start, _start + 1024

##################################
# setup a stack and segment regs #
##################################

_start:
xorw %ax, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
movw %ax, %sp

################################
# read kernel from floppy disk #
################################

movb %dl, bootdrive # boot drive stored by BIOS in DL.
# we save it to [bootdrive] to play for safety.

load_kernel:
xorw %ax, %ax # mov ax, 0 => function "reset"
int $0x13
jc load_kernel # trouble? try again

mov $0x8000, %bx # set up start address of kernel

# set parameters for reading function
# 8-bit-wise for better overview
movb bootdrive, %dl # select boot drive
mov $40, %al # read 40 sectors
mov $0, %ch # cylinder = 0
mov $2, %cl # sector = 2
mov $0, %dh # head = 0
mov $2, %ah # function "read"
int $0x13
jc load_kernel # trouble? try again

# show loading message
mov $loadmsg, %si
call print_string

##################
# jump to kernel #
##################

jmp kernel_start # address of kernel. "jmp bx" might also work.

#######################
# call "print_string" #
#######################

print_string:
mov $0x0E, %ah # VGA BIOS fnct. 0x0E: teletype
1:
lodsb # grab a byte from SI
testb %al, %al # NUL?
jz 2f # if the result is zero, get out
int $0x10 # otherwise, print out the character!
jmp 1b
2:
ret

########
# data #
########

bootdrive: .byte 0 # boot drive
loadmsg: .asciz "bootloader message: loading kernel ...\n\r"

. = _start + 510

.byte 0x55
.byte 0xAA

.end
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
.global _start
.section .text
.code16

.equ kernel_start, _start + 1024

##################################
# setup a stack and segment regs #
##################################

_start:
    xorw %ax, %ax
    movw %ax, %ds
    movw %ax, %es
    movw %ax, %ss
    movw %ax, %sp

################################
# read kernel from floppy disk #
################################

    movb %dl, bootdrive # boot drive stored by BIOS in DL.
                        # we save it to [bootdrive] to play for safety.

load_kernel:
    xorw %ax, %ax       # mov ax, 0  => function "reset"
    int $0x13        
    jc load_kernel      # trouble? try again

    mov $0x8000, %bx    # set up start address of kernel

    # set parameters for reading function
    # 8-bit-wise for better overview
    movb bootdrive, %dl # select boot drive
    mov $40, %al        # read 40 sectors
    mov $0, %ch         # cylinder = 0
    mov $2, %cl         # sector   = 2
    mov $0, %dh         # head     = 0
    mov $2, %ah         # function "read"
    int $0x13        
    jc load_kernel      # trouble? try again

    # show loading message
    mov $loadmsg, %si
    call print_string

##################
# jump to kernel #
##################

    jmp kernel_start    # address of kernel. "jmp bx" might also work.

#######################
# call "print_string" #
#######################
 
print_string:
    mov $0x0E, %ah    # VGA BIOS fnct. 0x0E: teletype
1:  
    lodsb             # grab a byte from SI
    testb %al, %al    # NUL?
    jz 2f             # if the result is zero, get out
    int $0x10         # otherwise, print out the character!
    jmp 1b
2:
    ret

########
# data #
########

bootdrive: .byte 0    # boot drive
loadmsg: .asciz "bootloader message: loading kernel ...\n\r"

. = _start + 510

.byte 0x55
.byte 0xAA

.end


Die Datei kernel.s:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
###############################################
# HenkesSoft 0.04 (version from Mar 26, 2009) #
###############################################

.global RealMode
.global _start
.section .text
.code16

#############
# Real Mode #
#############

_start:
RealMode:
    xorw %ax, %ax         # set up segments
    mov %ax, %es
    mov %ax, %ds
    mov %ax, %ss
    mov %ax, %sp

    mov $welcome, %si
    call print_string

    addw $-0x40, %sp    # make room for input buffer (64 chars)
   
loop_start:
    mov $prompt, %si    # show prompt
    call print_string

    mov %sp, %di        # get input
    call get_string
    jcxz loop_start   # blank line? -> yes, ignore it  

    mov %sp, %si
    mov $cmd_hi, %di    # "hi" command
    call strcmp
    je helloworld

    mov %sp, %si
    mov $cmd_help, %di  # "help" command
    call strcmp
    je help

    mov %sp, %si
    mov $cmd_questionmark, %di  # "?" command
    call strcmp
    je help
 
    mov %sp, %si
    mov $cmd_exit, %di  # "exit" command
    call strcmp
    je exit

    mov %sp, %si
    mov $cmd_pm, %di    # "pm (protected mode)" command
    call strcmp
    je pm

    mov $badcommand, %si # unknown command
    call print_string
    jmp loop_start

helloworld:
    mov $msg_helloworld, %si
    call print_string
    jmp loop_start

help:
    mov $msg_help, %si
    call print_string
    jmp loop_start

exit:
    mov $msg_exit, %si
    call print_string
    xorw %ax, %ax
    int $0x16          # Wait for keystroke
    jmp $0xffff, $0x0000 # Reboot

pm:
    call clrscr
    mov $msg_pm, %si
    call print_string
    call Waitingloop

    cli               # clear interrupts

    lgdt gdtr         # load GDT via GDTR

# we actually only need to do this ONCE, but for now it doesn't hurt to do this more often when
# switching between RM and PM
    inb $0x92, %al       # switch A20 gate via fast A20 port 92
    cmpb $0xFF, %al     # if it reads 0xFF, nothing's implemented on this port
    je 1f
   
    orb $2, %al         # set A20_Gate_Bit (bit 1)
    andb $0xFE, %al     # clear INIT_NOW bit (don't reset pc...)
    outb %al, $0x92
    jmp 2f
1:         # no fast shortcut -> use the slow kbc...
    call empty_8042  
   
    movb 0xD1, %al      # kbc command: write to output port
    outb %al, $0x64
    call empty_8042
   
    movb $0xDF, %al     # writing this to kbc output port enables A20
    outb %al, $0x60
    call empty_8042
2:
    mov %cr0, %eax      # switch-over to Protected Mode
    orl $1, %eax        # set bit 0 of CR0 register
    movl %eax, %cr0

jump_to_protected_mode:
    ljmp $8, $ProtectedMode
 
#########
# Calls #
#########

empty_8042:
    call Waitingloop
    inb $0x64, %al
    cmpb $0xFF, %al     # ... no real kbc at all?
    je 1f
   
    testb $1, %al       # something in input buffer?
    jz 2f
    call Waitingloop
    inb $0x60, %al       # yes: read buffer
    jmp empty_8042      # and try again
2:
    testb $2, %al       # command buffer empty?
    jnz empty_8042      # no: we can't send anything new till it's empty
1:
    ret

print_string:
    movb $0x0E, %ah
1:
    lodsb               # grab a byte from SI
    testb %al, %al      # test AL
    jz 2f               # if the result is zero, get out
    int $0x10           # otherwise, print out the character!
    jmp 1b
2:
    ret

get_string:
    xorw %cx, %cx
1:
    xorw %ax, %ax
    int $0x16           # wait for keypress
    cmpb $8, %al        # backspace pressed?
    je 2f               # yes, handle it
    cmpb $13, %al       # enter pressed?
    je 3f               # yes, we're done
    cmpb $63, %cl       # 63 chars inputted?
    je 1b               # yes, only let in backspace and enter
    movb $0x0E, %ah
    int $0x10           # print out character
    stosb               # put character in buffer
    inc %cx
    jmp 1b

2:
    jcxz 1b             # zero? (start of the string) if yes, ignore the key
    dec %di
    movb $0, (%di)      # delete character
    dec %cx             # decrement counter as well
    movb $0x0E, %ah
    int $0x10           # backspace on the screen
    movb $32, %al
    int $0x10           # blank character out
    movb $8, %al
    int $0x10           # backspace again
    jmp 1b              # go to the main loop

3:
    movb $0, (%di)      # null terminator
    movw $0x0E0D, %ax
    int $0x10
    movb $0x0A, %al
    int $0x10           # newline
    ret

strcmp:
1:
    movb (%si), %al       # grab a byte from SI
    cmpb (%di), %al       # are SI and DI equal?
    jne 2f          # no, we're done.

    testb %al, %al        # zero?
    jz 2f           # yes, we're done.

    inc %di             # increment DI
    inc %si             # increment SI
    jmp 1b             # loop!

2:  
    ret

clrscr:
    movw $0x0600, %ax
    xorw %cx, %cx
    mov $0x174F, %dx
    mov $0x07, %bh
    int $0x10
    ret

##################
# Protected Mode #
##################

.section .text
.code32

.p2align 4

ProtectedMode:
    movw $0x10, %ax
    mov %ax, %ds      # data descriptor --> data, stack and extra segment
    mov %ax, %ss
    mov %ax, %es
    xorl %eax, %eax    # null desriptor --> FS and GS
    mov %ax, %fs
    mov %ax, %gs
    mov $0x200000, %esp # set stack below 2 MB limit

    call clrscr_32
    movb $0x01, %ah
1:
    call Waitingloop
    incb %ah
    andb $0x0F, %ah
    mov $msg_pm2, %esi   # 'OS currently uses Protected Mode.'
    call PutStr_32
    cmpl $(25 * 80 * 2 + 0xB8000), PutStr_Ptr
    jb 1b
    movl $0xB8000, PutStr_Ptr   # text pointer wrap-arround

  call _kernel_main # ->-> C-Kernel
  jmp .
   


Waitingloop:                  
    mov $0x9FFFF, %ebx
1:
    dec %ebx    
    jnz 1b
    ret        

PutStr_32:    
    movl PutStr_Ptr, %edi
1:
    lodsb
    testb %al, %al
    jz 2f
    stosw
    jmp 1b
2:
    movl %edi, PutStr_Ptr
    ret

clrscr_32:
    movl $0xb8000, %edi
    movl %edi, PutStr_Ptr
    movl $1000, %ecx
    movl $0x07200720, %eax
    rep stosl
    ret
 
PutStr_Ptr: .long 0xb8000
   
# You load the address you want to output to in [PutStr_Ptr],
# the address of the string (has to be NUL terminated)
# you want to print in esi and the attributes in ah
# lodsb loads one byte from esi into al, then increments esi,
# then it checks for a NUL terminator,
# then it moves the char into the write position in video memory,
# then increments edi and writes the attributes,
# loops until it finds NUL pointer at which point it breaks ...

###########
# Strings #
###########

welcome: .asciz "HenkesSoft 0.05 (test version from Apr 03, 2009)\n\r"
msg_helloworld: .asciz "Hello World!\n\r"
badcommand: .asciz "Command unknown.\n\r"
prompt: .asciz ">"
cmd_hi: .asciz "hi"
cmd_help: .asciz "help"
cmd_questionmark: .asciz "?"
cmd_exit: .asciz "exit"
cmd_pm: .asciz "pm"
msg_help: .asciz "Commands: hi, help, ?, pm, exit\n\r"
msg_exit: .asciz "Reboot starts now. Enter keystroke, please.\n\r"
msg_pm: .asciz "Switch-over to Protected Mode.\n\r"
msg_pm2: .asciz "OS currently uses Protected Mode.  "

############
# Includes #
############

###################################
## Global Descriptor Table (GDT) ##
###################################

NULL_Desc:
.long 0
.long 0
   
CODE_Desc:
.word 0xFFFF    # segment length  bits 0-15 ("limit")    
.word 0         # segment base    byte 0,1      
.byte 0         # segment base    byte 2    
.byte 0b10011010    # access rights
.byte 0b11001111    # bit 7-4: 4 flag bits:  granularity, default operation size bit, 2 bits available for OS
                    # bit 3-0: segment length bits 16-19
.byte 0             # segment base    byte 3    

DATA_Desc:
.word 0xFFFF        # segment length  bits 0-15
.word 0             # segment base    byte 0,1
.byte 0             # segment base    byte 2
.byte 0b10010010    # access rights
.byte 0b11001111    # bit 7-4: 4 flag bits:  granularity, big bit (0=USE16-Segm., 1=USE32-Segm.), 2 bits avail.
                    # bit 3-0: segment length bits 16-19
.byte 0             # segment base    byte 3      

gdtr:
Limit: .word 24     # length of GDT
Base: .long NULL_Desc    # base of GDT ( linear address: RM Offset + Seg<<4 )
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
###############################################
# HenkesSoft 0.04 (version from Mar 26, 2009) #
###############################################

.global RealMode
.global _start
.section .text
.code16

#############
# Real Mode #
#############

_start:
RealMode:
xorw %ax, %ax # set up segments
mov %ax, %es
mov %ax, %ds
mov %ax, %ss
mov %ax, %sp

mov $welcome, %si
call print_string

addw $-0x40, %sp # make room for input buffer (64 chars)

loop_start:
mov $prompt, %si # show prompt
call print_string

mov %sp, %di # get input
call get_string
jcxz loop_start # blank line? -> yes, ignore it

mov %sp, %si
mov $cmd_hi, %di # "hi" command
call strcmp
je helloworld

mov %sp, %si
mov $cmd_help, %di # "help" command
call strcmp
je help

mov %sp, %si
mov $cmd_questionmark, %di # "?" command
call strcmp
je help

mov %sp, %si
mov $cmd_exit, %di # "exit" command
call strcmp
je exit

mov %sp, %si
mov $cmd_pm, %di # "pm (protected mode)" command
call strcmp
je pm

mov $badcommand, %si # unknown command
call print_string
jmp loop_start

helloworld:
mov $msg_helloworld, %si
call print_string
jmp loop_start

help:
mov $msg_help, %si
call print_string
jmp loop_start

exit:
mov $msg_exit, %si
call print_string
xorw %ax, %ax
int $0x16 # Wait for keystroke
jmp $0xffff, $0x0000 # Reboot

pm:
call clrscr
mov $msg_pm, %si
call print_string
call Waitingloop

cli # clear interrupts

lgdt gdtr # load GDT via GDTR

# we actually only need to do this ONCE, but for now it doesn't hurt to do this more often when
# switching between RM and PM
inb $0x92, %al # switch A20 gate via fast A20 port 92
cmpb $0xFF, %al # if it reads 0xFF, nothing's implemented on this port
je 1f

orb $2, %al # set A20_Gate_Bit (bit 1)
andb $0xFE, %al # clear INIT_NOW bit (don't reset pc...)
outb %al, $0x92
jmp 2f
1: # no fast shortcut -> use the slow kbc...
call empty_8042

movb 0xD1, %al # kbc command: write to output port
outb %al, $0x64
call empty_8042

movb $0xDF, %al # writing this to kbc output port enables A20
outb %al, $0x60
call empty_8042
2:
mov %cr0, %eax # switch-over to Protected Mode
orl $1, %eax # set bit 0 of CR0 register
movl %eax, %cr0

jump_to_protected_mode:
ljmp $8, $ProtectedMode

#########
# Calls #
#########

empty_8042:
call Waitingloop
inb $0x64, %al
cmpb $0xFF, %al # ... no real kbc at all?
je 1f

testb $1, %al # something in input buffer?
jz 2f
call Waitingloop
inb $0x60, %al # yes: read buffer
jmp empty_8042 # and try again
2:
testb $2, %al # command buffer empty?
jnz empty_8042 # no: we can't send anything new till it's empty
1:
ret

print_string:
movb $0x0E, %ah
1:
lodsb # grab a byte from SI
testb %al, %al # test AL
jz 2f # if the result is zero, get out
int $0x10 # otherwise, print out the character!
jmp 1b
2:
ret

get_string:
xorw %cx, %cx
1:
xorw %ax, %ax
int $0x16 # wait for keypress
cmpb $8, %al # backspace pressed?
je 2f # yes, handle it
cmpb $13, %al # enter pressed?
je 3f # yes, we're done
cmpb $63, %cl # 63 chars inputted?
je 1b # yes, only let in backspace and enter
movb $0x0E, %ah
int $0x10 # print out character
stosb # put character in buffer
inc %cx
jmp 1b

2:
jcxz 1b # zero? (start of the string) if yes, ignore the key
dec %di
movb $0, (%di) # delete character
dec %cx # decrement counter as well
movb $0x0E, %ah
int $0x10 # backspace on the screen
movb $32, %al
int $0x10 # blank character out
movb $8, %al
int $0x10 # backspace again
jmp 1b # go to the main loop

3:
movb $0, (%di) # null terminator
movw $0x0E0D, %ax
int $0x10
movb $0x0A, %al
int $0x10 # newline
ret

strcmp:
1:
movb (%si), %al # grab a byte from SI
cmpb (%di), %al # are SI and DI equal?
jne 2f # no, we're done.

testb %al, %al # zero?
jz 2f # yes, we're done.

inc %di # increment DI
inc %si # increment SI
jmp 1b # loop!

2:
ret

clrscr:
movw $0x0600, %ax
xorw %cx, %cx
mov $0x174F, %dx
mov $0x07, %bh
int $0x10
ret

##################
# Protected Mode #
##################

.section .text
.code32

.p2align 4

ProtectedMode:
movw $0x10, %ax
mov %ax, %ds # data descriptor --> data, stack and extra segment
mov %ax, %ss
mov %ax, %es
xorl %eax, %eax # null desriptor --> FS and GS
mov %ax, %fs
mov %ax, %gs
mov $0x200000, %esp # set stack below 2 MB limit

call clrscr_32
movb $0x01, %ah
1:
call Waitingloop
incb %ah
andb $0x0F, %ah
mov $msg_pm2, %esi # 'OS currently uses Protected Mode.'
call PutStr_32
cmpl $(25 * 80 * 2 + 0xB8000), PutStr_Ptr
jb 1b
movl $0xB8000, PutStr_Ptr # text pointer wrap-arround

call _kernel_main # ->-> C-Kernel
jmp .



Waitingloop:
mov $0x9FFFF, %ebx
1:
dec %ebx
jnz 1b
ret

PutStr_32:
movl PutStr_Ptr, %edi
1:
lodsb
testb %al, %al
jz 2f
stosw
jmp 1b
2:
movl %edi, PutStr_Ptr
ret

clrscr_32:
movl $0xb8000, %edi
movl %edi, PutStr_Ptr
movl $1000, %ecx
movl $0x07200720, %eax
rep stosl
ret

PutStr_Ptr: .long 0xb8000

# You load the address you want to output to in [PutStr_Ptr],
# the address of the string (has to be NUL terminated)
# you want to print in esi and the attributes in ah
# lodsb loads one byte from esi into al, then increments esi,
# then it checks for a NUL terminator,
# then it moves the char into the write position in video memory,
# then increments edi and writes the attributes,
# loops until it finds NUL pointer at which point it breaks ...

###########
# Strings #
###########

welcome: .asciz "HenkesSoft 0.05 (test version from Apr 03, 2009)\n\r"
msg_helloworld: .asciz "Hello World!\n\r"
badcommand: .asciz "Command unknown.\n\r"
prompt: .asciz ">"
cmd_hi: .asciz "hi"
cmd_help: .asciz "help"
cmd_questionmark: .asciz "?"
cmd_exit: .asciz "exit"
cmd_pm: .asciz "pm"
msg_help: .asciz "Commands: hi, help, ?, pm, exit\n\r"
msg_exit: .asciz "Reboot starts now. Enter keystroke, please.\n\r"
msg_pm: .asciz "Switch-over to Protected Mode.\n\r"
msg_pm2: .asciz "OS currently uses Protected Mode. "

############
# Includes #
############

###################################
## Global Descriptor Table (GDT) ##
###################################

NULL_Desc:
.long 0
.long 0

CODE_Desc:
.word 0xFFFF # segment length bits 0-15 ("limit")
.word 0 # segment base byte 0,1
.byte 0 # segment base byte 2
.byte 0b10011010 # access rights
.byte 0b11001111 # bit 7-4: 4 flag bits: granularity, default operation size bit, 2 bits available for OS
# bit 3-0: segment length bits 16-19
.byte 0 # segment base byte 3

DATA_Desc:
.word 0xFFFF # segment length bits 0-15
.word 0 # segment base byte 0,1
.byte 0 # segment base byte 2
.byte 0b10010010 # access rights
.byte 0b11001111 # bit 7-4: 4 flag bits: granularity, big bit (0=USE16-Segm., 1=USE32-Segm.), 2 bits avail.
# bit 3-0: segment length bits 16-19
.byte 0 # segment base byte 3

gdtr:
Limit: .word 24 # length of GDT
Base: .long NULL_Desc # base of GDT ( linear address: RM Offset + Seg<<4 )
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
###############################################
# HenkesSoft 0.04 (version from Mar 26, 2009) #
###############################################

.global RealMode
.global _start
.section .text
.code16

#############
# Real Mode #
#############

_start:
RealMode:
    xorw %ax, %ax         # set up segments
    mov %ax, %es
    mov %ax, %ds
    mov %ax, %ss
    mov %ax, %sp

    mov $welcome, %si
    call print_string

    addw $-0x40, %sp    # make room for input buffer (64 chars)
   
loop_start:
    mov $prompt, %si    # show prompt
    call print_string

    mov %sp, %di        # get input
    call get_string
    jcxz loop_start   # blank line? -> yes, ignore it  

    mov %sp, %si
    mov $cmd_hi, %di    # "hi" command
    call strcmp
    je helloworld

    mov %sp, %si
    mov $cmd_help, %di  # "help" command
    call strcmp
    je help

    mov %sp, %si
    mov $cmd_questionmark, %di  # "?" command
    call strcmp
    je help
 
    mov %sp, %si
    mov $cmd_exit, %di  # "exit" command
    call strcmp
    je exit

    mov %sp, %si
    mov $cmd_pm, %di    # "pm (protected mode)" command
    call strcmp
    je pm

    mov $badcommand, %si # unknown command
    call print_string
    jmp loop_start

helloworld:
    mov $msg_helloworld, %si
    call print_string
    jmp loop_start

help:
    mov $msg_help, %si
    call print_string
    jmp loop_start

exit:
    mov $msg_exit, %si
    call print_string
    xorw %ax, %ax
    int $0x16          # Wait for keystroke
    jmp $0xffff, $0x0000 # Reboot

pm:
    call clrscr
    mov $msg_pm, %si
    call print_string
    call Waitingloop

    cli               # clear interrupts

    lgdt gdtr         # load GDT via GDTR

# we actually only need to do this ONCE, but for now it doesn't hurt to do this more often when
# switching between RM and PM
    inb $0x92, %al       # switch A20 gate via fast A20 port 92
    cmpb $0xFF, %al     # if it reads 0xFF, nothing's implemented on this port
    je 1f
   
    orb $2, %al         # set A20_Gate_Bit (bit 1)
    andb $0xFE, %al     # clear INIT_NOW bit (don't reset pc...)
    outb %al, $0x92
    jmp 2f
1:         # no fast shortcut -> use the slow kbc...
    call empty_8042  
   
    movb 0xD1, %al      # kbc command: write to output port
    outb %al, $0x64
    call empty_8042
   
    movb $0xDF, %al     # writing this to kbc output port enables A20
    outb %al, $0x60
    call empty_8042
2:
    mov %cr0, %eax      # switch-over to Protected Mode
    orl $1, %eax        # set bit 0 of CR0 register
    movl %eax, %cr0

jump_to_protected_mode:
    ljmp $8, $ProtectedMode
 
#########
# Calls #
#########

empty_8042:
    call Waitingloop
    inb $0x64, %al
    cmpb $0xFF, %al     # ... no real kbc at all?
    je 1f
   
    testb $1, %al       # something in input buffer?
    jz 2f
    call Waitingloop
    inb $0x60, %al       # yes: read buffer
    jmp empty_8042      # and try again
2:
    testb $2, %al       # command buffer empty?
    jnz empty_8042      # no: we can't send anything new till it's empty
1:
    ret

print_string:
    movb $0x0E, %ah
1:
    lodsb               # grab a byte from SI
    testb %al, %al      # test AL
    jz 2f               # if the result is zero, get out
    int $0x10           # otherwise, print out the character!
    jmp 1b
2:
    ret

get_string:
    xorw %cx, %cx
1:
    xorw %ax, %ax
    int $0x16           # wait for keypress
    cmpb $8, %al        # backspace pressed?
    je 2f               # yes, handle it
    cmpb $13, %al       # enter pressed?
    je 3f               # yes, we're done
    cmpb $63, %cl       # 63 chars inputted?
    je 1b               # yes, only let in backspace and enter
    movb $0x0E, %ah
    int $0x10           # print out character
    stosb               # put character in buffer
    inc %cx
    jmp 1b

2:
    jcxz 1b             # zero? (start of the string) if yes, ignore the key
    dec %di
    movb $0, (%di)      # delete character
    dec %cx             # decrement counter as well
    movb $0x0E, %ah
    int $0x10           # backspace on the screen
    movb $32, %al
    int $0x10           # blank character out
    movb $8, %al
    int $0x10           # backspace again
    jmp 1b              # go to the main loop

3:
    movb $0, (%di)      # null terminator
    movw $0x0E0D, %ax
    int $0x10
    movb $0x0A, %al
    int $0x10           # newline
    ret

strcmp:
1:
    movb (%si), %al       # grab a byte from SI
    cmpb (%di), %al       # are SI and DI equal?
    jne 2f          # no, we're done.

    testb %al, %al        # zero?
    jz 2f           # yes, we're done.

    inc %di             # increment DI
    inc %si             # increment SI
    jmp 1b             # loop!

2:  
    ret

clrscr:
    movw $0x0600, %ax
    xorw %cx, %cx
    mov $0x174F, %dx
    mov $0x07, %bh
    int $0x10
    ret

##################
# Protected Mode #
##################

.section .text
.code32

.p2align 4

ProtectedMode:
    movw $0x10, %ax
    mov %ax, %ds      # data descriptor --> data, stack and extra segment
    mov %ax, %ss
    mov %ax, %es
    xorl %eax, %eax    # null desriptor --> FS and GS
    mov %ax, %fs
    mov %ax, %gs
    mov $0x200000, %esp # set stack below 2 MB limit

    call clrscr_32
    movb $0x01, %ah
1:
    call Waitingloop
    incb %ah
    andb $0x0F, %ah
    mov $msg_pm2, %esi   # 'OS currently uses Protected Mode.'
    call PutStr_32
    cmpl $(25 * 80 * 2 + 0xB8000), PutStr_Ptr
    jb 1b
    movl $0xB8000, PutStr_Ptr   # text pointer wrap-arround

  call _kernel_main # ->-> C-Kernel
  jmp .
   


Waitingloop:                  
    mov $0x9FFFF, %ebx
1:
    dec %ebx    
    jnz 1b
    ret        

PutStr_32:    
    movl PutStr_Ptr, %edi
1:
    lodsb
    testb %al, %al
    jz 2f
    stosw
    jmp 1b
2:
    movl %edi, PutStr_Ptr
    ret

clrscr_32:
    movl $0xb8000, %edi
    movl %edi, PutStr_Ptr
    movl $1000, %ecx
    movl $0x07200720, %eax
    rep stosl
    ret
 
PutStr_Ptr: .long 0xb8000
   
# You load the address you want to output to in [PutStr_Ptr],
# the address of the string (has to be NUL terminated)
# you want to print in esi and the attributes in ah
# lodsb loads one byte from esi into al, then increments esi,
# then it checks for a NUL terminator,
# then it moves the char into the write position in video memory,
# then increments edi and writes the attributes,
# loops until it finds NUL pointer at which point it breaks ...

###########
# Strings #
###########

welcome: .asciz "HenkesSoft 0.05 (test version from Apr 03, 2009)\n\r"
msg_helloworld: .asciz "Hello World!\n\r"
badcommand: .asciz "Command unknown.\n\r"
prompt: .asciz ">"
cmd_hi: .asciz "hi"
cmd_help: .asciz "help"
cmd_questionmark: .asciz "?"
cmd_exit: .asciz "exit"
cmd_pm: .asciz "pm"
msg_help: .asciz "Commands: hi, help, ?, pm, exit\n\r"
msg_exit: .asciz "Reboot starts now. Enter keystroke, please.\n\r"
msg_pm: .asciz "Switch-over to Protected Mode.\n\r"
msg_pm2: .asciz "OS currently uses Protected Mode.  "

############
# Includes #
############

###################################
## Global Descriptor Table (GDT) ##
###################################

NULL_Desc:
.long 0
.long 0
   
CODE_Desc:
.word 0xFFFF    # segment length  bits 0-15 ("limit")    
.word 0         # segment base    byte 0,1      
.byte 0         # segment base    byte 2    
.byte 0b10011010    # access rights
.byte 0b11001111    # bit 7-4: 4 flag bits:  granularity, default operation size bit, 2 bits available for OS
                    # bit 3-0: segment length bits 16-19
.byte 0             # segment base    byte 3    

DATA_Desc:
.word 0xFFFF        # segment length  bits 0-15
.word 0             # segment base    byte 0,1
.byte 0             # segment base    byte 2
.byte 0b10010010    # access rights
.byte 0b11001111    # bit 7-4: 4 flag bits:  granularity, big bit (0=USE16-Segm., 1=USE32-Segm.), 2 bits avail.
                    # bit 3-0: segment length bits 16-19
.byte 0             # segment base    byte 3      

gdtr:
Limit: .word 24     # length of GDT
Base: .long NULL_Desc    # base of GDT ( linear address: RM Offset + Seg<<4 )


Die Datei isr.s:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
# Interrupt Service Routine isr0 ... isr32  
.global _isr0
.global _isr1
.global _isr2
.global _isr3
.global _isr4
.global _isr5
.global _isr6
.global _isr7
.global _isr8
.global _isr9
.global _isr10
.global _isr11
.global _isr12
.global _isr13
.global _isr14
.global _isr15
.global _isr16
.global _isr17
.global _isr18
.global _isr19
.global _isr20
.global _isr21
.global _isr22
.global _isr23
.global _isr24
.global _isr25
.global _isr26
.global _isr27
.global _isr28
.global _isr29
.global _isr30
.global _isr31

.global _irq0
.global _irq1
.global _irq2
.global _irq3
.global _irq4
.global _irq5
.global _irq6
.global _irq7
.global _irq8
.global _irq9
.global _irq10
.global _irq11
.global _irq12
.global _irq13
.global _irq14
.global _irq15

.section .text

#  0: Divide By Zero Exception
_isr0:
    cli
    pushl $0
    pushl $0
    jmp isr_common_stub

#  1: Debug Exception
_isr1:
    cli
    pushl $0
    pushl $1
    jmp isr_common_stub

#  2: Non Maskable Interrupt Exception
_isr2:
    cli
    pushl $0
    pushl $2
    jmp isr_common_stub

#  3: Int 3 Exception
_isr3:
    cli
    pushl $0
    pushl $3
    jmp isr_common_stub

#  4: INTO Exception
_isr4:
    cli
    pushl $0
    pushl $4
    jmp isr_common_stub

#  5: Out of Bounds Exception
_isr5:
    cli
    pushl $0
    pushl $5
    jmp isr_common_stub

#  6: Invalid Opcode Exception
_isr6:
    cli
    pushl $0
    pushl $6
    jmp isr_common_stub

#  7: Coprocessor Not Available Exception
_isr7:
    cli
    pushl $0
    pushl $7
    jmp isr_common_stub

#  8: Double Fault Exception (With Error Code!)
_isr8:
    cli
    pushl $8
    jmp isr_common_stub

#  9: Coprocessor Segment Overrun Exception
_isr9:
    cli
    pushl $0
    pushl $9
    jmp isr_common_stub

# 10: Bad TSS Exception (With Error Code!)
_isr10:
    cli
    pushl $10
    jmp isr_common_stub

# 11: Segment Not Present Exception (With Error Code!)
_isr11:
    cli
    pushl $11
    jmp isr_common_stub

# 12: Stack Fault Exception (With Error Code!)
_isr12:
    cli
    pushl $12
    jmp isr_common_stub

# 13: General Protection Fault Exception (With Error Code!)
_isr13:
    cli
    pushl $13
    jmp isr_common_stub

# 14: Page Fault Exception (With Error Code!)
_isr14:
    cli
    pushl $14
    jmp isr_common_stub

# 15: Reserved Exception
_isr15:
    cli
    pushl $0
    pushl $15
    jmp isr_common_stub

# 16: Floating Point Exception
_isr16:
    cli
    pushl $0
    pushl $16
    jmp isr_common_stub

# 17: Alignment Check Exception
_isr17:
    cli
    pushl $0
    pushl $17
    jmp isr_common_stub

# 18: Machine Check Exception
_isr18:
    cli
    pushl $0
    pushl $18
    jmp isr_common_stub

# 19: Reserved
_isr19:
    cli
    pushl $0
    pushl $19
    jmp isr_common_stub

# 20: Reserved
_isr20:
    cli
    pushl $0
    pushl $20
    jmp isr_common_stub

# 21: Reserved
_isr21:
    cli
    pushl $0
    pushl $21
    jmp isr_common_stub

# 22: Reserved
_isr22:
    cli
    pushl $0
    pushl $22
    jmp isr_common_stub

# 23: Reserved
_isr23:
    cli
    pushl $0
    pushl $23
    jmp isr_common_stub

# 24: Reserved
_isr24:
    cli
    pushl $0
    pushl $24
    jmp isr_common_stub

# 25: Reserved
_isr25:
    cli
    pushl $0
    pushl $25
    jmp isr_common_stub

# 26: Reserved
_isr26:
    cli
    pushl $0
    pushl $26
    jmp isr_common_stub

# 27: Reserved
_isr27:
    cli
    pushl $0
    pushl $27
    jmp isr_common_stub

# 28: Reserved
_isr28:
    cli
    pushl $0
    pushl $28
    jmp isr_common_stub

# 29: Reserved
_isr29:
    cli
    pushl $0
    pushl $29
    jmp isr_common_stub

# 30: Reserved
_isr30:
    cli
    pushl $0
    pushl $30
    jmp isr_common_stub

# 31: Reserved
_isr31:
    cli
    pushl $0
    pushl $31
    jmp isr_common_stub


# Common ISR stub saves processor state, sets up for kernel mode segments, calls the C-level fault handler,
# and finally restores the stack frame.
isr_common_stub:
    pusha
    push %ds
    push %es
    push %fs
    push %gs
    mov $0x10, %ax
    mov %ax, %ds
    mov %ax, %es
    mov %ax, %fs
    mov %ax, %gs
    mov %esp, %eax
    push %eax
    mov $_fault_handler, %eax
    call *%eax
    pop %eax
    pop %gs
    pop %fs
    pop %es
    pop %ds
    popa
    add $8, %esp
    iret

# 32: IRQ0
_irq0:
    cli
    pushl $0
    pushl $32
    jmp irq_common_stub

# 33: IRQ1
_irq1:
    cli
    pushl $0
    pushl $33
    jmp irq_common_stub

# 34: IRQ2
_irq2:
    cli
    pushl $0
    pushl $34
    jmp irq_common_stub

# 35: IRQ3
_irq3:
    cli
    pushl $0
    pushl $35
    jmp irq_common_stub

# 36: IRQ4
_irq4:
    cli
    pushl $0
    pushl $36
    jmp irq_common_stub

# 37: IRQ5
_irq5:
    cli
    pushl $0
    pushl $37
    jmp irq_common_stub

# 38: IRQ6
_irq6:
    cli
    pushl $0
    pushl $38
    jmp irq_common_stub

# 39: IRQ7
_irq7:
    cli
    pushl $0
    pushl $39
    jmp irq_common_stub

# 40: IRQ8
_irq8:
    cli
    pushl $0
    pushl $40
    jmp irq_common_stub

# 41: IRQ9
_irq9:
    cli
    pushl $0
    pushl $41
    jmp irq_common_stub

# 42: IRQ10
_irq10:
    cli
    pushl $0
    pushl $42
    jmp irq_common_stub

# 43: IRQ11
_irq11:
    cli
    pushl $0
    pushl $43
    jmp irq_common_stub

# 44: IRQ12
_irq12:
    cli
    pushl $0
    pushl $44
    jmp irq_common_stub

# 45: IRQ13
_irq13:
    cli
    pushl $0
    pushl $45
    jmp irq_common_stub

# 46: IRQ14
_irq14:
    cli
    pushl $0
    pushl $46
    jmp irq_common_stub

# 47: IRQ15
_irq15:
    cli
    pushl $0
    pushl $47
    jmp irq_common_stub

irq_common_stub:
    pusha
    push %ds
    push %es
    push %fs
    push %gs

    mov $0x10, %ax
    mov %ax, %ds
    mov %ax, %es
    mov %ax, %fs
    mov %ax, %gs
    mov %esp, %eax

    push %eax
    mov $_irq_handler, %eax
    call *%eax
    pop %eax

    pop %gs
    pop %fs
    pop %es
    pop %ds
    popa
    add $8, %esp
    iret
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
# Interrupt Service Routine isr0 ... isr32
.global _isr0
.global _isr1
.global _isr2
.global _isr3
.global _isr4
.global _isr5
.global _isr6
.global _isr7
.global _isr8
.global _isr9
.global _isr10
.global _isr11
.global _isr12
.global _isr13
.global _isr14
.global _isr15
.global _isr16
.global _isr17
.global _isr18
.global _isr19
.global _isr20
.global _isr21
.global _isr22
.global _isr23
.global _isr24
.global _isr25
.global _isr26
.global _isr27
.global _isr28
.global _isr29
.global _isr30
.global _isr31

.global _irq0
.global _irq1
.global _irq2
.global _irq3
.global _irq4
.global _irq5
.global _irq6
.global _irq7
.global _irq8
.global _irq9
.global _irq10
.global _irq11
.global _irq12
.global _irq13
.global _irq14
.global _irq15

.section .text

# 0: Divide By Zero Exception
_isr0:
cli
pushl $0
pushl $0
jmp isr_common_stub

# 1: Debug Exception
_isr1:
cli
pushl $0
pushl $1
jmp isr_common_stub

# 2: Non Maskable Interrupt Exception
_isr2:
cli
pushl $0
pushl $2
jmp isr_common_stub

# 3: Int 3 Exception
_isr3:
cli
pushl $0
pushl $3
jmp isr_common_stub

# 4: INTO Exception
_isr4:
cli
pushl $0
pushl $4
jmp isr_common_stub

# 5: Out of Bounds Exception
_isr5:
cli
pushl $0
pushl $5
jmp isr_common_stub

# 6: Invalid Opcode Exception
_isr6:
cli
pushl $0
pushl $6
jmp isr_common_stub

# 7: Coprocessor Not Available Exception
_isr7:
cli
pushl $0
pushl $7
jmp isr_common_stub

# 8: Double Fault Exception (With Error Code!)
_isr8:
cli
pushl $8
jmp isr_common_stub

# 9: Coprocessor Segment Overrun Exception
_isr9:
cli
pushl $0
pushl $9
jmp isr_common_stub

# 10: Bad TSS Exception (With Error Code!)
_isr10:
cli
pushl $10
jmp isr_common_stub

# 11: Segment Not Present Exception (With Error Code!)
_isr11:
cli
pushl $11
jmp isr_common_stub

# 12: Stack Fault Exception (With Error Code!)
_isr12:
cli
pushl $12
jmp isr_common_stub

# 13: General Protection Fault Exception (With Error Code!)
_isr13:
cli
pushl $13
jmp isr_common_stub

# 14: Page Fault Exception (With Error Code!)
_isr14:
cli
pushl $14
jmp isr_common_stub

# 15: Reserved Exception
_isr15:
cli
pushl $0
pushl $15
jmp isr_common_stub

# 16: Floating Point Exception
_isr16:
cli
pushl $0
pushl $16
jmp isr_common_stub

# 17: Alignment Check Exception
_isr17:
cli
pushl $0
pushl $17
jmp isr_common_stub

# 18: Machine Check Exception
_isr18:
cli
pushl $0
pushl $18
jmp isr_common_stub

# 19: Reserved
_isr19:
cli
pushl $0
pushl $19
jmp isr_common_stub

# 20: Reserved
_isr20:
cli
pushl $0
pushl $20
jmp isr_common_stub

# 21: Reserved
_isr21:
cli
pushl $0
pushl $21
jmp isr_common_stub

# 22: Reserved
_isr22:
cli
pushl $0
pushl $22
jmp isr_common_stub

# 23: Reserved
_isr23:
cli
pushl $0
pushl $23
jmp isr_common_stub

# 24: Reserved
_isr24:
cli
pushl $0
pushl $24
jmp isr_common_stub

# 25: Reserved
_isr25:
cli
pushl $0
pushl $25
jmp isr_common_stub

# 26: Reserved
_isr26:
cli
pushl $0
pushl $26
jmp isr_common_stub

# 27: Reserved
_isr27:
cli
pushl $0
pushl $27
jmp isr_common_stub

# 28: Reserved
_isr28:
cli
pushl $0
pushl $28
jmp isr_common_stub

# 29: Reserved
_isr29:
cli
pushl $0
pushl $29
jmp isr_common_stub

# 30: Reserved
_isr30:
cli
pushl $0
pushl $30
jmp isr_common_stub

# 31: Reserved
_isr31:
cli
pushl $0
pushl $31
jmp isr_common_stub


# Common ISR stub saves processor state, sets up for kernel mode segments, calls the C-level fault handler,
# and finally restores the stack frame.
isr_common_stub:
pusha
push %ds
push %es
push %fs
push %gs
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %esp, %eax
push %eax
mov $_fault_handler, %eax
call *%eax
pop %eax
pop %gs
pop %fs
pop %es
pop %ds
popa
add $8, %esp
iret

# 32: IRQ0
_irq0:
cli
pushl $0
pushl $32
jmp irq_common_stub

# 33: IRQ1
_irq1:
cli
pushl $0
pushl $33
jmp irq_common_stub

# 34: IRQ2
_irq2:
cli
pushl $0
pushl $34
jmp irq_common_stub

# 35: IRQ3
_irq3:
cli
pushl $0
pushl $35
jmp irq_common_stub

# 36: IRQ4
_irq4:
cli
pushl $0
pushl $36
jmp irq_common_stub

# 37: IRQ5
_irq5:
cli
pushl $0
pushl $37
jmp irq_common_stub

# 38: IRQ6
_irq6:
cli
pushl $0
pushl $38
jmp irq_common_stub

# 39: IRQ7
_irq7:
cli
pushl $0
pushl $39
jmp irq_common_stub

# 40: IRQ8
_irq8:
cli
pushl $0
pushl $40
jmp irq_common_stub

# 41: IRQ9
_irq9:
cli
pushl $0
pushl $41
jmp irq_common_stub

# 42: IRQ10
_irq10:
cli
pushl $0
pushl $42
jmp irq_common_stub

# 43: IRQ11
_irq11:
cli
pushl $0
pushl $43
jmp irq_common_stub

# 44: IRQ12
_irq12:
cli
pushl $0
pushl $44
jmp irq_common_stub

# 45: IRQ13
_irq13:
cli
pushl $0
pushl $45
jmp irq_common_stub

# 46: IRQ14
_irq14:
cli
pushl $0
pushl $46
jmp irq_common_stub

# 47: IRQ15
_irq15:
cli
pushl $0
pushl $47
jmp irq_common_stub

irq_common_stub:
pusha
push %ds
push %es
push %fs
push %gs

mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %esp, %eax

push %eax
mov $_irq_handler, %eax
call *%eax
pop %eax

pop %gs
pop %fs
pop %es
pop %ds
popa
add $8, %esp
iret
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
# Interrupt Service Routine isr0 ... isr32  
.global _isr0
.global _isr1
.global _isr2
.global _isr3
.global _isr4
.global _isr5
.global _isr6
.global _isr7
.global _isr8
.global _isr9
.global _isr10
.global _isr11
.global _isr12
.global _isr13
.global _isr14
.global _isr15
.global _isr16
.global _isr17
.global _isr18
.global _isr19
.global _isr20
.global _isr21
.global _isr22
.global _isr23
.global _isr24
.global _isr25
.global _isr26
.global _isr27
.global _isr28
.global _isr29
.global _isr30
.global _isr31

.global _irq0
.global _irq1
.global _irq2
.global _irq3
.global _irq4
.global _irq5
.global _irq6
.global _irq7
.global _irq8
.global _irq9
.global _irq10
.global _irq11
.global _irq12
.global _irq13
.global _irq14
.global _irq15

.section .text

#  0: Divide By Zero Exception
_isr0:
    cli
    pushl $0
    pushl $0
    jmp isr_common_stub

#  1: Debug Exception
_isr1:
    cli
    pushl $0
    pushl $1
    jmp isr_common_stub

#  2: Non Maskable Interrupt Exception
_isr2:
    cli
    pushl $0
    pushl $2
    jmp isr_common_stub

#  3: Int 3 Exception
_isr3:
    cli
    pushl $0
    pushl $3
    jmp isr_common_stub

#  4: INTO Exception
_isr4:
    cli
    pushl $0
    pushl $4
    jmp isr_common_stub

#  5: Out of Bounds Exception
_isr5:
    cli
    pushl $0
    pushl $5
    jmp isr_common_stub

#  6: Invalid Opcode Exception
_isr6:
    cli
    pushl $0
    pushl $6
    jmp isr_common_stub

#  7: Coprocessor Not Available Exception
_isr7:
    cli
    pushl $0
    pushl $7
    jmp isr_common_stub

#  8: Double Fault Exception (With Error Code!)
_isr8:
    cli
    pushl $8
    jmp isr_common_stub

#  9: Coprocessor Segment Overrun Exception
_isr9:
    cli
    pushl $0
    pushl $9
    jmp isr_common_stub

# 10: Bad TSS Exception (With Error Code!)
_isr10:
    cli
    pushl $10
    jmp isr_common_stub

# 11: Segment Not Present Exception (With Error Code!)
_isr11:
    cli
    pushl $11
    jmp isr_common_stub

# 12: Stack Fault Exception (With Error Code!)
_isr12:
    cli
    pushl $12
    jmp isr_common_stub

# 13: General Protection Fault Exception (With Error Code!)
_isr13:
    cli
    pushl $13
    jmp isr_common_stub

# 14: Page Fault Exception (With Error Code!)
_isr14:
    cli
    pushl $14
    jmp isr_common_stub

# 15: Reserved Exception
_isr15:
    cli
    pushl $0
    pushl $15
    jmp isr_common_stub

# 16: Floating Point Exception
_isr16:
    cli
    pushl $0
    pushl $16
    jmp isr_common_stub

# 17: Alignment Check Exception
_isr17:
    cli
    pushl $0
    pushl $17
    jmp isr_common_stub

# 18: Machine Check Exception
_isr18:
    cli
    pushl $0
    pushl $18
    jmp isr_common_stub

# 19: Reserved
_isr19:
    cli
    pushl $0
    pushl $19
    jmp isr_common_stub

# 20: Reserved
_isr20:
    cli
    pushl $0
    pushl $20
    jmp isr_common_stub

# 21: Reserved
_isr21:
    cli
    pushl $0
    pushl $21
    jmp isr_common_stub

# 22: Reserved
_isr22:
    cli
    pushl $0
    pushl $22
    jmp isr_common_stub

# 23: Reserved
_isr23:
    cli
    pushl $0
    pushl $23
    jmp isr_common_stub

# 24: Reserved
_isr24:
    cli
    pushl $0
    pushl $24
    jmp isr_common_stub

# 25: Reserved
_isr25:
    cli
    pushl $0
    pushl $25
    jmp isr_common_stub

# 26: Reserved
_isr26:
    cli
    pushl $0
    pushl $26
    jmp isr_common_stub

# 27: Reserved
_isr27:
    cli
    pushl $0
    pushl $27
    jmp isr_common_stub

# 28: Reserved
_isr28:
    cli
    pushl $0
    pushl $28
    jmp isr_common_stub

# 29: Reserved
_isr29:
    cli
    pushl $0
    pushl $29
    jmp isr_common_stub

# 30: Reserved
_isr30:
    cli
    pushl $0
    pushl $30
    jmp isr_common_stub

# 31: Reserved
_isr31:
    cli
    pushl $0
    pushl $31
    jmp isr_common_stub


# Common ISR stub saves processor state, sets up for kernel mode segments, calls the C-level fault handler,
# and finally restores the stack frame.
isr_common_stub:
    pusha
    push %ds
    push %es
    push %fs
    push %gs
    mov $0x10, %ax
    mov %ax, %ds
    mov %ax, %es
    mov %ax, %fs
    mov %ax, %gs
    mov %esp, %eax
    push %eax
    mov $_fault_handler, %eax
    call *%eax
    pop %eax
    pop %gs
    pop %fs
    pop %es
    pop %ds
    popa
    add $8, %esp
    iret

# 32: IRQ0
_irq0:
    cli
    pushl $0
    pushl $32
    jmp irq_common_stub

# 33: IRQ1
_irq1:
    cli
    pushl $0
    pushl $33
    jmp irq_common_stub

# 34: IRQ2
_irq2:
    cli
    pushl $0
    pushl $34
    jmp irq_common_stub

# 35: IRQ3
_irq3:
    cli
    pushl $0
    pushl $35
    jmp irq_common_stub

# 36: IRQ4
_irq4:
    cli
    pushl $0
    pushl $36
    jmp irq_common_stub

# 37: IRQ5
_irq5:
    cli
    pushl $0
    pushl $37
    jmp irq_common_stub

# 38: IRQ6
_irq6:
    cli
    pushl $0
    pushl $38
    jmp irq_common_stub

# 39: IRQ7
_irq7:
    cli
    pushl $0
    pushl $39
    jmp irq_common_stub

# 40: IRQ8
_irq8:
    cli
    pushl $0
    pushl $40
    jmp irq_common_stub

# 41: IRQ9
_irq9:
    cli
    pushl $0
    pushl $41
    jmp irq_common_stub

# 42: IRQ10
_irq10:
    cli
    pushl $0
    pushl $42
    jmp irq_common_stub

# 43: IRQ11
_irq11:
    cli
    pushl $0
    pushl $43
    jmp irq_common_stub

# 44: IRQ12
_irq12:
    cli
    pushl $0
    pushl $44
    jmp irq_common_stub

# 45: IRQ13
_irq13:
    cli
    pushl $0
    pushl $45
    jmp irq_common_stub

# 46: IRQ14
_irq14:
    cli
    pushl $0
    pushl $46
    jmp irq_common_stub

# 47: IRQ15
_irq15:
    cli
    pushl $0
    pushl $47
    jmp irq_common_stub

irq_common_stub:
    pusha
    push %ds
    push %es
    push %fs
    push %gs

    mov $0x10, %ax
    mov %ax, %ds
    mov %ax, %es
    mov %ax, %fs
    mov %ax, %gs
    mov %esp, %eax

    push %eax
    mov $_irq_handler, %eax
    call *%eax
    pop %eax

    pop %gs
    pop %fs
    pop %es
    pop %ds
    popa
    add $8, %esp
    iret


Nicht zu lange draufgucken, schadet den Augen :D


Zuletzt bearbeitet von abc.w am 22:36:54 05.04.2009, insgesamt 1-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 20:34:27 05.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zitat:
Das einzige Programm, das nicht Teil von DJGPP und mingw ist, ist dd. Ich weiss nicht, wie man unter WinXP eine fest definierte Anzahl von Bytes aus einer Datei in eine andere kopieren kann.

Nicht-Linux-User kennen dd nicht, verwenden partcopy (das ist, was Du anstelle dd suchst) oder rawwrite.
Ich bin da aber flexibel, nur möchte ich alles auf MS Windows ermöglichen, was ja bisher keinerlei Problem ist.

Ich habe grade geguckt, woher ich dd auf meinem System habe... aus dem Verzeichnis C:\Compiler\WinAVR-20081205\utils\bin. Nicht schön. Benutze ein Programm und weiss überhaupt nicht, woher ich es habe. Das kommt davon, wenn man die PATH Variable einfach mal so modifiziert...

Erhard Henkes schrieb:
Ich möchte auch den Hinweis auf gvim (am Anfang fand ich das nicht uninteressant , weil OSDEV bezüglich des Flairs eher archaische Instrumente benötigt. :D ) verwerfen, weil notepad++ besser aussieht und weniger störrisch ist. Seht ihr das ähnlich? :confused:

Ich benutze in letzter Zeit ausschliesslich gvim... :)
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 20:55:45 05.04.2009   Titel:              Zitieren

Nobuo T schrieb:
+fricky schrieb:
Nobuo T schrieb:
Kann GAS nicht inzwischen auch Intel-Syntax? Das wuerde die Sache sicher vereinfachen.

echt, ne? diese bescheuerte at&t-syntax würde mich auch völlig nerven. welcher gehirnamputierte hat sich das bloss ausgedacht?
:)

Total! :D :live:
Wahrscheinlich irgendein weltfremder, idealistischer, langhaariger Linux-Frickler mit Strick-Polunder und Taxischein. :cool:

Ich glaube, AT&T Syntax ist älter als Linux und Intel und GNU zusammen. Ich sehe es so, dass allein aus der Tatsache, dass diese Syntax noch nicht "ausgestorben" ist und eine so lange Periode überdauert hat, muss etwas dahinter stecken. Ich hatte mich am Anfang auch wegen % und $ unbehaglich gefühlt, aber jetzt, sooo schlimm ist das nicht und die Syntax finde ich durchdachter und konsequenter in jeder Hinsicht als jede andere. Wenn wir hier in diesem Thread zurückschauen, wieviele Probleme gab es mit jmp und wieviel Ungewissheit, zumindest bei mir, ob jmp word oder jmp dword, nur weil nasm sowohl das eine als auch das andere erlaubt...
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:08:55 05.04.2009   Titel:              Zitieren

@abc.w: Danke für die Übersetzung von Intel nach AT&T und für das DJGPP / mingw makefile. Es sollte nicht von zu vielen Kleinigkeiten und/oder Geschmacksachen abhängen, ob jemand den Zugang zu OSDEV findet. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:29:50 05.04.2009   Titel:              Zitieren

Nun können System Clock und Keyboard unabhängig den Bildschirm beschmutzen. Die vielen Polling-Endlosschleifen wurden nun gebrochen. Bisher habe ich die Vorschläge von Nobuo T noch nicht eingebaut, sehe aber auch (noch!) keinen Nachteil.
Ich habe den aktuellen Code zum Testen "upgeloadet".

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include "keyboard.h"
#include
"os.h"

int ShiftKeyDown; // Variable for Shift Key Down

/* Wait until buffer is empty */

void keyboard_init()
{
    while (inportb(0x64)&1)
      inportb(0x60);
};

unsigned int FetchAndAnalyzeScancode()
{
    unsigned int scancode; // For getting the keyboard scancode
    while(TRUE) // Loop until a key (w/o shift key) has been pressed
    {
        scancode = inportb(0x60);   // 0x60: get scan code from the keyboard

        if ( scancode & 0x80 ) // Key released? Check bit 7 (10000000b = 0x80) of scan code for this
        {
            scancode &= 0x7F; // Key was released, compare only low seven bits: 01111111b = 0x7F
            if ( scancode == KRLEFT_SHIFT || scancode == KRRIGHT_SHIFT ) // A key was released, shift key up?
            {
                ShiftKeyDown = 0;    // yes, it is up --> NonShift
            }
        }
        else // Key was pressed.
        {
            // Capture scan code of shift key, if pressed
            if ( scancode == KRLEFT_SHIFT || scancode == KRRIGHT_SHIFT )
            {
                ShiftKeyDown = 1; // It is down, use asciiShift characters
                continue; // Loop, so it will not return a scan code for the shift key
            }
        }
        break; // Leave the loop
    }
    return scancode;
}

unsigned char const k_getch() // Scancode --> ASCII
{
    unsigned int scan;          // scancode from the keyboard
    unsigned char retchar;      // The chararacter that returns the scan code to ASCII code
    scan = FetchAndAnalyzeScancode(); // Grab scancode, and get the position of the shift key
    if ( ShiftKeyDown )
        retchar = asciiShift[scan];    // (Upper) Shift Codes
    else
        retchar = asciiNonShift[ scan ]; // (Lower) Non-Shift Codes
    return retchar; // ASCII version
}

void keyboard_handler(struct regs* r)
{
   k_printf("keyboard handler works!", 8, 0x2);

   unsigned char bufferKEY[10];
   bufferKEY[0] = k_getch();
   k_printf(bufferKEY, 10,0xA); // the ASCII character
}

void keyboard_install()
{
    /* Installs 'keyboard_handler' to IRQ1 */
    irq_install_handler(1, keyboard_handler);
    keyboard_init();
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include "keyboard.h"
#include
"os.h"

int ShiftKeyDown; // Variable for Shift Key Down

/* Wait until buffer is empty */

void keyboard_init()
{
while (inportb(0x64)&1)
inportb(0x60);
};

unsigned int FetchAndAnalyzeScancode()
{
unsigned int scancode; // For getting the keyboard scancode
while(TRUE) // Loop until a key (w/o shift key) has been pressed
{
scancode = inportb(0x60); // 0x60: get scan code from the keyboard

if ( scancode & 0x80 ) // Key released? Check bit 7 (10000000b = 0x80) of scan code for this
{
scancode &= 0x7F; // Key was released, compare only low seven bits: 01111111b = 0x7F
if ( scancode == KRLEFT_SHIFT || scancode == KRRIGHT_SHIFT ) // A key was released, shift key up?
{
ShiftKeyDown = 0; // yes, it is up --> NonShift
}
}
else // Key was pressed.
{
// Capture scan code of shift key, if pressed
if ( scancode == KRLEFT_SHIFT || scancode == KRRIGHT_SHIFT )
{
ShiftKeyDown = 1; // It is down, use asciiShift characters
continue; // Loop, so it will not return a scan code for the shift key
}
}
break; // Leave the loop
}
return scancode;
}

unsigned char const k_getch() // Scancode --> ASCII
{
unsigned int scan; // scancode from the keyboard
unsigned char retchar; // The chararacter that returns the scan code to ASCII code
scan = FetchAndAnalyzeScancode(); // Grab scancode, and get the position of the shift key
if ( ShiftKeyDown )
retchar = asciiShift[scan]; // (Upper) Shift Codes
else
retchar = asciiNonShift[ scan ]; // (Lower) Non-Shift Codes
return retchar; // ASCII version
}

void keyboard_handler(struct regs* r)
{
k_printf("keyboard handler works!", 8, 0x2);

unsigned char bufferKEY[10];
bufferKEY[0] = k_getch();
k_printf(bufferKEY, 10,0xA); // the ASCII character
}

void keyboard_install()
{
/* Installs 'keyboard_handler' to IRQ1 */
irq_install_handler(1, keyboard_handler);
keyboard_init();
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include "keyboard.h"
#include
"os.h"

int ShiftKeyDown; // Variable for Shift Key Down

/* Wait until buffer is empty */

void keyboard_init()
{
    while (inportb(0x64)&1)
      inportb(0x60);
};

unsigned int FetchAndAnalyzeScancode()
{
    unsigned int scancode; // For getting the keyboard scancode
    while(TRUE) // Loop until a key (w/o shift key) has been pressed
    {
        scancode = inportb(0x60);   // 0x60: get scan code from the keyboard

        if ( scancode & 0x80 ) // Key released? Check bit 7 (10000000b = 0x80) of scan code for this
        {
            scancode &= 0x7F; // Key was released, compare only low seven bits: 01111111b = 0x7F
            if ( scancode == KRLEFT_SHIFT || scancode == KRRIGHT_SHIFT ) // A key was released, shift key up?
            {
                ShiftKeyDown = 0;    // yes, it is up --> NonShift
            }
        }
        else // Key was pressed.
        {
            // Capture scan code of shift key, if pressed
            if ( scancode == KRLEFT_SHIFT || scancode == KRRIGHT_SHIFT )
            {
                ShiftKeyDown = 1; // It is down, use asciiShift characters
                continue; // Loop, so it will not return a scan code for the shift key
            }
        }
        break; // Leave the loop
    }
    return scancode;
}

unsigned char const k_getch() // Scancode --> ASCII
{
    unsigned int scan;          // scancode from the keyboard
    unsigned char retchar;      // The chararacter that returns the scan code to ASCII code
    scan = FetchAndAnalyzeScancode(); // Grab scancode, and get the position of the shift key
    if ( ShiftKeyDown )
        retchar = asciiShift[scan];    // (Upper) Shift Codes
    else
        retchar = asciiNonShift[ scan ]; // (Lower) Non-Shift Codes
    return retchar; // ASCII version
}

void keyboard_handler(struct regs* r)
{
   k_printf("keyboard handler works!", 8, 0x2);

   unsigned char bufferKEY[10];
   bufferKEY[0] = k_getch();
   k_printf(bufferKEY, 10,0xA); // the ASCII character
}

void keyboard_install()
{
    /* Installs 'keyboard_handler' to IRQ1 */
    irq_install_handler(1, keyboard_handler);
    keyboard_init();
}

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:38:30 05.04.2009, insgesamt 1-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 22:34:38 05.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
@abc.w: Danke für die Übersetzung von Intel nach AT&T und für das DJGPP / mingw makefile. Es sollte nicht von zu vielen Kleinigkeiten und/oder Geschmacksachen abhängen, ob jemand den Zugang zu OSDEV findet. :)

Bitte, aber ich glaube, ich habe da noch den einen oder anderen Fehler eingebaut und es wundert mich, dass es funktioniert:
Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
print_string:
    movb $0x0E, %ah
1:
    lodsb               # grab a byte from SI
    testb %al, %al      # test AL
    jz 2b               # if the result is zero, get out
    int $0x10           # otherwise, print out the character!
    jmp 1b
2:
    ret
Code:
1
2
3
4
5
6
7
8
9
10
print_string:
movb $0x0E, %ah
1:
lodsb # grab a byte from SI
testb %al, %al # test AL
jz 2b # if the result is zero, get out
int $0x10 # otherwise, print out the character!
jmp 1b
2:
ret
Code:
1
2
3
4
5
6
7
8
9
10
print_string:
    movb $0x0E, %ah
1:
    lodsb               # grab a byte from SI
    testb %al, %al      # test AL
    jz 2b               # if the result is zero, get out
    int $0x10           # otherwise, print out the character!
    jmp 1b
2:
    ret

Die Zeile jz 2b soll natürlich nicht 2 back sonder 2 forward heissen...
Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
print_string:
    movb $0x0E, %ah
1:
    lodsb               # grab a byte from SI
    testb %al, %al      # test AL
    jz 2f               # if the result is zero, get out
    int $0x10           # otherwise, print out the character!
    jmp 1b
2:
    ret
Code:
1
2
3
4
5
6
7
8
9
10
print_string:
movb $0x0E, %ah
1:
lodsb # grab a byte from SI
testb %al, %al # test AL
jz 2f # if the result is zero, get out
int $0x10 # otherwise, print out the character!
jmp 1b
2:
ret
Code:
1
2
3
4
5
6
7
8
9
10
print_string:
    movb $0x0E, %ah
1:
    lodsb               # grab a byte from SI
    testb %al, %al      # test AL
    jz 2f               # if the result is zero, get out
    int $0x10           # otherwise, print out the character!
    jmp 1b
2:
    ret

Entschuldigung... werde es oben gleich korrigieren...
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:50:03 05.04.2009   Titel:              Zitieren

Ich denke das nächste, was nun notwendig wird, ist eine vollständige Datei video.c - da gibt es ja nicht viel zu erklären - mit verbesserten Darstellungsmöglichkeiten, denn im jetzigen Zustand kann man das Programm nicht auf die Menschheit los lassen. In keyboard.c fehlt eigentlich auch noch die Abfrage auf weitere Kombinationen mit Sondertasten neben Shift, aber ich bin erstmal froh, dass es nun generell läuft. Mit dem Keyboard Handling stehe ich echt auf Kriegsfuß. :rolleyes:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:51:15 05.04.2009, insgesamt 1-mal bearbeitet
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 23:31:35 05.04.2009   Titel:              Zitieren

Naja, so ganz sinnvoll sieht mir deine fetchandsigsbums-Funktion noch nicht aus... Meine Vorschlaege (eigentlich waere das ja nur noch eine Sache?) noch nicht drin, dafuer die grosse Endlosschleife noch immer. :p
Mehr als einen Durchgang solltest du in dieser Funktion einfach nicht machen. Auch fuer erweiterte Codes, die aus mehreren Scancodes bestehen, wird jedes Mal ein IRQ ausgeloest.
Mal morgen nochmal drueber schauen...

video.c ... Mein Vorschlag waere erstmal globale Variablen fuer die character attributes und die aktuelle Bildschirmposition, etc. festzulegen. Evtl. sogar in der BDA im entsprechenden Format, wie es das VGA-BIOS tut.
Dann erstmal grundlegende Funktionen zum Positionieren des Cursors, Ausgabe von chars und Strings, setzen der attributes, etc. implementieren.
Darauf kannst du dann vielleicht eine abgespeckte Version von printf aufbauen, die zumindest mit 0-terminierten Strings vernuenftig arbeiten kann und evtl. auch sowas wie %x, %d, %c und %s unterstuetzt.

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908


Zuletzt bearbeitet von Nobuo T am 23:32:38 05.04.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:38:21 05.04.2009   Titel:              Zitieren

Eine Design-Frage: Wie geht man mit den "Handlern" bezüglich IRQ am besten um?
Der nachstehende keyboard_handler(...) holt ein Zeichen in einen lokalen Puffer.
Wie geht man mit all diesen Informationen egal ob Tick-Info oder ein Zeichen von der Tastatur schnittstellenmäßig am besten um? Hier die zwei bisherigen Beispiele für IRQ0 und IRQ1:

C/C++ Code:
void timer_handler(struct regs* r)
{
    ++timer_ticks;
    if (eticks)
        --eticks;
}
C/C++ Code:
void timer_handler(struct regs* r)
{
++timer_ticks;
if (eticks)
--eticks;
}
C/C++ Code:
void timer_handler(struct regs* r)
{
    ++timer_ticks;
    if (eticks)
        --eticks;
}


C/C++ Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
void keyboard_handler(struct regs* r)
{
   // k_printf("keyboard handler works!", 8, 0x2);

   unsigned char bufferKEY[10];
   bufferKEY[0] = k_getch();
   k_printf(bufferKEY, 10,0xA); // the ASCII character
}
C/C++ Code:
1
2
3
4
5
6
7
8
void keyboard_handler(struct regs* r)
{
// k_printf("keyboard handler works!", 8, 0x2);

unsigned char bufferKEY[10];
bufferKEY[0] = k_getch();
k_printf(bufferKEY, 10,0xA); // the ASCII character
}
C/C++ Code:
1
2
3
4
5
6
7
8
void keyboard_handler(struct regs* r)
{
   // k_printf("keyboard handler works!", 8, 0x2);

   unsigned char bufferKEY[10];
   bufferKEY[0] = k_getch();
   k_printf(bufferKEY, 10,0xA); // the ASCII character
}

Die Ergebnisse sind in einem Fall timer_ticks und eticks, im anderen Fall bufferKEY[0]. Was macht man damit sinnvollerweise, um überall damit umgehen zu können? Gibt es diesbezüglich eine allgemeine Theorie?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:52:30 05.04.2009   Titel:              Zitieren

Zitat:
video.c ... Mein Vorschlag waere erstmal globale Variablen fuer die character attributes und die aktuelle Bildschirmposition, etc. festzulegen. Evtl. sogar in der BDA im entsprechenden Format, wie es das VGA-BIOS tut.
Dann erstmal grundlegende Funktionen zum Positionieren des Cursors, Ausgabe von chars und Strings, setzen der attributes, etc. implementieren.
Darauf kannst du dann vielleicht eine abgespeckte Version von printf aufbauen, die zumindest mit 0-terminierten Strings vernuenftig arbeiten kann und evtl. auch sowas wie %x, %d, %c und %s unterstuetzt.

Genau so habe ich mir das auch vorgestellt, ist ja auch das übliche Verfahren bei x*y Textausgabe. Das bisherige k_printf(...) war nur eine Quick&Dirty-Notlösung, um rasch vorwärts zu gelangen.

Zitat:
dafuer die grosse Endlosschleife noch immer.

Das ist ja keine "echte" Endlosschleife, da ich dort mit continue oder break in die jeweils richtige Richtung ein-/aussteigen kann. Habe bisher noch keine perfekte Lösung für die passende Kontrollstruktur gefunden, weil man die while-Schleife verschieden durchlaufen muss. Ich hatte erst while (loopflag) geschrieben und das flag entsprechend gesetzt, dann aber festgestellt, dass man das auch durch ein einfaches break und Tschüss ersetzen kann.

Zitat:
Meine Vorschlaege (eigentlich waere das ja nur noch eine Sache?) noch nicht drin
Ich denke noch darüber nach, habe aber bisher keinen Nachteil im bisherigen Ablauf erkannt, ist aber auch alles noch zu chaotisch auf dem Bildschirm. Ab und zu tauchen da merkwürdige Zeichen an unerwarteten Stellen auf. :D

Auf jeden Fall vielen Dank an alle, die mich hier unterstützen! :live:
Dieses Tutorial ist ein lang gehegter Wunsch. Bisher hatte ich mich aber nicht an die Materie heran gewagt, bin ja kein Informatiker, sondern Autodidakt. Nun bin ich aber bereits soweit eingedrungen in das Thema, dass es kein Zurück mehr gibt, nur noch vorwärts. ;) :D

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:01:24 06.04.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:58:36 06.04.2009   Titel:              Zitieren

@Nobuo T:
Noch zu den Themen: Port 0x61 Bit7, EOI und IF

Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
; Acknowledge Keyboard : Toggle PB bit 7
PUSH AX ; save scan code
IN AL, 61H ; read current PB value
OR AL, 80H ; set bit 7
OUT 61H, AL ; write value back + bit 7=1
AND AL, 7FH ; clear bit 7–back to original
OUT 61H , AL ; write original value back
POP AX ; restore scan code
Code:
1
2
3
4
5
6
7
8
; Acknowledge Keyboard : Toggle PB bit 7
PUSH AX ; save scan code
IN AL, 61H ; read current PB value
OR AL, 80H ; set bit 7
OUT 61H, AL ; write value back + bit 7=1
AND AL, 7FH ; clear bit 7–back to original
OUT 61H , AL ; write original value back
POP AX ; restore scan code
Code:
1
2
3
4
5
6
7
8
; Acknowledge Keyboard : Toggle PB bit 7
PUSH AX ; save scan code
IN AL, 61H ; read current PB value
OR AL, 80H ; set bit 7
OUT 61H, AL ; write value back + bit 7=1
AND AL, 7FH ; clear bit 7–back to original
OUT 61H , AL ; write original value back
POP AX ; restore scan code

http://www.sce.carleton.ca/courses/sysc-3006/f08/Part19-KbdInts.pdf


Zitat:

Note that if you repeatedly read the port 0x60 without waiting for another IRQ, you'll read the same byte again. That's the 'normal' behaviour of keyboard controller, but if that doesn't suit your needs, you can still "acknowledge" the scancode by quickly disabling and re-enabling the keyboard at the PPI (Programmable Peripheral Interface):

C/C++ Code:
int temp = inportb(0x61);
outportb(0x61,temp | 0x80);  /* Disable */
outportb(0x61,temp & 0x7F);  /* Re-enable */
C/C++ Code:
int temp = inportb(0x61);
outportb(0x61,temp | 0x80); /* Disable */
outportb(0x61,temp & 0x7F); /* Re-enable */
C/C++ Code:
int temp = inportb(0x61);
outportb(0x61,temp | 0x80);  /* Disable */
outportb(0x61,temp & 0x7F);  /* Re-enable */

http://wiki.osdev.org/PS2_Keyboard

Nobuo T:
Zitat:
Kurz aus- und wieder einschalten ueber Port 61h, Bit7.


Ich gehe davon aus, dass für das MSB 0->1 u. 1->0 der korrekte Weg ist.

Wann muss man dieses ACK(nowledgement) abgeben?
Würde das so passen?

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
unsigned int FetchAndAnalyzeScancode()
{
  unsigned int scancode; // For getting the keyboard scancode
  while(TRUE) // Loop until a key (w/o shift key) has been pressed
  {
    scancode = inportb(0x60);   // 0x60: get scan code from the keyboard
    // ACK: toggle bit 7 at port 0x61

    outportb(0x61,inportb(0x61) |  0x80); // 0->1
    outportb(0x61,inportb(0x61) &~ 0x80); // 1->0

    if ( scancode & 0x80 ) // Key released? ...
    { //...
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
unsigned int FetchAndAnalyzeScancode()
{
unsigned int scancode; // For getting the keyboard scancode
while(TRUE) // Loop until a key (w/o shift key) has been pressed
{
scancode = inportb(0x60); // 0x60: get scan code from the keyboard
// ACK: toggle bit 7 at port 0x61

outportb(0x61,inportb(0x61) | 0x80); // 0->1
outportb(0x61,inportb(0x61) &~ 0x80); // 1->0

if ( scancode & 0x80 ) // Key released? ...
{ //...
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
unsigned int FetchAndAnalyzeScancode()
{
  unsigned int scancode; // For getting the keyboard scancode
  while(TRUE) // Loop until a key (w/o shift key) has been pressed
  {
    scancode = inportb(0x60);   // 0x60: get scan code from the keyboard
    // ACK: toggle bit 7 at port 0x61

    outportb(0x61,inportb(0x61) |  0x80); // 0->1
    outportb(0x61,inportb(0x61) &~ 0x80); // 1->0

    if ( scancode & 0x80 ) // Key released? ...
    { //...

oder ist es so besser? (wie oben bei osdev.org)
C/C++ Code:
     // ACK: toggle bit 7 at port 0x61
    unsigned char port_value = inportb(0x61);
    outportb(0x61,port_value |  0x80); // 0->1
    outportb(0x61,port_value &~ 0x80); // 1->0
C/C++ Code:
// ACK: toggle bit 7 at port 0x61
unsigned char port_value = inportb(0x61);
outportb(0x61,port_value | 0x80); // 0->1
outportb(0x61,port_value &~ 0x80); // 1->0
C/C++ Code:
     // ACK: toggle bit 7 at port 0x61
    unsigned char port_value = inportb(0x61);
    outportb(0x61,port_value |  0x80); // 0->1
    outportb(0x61,port_value &~ 0x80); // 1->0

Ich sehe allerdings noch keinen Effekt mit/ohne ACK? :confused:
Es heisst ja auch: "without waiting for another IRQ".
Wir reagieren doch jetzt immer auf einen IRQ1. Also brauchen wir das nun nicht?
Wir hätten es wohl eher beim Polling benötigt??? Da ist es mir aber nicht negativ aufgefallen.

Das EOI wird in irq.c gesendet:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*  EOI command to the controllers. If you don't send them, any more IRQs cannot be raised */
void irq_handler(struct regs* r)
{
    /* This is a blank function pointer */
    void (*handler)(struct regs* r);

    /* Find out if we have a custom handler to run for this IRQ, and then finally, run it */
    handler = irq_routines[r->int_no - 32];
    if (handler) { handler(r); }

    /* If the IDT entry that was invoked was greater than 40 (IRQ8 - 15),
    *  then we need to send an EOI to the slave controller */

    if (r->int_no >= 40) { outportb(0xA0, 0x20); }

    /* In either case, we need to send an EOI to the master interrupt controller too */
    outportb(0x20, 0x20);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* EOI command to the controllers. If you don't send them, any more IRQs cannot be raised */
void irq_handler(struct regs* r)
{
/* This is a blank function pointer */
void (*handler)(struct regs* r);

/* Find out if we have a custom handler to run for this IRQ, and then finally, run it */
handler = irq_routines[r->int_no - 32];
if (handler) { handler(r); }

/* If the IDT entry that was invoked was greater than 40 (IRQ8 - 15),
* then we need to send an EOI to the slave controller */

if (r->int_no >= 40) { outportb(0xA0, 0x20); }

/* In either case, we need to send an EOI to the master interrupt controller too */
outportb(0x20, 0x20);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*  EOI command to the controllers. If you don't send them, any more IRQs cannot be raised */
void irq_handler(struct regs* r)
{
    /* This is a blank function pointer */
    void (*handler)(struct regs* r);

    /* Find out if we have a custom handler to run for this IRQ, and then finally, run it */
    handler = irq_routines[r->int_no - 32];
    if (handler) { handler(r); }

    /* If the IDT entry that was invoked was greater than 40 (IRQ8 - 15),
    *  then we need to send an EOI to the slave controller */

    if (r->int_no >= 40) { outportb(0xA0, 0x20); }

    /* In either case, we need to send an EOI to the master interrupt controller too */
    outportb(0x20, 0x20);
}


Da war doch noch die Rede von einem IF? Ist dies das IF bei der CPU im Flag-Register?
Zitat:
Dieses Flag ist ... ein Steuerungs-Flag. Wird es gelöscht, so werden Interrupts vom Prozessor ausgesetzt. Man löscht dieses Flag zu Beginn von Interrupt-Routinen (manche Prozessoren erledigen dies automatisch), damit diese ungestört bis zum Ende durchlaufen können. Der Prozessor führt nach dem Setzen des Interrupt-Enable-Flags erst noch eine Anweisung aus, bevor er wieder Interrupts zulässt. So kann man in einer Interrupt-Routine nach dem Setzten dieses Flags noch den RETURN-Befehl ausführen lassen. Es gibt Interrupts, die vom Interrupt-Enable-Flag unberührt bleiben. Diese nennt man nicht-maskierbare Interrupts (NMI).

http://de.wikipedia.org/wiki/Statusregister#Interrupt-Enable-Flag

isr.asm: dort findet sich bei jedem IRQ ein cli
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
; 33: IRQ1
_irq1:
    cli
    push byte 0
    push byte 33
    jmp irq_common_stub

...

extern _irq_handler

irq_common_stub:
    pusha
    push ds
    push es
    push fs
    push gs

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov eax, esp

    push eax
    mov eax, _irq_handler
    call eax
    pop eax

    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp, 8
    iret
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
; 33: IRQ1
_irq1:
cli
push byte 0
push byte 33
jmp irq_common_stub

...

extern _irq_handler

irq_common_stub:
pusha
push ds
push es
push fs
push gs

mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, esp

push eax
mov eax, _irq_handler
call eax
pop eax

pop gs
pop fs
pop es
pop ds
popa
add esp, 8
iret
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
; 33: IRQ1
_irq1:
    cli
    push byte 0
    push byte 33
    jmp irq_common_stub

...

extern _irq_handler

irq_common_stub:
    pusha
    push ds
    push es
    push fs
    push gs

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov eax, esp

    push eax
    mov eax, _irq_handler
    call eax
    pop eax

    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp, 8
    iret

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:10:49 06.04.2009, insgesamt 9-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 09:52:43 06.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Eine Design-Frage: Wie geht man mit den "Handlern" bezüglich IRQ am besten um?
Der nachstehende keyboard_handler(...) holt ein Zeichen in einen lokalen Puffer.
Wie geht man mit all diesen Informationen egal ob Tick-Info oder ein Zeichen von der Tastatur schnittstellenmäßig am besten um? Hier die zwei bisherigen Beispiele für IRQ0 und IRQ1:

C/C++ Code:
void timer_handler(struct regs* r)
{
    ++timer_ticks;
    if (eticks)
        --eticks;
}
C/C++ Code:
void timer_handler(struct regs* r)
{
++timer_ticks;
if (eticks)
--eticks;
}
C/C++ Code:
void timer_handler(struct regs* r)
{
    ++timer_ticks;
    if (eticks)
        --eticks;
}


C/C++ Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
void keyboard_handler(struct regs* r)
{
   // k_printf("keyboard handler works!", 8, 0x2);

   unsigned char bufferKEY[10];
   bufferKEY[0] = k_getch();
   k_printf(bufferKEY, 10,0xA); // the ASCII character
}
C/C++ Code:
1
2
3
4
5
6
7
8
void keyboard_handler(struct regs* r)
{
// k_printf("keyboard handler works!", 8, 0x2);

unsigned char bufferKEY[10];
bufferKEY[0] = k_getch();
k_printf(bufferKEY, 10,0xA); // the ASCII character
}
C/C++ Code:
1
2
3
4
5
6
7
8
void keyboard_handler(struct regs* r)
{
   // k_printf("keyboard handler works!", 8, 0x2);

   unsigned char bufferKEY[10];
   bufferKEY[0] = k_getch();
   k_printf(bufferKEY, 10,0xA); // the ASCII character
}

Die Ergebnisse sind in einem Fall timer_ticks und eticks, im anderen Fall bufferKEY[0]. Was macht man damit sinnvollerweise, um überall damit umgehen zu können? Gibt es diesbezüglich eine allgemeine Theorie?

oft wird sowas objektorientiert gemacht (betriebssysteme schreien förmlich nach einem objektorientiertes design). für frei laufende countdown-timer machste dir z.b. ein paar funktionen:
Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
// erzeugt einen neuen timer und meldet ihn beim OS an. gibt 0 zurück, wenn kein timer alloziert werden konnte
timer_t *timer_create(void);

// startet den timer, der ab jetzt vom OS von 'timeout' bis 0 runtergezählt wird
void timer_start (timer_t *timer, unsigned long timeout);

// prüft ob der timer abgelaufen ist, gibt 0 zurück, wenn der timer noch läuft, sonst 1
int timer_expired (timer *t);

// beseitigt den timer (trägt ihn z.b. aus der liste des OS aus und gibt seinen speicher frei)
void timer_free (timer_t *timer);
Code:
1
2
3
4
5
6
7
8
9
10
11
// erzeugt einen neuen timer und meldet ihn beim OS an. gibt 0 zurück, wenn kein timer alloziert werden konnte
timer_t *timer_create(void);

// startet den timer, der ab jetzt vom OS von 'timeout' bis 0 runtergezählt wird
void timer_start (timer_t *timer, unsigned long timeout);

// prüft ob der timer abgelaufen ist, gibt 0 zurück, wenn der timer noch läuft, sonst 1
int timer_expired (timer *t);

// beseitigt den timer (trägt ihn z.b. aus der liste des OS aus und gibt seinen speicher frei)
void timer_free (timer_t *timer);
Code:
1
2
3
4
5
6
7
8
9
10
11
// erzeugt einen neuen timer und meldet ihn beim OS an. gibt 0 zurück, wenn kein timer alloziert werden konnte
timer_t *timer_create(void);

// startet den timer, der ab jetzt vom OS von 'timeout' bis 0 runtergezählt wird
void timer_start (timer_t *timer, unsigned long timeout);

// prüft ob der timer abgelaufen ist, gibt 0 zurück, wenn der timer noch läuft, sonst 1
int timer_expired (timer *t);

// beseitigt den timer (trägt ihn z.b. aus der liste des OS aus und gibt seinen speicher frei)
void timer_free (timer_t *timer);

^^die hardware-isr schaut bei jedem tick in eine verkettete liste, ob timer drin sind, die sie runterzählen muss.

zu den I/O-daten: am besten du benutzt FIFO-buffer für sowas. die ISR (z.b. von der tastatur) trägt empfangene daten in den FIFO ein und die anwendung holt sie sich raus. ein tastatur-FIFO kann recht klein sein und darf ältere daten überschreiben, weil uralte tastendrücke ja nicht mehr interessieren. ein benutzer-prozess kann dann einfach zeichen aus dem FIFO holen, z.b. so:
Code:
// hole ein zeichen aus dem tastatur-buffer. wenn c -1 (oder EOF) ist, war der FIFO leer
int c = getchar();
Code:
// hole ein zeichen aus dem tastatur-buffer. wenn c -1 (oder EOF) ist, war der FIFO leer
int c = getchar();
Code:
// hole ein zeichen aus dem tastatur-buffer. wenn c -1 (oder EOF) ist, war der FIFO leer
int c = getchar();

:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:04:03 06.04.2009   Titel:              Zitieren

@+fricky: Danke für die Ratschläge, kommt in die Planungs-/TODO-Liste. :live: Momentan fehlt dem OS noch ein solches C-Modul mit Strukturen wie Stack (LIFO), Pipe/Queue/Cache (FIFO), verketteter Liste usw. In C++ wäre dies wirklich leichter zu realisieren, muss mal in meinen alten C-Büchern schmökern. :rolleyes:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 11:11:19 06.04.2009, insgesamt 1-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 11:36:32 06.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Momentan fehlt dem OS noch ein solches C-Modul mit Strukturen wie Stack (LIFO), Pipe/Queue/Cache (FIFO), verketteter Liste usw.

hier hast schon mal was für listen: http://www.c-plusplus.de/forum/viewtopic-var-t-is-160978-and-start-is-5.html

Erhard Henkes schrieb:

In C++ wäre dies wirklich leichter zu realisieren...

auf den ersten blick vielleicht, aber letztlich würdest du dich mehr mit c++'s hausgemachten problemen, als mit deinem OS auseinandersetzen. mach den kernel besser in C, c++ (und beliebige andere sprachen) kannst du ja dann für usermode-anwendungnen nehmen.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 12:19:33 06.04.2009   Titel:              Zitieren

Danke für den Link, habe aber meine alten C-Bücher bereits von der zweiten in die erste Reihe gerückt: Kernighan/Ritchie, Willms, Schröder. Zum Glück habe ich die nicht bereits verschenkt. ;)
Zitat:
c++ (und beliebige andere sprachen) kannst du ja dann für usermode-anwendungnen nehmen.
Ja, so wird's gemacht. :live: Hoffentlich erlebt mein PrettyOS diesen Zeitpunkt noch und bleibt nicht bei 0.42 o.ä. wegen explodierender Taskliste stecken wie so viele Entwürfe. :D

Zitat:
Immer im Hinterkopf behalten, dass das ein Internet-Tutorial und kein Kompendium zur OS-Entwicklung werden soll - das wird wie ich das sehe schon so eine ordentliche Portion Stoff. :D
Ich habe den bisherigen Text mal als pdf gedruckt, da waren es schon fast 100 Seiten, ist schon ein umfassendes Thema, und dabei sind wir noch in der Overtüre. :D

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 18:20:23 06.04.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:46:31 06.04.2009   Titel:              Zitieren

@Nobuo T:
Zitat:
Evtl. sogar in der BDA im entsprechenden Format, wie es das VGA-BIOS tut.
Könntest Du diesen Punkt bitte genauer ausführen?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 01:17:47 07.04.2009   Titel:              Zitieren

http://heim.ifi.uio.no/~stanisls/helppc/bios_data_area.html
ab offset 449h. Mir scheint diese Struktur eigentlich im Grossen und Ganzen recht praktisch.

Erhard Henkes schrieb:
Zitat:
dafuer die grosse Endlosschleife noch immer.

Das ist ja keine "echte" Endlosschleife, da ich dort mit continue oder break in die jeweils richtige Richtung ein-/aussteigen kann. Habe bisher noch keine perfekte Lösung für die passende Kontrollstruktur gefunden, weil man die while-Schleife verschieden durchlaufen muss. Ich hatte erst while (loopflag) geschrieben und das flag entsprechend gesetzt, dann aber festgestellt, dass man das auch durch ein einfaches break und Tschüss ersetzen kann.

Ok, mal anders gefragt:
Was fuer Faelle siehst du konkret, bei denen es noetig oder sinnvoll waere, in dieser Schleife mehrere Male hintereinander Scancodes von Port 60h zu lesen?
Ich sehe hoechstens 2, naemlich erweiterte 2-Byte codes (Pfeiltasten, etc.) oder andere, laengere Status codes, die du aber saemtlichst noch nicht beruecksichtigst.
Dagegen springst du so immer noch beim Druecken der Shift-Taste in eine Endlosschleife ohne Sinn und Wiederkehr.
Deshalb mein Tipp: Weg mit der Schleife. Versuche moeglichst pro IRQ nur einmal Port 60h auszulesen, das gelesene direkt zu verarbeiten und gleich wieder zurueckzukehren.
Dazu kannst du zB. in dieser Fetch-Funktion einen speziellen Rueckgabewert fuer Codes einfuehren, die sich nicht direkt in ASCII-Codes umsetzen lassen und zur Bearbeitung der Codes globale Variablen und Flags benutzen (zB. fuer shift, strg, alt down, usw. siehe auch meinen Link zur BDA oben als groben Denkansatz).


Erhard Henkes schrieb:
Zitat:

Kurz aus- und wieder einschalten ueber Port 61h, Bit7.


Ich gehe davon aus, dass für das MSB 0->1 u. 1->0 der korrekte Weg ist.

AFAIR: Ja.

Erhard Henkes schrieb:
Wann muss man dieses ACK(nowledgement) abgeben?

Wenn du das Gelesene nicht mehr brauchst. In dem KB-Treiber, den ich vor Jahren mal geschrieben habe, hatte das direkt vor dem EOI stehen.

Erhard Henkes schrieb:

Würde das so passen?
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
    unsigned int FetchAndAnalyzeScancode()
{
  unsigned int scancode; // For getting the keyboard scancode
  while(TRUE) // Loop until a key (w/o shift key) has been pressed
  {
    scancode = inportb(0x60);   // 0x60: get scan code from the keyboard
    // ACK: toggle bit 7 at port 0x61

    outportb(0x61,inportb(0x61) |  0x80); // 0->1
    outportb(0x61,inportb(0x61) &~ 0x80); // 1->0

    if ( scancode & 0x80 ) // Key released? ...
    { //...    
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
unsigned int FetchAndAnalyzeScancode()
{
unsigned int scancode; // For getting the keyboard scancode
while(TRUE) // Loop until a key (w/o shift key) has been pressed
{
scancode = inportb(0x60); // 0x60: get scan code from the keyboard
// ACK: toggle bit 7 at port 0x61

outportb(0x61,inportb(0x61) | 0x80); // 0->1
outportb(0x61,inportb(0x61) &~ 0x80); // 1->0

if ( scancode & 0x80 ) // Key released? ...
{ //...
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
    unsigned int FetchAndAnalyzeScancode()
{
  unsigned int scancode; // For getting the keyboard scancode
  while(TRUE) // Loop until a key (w/o shift key) has been pressed
  {
    scancode = inportb(0x60);   // 0x60: get scan code from the keyboard
    // ACK: toggle bit 7 at port 0x61

    outportb(0x61,inportb(0x61) |  0x80); // 0->1
    outportb(0x61,inportb(0x61) &~ 0x80); // 1->0

    if ( scancode & 0x80 ) // Key released? ...
    { //...    


oder ist es so besser? (wie oben bei osdev.org)
C/C++ Code:
     // ACK: toggle bit 7 at port 0x61
    unsigned char port_value = inportb(0x61);
    outportb(0x61,port_value |  0x80); // 0->1
    outportb(0x61,port_value &~ 0x80); // 1->0    
C/C++ Code:
// ACK: toggle bit 7 at port 0x61
unsigned char port_value = inportb(0x61);
outportb(0x61,port_value | 0x80); // 0->1
outportb(0x61,port_value &~ 0x80); // 1->0
C/C++ Code:
     // ACK: toggle bit 7 at port 0x61
    unsigned char port_value = inportb(0x61);
    outportb(0x61,port_value |  0x80); // 0->1
    outportb(0x61,port_value &~ 0x80); // 1->0    


Die 2. Version ist eindeutig besser. Es schadet uebrigens sicher nicht, vor dem Lesen von Port 60h, den Port 64h, Bit 0 zu pruefen, wie du es urspruenglich auch gemacht hast (das meinte ich eigentlich gar nicht mit Endlosschleife, sondern deine aeussere while (true)-Schleife :D).
Vielleicht den Port 64h statt in einer while-Schleife in einer for-Schleife mit Zaehler als zusaetzliche Abbruchbedingung pruefen. Im Fehlerfall springst du dann halt sofort zurueck.


Erhard Henkes schrieb:

Ich sehe allerdings noch keinen Effekt mit/ohne ACK? :confused:
Es heisst ja auch: "without waiting for another IRQ".
Wir reagieren doch jetzt immer auf einen IRQ1. Also brauchen wir das nun nicht?
Wir hätten es wohl eher beim Polling benötigt??? Da ist es mir aber nicht negativ aufgefallen.

Theoretisch richtig, aber praktisch macht dieses x86-Gefrickel eben doch wieder alles anders. :D
Wenn du mit einer Runde Keyboard-Auslesen sicher fertig bist, kann es ganz bestimmt nicht verkehrt sein, mit diesem ACK sicher zu gehen.

Erhard Henkes schrieb:
Da war doch noch die Rede von einem IF? Ist dies das IF bei der CPU im Flag-Register?
[...]
isr.asm: dort findet sich bei jedem IRQ ein cli

Richtig. Und genau deshalb ist eine [laengere/endlose] Schleife in einem IRQ-Handler ziemlich fatal. Damit blockierst du das komplette System. Ein IRQ-Handler muss moeglichst schnell sein: Rein, Hardware auslesen, das absolut Wichtigste kurz aufbereiten und im RAM abladen, ACK und wieder raus.
Im Extremfall kannst du bei einem Micro-Kernel so weit gehen, dass du nur den Scancode in eine FIFO-queue im RAM schiebst und die Interpretation einem eigenen Treiber-Prozess ueberlaesst (wobei ich meine, dass man es nicht so uebertreiben braucht und sich der Keyboard-Input auch noch sehr gut weitgehend komplett im IRQ-Handler interpretieren/in ASCII-Codes umwandeln laesst).

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 17:34:44 07.04.2009   Titel:              Zitieren

@Nobuo T: Vielen Dank für diese umfassenden Ausführungen. Du hast mich überzeugt. :) Ich werde dies Schritt für Schritt umsetzen.

In utils.c habe ich auch noch eine Änderung bei k_i2hex (h und NUL anghängt). Nobuo T hat dankenswerterweise k_itoa weiter optimiert:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
void k_itoa(int value, char* valuestring)
{
  int tenth, min_flag;
  char swap, *p;
  min_flag = 0;

  if (0 > value)
  {
    *valuestring++ = '-';
    value = -INT_MAX > value ? min_flag = INT_MAX : -value;
  }

  p = valuestring;

  do
  {
    *p++ = (char)(value % 10) + '0';
    value /= 10;
  } while (value);

  if (min_flag != 0)
  {
    ++*valuestring;
  }
  *p-- = '\0';

  while (p > valuestring)
  {
    swap = *valuestring;
    *valuestring++ = *p;
    *p-- = swap;
  }
}

void k_i2hex(UINT val, UCHAR* dest, int len)
{
    UCHAR* cp;
    char x;
    UINT n;
    n = val;
    cp = &dest[len];
    while (cp > dest)
    {
        x = n & 0xF;
        n >>= 4;
        *--cp = x + ((x > 9) ? 'A' - 10 : '0');
    }
    dest[len]  ='h';
    dest[len+1]='\0'; // buffer dest must have room for len+2 characters
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
void k_itoa(int value, char* valuestring)
{
int tenth, min_flag;
char swap, *p;
min_flag = 0;

if (0 > value)
{
*valuestring++ = '-';
value = -INT_MAX > value ? min_flag = INT_MAX : -value;
}

p = valuestring;

do
{
*p++ = (char)(value % 10) + '0';
value /= 10;
} while (value);

if (min_flag != 0)
{
++*valuestring;
}
*p-- = '\0';

while (p > valuestring)
{
swap = *valuestring;
*valuestring++ = *p;
*p-- = swap;
}
}

void k_i2hex(UINT val, UCHAR* dest, int len)
{
UCHAR* cp;
char x;
UINT n;
n = val;
cp = &dest[len];
while (cp > dest)
{
x = n & 0xF;
n >>= 4;
*--cp = x + ((x > 9) ? 'A' - 10 : '0');
}
dest[len] ='h';
dest[len+1]='\0'; // buffer dest must have room for len+2 characters
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
void k_itoa(int value, char* valuestring)
{
  int tenth, min_flag;
  char swap, *p;
  min_flag = 0;

  if (0 > value)
  {
    *valuestring++ = '-';
    value = -INT_MAX > value ? min_flag = INT_MAX : -value;
  }

  p = valuestring;

  do
  {
    *p++ = (char)(value % 10) + '0';
    value /= 10;
  } while (value);

  if (min_flag != 0)
  {
    ++*valuestring;
  }
  *p-- = '\0';

  while (p > valuestring)
  {
    swap = *valuestring;
    *valuestring++ = *p;
    *p-- = swap;
  }
}

void k_i2hex(UINT val, UCHAR* dest, int len)
{
    UCHAR* cp;
    char x;
    UINT n;
    n = val;
    cp = &dest[len];
    while (cp > dest)
    {
        x = n & 0xF;
        n >>= 4;
        *--cp = x + ((x > 9) ? 'A' - 10 : '0');
    }
    dest[len]  ='h';
    dest[len+1]='\0'; // buffer dest must have room for len+2 characters
}


video.c sieht momentan wie folgt aus (noch ohne brauchbare printf(...), wei von Nobuo T vorgeschlagen):
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include "os.h"

UCHAR  csr_x  = 0;
UCHAR  csr_y  = 0;
UCHAR  attrib = 0x0F;
USHORT* vidmem = (USHORT*) 0xb8000;

void k_clear_screen()
{
    UINT blank = 0x20 | (attrib << 8);
    int i;
    for(i = 0; i < 25; ++i)
        k_memsetw (vidmem + i * 80, blank, 80);
    csr_x = 0; csr_y = 0;
    update_cursor();
}

void settextcolor(UCHAR forecolor, UCHAR backcolor)
{
    // Top 4 bytes: background, bottom 4 bytes: foreground color
    attrib = (backcolor << 4) | (forecolor & 0x0F);
}

void update_cursor()
{
    USHORT position = csr_y * 80 + csr_x;
    // cursor HIGH port to vga INDEX register
    outportb(0x3D4, 0x0E);
    outportb(0x3D5, (UCHAR)((position>>8)&0xFF));
    // cursor LOW port to vga INDEX register
    outportb(0x3D4, 0x0F);
    outportb(0x3D5, (UCHAR)(position&0xFF));
};

void putch(UCHAR c)
{
    USHORT* pos;
    UINT att = attrib << 8;

    if(c == 0x08) // backspace: move the cursor back one space
    {
        if(csr_x != 0) --csr_x;
    }
    else if(c == 0x09) // tab: increment csr_x (divisible by 8)
    {
        csr_x = (csr_x + 8) & ~(8 - 1);
    }
    else if(c == '\r') // cr: cursor back to the margin
    {
        csr_x = 0;
    }
    else if(c == '\n') // newline: like 'cr': cursor to the margin and increment csr_y
    {
        csr_x = 0; ++csr_y;
    }
    /* Any character greater than and including a space, is a printable character.
    *  Index = [(y * width) + x] */

    else if(c >= ' ')
    {
        pos = vidmem + (csr_y * 80 + csr_x);
        *pos = c | att; // Character AND attributes: color
        ++csr_x;
    }

    if(csr_x >= 80) // cursor reaches edge of the screen's width, a new line is inserted
    {
        csr_x = 0;
        ++csr_y;
    }

    /* Scroll the screen if needed, and finally move the cursor */
    scroll();
    update_cursor();
}

void puts(UCHAR* text)
{
    int i;
    for(i=0; i<k_strlen(text); ++i)
        putch(text[i]);

}

void scroll()
{
    UINT blank, temp;
    blank = 0x20 | (attrib << 8);
    if(csr_y >= 25)
    {
        temp = csr_y - 25 + 1;
        k_memcpy (vidmem, vidmem + temp * 80, (25 - temp) * 80 * 2);
        k_memsetw (vidmem + (25 - temp) * 80, blank, 80);
        csr_y = 25 - 1;
    }
}

void k_printf(UCHAR* message, UINT line, UCHAR attribute)
{
    // Top 4 bytes: background, bottom 4 bytes: foreground color
    settextcolor(attribute & 0x0F, attribute >> 4);
    csr_x = 0; csr_y = line;
    update_cursor();
    puts(message);
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include "os.h"

UCHAR csr_x = 0;
UCHAR csr_y = 0;
UCHAR attrib = 0x0F;
USHORT* vidmem = (USHORT*) 0xb8000;

void k_clear_screen()
{
UINT blank = 0x20 | (attrib << 8);
int i;
for(i = 0; i < 25; ++i)
k_memsetw (vidmem + i * 80, blank, 80);
csr_x = 0; csr_y = 0;
update_cursor();
}

void settextcolor(UCHAR forecolor, UCHAR backcolor)
{
// Top 4 bytes: background, bottom 4 bytes: foreground color
attrib = (backcolor << 4) | (forecolor & 0x0F);
}

void update_cursor()
{
USHORT position = csr_y * 80 + csr_x;
// cursor HIGH port to vga INDEX register
outportb(0x3D4, 0x0E);
outportb(0x3D5, (UCHAR)((position>>8)&0xFF));
// cursor LOW port to vga INDEX register
outportb(0x3D4, 0x0F);
outportb(0x3D5, (UCHAR)(position&0xFF));
};

void putch(UCHAR c)
{
USHORT* pos;
UINT att = attrib << 8;

if(c == 0x08) // backspace: move the cursor back one space
{
if(csr_x != 0) --csr_x;
}
else if(c == 0x09) // tab: increment csr_x (divisible by 8)
{
csr_x = (csr_x + 8) & ~(8 - 1);
}
else if(c == '\r') // cr: cursor back to the margin
{
csr_x = 0;
}
else if(c == '\n') // newline: like 'cr': cursor to the margin and increment csr_y
{
csr_x = 0; ++csr_y;
}
/* Any character greater than and including a space, is a printable character.
* Index = [(y * width) + x] */

else if(c >= ' ')
{
pos = vidmem + (csr_y * 80 + csr_x);
*pos = c | att; // Character AND attributes: color
++csr_x;
}

if(csr_x >= 80) // cursor reaches edge of the screen's width, a new line is inserted
{
csr_x = 0;
++csr_y;
}

/* Scroll the screen if needed, and finally move the cursor */
scroll();
update_cursor();
}

void puts(UCHAR* text)
{
int i;
for(i=0; i<k_strlen(text); ++i)
putch(text[i]);

}

void scroll()
{
UINT blank, temp;
blank = 0x20 | (attrib << 8);
if(csr_y >= 25)
{
temp = csr_y - 25 + 1;
k_memcpy (vidmem, vidmem + temp * 80, (25 - temp) * 80 * 2);
k_memsetw (vidmem + (25 - temp) * 80, blank, 80);
csr_y = 25 - 1;
}
}

void k_printf(UCHAR* message, UINT line, UCHAR attribute)
{
// Top 4 bytes: background, bottom 4 bytes: foreground color
settextcolor(attribute & 0x0F, attribute >> 4);
csr_x = 0; csr_y = line;
update_cursor();
puts(message);
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include "os.h"

UCHAR  csr_x  = 0;
UCHAR  csr_y  = 0;
UCHAR  attrib = 0x0F;
USHORT* vidmem = (USHORT*) 0xb8000;

void k_clear_screen()
{
    UINT blank = 0x20 | (attrib << 8);
    int i;
    for(i = 0; i < 25; ++i)
        k_memsetw (vidmem + i * 80, blank, 80);
    csr_x = 0; csr_y = 0;
    update_cursor();
}

void settextcolor(UCHAR forecolor, UCHAR backcolor)
{
    // Top 4 bytes: background, bottom 4 bytes: foreground color
    attrib = (backcolor << 4) | (forecolor & 0x0F);
}

void update_cursor()
{
    USHORT position = csr_y * 80 + csr_x;
    // cursor HIGH port to vga INDEX register
    outportb(0x3D4, 0x0E);
    outportb(0x3D5, (UCHAR)((position>>8)&0xFF));
    // cursor LOW port to vga INDEX register
    outportb(0x3D4, 0x0F);
    outportb(0x3D5, (UCHAR)(position&0xFF));
};

void putch(UCHAR c)
{
    USHORT* pos;
    UINT att = attrib << 8;

    if(c == 0x08) // backspace: move the cursor back one space
    {
        if(csr_x != 0) --csr_x;
    }
    else if(c == 0x09) // tab: increment csr_x (divisible by 8)
    {
        csr_x = (csr_x + 8) & ~(8 - 1);
    }
    else if(c == '\r') // cr: cursor back to the margin
    {
        csr_x = 0;
    }
    else if(c == '\n') // newline: like 'cr': cursor to the margin and increment csr_y
    {
        csr_x = 0; ++csr_y;
    }
    /* Any character greater than and including a space, is a printable character.
    *  Index = [(y * width) + x] */

    else if(c >= ' ')
    {
        pos = vidmem + (csr_y * 80 + csr_x);
        *pos = c | att; // Character AND attributes: color
        ++csr_x;
    }

    if(csr_x >= 80) // cursor reaches edge of the screen's width, a new line is inserted
    {
        csr_x = 0;
        ++csr_y;
    }

    /* Scroll the screen if needed, and finally move the cursor */
    scroll();
    update_cursor();
}

void puts(UCHAR* text)
{
    int i;
    for(i=0; i<k_strlen(text); ++i)
        putch(text[i]);

}

void scroll()
{
    UINT blank, temp;
    blank = 0x20 | (attrib << 8);
    if(csr_y >= 25)
    {
        temp = csr_y - 25 + 1;
        k_memcpy (vidmem, vidmem + temp * 80, (25 - temp) * 80 * 2);
        k_memsetw (vidmem + (25 - temp) * 80, blank, 80);
        csr_y = 25 - 1;
    }
}

void k_printf(UCHAR* message, UINT line, UCHAR attribute)
{
    // Top 4 bytes: background, bottom 4 bytes: foreground color
    settextcolor(attribute & 0x0F, attribute >> 4);
    csr_x = 0; csr_y = line;
    update_cursor();
    puts(message);
};

Fehlt da - außer printf(...) - noch etwas Wichtiges?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:33:48 07.04.2009, insgesamt 4-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:34:42 08.04.2009   Titel:              Zitieren

Leider noch nicht ganz perfekt, aber läuft prinzipiell schon wie es soll:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <stdarg.h>
//...
/* Lean version of printf: printformat(...): supports %u, %d, %x/%X, %s, %c */

void printformat (char *args, ...)
{
    va_list ap;
    va_start (ap, args);
    int index = 0, d;
    UINT u;
    char c, *s;

    float f;

    char buffer[100];

    while (args[index])
    {
        switch (args[index])
        {
        case '%':
            ++index;
            switch (args[index])
            {
            case 'u':
                u = va_arg (ap, UINT);
                k_itoa(u, buffer);
                puts(buffer);
                break;
            case 'd':
                d = va_arg (ap, int);
                k_itoa(d, buffer);
                puts(buffer);
                break;
            case 'X':
            case 'x':
                d = va_arg (ap, int);
                k_i2hex(d, buffer,8);
                puts(buffer);
                break;
            case 's':
                s = va_arg (ap, char*);
                puts(s);
                break;
            case 'c':
                c = (char) va_arg (ap, int);
                putch(c);
                break;
            default:
                putch('%');
                putch('%');
                break;
            }
            break;
        case '\n':
            csr_x = 0; ++csr_y;
            break;
        case '\r':
            csr_x = 0;
            break;
        case '\t':
            csr_x = (csr_x + 8) & ~(8 - 1);
            break;
        default:
            puts(args[index]); //printf("%c",*(args+index)); // no cast
            break;
        }
        ++index;
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <stdarg.h>
//...
/* Lean version of printf: printformat(...): supports %u, %d, %x/%X, %s, %c */

void printformat (char *args, ...)
{
va_list ap;
va_start (ap, args);
int index = 0, d;
UINT u;
char c, *s;

float f;

char buffer[100];

while (args[index])
{
switch (args[index])
{
case '%':
++index;
switch (args[index])
{
case 'u':
u = va_arg (ap, UINT);
k_itoa(u, buffer);
puts(buffer);
break;
case 'd':
d = va_arg (ap, int);
k_itoa(d, buffer);
puts(buffer);
break;
case 'X':
case 'x':
d = va_arg (ap, int);
k_i2hex(d, buffer,8);
puts(buffer);
break;
case 's':
s = va_arg (ap, char*);
puts(s);
break;
case 'c':
c = (char) va_arg (ap, int);
putch(c);
break;
default:
putch('%');
putch('%');
break;
}
break;
case '\n':
csr_x = 0; ++csr_y;
break;
case '\r':
csr_x = 0;
break;
case '\t':
csr_x = (csr_x + 8) & ~(8 - 1);
break;
default:
puts(args[index]); //printf("%c",*(args+index)); // no cast
break;
}
++index;
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <stdarg.h>
//...
/* Lean version of printf: printformat(...): supports %u, %d, %x/%X, %s, %c */

void printformat (char *args, ...)
{
    va_list ap;
    va_start (ap, args);
    int index = 0, d;
    UINT u;
    char c, *s;

    float f;

    char buffer[100];

    while (args[index])
    {
        switch (args[index])
        {
        case '%':
            ++index;
            switch (args[index])
            {
            case 'u':
                u = va_arg (ap, UINT);
                k_itoa(u, buffer);
                puts(buffer);
                break;
            case 'd':
                d = va_arg (ap, int);
                k_itoa(d, buffer);
                puts(buffer);
                break;
            case 'X':
            case 'x':
                d = va_arg (ap, int);
                k_i2hex(d, buffer,8);
                puts(buffer);
                break;
            case 's':
                s = va_arg (ap, char*);
                puts(s);
                break;
            case 'c':
                c = (char) va_arg (ap, int);
                putch(c);
                break;
            default:
                putch('%');
                putch('%');
                break;
            }
            break;
        case '\n':
            csr_x = 0; ++csr_y;
            break;
        case '\r':
            csr_x = 0;
            break;
        case '\t':
            csr_x = (csr_x + 8) & ~(8 - 1);
            break;
        default:
            puts(args[index]); //printf("%c",*(args+index)); // no cast
            break;
        }
        ++index;
    }
}

Wer das testen möchte:
http://www.henkessoft.de/OS_Dev/Downloads/PrettyOS_last_version.zip

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:40:32 08.04.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:04:43 08.04.2009   Titel:              Zitieren

Das ist - denke ich - noch nicht o.k.:
C/C++ Code:
case 'u':
                u = va_arg (ap, UINT);
                k_itoa(u, buffer);
                puts(buffer);
                break;
C/C++ Code:
case 'u':
u = va_arg (ap, UINT);
k_itoa(u, buffer);
puts(buffer);
break;
C/C++ Code:
case 'u':
                u = va_arg (ap, UINT);
                k_itoa(u, buffer);
                puts(buffer);
                break;

Kennt einer ein utoa(...)?

Bei %d fehlt noch das %i, das auch verwendet wird.
Kleines %x barauche ich auch noch. Da muss ich wohl ein zweites k_i2hex schreiben.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:06:14 08.04.2009, insgesamt 1-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 22:53:55 08.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Kennt einer ein utoa(...)?

bau doch dein 'itoa' um, aber statt 'int' mit 'nem 'unsigned' input.
Erhard Henkes schrieb:

Kleines %x barauche ich auch noch. Da muss ich wohl ein zweites k_i2hex schreiben.

unnötiger luxus. wer hexziffern als gross/kleinbuchstaben braucht, kann doch toupper() oder tolower() bemühen.
:)
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 23:33:41 08.04.2009   Titel:              Zitieren

+fricky schrieb:
Erhard Henkes schrieb:

Kennt einer ein utoa(...)?

bau doch dein 'itoa' um, aber statt 'int' mit 'nem 'unsigned' input.

:live: Keine Ahnung, wie die entsprechende Standard-Funktion in C heisst, aber vom Prinzip her ist der Unterschied zu dem itoa minimal.

Ansonsten ist da erstmal wohl alles Wichtige gut dabei. Nur einige Kleinigkeiten noch:

video.c:
k_clear_screen:
Warum nicht gleich
C/C++ Code:
k_memsetw (vidmem, blank, 80 * 25);
C/C++ Code:
k_memsetw (vidmem, blank, 80 * 25);
C/C++ Code:
k_memsetw (vidmem, blank, 80 * 25);

statt die Funktion 25* aufzurufen?

putch:
Grosse if/else-Schlacht... na egal :D
Ist es wirklich normales C-Verhalten, nur chars >= 0x20 auszugeben...?
DOS ist da zB. recht kompromisslos und gibt alles aus, was nicht als Steuerzeichen gewertet wird. Wuerde IMHO auch einen Vergleich sparen. :p

puts:
Wozu extra mit strlen zaehlen, wenn du das Array danach eh nochmal Zeichen fuer Zeichen abwanderst?
Mach's doch gleich so:
C/C++ Code:
void puts(UCHAR* text)
{
    for (; *text; text++) putchar (*text);
}
C/C++ Code:
void puts(UCHAR* text)
{
for (; *text; text++) putchar (*text);
}
C/C++ Code:
void puts(UCHAR* text)
{
    for (; *text; text++) putchar (*text);
}

(ich liebe es, for-Schleifen derart zu missbrauchen :cool: )

printf:
Ist die Behandlung von \n, \t, usw. hier nicht doppelt? Das wird doch in putch auch schon geprueft...
In dem Zusammenhang nehme ich auch mal an, dass du als default-Fall nicht wirklich "puts" nehmen wolltest?

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 23:40:24 08.04.2009   Titel:              Zitieren

Nobuo T schrieb:

C/C++ Code:
void puts(UCHAR* text)
{
    for (; *text; text++) putchar (*text);
}
C/C++ Code:
void puts(UCHAR* text)
{
for (; *text; text++) putchar (*text);
}
C/C++ Code:
void puts(UCHAR* text)
{
    for (; *text; text++) putchar (*text);
}

(ich liebe es, for-Schleifen derart zu missbrauchen :cool: )

Wenn missbrauchen, dann richtig:
C/C++ Code:
void puts(UCHAR* text)
{
    for (; *text; putchar (*text++));
}
C/C++ Code:
void puts(UCHAR* text)
{
for (; *text; putchar (*text++));
}
C/C++ Code:
void puts(UCHAR* text)
{
    for (; *text; putchar (*text++));
}

Weiss nicht obs kompiliert, wenn ja, dann :cool:
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 23:42:39 08.04.2009   Titel:              Zitieren

Ich bin skeptisch, aber: :D :live:

edit:
Bei genauerer Betrachtung: Wuerde das nicht einfach den referenzierten Wert erhoehen? Das waere ja eher kontraproduktiv... ;)

Wie waere es damit?
C/C++ Code:
for (; *text; putchar (*text), text++);
C/C++ Code:
for (; *text; putchar (*text), text++);
C/C++ Code:
for (; *text; putchar (*text), text++);

:o)

edit2:
ok, einen habe ich noch!
C/C++ Code:
for (; *text; putchar (*(text++));
C/C++ Code:
for (; *text; putchar (*(text++));
C/C++ Code:
for (; *text; putchar (*(text++));

Keine Ahnung, ob das kompiliert.

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908


Zuletzt bearbeitet von Nobuo T am 01:59:01 09.04.2009, insgesamt 3-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:18:38 09.04.2009   Titel:              Zitieren

gefällt mir wirklich gut! :)
C/C++ Code:
void puts(UCHAR* text)
{
    for(; *text; putch(*text), ++text);
}
C/C++ Code:
void puts(UCHAR* text)
{
for(; *text; putch(*text), ++text);
}
C/C++ Code:
void puts(UCHAR* text)
{
    for(; *text; putch(*text), ++text);
}


auch sehr schön:
C/C++ Code:
void k_clear_screen()
{
    k_memsetw (vidmem, 0x20 | (attrib << 8), 80 * 25);
    csr_x = 0; csr_y = 0; update_cursor();
}
C/C++ Code:
void k_clear_screen()
{
k_memsetw (vidmem, 0x20 | (attrib << 8), 80 * 25);
csr_x = 0; csr_y = 0; update_cursor();
}
C/C++ Code:
void k_clear_screen()
{
    k_memsetw (vidmem, 0x20 | (attrib << 8), 80 * 25);
    csr_x = 0; csr_y = 0; update_cursor();
}

:live:

Zitat:
Ist die Behandlung von \n, \t, usw. hier nicht doppelt? Das wird doch in putch auch schon geprueft...
In dem Zusammenhang nehme ich auch mal an, dass du als default-Fall nicht wirklich "puts" nehmen wolltest?

Ja, ich habe es mal auskommentiert. Habe putch(...) anstelle puts(...) gesetzt.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:26:43 09.04.2009, insgesamt 1-mal bearbeitet
Bitsy
Mitglied

Benutzerprofil
Anmeldungsdatum: 01.05.2001
Beiträge: 499
Beitrag Bitsy Mitglied 06:50:22 09.04.2009   Titel:              Zitieren

Habt ihr an das Backspace gedacht?
Für die ersten minimalen Editierdinge vielleicht doch wichtig.


Zuletzt bearbeitet von Bitsy am 06:54:23 09.04.2009, insgesamt 1-mal bearbeitet
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 10:42:38 09.04.2009   Titel:              Zitieren

Ist drin (siehe putch()). Was noch fehlt ist "bell". :p

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:58:31 09.04.2009   Titel:              Zitieren

Bell
Zitat:
Was noch fehlt ist "bell". :p
'\a': Was soll denn da passieren?
Ich habe es gerade mal ausprobiert:
C/C++ Code:
#include <iostream>

int main()
{
 for(int i=0;i<100;++i)
     std::cout << '\a' << "bell ";
}
C/C++ Code:
#include <iostream>

int main()
{
for(int i=0;i<100;++i)
std::cout << '\a' << "bell ";
}
C/C++ Code:
#include <iostream>

int main()
{
 for(int i=0;i<100;++i)
     std::cout << '\a' << "bell ";
}

Da kam nichts aus meinem PC! :D
Ich habe einen speaker code (timer, channel 2) probiert, aber da ist alles abgestürzt, hier ist der Code, ging aber nicht, alles abgestürzt. :rolleyes:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "os.h"

void sound(UINT frequency)
{
    outportb(0x43, 0xB6); //sending magic byte

    //writing frequency

    frequency=120000L/frequency;
    outportb(0x42, frequency>>8);
    outportb(0x42, (frequency<<8)>>8);

    //Sound on
    outportb(0x61, inportb(0x61)|3 );
}
void noSound()
{
    outportb(0x61, inportb(0x61) & ~3 );
}
void beep()
{
    sound(1500);
    sleepSeconds(1);
    noSound();
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "os.h"

void sound(UINT frequency)
{
outportb(0x43, 0xB6); //sending magic byte

//writing frequency

frequency=120000L/frequency;
outportb(0x42, frequency>>8);
outportb(0x42, (frequency<<8)>>8);

//Sound on
outportb(0x61, inportb(0x61)|3 );
}
void noSound()
{
outportb(0x61, inportb(0x61) & ~3 );
}
void beep()
{
sound(1500);
sleepSeconds(1);
noSound();
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "os.h"

void sound(UINT frequency)
{
    outportb(0x43, 0xB6); //sending magic byte

    //writing frequency

    frequency=120000L/frequency;
    outportb(0x42, frequency>>8);
    outportb(0x42, (frequency<<8)>>8);

    //Sound on
    outportb(0x61, inportb(0x61)|3 );
}
void noSound()
{
    outportb(0x61, inportb(0x61) & ~3 );
}
void beep()
{
    sound(1500);
    sleepSeconds(1);
    noSound();
}

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:38:19 09.04.2009, insgesamt 6-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:33:59 09.04.2009   Titel:              Zitieren

Als Belohnung für die, die bisher dabei geblieben sind:
http://www.youtube.com/watch?v=_RyodnisVvU ;)
http://www.youtube.com/watch?v=o8VqCqpfWrk

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:51:32 09.04.2009, insgesamt 1-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 23:52:28 09.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

http://www.youtube.com/watch?v=o8VqCqpfWrk

*gähn*
das sind coole roboter: http://www.bostondynamics.com/content/sec.php?section=robotics
(mit verbrennungsmotor und so)
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:50:52 10.04.2009   Titel:              Zitieren

OK, will niemanden langweilen, also "back to the grindstone":
http://www.henkessoft.de/OS_Dev/Downloads/PrettyOS_last_version.zip

Ich habe die GDT/IDT-Infos und Timer-Späßchen auf dem Screen lahm gelegt und begonnen, den Keyboard Treiber zu überarbeiten, damit man endlich Texte mit automatischem Zeilenumbruch und Scroll eintippen kann, so eine Art Primitiv-Editor eben. Nobuo T dürfte sich freuen, die while(TRUE) Story ist vorbei, nun läuft es nur einmal den "Scanner" durch, wie es logischer ist. BACKSPACE, TAB und ENTER funktionieren, aber man hat noch keine Steuerung mit den Pfeiltasten (da bin ich noch vorsichtig, ein move_cursor_right() ist allerdings schon eingebaut; Orientierung an schwarzer DOS-Box (cmd)?), diesbezüglich muss man also noch "übertippen" bzw. sich mit der Kombination aus TAB und BACKSPACE korrekt positionieren. Pos1, Ende, Entf ... sind auch noch nicht aktiviert. Das läuft ja alles via putc(...) als default im printformat(...), siehe keyboard_handler(...).
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include "keyboard.h"
#include
"os.h"

UCHAR ShiftKeyDown = 0; // Variable for Shift Key Down
UCHAR KeyPressed   = 0; // Variable for Key Pressed
UCHAR scan         = 0; // Scan code from Keyboard

UCHAR FetchAndAnalyzeScancode()
{
    if( inportb(0x64)&1 )
        scan = inportb(0x60);   // 0x60: get scan code from the keyboard

    // ACK: toggle bit 7 at port 0x61

    UCHAR port_value = inportb(0x61);
    outportb(0x61,port_value |  0x80); // 0->1
    outportb(0x61,port_value &~ 0x80); // 1->0

    if( scan & 0x80 ) // Key released? Check bit 7 (10000000b = 0x80) of scan code for this
    {
        KeyPressed = 0;
        scan &= 0x7F; // Key was released, compare only low seven bits: 01111111b = 0x7F
        if( scan == KRLEFT_SHIFT || scan == KRRIGHT_SHIFT ) // A key was released, shift key up?
        {
            ShiftKeyDown = 0;    // yes, it is up --> NonShift
        }
    }
    else // Key was pressed.
    {
        KeyPressed = 1;
        if( scan == KRLEFT_SHIFT || scan == KRRIGHT_SHIFT )
        {
            ShiftKeyDown = 1; // It is down, use asciiShift characters
        }
    }
    return scan;
}

UCHAR k_getch() // Scancode --> ASCII
{
    UCHAR retchar;                       // The chararacter that returns the scan code to ASCII code
    scan = FetchAndAnalyzeScancode();  // Grab scancode, and get the position of the shift key

    if( ShiftKeyDown )
        retchar = asciiShift[scan];       // (Upper) Shift Codes
    else
        retchar = asciiNonShift[scan]; // (Lower) Non-Shift Codes

    if( ( !(scan == KRLEFT_SHIFT || scan == KRRIGHT_SHIFT) ) && ( KeyPressed == 1 ) ) //filter Shift Key and Key Release
        return retchar; // ASCII version
    else
        return
0;
}

void keyboard_handler(struct regs* r)
{
   UCHAR KEY;
   KEY = k_getch();
   //restore_cursor();
   printformat("%c",KEY); // the ASCII character
   //save_cursor();

}

void keyboard_install()
{
    /* Installs 'keyboard_handler' to IRQ1 */
    irq_install_handler(1, keyboard_handler);
    keyboard_init();
}

/* Wait until buffer is empty */
void keyboard_init()
{
    while( inportb(0x64)&1 )
        inportb(0x60);
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include "keyboard.h"
#include
"os.h"

UCHAR ShiftKeyDown = 0; // Variable for Shift Key Down
UCHAR KeyPressed = 0; // Variable for Key Pressed
UCHAR scan = 0; // Scan code from Keyboard

UCHAR FetchAndAnalyzeScancode()
{
if( inportb(0x64)&1 )
scan = inportb(0x60); // 0x60: get scan code from the keyboard

// ACK: toggle bit 7 at port 0x61

UCHAR port_value = inportb(0x61);
outportb(0x61,port_value | 0x80); // 0->1
outportb(0x61,port_value &~ 0x80); // 1->0

if( scan & 0x80 ) // Key released? Check bit 7 (10000000b = 0x80) of scan code for this
{
KeyPressed = 0;
scan &= 0x7F; // Key was released, compare only low seven bits: 01111111b = 0x7F
if( scan == KRLEFT_SHIFT || scan == KRRIGHT_SHIFT ) // A key was released, shift key up?
{
ShiftKeyDown = 0; // yes, it is up --> NonShift
}
}
else // Key was pressed.
{
KeyPressed = 1;
if( scan == KRLEFT_SHIFT || scan == KRRIGHT_SHIFT )
{
ShiftKeyDown = 1; // It is down, use asciiShift characters
}
}
return scan;
}

UCHAR k_getch() // Scancode --> ASCII
{
UCHAR retchar; // The chararacter that returns the scan code to ASCII code
scan = FetchAndAnalyzeScancode(); // Grab scancode, and get the position of the shift key

if( ShiftKeyDown )
retchar = asciiShift[scan]; // (Upper) Shift Codes
else
retchar = asciiNonShift[scan]; // (Lower) Non-Shift Codes

if( ( !(scan == KRLEFT_SHIFT || scan == KRRIGHT_SHIFT) ) && ( KeyPressed == 1 ) ) //filter Shift Key and Key Release
return retchar; // ASCII version
else
return
0;
}

void keyboard_handler(struct regs* r)
{
UCHAR KEY;
KEY = k_getch();
//restore_cursor();
printformat("%c",KEY); // the ASCII character
//save_cursor();

}

void keyboard_install()
{
/* Installs 'keyboard_handler' to IRQ1 */
irq_install_handler(1, keyboard_handler);
keyboard_init();
}

/* Wait until buffer is empty */
void keyboard_init()
{
while( inportb(0x64)&1 )
inportb(0x60);
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include "keyboard.h"
#include
"os.h"

UCHAR ShiftKeyDown = 0; // Variable for Shift Key Down
UCHAR KeyPressed   = 0; // Variable for Key Pressed
UCHAR scan         = 0; // Scan code from Keyboard

UCHAR FetchAndAnalyzeScancode()
{
    if( inportb(0x64)&1 )
        scan = inportb(0x60);   // 0x60: get scan code from the keyboard

    // ACK: toggle bit 7 at port 0x61

    UCHAR port_value = inportb(0x61);
    outportb(0x61,port_value |  0x80); // 0->1
    outportb(0x61,port_value &~ 0x80); // 1->0

    if( scan & 0x80 ) // Key released? Check bit 7 (10000000b = 0x80) of scan code for this
    {
        KeyPressed = 0;
        scan &= 0x7F; // Key was released, compare only low seven bits: 01111111b = 0x7F
        if( scan == KRLEFT_SHIFT || scan == KRRIGHT_SHIFT ) // A key was released, shift key up?
        {
            ShiftKeyDown = 0;    // yes, it is up --> NonShift
        }
    }
    else // Key was pressed.
    {
        KeyPressed = 1;
        if( scan == KRLEFT_SHIFT || scan == KRRIGHT_SHIFT )
        {
            ShiftKeyDown = 1; // It is down, use asciiShift characters
        }
    }
    return scan;
}

UCHAR k_getch() // Scancode --> ASCII
{
    UCHAR retchar;                       // The chararacter that returns the scan code to ASCII code
    scan = FetchAndAnalyzeScancode();  // Grab scancode, and get the position of the shift key

    if( ShiftKeyDown )
        retchar = asciiShift[scan];       // (Upper) Shift Codes
    else
        retchar = asciiNonShift[scan]; // (Lower) Non-Shift Codes

    if( ( !(scan == KRLEFT_SHIFT || scan == KRRIGHT_SHIFT) ) && ( KeyPressed == 1 ) ) //filter Shift Key and Key Release
        return retchar; // ASCII version
    else
        return
0;
}

void keyboard_handler(struct regs* r)
{
   UCHAR KEY;
   KEY = k_getch();
   //restore_cursor();
   printformat("%c",KEY); // the ASCII character
   //save_cursor();

}

void keyboard_install()
{
    /* Installs 'keyboard_handler' to IRQ1 */
    irq_install_handler(1, keyboard_handler);
    keyboard_init();
}

/* Wait until buffer is empty */
void keyboard_init()
{
    while( inportb(0x64)&1 )
        inportb(0x60);
};


Was fehlt eurer Meinung nach noch bei dem EDIT-Modus des OS?
"Befehle" würde man dann wohl per ENTER entgegen nehmen?
In einem strcmp (analog zur Methode im Real Mode, jetzt nur in C) vergleichen und entsprechend über eine switch/case-Kontrollstruktur reagieren?
Welche Befehle würdet ihr denn als ersten Schritt implementieren?
- Info/info
- Help/help/?
- Reboot/reboot
- ...

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 12:05:03 10.04.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 12:12:28 10.04.2009   Titel:              Zitieren

Damit wir nicht den Gesamtüberblick verlieren, hier eine rohe Tasklist / Sammlung aus den bisherigen Posts:
Zitat:

- PIC (die beiden PICs wurden bereits beim remapping von IRQ 0-15 verarbeitet)
- PIT (programmable interval timer)
- Speaker (ja, BEEP (frequence)! Seit Win NT kaputt wegen Behinderung.)
- (video.c vernünftig ausbauen, bisher nur rudimentär)
- OS-Thematik (generell)
- Dynamische RAM Verwaltung:
- Unterteilung des Speichers in Blöcke statischer Groesse (4KB)
- Verwaltung (stat. Arrays, Bitmaps, dynam. Free-Lists)
- Reservierungsstrategie next fit
- Wiedereingliederungsproblematik
- Paging
- Programme & Prozesse
- Multitasking vs Singletasking
- Prozesserzeugung, Kontextwechsel, Scheduling, Verdrängung
- Privilegien / Schutzmechanismen / Adressraumtrennung
- Micro- vs Macro-Kernel
- inter-process communication

- Kernel-API (und einem HW-Abstraktions/Treiber-Prinzip).
Alle Kernel-Funktionen, Treiber etc. einfach nur ueber C-Funktionen und header zur Verfuegung zu stellen,
ist sicher nicht das Wahre. Ich wuerde die Einrichtung eines kleinen Sets der wichtigsten Funktionen zum
I/O und spaeter dann Speicher- und Prozessverwaltung ueber Interrupts aehnlich DOS oder Linux vorschlagen.
Je nachdem, was fuer einen Kern du basteln willst (Micro oder Monolith), waere es evtl. sinnvoll,
das schon ganz am Anfang beim Aufbauen der ersten abstrakteren OS-Funktionen wie RAM-Verwaltung zu diskutieren,
statt erst bei Adressraumtrennung, Privilegien und IPC. Evtl. mit Verweis auf diese spaeteren Themen zur Begruendung.


- Was du da weiter anfuehrst, sind doch eher Spezialfaelle und Teilgebiete, des Themenbereichs Scheduling
(Echtzeit-Prozesse). Solche Ansaetze wie Prioritaetensteuerung oder verschiedene Ansaetze fairer Ressourcenverteilung
mit verschiedensten abgefahrenen queue-Konstrukten (da gibt es wirklich eine Menge weit komplizierteres
als einfache Prioritaetensteuerung) kann man da vielleicht in einem Ueberblick kurz anschneiden,
aber um den Rahmen nicht zu sprengen, waere mein Vorschlag, sich schliesslich einfach auf Round Robin zu beschraenken.

- DMA-Gefrickel ist ja nun voellig abgehoben. Immer im Hinterkopf behalten, dass das ein Internet-Tutorial
und kein Kompendium zur OS-Entwicklung werden soll - das wird wie ich das sehe schon so eine ordentliche Portion Stoff.

Timer:
- für frei laufende countdown-timer machste dir z.b. ein paar funktionen:
// erzeugt einen neuen timer und meldet ihn beim OS an. gibt 0 zurück, wenn kein timer alloziert werden konnte
timer_t *timer_create(void);

// startet den timer, der ab jetzt vom OS von 'timeout' bis 0 runtergezählt wird
void timer_start (timer_t *timer, unsigned long timeout);

// prüft ob der timer abgelaufen ist, gibt 0 zurück, wenn der timer noch läuft, sonst 1
int timer_expired (timer *t);

// beseitigt den timer (trägt ihn z.b. aus der liste des OS aus und gibt seinen speicher frei)
void timer_free (timer_t *timer);

die hardware-isr schaut bei jedem tick in eine verkettete liste, ob timer drin sind, die sie runterzählen muss.


Keyboard:
- zu den I/O-daten: am besten du benutzt FIFO-buffer für sowas.
die ISR (z.b. von der tastatur) trägt empfangene daten in den FIFO ein und die anwendung holt sie sich raus.
ein tastatur-FIFO kann recht klein sein und darf ältere daten überschreiben, weil uralte tastendrücke ja nicht mehr interessieren.
ein benutzer-prozess kann dann einfach zeichen aus dem FIFO holen, z.b. so:
// hole ein zeichen aus dem tastatur-buffer. wenn c -1 (oder EOF) ist, war der FIFO leer
int c = getchar();

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 12:13:24 10.04.2009, insgesamt 1-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 15:11:37 10.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Was fehlt eurer Meinung nach noch bei dem EDIT-Modus des OS?

vi-Kompatibilitätsmodus? ;)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 15:55:27 10.04.2009   Titel:              Zitieren

Zitat:
vi-Kompatibilitätsmodus?
Interessanter Punkt. Ich kenne bisher nur dieses gvim und kann mich nur noch dunkel an den DOS editor (EDIT) erinnern. Arbeitet vi wie gvim?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 17:22:05 10.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zitat:
vi-Kompatibilitätsmodus?
Interessanter Punkt. Ich kenne bisher nur dieses gvim und kann mich nur noch dunkel an den DOS editor (EDIT) erinnern. Arbeitet vi wie gvim?

vim ist ein aufgemotzter vi, also voll kompatibel, aber genau so besch... in der bedienung. btw, ein editor ist doch kein bestandteil eines OS, sondern nur eine gewöhnliche anwendnung. mach besser mit'm OS weiter und nicht noch 'ne baustelle auf.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:11:04 10.04.2009   Titel:              Zitieren

Zitat:
ein editor ist doch kein bestandteil eines OS, sondern nur eine gewöhnliche anwendnung. mach besser mit'm OS weiter und nicht noch 'ne baustelle auf.
"Festina lente" sagt der Lateiner (Lieblingsspruch des Kaisers Augustus). Mir geht es aktuell darum, keyboard.c und video.c vernünftig zu stabilisieren. Diese beiden Module mit ihren Funktionen sind wichtig. Das wird dann auch das Ende von Teil 1 (Booten, RM, A20 Gate, RM -> PM, asm <-> C, GDT, IDT u. IRQ, video, timer und keyboard). Bei Teil 2 geht es mit dem wirklichen OS (Speicher, Multitasking, Prozesse, API, ...) weiter. Aber zuerst muss Teil 1 so abgerundet sein, dass man dort niemand verliert.

Ein echter Editor ist in der Tat ein User-Programm, gehört also nicht zwingend zum OS. Daher werde ich mich bezüglich der Bedienung an den DOS- und Linux-Konsolen orientieren.


Noch eine Detail-Frage: Über den PIT bin ich ja etwas weg gegangen, akzeptiere bisher die Standardeinstellung. Sollte man so etwas in der Art noch einbauen:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
void systemTimer_setFrequency( ULONG freq )
{
   ULONG divisor = 1193180 / freq; //divisor must fit into 16 bits
   
   //TODO: save frequency globally

   // Send the command byte.

   outportb(0x43, 0x36);

   // Send divisor.
   outportb(0x40, (UCHAR)(  divisor     & 0xFF )); // low  byte
   outportb(0x40, (UCHAR)( (divisor>>8) & 0xFF )); // high byte
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
void systemTimer_setFrequency( ULONG freq )
{
ULONG divisor = 1193180 / freq; //divisor must fit into 16 bits

//TODO: save frequency globally

// Send the command byte.

outportb(0x43, 0x36);

// Send divisor.
outportb(0x40, (UCHAR)( divisor & 0xFF )); // low byte
outportb(0x40, (UCHAR)( (divisor>>8) & 0xFF )); // high byte
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
void systemTimer_setFrequency( ULONG freq )
{
   ULONG divisor = 1193180 / freq; //divisor must fit into 16 bits
   
   //TODO: save frequency globally

   // Send the command byte.

   outportb(0x43, 0x36);

   // Send divisor.
   outportb(0x40, (UCHAR)(  divisor     & 0xFF )); // low  byte
   outportb(0x40, (UCHAR)( (divisor>>8) & 0xFF )); // high byte
}


Ich habe es mal mit 100 Hz (Standard: ca. 18 Hz), also alle 10 ms ein Tick, probiert:
C/C++ Code:
void timer_install()
{
    /* Installs 'timer_handler' to IRQ0 */
    irq_install_handler(0, timer_handler);
    systemTimer_setFrequency( 100 );
}
C/C++ Code:
void timer_install()
{
/* Installs 'timer_handler' to IRQ0 */
irq_install_handler(0, timer_handler);
systemTimer_setFrequency( 100 );
}
C/C++ Code:
void timer_install()
{
    /* Installs 'timer_handler' to IRQ0 */
    irq_install_handler(0, timer_handler);
    systemTimer_setFrequency( 100 );
}

C/C++ Code:
void sleepSeconds (ULONG seconds)
{
    // timer_wait((ULONG)18.2065*seconds); // standard
    timer_wait((ULONG)100*seconds);
}
C/C++ Code:
void sleepSeconds (ULONG seconds)
{
// timer_wait((ULONG)18.2065*seconds); // standard
timer_wait((ULONG)100*seconds);
}
C/C++ Code:
void sleepSeconds (ULONG seconds)
{
    // timer_wait((ULONG)18.2065*seconds); // standard
    timer_wait((ULONG)100*seconds);
}

Macht das mit 100 Hz Sinn? Sollte man hier eine Auswahl bieten oder eine Festeinstellung vornehmen? (wird für IRQ-gesteuertes Multitasking interessant)

Beim Keyboard verwende ich nun auch gespeicherte Cursors, falls man z.B. Infos in eine Statuszeile schreibt:
C/C++ Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
void keyboard_handler(struct regs* r)
{
   UCHAR KEY;
   KEY = k_getch();
   restore_cursor();
   printformat("%c",KEY); // the ASCII character
   save_cursor();
}
C/C++ Code:
1
2
3
4
5
6
7
8
void keyboard_handler(struct regs* r)
{
UCHAR KEY;
KEY = k_getch();
restore_cursor();
printformat("%c",KEY); // the ASCII character
save_cursor();
}
C/C++ Code:
1
2
3
4
5
6
7
8
void keyboard_handler(struct regs* r)
{
   UCHAR KEY;
   KEY = k_getch();
   restore_cursor();
   printformat("%c",KEY); // the ASCII character
   save_cursor();
}


ckernel.c:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include "os.h"

int main()
{
    k_clear_screen();

    // GDT, IDT, ISRS, IRQ, timer, keyboard
    gdt_install();
    idt_install();
    isrs_install();
    irq_install();
    timer_install(); //jetzt incl. Frequenz
    keyboard_install();
    sti();

    set_cursor(0,0);
    printformat("   ************************************************\n");
    printformat("   *                                              *\n");
    printformat("   *          Welcome to PrettyOS 0.05            *\n");
    printformat("   *                                              *\n");
    printformat("   *        The C kernel has been loaded.         *\n");
    printformat("   *                                              *\n");
    printformat("   ************************************************\n");

    settextcolor(4,1);
 
    int y=10;
    while(TRUE)
    {
    sleepSeconds(20);
    if(y>24) y=24;
    set_cursor(0,++y);
    printformat("10 sec have passed");
    };
    return 0;
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include "os.h"

int main()
{
k_clear_screen();

// GDT, IDT, ISRS, IRQ, timer, keyboard
gdt_install();
idt_install();
isrs_install();
irq_install();
timer_install(); //jetzt incl. Frequenz
keyboard_install();
sti();

set_cursor(0,0);
printformat(" ************************************************\n");
printformat(" * *\n");
printformat(" * Welcome to PrettyOS 0.05 *\n");
printformat(" * *\n");
printformat(" * The C kernel has been loaded. *\n");
printformat(" * *\n");
printformat(" ************************************************\n");

settextcolor(4,1);

int y=10;
while(TRUE)
{
sleepSeconds(20);
if(y>24) y=24;
set_cursor(0,++y);
printformat("10 sec have passed");
};
return 0;
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include "os.h"

int main()
{
    k_clear_screen();

    // GDT, IDT, ISRS, IRQ, timer, keyboard
    gdt_install();
    idt_install();
    isrs_install();
    irq_install();
    timer_install(); //jetzt incl. Frequenz
    keyboard_install();
    sti();

    set_cursor(0,0);
    printformat("   ************************************************\n");
    printformat("   *                                              *\n");
    printformat("   *          Welcome to PrettyOS 0.05            *\n");
    printformat("   *                                              *\n");
    printformat("   *        The C kernel has been loaded.         *\n");
    printformat("   *                                              *\n");
    printformat("   ************************************************\n");

    settextcolor(4,1);
 
    int y=10;
    while(TRUE)
    {
    sleepSeconds(20);
    if(y>24) y=24;
    set_cursor(0,++y);
    printformat("10 sec have passed");
    };
    return 0;
};

In Bochs klappt dies ganz gut mit den 100 Hz.


Allgemein:
Bezüglich des OS überdenke ich momentan die Reihenfolge. Wäre nun das "Paging" als nächster Schritt angesagt? Man kann diesem Mechanismus ja doch nicht wirklich entfliehen, und ich möchte wegen des interessanten inneren Aufbaus ein Multitasking-OS aufbauen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:50:20 10.04.2009, insgesamt 3-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 20:08:55 10.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Wäre nun das "Paging" als nächster Schritt angesagt? Man kann diesem Mechanismus ja doch nicht wirklich entfliehen, und ich möchte wegen des interessanten inneren Aufbaus ein Multitasking-OS aufbauen.

naja, virtual memory und paging/swapping/was-auch-immer kannste auch später noch einbauen. multitasking geht auch, ohne mmu und isolation des speichers der prozesse voneinander. nachträglich lässt sich virtual memory transparent ins system integrieren, ohne dass grossartige umbauten nötig sind. wenn dich das thema interessiert, kannste natürlich sofort damit loslegen. aber irgendwie werd' ich das gefühl nicht los, dass du dir sowas wie 'nen projektplan machen solltest.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:02:31 10.04.2009   Titel:              Zitieren

Zitat:
projektplan
@+fricky: Du siehst das IMHO sehr schematisch. "Projekte" sind zumeist langweilig, ökonomisch getrieben und haben einen engen Zielkorridor. So etwas interessiert mich nur beruflich.

Experimente schaffen dagegen wirklich Neues. Ich habe weitgehend klare Vorstellungen von der prinzipiellen Vorgehensweise. Obwohl es keine klare Theorie über den optimalen Weg gibt, werden vielfach bestehende OS als Ziel nachgeahmt. Als Ziel schwebt mir ein lernfähiges und bezüglich der Anforderungen adaptives OS vor, bin aber nicht sicher, ob dies im ersten Ansatz erreichbar ist.

Zur Zeit geht es erst einmal darum, die Basics stabil und dennoch flexibel zu arrangieren, um zum Experimentieren einzuladen. Das Ganze kann sich auch gabeln, wenn es darum geht interessante Pfade zu verfolgen. Bisher denke ich, habe ich hoffentlich noch keinen neuen wirklich verfolgenswerten Ansatz übersehen.

Einen Fehler muss ich allerdings gestehen, nämlich das Tutorial in deutsch aufgesetzt zu haben. Damit halte ich einige interessierte Mitstreiter aus aller Welt auf Distanz. Vielleicht kann ich noch kapitelweise englische Summaries einflechten, die das Nachvollziehen/Mitdenken erlauben.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:31:42 10.04.2009, insgesamt 1-mal bearbeitet
volkard
Moderator

Benutzerprofil
Anmeldungsdatum: 06.04.2000
Beiträge: 24349
Beitrag volkard Moderator 23:33:17 10.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Einen Fehler muss ich allerdings gestehen, nämlich das Tutorial in deutsch aufgesetzt zu haben. Damit halte ich einige interessierte Mitstreiter aus aller Welt auf Distanz. Vielleicht kann ich noch kapitelweise englische Summaries einflechten, die das Nachvollziehen/Mitdenken erlauben.

wenn du anklingen läßt, daß du dich freuen würdest, wenn das jemand übersetzen würde, dann findet sich vermutlich auch jemand, der sich freut, das offiziell zu übersetzen, natürlich mit namensnennung und link auf die hp des edlen helfers.

_________________
http://www.venganza.info/
plonk fürs Forum v1.02
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:48:59 10.04.2009   Titel:              Zitieren

Zitat:
wenn du anklingen läßt, daß du dich freuen würdest, wenn das jemand übersetzen würde, dann findet sich vermutlich auch jemand, der sich freut, das offiziell zu übersetzen, natürlich mit namensnennung und link auf die hp des edlen helfers.
Nein, daran habe ich wirklich nicht gedacht, da das Tutorial noch zu sehr im Fluss ist. Vorne den Abschnitt im Real Mode könnte man z.B. noch mit interessanten Befehlen/Funktionen aufbohren. Ich finde z.B. dein C++-Tutorial als didaktisches Vorbild super. Solche Fragestellungen mit Lösungen sind wirklich schön, weil man dadurch die Leser zum Experimentieren und selbst denken anregen kann. Es geht mir darum, auf praktische Weise zu zeigen, welche "Bausteine" beim OS-Bau zur Verfügung stehen, wie diese funktionieren und was man damit praktisch machen kann.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:54:34 10.04.2009   Titel:              Zitieren

Zunächst muss ich die Funktionen innerhalb video.c an allgemein übliche Vorgehensweisen anpassen. Mir ist z.B. aufgefallen, dass das "Backspace" noch nicht "löscht", das scheint aber üblich zu sein. http://de.wikipedia.org/wiki/Backspace
"Rücklöschtaste". Das und einiges andere muss ich zunächst anpassen, bevor es weiter geht. So, das sieht schon besser aus, sogar rekursiv :D :
Bei P(0,0) macht es gar nichts mehr, ansonsten geht es eins zurück, löscht (druckt ' ') und geht wieder eins zurück. Am Zeilenanfang muss ein Rücksprung ans Zeilenende eins höher erfolgen.
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void putch(UCHAR c)
{
    USHORT* pos;
    UINT att = attrib << 8;

    if(c == 0x08) // backspace: move the cursor back one space and delete
    {
        if(csr_x)
        {
            --csr_x;
            putch(' ');
            --csr_x;
        }
        if(!csr_x && csr_y>0)
        {
            csr_x=79;
            --csr_y;
            putch(' ');
            csr_x=79;
            --csr_y;
        }
   
    }
    // ...
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void putch(UCHAR c)
{
USHORT* pos;
UINT att = attrib << 8;

if(c == 0x08) // backspace: move the cursor back one space and delete
{
if(csr_x)
{
--csr_x;
putch(' ');
--csr_x;
}
if(!csr_x && csr_y>0)
{
csr_x=79;
--csr_y;
putch(' ');
csr_x=79;
--csr_y;
}

}
// ...
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void putch(UCHAR c)
{
    USHORT* pos;
    UINT att = attrib << 8;

    if(c == 0x08) // backspace: move the cursor back one space and delete
    {
        if(csr_x)
        {
            --csr_x;
            putch(' ');
            --csr_x;
        }
        if(!csr_x && csr_y>0)
        {
            csr_x=79;
            --csr_y;
            putch(' ');
            csr_x=79;
            --csr_y;
        }
   
    }
    // ...
}


Der Keyboard Handler fängt jetzt auch an, sich um die Sondertasten zu kümmern:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
void keyboard_handler(struct regs* r)
{
   UCHAR KEY;
   KEY = k_getch();
   restore_cursor();
   switch(KEY)
   {
       case KINS:
           break;
       case KDEL:
           move_cursor_right();
           putch('\b');//BACKSPACE
           break;
       case KHOME:
           move_cursor_home();
           break;
       case KEND:
           move_cursor_end();
           break;
       case KPGUP:
           break;
       case KPGDN:
           break;
       case KLEFT:
           move_cursor_left();
           break;
       case KUP:
           break;
       case KDOWN:
           break;
       case KRIGHT:
           move_cursor_right();
           break;
       default:
           printformat("%c",KEY); // the ASCII character
           break;
   }
   save_cursor();
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
void keyboard_handler(struct regs* r)
{
UCHAR KEY;
KEY = k_getch();
restore_cursor();
switch(KEY)
{
case KINS:
break;
case KDEL:
move_cursor_right();
putch('\b');//BACKSPACE
break;
case KHOME:
move_cursor_home();
break;
case KEND:
move_cursor_end();
break;
case KPGUP:
break;
case KPGDN:
break;
case KLEFT:
move_cursor_left();
break;
case KUP:
break;
case KDOWN:
break;
case KRIGHT:
move_cursor_right();
break;
default:
printformat("%c",KEY); // the ASCII character
break;
}
save_cursor();
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
void keyboard_handler(struct regs* r)
{
   UCHAR KEY;
   KEY = k_getch();
   restore_cursor();
   switch(KEY)
   {
       case KINS:
           break;
       case KDEL:
           move_cursor_right();
           putch('\b');//BACKSPACE
           break;
       case KHOME:
           move_cursor_home();
           break;
       case KEND:
           move_cursor_end();
           break;
       case KPGUP:
           break;
       case KPGDN:
           break;
       case KLEFT:
           move_cursor_left();
           break;
       case KUP:
           break;
       case KDOWN:
           break;
       case KRIGHT:
           move_cursor_right();
           break;
       default:
           printformat("%c",KEY); // the ASCII character
           break;
   }
   save_cursor();
}


In video.c musste auch noch einiges hinzu gefügt werden.
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void move_cursor_right()
{
    ++csr_x;
    if(csr_x>=80)
    {
      ++csr_y;
      csr_x=0;
    }
}

void move_cursor_left()
{
    if(csr_x)
        --csr_x;
    if(!csr_x && csr_y>0)
    {
        csr_x=79;
        --csr_y;
    }
}

void move_cursor_home()
{
    csr_x = 0; update_cursor();
}

void move_cursor_end()
{
    csr_x = 79; update_cursor();
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void move_cursor_right()
{
++csr_x;
if(csr_x>=80)
{
++csr_y;
csr_x=0;
}
}

void move_cursor_left()
{
if(csr_x)
--csr_x;
if(!csr_x && csr_y>0)
{
csr_x=79;
--csr_y;
}
}

void move_cursor_home()
{
csr_x = 0; update_cursor();
}

void move_cursor_end()
{
csr_x = 79; update_cursor();
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void move_cursor_right()
{
    ++csr_x;
    if(csr_x>=80)
    {
      ++csr_y;
      csr_x=0;
    }
}

void move_cursor_left()
{
    if(csr_x)
        --csr_x;
    if(!csr_x && csr_y>0)
    {
        csr_x=79;
        --csr_y;
    }
}

void move_cursor_home()
{
    csr_x = 0; update_cursor();
}

void move_cursor_end()
{
    csr_x = 79; update_cursor();
}

wie üblich:
http://www.henkessoft.de/OS_Dev/Downloads/PrettyOS_last_version.zip

Wenn jemand hier bessere Ideen hat, bitte posten.
Ich bin mir z.B. noch nicht sicher, ob man bei der Instruktionseingabe überhaupt einen Wechsel der Zeile - und damit mehrzeilige Eingaben - zulassen sollte.
Bei END springe ich an das Ende der Zeile und nicht an das Ende des Eingetippten. Bei DEL lösche ich auch nur ein Zeichen und schiebe nicht den Rest der Zeile eins nach links.
Vielleicht müsste man zwischen zwei ENTER einen virtuellen Befehlsstring aufbauen, der von HOME bis END geht. Zumindest sieht es bei der DOS-Box (Konsole) so aus. Da bin ich noch flexibel.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:14:02 11.04.2009, insgesamt 3-mal bearbeitet
Bitsy
Mitglied

Benutzerprofil
Anmeldungsdatum: 01.05.2001
Beiträge: 499
Beitrag Bitsy Mitglied 10:07:36 11.04.2009   Titel:              Zitieren

Ist auch einfach die Frage, wie komfortabel Du das überhaupt gestalten möchtest.
Ein grundlegender Kommandointerpreter könnte ja einen eigenen Editor mitbringen, sodaß etwas Rudimentäres vollkommen ausreicht. Auf der anderen Seite kannst Du's im Kernel aber bis zum kompletten Memoryhexeditor treiben ;)
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 10:48:47 11.04.2009   Titel:              Zitieren

IMHO haben konkrete Reaktionen auf Tasteneingaben im IRQ-Handler (HW-Treiber) nichts zu suchen. Das sind Teile einer Anwendung. Ist vielleicht so zu Demo-Zwecken ganz nett, aber mit brauchbarem OS-Design hat das nichts zu tun.
Irgendwie macht das so immer noch den Eindruck, als wuerdest du die Sache ein wenig wie dieses erste Polling-Relikt behandeln.
Also entweder ueberlegst du dir ein vernuenftiges Treiber-Design und machst bei keyboard und video dann mal langsam die Kiste zu (das bedeutet auch, dass du kapselnde Funktionen brauchst, falls du mal mit dem Entwurf einer echten API anfaengst), dann kannst du auf diesen abgeschlossenen Treibern auch etwas rumbasteln, das ueber den Rest des Tutorials im Prinzip so funktionieren sollte, oder du beschraenkst dich hier nur auf das absolut notwendigste. Solche aufwendigen, dennoch halbgaren und bestenfalls bis zum Ende dieses Kapitels brauchbaren Basteleien sind IMHO kontraproduktiv.

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908


Zuletzt bearbeitet von Nobuo T am 10:54:21 11.04.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 16:12:26 11.04.2009   Titel:              Zitieren

Zitat:
IMHO haben konkrete Reaktionen auf Tasteneingaben im IRQ-Handler (HW-Treiber) nichts zu suchen. Das sind Teile einer Anwendung. Ist vielleicht so zu Demo-Zwecken ganz nett, aber mit brauchbarem OS-Design hat das nichts zu tun.
Ja, das ist völlig richtig. Ich werde jetzt bei video.c und keyboard.c aufhören, als kleine Demo reichen diese Funktionen bereits. "Externe Anwendungen" sind noch nicht lauffähig. Was ich auf der Stufe noch einfügen möchte, ist ein Kommandozeileninterpreter mit nachgeschaltetem strcmp(...) und entsprechenden Reaktionen so wie beim Real Mode, am besten in main(), diesmal nur in C programmiert und ohne BIOS. Diese Parallele erwartet man irgendwie. :)
Dann geht's im zweiten Teil thematisch mit Paging, Heap, Designfragen weiter. Das wird dann aber alles elend komplex. Da knabbere ich noch dran. Zur Zeit beschimpft mich sogar schon mein Linker, weil ich Paging und Heap modular nicht sauber auseinander halte. Übel, übel, .... :D
EDIT: zumindest das endlich geschafft. :D

@Nobuo T: Wenn ich Dich richtig verstanden habe, würdest Du im Keyboard Handler die Information in eine Queue stecken. Der Kommandozeilen-Interpreter (wo gehört der als "Anwendung" hin? Für mich ist dies noch Teil des Kernels.) müsste sich diese dann dort abholen und verarbeiten, so wie jetzt - zur Demo - bereits im Keyboard Handler erfolgt, richtig? Der Kommandozeilen-Interpreter muss ein Prompt drucken, nach ENTER die Zeile (ohne Prompt) schlucken und verarbeiten mittels strcmp und switch/case-Struktur (wie bei einer Windows-Nachrichten-Pumpe).

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 17:25:00 11.04.2009, insgesamt 8-mal bearbeitet
jenz
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.06.2005
Beiträge: 227
Beitrag jenz Mitglied 18:18:45 11.04.2009   Titel:              Zitieren

Der Keyboardhandler sollte die Eingaben nicht in eine eigene Queue fließen lassen, sondern gleich an die Queue der aktiven Anwendung.
Deshalb würde ich als nächstes damit beginnen Grundstrukturen für Anwendungen zu definieren. Da gehören dann auch die Schnittstellen zu Treibern dazu.

Wenn man die Grundstrukturen hat, dann am besten gleich Multitasking/threading und nen einfach Scheduler einbauen, dann macht es einfach mehr Spaß.

Man kann auch erst mal die Schnittstellen zu den Treibern weglassen und einfach ein paar Anwendungen laufen lassen. Die könnten dann ja alle gleichzeitig in den Bildschirm malen.

Wenn man erst mal zwischen Anwendungen und Kern/System getrennt hat, dann ist es einfacher die Schnittstellen zu entdecken und zu bauen. Das diese dann gleich so angenehm wie möglich sind ist natürlich noch eine ganz andere Frage.

jenz
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:49:04 11.04.2009   Titel:              Zitieren

Zitat:
zwischen Anwendungen und Kern/System getrennt
Ja, das ist wohl der entscheidende Punkt.

Zitat:
Der Keyboardhandler sollte die Eingaben nicht in eine eigene Queue fließen lassen, sondern gleich an die Queue der aktiven Anwendung.
Ja, das klingt sinnvoll, damit es keine Verwechslungsprobleme beim Leeren eines gemeinsamen Briefkastens gibt. Das Problem ist, dass wir noch keine Anwendungen laufen lassen können, weil die Strukturen hierzu noch fehlen. Würdest Du den Kommandozeileninterpreter bereits als Anwendung in Privilegstufe 3 laufen lassen?

Zitat:
Am besten gleich Multitasking/Threading und 'nen einfachen Scheduler einbauen, dann macht es einfach mehr Spaß.
Spaß klingt gut. :)

Zitat:
Man kann auch erst mal die Schnittstellen zu den Treibern weglassen und einfach ein paar Anwendungen laufen lassen. Die könnten dann ja alle gleichzeitig in den Bildschirm malen.
Das mache ich momentan mit dem Timer und dem "Editor" Keyboard Handler ja auch, deshalb musste ich schon den Cursor speichern.

Ich experimentiere gerade mit einem Paging-/Heap-Modul, ist kompliziert (schlecht für Didaktik), miteinander vernetzt und klappt leider noch nicht, wie ich es will. Das wollte ich als nächsten Schritt einfügen, noch bevor die Anwendungen im Multitasking laufen. Das gehört aber alles nach Teil 2, der leider viel Zeit braucht (liegt an meinen beschränkten Fähigkeiten und Erfahrungen in diesem Bereich). Macht aber nichts, fahre ja kein Wettrennen.

Teil 1 wollte ich mit einem kleinen Befehlsinterpreter im Kernel (Analogie zur Vorgehensweise im RM) beenden, damit die eingetippten Zeichen Sinn machen. Kann man aber in Teil 2 wohl alles wegwerfen, da hat Nobuo T leider Recht. :rolleyes:
Sehe ich aber nicht als großes Problem.
EDIT: Vielleicht kann man die Idee mit dem BIOS-Briefkasten und dem Abholen der Post dort durch einen Befehlsinterpreter kombinieren. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 18:59:26 11.04.2009, insgesamt 2-mal bearbeitet
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 18:54:00 11.04.2009   Titel:              Zitieren

Klar waere es ein praktisches Konzept, eine KB-queue pro Anwendung einzurichten. Da das OS in diesem Stadium aber noch nicht mal ein Konzept fuer Anwendungen hat, ist das alles noch Zukunftsmusik und erst im naechsten Kapitel ausfuehrlich zu diskutieren.
Eine globale queue zum Ablegen der KB-Codes (so macht es das BIOS auch) waere im Moment sicher am praktischsten. Diese liesse sich spaeter auch relativ einfach entsprechend den Beduerfnissen des Multitaskings anpassen.
Die ISR liest also die Scancodes vom KB, setzt die Flags, wandelt in ASCII-Codes um, o.Ae. und eine getch-Funktion (vgl. int 16h, ah=0) liest die queue dann im Rahmen der Anwendung (hier einfach des "Kerns") wieder aus.

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
jenz
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.06.2005
Beiträge: 227
Beitrag jenz Mitglied 18:56:00 11.04.2009   Titel:              Zitieren

Ja, ich würde die Anwendung erst mal im Kern laufen lassen. Erst mal alle Anwendungen.

Die dürfen natürlich von Anfang an nur über entsprechende Methodenaufrufe auf Systemfunktionen zugreifen, da kann man dann den Wechsel von Rang 0 auf 3 oder wie herum auch immer Transparent einbauen.

Aber erst mal muss was laufen. Dann hat man auch leichter die Möglichkeit Aufgaben abzugeben und jemand anderes kann dir Testanwendungen zusammenbauen oder an Treiberfunktionen schrauben.

Ich würde (habe) es (mal mehr mal weniger) schön mit C++, nicht mit C machen (gemacht).

jenz
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:02:03 11.04.2009   Titel:              Zitieren

Zitat:
Ich würde (habe) es (mal mehr mal weniger) schön mit C++, nicht mit C machen (gemacht).
Im Kernel bleiben wir bei C.

@Nobuo T: welche Flags meinst Du genau (nehmen wir die BDA als Vorbild) setzen? Diesen Bereich bei 40:17? Gibt es bereits eine vereinfachte (oder auch die komplette) BDA Struktur als C-Struct, die man einsetzen könnte oder muss man das selbst aufbauen? Da könnte man ja auch die statische Queue gleich ablaufen lassen.
Im BDA wird offenbar 40:1E - 40:3D als "circular queue buffer" (32 Byte) verwendet.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:17:01 11.04.2009, insgesamt 1-mal bearbeitet
jenz
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.06.2005
Beiträge: 227
Beitrag jenz Mitglied 19:03:24 11.04.2009   Titel:              Zitieren

Schade, kann ich die Begründung weiter oben im Thread lesen?
Wenn nicht, wieso?
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 20:53:40 11.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
welche Flags meinst Du genau (nehmen wir die BDA als Vorbild) setzen? Diesen Bereich bei 40:17?

Jup, genau die.

Erhard Henkes schrieb:
Gibt es bereits eine vereinfachte (oder auch die komplette) BDA Struktur als C-Struct, die man einsetzen könnte oder muss man das selbst aufbauen? Da könnte man ja auch die statische Queue gleich ablaufen lassen.
Im BDA wird offenbar 40:1E - 40:3D als "circular queue buffer" (32 Byte) verwendet.

Keine Ahnung, ob es da bereits etwas fertiges gibt. Da was eigenes zu implementieren sollte aber wohl schneller erledigt sein, als nun erst was zu suchen. ;)

Musst ja erstmal auch nicht alles implementieren, und auch nicht genau wie in der BDA. Nicht vergessen: Das ist nur ein moegliches Konzept, das in der Form wahrscheinlich auch nicht gerade ideal fuer Multitasking geeignet ist.

... ...
Evtl. bietet es sich als naechstes dann doch schon mal an, vorausschauend grob etwas ueber das Treiber-Design nachzudenken. zB. erstmal:
Was hast du an Input von der HW? Was davon willst du welchen Anwendungen in welchem Fall mitteilen? Welche Datenstruktur koennte sich dazu eignen? Was fuer Interface-Funktionen koennte man darauf benutzen?

jenz schrieb:
Schade, kann ich die Begründung weiter oben im Thread lesen?
Wenn nicht, wieso?

Ja, das wurde bereits diskutiert und einvernehmlich befunden, dass die Nachteile beim Einsatz von C++ die Vorteile bisher ueberwiegen.

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 23:37:43 11.04.2009   Titel:              Zitieren

Nobuo T schrieb:
IMHO haben konkrete Reaktionen auf Tasteneingaben im IRQ-Handler (HW-Treiber) nichts zu suchen. Das sind Teile einer Anwendung. Ist vielleicht so zu Demo-Zwecken ganz nett, aber mit brauchbarem OS-Design hat das nichts zu tun.
Irgendwie macht das so immer noch den Eindruck, als wuerdest du die Sache ein wenig wie dieses erste Polling-Relikt behandeln.
Also entweder ueberlegst du dir ein vernuenftiges Treiber-Design und machst bei keyboard und video dann mal langsam die Kiste zu (das bedeutet auch, dass du kapselnde Funktionen brauchst, falls du mal mit dem Entwurf einer echten API anfaengst), dann kannst du auf diesen abgeschlossenen Treibern auch etwas rumbasteln, das ueber den Rest des Tutorials im Prinzip so funktionieren sollte, oder du beschraenkst dich hier nur auf das absolut notwendigste. Solche aufwendigen, dennoch halbgaren und bestenfalls bis zum Ende dieses Kapitels brauchbaren Basteleien sind IMHO kontraproduktiv.

alle daumen hoch. dem muss man nichts mehr hinzufügen.

jenz schrieb:

Der Keyboardhandler sollte die Eingaben nicht in eine eigene Queue fließen lassen, sondern gleich an die Queue der aktiven Anwendung.

würde ich nicht so machen. die queue gehört in den keyboard-treiber bzw. in den kernel und anwendungen können sich was daraus abholen. ebenso würde ich mit maus-events verfahren. auch würde ich mir die möglichkeit offen lassen, mehrere mäuse und mehrere keyboards anschliessen zu können, also von vorn herein modulare, objektorientierte strukturen zu schaffen, finde ich ziemlich wichtig.

Erhard Henkes schrieb:

Der Kommandozeilen-Interpreter (wo gehört der als "Anwendung" hin? Für mich ist dies noch Teil des Kernels.)

nee, ein komandozeilen-interpreter ist bestenfalls eine sogenannte 'shell', also eine art bindeglied zwischen benutzer und bestimmten system-services. der gehört genau so wenig in den kernel, wie ein editor oder eine tabellenkalkulation.

jenz schrieb:
Schade, kann ich die Begründung weiter oben im Thread lesen?
Wenn nicht, wieso?

C++ ist unglaublich mächtig, aber auch komplex und 'esoterisch'. man könnte natürlich c++ verwenden, aber dann bräuchte man knallharte coding-richtlinien und leute, die diszipliniert und perfekt im umgang mit dieser sprache sind, sonst wird das nix. C ist im vergleich dazu primitiv und einfach strukturiert. das ist aber der entscheidende vorteil: weniger ist mehr. z.b. sind fehler in einem C-programm, im vergleich zu C++, trivial, leicht zu finden/debuggen und haben weniger weitreichende folgen.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:46:23 11.04.2009   Titel:              Zitieren

Mir würde C++ leichter fallen als C, aber ich weiß von den Robotik-Anwendungen, dass man nur gewisse Features sinnvoll nutzen kann, sozusagen gekapseltes C mit Klassen ist der Idealstil, aber das schafft man auch anders. Daher trage ich die Entscheidung für C eindeutig mit. Wenn man vernünftig damit umgeht, ist es ein herrliches Bindeglied zwischen Assembler und der Hochsprachen-Welt, im OS-Bereich sicher die richtige Wahl.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:17:35 12.04.2009, insgesamt 1-mal bearbeitet
jenz
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.06.2005
Beiträge: 227
Beitrag jenz Mitglied 02:20:18 12.04.2009   Titel:              Zitieren

stimmt, objektorientiert kann man auch mit c entwickeln. ist aber aus meiner sicht eben fehleranfälliger und auch aufwendiger beim schreiben. aber okay, entscheidung ist gefallen.

warum sollen sich die anwendungen denn die ereignisse selbst abholen? man kann die doch besser von anfang gleich eventgesteuert implementieren.
pollen ist doch nicht wirklich schön

jenz
Unregistrierter





Beitrag Unregistrierter 11:06:27 12.04.2009   Titel:              Zitieren

Hat es angesichts der Diskussion über das weitere Vorgehen noch einen Sinn, den jeweils aktuellen Quellcode mal unter die Lupe zu nehmen?
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 11:42:28 12.04.2009   Titel:              Zitieren

jenz schrieb:

warum sollen sich die anwendungen denn die ereignisse selbst abholen?

weil das z.b. für sequenziell ablaufende programme (ein stinknormales c-programm z.b. das mit 'main' beginnt) einfacher ist und es bedeutet auch weniger verwaltungsaufwand im kernel (der schiebt einfach daten in die dazugehörigen queues und kümmert sich nicht weiter drum). falls du auf sowas wie eventgesteuerte gui-anwendnungen anspielst, die sind ja clients eines 'window-managers', der prinzipiell selber bloss eine anwendung ist. er würde dann z.b. beim eintreffen eines zeichens die window-prozedur des entsprechenden fensterchens aufrufen und damit hätte die gui-anwendung ihre events.

jenz schrieb:

man kann die doch besser von anfang gleich eventgesteuert implementieren.
pollen ist doch nicht wirklich schön.

mit dem 'selbstabholen' hat man doch beide möglichkeiten. beispiele mit einem non-blocking getchar()...

event-gesteuert:
Code:
int c;
wait_for_event (KEYBOARD_EVENT);  // die task schläft, bis mindestens 1 zeichen in der queue ist
c = getchar();  // zeichen abholen
Code:
int c;
wait_for_event (KEYBOARD_EVENT); // die task schläft, bis mindestens 1 zeichen in der queue ist
c = getchar(); // zeichen abholen
Code:
int c;
wait_for_event (KEYBOARD_EVENT);  // die task schläft, bis mindestens 1 zeichen in der queue ist
c = getchar();  // zeichen abholen

polling:
Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
int c;
c = getchar();  // zeichen abholen, -1 bei fehlschlag
if (c > 0)
{
  // ein zeichen ist da
}
else
{
  // war leider nix
}
Code:
1
2
3
4
5
6
7
8
9
10
int c;
c = getchar(); // zeichen abholen, -1 bei fehlschlag
if (c > 0)
{
// ein zeichen ist da
}
else
{
// war leider nix
}
Code:
1
2
3
4
5
6
7
8
9
10
int c;
c = getchar();  // zeichen abholen, -1 bei fehlschlag
if (c > 0)
{
  // ein zeichen ist da
}
else
{
  // war leider nix
}
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 13:11:04 12.04.2009   Titel:              Zitieren

Zitat:
Hat es angesichts der Diskussion über das weitere Vorgehen noch einen Sinn, den jeweils aktuellen Quellcode mal unter die Lupe zu nehmen?

Da gäbe es zwei Aspekte, wo ich Unterstützung/Zustimmung brauchen könnte:

1) Ich habe mal versuchsweise einen Paging/Heap-Mechanismus eingebaut, der aber sehr kompliziert ist, also für den ersten Schritt noch vereinfacht werden sollte, und leider noch nicht funktioniert, habe Testroutinen eingebaut, um zu sehen, wo der Code ausflippt: z.Z. beim Umschalten auf das Paging (wahrscheinlich sind Speicheradressen falsch vorgegeben), echte Tüftelei.
Da könnte sich jemand auf die Dateien ordered_array.h/c, kheap.h/c und paging.h/c konzentrieren und diese aus didaktischen Gründen vereinfachen und in PrettyOS zum Laufen bringen (da beiße ich gerade dran rum und komme nicht wirklich weiter). Ich habe diesen Code mal hochgeschickt, in der Hoffnung, dass mir jemand einen guten Tipp gibt:
http://www.henkessoft.de/OS_Dev/Downloads/20_paging_heap_problems.zip

2) s.u. (Circular Queue: füllen, leeren)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 13:18:27 12.04.2009, insgesamt 1-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 13:25:56 12.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Da könnte sich jemand auf die Dateien ordered_array.h/c, kheap.h/c und paging.h/c konzentrieren...

woher ist der code? oder haste alles selbst geschrieben?
:)
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 13:37:15 12.04.2009   Titel:              Zitieren

ah, schon gefunden: http://www.jamesmolloy.co.uk/tutorial_html/7.-The%20Heap.html
ist die frage, ob da bugs drin sind, oder ob du nachträglich was fehlerhaftes reinbastelt hast. ich würde vorschlagen, du machst sowas wie 'nen unit-test, also ein kleines testprogramm für den heap, das (unter windoofs, mit msvc z.b.) ohne dein OS läuft. dann kannste auch besser debuggen.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 14:08:49 12.04.2009   Titel:              Zitieren

@+fricky: Der ganze Code gefällt mir nicht, da er schwierig zu verstehen und vor allem bezüglich paging und heap nicht voneinander unabhängig ist, aber ich habe bisher noch kein besseres Beispiel gefunden, wollte die Mechanismen auf die Schnelle ausprobieren und analysieren, was man für einen ersten Einstieg wirklich benötigt. James Molloy ist einer der Moderatoren und führenden Köpfe bei osdev.net. Sein Code basiert teilweise auf älteren Arbeiten im Rahmen von Bran's Tutorial.

Die Idee mit dem unit test ist brauchbar.

Wenn man sti() vor der Paging-Initialisierung anschaltet, kracht es noch früher, für mich momentan nicht nachvollziehbar. :rolleyes:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 14:15:10 12.04.2009, insgesamt 3-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 14:32:35 12.04.2009   Titel:              Zitieren

zu 2) Ich mache mir momentan Gedanken im Verständnis des Queue-Mechanismus:
Wie bewegt man die beiden Zeiger Head and Tail am sinnvollsten? Der buffer verändert ja seine inhaltsbedeutende Größe. Tail ist der Eingang und wird vom Keyboard Handler versorgt. Der wandert bei jedem Key Entry Event eins nach "links", so dass die Zeichen in einer Kette angeordnet werden. Nun aber zum Head: Wenn die KeyQueue (KQ) leer ist, sind doch Head und Tail deckungsgleich und der Key an dieser Stelle wird auf ??? gesetzt. Man kann ja prüfen ob Head und Tail verschieden sind, wenn nein ist die KQ leer (Head minus Tail == 0), wenn ja, stehen Head minus Tail Zeichen drinnen. Sobald Zeichen rein kommen, wandern Head und Tail auseinander, Tail nach links, Head bleibt stehen. Sobald eine "Anwendung" ein Zeichen abholt, wandert Head ebenfalls eins nach links. Habe so etwas noch nie gebaut, daher die Frage, ob das so stimmt. man muss ja noch den Circular-Mechanismus einbauen: Bei Zeiger < KEYQUEUE springt man auf KEYQUEUE+KQSIZE-1, richtig?

Nun zu den "Zeichen" in der KQ: Ein Zeichen besteht ja aus dem ASCII-Zeichen plus Flags (Sonderzeichen), d.h. pro Zeichen müsste man eigentlich mindestens zwei Byte ablegen, eins enthält das ASCII-Zeichen (da könnte man Shift auch gleich verarbeiten, also im Flag weglassen) und eins die Zusatz-Info, z.B. (Shift links/rechts), ALT/ALT Gr, CTRL links/rechts, usw. bzw. Kombinationen davon. (Bisher analysiere ich im Handler ja nur die Shift-Taste, rechts/links noch gleich).

Ich hoffe, ihr versteht, was ich da schreibe. :confused:
Ich verstehe momentan nicht wie BIOS/BDA das machen, weil dort ja die Sondertasten-Bits stehen. Zu jedem Tastenanschlag gehört ja je nach design entweder nur eine Taste (shift/non-shift) oder eine Kombination aus Sondertasten und Taste (vielleicht zu kompliziert). Momentan kommen wir an ALT Gr aber nicht ran.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 14:49:27 12.04.2009, insgesamt 2-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 14:48:40 12.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Der ganze Code gefällt mir nicht, da er schwierig zu verstehen und vor allem bezüglich paging und heap nicht voneinander unabhängig ist...

naja, memory-management ist nie 'ne einfache sache. am anfang liefert der kernel ein paar aufeinanderfolgende speicherseiten und der heap-manager ist dazu da, diese relativ grossen speicherbereich in kleinere häppchen zu verhackstücken. sind alle seiten aufgebraucht, dann müssen vom kernel neue seiten angefordert werden, die hinten angehängt werden. trennen kannste das insofern, dass der heap-manager (testweise) mit einem fixen block arbeitet. also,
baustelle-1, kernel: seitenverwaltung, paging, virtual memory.
baustelle-2, heap-manager: einen beliebig grossen, zusammenhängenden speicherbereich mit malloc/realloc/free zu zerstückeln.
baustelle-3: zusammenspiel beider subsysteme.
wichtig ist z.b. auch, dass es mehrere instanzen des heap-managers geben kann, so dass jeder prozess seinen eigenen heap bekommt. auch im kernel sollte mindestens eine instanz des heap-managers da sein, damit kernel-komponenten nicht für jeden kleinkram eine ganze speicherseite verbraten müssen.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 14:52:10 12.04.2009   Titel:              Zitieren

Danke für die Ideen.

Der "Reset" des OS erfolgt bei noch ausgeschaltetem Interrupt hier:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
//TEST
    printformat("switch_page_directory before paging switch \n");
    for (counter=0; counter<50000000; ++counter);
//TEST

    cr0 |= 0x80000000; // Enable paging by setting the PG bit in the CR0 register //Absturz!!!
    asm volatile("mov %0, %%cr0":: "r"(cr0));

//TEST
    printformat("switch_page_directory after paging switch \n");
    for (counter=0; counter<50000000; ++counter);
//TEST
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
//TEST
printformat("switch_page_directory before paging switch \n");
for (counter=0; counter<50000000; ++counter);
//TEST

cr0 |= 0x80000000; // Enable paging by setting the PG bit in the CR0 register //Absturz!!!
asm volatile("mov %0, %%cr0":: "r"(cr0));

//TEST
printformat("switch_page_directory after paging switch \n");
for (counter=0; counter<50000000; ++counter);
//TEST
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
//TEST
    printformat("switch_page_directory before paging switch \n");
    for (counter=0; counter<50000000; ++counter);
//TEST

    cr0 |= 0x80000000; // Enable paging by setting the PG bit in the CR0 register //Absturz!!!
    asm volatile("mov %0, %%cr0":: "r"(cr0));

//TEST
    printformat("switch_page_directory after paging switch \n");
    for (counter=0; counter<50000000; ++counter);
//TEST

"switch_page_directory before paging switch " wird ausgegeben.
Dann wird der Cursor eins nach unten geschoben???
Dann erfolgt der Neustart (wohl triple fault).

Schaltet man sti() vorher ein, so kracht es sofort. Man sieht keine einzige Meldung:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#define PHYSICAL_MEMORY 0x4000000 // The size of physical memory, assume it is 64MB big.
#define
PAGESIZE        0x1000    // 0x1000 = 4096 = 4K
#define
XYZ_ADDRESS     0x300000  // ???

void paging_install()
{
    ULONG mem_end_page = PHYSICAL_MEMORY;
    nframes = mem_end_page/PAGESIZE;
    frames  = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes));
    k_memset(frames, 0, INDEX_FROM_BIT(nframes));

//TEST
    ULONG counter;
    printformat("nframes: %d frames: %d \n", nframes, frames);
    for (counter=0; counter<50000000; ++counter);
//TEST

    //ULONG phys;

    kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t));
    k_memset(kernel_directory, 0, sizeof(page_directory_t));
    kernel_directory->physicalAddr = (ULONG)kernel_directory->tablesPhysical;

//TEST
    printformat("kernel_directory->physicalAddr: %x \n", kernel_directory->physicalAddr);
    for (counter=0; counter<50000000; ++counter);
//TEST
    int i = 0;
    for (i=KHEAP_START; i<KHEAP_START+KHEAP_INITIAL_SIZE; i+=PAGESIZE)
        get_page(i, 1, kernel_directory);

//TEST
    printformat("get_page \n");
    for (counter=0; counter<50000000; ++counter);
//TEST

    i = 0;
    while (i < XYZ_ADDRESS ) //placement_address+0x1000)
    {
        alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
        i += PAGESIZE;
    }
    for (i = KHEAP_START; i < KHEAP_START+KHEAP_INITIAL_SIZE; i+=PAGESIZE)
        alloc_frame( get_page(i, 1, kernel_directory), 0, 0);

//TEST
    printformat("alloc_frame part 1 and 2 \n");
    for (counter=0; counter<50000000; ++counter);
//TEST

    // register_interrupt_handler(14, page_fault); // TODO???

    switch_page_directory(kernel_directory);//Hier liegt der Absturz begraben!

    kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0);
    current_directory = clone_directory(kernel_directory);
    switch_page_directory(current_directory);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#define PHYSICAL_MEMORY 0x4000000 // The size of physical memory, assume it is 64MB big.
#define
PAGESIZE 0x1000 // 0x1000 = 4096 = 4K
#define
XYZ_ADDRESS 0x300000 // ???

void paging_install()
{
ULONG mem_end_page = PHYSICAL_MEMORY;
nframes = mem_end_page/PAGESIZE;
frames = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes));
k_memset(frames, 0, INDEX_FROM_BIT(nframes));

//TEST
ULONG counter;
printformat("nframes: %d frames: %d \n", nframes, frames);
for (counter=0; counter<50000000; ++counter);
//TEST

//ULONG phys;

kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t));
k_memset(kernel_directory, 0, sizeof(page_directory_t));
kernel_directory->physicalAddr = (ULONG)kernel_directory->tablesPhysical;

//TEST
printformat("kernel_directory->physicalAddr: %x \n", kernel_directory->physicalAddr);
for (counter=0; counter<50000000; ++counter);
//TEST
int i = 0;
for (i=KHEAP_START; i<KHEAP_START+KHEAP_INITIAL_SIZE; i+=PAGESIZE)
get_page(i, 1, kernel_directory);

//TEST
printformat("get_page \n");
for (counter=0; counter<50000000; ++counter);
//TEST

i = 0;
while (i < XYZ_ADDRESS ) //placement_address+0x1000)
{
alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
i += PAGESIZE;
}
for (i = KHEAP_START; i < KHEAP_START+KHEAP_INITIAL_SIZE; i+=PAGESIZE)
alloc_frame( get_page(i, 1, kernel_directory), 0, 0);

//TEST
printformat("alloc_frame part 1 and 2 \n");
for (counter=0; counter<50000000; ++counter);
//TEST

// register_interrupt_handler(14, page_fault); // TODO???

switch_page_directory(kernel_directory);//Hier liegt der Absturz begraben!

kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0);
current_directory = clone_directory(kernel_directory);
switch_page_directory(current_directory);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#define PHYSICAL_MEMORY 0x4000000 // The size of physical memory, assume it is 64MB big.
#define
PAGESIZE        0x1000    // 0x1000 = 4096 = 4K
#define
XYZ_ADDRESS     0x300000  // ???

void paging_install()
{
    ULONG mem_end_page = PHYSICAL_MEMORY;
    nframes = mem_end_page/PAGESIZE;
    frames  = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes));
    k_memset(frames, 0, INDEX_FROM_BIT(nframes));

//TEST
    ULONG counter;
    printformat("nframes: %d frames: %d \n", nframes, frames);
    for (counter=0; counter<50000000; ++counter);
//TEST

    //ULONG phys;

    kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t));
    k_memset(kernel_directory, 0, sizeof(page_directory_t));
    kernel_directory->physicalAddr = (ULONG)kernel_directory->tablesPhysical;

//TEST
    printformat("kernel_directory->physicalAddr: %x \n", kernel_directory->physicalAddr);
    for (counter=0; counter<50000000; ++counter);
//TEST
    int i = 0;
    for (i=KHEAP_START; i<KHEAP_START+KHEAP_INITIAL_SIZE; i+=PAGESIZE)
        get_page(i, 1, kernel_directory);

//TEST
    printformat("get_page \n");
    for (counter=0; counter<50000000; ++counter);
//TEST

    i = 0;
    while (i < XYZ_ADDRESS ) //placement_address+0x1000)
    {
        alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
        i += PAGESIZE;
    }
    for (i = KHEAP_START; i < KHEAP_START+KHEAP_INITIAL_SIZE; i+=PAGESIZE)
        alloc_frame( get_page(i, 1, kernel_directory), 0, 0);

//TEST
    printformat("alloc_frame part 1 and 2 \n");
    for (counter=0; counter<50000000; ++counter);
//TEST

    // register_interrupt_handler(14, page_fault); // TODO???

    switch_page_directory(kernel_directory);//Hier liegt der Absturz begraben!

    kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0);
    current_directory = clone_directory(kernel_directory);
    switch_page_directory(current_directory);
}

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 15:36:16 12.04.2009, insgesamt 1-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 15:26:13 12.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
zu 2) Ich mache mir momentan Gedanken im Verständnis des Queue-Mechanismus:
Wie bewegt man die beiden Zeiger Head and Tail am sinnvollsten?

http://en.wikipedia.org/wiki/Circular_buffer
(lies ab 'difficulties')
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 15:46:07 12.04.2009   Titel:              Zitieren

+fricky schrieb:
Erhard Henkes schrieb:
zu 2) Ich mache mir momentan Gedanken im Verständnis des Queue-Mechanismus:
Wie bewegt man die beiden Zeiger Head and Tail am sinnvollsten?

http://en.wikipedia.org/wiki/Circular_buffer
(lies ab 'difficulties')
:)

Danke für den Hinweis. Kontrolle der "Read/Write Counts" gefällt mir am besten, weil der Zirkular-Mechanismus nicht gestört wird.
Zitat:
(write_count - read_count) always yields the number of items placed in the buffer and not yet retrieved.
Das macht Sinn, die beiden Variablen kommen in meine allgemeine ODA(OS Data Area)-Struktur dazu. Dann hat man auch eine einfache Kontrolle über Schreiben/Lesen/Buffer Full bzw. Overrun in der Queue.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 15:49:19 12.04.2009, insgesamt 1-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 18:08:26 12.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Schaltet man sti() vorher ein, so kracht es sofort. Man sieht keine einzige Meldung
Dann prüf mal wo genau es kracht:
C/C++ Code:
void paging_install()
{
 ULONG mem_end_page = PHYSICAL_MEMORY;
 nframes = mem_end_page/PAGESIZE;
 frames  = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes)); // <- hier?
 k_memset(frames, 0, INDEX_FROM_BIT(nframes));       // <- oder hier?
(...)
C/C++ Code:
void paging_install()
{
ULONG mem_end_page = PHYSICAL_MEMORY;
nframes = mem_end_page/PAGESIZE;
frames = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes)); // <- hier?
k_memset(frames, 0, INDEX_FROM_BIT(nframes)); // <- oder hier?
(...)
C/C++ Code:
void paging_install()
{
 ULONG mem_end_page = PHYSICAL_MEMORY;
 nframes = mem_end_page/PAGESIZE;
 frames  = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes)); // <- hier?
 k_memset(frames, 0, INDEX_FROM_BIT(nframes));       // <- oder hier?
(...)
Oder bereits vor dem Aufruf von "paging_install ()" (i.S.v. wenn sti() ausgeführt wird)?
jenz
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.06.2005
Beiträge: 227
Beitrag jenz Mitglied 19:14:31 12.04.2009   Titel:              Zitieren

@+fricky:

auch "stinknormale" c-anwendungen lassen sich bauen, wenn man die anwendungen ereignisgesteuert macht.
wie die tastatureingabe beim "keyget" ankommt hat damit überhaupt nichts zu tun.

in jeder anwendung aber dieses polling zu haben ist, meiner meinung nach, einfach nicht sinnvoll.

Eine Speicherverwaltung zu bauen ist aus meiner Sicht noch viel zu früh.

Lieber einen Scheduler und mehrere Anwendungen.

jenz
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:56:04 12.04.2009   Titel:              Zitieren

Zitat:
Eine Speicherverwaltung zu bauen ist aus meiner Sicht noch viel zu früh.
Lieber einen Scheduler und mehrere Anwendungen.
Noch liegt nichts fest, bin nur am Austesten. Ich habe mich bei der Reihenfolge des Aufbaus von folgender Aussage James Molloy's inspirieren lassen:
Zitat:
Dynamic memory allocation is one of the few things that it is very difficult to do without. Without it, you would have to specify an absolute maximum number of processes running (static array of pids), you would have to statically give the size of every buffer - Generally making your OS lacklustre and woefully inefficient.
"glanzlos und beklagenswert ineffizient", das hört sich nicht gerade anziehend an. :D
Daher schlage ich mich im Hintergrund mit dem Pagigng/Heap-Mechanismus von James Molley herum. Das muss auch alles noch simplifiziert werden, derart unverständlicher Code kommt mir in kein Tutorial.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:28:52 12.04.2009   Titel:              Zitieren

+gjm+ schrieb:
Erhard Henkes schrieb:
Schaltet man sti() vorher ein, so kracht es sofort. Man sieht keine einzige Meldung
Dann prüf mal wo genau es kracht:
C/C++ Code:
void paging_install()
{
 ULONG mem_end_page = PHYSICAL_MEMORY;
 nframes = mem_end_page/PAGESIZE;
 frames  = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes)); // <- hier?
 k_memset(frames, 0, INDEX_FROM_BIT(nframes));       // <- oder hier?
(...)
C/C++ Code:
void paging_install()
{
ULONG mem_end_page = PHYSICAL_MEMORY;
nframes = mem_end_page/PAGESIZE;
frames = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes)); // <- hier?
k_memset(frames, 0, INDEX_FROM_BIT(nframes)); // <- oder hier?
(...)
C/C++ Code:
void paging_install()
{
 ULONG mem_end_page = PHYSICAL_MEMORY;
 nframes = mem_end_page/PAGESIZE;
 frames  = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes)); // <- hier?
 k_memset(frames, 0, INDEX_FROM_BIT(nframes));       // <- oder hier?
(...)
Oder bereits vor dem Aufruf von "paging_install ()" (i.S.v. wenn sti() ausgeführt wird)?


Guter Vorschlag.

TEST:
ckernel:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "os.h"

int main()
{
    k_clear_screen();

    // GDT, IDT, ISRS, IRQ, timer, keyboard
    gdt_install();
    idt_install();
    isrs_install();
    irq_install();
    timer_install();
    keyboard_install();
    sti();
    paging_install(); //TEST
//...
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "os.h"

int main()
{
k_clear_screen();

// GDT, IDT, ISRS, IRQ, timer, keyboard
gdt_install();
idt_install();
isrs_install();
irq_install();
timer_install();
keyboard_install();
sti();
paging_install(); //TEST
//...
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "os.h"

int main()
{
    k_clear_screen();

    // GDT, IDT, ISRS, IRQ, timer, keyboard
    gdt_install();
    idt_install();
    isrs_install();
    irq_install();
    timer_install();
    keyboard_install();
    sti();
    paging_install(); //TEST
//...


paging.c:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void paging_install()
{
//TEST
    ULONG counter;
//TEST

    ULONG mem_end_page = PHYSICAL_MEMORY;

//TEST
    printformat("mem_end_page: %x \n", mem_end_page);
    for (counter=0; counter<50000000; ++counter);
//TEST

    nframes = mem_end_page/PAGESIZE;

//TEST
    printformat("nframes: %d \n", nframes);
    for (counter=0; counter<50000000; ++counter);
//TEST

    frames  = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes));

//TEST
    printformat("frames: %d \n", frames);
    printformat("Vor memset(...) - INDEX_FROM_BIT(nframes): %d INDEX_FROM_BIT(nframes) \n", INDEX_FROM_BIT(nframes));
    for (counter=0; counter<50000000; ++counter);
//TEST

    k_memset(frames, 0, INDEX_FROM_BIT(nframes)); //ABSTURZ ("reset") mit sti()! Ohne sti() läuft es durch bis Umschalten auf paging.

//TEST

    printformat("Hinter memset(...) - INDEX_FROM_BIT(nframes): %d INDEX_FROM_BIT(nframes) \n", INDEX_FROM_BIT(nframes));
    for (counter=0; counter<50000000; ++counter);
//TEST
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void paging_install()
{
//TEST
ULONG counter;
//TEST

ULONG mem_end_page = PHYSICAL_MEMORY;

//TEST
printformat("mem_end_page: %x \n", mem_end_page);
for (counter=0; counter<50000000; ++counter);
//TEST

nframes = mem_end_page/PAGESIZE;

//TEST
printformat("nframes: %d \n", nframes);
for (counter=0; counter<50000000; ++counter);
//TEST

frames = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes));

//TEST
printformat("frames: %d \n", frames);
printformat("Vor memset(...) - INDEX_FROM_BIT(nframes): %d INDEX_FROM_BIT(nframes) \n", INDEX_FROM_BIT(nframes));
for (counter=0; counter<50000000; ++counter);
//TEST

k_memset(frames, 0, INDEX_FROM_BIT(nframes)); //ABSTURZ ("reset") mit sti()! Ohne sti() läuft es durch bis Umschalten auf paging.

//TEST

printformat("Hinter memset(...) - INDEX_FROM_BIT(nframes): %d INDEX_FROM_BIT(nframes) \n", INDEX_FROM_BIT(nframes));
for (counter=0; counter<50000000; ++counter);
//TEST
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void paging_install()
{
//TEST
    ULONG counter;
//TEST

    ULONG mem_end_page = PHYSICAL_MEMORY;

//TEST
    printformat("mem_end_page: %x \n", mem_end_page);
    for (counter=0; counter<50000000; ++counter);
//TEST

    nframes = mem_end_page/PAGESIZE;

//TEST
    printformat("nframes: %d \n", nframes);
    for (counter=0; counter<50000000; ++counter);
//TEST

    frames  = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes));

//TEST
    printformat("frames: %d \n", frames);
    printformat("Vor memset(...) - INDEX_FROM_BIT(nframes): %d INDEX_FROM_BIT(nframes) \n", INDEX_FROM_BIT(nframes));
    for (counter=0; counter<50000000; ++counter);
//TEST

    k_memset(frames, 0, INDEX_FROM_BIT(nframes)); //ABSTURZ ("reset") mit sti()! Ohne sti() läuft es durch bis Umschalten auf paging.

//TEST

    printformat("Hinter memset(...) - INDEX_FROM_BIT(nframes): %d INDEX_FROM_BIT(nframes) \n", INDEX_FROM_BIT(nframes));
    for (counter=0; counter<50000000; ++counter);
//TEST


Fehler tritt in der Zeile
C/C++ Code:
k_memset(frames, 0, INDEX_FROM_BIT(nframes));
C/C++ Code:
k_memset(frames, 0, INDEX_FROM_BIT(nframes));
C/C++ Code:
k_memset(frames, 0, INDEX_FROM_BIT(nframes));
auf.

Bildschirm Mitschrift: (mit sti()
Zitat:
mem_end_page: 04000000h (67108864 dezimal, 64 MB)

nframes 16384

frames 44880 (manchmal taucht auch 44752 auf???)

Vor memset ... 512 INDEX_FROM_BIT(nframes)



Die "böse" Zeile heißt also:
k_memset(44880, 0, 512);

C/C++ Code:
void* k_memset(void* dest, char val, size_t count)
{
    char* temp = (char*)dest;
    for( ; count != 0; count--) *temp++ = val;
    return dest;
}
C/C++ Code:
void* k_memset(void* dest, char val, size_t count)
{
char* temp = (char*)dest;
for( ; count != 0; count--) *temp++ = val;
return dest;
}
C/C++ Code:
void* k_memset(void* dest, char val, size_t count)
{
    char* temp = (char*)dest;
    for( ; count != 0; count--) *temp++ = val;
    return dest;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
ULONG kmalloc_int(ULONG sz, int align, ULONG *phys)
{
    if (kheap != 0)
    {
        void* addr = alloc(sz, (UCHAR)align, kheap);
        if (phys != 0)
        {
            page_t* page = get_page((ULONG)addr, 0, kernel_directory);
            *phys = page->frame*PAGESIZE + ((ULONG)addr&0xFFF);
        }
        return (ULONG)addr;
    }
    else
    {
        if (align == 1 && (placement_address & 0xFFFFF000) )
        {
            // Align the placement address;
            placement_address &= 0xFFFFF000;
            placement_address += PAGESIZE;
        }
        if (phys)
        {
            *phys = placement_address;
        }
        ULONG tmp = placement_address;
        placement_address += sz;
        return tmp;
    }
}

ULONG kmalloc(ULONG sz)
{
    return kmalloc_int(sz, 0, 0);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
ULONG kmalloc_int(ULONG sz, int align, ULONG *phys)
{
if (kheap != 0)
{
void* addr = alloc(sz, (UCHAR)align, kheap);
if (phys != 0)
{
page_t* page = get_page((ULONG)addr, 0, kernel_directory);
*phys = page->frame*PAGESIZE + ((ULONG)addr&0xFFF);
}
return (ULONG)addr;
}
else
{
if (align == 1 && (placement_address & 0xFFFFF000) )
{
// Align the placement address;
placement_address &= 0xFFFFF000;
placement_address += PAGESIZE;
}
if (phys)
{
*phys = placement_address;
}
ULONG tmp = placement_address;
placement_address += sz;
return tmp;
}
}

ULONG kmalloc(ULONG sz)
{
return kmalloc_int(sz, 0, 0);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
ULONG kmalloc_int(ULONG sz, int align, ULONG *phys)
{
    if (kheap != 0)
    {
        void* addr = alloc(sz, (UCHAR)align, kheap);
        if (phys != 0)
        {
            page_t* page = get_page((ULONG)addr, 0, kernel_directory);
            *phys = page->frame*PAGESIZE + ((ULONG)addr&0xFFF);
        }
        return (ULONG)addr;
    }
    else
    {
        if (align == 1 && (placement_address & 0xFFFFF000) )
        {
            // Align the placement address;
            placement_address &= 0xFFFFF000;
            placement_address += PAGESIZE;
        }
        if (phys)
        {
            *phys = placement_address;
        }
        ULONG tmp = placement_address;
        placement_address += sz;
        return tmp;
    }
}

ULONG kmalloc(ULONG sz)
{
    return kmalloc_int(sz, 0, 0);
}


Das ganze ist einfach ein riesiger Wirrwarr, macht so als Tutorial keinen Sinn, weil niemand irgendetwas nachverfolgen und damit experimentieren kann. Ich stehe selbst wie vor einem Berg und weiß noch nicht, wie ich den Tunnel bohren soll.

Wenn ich so auf kmalloc(...) schaue, frage ich mich gerade, wo eigentlich der heap erzeugt wird, denn vorher ist kheap = 0.

Fall sich das jemand anschauen möchte:
http://www.henkessoft.de/OS_Dev/Downloads/20_analyze_failure.zip
Hintergründe:
http://www.jamesmolloy.co.uk/tutorial_html/6.-Paging.html
http://www.jamesmolloy.co.uk/tutorial_html/7.-The%20Heap.html

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 21:16:43 12.04.2009, insgesamt 6-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:11:03 12.04.2009   Titel:              Zitieren

TEST1:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "os.h"

int main()
{
    k_clear_screen();

    // GDT, IDT, ISRS, IRQ, timer, keyboard
    gdt_install();
    idt_install();
    isrs_install();
    irq_install();
    timer_install();
    keyboard_install();
    sti();
    k_memset(44880, 0, 512);
    //paging_install(); //TEST
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "os.h"

int main()
{
k_clear_screen();

// GDT, IDT, ISRS, IRQ, timer, keyboard
gdt_install();
idt_install();
isrs_install();
irq_install();
timer_install();
keyboard_install();
sti();
k_memset(44880, 0, 512);
//paging_install(); //TEST
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "os.h"

int main()
{
    k_clear_screen();

    // GDT, IDT, ISRS, IRQ, timer, keyboard
    gdt_install();
    idt_install();
    isrs_install();
    irq_install();
    timer_install();
    keyboard_install();
    sti();
    k_memset(44880, 0, 512);
    //paging_install(); //TEST

ergibt reset.

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "os.h"

int main()
{
    k_clear_screen();

    // GDT, IDT, ISRS, IRQ, timer, keyboard
    gdt_install();
    idt_install();
    isrs_install();
    irq_install();
    timer_install();
    keyboard_install();
    //sti();
    k_memset(44880, 0, 512);
    //paging_install(); //TEST


    set_cursor(0,0);
    printformat("   ************************************************\n");
    printformat("   *          Welcome to PrettyOS 0.06            *\n");
    printformat("   *          Paging is activated                 *\n");
    printformat("   ************************************************\n");
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "os.h"

int main()
{
k_clear_screen();

// GDT, IDT, ISRS, IRQ, timer, keyboard
gdt_install();
idt_install();
isrs_install();
irq_install();
timer_install();
keyboard_install();
//sti();
k_memset(44880, 0, 512);
//paging_install(); //TEST


set_cursor(0,0);
printformat(" ************************************************\n");
printformat(" * Welcome to PrettyOS 0.06 *\n");
printformat(" * Paging is activated *\n");
printformat(" ************************************************\n");
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "os.h"

int main()
{
    k_clear_screen();

    // GDT, IDT, ISRS, IRQ, timer, keyboard
    gdt_install();
    idt_install();
    isrs_install();
    irq_install();
    timer_install();
    keyboard_install();
    //sti();
    k_memset(44880, 0, 512);
    //paging_install(); //TEST


    set_cursor(0,0);
    printformat("   ************************************************\n");
    printformat("   *          Welcome to PrettyOS 0.06            *\n");
    printformat("   *          Paging is activated                 *\n");
    printformat("   ************************************************\n");

läuft durch bis zum Titel-Ausdruck.
Analyse passt also.
Jetzt brauchen wir die Diagnose und das Heilmittel.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:22:35 12.04.2009   Titel:              Zitieren

Ich habe mal
C/C++ Code:
    sti();
    k_memset(65536, 0, 512);
    //paging_install(); //TEST
C/C++ Code:
sti();
k_memset(65536, 0, 512);
//paging_install(); //TEST
C/C++ Code:
    sti();
    k_memset(65536, 0, 512);
    //paging_install(); //TEST

probiert, also mal 65536 (10000h) als Ziel. Das geht ohne Reset.
Also sollte es doch an diesem 44880 (AF50h) liegen. Liege ich da mit meinen Gedanken richtig?
Versuche gerade nachzuvollziehen, warum bei der Paging-Install-Routine gerade 44880 heraus kommt.

Diese Bitset-Geschichte (vielleicht kann man das einfacher machen) läuft wie folgt:

C/C++ Code:
INDEX_FROM_BIT(nframes)

// Macros used in the bitset algorithms.
#define
INDEX_FROM_BIT(a)   (a/(8*4))
#define
OFFSET_FROM_BIT(a)  (a%(8*4))
C/C++ Code:
INDEX_FROM_BIT(nframes)

// Macros used in the bitset algorithms.
#define
INDEX_FROM_BIT(a) (a/(8*4))
#define
OFFSET_FROM_BIT(a) (a%(8*4))
C/C++ Code:
INDEX_FROM_BIT(nframes)

// Macros used in the bitset algorithms.
#define
INDEX_FROM_BIT(a)   (a/(8*4))
#define
OFFSET_FROM_BIT(a)  (a%(8*4))


Also INDEX_FROM_BIT(16384) ==> (16384/(8*4)) = 512

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 21:34:38 12.04.2009, insgesamt 1-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 21:30:35 12.04.2009   Titel:              Zitieren

jenz schrieb:
@+fricky:
auch "stinknormale" c-anwendungen lassen sich bauen, wenn man die anwendungen ereignisgesteuert macht.
wie die tastatureingabe beim "keyget" ankommt hat damit überhaupt nichts zu tun.

also willst du, dass jede anwendung event-handler (für key events) implementieren muss, oder wie meinst du das?

jenz schrieb:

in jeder anwendung aber dieses polling zu haben ist, meiner meinung nach, einfach nicht sinnvoll.

polling in dem sinn, dass die cpu, wegen vieler missglückter abfragen, zyklen verbrät, kann ja schon durch eine blocking 'getchar' umgangen werden (oder durch mein beispiel von weiter oben).
:)
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 21:42:03 12.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Wenn ich so auf kmalloc(...) schaue, frage ich mich gerade, wo eigentlich der heap erzeugt wird, denn vorher ist kheap = 0.

da gibt's doch 'ne funktion 'create_heap'. die musste natürlich vorher aufrufen.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:50:11 12.04.2009   Titel:              Zitieren

Diese Message Geschichten sind eher typisch für Mini Kernels wie das bedeutungslose (?) aber "elegante" Minix von Tanenbaum. Wie gesagt, ich bin diesbezüglich noch völlig locker.

Momentan machen mich einfach die C-Basics fertig. Als C++ler bin ich ich echt nicht gewohnt, so "tief unten" zu wühlen, aber ich finde gerade diese herausforderung, alles selbst aufbauen zu müssen, total interessant. Ist alles nur eine Frage der Zeit, bis das klappt.

Aber ob das noch tutorial-tauglich ist, was ich da treibe, da bin ich nicht mehr sicher. So auf gar keinen Fall. Ein Zwischenverweis auf James Molley's Tutorial (er lädt mit Grubs und verwendet im Programm externe Daten aus dem Linker Skript, igitt) und weiter machen / modifizieren, wo er aufhört, macht IMHO keinen Sinn.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Unregistrierter





Beitrag Unregistrierter 21:57:16 12.04.2009   Titel:              Zitieren

"frames" ist seltsamerweise zu klein, was heißt, daß der Aufruf von
C/C++ Code:
k_memset(frames, 0, INDEX_FROM_BIT(nframes));
C/C++ Code:
k_memset(frames, 0, INDEX_FROM_BIT(nframes));
C/C++ Code:
k_memset(frames, 0, INDEX_FROM_BIT(nframes));
wohl einen Teil des Kernels überschrieben hat. Lt. Quelltext hätte "frames" aber nach Aufruf von
C/C++ Code:
frames = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes));
C/C++ Code:
frames = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes));
C/C++ Code:
frames = (ULONG*)kmalloc(INDEX_FROM_BIT(nframes));
0x300000 sein müssen:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//kheap.c

ULONG kmalloc(ULONG sz)
{
 return kmalloc_int(sz, 0, 0);
}

ULONG kmalloc_int(ULONG sz, int align, ULONG *phys)
{
  if (kheap != 0) // "kheap" ist Null beim ersten Aufruf
  {
(...)
  }
  else
  {               // "align" ist auch Null
   if (align == 1 && (placement_address & 0xFFFFF000) )
   {
(...)
   }
   if (phys)      // "phys" auch
   {
   *phys = placement_address;
   }
// somit wird "placement_address" zurückgegeben
   ULONG tmp = placement_address;
   placement_address += sz;
   return tmp;
  }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//kheap.c

ULONG kmalloc(ULONG sz)
{
return kmalloc_int(sz, 0, 0);
}

ULONG kmalloc_int(ULONG sz, int align, ULONG *phys)
{
if (kheap != 0) // "kheap" ist Null beim ersten Aufruf
{
(...)
}
else
{ // "align" ist auch Null
if (align == 1 && (placement_address & 0xFFFFF000) )
{
(...)
}
if (phys) // "phys" auch
{
*phys = placement_address;
}
// somit wird "placement_address" zurückgegeben
ULONG tmp = placement_address;
placement_address += sz;
return tmp;
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//kheap.c

ULONG kmalloc(ULONG sz)
{
 return kmalloc_int(sz, 0, 0);
}

ULONG kmalloc_int(ULONG sz, int align, ULONG *phys)
{
  if (kheap != 0) // "kheap" ist Null beim ersten Aufruf
  {
(...)
  }
  else
  {               // "align" ist auch Null
   if (align == 1 && (placement_address & 0xFFFFF000) )
   {
(...)
   }
   if (phys)      // "phys" auch
   {
   *phys = placement_address;
   }
// somit wird "placement_address" zurückgegeben
   ULONG tmp = placement_address;
   placement_address += sz;
   return tmp;
  }
}
Und "placement_address" ist:
C/C++ Code:
//kheap.h
(...)
heap_t* kheap = 0;
(...)
ULONG end               = 0x300000;    // 3 MB TODO???
ULONG placement_address = (ULONG)&end; // <- die Adresse von "end"?????
C/C++ Code:
//kheap.h
(...)
heap_t* kheap = 0;
(...)
ULONG end = 0x300000; // 3 MB TODO???
ULONG placement_address = (ULONG)&end; // <- die Adresse von "end"?????
C/C++ Code:
//kheap.h
(...)
heap_t* kheap = 0;
(...)
ULONG end               = 0x300000;    // 3 MB TODO???
ULONG placement_address = (ULONG)&end; // <- die Adresse von "end"?????
Hoffentlich hilft das weiter.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:29:41 12.04.2009   Titel:              Zitieren

@+gjm+: Danke für die Analyse, kannst Du Dir den aktuellen Code nochmals anschauen?

Da waren leider doch noch einige plötzlich aufpoppende Fehler mit memset() anstelle k_memset in ordered_array usw., aber dennoch klappt es noch nicht richtig. Habe auch in den headern os.h, ... noch etwas Ordnung (hoffentlich) geschafft.

Ich schiebe den aktuellen Code mal hoch, vielleicht hat jemand die entscheidende Idee zum Durchblick. Vor lauter blöden Adressen blicke ich nicht mehr durch.
create_heap() hilft auch noch nicht. Bin nicht völlig sicher, ob das in ckernel.c sein muss. Keine Ahnung, wo der heap momentan erzeugt wird.

Sehe vor lauter Wald die Bäume nicht mehr, aber den Code dürfte ich jetzt soweit funktionsfähig haben. Könnte sich das bitte mal jemand anschauen (fehlen nur noch die richtigen Parameter, sicher bin ich aber noch nicht)? :rolleyes:
http://www.henkessoft.de/OS_Dev/Downloads/20_analyze_failure.zip

EDIT1: hier sieht die frames Anzahl (mit createheap(0x300000,...) z.B. 3674124) nun besser aus.
es läuft ohne sti() durch bis zum Umschalten auf Paging, dann kommt der reset, kann noch an falschen Parametern liegen:
http://www.henkessoft.de/OS_Dev/Bilder/Fehlersuche_PAGING_HEAP.PNG

EDIT2: das Problem liegt in create_heap(...)
Da ist etwas im hinteren Teil instabil. Auch mit Kontroll-Prints passieren da merkwürdige Sachen auf dem Bildschirm, noch dazu nicht gleich reproduzierbar.
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
heap_t* create_heap(ULONG start, ULONG end_addr, ULONG max, UCHAR supervisor, UCHAR readonly)
{
    //TEST
    ULONG counter;
    //TEST

    heap_t* heap = (heap_t*)kmalloc(sizeof(heap_t));

    //TEST
    printformat("heap in create_heap(...) %x \n", heap);
    for (counter=0; counter<50000000; ++counter);
    //TEST

    // All our assumptions are made on startAddress and endAddress being page-aligned.

    ASSERT(start%PAGESIZE == 0);
    ASSERT(end_addr%PAGESIZE == 0);

    // Initialise the index.
    heap->index = place_ordered_array( (void*)start, HEAP_INDEX_SIZE, &header_t_less_than);

    //TEST
    printformat("heap->index in create_heap(...) %x \n", heap->index);
    printformat("header_t_less_than in create_heap(...) %x \n", &header_t_less_than);
    for (counter=0; counter<50000000; ++counter);
    //TEST

    // Shift the start address forward to resemble where we can start putting data.

    start += sizeof(type_t)*HEAP_INDEX_SIZE;

    //TEST
    printformat("start in create_heap(...) %x \n", start);
    for (counter=0; counter<50000000; ++counter);
    //TEST

    // Make sure the start address is page-aligned.

    if ((start & 0xFFFFF000) != 0)
    {
        start &= 0xFFFFF000;
        start += PAGESIZE;
    }

    //TEST
    printformat("start in create_heap(...) after alignment check %x \n", start);
    for (counter=0; counter<50000000; ++counter);
    //TEST

    // Write the start, end and max addresses into the heap structure.

    heap->start_address = start;
    heap->end_address   = end_addr;
    heap->max_address   = max;
    heap->supervisor    = supervisor;
    heap->readonly      = readonly;

    //TEST
    printformat("start: %x end: %x", heap->start_address, heap->end_address);
    for (counter=0; counter<50000000; ++counter);
    //TEST


    // We start off with one large hole in the index.

    header_t* hole = (header_t*) start;
    hole->size     = end_addr-start;
    hole->magic    = HEAP_MAGIC;
    hole->is_hole  = 1;

    //TEST
    printformat("hole %x", hole);
    for (counter=0; counter<50000000; ++counter);
    //TEST

    insert_ordered_array((void*)hole, &heap->index);

    //TEST
    printformat("after insert_ordered_array");
    for (counter=0; counter<50000000; ++counter);
    //TEST

    return heap;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
heap_t* create_heap(ULONG start, ULONG end_addr, ULONG max, UCHAR supervisor, UCHAR readonly)
{
//TEST
ULONG counter;
//TEST

heap_t* heap = (heap_t*)kmalloc(sizeof(heap_t));

//TEST
printformat("heap in create_heap(...) %x \n", heap);
for (counter=0; counter<50000000; ++counter);
//TEST

// All our assumptions are made on startAddress and endAddress being page-aligned.

ASSERT(start%PAGESIZE == 0);
ASSERT(end_addr%PAGESIZE == 0);

// Initialise the index.
heap->index = place_ordered_array( (void*)start, HEAP_INDEX_SIZE, &header_t_less_than);

//TEST
printformat("heap->index in create_heap(...) %x \n", heap->index);
printformat("header_t_less_than in create_heap(...) %x \n", &header_t_less_than);
for (counter=0; counter<50000000; ++counter);
//TEST

// Shift the start address forward to resemble where we can start putting data.

start += sizeof(type_t)*HEAP_INDEX_SIZE;

//TEST
printformat("start in create_heap(...) %x \n", start);
for (counter=0; counter<50000000; ++counter);
//TEST

// Make sure the start address is page-aligned.

if ((start & 0xFFFFF000) != 0)
{
start &= 0xFFFFF000;
start += PAGESIZE;
}

//TEST
printformat("start in create_heap(...) after alignment check %x \n", start);
for (counter=0; counter<50000000; ++counter);
//TEST

// Write the start, end and max addresses into the heap structure.

heap->start_address = start;
heap->end_address = end_addr;
heap->max_address = max;
heap->supervisor = supervisor;
heap->readonly = readonly;

//TEST
printformat("start: %x end: %x", heap->start_address, heap->end_address);
for (counter=0; counter<50000000; ++counter);
//TEST


// We start off with one large hole in the index.

header_t* hole = (header_t*) start;
hole->size = end_addr-start;
hole->magic = HEAP_MAGIC;
hole->is_hole = 1;

//TEST
printformat("hole %x", hole);
for (counter=0; counter<50000000; ++counter);
//TEST

insert_ordered_array((void*)hole, &heap->index);

//TEST
printformat("after insert_ordered_array");
for (counter=0; counter<50000000; ++counter);
//TEST

return heap;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
heap_t* create_heap(ULONG start, ULONG end_addr, ULONG max, UCHAR supervisor, UCHAR readonly)
{
    //TEST
    ULONG counter;
    //TEST

    heap_t* heap = (heap_t*)kmalloc(sizeof(heap_t));

    //TEST
    printformat("heap in create_heap(...) %x \n", heap);
    for (counter=0; counter<50000000; ++counter);
    //TEST

    // All our assumptions are made on startAddress and endAddress being page-aligned.

    ASSERT(start%PAGESIZE == 0);
    ASSERT(end_addr%PAGESIZE == 0);

    // Initialise the index.
    heap->index = place_ordered_array( (void*)start, HEAP_INDEX_SIZE, &header_t_less_than);

    //TEST
    printformat("heap->index in create_heap(...) %x \n", heap->index);
    printformat("header_t_less_than in create_heap(...) %x \n", &header_t_less_than);
    for (counter=0; counter<50000000; ++counter);
    //TEST

    // Shift the start address forward to resemble where we can start putting data.

    start += sizeof(type_t)*HEAP_INDEX_SIZE;

    //TEST
    printformat("start in create_heap(...) %x \n", start);
    for (counter=0; counter<50000000; ++counter);
    //TEST

    // Make sure the start address is page-aligned.

    if ((start & 0xFFFFF000) != 0)
    {
        start &= 0xFFFFF000;
        start += PAGESIZE;
    }

    //TEST
    printformat("start in create_heap(...) after alignment check %x \n", start);
    for (counter=0; counter<50000000; ++counter);
    //TEST

    // Write the start, end and max addresses into the heap structure.

    heap->start_address = start;
    heap->end_address   = end_addr;
    heap->max_address   = max;
    heap->supervisor    = supervisor;
    heap->readonly      = readonly;

    //TEST
    printformat("start: %x end: %x", heap->start_address, heap->end_address);
    for (counter=0; counter<50000000; ++counter);
    //TEST


    // We start off with one large hole in the index.

    header_t* hole = (header_t*) start;
    hole->size     = end_addr-start;
    hole->magic    = HEAP_MAGIC;
    hole->is_hole  = 1;

    //TEST
    printformat("hole %x", hole);
    for (counter=0; counter<50000000; ++counter);
    //TEST

    insert_ordered_array((void*)hole, &heap->index);

    //TEST
    printformat("after insert_ordered_array");
    for (counter=0; counter<50000000; ++counter);
    //TEST

    return heap;
}

Zitat:
heap in create_heap(...) 0000B1D0h
heap->index in create_heap(...) 00200000h
header_t_less_than in create_heap(...) 0000A90Ch
start in create_heap(...) 00280000h
start ... after alignment check 00281000h

Absturz?

Manchmal kommt auch noch die nächste Zeile. ???
Nach der letzten Ausgabe springt der Cursor nach (0,0)! keine Ahnung warum?
Dann erfolgt Reset.

Ohne sti() bekommt man mehr Infos (s.u. seaprater Post)


Bitte um weitere Unterstützung, damit wir das Thema didaktisch angehen können.

Ich werde mich mal zur Ablenkung auf die Key Queue als nächste Aufgabe konzentrieren.

Diesen Paging/Heap Mist werde ich etwas schieben. Dieser verschachtelte Code mit den kreuz und quer verteilten Parametern nervt mich langsam.

Der Code müsste für ein Tutorial entflochten und klar strukturiert werden.
Vielleicht kennt/hat jemand etwas Besseres?

Problemliste:
- Beep() geht nicht (speaker)
- Paging/Heap zum Laufen bringen

Kurzfristige Taskliste:
- KeyQueue aufbauen (als ersten Schritt kann man die Daten ja über eine Auswerte-Funktion in ckernel.c abholen und darstellen)
- Paging/Heap entflechten (erst Heap und Demo, dann Paging für Multitasking)

Auf jeden Fall danke an alle, die mich unterstützen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:35:52 13.04.2009, insgesamt 9-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:49:28 13.04.2009   Titel:              Zitieren

Letzter Stand:
http://www.henkessoft.de/OS_Dev/Downloads/20_analyze_failure.zip ( ohne sti() )
C/C++ Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
#include "os.h"

int main()
{
    //...
    //sti(); //ansonsten Absturz im hinteren Teil von create_heap(...)

    kheap = create_heap(0x200000, 0x400000, 0x500000, 0, 0);
    paging_install(); //TEST
C/C++ Code:
1
2
3
4
5
6
7
8
#include "os.h"

int main()
{
//...
//sti(); //ansonsten Absturz im hinteren Teil von create_heap(...)

kheap = create_heap(0x200000, 0x400000, 0x500000, 0, 0);
paging_install(); //TEST
C/C++ Code:
1
2
3
4
5
6
7
8
#include "os.h"

int main()
{
    //...
    //sti(); //ansonsten Absturz im hinteren Teil von create_heap(...)

    kheap = create_heap(0x200000, 0x400000, 0x500000, 0, 0);
    paging_install(); //TEST


Bildschirmausdruck:
http://www.henkessoft.de/OS_Dev/Bilder/Fehlersuche_PAGING_HEAP_1.PNG

Please help. :confused:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 02:48:19 13.04.2009   Titel:              Zitieren

- deleted -

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 10:30:00 13.04.2009, insgesamt 6-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 10:29:26 13.04.2009   Titel:              Zitieren

Fehler gefunden, ein kleines & zuviel vor 'end'. Man sucht immer an der falschen Stelle. Naja, zumindest beschäftigt man sich intensiv mit dem Code. Das hat seine Vorteile. ;)

Nun endlich lauffähig: die vereinfachte Paging-Version ohne create_heap(...):
http://www.henkessoft.de/OS_Dev/Downloads/22.zip

Mit Bitte um Vorschläge zur Vereinfachung und Demo-Nutzung des Codes,
z.B. Page Fault ...
Bezüglich Didaktik denke ich darüber nach:
Wie kann man Paging zum Anfassen/Experimentieren darstellen?
Welche Vorteile haben wir nun davon?
...

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 14:19:07 13.04.2009, insgesamt 7-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:14:25 13.04.2009   Titel:              Zitieren

So nun habe ich auch die komplexe Variante mit create_heap() zum Laufen gebracht.
@abc.w: bringt sogar eine echte page_fault_exception :D

http://www.henkessoft.de/OS_Dev/Downloads/20_Paging_Heap.zip

So, nun geht's mir wieder besser. :)
... und den Blick nach vorne:

Problemliste:
- Beep() geht nicht (speaker)
- Scroll in video.c schneidet erstes Zeichen in neuer Zeile ab (??)

Kurzfristige Taskliste:
- Paging optimieren (für Tutorial)
- Was macht man nun mit dem Heap? - Einfache Anwendungssteuerung? (was zuerst?)
- KeyQueue aufbauen
- Anwendung auf KeyQueue zugreifen lassen
- Multitasking

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 11:19:00 13.04.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 13:01:01 13.04.2009   Titel:              Zitieren

Zitat:
da gibt's doch 'ne funktion 'create_heap'. die musste natürlich vorher aufrufen.
@+fricky: Wie Du siehst ist Paging und Heap hier entkoppelt, geht also zum Glück ohne dieses create_heap(...) via kmalloc(...). :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 16:24:20 13.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zitat:
da gibt's doch 'ne funktion 'create_heap'. die musste natürlich vorher aufrufen.
@+fricky: Wie Du siehst ist Paging und Heap hier entkoppelt, geht also zum Glück ohne dieses create_heap(...) via kmalloc(...).

ok, aber irgendwie musste dem heap ja sagen, wo sein speicher ist.

Erhard Henkes schrieb:

- Was macht man nun mit dem Heap? - Einfache Anwendungssteuerung? (was zuerst?)

na, den user-programmen (und dem kernel, also z.b. treibern usw) die funktionen malloc(), realloc() und free() zur verfügung stellen.
Erhard Henkes schrieb:

- Anwendung auf KeyQueue zugreifen lassen

hier haste für sowas einen lock-free FIFO: http://svn.akop.org/psp/tags/fuse/0.9.0.1/sound/sfifo.c
so'n FIFO kann z.b. von einer interrupt-routine (oder anderen task) gefüllt und während des lesens müssen keine interrupts gesperrt werden. ich hab' ihn schon mal benutzt: funzt perfekt.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:04:41 13.04.2009   Titel:              Zitieren

Danke für den Link, aber ich möchte es mit einer Datenstruktur analog BDA probieren, sieht momentan so aus:
os.h:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* This defines the operatings system common data area */

#define
KQSIZE    100 // size of key queue

typedef struct oda
{
    // Hardware Data
    //...

    // Key Queue

    UCHAR  KEYQUEUE[KQSIZE];   // circular queue buffer
    UCHAR* pHeadKQ;            // pointer to the head of valid data
    UCHAR* pTailKQ;            // pointer to the tail of valid data
    UCHAR  KQ_count_read;      // number of data read from queue buffer
    UCHAR  KQ_count_write;     // number of data put into queue buffer
}oda_t;

// operatings system common data area
oda_t ODA;
extern oda_t* pODA;
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* This defines the operatings system common data area */

#define
KQSIZE 100 // size of key queue

typedef struct oda
{
// Hardware Data
//...

// Key Queue

UCHAR KEYQUEUE[KQSIZE]; // circular queue buffer
UCHAR* pHeadKQ; // pointer to the head of valid data
UCHAR* pTailKQ; // pointer to the tail of valid data
UCHAR KQ_count_read; // number of data read from queue buffer
UCHAR KQ_count_write; // number of data put into queue buffer
}oda_t;

// operatings system common data area
oda_t ODA;
extern oda_t* pODA;
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* This defines the operatings system common data area */

#define
KQSIZE    100 // size of key queue

typedef struct oda
{
    // Hardware Data
    //...

    // Key Queue

    UCHAR  KEYQUEUE[KQSIZE];   // circular queue buffer
    UCHAR* pHeadKQ;            // pointer to the head of valid data
    UCHAR* pTailKQ;            // pointer to the tail of valid data
    UCHAR  KQ_count_read;      // number of data read from queue buffer
    UCHAR  KQ_count_write;     // number of data put into queue buffer
}oda_t;

// operatings system common data area
oda_t ODA;
extern oda_t* pODA;

util.c (später vielleicht os.c):
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
oda_t* pODA = &ODA;

void initODA()
{
    int i;
    for(i=0;i<KQSIZE;++i)
       pODA->KEYQUEUE[i]=0;          // circular queue buffer
    pODA->pHeadKQ = pODA->KEYQUEUE;  // pointer to the head of valid data
    pODA->pTailKQ = pODA->KEYQUEUE;  // pointer to the tail of valid data
    pODA->KQ_count_read  = 0;        // number of data read from queue buffer
    pODA->KQ_count_write = 0;        // number of data put into queue buffer
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
oda_t* pODA = &ODA;

void initODA()
{
int i;
for(i=0;i<KQSIZE;++i)
pODA->KEYQUEUE[i]=0; // circular queue buffer
pODA->pHeadKQ = pODA->KEYQUEUE; // pointer to the head of valid data
pODA->pTailKQ = pODA->KEYQUEUE; // pointer to the tail of valid data
pODA->KQ_count_read = 0; // number of data read from queue buffer
pODA->KQ_count_write = 0; // number of data put into queue buffer
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
oda_t* pODA = &ODA;

void initODA()
{
    int i;
    for(i=0;i<KQSIZE;++i)
       pODA->KEYQUEUE[i]=0;          // circular queue buffer
    pODA->pHeadKQ = pODA->KEYQUEUE;  // pointer to the head of valid data
    pODA->pTailKQ = pODA->KEYQUEUE;  // pointer to the tail of valid data
    pODA->KQ_count_read  = 0;        // number of data read from queue buffer
    pODA->KQ_count_write = 0;        // number of data put into queue buffer
}

keyboard.c
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void keyboard_handler(struct regs* r)
{
   UCHAR KEY = ScanToASCII();
   if(KEY)
   {
     *(pODA->pTailKQ) = KEY;
     ++(pODA->KQ_count_write);

       if(pODA->pTailKQ > pODA->KEYQUEUE)
       {
           --pODA->pTailKQ;
       }
       if(pODA->pTailKQ == pODA->KEYQUEUE)
       {
           pODA->pTailKQ = (pODA->KEYQUEUE)+KQSIZE-1;
       }
   }
   //...
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void keyboard_handler(struct regs* r)
{
UCHAR KEY = ScanToASCII();
if(KEY)
{
*(pODA->pTailKQ) = KEY;
++(pODA->KQ_count_write);

if(pODA->pTailKQ > pODA->KEYQUEUE)
{
--pODA->pTailKQ;
}
if(pODA->pTailKQ == pODA->KEYQUEUE)
{
pODA->pTailKQ = (pODA->KEYQUEUE)+KQSIZE-1;
}
}
//...
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void keyboard_handler(struct regs* r)
{
   UCHAR KEY = ScanToASCII();
   if(KEY)
   {
     *(pODA->pTailKQ) = KEY;
     ++(pODA->KQ_count_write);

       if(pODA->pTailKQ > pODA->KEYQUEUE)
       {
           --pODA->pTailKQ;
       }
       if(pODA->pTailKQ == pODA->KEYQUEUE)
       {
           pODA->pTailKQ = (pODA->KEYQUEUE)+KQSIZE-1;
       }
   }
   //...
}

Test in ckernel.c:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//...
    initODA();
    printformat("KQ: %x TAIL: %x HEAD: %x", pODA->KEYQUEUE, pODA->pTailKQ, pODA->pHeadKQ);

    settextcolor(2,0);

    int y=6;
    while(TRUE)
    {
        sleepSeconds(10);
        if(y>24) y=24;
        set_cursor(0,++y);
        printformat(" 10 sec: ");
        printformat("TAIL: %x HEAD: %x WRITE: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write);
        printformat("TAILCONTENT: %c %i HEADCONTENT: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
    };
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//...
initODA();
printformat("KQ: %x TAIL: %x HEAD: %x", pODA->KEYQUEUE, pODA->pTailKQ, pODA->pHeadKQ);

settextcolor(2,0);

int y=6;
while(TRUE)
{
sleepSeconds(10);
if(y>24) y=24;
set_cursor(0,++y);
printformat(" 10 sec: ");
printformat("TAIL: %x HEAD: %x WRITE: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write);
printformat("TAILCONTENT: %c %i HEADCONTENT: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//...
    initODA();
    printformat("KQ: %x TAIL: %x HEAD: %x", pODA->KEYQUEUE, pODA->pTailKQ, pODA->pHeadKQ);

    settextcolor(2,0);

    int y=6;
    while(TRUE)
    {
        sleepSeconds(10);
        if(y>24) y=24;
        set_cursor(0,++y);
        printformat(" 10 sec: ");
        printformat("TAIL: %x HEAD: %x WRITE: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write);
        printformat("TAILCONTENT: %c %i HEADCONTENT: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
    };

Zitat:

************************************************
* Welcome to PrettyOS 0.06 *
* Paging is activated *
************************************************
KQ: 0000A1A4h TAIL: 0000A1A4h HEAD: 0000A1A4h


10 sec: TAIL: A1A4h HEAD: A1A4h WRITE: 0 TAILCONTENT: 0 HEADCONTENT:
10 sec: TAIL: A207h HEAD: A1A4h WRITE: 1 TAILCONTENT: 0 HEADCONTENT: a
10 sec: TAIL: A206h HEAD: A1A4h WRITE: 2 TAILCONTENT: 0 HEADCONTENT: a
10 sec: TAIL: A205h HEAD: A1A4h WRITE: 3 TAILCONTENT: 0 HEADCONTENT: a
10 sec: TAIL: A204h HEAD: A1A4h WRITE: 4 TAILCONTENT: 0 HEADCONTENT: a
10 sec: TAIL: A1FEh HEAD: A1A4h WRITE: 109 TAILCONTENT: g 103 HEADCONTE
NT: a 97


0xA207 = 0xA1A4 + 0x64 (KQSIZE) - 1
passt also alles. Den Tasten-Release (KEY == 0) habe ich unterdrückt, so dass nur ein Zeichen pro Tastenanschlag in die KQ gelangt.

Ich möchte diesen Mechanismus komplett selbst durchziehen, weil ich das derart low-level noch nicht gemacht habe, bin durch die Standard Template Library verhätschelt. :D

Über Lesen aus der KQ und Interrupts habe ich mir noch keine Gedanken gemacht.
Wie geht man mit einem buffer full, also (pODA->KQ_count_write - pODA->KQ_count_read)>100 um. Da ich die Zähler momentan leichtsinnig in UCHAR definiert habe, kommt es auch noch zu einem Überlauf. :D Das lässt sich sicher durch ULONG in den Griff bekommen, aber prinzipiell ist das Problem dadurch nur in die weite Ferne geschoben. Es soll ja Leute geben, die ihren Rechner nie ausschalten. Bei PrettyOS ist das fast garantiert. ;)

Wo sollte das Lese-Programm, also das alte:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
   restore_cursor();
   switch(KEY)
   {
       case KINS:
           break;
       case KDEL:
           move_cursor_right();
           putch('\b'); //BACKSPACE
           break;
       case KHOME:
           move_cursor_home();
           break;
       case KEND:
           move_cursor_end();
           break;
       case KPGUP:
           break;
       case KPGDN:
           break;
       case KLEFT:
           move_cursor_left();
           break;
       case KUP:
           break;
       case KDOWN:
           break;
       case KRIGHT:
           move_cursor_right();
           break;
       default:
           printformat("%c",KEY); // the ASCII character
           break;
   }
   save_cursor();
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
restore_cursor();
switch(KEY)
{
case KINS:
break;
case KDEL:
move_cursor_right();
putch('\b'); //BACKSPACE
break;
case KHOME:
move_cursor_home();
break;
case KEND:
move_cursor_end();
break;
case KPGUP:
break;
case KPGDN:
break;
case KLEFT:
move_cursor_left();
break;
case KUP:
break;
case KDOWN:
break;
case KRIGHT:
move_cursor_right();
break;
default:
printformat("%c",KEY); // the ASCII character
break;
}
save_cursor();
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
   restore_cursor();
   switch(KEY)
   {
       case KINS:
           break;
       case KDEL:
           move_cursor_right();
           putch('\b'); //BACKSPACE
           break;
       case KHOME:
           move_cursor_home();
           break;
       case KEND:
           move_cursor_end();
           break;
       case KPGUP:
           break;
       case KPGDN:
           break;
       case KLEFT:
           move_cursor_left();
           break;
       case KUP:
           break;
       case KDOWN:
           break;
       case KRIGHT:
           move_cursor_right();
           break;
       default:
           printformat("%c",KEY); // the ASCII character
           break;
   }
   save_cursor();

nun eigentlich hin? Der User will doch Zahlen und Buchstaben sehen, wenn er tippt. :D Zumindest als Demo.
Soll ich das als getchar() in keyboard.c realisieren und in ckernel.c mal als demo in der while-Schleife (klares "Polling") laufen lassen oder habt ihr bessere Ideen?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:08:31 13.04.2009, insgesamt 6-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:30:16 14.04.2009   Titel:              Zitieren

Ich habe das zunächst als k_checkKQ_and_print_char() umgesetzt, um didaktisch an unsere bisherige - von Nobuo T kritisierte - "Schreibmaschine" in keyboard_handler(...) anzuknüpfen.

Test in ckernel:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
UINT c=0;
    while(TRUE)
    {
      if( k_checkKQ_and_print_char() )
      {
        ++c;
        if(c>79)
        {
          c=0;
          settextcolor(4,0);
          printformat("\nT: %x H: %x WRITE: %i Read: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write, pODA->KQ_count_read);
          printformat("*T: %c %i *H: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
          settextcolor(2,0);
        }
      }
    }
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
UINT c=0;
while(TRUE)
{
if( k_checkKQ_and_print_char() )
{
++c;
if(c>79)
{
c=0;
settextcolor(4,0);
printformat("\nT: %x H: %x WRITE: %i Read: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write, pODA->KQ_count_read);
printformat("*T: %c %i *H: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
settextcolor(2,0);
}
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
UINT c=0;
    while(TRUE)
    {
      if( k_checkKQ_and_print_char() )
      {
        ++c;
        if(c>79)
        {
          c=0;
          settextcolor(4,0);
          printformat("\nT: %x H: %x WRITE: %i Read: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write, pODA->KQ_count_read);
          printformat("*T: %c %i *H: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
          settextcolor(2,0);
        }
      }
    }

Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
jkdfhsdjkhgksjhkjdhkjdfshjkdsfhgjkhjghdfjkghjkdfhgdjkfhkdjfhgkdjfhgkjdfhjkdfhgjk
dfhgjkdfhksdfhksdahfksdajhfkjsdhfksdjhfksdajhfasdkhfjkasdhfkasjdfhkjasdhfksladjh
faskdjlhfkjhsadkjfhkjasdhfjkasdfhkajsdhfjkasdfhkjasdhfjkasdhfjkasdhfjkasdhfjkasd
hfjkhfjkasdhfjksdhfkjahhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
jjjjjjjjjjjjjjjjjjjjjjjjjjjjkkkkkkkkkkkkkkkkkkkKKKKKKKKKKKKKLAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
T: 0000A2DAh H: 0000A2DAh WRITE: 640 Read: 640 *T: j 106 *H: j 106
T: 0000A2EDh H: 0000A2EDh WRITE: 720 Read: 720 *T: A 65 *H: A 65
Code:
1
2
3
4
5
6
7
8
9
10
11
jkdfhsdjkhgksjhkjdhkjdfshjkdsfhgjkhjghdfjkghjkdfhgdjkfhkdjfhgkdjfhgkjdfhjkdfhgjk
dfhgjkdfhksdfhksdahfksdajhfkjsdhfksdjhfksdajhfasdkhfjkasdhfkasjdfhkjasdhfksladjh
faskdjlhfkjhsadkjfhkjasdhfjkasdfhkajsdhfjkasdfhkjasdhfjkasdhfjkasdhfjkasdhfjkasd
hfjkhfjkasdhfjksdhfkjahhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
jjjjjjjjjjjjjjjjjjjjjjjjjjjjkkkkkkkkkkkkkkkkkkkKKKKKKKKKKKKKLAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
T: 0000A2DAh H: 0000A2DAh WRITE: 640 Read: 640 *T: j 106 *H: j 106
T: 0000A2EDh H: 0000A2EDh WRITE: 720 Read: 720 *T: A 65 *H: A 65
Code:
1
2
3
4
5
6
7
8
9
10
11
jkdfhsdjkhgksjhkjdhkjdfshjkdsfhgjkhjghdfjkghjkdfhgdjkfhkdjfhgkdjfhgkjdfhjkdfhgjk
dfhgjkdfhksdfhksdahfksdajhfkjsdhfksdjhfksdajhfasdkhfjkasdhfkasjdfhkjasdhfksladjh
faskdjlhfkjhsadkjfhkjasdhfjkasdfhkajsdhfjkasdfhkjasdhfjkasdhfjkasdhfjkasdhfjkasd
hfjkhfjkasdhfjksdhfkjahhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
jjjjjjjjjjjjjjjjjjjjjjjjjjjjkkkkkkkkkkkkkkkkkkkKKKKKKKKKKKKKLAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
T: 0000A2DAh H: 0000A2DAh WRITE: 640 Read: 640 *T: j 106 *H: j 106
T: 0000A2EDh H: 0000A2EDh WRITE: 720 Read: 720 *T: A 65 *H: A 65


Test und Reaktion (welche?) auf BufferFull/Overrun fehlt noch.
Die Pfeiltasten links/rechts kommen nicht mehr durch.
Was man wirklich mit den Infos in der KeyQueue machen will, hängt sehr von der konkreten Anwendung ab. Ich frage mich momentan, wie man mit den Sondertasten sinnvoll umgehen sollte. Als Flags in der ODA wie bei der BDA machen sie keinen Sinn, weil man nicht weiß, zu welchem Zeichen sie gehören. Aber das lässt sich alles leicht anpassen. Vielleicht hat jemand eine glänzende Idee oder gute Erfahrungen mit eigenen OS.

Ich schieb das Programm oben mal hoch, wenn jemand mit dem Code spielen will:
http://www.henkessoft.de/OS_Dev/Downloads/22a.zip

Baut man eine Verzögerungsschleife ein, so kommt Schreiben/Lesen so ab 100 Millisekunden (Warteschleife für ms habe ich nun in timer.c ergänzt) aus dem Gleichklang: http://www.henkessoft.de/OS_Dev/Downloads/22b.zip
Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
jksdghkdfjhgkskdfjhgkjsdfhgkjsdfhgskjdfhkhjhgdfjkhgdfkjhgkjdfhgkjdfhgkdfjhgkjdfh
gkfdhgkdfhgkdfhgkdfhgkdfhgkdfjhgkdfhgkdfhgkfhkjdshgkjsdfjjjjjjjjjjjjjjjjjjjjjjjj
jjjjJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAh WRITE: 662 Read: 640 *T: A 65 *H: A 65
T: 0000A2E0h H: 0000A30Dh WRITE: 765 Read: 720 *T: A 65 *H: A 65
Code:
1
2
3
4
5
6
7
8
9
10
11
jksdghkdfjhgkskdfjhgkjsdfhgkjsdfhgskjdfhkhjhgdfjkhgdfkjhgkjdfhgkjdfhgkdfjhgkjdfh
gkfdhgkdfhgkdfhgkdfhgkdfhgkdfjhgkdfhgkdfhgkfhkjdshgkjsdfjjjjjjjjjjjjjjjjjjjjjjjj
jjjjJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAh WRITE: 662 Read: 640 *T: A 65 *H: A 65
T: 0000A2E0h H: 0000A30Dh WRITE: 765 Read: 720 *T: A 65 *H: A 65
Code:
1
2
3
4
5
6
7
8
9
10
11
jksdghkdfjhgkskdfjhgkjsdfhgkjsdfhgskjdfhkhjhgdfjkhgdfkjhgkjdfhgkjdfhgkdfjhgkjdfh
gkfdhgkdfhgkdfhgkdfhgkdfhgkdfjhgkdfhgkdfhgkfhkjdshgkjsdfjjjjjjjjjjjjjjjjjjjjjjjj
jjjjJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAh WRITE: 662 Read: 640 *T: A 65 *H: A 65
T: 0000A2E0h H: 0000A30Dh WRITE: 765 Read: 720 *T: A 65 *H: A 65

Bleiben die Fragen, wie groß muss KQ sein und wie geht man mit einem Overrun um? (früher hat es da gepiepst :D ).

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:14:20 14.04.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:37:54 14.04.2009   Titel:              Zitieren

Bezüglich der Interpretation von Scancodes habe ich folgende interessante Gliederung gefunden:
http://www.toasteros.net/
Zitat:

ASCII Translation
Bedeutet Tasten die als ASCII/ANSI Zeichen darzustellen sind, solche wie „asdf“.
Folgende Scancodes zählen dazu: 2 – 13, 16 – 27, 30 – 41, 43 – 53, 86
Sie müssen je nach Shift und Alt Gr und Tastatur Layout interpretiert werden.

Immediate Translation
Tasten die direkt an den User weitergesendet werden ohne vorher in irgendeiner Weise interpretiert zu haben, solche wie die escape taste oder backspace.
Folgende Scancodes zählen dazu: 0 – 1, 14 – 15, 28, 57, 59 – 68, 87 – 88

Numblock Translation
Tasten die vom numerischen Block stammen.
Sie müssen je nach Num Lock interpretiert werden.
Folgende Scancodes zählen dazu: 69, 71 – 83, 55

Direct Translation
Der Rest der Tasten der direkt interpretiert werden muss, dazu gehören caps lock, ctrl, shift, alt und screen lock.
Folgende Scancodes zählen dazu: 58, 29, 42, 54, 56, 70

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 08:29:46 14.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Bleiben die Fragen, wie groß muss KQ sein und wie geht man mit einem Overrun um?

einfach das älteste zeichen überschreiben (overrun ignorieren). daten von der tastatur kannste als veraltet ansehen, wenn lange keiner drauf zugegriffen hat. der buffer kann auch ziemlich klein sein.
:)
volkard
Moderator

Benutzerprofil
Anmeldungsdatum: 06.04.2000
Beiträge: 24349
Beitrag volkard Moderator 09:41:47 14.04.2009   Titel:              Zitieren

+fricky schrieb:
der buffer kann auch ziemlich klein sein.

jup. afair nur 10 zeichen bei MS-DOS. und keiner hats gemerkt.

_________________
http://www.venganza.info/
plonk fürs Forum v1.02
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:45:55 14.04.2009   Titel:              Zitieren

Ja, ich denke auch, dass ein Puffer für Tastatureingaben eher max. 20 Zeichen haben sollte, denn es wirkt - siehe Beispiel mit Warteschleife oben - extrem komisch, wenn da nach dem Tippen noch fast 100 Zeichen aus der Queue auf dem Bildschirm eintrudeln. :D

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 19:56:34 14.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
...extrem komisch, wenn da nach dem Tippen noch fast 100 Zeichen aus der Queue auf dem Bildschirm eintrudeln.

vor allem brauchste dir keine gedanken darum zu machen, wie du den fall handlest, wenn die queue voll ist und neue daten eintrudeln. das problem kriegste erst bei datenquellen, wo nix verloren gehen darf.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:29:54 14.04.2009   Titel:              Zitieren

Noch ein Nachtrag zum Thema C vs C++:
Lowlevel Magazin ( http://lowlevel.brainsware.org/old/files/lowlevel_4.pdf ):
Zitat:
C++ in the Kernel
Opinions vary widely over the use of C++ in a kernel: most Linux kernel coders stay well away from it, whereas some people have entire operating systems in C++. I'd personally stick with C, although I see no real reason why you shouldn't use C++, as long as you know what you're doing. One thing you should realize is that to write a C++ kernel you'll need to write a bit more code for the framework, and that some C++ features are off-limits to you (unless you can write the necessary support code). First off, you'll need to code the new and delete operators. This is easy if you've already coded malloc() and free(): new and delete can be single-line functions which call each of these. If you want to have global instances of classes you'll need to put some code in your startup routine to call each of their constructors. The way this is done will differ between compilers, so the best thing to do is to browse through your compiler's run-time library to see how the vendor did it; try looking in files with names like crt0.c. You'll probably also need to implement atexit(), because the compiler is likely to emit code which uses atexit() to call global object's destructors when the program ends. If you want to use try/catch in your kernel you'll have to implement whatever mechanism your compile uses to implement them. Again, this will depend on the compiler you use, and whatever operating system that compiler targets. In general, I'd steer clear of both exception handling and huge virtual classes in your kernel. Exception handling usually adds unneeded bloat, and calling masses of virtual functions add unnecessary indirection and defeats the optimizer somewhat. Remember, your kernel should be as efficient as possible, even to the detriment of a beautiful design where necessary. Writing an OS in a high-level language such as C can be a lot more productive than coding one entirely in assembly, particularly if you're willing to forego the slight speed increase that assembly offers. There are compilers freely available, such as gcc, which make writing kernel code relatively easy, and using C will probably prove beneficial in the long run

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:32:03 14.04.2009, insgesamt 2-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 20:50:44 14.04.2009   Titel:              Zitieren

^^objective-c bringts auch nicht so: http://kerneltrap.org/mailarchive/linux-kernel/2007/11/30/463283
aber es gibt auch das: http://de.wikipedia.org/wiki/Singularity
(wobei der low-level code aber in C geschrieben wurde).
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:57:01 16.04.2009   Titel:              Zitieren

Ich habe da eine Funktion - basierend auf dem Sourcecode von James Molloy - die dem Compiler beständig eine Warnung entlockt:
C/C++ Code:
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
static ULONG first_frame() // find the first free frame in frames bitset
{
    ULONG index, offset;
    for(index=0; index<(NFRAMES/32); ++index)
        if(frames[index] != 0xFFFFFFFF)
            for(offset=0; offset<32; ++offset)
                if( !(frames[index] & 1<<offset) ) // bit set to zero?
                    return (index*32 + offset);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
static ULONG first_frame() // find the first free frame in frames bitset
{
ULONG index, offset;
for(index=0; index<(NFRAMES/32); ++index)
if(frames[index] != 0xFFFFFFFF)
for(offset=0; offset<32; ++offset)
if( !(frames[index] & 1<<offset) ) // bit set to zero?
return (index*32 + offset);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
static ULONG first_frame() // find the first free frame in frames bitset
{
    ULONG index, offset;
    for(index=0; index<(NFRAMES/32); ++index)
        if(frames[index] != 0xFFFFFFFF)
            for(offset=0; offset<32; ++offset)
                if( !(frames[index] & 1<<offset) ) // bit set to zero?
                    return (index*32 + offset);
}

Zitat:
warning: control reaches end of non-void function

Diese Warnung erhält man, wenn eine Funktion beendet wird, ohne einen Rückgabewert zu erzeugen, obwohl dies laut Deklaration erfolgen sollte. Hat jemand eine Idee, wie man diese nicht einfach lesbare Funktion gesamtheitlich am besten umbaut, damit diese Warnung entfällt.

Anwendung dieser modul-eigenen static-Funktion bisher nur hier:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
void alloc_frame(page_t* page, int is_kernel, int is_writeable) // allocate a frame
{
    if (!(page->frame_addr) )
    {
        ULONG index = first_frame(); //search first free page frame
        if (index == (ULONG)-1)
            printformat("message from alloc_frame: no free frames!!!");

        \\...
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
void alloc_frame(page_t* page, int is_kernel, int is_writeable) // allocate a frame
{
if (!(page->frame_addr) )
{
ULONG index = first_frame(); //search first free page frame
if (index == (ULONG)-1)
printformat("message from alloc_frame: no free frames!!!");

\\...
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
void alloc_frame(page_t* page, int is_kernel, int is_writeable) // allocate a frame
{
    if (!(page->frame_addr) )
    {
        ULONG index = first_frame(); //search first free page frame
        if (index == (ULONG)-1)
            printformat("message from alloc_frame: no free frames!!!");

        \\...
    }
}

Man könnte first_frame() z.B. void deklarieren und eine Argument 'index' als Pointer übergeben, aber vielleicht habt ihr eine bessere Idee.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 21:58:46 16.04.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:07:54 16.04.2009   Titel:              Zitieren

Diese Funktion ist ebenfalls ein merkwürdiges Konstrukt:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
page_t* get_page(ULONG address, UCHAR make, page_directory_t* dir)
{
    address /= PAGESIZE;                // address ==> index.
    ULONG table_index = address / 1024; // ==> page table containing this address

    if (dir->tables[table_index])       // table already assigned
    {
        return &dir->tables[table_index]->pages[address%1024];
    }
    else if(make)
    {
        ULONG phys;
        dir->tables[table_index] = (page_table_t*) k_malloc( sizeof(page_table_t), 1, &phys );
        k_memset(dir->tables[table_index], 0, PAGESIZE);
        dir->tablesPhysical[table_index] = phys | 0x7; // 111b meaning: PRESENT=1, RW=1, USER=1
        return &dir->tables[table_index]->pages[address%1024];
    }
    else
        return
0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
page_t* get_page(ULONG address, UCHAR make, page_directory_t* dir)
{
address /= PAGESIZE; // address ==> index.
ULONG table_index = address / 1024; // ==> page table containing this address

if (dir->tables[table_index]) // table already assigned
{
return &dir->tables[table_index]->pages[address%1024];
}
else if(make)
{
ULONG phys;
dir->tables[table_index] = (page_table_t*) k_malloc( sizeof(page_table_t), 1, &phys );
k_memset(dir->tables[table_index], 0, PAGESIZE);
dir->tablesPhysical[table_index] = phys | 0x7; // 111b meaning: PRESENT=1, RW=1, USER=1
return &dir->tables[table_index]->pages[address%1024];
}
else
return
0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
page_t* get_page(ULONG address, UCHAR make, page_directory_t* dir)
{
    address /= PAGESIZE;                // address ==> index.
    ULONG table_index = address / 1024; // ==> page table containing this address

    if (dir->tables[table_index])       // table already assigned
    {
        return &dir->tables[table_index]->pages[address%1024];
    }
    else if(make)
    {
        ULONG phys;
        dir->tables[table_index] = (page_table_t*) k_malloc( sizeof(page_table_t), 1, &phys );
        k_memset(dir->tables[table_index], 0, PAGESIZE);
        dir->tablesPhysical[table_index] = phys | 0x7; // 111b meaning: PRESENT=1, RW=1, USER=1
        return &dir->tables[table_index]->pages[address%1024];
    }
    else
        return
0;
}


Verwendung (diesmal nicht statisch):
C/C++ Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
    // map (phys addr <---> virt addr) from 0x0 to the end of used memory
    ULONG i=0, counter=0;
    while (i < placement_address)
    {
        alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
        i += PAGESIZE;
        ++counter;
    }
C/C++ Code:
1
2
3
4
5
6
7
8
// map (phys addr <---> virt addr) from 0x0 to the end of used memory
ULONG i=0, counter=0;
while (i < placement_address)
{
alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
i += PAGESIZE;
++counter;
}
C/C++ Code:
1
2
3
4
5
6
7
8
    // map (phys addr <---> virt addr) from 0x0 to the end of used memory
    ULONG i=0, counter=0;
    while (i < placement_address)
    {
        alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
        i += PAGESIZE;
        ++counter;
    }

Eigentlich müsste die Funktion mit gesetztem make-Flag 'make_page(...)' heißen.
Sollte man diese Funktion in eine get_page(...) und eine make_page(...) zerlegen oder ist dies eurer Meinung so o.k.?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:09:15 16.04.2009, insgesamt 1-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 22:13:34 16.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Ich habe da eine Funktion - basierend auf dem Sourcecode von James Molloy - die dem Compiler beständig eine Warnung entlockt:
C/C++ Code:
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
static ULONG first_frame() // find the first free frame in frames bitset
{
    ULONG index, offset;
    for(index=0; index<(NFRAMES/32); ++index)
        if(frames[index] != 0xFFFFFFFF)
            for(offset=0; offset<32; ++offset)
                if( !(frames[index] & 1<<offset) ) // bit set to zero?
                    return (index*32 + offset);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
static ULONG first_frame() // find the first free frame in frames bitset
{
ULONG index, offset;
for(index=0; index<(NFRAMES/32); ++index)
if(frames[index] != 0xFFFFFFFF)
for(offset=0; offset<32; ++offset)
if( !(frames[index] & 1<<offset) ) // bit set to zero?
return (index*32 + offset);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
static ULONG first_frame() // find the first free frame in frames bitset
{
    ULONG index, offset;
    for(index=0; index<(NFRAMES/32); ++index)
        if(frames[index] != 0xFFFFFFFF)
            for(offset=0; offset<32; ++offset)
                if( !(frames[index] & 1<<offset) ) // bit set to zero?
                    return (index*32 + offset);
}

Zitat:
warning: control reaches end of non-void function

Diese Warnung erhält man, wenn eine Funktion beendet wird, ohne einen Rückgabewert zu erzeugen, obwohl dies laut Deklaration erfolgen sollte. Hat jemand eine Idee, wie man diese nicht einfach lesbare Funktion gesamtheitlich am besten umbaut, damit diese Warnung entfällt.

Anwendung dieser modul-eigenen static-Funktion bisher nur hier:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
void alloc_frame(page_t* page, int is_kernel, int is_writeable) // allocate a frame
{
    if (!(page->frame_addr) )
    {
        ULONG index = first_frame(); //search first free page frame
        if (index == (ULONG)-1)
            printformat("message from alloc_frame: no free frames!!!");

        \\...
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
void alloc_frame(page_t* page, int is_kernel, int is_writeable) // allocate a frame
{
if (!(page->frame_addr) )
{
ULONG index = first_frame(); //search first free page frame
if (index == (ULONG)-1)
printformat("message from alloc_frame: no free frames!!!");

\\...
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
void alloc_frame(page_t* page, int is_kernel, int is_writeable) // allocate a frame
{
    if (!(page->frame_addr) )
    {
        ULONG index = first_frame(); //search first free page frame
        if (index == (ULONG)-1)
            printformat("message from alloc_frame: no free frames!!!");

        \\...
    }
}

Man könnte first_frame() z.B. void deklarieren und eine Argument 'index' als Pointer übergeben, aber vielleicht habt ihr eine bessere Idee.

mach ans ende der funktion return (ULONG)-1;
das ist ja der wert für einen ungültigen index, den der aufrufer auch auswertet.
:)
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 22:16:17 16.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Diese Funktion ist ebenfalls ein merkwürdiges Konstrukt:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
page_t* get_page(ULONG address, UCHAR make, page_directory_t* dir)
{
    address /= PAGESIZE;                // address ==> index.
    ULONG table_index = address / 1024; // ==> page table containing this address

    if (dir->tables[table_index])       // table already assigned
    {
        return &dir->tables[table_index]->pages[address%1024];
    }
    else if(make)
    {
        ULONG phys;
        dir->tables[table_index] = (page_table_t*) k_malloc( sizeof(page_table_t), 1, &phys );
        k_memset(dir->tables[table_index], 0, PAGESIZE);
        dir->tablesPhysical[table_index] = phys | 0x7; // 111b meaning: PRESENT=1, RW=1, USER=1
        return &dir->tables[table_index]->pages[address%1024];
    }
    else
        return
0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
page_t* get_page(ULONG address, UCHAR make, page_directory_t* dir)
{
address /= PAGESIZE; // address ==> index.
ULONG table_index = address / 1024; // ==> page table containing this address

if (dir->tables[table_index]) // table already assigned
{
return &dir->tables[table_index]->pages[address%1024];
}
else if(make)
{
ULONG phys;
dir->tables[table_index] = (page_table_t*) k_malloc( sizeof(page_table_t), 1, &phys );
k_memset(dir->tables[table_index], 0, PAGESIZE);
dir->tablesPhysical[table_index] = phys | 0x7; // 111b meaning: PRESENT=1, RW=1, USER=1
return &dir->tables[table_index]->pages[address%1024];
}
else
return
0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
page_t* get_page(ULONG address, UCHAR make, page_directory_t* dir)
{
    address /= PAGESIZE;                // address ==> index.
    ULONG table_index = address / 1024; // ==> page table containing this address

    if (dir->tables[table_index])       // table already assigned
    {
        return &dir->tables[table_index]->pages[address%1024];
    }
    else if(make)
    {
        ULONG phys;
        dir->tables[table_index] = (page_table_t*) k_malloc( sizeof(page_table_t), 1, &phys );
        k_memset(dir->tables[table_index], 0, PAGESIZE);
        dir->tablesPhysical[table_index] = phys | 0x7; // 111b meaning: PRESENT=1, RW=1, USER=1
        return &dir->tables[table_index]->pages[address%1024];
    }
    else
        return
0;
}


hier ist eigentlich nur das letzte 'else' überflüssig.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:58:36 16.04.2009   Titel:              Zitieren

(ULONG)-1 sollte man hier besser 0xFFFFFFFF schreiben?

Ich habe übrigens von James Molloy schriftlich die Freigabe, seinen - aus meiner Sicht nicht uninteressanten - Sourcecode als Basis für eigene Entwicklungen im Rahmen des Tutorials nutzen zu dürfen. Man muss ja nicht immer wieder das Rad neu erfinden, wie man so schön sagt.

Gerade die Verwendung des Bitsets beim Paging ist effizient. Ich habe hier seine #defines durch get_Index_and_Offset(...) ersetzt, so dass man diesen Teil nicht ständig komplett in set/clear/test wiederholen muss:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/************* bitset variables and functions **************/
ULONG ind, offs;

static void get_Index_and_Offset(ULONG frame_addr)
{
    ULONG frame    = frame_addr/PAGESIZE;
    ind    = frame/32;
    offs   = frame%32;
}

static void set_frame(ULONG frame_addr)
{
    get_Index_and_Offset(frame_addr);
    frames[ind] |= (1<<offs);
}

static void clear_frame(ULONG frame_addr)
{
    get_Index_and_Offset(frame_addr);
    frames[ind] &= ~(1<<offs);
}

static ULONG test_frame(ULONG frame_addr)
{
    get_Index_and_Offset(frame_addr);
    return( frames[ind] & (1<<offs) );
}
/***********************************************************/
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/************* bitset variables and functions **************/
ULONG ind, offs;

static void get_Index_and_Offset(ULONG frame_addr)
{
ULONG frame = frame_addr/PAGESIZE;
ind = frame/32;
offs = frame%32;
}

static void set_frame(ULONG frame_addr)
{
get_Index_and_Offset(frame_addr);
frames[ind] |= (1<<offs);
}

static void clear_frame(ULONG frame_addr)
{
get_Index_and_Offset(frame_addr);
frames[ind] &= ~(1<<offs);
}

static ULONG test_frame(ULONG frame_addr)
{
get_Index_and_Offset(frame_addr);
return( frames[ind] & (1<<offs) );
}
/***********************************************************/
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/************* bitset variables and functions **************/
ULONG ind, offs;

static void get_Index_and_Offset(ULONG frame_addr)
{
    ULONG frame    = frame_addr/PAGESIZE;
    ind    = frame/32;
    offs   = frame%32;
}

static void set_frame(ULONG frame_addr)
{
    get_Index_and_Offset(frame_addr);
    frames[ind] |= (1<<offs);
}

static void clear_frame(ULONG frame_addr)
{
    get_Index_and_Offset(frame_addr);
    frames[ind] &= ~(1<<offs);
}

static ULONG test_frame(ULONG frame_addr)
{
    get_Index_and_Offset(frame_addr);
    return( frames[ind] & (1<<offs) );
}
/***********************************************************/


Er hat in seinem Tutorial (Kap. 6-10) folgende Reihenfolge aufgeboten:
6) Paging
7) Heap
8) Virtual File System
9) Multitasking
10) User mode and syscalls

http://www.jamesmolloy.co.uk/tutorial_html/6.-Paging.html etc.

Sein Code und seine Erläuterungen sind aus meiner Sicht aber nur schwer verständlich für Einsteiger in die Materie. Da arbeite ich dran, das zu entflechten und didaktisch zugänglich zu machen.

Mein aktueller Stand bezüglich 6+7:
http://www.henkessoft.de/OS_Dev/Downloads/23.zip

Suche didaktisch noch nach einem guten Weg, die eminente bedeutung von paging und heap wirklich begreiflich zu machen. Aktiviert man momentan die Funktion create_heap in ckernel.c, dann erfolgt ein 'page fault'.
Der nächste Schritt wäre genau die Überwindung dieses Punkts.

Aber es gibt didaktisch noch viele Probleme, z.B. würde ich gerne die Speichernutzung transparent machen, weiß aber nicht wie ich das visualisieren soll. Woher weiß ich, wo der kernel endet ('end' im Linker-Skript? einer meiner Schwächen)? Wo gehört die Page-Verwaltung hin? Warum wird nicht gleich alles gepaged? Wo gehört ein Heap hin? Wo das placement_address? So richtig wird das alles ja erst beim Multitasking klar. Aber man muss vorher damit sinnvoll experimentieren. Falls da jemand geniale Ideen hat. :confused:

James Molloy baut das wie folgt auf (aber keine Ahnung, ob das wirklich gut ist):
- Ende des Kernels (via Linker Script, wie könnte man bei uns diese Adresse sinnvoll besorgen?)
- Bitset ( frames[...] )
- page_directory
C/C++ Code:
    kernel_directory = (page_directory_t*)k_malloc(sizeof(page_directory_t,1,0));
C/C++ Code:
kernel_directory = (page_directory_t*)k_malloc(sizeof(page_directory_t,1,0));
C/C++ Code:
    kernel_directory = (page_directory_t*)k_malloc(sizeof(page_directory_t,1,0));

- dann macht er etwas eher seltsam Anmutendes:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    // Map some pages in the kernel heap area.
    // Here we call get_page but not alloc_frame. This causes page_table_t's
    // to be created where necessary. We can't allocate frames yet because they
    // they need to be identity mapped first below, and yet we can't increase
    // placement_address between identity mapping and enabling the heap!

    int i = 0;
    for (i = KHEAP_START; i < KHEAP_START+KHEAP_INITIAL_SIZE; i += 0x1000)
        get_page(i, 1, kernel_directory);

    // We need to identity map (phys addr = virt addr) from
    // 0x0 to the end of used memory, so we can access this
    // transparently, as if paging wasn't enabled.
    // NOTE that we use a while loop here deliberately.
    // inside the loop body we actually change placement_address
    // by calling kmalloc(). A while loop causes this to be
    // computed on-the-fly rather than once at the start.
    // Allocate a lil' bit extra so the kernel heap can be
    // initialised properly.

    i = 0;
    while (i < placement_address + 0x1000)
    {
        // Kernel code is readable but not writeable from userspace.
        alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
        i += 0x1000;
    }
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Map some pages in the kernel heap area.
// Here we call get_page but not alloc_frame. This causes page_table_t's
// to be created where necessary. We can't allocate frames yet because they
// they need to be identity mapped first below, and yet we can't increase
// placement_address between identity mapping and enabling the heap!

int i = 0;
for (i = KHEAP_START; i < KHEAP_START+KHEAP_INITIAL_SIZE; i += 0x1000)
get_page(i, 1, kernel_directory);

// We need to identity map (phys addr = virt addr) from
// 0x0 to the end of used memory, so we can access this
// transparently, as if paging wasn't enabled.
// NOTE that we use a while loop here deliberately.
// inside the loop body we actually change placement_address
// by calling kmalloc(). A while loop causes this to be
// computed on-the-fly rather than once at the start.
// Allocate a lil' bit extra so the kernel heap can be
// initialised properly.

i = 0;
while (i < placement_address + 0x1000)
{
// Kernel code is readable but not writeable from userspace.
alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
i += 0x1000;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    // Map some pages in the kernel heap area.
    // Here we call get_page but not alloc_frame. This causes page_table_t's
    // to be created where necessary. We can't allocate frames yet because they
    // they need to be identity mapped first below, and yet we can't increase
    // placement_address between identity mapping and enabling the heap!

    int i = 0;
    for (i = KHEAP_START; i < KHEAP_START+KHEAP_INITIAL_SIZE; i += 0x1000)
        get_page(i, 1, kernel_directory);

    // We need to identity map (phys addr = virt addr) from
    // 0x0 to the end of used memory, so we can access this
    // transparently, as if paging wasn't enabled.
    // NOTE that we use a while loop here deliberately.
    // inside the loop body we actually change placement_address
    // by calling kmalloc(). A while loop causes this to be
    // computed on-the-fly rather than once at the start.
    // Allocate a lil' bit extra so the kernel heap can be
    // initialised properly.

    i = 0;
    while (i < placement_address + 0x1000)
    {
        // Kernel code is readable but not writeable from userspace.
        alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
        i += 0x1000;
    }

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:25:58 17.04.2009, insgesamt 8-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:32:34 16.04.2009   Titel:              Zitieren

Zitat:
mach ans ende der funktion return (ULONG)-1;

Ich habe das (ULONG)-1 aussterben lassen:

Sieht momentan - ohne Warnungen - so aus:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
static ULONG first_frame() // find the first free frame in frames bitset
{
    ULONG index, offset;
    for(index=0; index<(NFRAMES/32); ++index)
        if(frames[index] != 0xFFFFFFFF)
            for(offset=0; offset<32; ++offset)
                if( !(frames[index] & 1<<offset) ) // bit set to zero?
                    return (index*32 + offset);
    return 0xFFFFFFFF;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
static ULONG first_frame() // find the first free frame in frames bitset
{
ULONG index, offset;
for(index=0; index<(NFRAMES/32); ++index)
if(frames[index] != 0xFFFFFFFF)
for(offset=0; offset<32; ++offset)
if( !(frames[index] & 1<<offset) ) // bit set to zero?
return (index*32 + offset);
return 0xFFFFFFFF;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
static ULONG first_frame() // find the first free frame in frames bitset
{
    ULONG index, offset;
    for(index=0; index<(NFRAMES/32); ++index)
        if(frames[index] != 0xFFFFFFFF)
            for(offset=0; offset<32; ++offset)
                if( !(frames[index] & 1<<offset) ) // bit set to zero?
                    return (index*32 + offset);
    return 0xFFFFFFFF;
}

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void alloc_frame(page_t* page, int is_kernel, int is_writeable) // allocate a frame
{
    if( !(page->frame_addr) )
    {
        ULONG index = first_frame(); //search first free page frame
        if( index == 0xFFFFFFFF )
            printformat("message from alloc_frame: no free frames!!!");

        set_frame(index*PAGESIZE);

        page->present    = 1;
        page->rw         = ( is_writeable == 1 ) ? 1 : 0;
        page->user       = ( is_kernel    == 1 ) ? 0 : 1;
        page->frame_addr = index;
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void alloc_frame(page_t* page, int is_kernel, int is_writeable) // allocate a frame
{
if( !(page->frame_addr) )
{
ULONG index = first_frame(); //search first free page frame
if( index == 0xFFFFFFFF )
printformat("message from alloc_frame: no free frames!!!");

set_frame(index*PAGESIZE);

page->present = 1;
page->rw = ( is_writeable == 1 ) ? 1 : 0;
page->user = ( is_kernel == 1 ) ? 0 : 1;
page->frame_addr = index;
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void alloc_frame(page_t* page, int is_kernel, int is_writeable) // allocate a frame
{
    if( !(page->frame_addr) )
    {
        ULONG index = first_frame(); //search first free page frame
        if( index == 0xFFFFFFFF )
            printformat("message from alloc_frame: no free frames!!!");

        set_frame(index*PAGESIZE);

        page->present    = 1;
        page->rw         = ( is_writeable == 1 ) ? 1 : 0;
        page->user       = ( is_kernel    == 1 ) ? 0 : 1;
        page->frame_addr = index;
    }
}


Zitat:
hier ist eigentlich nur das letzte 'else' überflüssig.

Das mag sein, macht die Sache aber nur noch schlimmer. :rolleyes:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:42:22 16.04.2009, insgesamt 2-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 08:34:35 17.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zitat:
mach ans ende der funktion return (ULONG)-1;

Ich habe das (ULONG)-1 aussterben lassen:

dann mach wenigstens eine #define aus 0xFFFFFFFF. vergisste mal ein F, dann kannste wieder schön lange fehler suchen.

Erhard Henkes schrieb:

Zitat:
hier ist eigentlich nur das letzte 'else' überflüssig.

Das mag sein, macht die Sache aber nur noch schlimmer.

wieso? einfach wech damit und return 0 ans ende. bleibt das gleiche.
:)
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 10:45:56 17.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Ich habe da eine Funktion - basierend auf dem Sourcecode von James Molloy - die dem Compiler beständig eine Warnung entlockt:
C/C++ Code:
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
static ULONG first_frame() // find the first free frame in frames bitset
{
    ULONG index, offset;
    for(index=0; index<(NFRAMES/32); ++index)
        if(frames[index] != 0xFFFFFFFF)
            for(offset=0; offset<32; ++offset)
                if( !(frames[index] & 1<<offset) ) // bit set to zero?
                    return (index*32 + offset);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
static ULONG first_frame() // find the first free frame in frames bitset
{
ULONG index, offset;
for(index=0; index<(NFRAMES/32); ++index)
if(frames[index] != 0xFFFFFFFF)
for(offset=0; offset<32; ++offset)
if( !(frames[index] & 1<<offset) ) // bit set to zero?
return (index*32 + offset);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
static ULONG first_frame() // find the first free frame in frames bitset
{
    ULONG index, offset;
    for(index=0; index<(NFRAMES/32); ++index)
        if(frames[index] != 0xFFFFFFFF)
            for(offset=0; offset<32; ++offset)
                if( !(frames[index] & 1<<offset) ) // bit set to zero?
                    return (index*32 + offset);
}


*hüstel* hier ist das original:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Static function to find the first free frame.
static u32int first_frame()
{
   u32int i, j;
   for (i = 0; i < INDEX_FROM_BIT(nframes); i++)
   {
       if (frames[i] != 0xFFFFFFFF) // nothing free, exit early.
       {
           // at least one bit is free here.
           for (j = 0; j < 32; j++)
           {
               u32int toTest = 0x1 << j;
               if ( !(frames[i]&toTest) )
               {
                   return i*4*8+j;
               }
           }
       }
   }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Static function to find the first free frame.
static u32int first_frame()
{
u32int i, j;
for (i = 0; i < INDEX_FROM_BIT(nframes); i++)
{
if (frames[i] != 0xFFFFFFFF) // nothing free, exit early.
{
// at least one bit is free here.
for (j = 0; j < 32; j++)
{
u32int toTest = 0x1 << j;
if ( !(frames[i]&toTest) )
{
return i*4*8+j;
}
}
}
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Static function to find the first free frame.
static u32int first_frame()
{
   u32int i, j;
   for (i = 0; i < INDEX_FROM_BIT(nframes); i++)
   {
       if (frames[i] != 0xFFFFFFFF) // nothing free, exit early.
       {
           // at least one bit is free here.
           for (j = 0; j < 32; j++)
           {
               u32int toTest = 0x1 << j;
               if ( !(frames[i]&toTest) )
               {
                   return i*4*8+j;
               }
           }
       }
   }
}

wieso verunstaltest du eigentlich diese, gut lesbare funktion, zu einem grausam verfrickelten ungetüm wie da oben? alle geschweiften klammern und temporären variablen wegzulöschen, aus i++ ++i machen und macros von hand aufzulösen ist zwar voll 1337-mässig, bringt aber überhaupt nix. wenn du auf verständlichkeit des codes wert legst, dann lass solchen unsinn besser sein.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:35:28 17.04.2009   Titel:              Zitieren

Jeder hat seinen Stil. :cool:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 18:51:47 17.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Jeder hat seinen Stil.

ok, aber es soll doch ein tutorial sein. wenn du die funktionen ihrer lesbarkeit beraubst und eventuell dadurch fehler einbaust (z.b. i++ ist oft nicht das selbe wie ++i), dann machst du's dir und deinen lesern nur unnötig schwer.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:05:55 17.04.2009   Titel:              Zitieren

An ein paar Klammern soll es wahrlich nicht scheitern:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static ULONG first_frame() // find the first free frame in frames bitset
{
    ULONG index, offset;
    for(index=0; index<(NFRAMES/32); ++index)
    {
        if(frames[index] != ULONG_MAX)
        {
            for(offset=0; offset<32; ++offset)
            {
                if( !(frames[index] & 1<<offset) ) // bit set to zero?
                    return (index*32 + offset);
            }
        }
    }
    return ULONG_MAX; // no free page frames
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static ULONG first_frame() // find the first free frame in frames bitset
{
ULONG index, offset;
for(index=0; index<(NFRAMES/32); ++index)
{
if(frames[index] != ULONG_MAX)
{
for(offset=0; offset<32; ++offset)
{
if( !(frames[index] & 1<<offset) ) // bit set to zero?
return (index*32 + offset);
}
}
}
return ULONG_MAX; // no free page frames
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static ULONG first_frame() // find the first free frame in frames bitset
{
    ULONG index, offset;
    for(index=0; index<(NFRAMES/32); ++index)
    {
        if(frames[index] != ULONG_MAX)
        {
            for(offset=0; offset<32; ++offset)
            {
                if( !(frames[index] & 1<<offset) ) // bit set to zero?
                    return (index*32 + offset);
            }
        }
    }
    return ULONG_MAX; // no free page frames
}


Mir gefällt das sprechende index u. offset aber besser als i und j.
Das große NFRAMES finde ich auch besser, weil konstant:
C/C++ Code:
ULONG  NFRAMES = PHYSICAL_MEMORY / PAGESIZE;
C/C++ Code:
ULONG NFRAMES = PHYSICAL_MEMORY / PAGESIZE;
C/C++ Code:
ULONG  NFRAMES = PHYSICAL_MEMORY / PAGESIZE;

Ich verwende das Präinkrement bevorzugt vor dem Postinkrement. In der for-Schleife spielt es keine Rolle.
Welches #define ... würdest Du denn für 0xFFFFFFFF verwenden? Da hat mich Dein Vorschlag sogar überzeugt, das könnte man noch austauschen, man nimmt wohl am besten das aus limits.h:
#define ULONG_MAX 4294967295UL also ULONG_MAX

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:32:36 17.04.2009, insgesamt 2-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 19:30:06 17.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

An ein paar Klammern soll es wahrlich nicht scheitern:

alle daumen hoch^^

Erhard Henkes schrieb:

Mir gefällt das sprechende index u. offset aber besser als i und j.

das ist ok, aussagekräftige bezeichner sind immer gut, solange sie auch das richtige ausdrücken.

Erhard Henkes schrieb:

Ich verwende das Präinkrement bevorzugt vor dem Postinkrement.

naja, weil's dir vielleicht besser gefällt, aber für eine änderung gibt's keinen sachlichen grund, erst recht nicht, wenn der code vorher schon gut funktionierte. ich behaupte mal, die meisten c-programmierer benutzen eher das post-increment. mir jedenfalls sticht ein pre-increment immer ins auge und ich denke mir 'warum macht das hier jemand so? das hat mehr zu bedeuten, als nur die variable hochzuzählen'.

Erhard Henkes schrieb:

Welches #define ... würdest Du denn für 0xFFFFFFFF verwenden? Da hat mich Dein Vorschlag sogar überzeugt, das könnte man noch austauschen.

das 0xFFFFFFFF bedeutet hier doch 'ungültiger wert' oder sowas, dann könnteste es z.b. INVALID_VALUE o.ä. taufen.

btw, und was selbstdefinierte typen angeht: ULONG sieht aus wie ein #define (alles gross geschrieben). nimm doch als typedef uint32_t. das wäre dann sogar richtig modern, C99-mässig
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:53:00 17.04.2009   Titel:              Zitieren

Ich finde dieses angehängte _t für Standardtypen irgendwie lästig.
C/C++ Code:
typedef unsigned int   UINT;
typedef unsigned char  UCHAR;
typedef unsigned short USHORT;
typedef unsigned long  ULONG;
typedef signed char    CHAR;
C/C++ Code:
typedef unsigned int UINT;
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef unsigned long ULONG;
typedef signed char CHAR;
C/C++ Code:
typedef unsigned int   UINT;
typedef unsigned char  UCHAR;
typedef unsigned short USHORT;
typedef unsigned long  ULONG;
typedef signed char    CHAR;

findet man in os.h. Schön ist dies wirklich nicht, aber auf jeden Fall kürzer als unsigned xxx. Zumindest habe ich nicht BYTE, WORD und DWORD verwendet. :D

Die Code-Einfärbung kennt dies auch noch nicht:
C/C++ Code:
uint32_t zahl
C/C++ Code:
uint32_t zahl
C/C++ Code:
uint32_t zahl


Da mir Didaktik wichtig ist, wie sieht dies die Allgemeinheit?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:15:48 17.04.2009, insgesamt 2-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 20:31:05 17.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Ich finde dieses angehängte _t für Standardtypen irgendwie lästig.

Wenn man primitiven Editor nutzt, dann ist es eben so, dass man alles selbst eintippen muss. Es gibt bekanntlich Alternativen ;)
return -1
Unregistrierter




Beitrag return -1 Unregistrierter 20:39:53 17.04.2009   Titel:              Zitieren

+fricky schrieb:
ich behaupte mal, die meisten c-programmierer benutzen eher das post-increment. mir jedenfalls sticht ein pre-increment immer ins auge und ich denke mir 'warum macht das hier jemand so? das hat mehr zu bedeuten, als nur die variable hochzuzählen'.


Dabei ist es doch genau umgekehrt, pre-incement zählt nur hoch, post-increment kann mehr bedeuten.
Unregistrierter





Beitrag Unregistrierter 21:11:46 17.04.2009   Titel:              Zitieren

C/C++ Code:
typedef unsigned int   UINT;
typedef unsigned char  UCHAR;
typedef unsigned short USHORT;
typedef unsigned long  ULONG;
typedef signed char    CHAR;
C/C++ Code:
typedef unsigned int UINT;
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef unsigned long ULONG;
typedef signed char CHAR;
C/C++ Code:
typedef unsigned int   UINT;
typedef unsigned char  UCHAR;
typedef unsigned short USHORT;
typedef unsigned long  ULONG;
typedef signed char    CHAR;
Besser mit Breite statt mit "Namen", z.B. UINT32, UINT16, usw.
Für mein Kompiler gilt dummerweise ULONG == UINT.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:38:34 18.04.2009   Titel:              Zitieren

Ist das ein ernsthaftes Problem? Beim verwendeten DJGPP entspricht int nämlich 32 Bit.

C/C++ Code:
printformat("Size of short: %d, int: %d, long: %d\n", sizeof(short), sizeof(int), sizeof(long));
C/C++ Code:
printformat("Size of short: %d, int: %d, long: %d\n", sizeof(short), sizeof(int), sizeof(long));
C/C++ Code:
printformat("Size of short: %d, int: %d, long: %d\n", sizeof(short), sizeof(int), sizeof(long));
Zitat:
Size of short: 2, int: 4, long: 4

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:46:15 18.04.2009, insgesamt 1-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 10:11:36 18.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Ist das ein ernsthaftes Problem? Beim verwendeten DJGPP entspricht int nämlich 32 Bit. ...

Für PC-Programmierer ist es wahrscheinlich kein Problem.
Bei dem Compiler, den ich grade verwende (verwenden muss ;)), ist z.B. sizeof(int) == 4 (32 Bit) und sizeof(long) == 5 (40 Bit)...
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 10:34:05 18.04.2009   Titel:              Zitieren

Zitat:
Bei dem Compiler, den ich grade verwende (verwenden muss ;)), ist z.B. sizeof(int) == 4 (32 Bit) und sizeof(long) == 5 (40 Bit)...

Danke für das Feedback. Momentan möchte ich diese Zahlen in den Typen vermeiden. Bei seltsamen Breiten von long kann man ja in os.h im typedef von long auf int umschalten, oders ehe ich das verkehrt?

Ich habe da noch eine Warnung im Compiler, bei der ich nicht ganz sicher bin, wie man sie am saubersten abschaltet:

C/C++ Code:
ULONG fetchESP()
{
    asm ( "mov %esp,%eax" );
}
C/C++ Code:
ULONG fetchESP()
{
asm ( "mov %esp,%eax" );
}
C/C++ Code:
ULONG fetchESP()
{
    asm ( "mov %esp,%eax" );
}

Verwendung:
C/C++ Code:
printformat("SS: %x, ESP: %x, EBP: %x\n", fetchSS(),fetchESP(),fetchEBP());
C/C++ Code:
printformat("SS: %x, ESP: %x, EBP: %x\n", fetchSS(),fetchESP(),fetchEBP());
C/C++ Code:
printformat("SS: %x, ESP: %x, EBP: %x\n", fetchSS(),fetchESP(),fetchEBP());

Warnung:
Zitat:
control reaches end of non-void function

Wie muss die Rückgabezeile aussehen? Ich möchte nicht void* als Rückgabewert verwenden, sondern ULONG, das in PrettyOS für 32-Bit-Speicheradressen Verwendung findet.
Selbe Frage wie hier: http://www.c-plusplus.de/forum/viewtopic-var-p-is-1697586.html

Ich habe mal folgendes probiert, was offenbar funktioniert, bin bei der AT&T Syntax nie ganz sicher, aber offenbar wird es langsam:
C/C++ Code:
ULONG fetchESP()
{
    register int eax asm("%eax");
    asm volatile ( "movl %esp,%eax" );
    return eax;
}
C/C++ Code:
ULONG fetchESP()
{
register int eax asm("%eax");
asm volatile ( "movl %esp,%eax" );
return eax;
}
C/C++ Code:
ULONG fetchESP()
{
    register int eax asm("%eax");
    asm volatile ( "movl %esp,%eax" );
    return eax;
}

Benötigt man hier movl oder geht auch mov? Ist asm volatile notwendig?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 11:45:19 18.04.2009, insgesamt 4-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 10:44:23 18.04.2009   Titel:              Zitieren

Noch ein Punkt: Ich möchte "Files" in die kommende "RAM disk" laden und dort mit dem virtuellen Filesystem bearbeiten. Dabei habe ich die Aufgabe eine bin- oder img-Datei von Floppy (hat nicht jeder) oder Festplatte (gefährlich bei Fehler) an eine feste Stelle im Speicher zu laden. Dies erfolgt typisch mittels GRUB, unser System soll ja aber ohne GRUB laufen. Welches Tool nimmt man da bei MS Windows in makefile, um ein file.img (sagen wir mal von Festplatte) sicher an eine bestimmte Stelle im RAM zu transportieren?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 11:43:35 18.04.2009, insgesamt 1-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 12:51:38 18.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Danke für das Feedback. Momentan möchte ich diese Zahlen in den Typen vermeiden. Bei seltsamen Breiten von long kann man ja in os.h im typedef von long auf int umschalten, oders ehe ich das verkehrt?

Was ist dann der Sinn und Zweck von diesen Typdefinitionen... Man strebt eine gewisse Portabilität, z.B. mit der folgenden Typdefinition:
C/C++ Code:
typedef long LONG;
C/C++ Code:
typedef long LONG;
C/C++ Code:
typedef long LONG;
weiss man immer noch nicht, wie viele Bits soll denn ein LONG sein? 32, 40 oder 64 Bit? Es geht ja nicht darum, den Typ long irgendwie zu verstecken, sondern "neue" Typen einzuführen, wo man genau weiss, dass sie so und so viele Bits breit sind.

Erhard Henkes schrieb:
Ich habe da noch eine Warnung im Compiler, bei der ich nicht ganz sicher bin, wie man sie am saubersten abschaltet...

Was würde dagegen sprechen, diese Funktion ganz in Assembler zu realisieren. Diese asm im Quellcode ist wie ein Dorn im Auge :) Wieder mal meine Phylosophie...
Also in Assembler z.B. so:
Assembler Code:
.global _fetchESP

.section .text

_fetchESP:
    movl %esp, %eax
    ret
Assembler Code:
.global _fetchESP

.section .text

_fetchESP:
movl %esp, %eax
ret
Assembler Code:
.global _fetchESP

.section .text

_fetchESP:
    movl %esp, %eax
    ret

Assemblieren geht so:
Code:
as datei.s -o datei.o
Code:
as datei.s -o datei.o
Code:
as datei.s -o datei.o

Dann in irgendeiner Header Datei dem Compiler sagen, wie die Funktion aussieht:
C/C++ Code:
extern uint32_t fetchESP(void);
C/C++ Code:
extern uint32_t fetchESP(void);
C/C++ Code:
extern uint32_t fetchESP(void);

Und die Objektdatei datei.o noch beim Linken angeben...

Erhard Henkes schrieb:
Benötigt man hier movl oder geht auch mov? Ist asm volatile notwendig?

Bei Befehlen, bei denen der Assembler erkennen kann, wie breit die Operanden sind, kann man l (steht für long) auch weglassen. Ich persönlich mach das nicht, weil defensive Programmierung usw. :)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 13:44:54 18.04.2009   Titel:              Zitieren

Zitat:
Diese asm im Quellcode ist wie ein Dorn im Auge
Dank der AT&T Syntax sicherlich. Dafür hat es den Vorteil, dass man den Code im gleichen Modul betrachten kann. In obigem Fall sicher nicht so kritisch, da sprechende Funktionen.

In PrettyOS haben wir eine Mischung aus beidem, so dass der geneigte Leser/Entwickler selbst entscheiden kann, wie er es gerne hätte.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 13:48:33 18.04.2009, insgesamt 1-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 14:22:42 18.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zitat:
Diese asm im Quellcode ist wie ein Dorn im Auge
Dank der AT&T Syntax sicherlich. Dafür hat es den Vorteil, dass man den Code im gleichen Modul betrachten kann.

Für mich nicht wegen der AT&T Syntax, sondern wegen diesem gcc-spezifischen Inline und der ganzen Schar von Regeln, die man dabei beachten muss. Diese c-Datei ist nun auf den gcc-Compiler festgenagelt, was ja der Philosophie der C-Sprache, im Sinne höhere Sprache, plattformunabhängig, portabel usw., widerspricht...
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 15:18:52 18.04.2009   Titel:              Zitieren

Ja, das ist ein Argument.

Momentan kämpfe ich auf Basis des leider blutleeren Tutorials und mit Grub Multiboot Daten und festen Parametern durchzogenen Codes von James Molloy mit diesen wirklich interessanten aber auch komplexen Themen:
- Paging (läuft sehr gut, fehlt noch die richtige Visualisierungsidee für die Pages),
- Heap (läuft, RAM Disk landet z.B. dort),
- Virtual File System (tolles Feature, weiß noch nicht, wie ich die Daten von HD oder Floppy in die zu erzeugende RAM Disk bringen soll, aber da wird mir noch etwas einfallen),
- Multitasking / Kernel & User Mode/ System calls (komplex, aber interessant)

... und suche nach einem vernünftigen didaktischem Konzept und guten Ideen der "Begreiflichmachung" dessen, was da vor und hinter den "Mauern" (PM) des Kernels vor sich geht. Das ist ein größeres Problem als ich dachte. Ich verzichte darauf, die Probleme detailliert darzustellen, wühle zunächst weiter. Wenn mich jemand konkret unterstützen will, kann er mich gerne kontaktieren.

Ich bin froh, dass ich diese konkrete Grundlage von JM (auf Basis des alten Bran's Tut) gefunden habe. Sobald die von mir modifizierten Module transparent, verständlich(!) und korrekt zusammen arbeiten, werde ich das Ganze hier zur Diskussion stellen und parallel im Tutorial verarbeiten. Kann aber leider dauern, da ich momentan didaktisch noch(!) keine klare Linie sehe, also bitte Geduld oder konkrete Mithilfe.

Was mir am meisten fehlt, ist eine standardisierte Diagnose-Funktion für die Memory-Darstellung. Vielleicht muss ich da meine "ODA" noch mit ein paar Daten auf Stand halten, die ich dann bei Bedarf loggen kann. Hauptproblem sind momentan page faults. :)

Das mit dem FIFO (20 Keys) bei den Tasten-Infos hat ja sehr gut geklappt. Danke für den Vorschlag. Die exakte Auswertung der Scans kann man später noch ausgefeilt aufbauen, wenn die Anwendungen (z.B. eine Shell) diese wirklich brauchen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 10:19:52 19.04.2009, insgesamt 8-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 10:37:24 19.04.2009   Titel:              Zitieren

Hier könnte ich noch Hilfestellung brauchen:
"Which tool could you recommend (MS Windows) for transfering files/data from external mediums to the memory before or after the boot process?"
Vielleicht denke ich da auch verkehrt herum. Bisher habe ich ja noch keine Einrichtung im OS für einen File-Transfer. Wäre hilfreich, weil man da einige Demo-Daten in die "RAM Disk" schieben könnte. Hat aber noch Zeit, über das eigene Filesystem muss man hierbei ja auch vertieft nachdenken.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:51:09 19.04.2009   Titel:              Zitieren

Das hier ist z.B. die "niedliche" Umschaltung auf User Mode. Da hinten dran wühle ich gerade herum. Jetzt fehlen noch brauchbare syscalls usw. Kämpfe noch mit page faults, weil der user nicht einfach auf kernel code zugreifen darf. PM schlägt voll zu (schön!). Endlich passt alles zusammen.
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    // Set up a stack structure for switching to user mode (ring 3 => RPL = 0x3)
    // 0x200 is IF flag (enabling interrupts)
    // 0x20|0x3=0x23  // 0x18|0x3=0x1B
    // $1F means "the address of the next label '1:', searching forward"
    // User Mode:    

      asm volatile("  \
      cli; \
      mov $0x23, %ax; \
      mov %ax, %ds; \
      mov %ax, %es; \
      mov %ax, %fs; \
      mov %ax, %gs; \
                    \
      mov %esp, %eax; \
      pushl $0x23; \
      pushl %esp; \
      pushf; \
      pop %eax; \
      or $0x200, %eax; \
      push %eax; \
      pushl $0x1B; \
      push $1f; \
      iret; \
    1: \
     
");
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Set up a stack structure for switching to user mode (ring 3 => RPL = 0x3)
// 0x200 is IF flag (enabling interrupts)
// 0x20|0x3=0x23 // 0x18|0x3=0x1B
// $1F means "the address of the next label '1:', searching forward"
// User Mode:

asm volatile(" \
cli; \
mov $0x23, %ax; \
mov %ax, %ds; \
mov %ax, %es; \
mov %ax, %fs; \
mov %ax, %gs; \
\
mov %esp, %eax; \
pushl $0x23; \
pushl %esp; \
pushf; \
pop %eax; \
or $0x200, %eax; \
push %eax; \
pushl $0x1B; \
push $1f; \
iret; \
1: \
");
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    // Set up a stack structure for switching to user mode (ring 3 => RPL = 0x3)
    // 0x200 is IF flag (enabling interrupts)
    // 0x20|0x3=0x23  // 0x18|0x3=0x1B
    // $1F means "the address of the next label '1:', searching forward"
    // User Mode:    

      asm volatile("  \
      cli; \
      mov $0x23, %ax; \
      mov %ax, %ds; \
      mov %ax, %es; \
      mov %ax, %fs; \
      mov %ax, %gs; \
                    \
      mov %esp, %eax; \
      pushl $0x23; \
      pushl %esp; \
      pushf; \
      pop %eax; \
      or $0x200, %eax; \
      push %eax; \
      pushl $0x1B; \
      push $1f; \
      iret; \
    1: \
     
");

Danach hat man allerdings keinen direkten Zugriff mehr auf den eigenen Code in ckernel.c! Wenn man nach dem Umschalten in den user mode nicht per "page fault" ausgehebelt werden will, muss man dem user sozusagen Supervisor-Rechte geben, funktioniert voll!
User als Supervisor:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    //Kernel Mode:    
    asm volatile("  \
      cli; \
      mov $0x20, %ax; \
      mov %ax, %ds; \
      mov %ax, %es; \
      mov %ax, %fs; \
      mov %ax, %gs; \
                    \
      mov %esp, %eax; \
      pushl $0x20; \
      pushl %esp; \
      pushf; \
      pop %eax; \
      or $0x200, %eax; \
      push %eax; \
      pushl $0x18; \
      push $1f; \
      iret; \
    1: \
     
");
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Kernel Mode:
asm volatile(" \
cli; \
mov $0x20, %ax; \
mov %ax, %ds; \
mov %ax, %es; \
mov %ax, %fs; \
mov %ax, %gs; \
\
mov %esp, %eax; \
pushl $0x20; \
pushl %esp; \
pushf; \
pop %eax; \
or $0x200, %eax; \
push %eax; \
pushl $0x18; \
push $1f; \
iret; \
1: \
");
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    //Kernel Mode:    
    asm volatile("  \
      cli; \
      mov $0x20, %ax; \
      mov %ax, %ds; \
      mov %ax, %es; \
      mov %ax, %fs; \
      mov %ax, %gs; \
                    \
      mov %esp, %eax; \
      pushl $0x20; \
      pushl %esp; \
      pushf; \
      pop %eax; \
      or $0x200, %eax; \
      push %eax; \
      pushl $0x18; \
      push $1f; \
      iret; \
    1: \
     
");

und
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void gdt_install()
{
    /* Setup the GDT pointer and limit */
    gdt_register.limit = (sizeof(struct gdt_entry) * NUMBER_GDT_GATES)-1;
    gdt_register.base  = (ULONG) &gdt;

    /* GDT GATES -  desriptors with pointers to the linear memory address */
    gdt_set_gate(0, 0, 0, 0, 0);                // NULL descriptor
    gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // CODE, privilege level 0 for kernel code
    gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // DATA, privilege level 0 for kernel code

    //TEST
    //Kernel Mode:

    gdt_set_gate(3, 0, 0xFFFFFFFF, 0x9A, 0xCF); // CODE, privilege level 0 for kernel code
    gdt_set_gate(4, 0, 0xFFFFFFFF, 0x92, 0xCF); // DATA, privilege level 0 for kernel code
    //TEST
    //User Mode:
    //gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // CODE, privilege level 3 for user code
    //gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // DATA, privilege level 3 for user code


    write_tss   (5, 0x10, 0x0);

   
    gdt_flush((ULONG)&gdt_register); // inclusive gdt_load() in Assembler
    tss_flush();
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void gdt_install()
{
/* Setup the GDT pointer and limit */
gdt_register.limit = (sizeof(struct gdt_entry) * NUMBER_GDT_GATES)-1;
gdt_register.base = (ULONG) &gdt;

/* GDT GATES - desriptors with pointers to the linear memory address */
gdt_set_gate(0, 0, 0, 0, 0); // NULL descriptor
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // CODE, privilege level 0 for kernel code
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // DATA, privilege level 0 for kernel code

//TEST
//Kernel Mode:

gdt_set_gate(3, 0, 0xFFFFFFFF, 0x9A, 0xCF); // CODE, privilege level 0 for kernel code
gdt_set_gate(4, 0, 0xFFFFFFFF, 0x92, 0xCF); // DATA, privilege level 0 for kernel code
//TEST
//User Mode:
//gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // CODE, privilege level 3 for user code
//gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // DATA, privilege level 3 for user code


write_tss (5, 0x10, 0x0);


gdt_flush((ULONG)&gdt_register); // inclusive gdt_load() in Assembler
tss_flush();
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void gdt_install()
{
    /* Setup the GDT pointer and limit */
    gdt_register.limit = (sizeof(struct gdt_entry) * NUMBER_GDT_GATES)-1;
    gdt_register.base  = (ULONG) &gdt;

    /* GDT GATES -  desriptors with pointers to the linear memory address */
    gdt_set_gate(0, 0, 0, 0, 0);                // NULL descriptor
    gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // CODE, privilege level 0 for kernel code
    gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // DATA, privilege level 0 for kernel code

    //TEST
    //Kernel Mode:

    gdt_set_gate(3, 0, 0xFFFFFFFF, 0x9A, 0xCF); // CODE, privilege level 0 for kernel code
    gdt_set_gate(4, 0, 0xFFFFFFFF, 0x92, 0xCF); // DATA, privilege level 0 for kernel code
    //TEST
    //User Mode:
    //gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // CODE, privilege level 3 for user code
    //gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // DATA, privilege level 3 for user code


    write_tss   (5, 0x10, 0x0);

   
    gdt_flush((ULONG)&gdt_register); // inclusive gdt_load() in Assembler
    tss_flush();
}


Test in ckernel.c:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include "os.h"
#include
"kheap.h"
#include
"initrd.h"
#include
"task.h"

int main()
{
    initial_esp = fetchESP();
    k_clear_screen();
    printformat("Welcome to PrettyOS 0.07\n");
    printformat("initial_esp: %x \n", initial_esp);

    // GDT, IDT, ISRS, IRQ, timer, keyboard, paging, enable interrupts, RAM disk, multitasking

    settextcolor(2,0); printformat("GDT, IDT, ISRS, IRQ, timer, keyboard install\n"); settextcolor(15,0);
    gdt_install();
    idt_install();
    isrs_install();
    irq_install();
    initODA();
    sti();
    timer_install();
    keyboard_install();

    settextcolor(2,0); printformat("paging install\n"); settextcolor(15,0);
    paging_install();

    settextcolor(2,0); printformat("tasking install\n"); settextcolor(15,0);
    install_tasking();

    settextcolor(2,0); printformat("VFS & RAM Disk install\n"); settextcolor(15,0);
    ULONG ramdisk_start = 0x40081000, ramdisk_end = 0x40090000; // Im Heap Bereich
    if(placement_address < ramdisk_end) placement_address = ramdisk_end;
    printformat("placement_address: %x \n", placement_address);
    fs_root = install_initrd(ramdisk_start);
    printformat("fs_root->name: %s fs_root->ptr: %d \n", fs_root->name, fs_root->ptr);

    settextcolor(2,0); printformat("switch to user mode\n"); settextcolor(15,0);
    switch_to_user_mode();
    settextcolor(2,0); printformat("behind switch to user mode with ring 0 supervisor privilege!\n"); settextcolor(15,0);

    printformat("KQ: %x TAIL: %x HEAD: %x\n", pODA->KEYQUEUE, pODA->pTailKQ, pODA->pHeadKQ);
    printformat("SS: %x, ESP: %x, EBP: %x\n", fetchSS(),fetchESP(),fetchEBP());
    printformat("CS: %x, DS: %x\n",  fetchCS(),fetchDS());

    settextcolor(2,0);
    set_cursor(0,6);

    UCHAR c=0;
    while(TRUE)
    {
      if( k_checkKQ_and_print_char() )
      {
        ++c;
        if(c>5)
        {
          c=0;
          settextcolor(4,0);
          printformat("\nT: %x H: %x WRITE: %i Read: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write, pODA->KQ_count_read);
          printformat("*T: %c %i *H: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
          settextcolor(2,0);
        }
      }
    }

    return 0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include "os.h"
#include
"kheap.h"
#include
"initrd.h"
#include
"task.h"

int main()
{
initial_esp = fetchESP();
k_clear_screen();
printformat("Welcome to PrettyOS 0.07\n");
printformat("initial_esp: %x \n", initial_esp);

// GDT, IDT, ISRS, IRQ, timer, keyboard, paging, enable interrupts, RAM disk, multitasking

settextcolor(2,0); printformat("GDT, IDT, ISRS, IRQ, timer, keyboard install\n"); settextcolor(15,0);
gdt_install();
idt_install();
isrs_install();
irq_install();
initODA();
sti();
timer_install();
keyboard_install();

settextcolor(2,0); printformat("paging install\n"); settextcolor(15,0);
paging_install();

settextcolor(2,0); printformat("tasking install\n"); settextcolor(15,0);
install_tasking();

settextcolor(2,0); printformat("VFS & RAM Disk install\n"); settextcolor(15,0);
ULONG ramdisk_start = 0x40081000, ramdisk_end = 0x40090000; // Im Heap Bereich
if(placement_address < ramdisk_end) placement_address = ramdisk_end;
printformat("placement_address: %x \n", placement_address);
fs_root = install_initrd(ramdisk_start);
printformat("fs_root->name: %s fs_root->ptr: %d \n", fs_root->name, fs_root->ptr);

settextcolor(2,0); printformat("switch to user mode\n"); settextcolor(15,0);
switch_to_user_mode();
settextcolor(2,0); printformat("behind switch to user mode with ring 0 supervisor privilege!\n"); settextcolor(15,0);

printformat("KQ: %x TAIL: %x HEAD: %x\n", pODA->KEYQUEUE, pODA->pTailKQ, pODA->pHeadKQ);
printformat("SS: %x, ESP: %x, EBP: %x\n", fetchSS(),fetchESP(),fetchEBP());
printformat("CS: %x, DS: %x\n", fetchCS(),fetchDS());

settextcolor(2,0);
set_cursor(0,6);

UCHAR c=0;
while(TRUE)
{
if( k_checkKQ_and_print_char() )
{
++c;
if(c>5)
{
c=0;
settextcolor(4,0);
printformat("\nT: %x H: %x WRITE: %i Read: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write, pODA->KQ_count_read);
printformat("*T: %c %i *H: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
settextcolor(2,0);
}
}
}

return 0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include "os.h"
#include
"kheap.h"
#include
"initrd.h"
#include
"task.h"

int main()
{
    initial_esp = fetchESP();
    k_clear_screen();
    printformat("Welcome to PrettyOS 0.07\n");
    printformat("initial_esp: %x \n", initial_esp);

    // GDT, IDT, ISRS, IRQ, timer, keyboard, paging, enable interrupts, RAM disk, multitasking

    settextcolor(2,0); printformat("GDT, IDT, ISRS, IRQ, timer, keyboard install\n"); settextcolor(15,0);
    gdt_install();
    idt_install();
    isrs_install();
    irq_install();
    initODA();
    sti();
    timer_install();
    keyboard_install();

    settextcolor(2,0); printformat("paging install\n"); settextcolor(15,0);
    paging_install();

    settextcolor(2,0); printformat("tasking install\n"); settextcolor(15,0);
    install_tasking();

    settextcolor(2,0); printformat("VFS & RAM Disk install\n"); settextcolor(15,0);
    ULONG ramdisk_start = 0x40081000, ramdisk_end = 0x40090000; // Im Heap Bereich
    if(placement_address < ramdisk_end) placement_address = ramdisk_end;
    printformat("placement_address: %x \n", placement_address);
    fs_root = install_initrd(ramdisk_start);
    printformat("fs_root->name: %s fs_root->ptr: %d \n", fs_root->name, fs_root->ptr);

    settextcolor(2,0); printformat("switch to user mode\n"); settextcolor(15,0);
    switch_to_user_mode();
    settextcolor(2,0); printformat("behind switch to user mode with ring 0 supervisor privilege!\n"); settextcolor(15,0);

    printformat("KQ: %x TAIL: %x HEAD: %x\n", pODA->KEYQUEUE, pODA->pTailKQ, pODA->pHeadKQ);
    printformat("SS: %x, ESP: %x, EBP: %x\n", fetchSS(),fetchESP(),fetchEBP());
    printformat("CS: %x, DS: %x\n",  fetchCS(),fetchDS());

    settextcolor(2,0);
    set_cursor(0,6);

    UCHAR c=0;
    while(TRUE)
    {
      if( k_checkKQ_and_print_char() )
      {
        ++c;
        if(c>5)
        {
          c=0;
          settextcolor(4,0);
          printformat("\nT: %x H: %x WRITE: %i Read: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write, pODA->KQ_count_read);
          printformat("*T: %c %i *H: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
          settextcolor(2,0);
        }
      }
    }

    return 0;
}

Zitat:

GDT, IDT, ISRS, IRQ, timer, keyboard install
paging install
frames: 01000000h NFRAMES: 524288
kernel_directory->physicalAddr: 01006000h
placement_address: 01013000h number of allocated frames: 4371
HEAP start: 40081000h end: 40100000h max: 4FFFF000h kernel: 0 read-only: 0
hole 40081000h hole-size: 520192
frames: 01000000h NFRAMES: 524288
kernel_directory->physicalAddr: 01006000h
placement_address: 01014020h number of allocated frames: 4371
tasking install
after moving stack, ESP: 0018FFD0h
After init first task (kernel task), placement_address: 01014020h
After k_mallocing kernel_stack), placement_address: 01014020h
VFS & RAM Disk install
placement_address: 40090000h
fs_root->name: initrd fs_root->ptr: 0
switch to user mode
After set_kernel_stack. tss_entry.esp0: 0000083Ch
Right before user mode
behind switch to user mode with ring 0 supervisor privilege!
KQ: 0000BDF4h TAIL: 0000BDF4h HEAD: 0000BDF4h
SS: 00000010h, ESP: 0018FFF0h, EBP: 00190000h
CS: 00000018h, DS: 00000020h

:live: :live:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 12:15:58 19.04.2009, insgesamt 4-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 12:22:42 19.04.2009   Titel:              Zitieren

Fragen:
- Welche Privilegstufen sollte man einrichten? Nur 0 und 3, oder auch 1 und 2?
--- Kernel (0) und User (3) ist klar, wozu sollte man den Rest nutzen?
- Wie würdet ihr die "sys calls" (call to the kernel) praktisch einrichten?
--- software interrupt (linux: 0x80), ich würde 0x7F bevorzugen wegen der unsigned char Begrenzung in unserem OS?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 13:10:30 19.04.2009, insgesamt 2-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 12:42:57 19.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Frage: Wie würdet ihr nun die Syscalls praktisch einrichten?

x86'er haben spezielle befehle dafür: http://www.ews.uiuc.edu/~cjiang/reference/vc311.htm
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 13:12:43 19.04.2009   Titel:              Zitieren

Danke für den Link! Was hältst Du von der Software-Interrupt-Methode (software interrupt bei Linux: 0x80), ich würde allerdings 0x7F bevorzugen wegen der aktuellen Begrenzung auf 0..127 in unserem OS?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 14:05:04 19.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Was hältst Du von der Software-Interrupt-Methode ...

geht im prinzip auch, aber sysenter ist schneller. diese software-interrupt methode funzt ausserdem sogar auf 368'ern. 'sysenter' gibt's ja erst ab pentium-ähnlichen und späteren intel- und AMD-prozessoren. aber ich bin nicht so der x86-freak, warten wir doch mal ab, was nobuo dazu zu erzählen hat.
btw: bei syscalls musste extrem drauf achten, dass du keine backdoors einbaust. das problemchen hatten z.b. die ersten versionen von win-nt 4, die man mit zufallsparametern in syscalls crashen, oder sehr einfach code in den kernel einschleusen konnte. daher auch der imageverlust von windoofs, an dem mickrigsoft bis heute zu knabbern hat.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 14:14:51 19.04.2009   Titel:              Zitieren

Na, klasse! Bereits die erste Sicherheitsdiskussion. Ist das z.B. dieses Thema:
Zitat:
One thing that is important to note is that the kernel, when executing interrupt handling code, requires a valid stack to work with. If it doesn't have one, the processor will double fault (and then eventually triple fault because the double fault handler needs a valid stack too!). This would obviously be a very easy way for a malicious user to bring down your system, so it is normal practice to, on mode change from ring 3 to ring 0, switch to a new stack designed solely for use by the kernel, and which is guaranteed to be valid.
Quelle: www.jamesmolloy.co.uk

Zitat:
'sysenter' gibt's ja erst ab pentium-ähnlichen und späteren intel- und AMD-prozessoren.
Eines meiner Ziele ist, dass PrettyOS ab 80386 lauffähig ist, denn die späteren CPU haben an der prinzipiellen inneren Technik (GDT, IDT, ...) fest gehalten. Daher auch die komplizierte Umschaltung von einem Gate auf das andere, die bei modernen Pentiums hoffentlich leichter geht. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 14:56:18 19.04.2009, insgesamt 2-mal bearbeitet
blitzmaster
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 45
Beitrag blitzmaster Mitglied 15:06:49 19.04.2009   Titel:              Zitieren

also ich würde euch empfehlen, das ganze über interrupts zu machen. da gibts dann später bei multitasking keine probleme, da bei einem interrupt autamtisch das i-flag in den eflags gelöscht wird, sodass der kernel nicht unterbrochen werden wird, bis er zumindest einen stack gewechselt hat bzw. bis ihr das halt wieder zulasst... Aber nachdem das ja ein Sprung in den Kernel ist, könnte es sein, dass dann zwei Tasks gleichzeitig springen und im Kernel dann Datenstrukturen zerstört werden, weil das nicht synchron geschieht.
Aber das ist nur meine bescheidene Meinung
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 15:32:58 19.04.2009   Titel:              Zitieren

Die Interrupt-Technik habe ich bereits vorbereitet (0x7F = 127).

Falls jemand den aktuellen Sourcecode mal anschauen / testen / weiter entwicklen möchte, hier eine hoffentlich stabile Zwischen-Version (ohne sys calls, also user mode auf Privileg 0 gesetzt. Einfach mal in gtd.c und task.c auf Privileg 3 umstellen, dann gibt es einen error. PM wirkt also! Didaktisch sehr schön.):
http://www.henkessoft.de/OS_Dev/Downloads/30_prettyOS.zip
testwise implemented: paging, heap, virtual file system & ram disk, multitasking, move of stack, switch to another gate (based on tutorial/code of James Molloy)
path forward: real user mode (ring 3) & sys calls, safety against malicious code

:arrow: Danke an alle, die mich bisher soweit getragen haben.
Jetzt habe ich soviel OS-Blut geleckt, dass ich keinesfalls aufhöre. :leak:
Diesem Assembler-Forum möchte ich für seine konstruktive und offene Haltung ein ganz großes Lob aussprechen. Das findet man sehr selten!

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 15:45:09 19.04.2009, insgesamt 2-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 15:34:28 19.04.2009   Titel:              Zitieren

blitzmaster schrieb:

also ich würde euch empfehlen, das ganze über interrupts zu machen. da gibts dann später bei multitasking keine probleme, da bei einem interrupt autamtisch das i-flag in den eflags gelöscht wird, sodass der kernel nicht unterbrochen werden wird...

interrupts global zu sperren (macht man das mit dem i-flag?) ist, wenn nicht unbedingt erforderlich, eigentlich keine gute idee, weil dann interrupt-anforderungen verloren gehen können, wenn die sperre zu häufig eingesetzt wird oder lange dauert. und ich weiss nicht, ob die pc-architektur 'nested' interrupts und interrupt-prioritäten kennt (ich glaub' die hardware unterstützt es nicht, aber es geht mit software-tricks).

blitzmaster schrieb:

Aber nachdem das ja ein Sprung in den Kernel ist, könnte es sein, dass dann zwei Tasks gleichzeitig springen und im Kernel dann Datenstrukturen zerstört werden, weil das nicht synchron geschieht.

in einem multitasking-os sollten systemfunktionen sowieso immer reentrant-fähig sein. dass mehrere task gleichzeitig im kernel rumschwirren, oder gar die selbe systemfunktion nutzen, ist keine seltenheit.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 15:51:01 19.04.2009   Titel:              Zitieren

Zitat:
in einem multitasking-os sollten systemfunktionen sowieso immer reentrant-fähig sein. dass mehrere task gleichzeitig im kernel rumschwirren, oder gar die selbe systemfunktion nutzen, ist keine seltenheit.
Klingt wirklich herausfordernd, erinnert mich an multithreading. Da lauern neben "malicious codes" bestimmt schon die "deadlocks". ;)

Zitat:
interrupt-prioritäten
Je kleiner die Zahl, je höher die Priorität, zumindest habe ich es so gelesen. Also Timer > Keyboard > ...

Hat eigentlich jemand einen Tipp, wie ich "Files" - ohne GRUB - möglichst einfach in diese RAM disk tranferieren kann, so dass man den VFS-Mechanismus mal vorführen könnte?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 15:54:15 19.04.2009, insgesamt 1-mal bearbeitet
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 17:05:18 19.04.2009   Titel:              Zitieren

+fricky schrieb:
blitzmaster schrieb:

also ich würde euch empfehlen, das ganze über interrupts zu machen. da gibts dann später bei multitasking keine probleme, da bei einem interrupt autamtisch das i-flag in den eflags gelöscht wird, sodass der kernel nicht unterbrochen werden wird...

interrupts global zu sperren (macht man das mit dem i-flag?) ist, wenn nicht unbedingt erforderlich, eigentlich keine gute idee, weil dann interrupt-anforderungen verloren gehen können, wenn die sperre zu häufig eingesetzt wird oder lange dauert. und ich weiss nicht, ob die pc-architektur 'nested' interrupts und interrupt-prioritäten kennt (ich glaub' die hardware unterstützt es nicht, aber es geht mit software-tricks).

Jo, das IF ignoriert praktisch die IRQ-Line der CPU (nicht aber NMIs, exceptions, usw.).
AFAIR: Selbst der PIC (programmable Interrupt Controller) in den ersten PCs kannte schon eine Prioritaetsbehandlung von IRQs. Das Ding wurde dann zunaechst in typischer x86-manier erweitert, indem man quasi den gleichen Controller nochmal hinten dran geklatscht hat (toll: jetzt mit 16 IRQs!!) und inzwischen gibt es den in die CPU integrierten APIC.
IAR geht also nichts verloren, wenn das IF geloescht wird ... es sei denn, das bleibt ueber Sekunden so (daher auch meine Ermahnung, schnelle IRQ-handler zu schreiben).
Dennoch hast du recht: IRQs sollte man nur ausschalten, wenn unbedingt noetig, was bei x86ern mit ihren ganzen atomaren spezial-Befehlen im Prinzip relativ selten vorkommen duerfte.

+fricky schrieb:

blitzmaster schrieb:

Aber nachdem das ja ein Sprung in den Kernel ist, könnte es sein, dass dann zwei Tasks gleichzeitig springen und im Kernel dann Datenstrukturen zerstört werden, weil das nicht synchron geschieht.

in einem multitasking-os sollten systemfunktionen sowieso immer reentrant-fähig sein. dass mehrere task gleichzeitig im kernel rumschwirren, oder gar die selbe systemfunktion nutzen, ist keine seltenheit.
:)

Richtig. Da kann man entweder alle moeglichen Teile des Kerns einzeln in kritische Sektionen packen, oder man tuetet den ganzen Kern einfach in eben eine solche. Zu Demonstrationszwecken im Rahmen eines Tutorials waere das IMHO uebersichtlicher. Dabei kann man dann auch problemlos IRQs zulassen.

Int loescht uebrigens nicht das IF. AFAIR sysenter genau so wenig.
Die Entscheidung gegen sysenter und fuer int befuerworte ich uebrigens (wie ich schon sagte) : Kein neuer Spezial-Befehl, Gebastel mit AMD vs. Intel, einfache Handhabung, abwaertskompatibel. KISS halt. :D

BTW ist die Benutzung eines eigenen Stacks fuer Kern-Aufrufe (auch IRQ- und Exception-Handler) wie gesagt dringend zu empfehlen. Praktisch fast wie ein TASK-Switch.

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
blitzmaster
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 45
Beitrag blitzmaster Mitglied 18:22:32 19.04.2009   Titel:              Zitieren

Nobuo T schrieb:
Int loescht uebrigens nicht das IF. AFAIR sysenter genau so wenig.
So weit ich weiß, wird das IF bei einem Sprung zu einem Interrupt Gate gelöscht.


Zuletzt bearbeitet von blitzmaster am 18:22:46 19.04.2009, insgesamt 1-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 19:54:06 19.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zitat:
in einem multitasking-os sollten systemfunktionen sowieso immer reentrant-fähig sein. dass mehrere task gleichzeitig im kernel rumschwirren, oder gar die selbe systemfunktion nutzen, ist keine seltenheit.
Klingt wirklich herausfordernd, erinnert mich an multithreading.

isses auch. multithreading und -tasking bedeutet, je nach kontext, mal was anderes, mal das selbe. windows-user verstehen unter multitasking, dass gleichzeitig mehrere prozesse möglich sind, von denen jeder mehrere threads (==parallel ausführbare einheiten) haben kann. in der RTOS-terminologie wird das, was unter win 'thread' heisst, oft 'task' oder 'prozess' genannt.

Nobuo T schrieb:

BTW ist die Benutzung eines eigenen Stacks fuer Kern-Aufrufe (auch IRQ- und Exception-Handler) wie gesagt dringend zu empfehlen. Praktisch fast wie ein TASK-Switch.

dann haste aber ein ziemlich schwergewichtiges interface zwischen kernel und userland, das syscalls relativ unperformant macht. eigentlich braucht man doch nur einen privilegwechsel beim sprung in den kernel und bei der rückkehr. natürlich musste noch checken, ob die parameter gültig sind, genug platz auf dem stack ist, pointer sinnvollen inhalt haben und ähnliche kleinigkeiten. einen kompletten, task-switch ähnlichen mechanismus, halte ich für übertrieben. aber vielleicht geht's mit den x86 software-int befehlen nur so (weshalb später 'sysenter' eingeführt wurde).
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:15:00 19.04.2009   Titel:              Zitieren

Die system calls laufen. Man kann also nun z.B. die Funktion puts(...) als syscall_puts(...) aufrufen. Ich benötige mal eure Hilfe, da ich momentan etwas nicht verstehe und nicht sicher bin, ob das genau so richtig ist oder ob im OS etwas nicht stimmt (was mir wahrscheinlicher erscheint).

Ich habe hier zwei Varianten:
http://www.henkessoft.de/OS_Dev/Downloads/31&32.zip
31) nach dem switch_to_user_mode() hat der user privileg 0
32) nach dem switch_to_user_mode() hat der user privileg 3

Im ersten Fall:
Zitat:

switch to user mode
After set_kernel_stack. tss_entry.esp0: 0000083Ch
Right before user mode

>>>IRQ 127<<<Hello, user world!
behind switch to user mode with ring 0 supervisor privilege!
SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000018h, DS: 00000020h

Das "Hello, user world!" wird mittels syscall_puts(...) ausgegeben. Daher weiß ich, dass die system calls nun funktionieren. Baut man auf diese Weise ein API auf? (habe das bisher noch nie gemacht :D )
C/C++ Code:
switch_to_user_mode();
    syscall_puts("Hello, user world!\n");
C/C++ Code:
switch_to_user_mode();
syscall_puts("Hello, user world!\n");
C/C++ Code:
switch_to_user_mode();
    syscall_puts("Hello, user world!\n");


Im zweiten Fall:
Zitat:

switch to user mode
After set_kernel_stack. tss_entry.esp0: 0000083Ch
Right before user mode
Page Fault
>>>Exception. System Halted! <<<

Ich bin etwas irritiert darüber, dass im echten User Mode der Syscall (ring 3 ruft ring 0) vor dem Page Fault (wegen unerlaubtem Zugriff auf Kernel code) nicht durchgegangen ist. Vielleicht liegt es daran, dass auf dem Weg zur Ausführung des Syscalls (... -> IRQ127 -> syscall_handler -> ...) bereits ein "Page Fault" erfolgte.

Sorry, dass der Code im IRQ-Bereich momentan etwas "gestöpselt" ist. Das muss ich noch aufräumen, wollte jetzt nur erst mal das Tasking und die Syscalls zum Laufen bekommen, denn die Schnittstelle zwischen Kernel und Anwendungen im User Mode sind ja genau das Interessante. :)

Wenn ich das so nebeneinander sehe, wundere ich mich gerade über die Leerzeile zwischen Right before user mode und >>>IRQ 127<<<Hello, user world!.

Die nächste Aufgabe ist jetzt, den vorhandenen Code vernünftig zu überarbeiten, damit er eine wirklich brauchbare Basis für ein OS ergibt, möchte nicht völlig chaotisch weiter hetzen, weil dann die Didaktik und vor allem das Tutorial auf der Strecke bleibt. Schlechten Code erklärt und zeigt man nicht gerne, sondern ist froh, wenn er läuft. Damit Experimentieren ist zumeist auch nicht gerade lustig. Vielleicht, wenn man die Module noch ordentlich sortiert und hier und da entkoppelt, kann das noch etwas Sinnvolles werden?

Vielleicht kann sich ein Assembler-Spezialist die IRQ/ISR/exception-Story mal anschauen (z.Z. eine wilde Mischung aus ASM und C). Da blicke ich kaum noch selbst durch. Den int127 (128 ging nicht wegen Überlauf, muss ja auch nicht sein, wäre nur wegen Linux 0x80) habe ich schon an den fault_handler, der eigentlich nur für exceptions gedacht war, "provisorisch angeschraubt", ging irgendwie nicht anders. :rolleyes: Aber so ist wahrscheinlich auch Windows und Linux entstanden. :D

Inzwischen habe ich gehörig Respekt vor der OS-Entwicklung. :live:
... und das Schwierigste liegt ja eher noch vor mir. :cool:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 21:45:35 19.04.2009, insgesamt 4-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 22:00:13 19.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Den int127 (128 ging nicht wegen Überlauf, muss ja auch nicht sein, wäre nur wegen Linux 0x80) habe ich schon an den fault_handler, der eigentlich nur für exceptions gedacht war, "provisorisch angeschraubt", ging irgendwie nicht anders.

page faults und fehler wie access violations sind sich sehr ähnlich. kann es sein, dass beim x86 beides sowieso über den selben handler gehen muss? wenn ja, musste irgendwie unterscheiden, was was ist.

Erhard Henkes schrieb:

Aber so ist wahrscheinlich auch Windows und Linux entstanden.

naja, was win angeht, so hat mickrigweich dereinst die halbe crew von DEC abgeworben, die VMS entwickelt hat. die ur-version von windoof-nt wurde ursprünglich für irgend so'nen RISC prozessor gebaut. ich kann mir gut vorstellen, dass die m$-programmierer, bei der portierung nach x86, auch mal den einen oder anderen schrei- und weinkrampf hatten.

Erhard Henkes schrieb:

Inzwischen habe ich gehörig Respekt vor der OS-Entwicklung.

jetzt erst? hättest mal weniger copy-and-paste von dem engländer machen sollen.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:29:19 19.04.2009   Titel:              Zitieren

Zitat:
hättest mal weniger copy-and-paste von dem engländer machen sollen.
James hat mir schriftlich freie Hand gelassen. Ich bin weder Student noch in einem Wettrennen, sondern bearbeite dieses Thema einzig und allein, weil es mich interessiert und weil ich anderen die Materie - soweit ich das schaffe - verständlich machen will. Noch steht der Code von James Molloy, der auf älterem Code von Bran's Tutorial aufbaut, nicht in meinem Tutorial. Ich lasse mir Zeit, bis ich weiß, was wirklich wichtig ist. Die Diskussion hier und teilweise auch in anderen Foren hilft mir dabei.

Gut finde ich bisher,
- dass nicht der GRUB Loader verwendet wird
- den sauberen Übergang von Assembler zum C-Kernel (thanks to Nobuo T)
- die Bitset-Verwaltung beim Paging (effizient)
- das VFS analog Linux (leider noch nicht richtig in Aktion)

Schlecht finde ich
- das Interrupt-Gerödel (richtig zusammen geschustert, da verwende ich sogar noch den alten Aufbau, weil James das auch nicht wirklich auf die Reihe bekam, ist jedoch im Wesentlichen Fleißarbeit, das zu ordnen)
- die AT&T Syntax innerhalb C (ziemlich unverständlich, das gehört wirklich alles als Intel Syntax ausgelagert, da hat abc.w Recht)

Unsicher bin ich mir bei
- der Heap-Erzeugung/-Verwaltung (schwieriges aber langweiliges Thema, Hauptsache läuft erstmal)
- der Tasking-Steuerung

Das wird aber alles noch richtig gut, da bin ich ganz sicher.

Ich musste für mich schnell Zusammenhänge praktisch durchspielen, daher der Rückgriff auf Vorhandenes, um zu sehen, was wirklich voneinander abhängt. Übrigens geht es anderen auch so. Selbst, wenn ich den Sourcecode alleine erfinde, bringt das niemand weiter. Für andere ist der Code immer "fremd". Was zählt, sind gute Erklärungen. Da sieht es in James Molloy's Tutorial allerdings düster aus.

Was mir bisher noch weitgehend fehlt, ist die Darstellung der Arbeitsweise des OS. Ich möchte kein "unsichtbares" OS, sondern einen "offenen Wecker". Da habe ich bisher überhaupt noch keinen Ansatz gefunden, das ist bei vielen "Educational OS" lauter in sich geschlossenes unverständliches "Gefrickel".

Ich habe in einigen Foren sogar das Gefühl, das sich die OSDEVer gegenseitig nicht wirklich verstehen. :D

Es gibt übrigens noch einige offene Fragen, auf die bisher niemand eingegangen ist. :confused:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:06:25 20.04.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:06:07 20.04.2009   Titel:              Zitieren

Zitat:
page faults und fehler wie access violations sind sich sehr ähnlich. kann es sein, dass beim x86 beides sowieso über den selben handler gehen muss? wenn ja, musste irgendwie unterscheiden, was was ist.
Diese Fehler werden unterschieden:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
/* Message string corresponding to the exception number 0-31: exception_messages[interrupt_number] */
UCHAR* exception_messages[] =
{
    "Division By Zero",        "Debug",                         "Non Maskable Interrupt",    "Breakpoint",
    "Into Detected Overflow",  "Out of Bounds",                 "Invalid Opcode",            "No Coprocessor",
    "Double Fault",            "Coprocessor Segment Overrun",   "Bad TSS",                   "Segment Not Present",
    "Stack Fault",             "General Protection Fault",      "Page Fault",                "Unknown Interrupt",
    "Coprocessor Fault",       "Alignment Check",               "Machine Check",             "Reserved",
    "Reserved",                "Reserved",                      "Reserved",                  "Reserved",
    "Reserved",                "Reserved",                      "Reserved",                  "Reserved",
    "Reserved",                "Reserved",                      "Reserved",                  "Reserved"
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
/* Message string corresponding to the exception number 0-31: exception_messages[interrupt_number] */
UCHAR* exception_messages[] =
{
"Division By Zero", "Debug", "Non Maskable Interrupt", "Breakpoint",
"Into Detected Overflow", "Out of Bounds", "Invalid Opcode", "No Coprocessor",
"Double Fault", "Coprocessor Segment Overrun", "Bad TSS", "Segment Not Present",
"Stack Fault", "General Protection Fault", "Page Fault", "Unknown Interrupt",
"Coprocessor Fault", "Alignment Check", "Machine Check", "Reserved",
"Reserved", "Reserved", "Reserved", "Reserved",
"Reserved", "Reserved", "Reserved", "Reserved",
"Reserved", "Reserved", "Reserved", "Reserved"
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
/* Message string corresponding to the exception number 0-31: exception_messages[interrupt_number] */
UCHAR* exception_messages[] =
{
    "Division By Zero",        "Debug",                         "Non Maskable Interrupt",    "Breakpoint",
    "Into Detected Overflow",  "Out of Bounds",                 "Invalid Opcode",            "No Coprocessor",
    "Double Fault",            "Coprocessor Segment Overrun",   "Bad TSS",                   "Segment Not Present",
    "Stack Fault",             "General Protection Fault",      "Page Fault",                "Unknown Interrupt",
    "Coprocessor Fault",       "Alignment Check",               "Machine Check",             "Reserved",
    "Reserved",                "Reserved",                      "Reserved",                  "Reserved",
    "Reserved",                "Reserved",                      "Reserved",                  "Reserved",
    "Reserved",                "Reserved",                      "Reserved",                  "Reserved"
};

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:01:45 21.04.2009   Titel:              Zitieren

So sieht momentan ein typischer Bildschirmausdruck zur Überprüfung aus:
Zitat:

GDT, IDT, ISRS, IRQ, timer, keyboard install
paging install
frames: 01000000h NFRAMES: 524288
kernel_directory->physicalAddr: 01006000h
placement_address: 01013000h number of allocated frames: 4371
HEAP start: 40081000h end: 40100000h max: 4FFFF000h kernel: 0 read-only: 0
hole 40081000h hole-size: 520192
frames: 01000000h NFRAMES: 524288
kernel_directory->physicalAddr: 01006000h
placement_address: 01014020h number of allocated frames: 4371
tasking install
after moving stack, ESP: 0018FFD0h
After init first task (kernel task), placement_address: 01014020h
After k_mallocing kernel_stack), placement_address: 01014020h
VFS & RAM Disk install
placement_address: 40090000h
fs_root->name: initrd fs_root->ptr: 0
switch to user mode
After set_kernel_stack. tss_entry.esp0: 0000083Ch
Right before user mode
>>>IRQ 127<<<
Hello, user world!
behind switch to user mode with ring 0 supervisor privilege!
SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000018h, DS: 00000020h


Bezüglich Visualisierung des Pagings habe ich mal Folgendes probiert:
Um das Bitset mit seinen Nullen und Einsen und den Bezug zu den Speicheradressen darzustellen, habe ich die unten stehende Funktion entworfen. Sie bleibt 'sec' Sekunden stehen, wenn eine oder mehrere Einsen (allokierte Pages) auftauchen, bei Nullen flitzt sie durch. Damit kann man recht praktisch den Speicher scannen und sich in Bochs mit copy von der jeweils interessanten Region screenshots machen:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void analyze_frames_bitset(ULONG sec)
{
    ULONG index, offset, counter1=0, counter2=0;
    for(index=0; index<(NFRAMES/32); ++index)
    {
        settextcolor(15,0);
        printformat("\n%x  ",index*32*0x1000);
        ++counter1;
        for(offset=0; offset<32; ++offset)
        {
            if( !(frames[index] & 1<<offset) )
            {
                settextcolor(4,0);
                putch('0');
            }
            else
            {
                settextcolor(2,0);
                putch('1');
                ++counter2;
            }
        }
        if(counter1==24)
        {
            counter1=0;
            if(counter2)
                sleepSeconds(sec);
            counter2=0;
        }
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void analyze_frames_bitset(ULONG sec)
{
ULONG index, offset, counter1=0, counter2=0;
for(index=0; index<(NFRAMES/32); ++index)
{
settextcolor(15,0);
printformat("\n%x ",index*32*0x1000);
++counter1;
for(offset=0; offset<32; ++offset)
{
if( !(frames[index] & 1<<offset) )
{
settextcolor(4,0);
putch('0');
}
else
{
settextcolor(2,0);
putch('1');
++counter2;
}
}
if(counter1==24)
{
counter1=0;
if(counter2)
sleepSeconds(sec);
counter2=0;
}
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void analyze_frames_bitset(ULONG sec)
{
    ULONG index, offset, counter1=0, counter2=0;
    for(index=0; index<(NFRAMES/32); ++index)
    {
        settextcolor(15,0);
        printformat("\n%x  ",index*32*0x1000);
        ++counter1;
        for(offset=0; offset<32; ++offset)
        {
            if( !(frames[index] & 1<<offset) )
            {
                settextcolor(4,0);
                putch('0');
            }
            else
            {
                settextcolor(2,0);
                putch('1');
                ++counter2;
            }
        }
        if(counter1==24)
        {
            counter1=0;
            if(counter2)
                sleepSeconds(sec);
            counter2=0;
        }
    }
}

Diese Funktion geht sämtliche Pages durch und stellt jeweils 32 in einer Zeile je nach Allokation als Null oder Eins dar. Vorne steht die erste Hex-Speicheradresse der ersten Page (also jeweils 4KB * 32 = 128KB in einer Reihe).

Bsp.: Erstes Ende der kompakten Allokierung oberhalb 18 MB (1200000h) :
Code:
011C0000h  11111111111111111111111111111111
011E0000h  11111111111111111111111111111111
01200000h  11111111111111111110000000000000
01220000h  00000000000000000000000000000000
Code:
011C0000h 11111111111111111111111111111111
011E0000h 11111111111111111111111111111111
01200000h 11111111111111111110000000000000
01220000h 00000000000000000000000000000000
Code:
011C0000h  11111111111111111111111111111111
011E0000h  11111111111111111111111111111111
01200000h  11111111111111111110000000000000
01220000h  00000000000000000000000000000000

Screenshot: http://www.henkessoft.de/OS_Dev/Bilder/Paging_Scan.PNG

Bsp.: #define KHEAP_START 0x40000000 // 1GB
#define KHEAP_INITIAL_SIZE 0x100000
#define KHEAP_MAX 0x4FFFF000
Dort befindet sich auch die RAM Disk:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
3FFC0000h  00000000000000000000000000000000
3FFE0000h  00000000000000000000000000000000
40000000h  10100110000011001000100010000000
40020000h  10100000000000101000100010000000
40040000h  10100000000010101000100010000000
40060000h  10100000000001101000100010000000
40080000h  10100000000011101000100010000000
400A0000h  10100000000000011000100010000000
400C0000h  10100000000010011000100010000000
400E0000h  10100000000001011000100010000000
40100000h  10100000000011011000100010000000
40120000h  10100000000000111000100010000000
40140000h  10100000000010111000100010000000
40160000h  10100000000001111000100010000000
40180000h  10100000000011111000100010000000
401A0000h  10100000000000000100100010000000
401C0000h  10100000000010000100100010000000
401E0000h  10100000000001000100100010000000
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
3FFC0000h 00000000000000000000000000000000
3FFE0000h 00000000000000000000000000000000
40000000h 10100110000011001000100010000000
40020000h 10100000000000101000100010000000
40040000h 10100000000010101000100010000000
40060000h 10100000000001101000100010000000
40080000h 10100000000011101000100010000000
400A0000h 10100000000000011000100010000000
400C0000h 10100000000010011000100010000000
400E0000h 10100000000001011000100010000000
40100000h 10100000000011011000100010000000
40120000h 10100000000000111000100010000000
40140000h 10100000000010111000100010000000
40160000h 10100000000001111000100010000000
40180000h 10100000000011111000100010000000
401A0000h 10100000000000000100100010000000
401C0000h 10100000000010000100100010000000
401E0000h 10100000000001000100100010000000
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
3FFC0000h  00000000000000000000000000000000
3FFE0000h  00000000000000000000000000000000
40000000h  10100110000011001000100010000000
40020000h  10100000000000101000100010000000
40040000h  10100000000010101000100010000000
40060000h  10100000000001101000100010000000
40080000h  10100000000011101000100010000000
400A0000h  10100000000000011000100010000000
400C0000h  10100000000010011000100010000000
400E0000h  10100000000001011000100010000000
40100000h  10100000000011011000100010000000
40120000h  10100000000000111000100010000000
40140000h  10100000000010111000100010000000
40160000h  10100000000001111000100010000000
40180000h  10100000000011111000100010000000
401A0000h  10100000000000000100100010000000
401C0000h  10100000000010000100100010000000
401E0000h  10100000000001000100100010000000
usw.

Zum Verständnis die Bitset-Funktionen aus paging.c:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
ULONG*  frames; // pointer to the bitset (functions: set/clear/test)
ULONG  NFRAMES = PHYSICAL_MEMORY / PAGESIZE;

/************* bitset variables and functions **************/
ULONG ind, offs;

static void get_Index_and_Offset(ULONG frame_addr)
{
    ULONG frame    = frame_addr/PAGESIZE;
    ind    = frame/32;
    offs   = frame%32;
}

static void set_frame(ULONG frame_addr)
{
    get_Index_and_Offset(frame_addr);
    frames[ind] |= (1<<offs);
}

static void clear_frame(ULONG frame_addr)
{
    get_Index_and_Offset(frame_addr);
    frames[ind] &= ~(1<<offs);
}

static ULONG test_frame(ULONG frame_addr)
{
    get_Index_and_Offset(frame_addr);
    return( frames[ind] & (1<<offs) );
}
/***********************************************************/
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
ULONG* frames; // pointer to the bitset (functions: set/clear/test)
ULONG NFRAMES = PHYSICAL_MEMORY / PAGESIZE;

/************* bitset variables and functions **************/
ULONG ind, offs;

static void get_Index_and_Offset(ULONG frame_addr)
{
ULONG frame = frame_addr/PAGESIZE;
ind = frame/32;
offs = frame%32;
}

static void set_frame(ULONG frame_addr)
{
get_Index_and_Offset(frame_addr);
frames[ind] |= (1<<offs);
}

static void clear_frame(ULONG frame_addr)
{
get_Index_and_Offset(frame_addr);
frames[ind] &= ~(1<<offs);
}

static ULONG test_frame(ULONG frame_addr)
{
get_Index_and_Offset(frame_addr);
return( frames[ind] & (1<<offs) );
}
/***********************************************************/
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
ULONG*  frames; // pointer to the bitset (functions: set/clear/test)
ULONG  NFRAMES = PHYSICAL_MEMORY / PAGESIZE;

/************* bitset variables and functions **************/
ULONG ind, offs;

static void get_Index_and_Offset(ULONG frame_addr)
{
    ULONG frame    = frame_addr/PAGESIZE;
    ind    = frame/32;
    offs   = frame%32;
}

static void set_frame(ULONG frame_addr)
{
    get_Index_and_Offset(frame_addr);
    frames[ind] |= (1<<offs);
}

static void clear_frame(ULONG frame_addr)
{
    get_Index_and_Offset(frame_addr);
    frames[ind] &= ~(1<<offs);
}

static ULONG test_frame(ULONG frame_addr)
{
    get_Index_and_Offset(frame_addr);
    return( frames[ind] & (1<<offs) );
}
/***********************************************************/


Wer damit mal spielen möchte:
http://www.henkessoft.de/OS_Dev/Downloads/33.zip :)

Nun "sieht" man endlich, was man macht. ;)
Solche Dinge sind mir wie bereits ausgeführt wichtig.

EDIT: Ebenfalls hilfreich ist eine Analyse der physikalischen Adressen der Startadressen der Pages:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
ULONG show_physical_address(ULONG virtual_address)
{
    page_t* page = get_page(virtual_address, 0, kernel_directory);
    return( (page->frame_addr)*PAGESIZE + (virtual_address&0xFFF) );
}

void analyze_physical_addresses()
{
   int i,j,k, k_old;
    for(i=0;i<(PHYSICAL_MEMORY/0x18000+1);++i){
        for(j=i*0x18000; j<i*0x18000+0x18000; j+=0x1000){
            if(show_physical_address(j)==0){
                settextcolor(4,0); k_old=k; k=1;
            }
            else{
                if(show_physical_address(j)-j){
                    settextcolor(3,0); k_old=k; k=2;
                }
                else{
                    settextcolor(2,0); k_old=k; k=3;
                }
            }
            if(k!=k_old)
                printformat("%x %x\n", j, show_physical_address(j));
        }
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
ULONG show_physical_address(ULONG virtual_address)
{
page_t* page = get_page(virtual_address, 0, kernel_directory);
return( (page->frame_addr)*PAGESIZE + (virtual_address&0xFFF) );
}

void analyze_physical_addresses()
{
int i,j,k, k_old;
for(i=0;i<(PHYSICAL_MEMORY/0x18000+1);++i){
for(j=i*0x18000; j<i*0x18000+0x18000; j+=0x1000){
if(show_physical_address(j)==0){
settextcolor(4,0); k_old=k; k=1;
}
else{
if(show_physical_address(j)-j){
settextcolor(3,0); k_old=k; k=2;
}
else{
settextcolor(2,0); k_old=k; k=3;
}
}
if(k!=k_old)
printformat("%x %x\n", j, show_physical_address(j));
}
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
ULONG show_physical_address(ULONG virtual_address)
{
    page_t* page = get_page(virtual_address, 0, kernel_directory);
    return( (page->frame_addr)*PAGESIZE + (virtual_address&0xFFF) );
}

void analyze_physical_addresses()
{
   int i,j,k, k_old;
    for(i=0;i<(PHYSICAL_MEMORY/0x18000+1);++i){
        for(j=i*0x18000; j<i*0x18000+0x18000; j+=0x1000){
            if(show_physical_address(j)==0){
                settextcolor(4,0); k_old=k; k=1;
            }
            else{
                if(show_physical_address(j)-j){
                    settextcolor(3,0); k_old=k; k=2;
                }
                else{
                    settextcolor(2,0); k_old=k; k=3;
                }
            }
            if(k!=k_old)
                printformat("%x %x\n", j, show_physical_address(j));
        }
    }
}


Zitat:

00000000h 00000000h
00001000h 00001000h
01113000h 00000000h
01400000h 12389000h
40100000h 00000000h
40400000h 12389000h

12389... ist eine "Magic Number" (#define HEAP_MAGIC 0x123890AB in kheap.h)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 04:51:38 22.04.2009, insgesamt 8-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:46:51 22.04.2009   Titel:              Zitieren

Um den Page Fault näher zu beschreiben, wurde jetzt folgende Auswertung eingebaut:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if (r->int_no == 14) //Page Fault
        {
            ULONG faulting_address;
            asm volatile("mov %%cr2, %0" : "=r" (faulting_address)); // faulting address => CR2 register

            // The error code gives us details of what happened.

            int present   = !(r->err_code & 0x1); // Page not present
            int rw        =   r->err_code & 0x2;  // Write operation?
            int us        =   r->err_code & 0x4;  // Processor was in user-mode?
            int reserved  =   r->err_code & 0x8;  // Overwritten CPU-reserved bits of page entry?
            int id        =   r->err_code & 0x10; // Caused by an instruction fetch?

            // Output an error message.

                          printformat("Page Fault (");
            if (present)  printformat("page not present");
            if (rw)       printformat("read-only - write operation");
            if (us)       printformat("user-mode");
            if (reserved) printformat("overwritten CPU-reserved bits of page entry");
            if (id)       printformat("caused by an instruction fetch");
                          printformat(") at %x - EIP: %x\n", faulting_address, r->eip);
        }
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if (r->int_no == 14) //Page Fault
{
ULONG faulting_address;
asm volatile("mov %%cr2, %0" : "=r" (faulting_address)); // faulting address => CR2 register

// The error code gives us details of what happened.

int present = !(r->err_code & 0x1); // Page not present
int rw = r->err_code & 0x2; // Write operation?
int us = r->err_code & 0x4; // Processor was in user-mode?
int reserved = r->err_code & 0x8; // Overwritten CPU-reserved bits of page entry?
int id = r->err_code & 0x10; // Caused by an instruction fetch?

// Output an error message.

printformat("Page Fault (");
if (present) printformat("page not present");
if (rw) printformat("read-only - write operation");
if (us) printformat("user-mode");
if (reserved) printformat("overwritten CPU-reserved bits of page entry");
if (id) printformat("caused by an instruction fetch");
printformat(") at %x - EIP: %x\n", faulting_address, r->eip);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if (r->int_no == 14) //Page Fault
        {
            ULONG faulting_address;
            asm volatile("mov %%cr2, %0" : "=r" (faulting_address)); // faulting address => CR2 register

            // The error code gives us details of what happened.

            int present   = !(r->err_code & 0x1); // Page not present
            int rw        =   r->err_code & 0x2;  // Write operation?
            int us        =   r->err_code & 0x4;  // Processor was in user-mode?
            int reserved  =   r->err_code & 0x8;  // Overwritten CPU-reserved bits of page entry?
            int id        =   r->err_code & 0x10; // Caused by an instruction fetch?

            // Output an error message.

                          printformat("Page Fault (");
            if (present)  printformat("page not present");
            if (rw)       printformat("read-only - write operation");
            if (us)       printformat("user-mode");
            if (reserved) printformat("overwritten CPU-reserved bits of page entry");
            if (id)       printformat("caused by an instruction fetch");
                          printformat(") at %x - EIP: %x\n", faulting_address, r->eip);
        }


Test mit Page Fault: http://www.henkessoft.de/OS_Dev/Downloads/34.zip

Der Page Fault wurde provoziert durch Streichen des Extra-Speichers oberhalb der placement_address:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
    // Allocate a little bit extra so the kernel heap can be initialised properly.
    // map (phys addr <---> virt addr) from 0x0 to the end of used memory

    ULONG counter=0;
    i=0;
    while( i < placement_address /*+ 0x100000*/ ) //important to add more!
    {
        alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
        i += PAGESIZE;
        ++counter;
    }
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
// Allocate a little bit extra so the kernel heap can be initialised properly.
// map (phys addr <---> virt addr) from 0x0 to the end of used memory

ULONG counter=0;
i=0;
while( i < placement_address /*+ 0x100000*/ ) //important to add more!
{
alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
i += PAGESIZE;
++counter;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
    // Allocate a little bit extra so the kernel heap can be initialised properly.
    // map (phys addr <---> virt addr) from 0x0 to the end of used memory

    ULONG counter=0;
    i=0;
    while( i < placement_address /*+ 0x100000*/ ) //important to add more!
    {
        alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
        i += PAGESIZE;
        ++counter;
    }

Dadurch kann man heraus finden, wieviel Speicher allokiert werden muss, um den Kernel Heap zu initialisieren. Endlich mal eine Aufgabe für die Leser. :D

Antwort: Bei 0x0 0der 0x1000 erfolgt ein Page Fault. Die Info lautet:
Zitat:
Page Fault (page not present) at 01014004h - EIP: 0000AD36h

Über die Info 01014000h 00000000h weiß man, dass nur bis 01013000h frames allokiert wurden. Daher muss man mindestens 0x1001 addieren, welches dann auf 0x2000 "aligned" wird. Dann klappt das.

So langsam bekomme ich das Thema Paging didaktisch in den Griff. Jetzt fehlt eigentlich nur noch die Darstellung des nicht-linearen Mappings.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:01:32 22.04.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:46:15 24.04.2009   Titel:              Zitieren

Für das Laden von vorgefertigten File-Daten in den Speicher für die Ram Disk des VFS hat mir jemand einen möglichen Weg gewiesen, nämlich via NASM-Anweisung incbin und Linken mit ld. Diesen Befehl kannte ich bisher noch nicht.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:54:04 24.04.2009   Titel:              Zitieren

Hier ein prinzipielles Beispiel mit Erzeugung mehrerer Tasks und Taskswitch:
http://www.henkessoft.de/OS_Dev/Downloads/35.zip
Zitat:
After set_kernel_stack ==> tss_entry.esp0: 40101800h
>>> IRQ 127 <<<
Hello, user world!

create a new process in a new address space
fork() returned: 00000002h and getpid() returned: 00000001h

create a new process in a new address space
fork() returned: 00000003h and getpid() returned: 00000001h

create a new process in a new address space
fork() returned: 00000004h and getpid() returned: 00000001h

getpid() 00000002h
getpid() 00000003h
getpid() 00000004h
getpid() 00000001h
getpid() 00000002h

C/C++ Code:
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
    int retValFork1 = fork(); //create a new process in a new address space which is a clone of this
    int retValGetPid1 = getpid();
    printformat("fork() returned: %x and getpid() returned: %x\n", retValFork1, retValGetPid1);
//...
    task_switch();
    printformat("getpid() %x\n", getpid());
    sleepSeconds(3);
    task_switch();
//...
C/C++ Code:
1
2
3
4
5
6
7
8
9
int retValFork1 = fork(); //create a new process in a new address space which is a clone of this
int retValGetPid1 = getpid();
printformat("fork() returned: %x and getpid() returned: %x\n", retValFork1, retValGetPid1);
//...
task_switch();
printformat("getpid() %x\n", getpid());
sleepSeconds(3);
task_switch();
//...
C/C++ Code:
1
2
3
4
5
6
7
8
9
    int retValFork1 = fork(); //create a new process in a new address space which is a clone of this
    int retValGetPid1 = getpid();
    printformat("fork() returned: %x and getpid() returned: %x\n", retValFork1, retValGetPid1);
//...
    task_switch();
    printformat("getpid() %x\n", getpid());
    sleepSeconds(3);
    task_switch();
//...

Den Scheduler kann man dann über den Timer aufrufen.

Mit Task Switches kann man schon auf einfachste Weise recht nette Sachen machen, hier ein Beispiel mit Farbwechsel (Farbe = Process ID) beim Tippen:
http://www.henkessoft.de/OS_Dev/Downloads/35a.zip (Programm)
http://www.henkessoft.de/OS_Dev/Downloads/task_switch_test.png (Test in Bochs)

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    UCHAR c=0;
    while(TRUE) {
      if( k_checkKQ_and_print_char() ) {
        ++c;
        if(c>5) {
          c=0;
          settextcolor(4,0);
          printformat("\nT: %x H: %x WRITE: %i Read: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write, pODA->KQ_count_read);
          printformat("*T: %c %i *H: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
          settextcolor(2,0);
          task_switch(); settextcolor(getpid(),0);
        }
      }
    }
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
UCHAR c=0;
while(TRUE) {
if( k_checkKQ_and_print_char() ) {
++c;
if(c>5) {
c=0;
settextcolor(4,0);
printformat("\nT: %x H: %x WRITE: %i Read: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write, pODA->KQ_count_read);
printformat("*T: %c %i *H: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
settextcolor(2,0);
task_switch(); settextcolor(getpid(),0);
}
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    UCHAR c=0;
    while(TRUE) {
      if( k_checkKQ_and_print_char() ) {
        ++c;
        if(c>5) {
          c=0;
          settextcolor(4,0);
          printformat("\nT: %x H: %x WRITE: %i Read: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write, pODA->KQ_count_read);
          printformat("*T: %c %i *H: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
          settextcolor(2,0);
          task_switch(); settextcolor(getpid(),0);
        }
      }
    }


Interessant ist, wenn man die Zeile task_switch(); settextcolor(getpid(),0); an eine andere Stelle in der while-Schleife setzt, dann gibt es einen eindrucksvollen "General protection fault":
http://en.wikipedia.org/wiki/General_protection_fault#Switching
Zitat:

Faults can occur in the task state segment (TSS) structure when:
* switching to a busy task during a call or jump instruction
* switching to an available task during an interrupt return (IRET) instruction
* using a segment selector on a switch pointing to a TSS descriptor in the LDT


Nun muss ich mich noch mit dem Fileformat, dem Transfer in die RAM Disk und dem Zugriff im Programm via Virtual File System beschäftigen. Sobald das alles klappt und die Didaktik passt, werde ich stepwise am Tutorial weiter schreiben (verflixt viel Material und Background) und ein Basis Modell für die Weiterentwicklung von PrettyOS stabilisieren.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:32:06 25.04.2009, insgesamt 4-mal bearbeitet
volkard
Moderator

Benutzerprofil
Anmeldungsdatum: 06.04.2000
Beiträge: 24349
Beitrag volkard Moderator 00:44:21 25.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Nun muss ich mich noch mit dem Fileformat, dem Transfer in die RAM Disk und dem Zugriff im Programm via Virtual File System beschäftigen. Sobald das alles klappt und die Didaktik passt, werde ich stepwise am Tutorial weiter schreiben (verflixt viel Material und Background) und ein Basis Modell für die Weiterentwicklung von PrettyOS stabilisieren.

nun wird es auch an der zeit sein, dir grundsätzliche überlegungen zu machen, ob du dabeibleiben oder abweichen solltest.
nur ein kleines beispiel: ich bekomme als spielstandslader oder compilerbauer vom bs (win oder linux hier echt gleich) per filemapping daten hereingeschubst. Shade nannnte es dieser datenhaltung diesbezüglich afair NonCopyStrings, ich splitte bei zum beispiel immer bei \n und habe "zeilen", die aus struct{char *begin,*end} bestehen. das bs gibt mir einen bei read() z.B. 8K großen sektor un ich gebe ihn zurück, wenn ich ihn nicht mehr brauche. natürlich kann ich als old-style-lib ein kopierendes read() im userspace anbieten. vielleicht wäre ein no-copy-read verflixt viel schneller, wenn die anwendung das neue paradigma verwendet. in dieser richtung isses nicht nervig. andersrum schon: ich habe viele strings, ich habe ausschließlich stings mit begin/end in meiner anwendung (naja, c++ halt) und muß bei jedem syscall erstmal speicher für nullterminierten string anlegen, würg.
vielleicht wäre das an sich gar kein problem, wenn man strings von vorn herein mit begin/end auch im kernel schon angedacht hätte.
vielleicht wäre das ganze startup/shuutdown-geschmuse gar nicht notwendig, wenn ein prozess==programm leben würde, sobald es installiert ist und runterfahren/hochfahren nur betriebssystem-kacke wäre, die die anwendungen gar nicht sehen.
nur mal so als meinen kleinen einwurf. es könnte möglich sein, daß anscheinend voll verrückte konzepte aus versehen zugleich dir voll arbeit sparen, das BS schneller machen und für den anwendungsprogrammierer auch noch netter sind.

hihi, ich möchte nicht in deinen schuhen stecken.

_________________
http://www.venganza.info/
plonk fürs Forum v1.02
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 01:14:03 25.04.2009   Titel:              Zitieren

volkard schrieb:

nur ein kleines beispiel: ich bekomme als spielstandslader oder compilerbauer vom bs (win oder linux hier echt gleich) per filemapping daten hereingeschubst. Shade nannnte es dieser datenhaltung diesbezüglich afair NonCopyStrings, ich splitte bei zum beispiel immer bei \n und habe "zeilen", die aus struct{char *begin,*end} bestehen. das bs gibt mir einen bei read() z.B. 8K großen sektor un ich gebe ihn zurück, wenn ich ihn nicht mehr brauche.

hört sich gut an. eine proprietäre high-speed datenschnittstelle zwischen OS und user-mode hat vorteile, z.b. wenn irgendwann netzwerkprotokolle, filesystems, etc. dran sind, die dann bequem im userspace laufen könnten, was der stabilität des system zugute kommen würde. knackpunkt ist aber das zurückgeben der buffer ans system, es wäre ja doof, wenn die anwendung das vergisst und der kernel irgendwann 'out of memory' ist.

volkard schrieb:

hihi, ich möchte nicht in deinen schuhen stecken.

ich auch nicht, aber erhard hat durchhaltevermögen und auf den kopf gefallen ist er auch nicht.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:15:58 25.04.2009   Titel:              Zitieren

Danke für den interessanten Einwurf. :)

Zitat:
hihi, ich möchte nicht in deinen schuhen stecken.

Das Problem ist, dass alles miteinander vernetzt ist, aber so ist es nun einmal.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 01:19:12 25.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Das Problem ist, dass alles miteinander vernetzt ist, aber so ist es nun einmal.

deswegen sollteste frühzeitig das ganze in überschaubare teilkomponenten zerlegen, KISS-prinzip, teile und herrsche und so.
:)
volkard
Moderator

Benutzerprofil
Anmeldungsdatum: 06.04.2000
Beiträge: 24349
Beitrag volkard Moderator 01:27:28 25.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zitat:
hihi, ich möchte nicht in deinen schuhen stecken.

Das Problem ist, dass alles miteinander vernetzt ist, aber so ist es nun einmal.

hihi, ich möchte nicht in deinen schuhen stecken.

_________________
http://www.venganza.info/
plonk fürs Forum v1.02


Zuletzt bearbeitet von volkard am 01:28:22 25.04.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:24:20 25.04.2009   Titel:              Zitieren

Zitat:
deswegen sollteste frühzeitig das ganze in überschaubare teilkomponenten zerlegen
Genau dies werde ich versuchen, soweit das möglich ist. Paging, Heap, Task Switching, User Mode vs Kernel Mode, Syscalls, VFS sind solche Einheiten, die allerdings zum einfachen Begreifen teilweise zu groß sind. Da versuche ich gerade, Unterelemente als elementare Module weiter heraus zu schneiden.

Noch wichtiger ist die Visualisierung / Verständlichmachung dessen, was passiert, wenn man dies oder jenes ändert, weil viele Leute beim Verstehen und Begreifen eher praktisch an die Dinge heran gehen.

Ich denke gerade über diesen so lässig dahin geworfenen Begriff nach:
Zitat:
filemapping

http://msdn.microsoft.com/en-us/library/aa366556(VS.85).aspx (MS Windows)
Zitat:
Processes read from and write to the file view using pointers, just as they would with dynamically allocated memory. The use of file mapping improves efficiency because the file resides on disk, but the file view resides in memory. ...

http://i.msdn.microsoft.com/Aa366556.fmap(en-us,VS.85).png

Der Schwachpunkt von PrettyOS besteht momentan noch darin, dass noch kein Fileformat festgelegt wurde (jedoch kein Problem) und noch kein Mechanismus zum Übertragen von "Files" (Laden/Lesen Schreiben/Speichern), z.B. aus der RAM Disk in den Speicher und umgekehrt existiert. Sobald diese Mechanismen funktionieren, komme ich auf dieses Thema "proprietäre high-speed Datenschnittstelle zwischen OS und User Mode" zurück. Es geht nichts verloren. Wie sehen die entsprechenden Pendants bei Linux und Windows genau aus, damit ich das im Detail studieren kann?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 11:30:52 25.04.2009, insgesamt 1-mal bearbeitet
volkard
Moderator

Benutzerprofil
Anmeldungsdatum: 06.04.2000
Beiträge: 24349
Beitrag volkard Moderator 11:29:23 25.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Wie sehen die entsprechenden Pendants bei Linux und Windows genau aus, damit ich das im Detail studieren kann?

win haste ja schon gefunden. bei linux heißt die schlüsselfunktion mmap http://linux.die.net/man/3/mmap

_________________
http://www.venganza.info/
plonk fürs Forum v1.02
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:34:17 25.04.2009   Titel:              Zitieren

Danke! :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 11:40:14 25.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Wie sehen die entsprechenden Pendants bei Linux und Windows genau aus, damit ich das im Detail studieren kann?

http://www.i.u-tokyo.ac.jp/edu/training/ss/lecture/new-documents/Lectures/
unter: 10-LPC. auch der rest, z.b. memory management, dürfte dich auch interessieren.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 12:56:10 25.04.2009   Titel:              Zitieren

@+fricky: Danke für den Link!
Momentan interessiert mich dies hier am meisten, da ich davon bisher nur einen Bruchteil habe, und mir genau der Rest fehlt: ;)
http://www.i.u-tokyo.ac.jp/edu/training/ss/lecture/new-documents/Lectures/02-VirtualMemory/VirtualMemory.pdf
PrettyOS muss aber nicht wirklich performant sein, sondern vor allem verständlich, eben als Experimentier-Plattform geeignet. Ich bin mir noch nicht sicher, ob mir das gelingt, hängt davon ab, inwieweit mir geeignete Visualisierungs-Funktionen für die einzelnen Module und Exceptions gelingen.

Gibt es eine Übersicht, wie man weitere Infos aus Registern erhält, um Exceptions möglichst vollständig zu analysieren? Dann könnte man diese Funktion, die bisher nur Page Faults genauer unter die Lupe nimmt, weiter ausbauen:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void fault_handler(struct regs* r)
{
    if (r->int_no < 32)
    {
        settextcolor(4,0);

        if (r->int_no == 14) //Page Fault
        {
            ULONG faulting_address;
            asm volatile("mov %%cr2, %0" : "=r" (faulting_address)); // faulting address => CR2 register

            // The error code gives us details of what happened.

            int present   = !(r->err_code & 0x1); // Page not present
            int rw        =   r->err_code & 0x2;  // Write operation?
            int us        =   r->err_code & 0x4;  // Processor was in user-mode?
            int reserved  =   r->err_code & 0x8;  // Overwritten CPU-reserved bits of page entry?
            int id        =   r->err_code & 0x10; // Caused by an instruction fetch?

            // Output an error message.
            //...

        }
        printformat("%s >>> Exception. System Halted! <<<", exception_messages[r->int_no]);
        for (;;); // currently STOP!
    }

    if (r->int_no == 127)
    {
        settextcolor(4,0);
        printformat(">>> IRQ 127 <<<\n");
        syscall_handler(r);
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void fault_handler(struct regs* r)
{
if (r->int_no < 32)
{
settextcolor(4,0);

if (r->int_no == 14) //Page Fault
{
ULONG faulting_address;
asm volatile("mov %%cr2, %0" : "=r" (faulting_address)); // faulting address => CR2 register

// The error code gives us details of what happened.

int present = !(r->err_code & 0x1); // Page not present
int rw = r->err_code & 0x2; // Write operation?
int us = r->err_code & 0x4; // Processor was in user-mode?
int reserved = r->err_code & 0x8; // Overwritten CPU-reserved bits of page entry?
int id = r->err_code & 0x10; // Caused by an instruction fetch?

// Output an error message.
//...

}
printformat("%s >>> Exception. System Halted! <<<", exception_messages[r->int_no]);
for (;;); // currently STOP!
}

if (r->int_no == 127)
{
settextcolor(4,0);
printformat(">>> IRQ 127 <<<\n");
syscall_handler(r);
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void fault_handler(struct regs* r)
{
    if (r->int_no < 32)
    {
        settextcolor(4,0);

        if (r->int_no == 14) //Page Fault
        {
            ULONG faulting_address;
            asm volatile("mov %%cr2, %0" : "=r" (faulting_address)); // faulting address => CR2 register

            // The error code gives us details of what happened.

            int present   = !(r->err_code & 0x1); // Page not present
            int rw        =   r->err_code & 0x2;  // Write operation?
            int us        =   r->err_code & 0x4;  // Processor was in user-mode?
            int reserved  =   r->err_code & 0x8;  // Overwritten CPU-reserved bits of page entry?
            int id        =   r->err_code & 0x10; // Caused by an instruction fetch?

            // Output an error message.
            //...

        }
        printformat("%s >>> Exception. System Halted! <<<", exception_messages[r->int_no]);
        for (;;); // currently STOP!
    }

    if (r->int_no == 127)
    {
        settextcolor(4,0);
        printformat(">>> IRQ 127 <<<\n");
        syscall_handler(r);
    }
}

r->err_code und das Register cr2 dürften wohl der Schlüssel dazu sein. Wenn man beim "Spielen" mit dem Code in ckernel.c auf eine Exception trifft, sollte man heraus finden können, was man eigentlich falsch gemacht hat. Das ist momentan noch nicht ausreichend gegeben. Das ist aus meiner Sicht noch das Hauptproblem.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 13:15:35 25.04.2009, insgesamt 3-mal bearbeitet
PHPnerd
Unregistrierter




Beitrag PHPnerd Unregistrierter 13:24:12 25.04.2009   Titel:              Zitieren

English, my German is not very well.

Try to create some code for installing fault handlers, so each fault handler does have its own function. Check if a custom handler is installed, and execute it. If not, write down a message on the screen and halt CPU (cli, hlt, for(;;);)
Keeping them apart this way like, is very handy for dynamically installing and removing handlers. Also, when having a Virtual86Mode implemented, you will need #GP (general protection fault) very often, and write some big routines for it.

for the Debug and Break exception you can write some nice simple handler. Just dump all registers given as argument in function call.

The Page Fault handler:
Receive the CR3 AND CR2. CR2 contains faulting address. CR3 the PHYSICAL address of the page directory. Then, split the faulting address in some parts.
PageDirectoryIndex (cr2 >> 22, when using 4kb pages on a 32-bit system)
PageTableIndex ((cr2 >> 12) & 0x3ff)
PageOffset ((cr2 & 0xfff), not necessary for now)

Then, when page was not present, check the PDE for present bit, then the existence of the PageTable (PDE->frame << 12 and then to virtual), then present of PTE, and then existence of the page mapped to the PTE. (PTE->frame != 0x0)

Solve any of these things, but keep patience: be sure caller should be able to write or read something at the address in cr2.

When having r/w (read/write) page fault and is present, kill the process. It is trying to access kernel space. Same way with u/s (user/supervisor).

When looking at the Intel Manual, we see that there is NO ID bit in the error code of a #PF (page fault).
Reserved, if problems with that, kill process. (or maybe just continuing is fine too)

greetings, and success.

// PHPnerd :D
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 14:22:40 25.04.2009   Titel:              Zitieren

@PHPnerd: thank you very much. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 16:56:07 25.04.2009   Titel:              Zitieren

Keine Probleme. :P

I will look at this topic often to help here :)
I am busy with kmalloc.

The memory management part is the most boring, tricky and frustrating part of OS development.Don't quit :P

Also: be sure you always print out messages of exceptions, especially at the page fault exception. There shouldn't be ANY exceptions occur when programming kernel itself.

// PHPnerd
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 20:05:56 25.04.2009   Titel:              Zitieren

PHPnerd schrieb:

There shouldn't be ANY exceptions occur when programming kernel itself.

even if the kernel is 100% bug free, third-party modules (device drivers and similar stuff running in kernel space) can crash the system. erhard should implement an exception handling mechanism, so that common errors (like wild pointers, divison by zero, etc.) are handled properly.
:)
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 20:53:03 25.04.2009   Titel:              Zitieren

Yeah, but kernel itself (main routine, setting up paging) should :P

Writing div by zero handler. I think that should be setting return value to zero.

so
int a = 5/0;
a will be zero, instead of killing process.

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 21:46:39 25.04.2009   Titel:              Zitieren

PHPnerd schrieb:

so
int a = 5/0;
a will be zero, instead of killing process.

no, that keeps the error. the error creeps forward and will cause weird behaviour of the whole thing. instead, exceptions should be 'handled' in a controlled manner (like this):
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
...
begin_guarded_section();
{
  ...
  int a = x/0;
  ...
}
if (get_exception_code() == DIV_BY_ZERO)  // enter exception handler
{
  // deal with division by 0
}
end_guarded_section();  // stop guarding
...   // process will be killed at this point, if another exceptions occur
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
...
begin_guarded_section();
{
...
int a = x/0;
...
}
if (get_exception_code() == DIV_BY_ZERO) // enter exception handler
{
// deal with division by 0
}
end_guarded_section(); // stop guarding
... // process will be killed at this point, if another exceptions occur
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
...
begin_guarded_section();
{
  ...
  int a = x/0;
  ...
}
if (get_exception_code() == DIV_BY_ZERO)  // enter exception handler
{
  // deal with division by 0
}
end_guarded_section();  // stop guarding
...   // process will be killed at this point, if another exceptions occur

^^all can be done using c-functions. there's no need for a modfied compiler (like that is the case with structured exception handling under m$-windoofs).
:)
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 22:12:46 25.04.2009   Titel:              Zitieren

So, no kernelmode div by zero handler?

Erhard: do not forget to invalidate the TLB. use INVLPG (see Intel manuals) or read CR3, and write it to it again.

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix


Zuletzt bearbeitet von PHPnerd am 22:13:24 25.04.2009, insgesamt 1-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 22:44:27 25.04.2009   Titel:              Zitieren

PHPnerd schrieb:
So, no kernelmode div by zero handler?

of course, kernel must handle that, but must not terminate the application if an exception occurs inside guarded code. after that, the application should ask the kernel for exception code and (if there is one), retry the operation, notify the user, abort the program or something like that.
:)
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 22:54:26 25.04.2009   Titel:              Zitieren

All right, understand. But that is something for later on to me :P

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 02:37:08 26.04.2009   Titel:              Zitieren

Yes, exception handling has to be fine-tuned in PrettyOS. Currently, there is only a message and a big stop sign. Page faults are already analyzed deeper.

I worked on the VFS and the RAM disk, because it is very important to bring data, specialized kernel modules or user code into the memory of the OS. The way how it works now is as follows:

1) produce a binary image from various files (with "make_initrd.exe", source code: "make_initrd.c"). I renamed the resulting image to "file_data.dat". This is the target for incbin in process.asm.

2a) include it in process.asm with incbin, global addresses:
Code:
; data for ramdisk
global _file_data_start
global _file_data_end
_file_data_start:
incbin "file_data.dat"
_file_data_end:
Code:
; data for ramdisk
global _file_data_start
global _file_data_end
_file_data_start:
incbin "file_data.dat"
_file_data_end:
Code:
; data for ramdisk
global _file_data_start
global _file_data_end
_file_data_start:
incbin "file_data.dat"
_file_data_end:

2b) Linker transfers it to the memory at &file_data_start

3) The source code line
C/C++ Code:
k_memcpy((void*)ramdisk_start, &file_data_start, (ULONG)&file_data_end - (ULONG)&file_data_start);
C/C++ Code:
k_memcpy((void*)ramdisk_start, &file_data_start, (ULONG)&file_data_end - (ULONG)&file_data_start);
C/C++ Code:
k_memcpy((void*)ramdisk_start, &file_data_start, (ULONG)&file_data_end - (ULONG)&file_data_start);
in ckernel.c transfers the data with the files to the RAM disk (this is the way we exchange data with PrettyOS at the time being)

4) The Virtual File System (VFS) with individual file headers helps to access the files in the RAM disk

Enjoy it! :)

PrettyOS: http://www.henkessoft.de/OS_Dev/Downloads/36.zip
Screenshot: http://www.henkessoft.de/OS_Dev/Downloads/ramdisk_test.png

Currently the framework for booting, loading asm kernel, switch to PM and C-kernel, interrupts, write/read key queue, set system timer frequency (I use 100 Hz), paging, heap, virtual file system, RAM disk, multitasking, syscalls now basically work. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:43:15 26.04.2009, insgesamt 2-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 10:22:56 26.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Hier ein prinzipielles Beispiel mit Erzeugung mehrerer Tasks und Taskswitch:...

Aha, jetzt wird's interessanter und praxisbezogener...
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 12:05:16 26.04.2009   Titel:              Zitieren

Zitat:
Aha, jetzt wird's interessanter und praxisbezogener...
Die letzten beiden Wochen habe ich mich - zumindest grundlegend - um die komplexen Themen Memory-, Task- und File-Management (VFS, RAM Disk) sowie Syscalls gekümmert, um zu sehen, wie man dies am besten aufbauen und darstellen könnte. Manchmal sucht man auch nur "ewig" nach einem Fehler im Sourcecode. Hierbei behebt man dann zunächst noch alle möglichen anderen Baustellen, die man bei genauerem Hinsehen als nicht korrekt aufspürt. Bei mir liegen die "üblen" Fehler immer im Zeiger-Bereich. Kleines Beispiel:

Diese Zeile hatte ich schnell "hingehauen":
C/C++ Code:
k_memcpy((void*)ramdisk_start, &file_data_start, &file_data_end - &file_data_start);
C/C++ Code:
k_memcpy((void*)ramdisk_start, &file_data_start, &file_data_end - &file_data_start);
C/C++ Code:
k_memcpy((void*)ramdisk_start, &file_data_start, &file_data_end - &file_data_start);

Mit k_memshow(...) sah ich zufrieden, dass die "eingelinkten" Daten gefunden und sauber an den Anfang der RAM Disk kopiert wurden.
Das Schlimme ist, dass durch die Pointer-Arithmetik zu wenige Daten kopiert wurden. Über die Blödsinnigkeit dieses Fehlers (es gibt nur wenige geniale Fehler) möchte ich hier nicht reden, so etwas passiert eben ab und zu, wenn man den cast auf die Schnelle vergisst. Dieses Wechselspiel zwischen Speicheradresse und Darstellung als unsigned long integer (ULONG) ist eine der Schwächen des Systems. Zwei kleine Casts nach ULONG, und schon funktionierte es perfekt:
C/C++ Code:
k_memcpy((void*)ramdisk_start, &file_data_start, (ULONG)&file_data_end - (ULONG)&file_data_start);
C/C++ Code:
k_memcpy((void*)ramdisk_start, &file_data_start, (ULONG)&file_data_end - (ULONG)&file_data_start);
C/C++ Code:
k_memcpy((void*)ramdisk_start, &file_data_start, (ULONG)&file_data_end - (ULONG)&file_data_start);

Das Schlimme ist, dass man den Fehler an völlig anderer Stelle - nämlich den neu eingebauten Mechanismen - sucht. Auslöser ist, dass man große Speicherbereiche nicht auf einfache Weise wie bei einem Hex-Editor durchscrollen kann. Mir ist der Fehler erst aufgefallen, als ich mich mit k_memshow(...) auf die konkrete Stelle im Speicher gesetzt und dort nur Nullen gefunden habe. :D
Solche Erfahrungen sind in einem Tutorial wichtig und sollten auch dargestellt werden, damit andere an solche Trivialitäten denken, wenn Sie Fehler suchen. Denn das "Aufgeben" kommt oft daher, dass man Fehler nicht findet, keine geeigneten Vorbilder hat und/oder in einem Forum (http://forum.osdev.org/ ist ein Musterbeispiel) arrogant behandelt wird.

Momentan schreibe ich an dem Tutorial noch nicht weiter, weil die grundlegenden Mechanismen zwar funktionieren, ich aber mit der Visualisierung noch nicht zufrieden bin.

Erste zaghafte Beispiele für Visualisierung sind:
C/C++ Code:
void k_memshow(void* start, size_t count)
{
    const UCHAR* end = (const UCHAR*)(start+count);
    for(; count != 0; count--) printformat("%x ",*(end-count));
}
C/C++ Code:
void k_memshow(void* start, size_t count)
{
const UCHAR* end = (const UCHAR*)(start+count);
for(; count != 0; count--) printformat("%x ",*(end-count));
}
C/C++ Code:
void k_memshow(void* start, size_t count)
{
    const UCHAR* end = (const UCHAR*)(start+count);
    for(; count != 0; count--) printformat("%x ",*(end-count));
}


und die Paging-Analyse-Funktionen
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
ULONG show_physical_address(ULONG virtual_address)
{
    page_t* page = get_page(virtual_address, 0, kernel_directory);
    return( (page->frame_addr)*PAGESIZE + (virtual_address&0xFFF) );
}

void analyze_physical_addresses()
{
   int i,j,k, k_old;
    for(i=0;i<(PHYSICAL_MEMORY/0x18000+1);++i)
    {
        for(j=i*0x18000; j<i*0x18000+0x18000; j+=0x1000)
        {
            if(show_physical_address(j)==0)
            {
                settextcolor(4,0);
                k_old=k; k=1;
            }
            else
            {
                if(show_physical_address(j)-j)
                {
                    settextcolor(3,0);
                    k_old=k; k=2;
                }
                else
                {
                    settextcolor(2,0);
                    k_old=k; k=3;
                }
            }
            if(k!=k_old)
                printformat("%x %x\n", j, show_physical_address(j));
        }
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
ULONG show_physical_address(ULONG virtual_address)
{
page_t* page = get_page(virtual_address, 0, kernel_directory);
return( (page->frame_addr)*PAGESIZE + (virtual_address&0xFFF) );
}

void analyze_physical_addresses()
{
int i,j,k, k_old;
for(i=0;i<(PHYSICAL_MEMORY/0x18000+1);++i)
{
for(j=i*0x18000; j<i*0x18000+0x18000; j+=0x1000)
{
if(show_physical_address(j)==0)
{
settextcolor(4,0);
k_old=k; k=1;
}
else
{
if(show_physical_address(j)-j)
{
settextcolor(3,0);
k_old=k; k=2;
}
else
{
settextcolor(2,0);
k_old=k; k=3;
}
}
if(k!=k_old)
printformat("%x %x\n", j, show_physical_address(j));
}
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
ULONG show_physical_address(ULONG virtual_address)
{
    page_t* page = get_page(virtual_address, 0, kernel_directory);
    return( (page->frame_addr)*PAGESIZE + (virtual_address&0xFFF) );
}

void analyze_physical_addresses()
{
   int i,j,k, k_old;
    for(i=0;i<(PHYSICAL_MEMORY/0x18000+1);++i)
    {
        for(j=i*0x18000; j<i*0x18000+0x18000; j+=0x1000)
        {
            if(show_physical_address(j)==0)
            {
                settextcolor(4,0);
                k_old=k; k=1;
            }
            else
            {
                if(show_physical_address(j)-j)
                {
                    settextcolor(3,0);
                    k_old=k; k=2;
                }
                else
                {
                    settextcolor(2,0);
                    k_old=k; k=3;
                }
            }
            if(k!=k_old)
                printformat("%x %x\n", j, show_physical_address(j));
        }
    }
}

Im Tasking-Bereich ist mir bisher nur die Darstellung der PID als Farbe beim "Tippen" (Schreiben/Lesen KeyQueue) eingefallen.
Vor dem Heap-Gebäude stehe ich noch etwas zögerlich bezüglich Darstellung der "blocks and holes". Man hat im Textmode mit 80*25 mit wenigen brauchbaren Farben auch nicht allzu viele Möglichkeiten.

Didaktische Ideen sind daher immer willkommen. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 14:07:09 26.04.2009, insgesamt 3-mal bearbeitet
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 14:27:44 26.04.2009   Titel:              Zitieren

Well done!

I am still busy with kmalloc, almost finished it.

How advanced is your multitasker now?

And did you make your filesystem manager usable for programmers, who want to make a filesystem driver like Ext2, Ext3, FAT etc?

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 16:13:03 26.04.2009   Titel:              Zitieren

Zitat:
How advanced is your multitasker now?

There is the function task_switch of PrettyOS: 1 -> 2 -> 3 -> ... -> N -> 1 ->...
This could be triggered by the system timer according to allowed timeslices, but not done until now. I tried it out, but got General Protection Fault. You can't switch at each time. Thus, the question is how to avoid and switch on the right time?
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void task_switch()
{
    if (!current_task) return;
    ULONG esp, ebp, eip;
    asm volatile("mov %%esp, %0" : "=r"(esp));
    asm volatile("mov %%ebp, %0" : "=r"(ebp));
    eip = read_eip();
    if (eip == 0x12345) return;
    current_task->eip = eip;
    current_task->esp = esp;
    current_task->ebp = ebp;
    current_task = current_task->next;
    if (!current_task) current_task = ready_queue;
    eip = current_task->eip;
    esp = current_task->esp;
    ebp = current_task->ebp;
    current_directory = current_task->page_directory;
    set_kernel_stack(current_task->kernel_stack+KERNEL_STACK_SIZE);
    asm volatile("         \
      cli;                 \
      mov %0, %%ecx;       \
      mov %1, %%esp;       \
      mov %2, %%ebp;       \
      mov %3, %%cr3;       \
      mov $0x12345, %%eax; \
      sti;                 \
      jmp *%%ecx          
"
                 : : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr));
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void task_switch()
{
if (!current_task) return;
ULONG esp, ebp, eip;
asm volatile("mov %%esp, %0" : "=r"(esp));
asm volatile("mov %%ebp, %0" : "=r"(ebp));
eip = read_eip();
if (eip == 0x12345) return;
current_task->eip = eip;
current_task->esp = esp;
current_task->ebp = ebp;
current_task = current_task->next;
if (!current_task) current_task = ready_queue;
eip = current_task->eip;
esp = current_task->esp;
ebp = current_task->ebp;
current_directory = current_task->page_directory;
set_kernel_stack(current_task->kernel_stack+KERNEL_STACK_SIZE);
asm volatile(" \
cli; \
mov %0, %%ecx; \
mov %1, %%esp; \
mov %2, %%ebp; \
mov %3, %%cr3; \
mov $0x12345, %%eax; \
sti; \
jmp *%%ecx
"
: : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr));
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void task_switch()
{
    if (!current_task) return;
    ULONG esp, ebp, eip;
    asm volatile("mov %%esp, %0" : "=r"(esp));
    asm volatile("mov %%ebp, %0" : "=r"(ebp));
    eip = read_eip();
    if (eip == 0x12345) return;
    current_task->eip = eip;
    current_task->esp = esp;
    current_task->ebp = ebp;
    current_task = current_task->next;
    if (!current_task) current_task = ready_queue;
    eip = current_task->eip;
    esp = current_task->esp;
    ebp = current_task->ebp;
    current_directory = current_task->page_directory;
    set_kernel_stack(current_task->kernel_stack+KERNEL_STACK_SIZE);
    asm volatile("         \
      cli;                 \
      mov %0, %%ecx;       \
      mov %1, %%esp;       \
      mov %2, %%ebp;       \
      mov %3, %%cr3;       \
      mov $0x12345, %%eax; \
      sti;                 \
      jmp *%%ecx          
"
                 : : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr));
}


As mentioned above, I don't have a time-based scheduler. Here I found some easy code, which might be interesting:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
      //global pointer to current task:
      prozess_t* p;

      //the isr:
      void timer_handler(void)
      {
        if(task_to_bill->prozess_timetorun>0)
        {
          task_to_bill->prozess_timetorun--;
          if(task_to_bill->prozess_timetorun<1)
          {
            schedule(0);
          }
        }
      }

      //the scheduler:
      void schedule(int irq)
      {
        ELEMENT* proz;
        if(!(queue_empty(&roundrobin_prozesse))&&p->prozess_timetorun<1)
        {
          p->prozess_timetorun=10;//refill timeslice.
      //remove process from the head of the queue.

          proz=remove_first_element_from_queue(&roundrobin_prozesse,0);
      //put the element to the rear of the queue.
          add_element_to_queue_rear(&roundrobin_prozesse,proz);
        }
    //pick the process at the head of any queue. (f. ex. round robin queue)
    //and put it in p.

        choose_prozess(irq);
      }
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//global pointer to current task:
prozess_t* p;

//the isr:
void timer_handler(void)
{
if(task_to_bill->prozess_timetorun>0)
{
task_to_bill->prozess_timetorun--;
if(task_to_bill->prozess_timetorun<1)
{
schedule(0);
}
}
}

//the scheduler:
void schedule(int irq)
{
ELEMENT* proz;
if(!(queue_empty(&roundrobin_prozesse))&&p->prozess_timetorun<1)
{
p->prozess_timetorun=10;//refill timeslice.
//remove process from the head of the queue.

proz=remove_first_element_from_queue(&roundrobin_prozesse,0);
//put the element to the rear of the queue.
add_element_to_queue_rear(&roundrobin_prozesse,proz);
}
//pick the process at the head of any queue. (f. ex. round robin queue)
//and put it in p.

choose_prozess(irq);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
      //global pointer to current task:
      prozess_t* p;

      //the isr:
      void timer_handler(void)
      {
        if(task_to_bill->prozess_timetorun>0)
        {
          task_to_bill->prozess_timetorun--;
          if(task_to_bill->prozess_timetorun<1)
          {
            schedule(0);
          }
        }
      }

      //the scheduler:
      void schedule(int irq)
      {
        ELEMENT* proz;
        if(!(queue_empty(&roundrobin_prozesse))&&p->prozess_timetorun<1)
        {
          p->prozess_timetorun=10;//refill timeslice.
      //remove process from the head of the queue.

          proz=remove_first_element_from_queue(&roundrobin_prozesse,0);
      //put the element to the rear of the queue.
          add_element_to_queue_rear(&roundrobin_prozesse,proz);
        }
    //pick the process at the head of any queue. (f. ex. round robin queue)
    //and put it in p.

        choose_prozess(irq);
      }

http://www.osdever.net/tutorials/multitasking.php

What do you think about it?
How to prohibit general protection faults by the task switch?



Zitat:
And did you make your filesystem manager usable for programmers, who want to make a filesystem driver like Ext2, Ext3, FAT etc?

Not yet, but it should be possible by the VFS.
Currently I use a very primitive filesystem, only magic number, name and content (initrd.h/initrd.c):
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "os.h"
#include
"fs.h" // Virtual File System (UNIX idea: everything is a file)

typedef struct {
    ULONG nfiles; // The number of files in the ramdisk.
} initrd_header_t;

typedef struct {
    ULONG magic;    // Magic number, for error checking.
    CHAR  name[64]; // Filename.
    ULONG off;      // Offset in the initrd that the file starts.
    ULONG length;   // Length of the file.
} initrd_file_header_t;

// Installs the initial ramdisk. It gets passed the address, and returns a completed filesystem node.
fs_node_t* install_initrd(ULONG location);
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "os.h"
#include
"fs.h" // Virtual File System (UNIX idea: everything is a file)

typedef struct {
ULONG nfiles; // The number of files in the ramdisk.
} initrd_header_t;

typedef struct {
ULONG magic; // Magic number, for error checking.
CHAR name[64]; // Filename.
ULONG off; // Offset in the initrd that the file starts.
ULONG length; // Length of the file.
} initrd_file_header_t;

// Installs the initial ramdisk. It gets passed the address, and returns a completed filesystem node.
fs_node_t* install_initrd(ULONG location);
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "os.h"
#include
"fs.h" // Virtual File System (UNIX idea: everything is a file)

typedef struct {
    ULONG nfiles; // The number of files in the ramdisk.
} initrd_header_t;

typedef struct {
    ULONG magic;    // Magic number, for error checking.
    CHAR  name[64]; // Filename.
    ULONG off;      // Offset in the initrd that the file starts.
    ULONG length;   // Length of the file.
} initrd_file_header_t;

// Installs the initial ramdisk. It gets passed the address, and returns a completed filesystem node.
fs_node_t* install_initrd(ULONG location);


I was very glad, when it worked. :)

Looking at the path forward, I think the next milestones could be:
- loading executables (file format?)
- kernel modules
- shell

How do you / will you load executables? (one of the text files in the RAM disk of the last example could have been an executable file (elf, com, exe, ...) ). What's the best way to start it?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 18:35:28 26.04.2009, insgesamt 12-mal bearbeitet
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 19:04:43 26.04.2009   Titel:              Zitieren

I recognise some JamesMolloy code in your multitasker :P
I will see if I find something. Try to use cli(); at start of the handler. And keep patience of the order you set the registers.

Loading executables. I will start with having possibility to load more executable-types. First, ELF. You got to read out the header, and copy-on-write the data to user-process memory. Allocate a stack, and don't forget to make space for .bss section. (should be filled with zero's). Just read ELF specifications and start simple. (just the data, bss, text sections).

When loading executable, you are in Ring0, you are in the address space you will load the executable in. When done loading, jump to ring 3 and start at the beginning of the executable.

I haven't been working on executables. But this is what I think it should work.

Success!

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:49:21 26.04.2009   Titel:              Zitieren

Zitat:
Try to use cli(); at start of the handler.
I did, but the GPF didn't leave. In between I was told that C might be not perfect for the task switch. :rolleyes: The above presented function for task_switch does not save all registers. That might be the real problem in some situations.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:55:23 26.04.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:57:14 26.04.2009   Titel:              Zitieren

Another point in the whole source code is the mixing of physical and virtual memory management in paging.h/paging.c. That has to be separated.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 21:41:26 26.04.2009   Titel:              Zitieren

Sure it has to be separate, i do, the PMM, VMM and kmalloc, all apart.

What is o_0:
Code:
if(!(queue_empty(&roundrobin_prozesse))&&p->prozess_timetorun<1)
Code:
if(!(queue_empty(&roundrobin_prozesse))&&p->prozess_timetorun<1)
Code:
if(!(queue_empty(&roundrobin_prozesse))&&p->prozess_timetorun<1)


the double && looks very bad to me

I checked task switch code with my old, its the same (diff is what I added, like threads and states). I put a cli() just after very first statement. (if(!task)).

And where exactly (line) does the #GP trigger? (just try putting chars like ! on as much as lines as possible, and count numbeer of printed when running)

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:07:02 26.04.2009   Titel:              Zitieren

Zitat:
just try putting chars like ! on as much as lines as possible, and count numbeer of printed when running
Interesting trick. This I try at once:
Zitat:
!!!!#!!!!#!!!!#General Protection Fault >>> Exception. System Halted! <<<

Hence, I know that the GPF happens in the asm-code:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
set_kernel_stack(current_task->kernel_stack+KERNEL_STACK_SIZE); putch('#');
      asm volatile("         \
      cli;                 \
      mov %0, %%ecx;       \
      mov %1, %%esp;       \
      mov %2, %%ebp;       \
      mov %3, %%cr3;       \
      mov $0x12345, %%eax; \
      sti;                 \
      jmp *%%ecx          
"
                 : : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr)); putch('!');
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
set_kernel_stack(current_task->kernel_stack+KERNEL_STACK_SIZE); putch('#');
asm volatile(" \
cli; \
mov %0, %%ecx; \
mov %1, %%esp; \
mov %2, %%ebp; \
mov %3, %%cr3; \
mov $0x12345, %%eax; \
sti; \
jmp *%%ecx
"
: : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr)); putch('!');
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
set_kernel_stack(current_task->kernel_stack+KERNEL_STACK_SIZE); putch('#');
      asm volatile("         \
      cli;                 \
      mov %0, %%ecx;       \
      mov %1, %%esp;       \
      mov %2, %%ebp;       \
      mov %3, %%cr3;       \
      mov $0x12345, %%eax; \
      sti;                 \
      jmp *%%ecx          
"
                 : : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr)); putch('!');

because the last ! did not show up.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:07:27 26.04.2009, insgesamt 1-mal bearbeitet
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 22:11:58 26.04.2009   Titel:              Zitieren

You really do? Dont be so sure. What does the ASM do? Yes, it switches task, it chnages page directory, and the instrcution pointer after that code, we continue the task, and not the code of the scheduler.

Or am i wrong, and is the ! showed at the other switchs?

// PHP

_________________
Being Dutch. Talking English. On a German community.

Jinix
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 22:35:11 26.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:

In between I was told that C might be not perfect for the task switch. The above presented function for task_switch does not save all registers. That might be the real problem in some situations.

that's true. even if most c-compilers have support for interrupt routines, you can't access cpu registers directly in C (only few compilers for embedded systems support that). you have to code this very low level stuff in assembly. all real life RTOS (although portable among many cpus), with preemptive schedulers, use asm for the heart of the task switcher.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:35:48 26.04.2009   Titel:              Zitieren

Well, you think, the last ! cannot show up. OK, then I have to try a situation where it works correctly.

You are right! If it works, then !!!!#!!!!#!!!!## is presented at the screen. Thus, the last # is given out twice instead of the ! :confused:

Now I am in a dead-end-street. :(

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:37:51 26.04.2009, insgesamt 1-mal bearbeitet
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 23:05:51 26.04.2009   Titel:              Zitieren

Are you using Bochs? I hope so, do following for me:

put cli, hlt, for(;;); before the big assembly part. Shutdown, and open the bochsout file. Put the register info in here. Btw: remove any calls to the scheduler and call it the way it will fault. So it will give us the right values.

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:34:04 26.04.2009   Titel:              Zitieren

C/C++ Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
    /// TEST
      cli();
      asm volatile("hlt;");
      for(;;);
    /// TEST

    asm volatile("         \
    //...
C/C++ Code:
1
2
3
4
5
6
7
8
/// TEST
cli();
asm volatile("hlt;");
for(;;);
/// TEST

asm volatile(" \
//...
C/C++ Code:
1
2
3
4
5
6
7
8
    /// TEST
      cli();
      asm volatile("hlt;");
      for(;;);
    /// TEST

    asm volatile("         \
    //...

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
01368000000p[WGUI ] >>PANIC<< POWER button turned off.
01368000000i[CPU0 ] CPU is in protected mode (halted)
01368000000i[CPU0 ] CS.d_b = 32 bit
01368000000i[CPU0 ] SS.d_b = 32 bit
01368000000i[CPU0 ] EFER   = 0x00000000
01368000000i[CPU0 ] | RAX=000000000000008f  RBX=000000000000d502
01368000000i[CPU0 ] | RCX=00000000000b8000  RDX=00000000000003d5
01368000000i[CPU0 ] | RSP=000000000018ff1c  RBP=000000000018ff44
01368000000i[CPU0 ] | RSI=000000000018ffd8  RDI=000000000018fff0
01368000000i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
01368000000i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
01368000000i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
01368000000i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
01368000000i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf zf af pf cf
01368000000i[CPU0 ] | SEG selector     base    limit G D
01368000000i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
01368000000i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
01368000000i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
01368000000i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
01368000000i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 1 1
01368000000i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 1 1
01368000000i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 1 1
01368000000i[CPU0 ] |  MSR_FS_BASE:0000000000000000
01368000000i[CPU0 ] |  MSR_GS_BASE:0000000000000000
01368000000i[CPU0 ] | RIP=000000000000d3f9 (000000000000d3f9)
01368000000i[CPU0 ] | CR0=0xe0000011 CR1=0x0 CR2=0x0000000000000000
01368000000i[CPU0 ] | CR3=0x00306000 CR4=0x00000000
01368000000i[CPU0 ] >> add esp, 0x00000010 : 83C410
01368000000i[CMOS ] Last time is 1240781579 (Sun Apr 26 23:32:59 2009)
01368000000i[     ] restoring default signal behavior
01368000000i[CTRL ] quit_sim called with exit code 1
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
01368000000p[WGUI ] >>PANIC<< POWER button turned off.
01368000000i[CPU0 ] CPU is in protected mode (halted)
01368000000i[CPU0 ] CS.d_b = 32 bit
01368000000i[CPU0 ] SS.d_b = 32 bit
01368000000i[CPU0 ] EFER = 0x00000000
01368000000i[CPU0 ] | RAX=000000000000008f RBX=000000000000d502
01368000000i[CPU0 ] | RCX=00000000000b8000 RDX=00000000000003d5
01368000000i[CPU0 ] | RSP=000000000018ff1c RBP=000000000018ff44
01368000000i[CPU0 ] | RSI=000000000018ffd8 RDI=000000000018fff0
01368000000i[CPU0 ] | R8=0000000000000000 R9=0000000000000000
01368000000i[CPU0 ] | R10=0000000000000000 R11=0000000000000000
01368000000i[CPU0 ] | R12=0000000000000000 R13=0000000000000000
01368000000i[CPU0 ] | R14=0000000000000000 R15=0000000000000000
01368000000i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf zf af pf cf
01368000000i[CPU0 ] | SEG selector base limit G D
01368000000i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
01368000000i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1
01368000000i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 000fffff 1 1
01368000000i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1
01368000000i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1
01368000000i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1
01368000000i[CPU0 ] | GS:0010( 0002| 0| 0) 00000000 000fffff 1 1
01368000000i[CPU0 ] | MSR_FS_BASE:0000000000000000
01368000000i[CPU0 ] | MSR_GS_BASE:0000000000000000
01368000000i[CPU0 ] | RIP=000000000000d3f9 (000000000000d3f9)
01368000000i[CPU0 ] | CR0=0xe0000011 CR1=0x0 CR2=0x0000000000000000
01368000000i[CPU0 ] | CR3=0x00306000 CR4=0x00000000
01368000000i[CPU0 ] >> add esp, 0x00000010 : 83C410
01368000000i[CMOS ] Last time is 1240781579 (Sun Apr 26 23:32:59 2009)
01368000000i[ ] restoring default signal behavior
01368000000i[CTRL ] quit_sim called with exit code 1
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
01368000000p[WGUI ] >>PANIC<< POWER button turned off.
01368000000i[CPU0 ] CPU is in protected mode (halted)
01368000000i[CPU0 ] CS.d_b = 32 bit
01368000000i[CPU0 ] SS.d_b = 32 bit
01368000000i[CPU0 ] EFER   = 0x00000000
01368000000i[CPU0 ] | RAX=000000000000008f  RBX=000000000000d502
01368000000i[CPU0 ] | RCX=00000000000b8000  RDX=00000000000003d5
01368000000i[CPU0 ] | RSP=000000000018ff1c  RBP=000000000018ff44
01368000000i[CPU0 ] | RSI=000000000018ffd8  RDI=000000000018fff0
01368000000i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
01368000000i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
01368000000i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
01368000000i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
01368000000i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf zf af pf cf
01368000000i[CPU0 ] | SEG selector     base    limit G D
01368000000i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
01368000000i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
01368000000i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
01368000000i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
01368000000i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 1 1
01368000000i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 1 1
01368000000i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 1 1
01368000000i[CPU0 ] |  MSR_FS_BASE:0000000000000000
01368000000i[CPU0 ] |  MSR_GS_BASE:0000000000000000
01368000000i[CPU0 ] | RIP=000000000000d3f9 (000000000000d3f9)
01368000000i[CPU0 ] | CR0=0xe0000011 CR1=0x0 CR2=0x0000000000000000
01368000000i[CPU0 ] | CR3=0x00306000 CR4=0x00000000
01368000000i[CPU0 ] >> add esp, 0x00000010 : 83C410
01368000000i[CMOS ] Last time is 1240781579 (Sun Apr 26 23:32:59 2009)
01368000000i[     ] restoring default signal behavior
01368000000i[CTRL ] quit_sim called with exit code 1


This I did not understand:
Zitat:
remove any calls to the scheduler and call it the way it will fault. So it will give us the right values.


The timer_handler:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void timer_handler(struct regs* r)
{
    ++timer_ticks;
    if (eticks)
        --eticks;

    //TEST
    static ULONG c = 0;
    ++c;
    if(c>200)
    {
      task_switch();
      settextcolor(getpid(),0);
      c=0;
    }
    //TEST
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void timer_handler(struct regs* r)
{
++timer_ticks;
if (eticks)
--eticks;

//TEST
static ULONG c = 0;
++c;
if(c>200)
{
task_switch();
settextcolor(getpid(),0);
c=0;
}
//TEST
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void timer_handler(struct regs* r)
{
    ++timer_ticks;
    if (eticks)
        --eticks;

    //TEST
    static ULONG c = 0;
    ++c;
    if(c>200)
    {
      task_switch();
      settextcolor(getpid(),0);
      c=0;
    }
    //TEST
}

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:38:30 26.04.2009, insgesamt 1-mal bearbeitet
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 23:42:53 26.04.2009   Titel:              Zitieren

You see that task_switch() will never be called? you declare a variable, does 1 time incrmeent, and checks for 200?



///////////

Ok, good.

Try the same, but than in the assbly part itself, each time one line, until the GPF occurs. then we know which opcode makes the fault. (Maybe it is just the jump).

If that fails, try getting all values of the registers when GPF triggers (print out all registers etc from the Registers given at the handler and post them, and maybe a disassembly of your schedule() (so we can exactly see when it trigger according to RIP's. We cant put cli hlt etc into the assembly part

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix


Zuletzt bearbeitet von PHPnerd am 23:44:39 26.04.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:04:08 27.04.2009   Titel:              Zitieren

PHPnerd schrieb:
You see that task_switch() will never be called? you declare a variable, does 1 time incrmeent, and checks for 200?

c is declared static, therefore it works:
http://ee.hawaii.edu/~tep/EE160/Book/chap14/subsection2.1.1.6.html (static variables)
C/C++ Code:
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
    static ULONG c = 0;
    ++c;
    if(c>200)
    {
      printformat("task_switch\n");
      task_switch();
      settextcolor(getpid(),0);
      c=0;
    }
C/C++ Code:
1
2
3
4
5
6
7
8
9
static ULONG c = 0;
++c;
if(c>200)
{
printformat("task_switch\n");
task_switch();
settextcolor(getpid(),0);
c=0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
    static ULONG c = 0;
    ++c;
    if(c>200)
    {
      printformat("task_switch\n");
      task_switch();
      settextcolor(getpid(),0);
      c=0;
    }

Zitat:
task_switch
!!!!#!!!!#!!!!#

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:07:18 27.04.2009, insgesamt 1-mal bearbeitet
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 00:11:50 27.04.2009   Titel:              Zitieren

What is the info from the #GP?

// PHP

_________________
Being Dutch. Talking English. On a German community.

Jinix
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:54:53 27.04.2009   Titel:              Zitieren

Currently, I do not get GPF again. I have done the following:

1) I used the clobber list:
C/C++ Code:
asm volatile("..." : : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr) : "ebx", "edx");
C/C++ Code:
asm volatile("..." : : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr) : "ebx", "edx");
C/C++ Code:
asm volatile("..." : : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr) : "ebx", "edx");

ebx and edx were accepted, edi and esi gave failure ("can't find a register in class `GENERAL_REGS' while reloading `asm'").
2) I accelerated the task switch:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
    //TEST
    static ULONG c = 0;
    ++c;
    if(c>0)
    {
      printformat("task_switch\n");
      task_switch();
      settextcolor(getpid(),0);
      c=0;
    }
    //TEST
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
//TEST
static ULONG c = 0;
++c;
if(c>0)
{
printformat("task_switch\n");
task_switch();
settextcolor(getpid(),0);
c=0;
}
//TEST
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
    //TEST
    static ULONG c = 0;
    ++c;
    if(c>0)
    {
      printformat("task_switch\n");
      task_switch();
      settextcolor(getpid(),0);
      c=0;
    }
    //TEST


output at bochs:
Zitat:

!task_switch
!task_switch
!task_switch
!HEAP start: 40081000h end: 40100000h max: 4FFFF000h kernel mode: 0 read-only: 0

ask_switch
!
hole 40081000h hole-size: 0007F000h
after create_heap: placement_address: 0030C020h allocated frames: 795
ask_switch
!
task_switch
!tasking install
!tasking install
after moving stack, ESP: 0018FFD0h ddress: 0030C020h
After k_mallocing kernel_stack), placement_address: 0030C020h kernel_stack: 4010
1000h
VFS & RAM Disk install
ask_switch
!!!!#!!!!#!!!!##

placement_address after ram disk install: 40100000h
ramdisk_start: 40081000h file_data_start: 0000A2F0h file_data_end: 0000B662h
ask_switch
!Page Fault (page not present) at 00D2ECF0h - EIP: 0000D2C9h
Page Fault >>> Exception. System Halted! <<<

As you can see, there is one failure free task switch.
But the output looks disturbed.

Zitat:
What is the info from the #GP?

Ihave no specific info from GPF. You mentioned a failure analysis routine. Do you have a link for that code or a table with the error flag meanings?

I post the current version with the problematic task switch in the time handler:
http://www.henkessoft.de/OS_Dev/Downloads/37.zip

I use gcc.exe (version 3.1) and ld.exe (version 2.13) due to linking aout-format of NASM
http://www.osdever.net/downloads/compilers/DJGPP-Installer-nocpp.exe

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:05:50 27.04.2009, insgesamt 1-mal bearbeitet
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 00:59:12 27.04.2009   Titel:              Zitieren

Well done!

Just, remove the ! and # and task switch printouts :P

Do you have a keyboard handler? Try to make a simple console system. Use the Function keys to switch to another console. Each task is linked to a console. When switching console, you copy the data from 0xb8000 to the data of current console. And write data of new console to 0xb8000.

Something like that will work.

Then, you will see on each console the output of each task apart :) nice for testing your multitasker.

About the GP: The code of JamesM tutorials uses the structure registers. Filled in some assebly code. Use that structure to printout eip, esp etc, and get the control registers and print them out too. Error flag meanings can be found in the Intel Manual Volume 1.

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix


Zuletzt bearbeitet von PHPnerd am 01:25:38 27.04.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:32:45 27.04.2009   Titel:              Zitieren

Zitat:
Try to make a simple console system. Use the Function keys to switch to another console. Each task is linked to a console.
This sounds good. I have a keyboard handler and an own circular key queue. A console in your concept is an array of 4000 Bytes which is swapped with the video RAM by the task switcher or by function keys? Not bad.

Zitat:
Well done!

Now I have exchanged the GPF for Page Faults:
Zitat:
paging install
frames: 00300000h NFRAMES: 524288
kernel_directory->physicalAddr: 00306000h
placement_address: 0030B000h allocated frames: 795
HEAP start: 40081000h end: 40100000h max: 4FFFF000h kernel mode: 0 read-only: 0
hole start: 40081000h end: 40100000h max: 4FFFF000h kernel mode: 0 read-only: 0
hole 40081000h hole-size: 0007F000h
after create_heap: placement_address: 0030C020h allocated frames: 795
tasking install
after moving stack, ESP: 0018FFD0h
After init first task (kernel task), placement_address: 0030C020h
After k_mallocing kernel_stack), placement_address: 0030C020h kernel_stack: 4010
1000h
VFS & RAM Disk install
placement_address after ram disk install: 40200000h
ramdisk_start: 40081000h file_data_start: 0000A2E0h file_data_end: 0000B652h
After set_kernel_stack ==> tss_entry.esp0: 40101800h
>>> IRQ 127 <<<
Hello, user world!
Found file dev
(directory)
Found file f1
contents: "PrettyOS: My filename is test1.txt!"
age Fault (page not present) at 0F000123h - EIP: 0F000123h
Page Fault >>> Exception. System Halted! <<<

Dependent on the value of c in the timer handler the page fault comes earlier or later. With c=2000 (means 20 sec) it came with the fisrt task switch:
Zitat:
ksldfgjskldfgjldfksjgklsdfgklsdfjgklsdfjglksdfjglksdfjgsklgjklsd;jglkdsfjglkdsfg
jlsk;dfjgskldfjgslkdjglk;sdgjldk;sfjglk;sdfjgl;ksdjgkl;sdgjklsdfgjsl;dkjglsdk;fg
js 0000D794h H: 0000D794h WRITE: 156 Read: 156 *T: g 103 *H: g 103
T: 0000D78Eh H: 0000D78Eh WRITE: 162 Read: 162 *T: f 102 *H: f 102
Page Fault (page not present) at 0040FC20h - EIP: 0040FC20h
Page Fault >>> Exception. System Halted! <<<
...

Hence, I think the EIP gets a wrong value under certain circumstances.
The function read_eip() is defined in Assembler (process.asm):
Code:
global _read_eip
_read_eip:
    pop eax               ; Get the return address
    jmp eax               ; Return. Can't use RET because return
                          ; address popped off the stack.
Code:
global _read_eip
_read_eip:
pop eax ; Get the return address
jmp eax ; Return. Can't use RET because return
; address popped off the stack.
Code:
global _read_eip
_read_eip:
    pop eax               ; Get the return address
    jmp eax               ; Return. Can't use RET because return
                          ; address popped off the stack.


Zitat:
About the GP: The code of JamesM tutorials uses the structure registers. Filled in some assebly code. Use that structure to printout eip, esp etc, and get the control registers and print them out too. Error flag meanings can be found in the Intel Manual Volume 1.

Thanks, great idea.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:03:40 27.04.2009, insgesamt 2-mal bearbeitet
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 10:57:58 27.04.2009   Titel:              Zitieren

read_eip() is fine. But you could try:
Code:
readEip:
    pop eax
    push eax
    ret
Code:
readEip:
pop eax
push eax
ret
Code:
readEip:
    pop eax
    push eax
    ret


You are having some drivers, right?

When switching tasks, you change the registers, and the cr3. When a task does something with a device, and there is not good code implemented to handle multitasking in device drivers, the device will move data. But when in that time a task switch occurs, some problems may come. The task switch at 20seconds is very bad. The process doesn't need to know it is EVER switched. 100Hz may be nice (100 switches each second). Play something with it.

Consoles: you got it :)

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef struct
{
    uint32_t id; // console id, just for making some things easier
    uint8_t keystroke[KEYSTROKE_LENGTH]; // make this the way you did with keystrokes
    uint32_t *videoBuffer; // a pointer to some place in memory, size: width*height*2 bytes (probably 80*25*2)
    uint32_t cursorX;
    uint32_t cursorY; // coordinates of the cursor for this console
    uint8_t colorAttribute; // attributes curently used by console
} console_t

struct task
{
    ....
    console_t *console; // put console in task
    ....
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef struct
{
uint32_t id; // console id, just for making some things easier
uint8_t keystroke[KEYSTROKE_LENGTH]; // make this the way you did with keystrokes
uint32_t *videoBuffer; // a pointer to some place in memory, size: width*height*2 bytes (probably 80*25*2)
uint32_t cursorX;
uint32_t cursorY; // coordinates of the cursor for this console
uint8_t colorAttribute; // attributes curently used by console
} console_t

struct task
{
....
console_t *console; // put console in task
....
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef struct
{
    uint32_t id; // console id, just for making some things easier
    uint8_t keystroke[KEYSTROKE_LENGTH]; // make this the way you did with keystrokes
    uint32_t *videoBuffer; // a pointer to some place in memory, size: width*height*2 bytes (probably 80*25*2)
    uint32_t cursorX;
    uint32_t cursorY; // coordinates of the cursor for this console
    uint8_t colorAttribute; // attributes curently used by console
} console_t

struct task
{
    ....
    console_t *console; // put console in task
    ....
};


That is an example for a console structure. Be sure of:
- Create one console when initializing screen (VGA), set it into a global variable, currentConsole
- Be sure the functions work to the right console. Each time a task switch occurs, it should use another console structure. But not the currentConsole, because that is the console currently SHOWED. En when not watching task 2, it should be able to print text, so the user can see it later.

You can determine the console of the current task by just using currentTask->console(->cursorX, ->cursorY etc.)

It is simple, but much work. Also be sure to make a backup from all you have first, it is a lot of work to remove the console code from your VGA driver.

Good luck, I think it will work with this.

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix


Zuletzt bearbeitet von PHPnerd am 12:08:39 27.04.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:01:58 27.04.2009   Titel:              Zitieren

Code:
global _read_eip
_read_eip:
    pop eax
    push eax
    ret
Code:
global _read_eip
_read_eip:
pop eax
push eax
ret
Code:
global _read_eip
_read_eip:
    pop eax
    push eax
    ret


... looks better and works fine, but does not help with the page fault due to the strange EIP. :rolleyes:

Thanks for the consoles' code. Nice feature. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:03:30 27.04.2009, insgesamt 1-mal bearbeitet
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 21:16:23 27.04.2009   Titel:              Zitieren

Does the page fault trigger after setting eip, or after setting cr3? or something else?

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 03:59:07 28.04.2009   Titel:              Zitieren

Ich habe mit HLT im asm-code probiert, der page fault erfolgt beim jmp *%%ecx;
Was bedeutet eigentlich dieser * vor %%ecx ? Wenn ich ihn weglasse, passiert genau das gleiche.
Ich habe eip,esp,ebp,cur_dir->phys direkt vor dem asm-code geloggt:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
printformat("task_switch before asm: eip: %x esp: %x ebp: %x cur_dir->phys: %x\n",eip,esp,ebp,current_directory->physicalAddr);

    asm volatile("         \
      cli;                 \
      mov %0, %%ecx;       \
      mov %1, %%esp;       \
      mov %2, %%ebp;       \
      mov %3, %%cr3;       \
      mov $0x12345, %%eax; \
      sti;                 \
      jmp *%%ecx;          
"
      :: "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr)
      : "ebx", "edx");
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
printformat("task_switch before asm: eip: %x esp: %x ebp: %x cur_dir->phys: %x\n",eip,esp,ebp,current_directory->physicalAddr);

asm volatile(" \
cli; \
mov %0, %%ecx; \
mov %1, %%esp; \
mov %2, %%ebp; \
mov %3, %%cr3; \
mov $0x12345, %%eax; \
sti; \
jmp *%%ecx;
"
:: "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr)
: "ebx", "edx");
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
printformat("task_switch before asm: eip: %x esp: %x ebp: %x cur_dir->phys: %x\n",eip,esp,ebp,current_directory->physicalAddr);

    asm volatile("         \
      cli;                 \
      mov %0, %%ecx;       \
      mov %1, %%esp;       \
      mov %2, %%ebp;       \
      mov %3, %%cr3;       \
      mov $0x12345, %%eax; \
      sti;                 \
      jmp *%%ecx;          
"
      :: "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr)
      : "ebx", "edx");

Schalten nach 0,01 sec:
Zitat:
task_switch before asm: eip: 0000D306h esp: 0018FF3Ch ebp: 0018FF54h cur_dir->phys: 00001000h
Page Fault (page not present) at 0F000123h - EIP: 0F000123h

Schalten nach 1 sec: (dann wurden zumindest die neuen Tasks angelegt)
Zitat:
task_switch before asm: eip: 0000D4C2h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0041E000h
Page Fault (page not present) at 0040FCA0h - EIP: 0040FCA0h

Wenn ich das richtig sehe, liegt das Problem eher bei current_directory->physicalAddr als bei eip, oder?.

Im Lowlevel Forum meinte man dazu, dass das Problem vom C-Compiler kommen könnte (nicht alle register wurden gespeichert und zurück geschrieben), und man empfahl mir das komplett in Assembler zu machen analog tyndur. :rolleyes:

Ohne die Clobber List kommt übrigens wieder der GPF:
C/C++ Code:
...
jmp %%ecx;           "
: : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr) );
C/C++ Code:
...
jmp %%ecx; "
: : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr) );
C/C++ Code:
...
jmp %%ecx;           "
: : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr) );

Zitat:
task_switch before asm: eip: 0000D4C2h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0041E000h
General Protection Fault >>> Exception. System Halted! <<<


Erst, wenn ich sowohl ebx als auch edx "clobbere", kommt der PF, einzeln GPF. edi und esi kann ich leider nicht clobbern wegen Fehlermeldung des Compilers.

Fundstelle zur Clobber List:
http://groups.google.im/group/comp.lang.asm.x86/browse_thread/thread/cf89391bb64126f7
Zitat:
DJ Delorie: The clobber list tells gcc which registers (or memory) are changed by the asm, but not listed as an output. That way, gcc knows not to leave a value in there and expect it to be the same after the asm. If you clobber enough registers, gcc has to start saving values on the stack instead of in unclobbered registers. ... You can overlap clobbers and *input* registers.


Das kommt mir inzwischen alles suspekt vor, was gcc da schafft. Mit dem Clobbern habe ich wenig Erfahrung.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 04:36:03 28.04.2009, insgesamt 6-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 08:20:09 28.04.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Was bedeutet eigentlich dieser * vor %%ecx ?...

Siehe hier http://www.c-plusplus.de/forum/viewtopic-var-t-is-238553.html
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 12:55:17 28.04.2009   Titel:              Zitieren

Did you try to get the assembly code generated by GCC?

Are you sure that the currentDir->physical is physical?
And are the new page tables, and page directories you made, page aligned?

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:26:10 28.04.2009   Titel:              Zitieren

Zitat:
Did you try to get the assembly code generated by GCC?
Yes, I was interested in the consequence of putting (or not putting) registers into the clobber list. Here is the result:

clobbering ebx and edx ==> Page Fault:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
    asm volatile("         \
      cli;                 \
      mov %0, %%ecx;       \
      mov %1, %%esp;       \
      mov %2, %%ebp;       \
      mov %3, %%cr3;       \
      mov $0x12345, %%eax; \
      sti;                 \
      jmp %%ecx;          
"
      : : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr)
      : "ebx","edx" );
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
asm volatile(" \
cli; \
mov %0, %%ecx; \
mov %1, %%esp; \
mov %2, %%ebp; \
mov %3, %%cr3; \
mov $0x12345, %%eax; \
sti; \
jmp %%ecx;
"
: : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr)
: "ebx","edx" );
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
    asm volatile("         \
      cli;                 \
      mov %0, %%ecx;       \
      mov %1, %%esp;       \
      mov %2, %%ebp;       \
      mov %3, %%cr3;       \
      mov $0x12345, %%eax; \
      sti;                 \
      jmp %%ecx;          
"
      : : "r"(eip), "r"(esp), "r"(ebp), "r"(current_directory->physicalAddr)
      : "ebx","edx" );


objdump task.o -D > task.txt
Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
 35f:    fa                       cli    
 360:    89 f1                    mov    %esi,%ecx
 362:    89 fc                    mov    %edi,%esp
 364:    89 cd                    mov    %ecx,%ebp
 366:    0f 22 d8                 mov    %eax,%cr3
 369:    b8 45 23 01 00           mov    $0x12345,%eax
 36e:    fb                       sti    
 36f:    ff e1                    jmp    *%ecx
Code:
1
2
3
4
5
6
7
8
35f: fa cli
360: 89 f1 mov %esi,%ecx
362: 89 fc mov %edi,%esp
364: 89 cd mov %ecx,%ebp
366: 0f 22 d8 mov %eax,%cr3
369: b8 45 23 01 00 mov $0x12345,%eax
36e: fb sti
36f: ff e1 jmp *%ecx
Code:
1
2
3
4
5
6
7
8
 35f:    fa                       cli    
 360:    89 f1                    mov    %esi,%ecx
 362:    89 fc                    mov    %edi,%esp
 364:    89 cd                    mov    %ecx,%ebp
 366:    0f 22 d8                 mov    %eax,%cr3
 369:    b8 45 23 01 00           mov    $0x12345,%eax
 36e:    fb                       sti    
 36f:    ff e1                    jmp    *%ecx


The first thing you see is why we cannot clobber edi and esi, too.

Empty clobber list ==> GPF
Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
351:    fa                       cli    
 352:    89 d9                    mov    %ebx,%ecx
 354:    89 f4                    mov    %esi,%esp
 356:    89 fd                    mov    %edi,%ebp
 358:    0f 22 d8                 mov    %eax,%cr3
 35b:    b8 45 23 01 00           mov    $0x12345,%eax
 360:    fb                       sti    
 361:    ff e1                    jmp    *%ecx
Code:
1
2
3
4
5
6
7
8
351: fa cli
352: 89 d9 mov %ebx,%ecx
354: 89 f4 mov %esi,%esp
356: 89 fd mov %edi,%ebp
358: 0f 22 d8 mov %eax,%cr3
35b: b8 45 23 01 00 mov $0x12345,%eax
360: fb sti
361: ff e1 jmp *%ecx
Code:
1
2
3
4
5
6
7
8
351:    fa                       cli    
 352:    89 d9                    mov    %ebx,%ecx
 354:    89 f4                    mov    %esi,%esp
 356:    89 fd                    mov    %edi,%ebp
 358:    0f 22 d8                 mov    %eax,%cr3
 35b:    b8 45 23 01 00           mov    $0x12345,%eax
 360:    fb                       sti    
 361:    ff e1                    jmp    *%ecx


clobbering ebx ==> GPF
Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
 35f:    fa                       cli    
 360:    89 f1                    mov    %esi,%ecx
 362:    89 fc                    mov    %edi,%esp
 364:    89 d5                    mov    %edx,%ebp
 366:    0f 22 d8                 mov    %eax,%cr3
 369:    b8 45 23 01 00           mov    $0x12345,%eax
 36e:    fb                       sti    
 36f:    ff e1                    jmp    *%ecx
Code:
1
2
3
4
5
6
7
8
35f: fa cli
360: 89 f1 mov %esi,%ecx
362: 89 fc mov %edi,%esp
364: 89 d5 mov %edx,%ebp
366: 0f 22 d8 mov %eax,%cr3
369: b8 45 23 01 00 mov $0x12345,%eax
36e: fb sti
36f: ff e1 jmp *%ecx
Code:
1
2
3
4
5
6
7
8
 35f:    fa                       cli    
 360:    89 f1                    mov    %esi,%ecx
 362:    89 fc                    mov    %edi,%esp
 364:    89 d5                    mov    %edx,%ebp
 366:    0f 22 d8                 mov    %eax,%cr3
 369:    b8 45 23 01 00           mov    $0x12345,%eax
 36e:    fb                       sti    
 36f:    ff e1                    jmp    *%ecx


clobbering edx ==> GPF
Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
 351:    fa                       cli    
 352:    89 d9                    mov    %ebx,%ecx
 354:    89 f4                    mov    %esi,%esp
 356:    89 fd                    mov    %edi,%ebp
 358:    0f 22 d8                 mov    %eax,%cr3
 35b:    b8 45 23 01 00           mov    $0x12345,%eax
 360:    fb                       sti    
 361:    ff e1                    jmp    *%ecx
Code:
1
2
3
4
5
6
7
8
351: fa cli
352: 89 d9 mov %ebx,%ecx
354: 89 f4 mov %esi,%esp
356: 89 fd mov %edi,%ebp
358: 0f 22 d8 mov %eax,%cr3
35b: b8 45 23 01 00 mov $0x12345,%eax
360: fb sti
361: ff e1 jmp *%ecx
Code:
1
2
3
4
5
6
7
8
 351:    fa                       cli    
 352:    89 d9                    mov    %ebx,%ecx
 354:    89 f4                    mov    %esi,%esp
 356:    89 fd                    mov    %edi,%ebp
 358:    0f 22 d8                 mov    %eax,%cr3
 35b:    b8 45 23 01 00           mov    $0x12345,%eax
 360:    fb                       sti    
 361:    ff e1                    jmp    *%ecx

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:27:33 28.04.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:11:15 28.04.2009   Titel:              Zitieren

Zitat:
Are you sure that the currentDir->physical is physical?

hmmm, I have to look deeper into that. EDIT:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// This structure defines a 'task' - a process.
typedef struct task
{
    int id;                           // Process ID.
    ULONG esp, ebp;                   // Stack and base pointers.
    ULONG eip;                        // Instruction pointer.
    page_directory_t* page_directory; // Page directory.
    ULONG kernel_stack;               // Kernel stack location.
    struct task* next;                // The next task in a linked list.
} task_t;

//in fork():
page_directory_t* directory = clone_directory(current_directory);
//...
new_task->page_directory = directory;
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// This structure defines a 'task' - a process.
typedef struct task
{
int id; // Process ID.
ULONG esp, ebp; // Stack and base pointers.
ULONG eip; // Instruction pointer.
page_directory_t* page_directory; // Page directory.
ULONG kernel_stack; // Kernel stack location.
struct task* next; // The next task in a linked list.
} task_t;

//in fork():
page_directory_t* directory = clone_directory(current_directory);
//...
new_task->page_directory = directory;
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// This structure defines a 'task' - a process.
typedef struct task
{
    int id;                           // Process ID.
    ULONG esp, ebp;                   // Stack and base pointers.
    ULONG eip;                        // Instruction pointer.
    page_directory_t* page_directory; // Page directory.
    ULONG kernel_stack;               // Kernel stack location.
    struct task* next;                // The next task in a linked list.
} task_t;

//in fork():
page_directory_t* directory = clone_directory(current_directory);
//...
new_task->page_directory = directory;

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
page_directory_t *clone_directory(page_directory_t *src)
{
    ULONG phys;
    page_directory_t *dir = (page_directory_t*) k_malloc( sizeof(page_directory_t),1,&phys );
    k_memset( dir, 0, sizeof(page_directory_t) );
    ULONG offset = (ULONG)dir->tablesPhysical - (ULONG)dir;
    dir->physicalAddr = phys + offset;
    int i;
    for(i=0; i<1024; ++i)
    {
        if (!src->tables[i])
            continue;
        if (kernel_directory->tables[i] == src->tables[i])
        {
            dir->tables[i] = src->tables[i];
            dir->tablesPhysical[i] = src->tablesPhysical[i];
        }
        else
        {
            ULONG phys;
            dir->tables[i] = clone_table(src->tables[i], &phys);
            dir->tablesPhysical[i] = phys | 0x07;
        }
    }
    return dir;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
page_directory_t *clone_directory(page_directory_t *src)
{
ULONG phys;
page_directory_t *dir = (page_directory_t*) k_malloc( sizeof(page_directory_t),1,&phys );
k_memset( dir, 0, sizeof(page_directory_t) );
ULONG offset = (ULONG)dir->tablesPhysical - (ULONG)dir;
dir->physicalAddr = phys + offset;
int i;
for(i=0; i<1024; ++i)
{
if (!src->tables[i])
continue;
if (kernel_directory->tables[i] == src->tables[i])
{
dir->tables[i] = src->tables[i];
dir->tablesPhysical[i] = src->tablesPhysical[i];
}
else
{
ULONG phys;
dir->tables[i] = clone_table(src->tables[i], &phys);
dir->tablesPhysical[i] = phys | 0x07;
}
}
return dir;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
page_directory_t *clone_directory(page_directory_t *src)
{
    ULONG phys;
    page_directory_t *dir = (page_directory_t*) k_malloc( sizeof(page_directory_t),1,&phys );
    k_memset( dir, 0, sizeof(page_directory_t) );
    ULONG offset = (ULONG)dir->tablesPhysical - (ULONG)dir;
    dir->physicalAddr = phys + offset;
    int i;
    for(i=0; i<1024; ++i)
    {
        if (!src->tables[i])
            continue;
        if (kernel_directory->tables[i] == src->tables[i])
        {
            dir->tables[i] = src->tables[i];
            dir->tablesPhysical[i] = src->tablesPhysical[i];
        }
        else
        {
            ULONG phys;
            dir->tables[i] = clone_table(src->tables[i], &phys);
            dir->tablesPhysical[i] = phys | 0x07;
        }
    }
    return dir;
}

I think, it is.


Zitat:
And are the new page tables, and page directories you made, page aligned?
That is an interesting question! I use task_switch() with clobbering ebx and edx leading to the page fault. The new tasks have just been generated by fork():
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
int fork()
{
    cli();
    task_t* parent_task = (task_t*)current_task;
    page_directory_t* directory = clone_directory(current_directory);
    task_t* new_task = (task_t*) k_malloc( sizeof(task_t),0,0 ); // <== second 0 means not aligned, 1 means aligned !
    new_task->id  = next_pid++;
    new_task->esp = new_task->ebp = 0;
    new_task->eip = 0;
    new_task->page_directory = directory;
    current_task->kernel_stack = k_malloc(KERNEL_STACK_SIZE,1,0);
    new_task->next = 0;

    task_t* tmp_task = (task_t*)ready_queue;
    while (tmp_task->next)
        tmp_task = tmp_task->next;
    tmp_task->next = new_task;

    ULONG eip = read_eip();

    if (current_task == parent_task)
    {
        ULONG esp; asm volatile("mov %%esp, %0" : "=r"(esp));
        ULONG ebp; asm volatile("mov %%ebp, %0" : "=r"(ebp));
        new_task->esp = esp;
        new_task->ebp = ebp;
        new_task->eip = eip;

        sti();              
        return new_task->id;
    }
    else
        return
0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
int fork()
{
cli();
task_t* parent_task = (task_t*)current_task;
page_directory_t* directory = clone_directory(current_directory);
task_t* new_task = (task_t*) k_malloc( sizeof(task_t),0,0 ); // <== second 0 means not aligned, 1 means aligned !
new_task->id = next_pid++;
new_task->esp = new_task->ebp = 0;
new_task->eip = 0;
new_task->page_directory = directory;
current_task->kernel_stack = k_malloc(KERNEL_STACK_SIZE,1,0);
new_task->next = 0;

task_t* tmp_task = (task_t*)ready_queue;
while (tmp_task->next)
tmp_task = tmp_task->next;
tmp_task->next = new_task;

ULONG eip = read_eip();

if (current_task == parent_task)
{
ULONG esp; asm volatile("mov %%esp, %0" : "=r"(esp));
ULONG ebp; asm volatile("mov %%ebp, %0" : "=r"(ebp));
new_task->esp = esp;
new_task->ebp = ebp;
new_task->eip = eip;

sti();
return new_task->id;
}
else
return
0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
int fork()
{
    cli();
    task_t* parent_task = (task_t*)current_task;
    page_directory_t* directory = clone_directory(current_directory);
    task_t* new_task = (task_t*) k_malloc( sizeof(task_t),0,0 ); // <== second 0 means not aligned, 1 means aligned !
    new_task->id  = next_pid++;
    new_task->esp = new_task->ebp = 0;
    new_task->eip = 0;
    new_task->page_directory = directory;
    current_task->kernel_stack = k_malloc(KERNEL_STACK_SIZE,1,0);
    new_task->next = 0;

    task_t* tmp_task = (task_t*)ready_queue;
    while (tmp_task->next)
        tmp_task = tmp_task->next;
    tmp_task->next = new_task;

    ULONG eip = read_eip();

    if (current_task == parent_task)
    {
        ULONG esp; asm volatile("mov %%esp, %0" : "=r"(esp));
        ULONG ebp; asm volatile("mov %%ebp, %0" : "=r"(ebp));
        new_task->esp = esp;
        new_task->ebp = ebp;
        new_task->eip = eip;

        sti();              
        return new_task->id;
    }
    else
        return
0;
}


1) not aligned, phys=0:
C/C++ Code:
   // Create a new process.
    task_t* new_task = (task_t*) k_malloc( sizeof(task_t),0,0 );
C/C++ Code:
// Create a new process.
task_t* new_task = (task_t*) k_malloc( sizeof(task_t),0,0 );
C/C++ Code:
   // Create a new process.
    task_t* new_task = (task_t*) k_malloc( sizeof(task_t),0,0 );

Zitat:
SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000018h, DS: 00000020h
task_switch before asm: eip: 0000D4C2h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->ph
ys: 0041E000h
Page Fault (page not present) at 0040FCA0h - EIP: 0040FCA0h



2) aligned, phys=0:
C/C++ Code:
   // Create a new process.
    task_t* new_task = (task_t*) k_malloc( sizeof(task_t),1,0 );
C/C++ Code:
// Create a new process.
task_t* new_task = (task_t*) k_malloc( sizeof(task_t),1,0 );
C/C++ Code:
   // Create a new process.
    task_t* new_task = (task_t*) k_malloc( sizeof(task_t),1,0 );

==> reboot


3) not aligned, phys=1:
C/C++ Code:
   // Create a new process.
    task_t* new_task = (task_t*) k_malloc( sizeof(task_t),0,1 );
C/C++ Code:
// Create a new process.
task_t* new_task = (task_t*) k_malloc( sizeof(task_t),0,1 );
C/C++ Code:
   // Create a new process.
    task_t* new_task = (task_t*) k_malloc( sizeof(task_t),0,1 );

Zitat:
fork() returned: 00000002h and getpid() returned: 00000001h
Page Fault (page not presentread-only - write operation) at 4010B000h - EIP: 00009BC0h



4)aligned, phys=1:
C/C++ Code:
   // Create a new process.
    task_t* new_task = (task_t*) k_malloc( sizeof(task_t),1,1 );
C/C++ Code:
// Create a new process.
task_t* new_task = (task_t*) k_malloc( sizeof(task_t),1,1 );
C/C++ Code:
   // Create a new process.
    task_t* new_task = (task_t*) k_malloc( sizeof(task_t),1,1 );

Zitat:
Page Fault (page not presentread-only - write operation) at 4010C000h - EIP: 00009BC0h


Hence, the increase of placement_address seems to be important. Alignment has no effect.

k_malloc:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
ULONG k_malloc(ULONG size, UCHAR align, ULONG* phys)
{
    if( kheap!=0 )
    {
        void* addr = alloc(size, align, kheap);
        if (phys != 0)
        {
            page_t* page = get_page((ULONG)addr, 0, kernel_directory);
            *phys = page->frame_addr * PAGESIZE + ((ULONG)addr&0xFFF);
        }
        return (ULONG)addr;
    }
    else
    {
        if( align == 1 && (placement_address & 0xFFFFF000) )
        {
            // Align the placement address;
            placement_address &= 0xFFFFF000;
            placement_address += PAGESIZE;
        }
        if( phys )
        {
            *phys = placement_address;
        }
        ULONG temp = placement_address;
        placement_address += size;     // new placement_address is increased
        return temp;                   // old placement_address is returned
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
ULONG k_malloc(ULONG size, UCHAR align, ULONG* phys)
{
if( kheap!=0 )
{
void* addr = alloc(size, align, kheap);
if (phys != 0)
{
page_t* page = get_page((ULONG)addr, 0, kernel_directory);
*phys = page->frame_addr * PAGESIZE + ((ULONG)addr&0xFFF);
}
return (ULONG)addr;
}
else
{
if( align == 1 && (placement_address & 0xFFFFF000) )
{
// Align the placement address;
placement_address &= 0xFFFFF000;
placement_address += PAGESIZE;
}
if( phys )
{
*phys = placement_address;
}
ULONG temp = placement_address;
placement_address += size; // new placement_address is increased
return temp; // old placement_address is returned
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
ULONG k_malloc(ULONG size, UCHAR align, ULONG* phys)
{
    if( kheap!=0 )
    {
        void* addr = alloc(size, align, kheap);
        if (phys != 0)
        {
            page_t* page = get_page((ULONG)addr, 0, kernel_directory);
            *phys = page->frame_addr * PAGESIZE + ((ULONG)addr&0xFFF);
        }
        return (ULONG)addr;
    }
    else
    {
        if( align == 1 && (placement_address & 0xFFFFF000) )
        {
            // Align the placement address;
            placement_address &= 0xFFFFF000;
            placement_address += PAGESIZE;
        }
        if( phys )
        {
            *phys = placement_address;
        }
        ULONG temp = placement_address;
        placement_address += size;     // new placement_address is increased
        return temp;                   // old placement_address is returned
    }
}


Alles verflixt komplex. Ich weiß hier nicht genau, was ich mit "phys" anfangen soll. 0x1 ist sicher kein brauchbarer Wert. Warum beeinflusst das EIP???

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 21:06:57 28.04.2009, insgesamt 5-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:44:03 28.04.2009   Titel:              Zitieren

Ich habe nun noch eine Variable für die physikalische Adresse in fork() eingefügt, um diese dort auszugeben:
C/C++ Code:
    // Create a new process.
    ULONG phys;
    task_t* new_task = (task_t*) k_malloc( sizeof(task_t),0,&phys );
    printformat("placement_address after creating a new process: %x phys: %x\n", placement_address, phys);
C/C++ Code:
// Create a new process.
ULONG phys;
task_t* new_task = (task_t*) k_malloc( sizeof(task_t),0,&phys );
printformat("placement_address after creating a new process: %x phys: %x\n", placement_address, phys);
C/C++ Code:
    // Create a new process.
    ULONG phys;
    task_t* new_task = (task_t*) k_malloc( sizeof(task_t),0,&phys );
    printformat("placement_address after creating a new process: %x phys: %x\n", placement_address, phys);

Zitat:
VFS & RAM Disk install
placement_address after ram disk install: 40200000h
ramdisk_start: 40081000h file_data_start: 0000A2E0h file_data_end: 0000B652h
After set_kernel_stack ==> tss_entry.esp0: 40101800h
>>> IRQ 127 <<<
Hello, user world!
...
placement_address after creating a new process: 40200000h phys: 0041CBE8h
fork() returned: 00000002h and getpid() returned: 00000001h
placement_address after creating a new process: 40200000h phys: 0041CC18h
fork() returned: 00000003h and getpid() returned: 00000001h
placement_address after creating a new process: 40200000h phys: 0041CC48h
fork() returned: 00000004h and getpid() returned: 00000001h
SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000018h, DS: 00000020h
task_switch before asm: eip: 0000D4CFh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->ph
ys: 0041E000h
Page Fault (page not present) at 0040FCC0h - EIP: 0040FCC0h

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 00:04:47 29.04.2009   Titel:              Zitieren

:)

I will explain the kmalloc for you.

size = size (doh)
align = page aligned, this makes your address page aligned, usable for paging structures and TSS (and others)
phys = get the physical address. You can put NULL in it, or a pointer to a variable. Like:

C/C++ Code:
uint32_t phys = 0;
uint32_t ptr = kmallocAP(0x100, 1, &phys);
printf("Phys: 0x%X, Virt: 0x%X\n",phys,ptr);
C/C++ Code:
uint32_t phys = 0;
uint32_t ptr = kmallocAP(0x100, 1, &phys);
printf("Phys: 0x%X, Virt: 0x%X\n",phys,ptr);
C/C++ Code:
uint32_t phys = 0;
uint32_t ptr = kmallocAP(0x100, 1, &phys);
printf("Phys: 0x%X, Virt: 0x%X\n",phys,ptr);


Getting physical address and doing nothing with it won't solve your problem.
The task doesn't have to be page aligned, since it is Software Multitasking, and you made it your own (nah, JamesM did :P)

The kmalloc code is 100% fine. (I used it my own some time ago)

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 03:04:39 29.04.2009   Titel:              Zitieren

Yes, the k_malloc(...) of James Molloy (I have his written permission to use his source code as a base for own experiments in an OS tutorial, if I like, but I am not sure, if his code is really robust enough) is usable and is not the problem (Other people think, JM has put too much into paging.h/paging.c, because phys./virt. memory management should be separated clearly. This can be done easily.).

OK, alignment is not important. I was not quite sure about it.

Currently, I do not understand the difference in the result of EIP between cases 1) and 3). In 3) I just save the physical address at 0x01 or a variable phys. The reason must be in the way of saving details of the tasks. Hence, the clobbering can influence the deficient process. :rolleyes:

I think, I should go back to the test code where the task switch really works and analyze the effects by looking at all the details again. I just did and the page fault came, too. Thus, the failure has another reason. That's good. :)
As soon as I have analyzed it, I will come back.

@PHPnerd: Thanks for staying with me in times of confusion. :live:

I use the following "stable version":
ckernel.c (like main.c):
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    UCHAR c=0;
    while(TRUE)
    {

      if( k_checkKQ_and_print_char() )
      {
        ++c;

        if(c>5)
        {
          c=0;
          settextcolor(4,0);
          printformat("\nT: %x H: %x WRITE: %i Read: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write, pODA->KQ_count_read);
          printformat("*T: %c %i *H: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
          settextcolor(2,0);

          task_switch(); settextcolor(getpid(),0);
        }
      }
    }
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
UCHAR c=0;
while(TRUE)
{

if( k_checkKQ_and_print_char() )
{
++c;

if(c>5)
{
c=0;
settextcolor(4,0);
printformat("\nT: %x H: %x WRITE: %i Read: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write, pODA->KQ_count_read);
printformat("*T: %c %i *H: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
settextcolor(2,0);

task_switch(); settextcolor(getpid(),0);
}
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    UCHAR c=0;
    while(TRUE)
    {

      if( k_checkKQ_and_print_char() )
      {
        ++c;

        if(c>5)
        {
          c=0;
          settextcolor(4,0);
          printformat("\nT: %x H: %x WRITE: %i Read: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write, pODA->KQ_count_read);
          printformat("*T: %c %i *H: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
          settextcolor(2,0);

          task_switch(); settextcolor(getpid(),0);
        }
      }
    }

Zitat:
kjsdfhsdkjksdjfhksdjfhsdkjfhksdjfhksdjfhsdkjfhsdkjfhksdjfhkjsdfhksjdhfß
T: 0000D80Fh H: 0000D80Fh WRITE: 66 Read: 66 *T: d 100 *H: d 100rnel_stack: 4010
task_switch before asm: eip: 0000D303h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->ph
ys: 00426000hk install
placement_address after ram disk install: 40200000h
ramdisk_start: 40081000h file_data_start: 0000A2C0h file_data_end: 0000B632h
After set_kernel_stack ==> tss_entry.esp0: 40101800h
>>> IRQ 127 <<<
Hello, user world!
Found file dev
(directory)
Found file f1
contents: "PrettyOS: My filename is test1.txt!"
Found file f2
contents: "PrettyOS: My filename is test2.txt!"
Found file f3
contents: "PrettyOS: My filename is test3.txt!"
placement_address after creating a new process: 40200000h phys: 0041CBE8h
fork() returned: 00000002h and getpid() returned: 00000001h
placement_address after creating a new process: 40200000h phys: 0041CC18h
fork() returned: 00000003h and getpid() returned: 00000001h
placement_address after creating a new process: 40200000h phys: 0041CC48h
fork() returned: 00000004h and getpid() returned: 00000001h
SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000018h, DS: 00000020h

While entering keystrokes, the task is switched after every sixth keystroke.
The logs of 'task_switch before asm:' with the original and 3 forked tasks are:
Zitat:

task_switch before asm: eip: 0000D4AFh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0041E000h //PID 2

task_switch before asm: eip: 0000D4AFh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00422000h //PID 3

task_switch before asm: eip: 0000D4AFh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00426000h //PID 4

task_switch before asm: eip: 0000D303h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00001000h //PID 1

task_switch before asm: eip: 0000D303h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0041E000h //PID 2

task_switch before asm: eip: 0000D303h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00422000h //PID 3

task_switch before asm: eip: 0000D303h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00426000h //PID 4

task_switch before asm: eip: 0000D303h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00001000h //PID 1 - the same as line 4

ff.


These are the data of the forked tasks:
Zitat:

phys: 0041CBE8h
fork() returned: 00000002h

phys: 0041CC18h
fork() returned: 00000003h

phys: 0041CC48h
fork() returned: 00000004h

SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000018h, DS: 00000020h


The task switch runs "unclobbered". Now it comes:

If I clobber ebx and edx (see above), then I get a PF:
Zitat:

task_switch before asm: eip: 0000D4AFh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0041E000h
Page Fault (page not present) at 0040FCA0h - EIP: 0040FCA0h


If I shift the task switch to timer handler, then I get an "Absturz":
Zitat:
task_switch before asm: eip: 0000D303h esp: 0018FE74h ebp: 0018FE8Ch cur_dir->phys: 00001000h
...
task_switch before asm: eip: 0000D303h esp: 0018FE74h ebp: 0018FE8Ch cur_dir->phys: 00001000h
...
task_switch before asm: eip: 0000D303h esp: 0018FF70h ebp: 0018FF88h cur_dir->phys: 00001000h
...
task_switch before asm: eip: 0000D303h esp: 0018FE74h ebp: 0018FE8Ch cur_dir->phys: 00001000h
...
task_switch before asm: eip: 0000D4AFh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0041E000h
...
placement_address after creating a new process: 40200000h phys: 0041CC18h
fork() returned: 00000003h and getpid() returned: 00000002h
placement_address after creating a new process: 40200000h phys: 0041CC48h
fork() returned: 00000004h and getpid() returned: 00000002h
SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000008h, DS: 00000010h

==> Absturz (no exception, no reboot, just nothing besides blinking cursor)

I think, this shows that JM's function task_switch() does not correctly work. Caring only for eip, esp, ebp seems to be not enough! Right?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 05:28:58 29.04.2009, insgesamt 11-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 07:00:22 29.04.2009   Titel:              Zitieren

@PHPnerd: How do you switch tasks? Are you willing to show your new kmalloc?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 09:58:45 29.04.2009   Titel:              Zitieren

I do not switch tasks yet. I will explain main for it later here :)

And, I am using DogLea Algorithm with my own code.
So:
Headers and footers
List containing free blocks, sorted by size

Like the JamesM one, but than all my own code (like it more :P)

Maybe look deeper in Intel Manuals of the source of other OSes to get idea's :P

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 13:36:43 29.04.2009   Titel:              Zitieren

With the multitasker:

Try to save more registers, since you don't have a TSS.

Save:
EFLAGS <-- :)
Segment registers: CS, DS, ES, FS, GS
Possible save some general registers (can be done later)

Maybe the EFLAGS will save the problem.
Oh, and, did you do a end-of-interrupt before task switch when using switching in PIT? May be important.

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:38:13 29.04.2009   Titel:              Zitieren

Zitat:
Save: FLAGS/EFLAGS
How can I do that? Is there a name for it in assembler? But I have read that you need not save them for task switch. :)

I think the problem is with eip. I have logged it just before the asm code and directly after the task_switch():
Code:
task_switch before asm: eip: 0000D54Fh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0041E000h PID: 2
after task_switch: eip: 00008B11h esp: 0018FFE0h ebp: 0018FFF0h cur_dir->phys: 0041E000h PID: 2
Code:
task_switch before asm: eip: 0000D54Fh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0041E000h PID: 2
after task_switch: eip: 00008B11h esp: 0018FFE0h ebp: 0018FFF0h cur_dir->phys: 0041E000h PID: 2
Code:
task_switch before asm: eip: 0000D54Fh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0041E000h PID: 2
after task_switch: eip: 00008B11h esp: 0018FFE0h ebp: 0018FFF0h cur_dir->phys: 0041E000h PID: 2


D54Fh vs. 8B11h ? But the task switch runs in this special case:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
    ///TEST
    printformat("task_switch before asm: eip: %x esp: %x ebp: %x cur_dir->phys: %x PID: %d\n",eip,esp,ebp,current_directory->physicalAddr, getpid());
    ///TEST

    asm volatile("       \
    cli;                 \
    mov %%ebx, %%esp;    \
    mov %%edx, %%ebp;    \
    mov %%eax, %%cr3;    \
    mov $0x12345, %%eax; \
    sti;                 \
    jmp *%%ecx;          
"
               : : "c"(eip), "b"(esp), "d"(ebp), "a"(current_directory->physicalAddr) );
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
///TEST
printformat("task_switch before asm: eip: %x esp: %x ebp: %x cur_dir->phys: %x PID: %d\n",eip,esp,ebp,current_directory->physicalAddr, getpid());
///TEST

asm volatile(" \
cli; \
mov %%ebx, %%esp; \
mov %%edx, %%ebp; \
mov %%eax, %%cr3; \
mov $0x12345, %%eax; \
sti; \
jmp *%%ecx;
"
: : "c"(eip), "b"(esp), "d"(ebp), "a"(current_directory->physicalAddr) );
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
    ///TEST
    printformat("task_switch before asm: eip: %x esp: %x ebp: %x cur_dir->phys: %x PID: %d\n",eip,esp,ebp,current_directory->physicalAddr, getpid());
    ///TEST

    asm volatile("       \
    cli;                 \
    mov %%ebx, %%esp;    \
    mov %%edx, %%ebp;    \
    mov %%eax, %%cr3;    \
    mov $0x12345, %%eax; \
    sti;                 \
    jmp *%%ecx;          
"
               : : "c"(eip), "b"(esp), "d"(ebp), "a"(current_directory->physicalAddr) );

... changed to named registers.

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    while(TRUE)
    {

      if( k_checkKQ_and_print_char() )
      {
        ++c;

        if(c>5)
        {
          c=0;
          settextcolor(4,0);
          printformat("\nT: %x H: %x WRITE: %i Read: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write, pODA->KQ_count_read);
          printformat("*T: %c %i *H: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
          settextcolor(2,0);

          task_switch();
          ///TEST
          printformat("after task_switch: eip: %x esp: %x ebp: %x cur_dir->phys: %x PID: %d\n",read_eip(),fetchESP(),fetchEBP(),current_directory->physicalAddr, getpid());
          ///TEST
          settextcolor(getpid(),0);
        }
      }
    }
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
while(TRUE)
{

if( k_checkKQ_and_print_char() )
{
++c;

if(c>5)
{
c=0;
settextcolor(4,0);
printformat("\nT: %x H: %x WRITE: %i Read: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write, pODA->KQ_count_read);
printformat("*T: %c %i *H: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
settextcolor(2,0);

task_switch();
///TEST
printformat("after task_switch: eip: %x esp: %x ebp: %x cur_dir->phys: %x PID: %d\n",read_eip(),fetchESP(),fetchEBP(),current_directory->physicalAddr, getpid());
///TEST
settextcolor(getpid(),0);
}
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    while(TRUE)
    {

      if( k_checkKQ_and_print_char() )
      {
        ++c;

        if(c>5)
        {
          c=0;
          settextcolor(4,0);
          printformat("\nT: %x H: %x WRITE: %i Read: %i ", pODA->pTailKQ, pODA->pHeadKQ, pODA->KQ_count_write, pODA->KQ_count_read);
          printformat("*T: %c %i *H: %c %i\n", *(pODA->pTailKQ),*(pODA->pTailKQ),*(pODA->pHeadKQ),*(pODA->pHeadKQ));
          settextcolor(2,0);

          task_switch();
          ///TEST
          printformat("after task_switch: eip: %x esp: %x ebp: %x cur_dir->phys: %x PID: %d\n",read_eip(),fetchESP(),fetchEBP(),current_directory->physicalAddr, getpid());
          ///TEST
          settextcolor(getpid(),0);
        }
      }
    }

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:03:37 29.04.2009, insgesamt 5-mal bearbeitet
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 00:41:50 30.04.2009   Titel:              Zitieren

Does it work now?

// PHP

_________________
Being Dutch. Talking English. On a German community.

Jinix
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 17:27:26 30.04.2009   Titel:              Zitieren

Only in the while loop at the above shown location. I think that the failure is at another place, perhaps concerning kernel_stack of the task. I come back to that.

EDIT: One failure was in fork(): now new_task->kernel_stack instead of current_task->...

I log the processes with its data, the first task looks strange:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
HEAP start: 40081000h end: 40100000h max: 4FFFF000h kernel mode: 0 read-only: 0
hole 40081000h hole-size: 0007F000h after create_heap: placement_address: 0030C020h  allocated frames: 795

VFS & RAM Disk install
placement_address after ram disk install: 40200000h ramdisk_start: 40081000h file_data_start: 0000A200h file_data_end: 0000B572h

tasking install
move stack, ESP: 0018FFD0h After init first task, p_a: 40200000h After k_malloc kernel_stack, p_a: 40200000h k_stack: 40101000h

placement_address after creating a new process: 40200000h phys: 0041C814h
fork(): 00000002h and getpid(): 00000001h
placement_address after creating a new process: 40200000h phys: 0041C844h
fork(): 00000003h and getpid(): 00000001h
placement_address after creating a new process: 40200000h phys: 0041C874h
fork(): 00000004h and getpid(): 00000001h
t->id: 1, esp: 00000000h, eip: 00000000h k_stack: 40101000h, p_dir: 00000000h next: 40101814h
t->id: 2, esp: 0018FFD8h, eip: 0000D3C9h k_stack: 40105000h, p_dir: 40102000h next: 40101844h
t->id: 3, esp: 0018FFD8h, eip: 0000D3C9h k_stack: 40109000h, p_dir: 40106000h next: 40101874h
t->id: 4, esp: 0018FFD8h, eip: 0000D3C9h k_stack: 4010D000h, p_dir: 4010A000h next: 00000000h

SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000008h, DS: 00000010h
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
HEAP start: 40081000h end: 40100000h max: 4FFFF000h kernel mode: 0 read-only: 0
hole 40081000h hole-size: 0007F000h after create_heap: placement_address: 0030C020h allocated frames: 795

VFS & RAM Disk install
placement_address after ram disk install: 40200000h ramdisk_start: 40081000h file_data_start: 0000A200h file_data_end: 0000B572h

tasking install
move stack, ESP: 0018FFD0h After init first task, p_a: 40200000h After k_malloc kernel_stack, p_a: 40200000h k_stack: 40101000h

placement_address after creating a new process: 40200000h phys: 0041C814h
fork(): 00000002h and getpid(): 00000001h
placement_address after creating a new process: 40200000h phys: 0041C844h
fork(): 00000003h and getpid(): 00000001h
placement_address after creating a new process: 40200000h phys: 0041C874h
fork(): 00000004h and getpid(): 00000001h
t->id: 1, esp: 00000000h, eip: 00000000h k_stack: 40101000h, p_dir: 00000000h next: 40101814h
t->id: 2, esp: 0018FFD8h, eip: 0000D3C9h k_stack: 40105000h, p_dir: 40102000h next: 40101844h
t->id: 3, esp: 0018FFD8h, eip: 0000D3C9h k_stack: 40109000h, p_dir: 40106000h next: 40101874h
t->id: 4, esp: 0018FFD8h, eip: 0000D3C9h k_stack: 4010D000h, p_dir: 4010A000h next: 00000000h

SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000008h, DS: 00000010h
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
HEAP start: 40081000h end: 40100000h max: 4FFFF000h kernel mode: 0 read-only: 0
hole 40081000h hole-size: 0007F000h after create_heap: placement_address: 0030C020h  allocated frames: 795

VFS & RAM Disk install
placement_address after ram disk install: 40200000h ramdisk_start: 40081000h file_data_start: 0000A200h file_data_end: 0000B572h

tasking install
move stack, ESP: 0018FFD0h After init first task, p_a: 40200000h After k_malloc kernel_stack, p_a: 40200000h k_stack: 40101000h

placement_address after creating a new process: 40200000h phys: 0041C814h
fork(): 00000002h and getpid(): 00000001h
placement_address after creating a new process: 40200000h phys: 0041C844h
fork(): 00000003h and getpid(): 00000001h
placement_address after creating a new process: 40200000h phys: 0041C874h
fork(): 00000004h and getpid(): 00000001h
t->id: 1, esp: 00000000h, eip: 00000000h k_stack: 40101000h, p_dir: 00000000h next: 40101814h
t->id: 2, esp: 0018FFD8h, eip: 0000D3C9h k_stack: 40105000h, p_dir: 40102000h next: 40101844h
t->id: 3, esp: 0018FFD8h, eip: 0000D3C9h k_stack: 40109000h, p_dir: 40106000h next: 40101874h
t->id: 4, esp: 0018FFD8h, eip: 0000D3C9h k_stack: 4010D000h, p_dir: 4010A000h next: 00000000h

SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000008h, DS: 00000010h


after typing keys and taskswitching by that:
Code:
kjdfghjkkhjkhkjkhkjhkkjh
task_switch before asm: eip: 0000D216h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00001000h PID: 1
after task_switch in ckernel.c: eip: 000089C7h esp: 0018FFE0h ebp: 0018FFF0h cur_dir->phys: 00001000h PID: 1
Code:
kjdfghjkkhjkhkjkhkjhkkjh
task_switch before asm: eip: 0000D216h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00001000h PID: 1
after task_switch in ckernel.c: eip: 000089C7h esp: 0018FFE0h ebp: 0018FFF0h cur_dir->phys: 00001000h PID: 1
Code:
kjdfghjkkhjkhkjkhkjhkkjh
task_switch before asm: eip: 0000D216h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00001000h PID: 1
after task_switch in ckernel.c: eip: 000089C7h esp: 0018FFE0h ebp: 0018FFF0h cur_dir->phys: 00001000h PID: 1

Improved Sourcecode: http://www.henkessoft.de/OS_Dev/Downloads/40.zip
I think it is not yet ready for the timer_handler, but I am on the right track now.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 18:48:45 30.04.2009, insgesamt 2-mal bearbeitet
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 20:02:48 30.04.2009   Titel:              Zitieren

Good!~

I almost finished my kmalloc. Working on Shrink now. Next is krealloc, but I may skip that one for now.

I will continue ordering my OS, and then the MultiTasker.

// PHP

_________________
Being Dutch. Talking English. On a German community.

Jinix
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:54:52 30.04.2009   Titel:              Zitieren

To my mind, the crucial point is that the source code stays transparent. :)

There was a create_heap(...) inside of paging_install(). I have taken it out, because the heap is more complicated to visualize by printformat(...), and process' stacks were created in the heap! :D :rolleyes:

Now there is a new exception, if you put the task_switch() to practice inside the time_handler (k_m_nonheap means "pushing" placement_address, no heap):
Zitat:

k_m_nonheap k_m_nonheap k_m_nonheap k_m_nonheap k_m_nonheap
p_a: 0040D000h allocated frames: 1053
frames: 00400000h NFRAMES: 524288
k_dir->phys: 00406000h
p_a: 0040D000h allocated frames: 1053

k_m_nonheap

tasking install
stack, ESP: 0018FFD0h k_m_nonheap Init first task, p_a: 00410020h cur_task: 00410004h k_m_nonheap After k_malloc k_stack, p_a: 00411800h k_stack: 00411000h

k_m_nonheap k_m_nonheap placement_address after creating a new process: 00414020h phys: 00414004h
k_m_nonheap fork(): 00000002h and getpid(): 00000001h
k_m_nonheap k_m_nonheap placement_address after creating a new process: 00418020h phys: 00418004h
k_m_nonheap fork(): 00000003h and getpid(): 00000001h
t->id: 1, esp: 00000000h, eip: 00000000h k_stack: 00411000h, p_dir: 0040E000h next: 00414004h
t->id: 2, esp: 0018FFD8h, eip: 0000D379h k_stack: 00415000h, p_dir: 00412000h next: 00418004h
t->id: 3, esp: 0018FFD8h, eip: 0000D379h k_stack: 00419000h, p_dir: 00416000h next: 00000000h

p_a: 00419800h

SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000008h, DS: 00000010h

task_switch before asm: cur_task->p_dir: 00412000h task_switch before asm:
eip: 0000D379h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00413000h PID: 2
Invalid Opcode >>> Exception. System Halted! <<<


Wie kann man den "Invalid Opcode" besser auswerten? z.B. Invalid Opcode ... at address ...? Ich habe mir z.B. r->eip angeschaut. Das passt einfach nicht zu dem in task_t. Verflixt! :(

Tippt man vor dem Timer Handler schnell noch ein paar task switches, dann findet man:
Zitat:
klxdfgjkldfgjdfkgjkldfgjkldfgjkldfgjkldfjglkdfgjlkdfgjkldfjgkldfjglk
task_switch before asm: cur_task->p_dir: 0040E000h task_switch before asm: eip: 0000D1BBh esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 0040F000h PID: 10h ebp: 0018FFF0h cur
Invalid Opcode >>> Exception. System Halted! <<<


This is the test code in ckernel.c (main.c):
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
int main()
{
//...

    settextcolor(2,0); printformat("paging install\n"); settextcolor(15,0);
    paging_install();
   
    settextcolor(2,0); printformat("tasking install\n"); settextcolor(15,0);
    tasking_install(); settextcolor(15,0);
    int retValFork1 = fork(); int retValGetPid1 = getpid();
    printformat("fork(): %x and getpid(): %x\n", retValFork1, retValGetPid1);
    int retValFork2 = fork(); int retValGetPid2 = getpid();
    printformat("fork(): %x and getpid(): %x\n", retValFork2, retValGetPid2);
    int retValFork3 = fork(); int retValGetPid3 = getpid();
    printformat("fork(): %x and getpid(): %x\n", retValFork3, retValGetPid3);

    task_t* t = current_task;
    while(TRUE) {
        while(t->next) {
          printformat("t->id: %d, esp: %x, eip: %x k_stack: %x, p_dir: %x next: %x\n", t->id, t->esp, t->eip, t->kernel_stack, t->page_directory, t->next);
          t = t->next;
        }
        printformat("t->id: %d, esp: %x, eip: %x k_stack: %x, p_dir: %x next: %x\n", t->id, t->esp, t->eip, t->kernel_stack, t->page_directory, t->next);
        break;
    }
    printformat("p_a: %x \n", placement_address);
    printformat("SS: %x, ESP: %x, EBP: %x, CS: %x, DS: %x\n", fetchSS(),fetchESP(),fetchEBP(),fetchCS(),fetchDS());
    settextcolor(2,0);
    UCHAR c=0;
    while(TRUE) {
      if( k_checkKQ_and_print_char() ) {
        ++c;
        if(c>5) {
          c=0;
          task_switch();
              printformat("after task_switch in ckernel.c: eip: %x esp: %x ebp: %x cur_dir->phys: %x PID: %d\n",read_eip(),fetchESP(),fetchEBP(),current_directory->physicalAddr, getpid());
              settextcolor(getpid(),0);
        }
      }
    }
    return 0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
int main()
{
//...

settextcolor(2,0); printformat("paging install\n"); settextcolor(15,0);
paging_install();

settextcolor(2,0); printformat("tasking install\n"); settextcolor(15,0);
tasking_install(); settextcolor(15,0);
int retValFork1 = fork(); int retValGetPid1 = getpid();
printformat("fork(): %x and getpid(): %x\n", retValFork1, retValGetPid1);
int retValFork2 = fork(); int retValGetPid2 = getpid();
printformat("fork(): %x and getpid(): %x\n", retValFork2, retValGetPid2);
int retValFork3 = fork(); int retValGetPid3 = getpid();
printformat("fork(): %x and getpid(): %x\n", retValFork3, retValGetPid3);

task_t* t = current_task;
while(TRUE) {
while(t->next) {
printformat("t->id: %d, esp: %x, eip: %x k_stack: %x, p_dir: %x next: %x\n", t->id, t->esp, t->eip, t->kernel_stack, t->page_directory, t->next);
t = t->next;
}
printformat("t->id: %d, esp: %x, eip: %x k_stack: %x, p_dir: %x next: %x\n", t->id, t->esp, t->eip, t->kernel_stack, t->page_directory, t->next);
break;
}
printformat("p_a: %x \n", placement_address);
printformat("SS: %x, ESP: %x, EBP: %x, CS: %x, DS: %x\n", fetchSS(),fetchESP(),fetchEBP(),fetchCS(),fetchDS());
settextcolor(2,0);
UCHAR c=0;
while(TRUE) {
if( k_checkKQ_and_print_char() ) {
++c;
if(c>5) {
c=0;
task_switch();
printformat("after task_switch in ckernel.c: eip: %x esp: %x ebp: %x cur_dir->phys: %x PID: %d\n",read_eip(),fetchESP(),fetchEBP(),current_directory->physicalAddr, getpid());
settextcolor(getpid(),0);
}
}
}
return 0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
int main()
{
//...

    settextcolor(2,0); printformat("paging install\n"); settextcolor(15,0);
    paging_install();
   
    settextcolor(2,0); printformat("tasking install\n"); settextcolor(15,0);
    tasking_install(); settextcolor(15,0);
    int retValFork1 = fork(); int retValGetPid1 = getpid();
    printformat("fork(): %x and getpid(): %x\n", retValFork1, retValGetPid1);
    int retValFork2 = fork(); int retValGetPid2 = getpid();
    printformat("fork(): %x and getpid(): %x\n", retValFork2, retValGetPid2);
    int retValFork3 = fork(); int retValGetPid3 = getpid();
    printformat("fork(): %x and getpid(): %x\n", retValFork3, retValGetPid3);

    task_t* t = current_task;
    while(TRUE) {
        while(t->next) {
          printformat("t->id: %d, esp: %x, eip: %x k_stack: %x, p_dir: %x next: %x\n", t->id, t->esp, t->eip, t->kernel_stack, t->page_directory, t->next);
          t = t->next;
        }
        printformat("t->id: %d, esp: %x, eip: %x k_stack: %x, p_dir: %x next: %x\n", t->id, t->esp, t->eip, t->kernel_stack, t->page_directory, t->next);
        break;
    }
    printformat("p_a: %x \n", placement_address);
    printformat("SS: %x, ESP: %x, EBP: %x, CS: %x, DS: %x\n", fetchSS(),fetchESP(),fetchEBP(),fetchCS(),fetchDS());
    settextcolor(2,0);
    UCHAR c=0;
    while(TRUE) {
      if( k_checkKQ_and_print_char() ) {
        ++c;
        if(c>5) {
          c=0;
          task_switch();
              printformat("after task_switch in ckernel.c: eip: %x esp: %x ebp: %x cur_dir->phys: %x PID: %d\n",read_eip(),fetchESP(),fetchEBP(),current_directory->physicalAddr, getpid());
              settextcolor(getpid(),0);
        }
      }
    }
    return 0;
}


EDIT:
I have printed now the infos from the struct reg by evaluating the exception in the IRQ/fault handler:
Zitat:
placement_address: 00419800h
SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000008h, DS: 00000010h
task_switch before asm: cur_task->p_dir: 00412000h eip: 0000D4D9h esp: 0018FFD8h ebp: 0018FFF0h cur_dir->phys: 00413000h PID: 2

Invalid Opcode >>> Exception. System Halted! <<<
err_code: 00000000h address(eip): 0000024Bh edi: 00000020h esi: 00000000h ebp: 00000008h esp: 0018FFE8h eax: 000000D7h ebx: 00000000h ecx: 00012345h edx: 0000D7F0h cs: 8 ds: 16 es: 16 fs: 16 gs 16 ss 2097144 int_no 6 eflags 00010202h useresp 00000000h


These should be the data direct after the asm-code in task switch.
address: 24Bh (eip) cannot be correct, if we enter with D4D9h.
The ss 2097144 = 1FFFF8h looks "kaput". It should be 16 (10h). :(
eflags: 10000001000000010b = 10202h

The whole task_management has to be looked thru.
JM's code in this area is not robust, it was only for short demos.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 08:18:24 01.05.2009, insgesamt 12-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 10:07:34 01.05.2009   Titel:              Zitieren

Ich habe jetzt mal pushf und popf eingebaut, um die flags zu sichern:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
    asm volatile("       \
    cli;                 \
    pushf;               \
    mov %%ebx, %%esp;    \
    mov %%edx, %%ebp;    \
    mov %%eax, %%cr3;    \
    mov $0x12345, %%eax; \
    popf;                \
    sti;                 \
    jmp *%%ecx;          
"
               : : "c"(eip), "b"(esp), "d"(ebp), "a"(current_directory->physicalAddr) );
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
asm volatile(" \
cli; \
pushf; \
mov %%ebx, %%esp; \
mov %%edx, %%ebp; \
mov %%eax, %%cr3; \
mov $0x12345, %%eax; \
popf; \
sti; \
jmp *%%ecx;
"
: : "c"(eip), "b"(esp), "d"(ebp), "a"(current_directory->physicalAddr) );
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
    asm volatile("       \
    cli;                 \
    pushf;               \
    mov %%ebx, %%esp;    \
    mov %%edx, %%ebp;    \
    mov %%eax, %%cr3;    \
    mov $0x12345, %%eax; \
    popf;                \
    sti;                 \
    jmp *%%ecx;          
"
               : : "c"(eip), "b"(esp), "d"(ebp), "a"(current_directory->physicalAddr) );

Ergebnis via task_switch mittels timer:
Zitat:

p_a: 00419800h
SS: 00000010h, ESP: 0018FFE0h, EBP: 0018FFF0h, CS: 00000008h, DS: 00000010h
task_switch before asm: cur_task->p_dir: 00412000h eip: 0000D519h esp: 0018FFD8
h ebp: 0018FFF0h cur_dir->phys: 00413000h PID: 2 ss: 16
err_code: 00000000h address(eip): 0000D40Bh
edi: 0018FFF0h esi: 0018FFD8h ebp: 0018FFF0h esp: 0018FFC8h eax: 00012345h ebx:
0018FFD8h ecx: 0000D519h edx: 0018FFF0h
cs: 8 ds: 16 es: 16 fs: 16 gs 16 ss 55376
int_no 1 eflags 00007FC6h useresp 00418000h
Debug >>> Exception. System Halted! <<<

Jetzt haben wir eine DEBUG Exception. :D

Übrigens: Wenn ich pushfd / popfd verwenden will, macht mein oldtimer gcc (verwendet wegen aout Format von NASM um den Asemblercode einzubinden) das nicht mit:
Zitat:
c:/djgpp/tmp/cc5s5oYe.s: Assembler messages:
c:/djgpp/tmp/cc5s5oYe.s:237: Error: no such instruction: `pushfd'
c:/djgpp/tmp/cc5s5oYe.s:237: Error: no such instruction: `popfd'

kann also nur die FLAGS nicht die EFLAGS sichern. :confused:

EDIT: Ich denke inzwischen, dass JM's Sourcecode im Bereich (multi)tasking für PrettyOS einfach unbrauchbar ist.

Auf jeden Fall hat mir die Beschäftigung mit den Themen viel gebracht, bin nun auch oft genug gegen den Baum gefahren, um zu wissen, was etwas taugt und was einem bei Problemen nur noch den Rest gibt.

Daher mache ich nun einen kompletten "roll-back" und setze am Ende des Tutorials an. !!!Schnitt!!! :warning:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 11:08:30 01.05.2009, insgesamt 4-mal bearbeitet
schnitt
Unregistrierter




Beitrag schnitt Unregistrierter 11:23:11 01.05.2009   Titel:              Zitieren

Wird es nicht mehr weiter entwickelt oder was?????
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:42:11 01.05.2009   Titel:              Zitieren

Roll-back starts now:

Tutorial: http://www.henkessoft.de/OS_Dev/OS_Dev1.htm
Source Code: http://www.henkessoft.de/OS_Dev/Downloads/20090501_PrettyOS.zip
bzw. http://www.henkessoft.de/OS_Dev/Downloads/PrettyOS_last_version.zip (momentan identisch)

Zunächst mal einige Fragen an euch zu den Tools (nasm/gcc/ld):

1) Im Tutorial werden gcc 3.1 und ld 2.13 (im Rahmen von DJGPP, Download-Link von osdever.net empfohlen: http://www.osdever.net/downloads/compilers/DJGPP-Installer-nocpp.exe ) verwendet.
Einer der Gründe besteht darin, dass wir damit das aout-Format (Linux a.out object file) linken konnten. abc.w konnte dieses Problem, soweit ich es verstanden habe, auch nicht lösen, sodass wir dabei blieben. Mit dem gcc 3.1 kommt man allerdings immer suspekt daher. Ein Fehler könnte ja am Uralt-Compiler liegen.

Mögliche NASM output-Formate sind:
Zitat:
valid output formats for -f are (`*' denotes default):
* bin flat-form binary files (e.g. DOS .COM, .SYS)
aout Linux a.out object files
aoutb NetBSD/FreeBSD a.out object files
coff COFF (i386) object files (e.g. DJGPP for DOS)
elf32 ELF32 (i386) object files (e.g. Linux)
elf ELF (short name for ELF32)
elf64 ELF64 (x86_64) object files (e.g. Linux)
as86 Linux as86 (bin86 version 0.3) object files
obj MS-DOS 16-bit/32-bit OMF object files
win32 Microsoft Win32 (i386) object files
win64 Microsoft Win64 (x86-64) object files
rdf Relocatable Dynamic Object File Format v2.0
ieee IEEE-695 (LADsoft variant) object file format
macho NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X object files


Verwendet man für die NASM outputs COFF bzw. WIN32, dann gibt es folgende nette Meldung:
kernel.asm: ... : error: COFF format does not support non-32-bit relocations
Soweit ich das verstanden habe, hängt dies an unserem eleganten Übergang von 16 Bit nach 32 Bit. Hier erhält man von "Fachleuten" den Rat, GRUB einzusetzen und sich auf den C-Kernel zu konzentrieren. Das widerspricht aber dem Geist des bisherigen Tutorials, das die Dinge bottom-up zeigen will. Ich habe außer diesem aout-Format bisher kein Format gefunden, dass sowohl 16- als auch 32-Bit verarbeitet und von ld zum restlichen C-Code gebunden wird. Gibt es ein modernes Format, das dies kann?

Ich bin nicht sicher, inweiweit dies ein echtes Problem oder nur Ansichtssache ist. GCC 3.1 stammt ja immerhin schon von May 15, 2002. Also so richtig uralt ist er nicht.

Warum wurde z.B. pushfd / popfd im asm-Code nicht akzeptiert? Das kann doch nicht am gcc-Baudatum 2002 liegen, den 386er asm-Set gibt es seit den 80ern.

2) zur AT&T-Syntax: %eax %%eax *%%eax
wo muss man genau was verwenden?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 13:04:36 01.05.2009, insgesamt 1-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 13:16:40 01.05.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Auf jeden Fall hat mir die Beschäftigung mit den Themen viel gebracht, bin nun auch oft genug gegen den Baum gefahren, um zu wissen, was etwas taugt und was einem bei Problemen nur noch den Rest gibt.

meiner meinung nach hast du zu viele themen gleichzeitig bearbeitet. das liegt wohl auch daran, dass es keine richtige trennung zwischen den komponenten des 'referenzsystems' von JM gibt (vermutlich ist er ein opfer der verfrickelten x86-technologie geworden, die einem instabile software-konstrukte aufzwingt). dabei kann man virtual memory, multitasking, heaps und exceptions ziemlich unabhängig voneinander betrachten. aber egal, nur nicht aufgeben...
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 13:49:09 01.05.2009   Titel:              Zitieren

Den Mut habe ich keinesfalls verloren, ganz im Gegenteil! Man kann ein solches Tutorial keinesfalls schreiben, wenn man schon 20 verschiedene OS entwickelt hat, weil man sich dann für garnix mehr entscheiden kann und alles nur noch theoretisch/abstrakt sieht, aber auch nicht aus dem Nichts. Inzwischen verstehe ich, warum JM nicht weiter macht. ;)

Zitat:
dabei kann man virtual memory, multitasking, heaps und exceptions ziemlich unabhängig voneinander betrachten

Ja, das stimmt. Es gibt daneben noch weitere Punkte, nämlich die Trennung des physikalischen und virtuellen MM, die Software-Interrupts, die Syscalls und die Ausführung von Programmen. Das VFS und die RAM-Disk gefallen mir gut von JM, wobei sein VFS noch nicht ausgefeilt ist, aber das kann man ja noch machen. Heap-Mechanismus funktioniert auch gut. Vielleicht liefert uns PHPnerd etwas Besseres, aber sein Ansatz klingt für mich gleich zu JM, aber ich bin kein Informatiker.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 14:40:59 01.05.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:49:51 01.05.2009   Titel:              Zitieren

Ich habe mit Teil 2 begonnen und die Themen FIFO circular Key Queue und "lean" key handler verarbeitet, um den Anschluss an das Tutorial zu bekommen.
http://www.henkessoft.de/OS_Dev/OS_Dev2.htm (Tut)
http://www.henkessoft.de/OS_Dev/Downloads/20090501_PrettyOS_101.zip

Was mir wirklich Sorgen macht, ist, dass ich mit DJGPP arbeite, gilt als obsolet. leider haben wir 16-bit im Gepäck. Vielleicht kann man das auf 32-Bit abändern und auf COFF umsteigen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:24:10 01.05.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:50:10 01.05.2009   Titel:              Zitieren

Zitat:
Wird es nicht mehr weiter entwickelt oder was?????
Ganz im Gegenteil, jetzt geht es erst richtig los, allerdings geordnet, so robust wie möglich und transparent, damit eigenes Experimentieren gelingt. :) Einfach dabei bleiben, oder noch besser, zusammen mit mir entwickeln. Ich werde nicht aufgeben. Das Thema OSDEV ist faszinierend. Ich werde ab jetzt aber jede einzelne Code-Zeile - egal ob fremd oder von mir selbst - auf die Goldwaage legen. Anders geht es nicht.

Es gibt bezüglich Teil 2 folgende technische Fragestellungen:
1) GRUB oder Tiny Bootloader?
2) DJGPP oder neuere gcc-ld-binutils-Toolchain

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:08:19 02.05.2009, insgesamt 3-mal bearbeitet
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 23:32:08 01.05.2009   Titel:              Zitieren

Let's all take the Intel Manuals, close the jamesMolloy website, and start by ourself. We just use GRUB to load, so we take the GRUB specifications too.

We read the GRUB specifications, and we find out how to make our starting OS multiboot able for GRUB. When done, we move to C, by just calling our C function.

Read Intel manuals, on IDT, GDT, ISR and IRQ's (exceptions), work out some code.

We already know howto use VGA in protected mode: writing to 0xb8000, write some nice code to make our life easier.

Then, go on to intel manuals again, and go starting writing your PMM and VMM. (Volume 3A, Protected Mode Memory Management)

Then, when all is working, do some research on internet about different algorithms of memory allocation (heap management). Write your own, without looking to others code. :)

Debug debug debug all you got. Try to get your friends starting it and doing weird things.

When done, Take Intel manuals and find the chapters about task management, but especially (when you want to use Software Multitasking) the chapter about the architecture itself. I think it is chapter 3 of Volume 1, not sure ;)

Then go on writing some code to change the registers of the CPU. Just try to switch static tasks, then try make dynamic ones (so a task can start a new task).

Go on to write code for device drivers and file systems, write some drivers, and
support a nice filesystem (FAT32 for example). Then support executables, port newlib, compile the whole GCC packet. Run it on your OS, compile NASM. Write some simple nice text editor. Do not forget to make a command line interface for executing your commands.

Now you can make your OS on your OS. And you can take a drink.

When someone got so far, tip me, and i will tell you next steps (LOL, I will be back after some years and check the forum (just joking, will still be here)).

Success you all! When you want some details (tips), ask for them.

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:42:59 02.05.2009   Titel:              Zitieren

Thank you for the guideline showing the path forward to OS excellence. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 09:21:06 02.05.2009   Titel:              Zitieren

PHPnerd schrieb:

Then, go on to intel manuals again...

...but don't rely on too much intel crap. only the very low level stuff (which must be coded in asm, anyway) should be hooked on x86. separate cpu specific code from the rest of the system, so you can...
1. easily port your OS to another architecture
2. run and debug parts of the OS inside a test bench (perhaps under windoze)
:)
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 11:51:28 02.05.2009   Titel:              Zitieren

Erhard Henkes schrieb:
2) zur AT&T-Syntax: %eax %%eax *%%eax
wo muss man genau was verwenden?

Man muss unterscheiden zwischen Assembler-Syntax für den GNU Assembler und dem Assembler-Inline Formalismus für den gcc Compiler.

Für den GNU Assembler gilt: Alle Register-Bezeichnungen, weil sie was besonderes sind, im Sinne, keine Variablen uns so was, bekommen ein % Zeichen. Man kann ruhig Variablen anlegen, die eax, ebx und sonst wie heissen, und auf diese Variablen zugreifen:
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.section .data
eax: .long 0        # Variable eax
ebx: .long 0        # Variable ebx
ecx: .long 0, 0, 0  # Ein Array ecx[3]

.section .text
_Helper:
    movl %eax, eax      # Speichere Inhalt des CPU-Registers EAX (%eax) in der Variable eax (eax)
    movl %ebx, ebx      # Speichere Inhalt des CPU-Registers EBX (%ebx) in der Variable ebx (ebx)
    movl $eax, %eax     # Lade Addresse der Variable eax ($eax) ins CPU-Register EAX (%eax)
    movl $ecx, %ecx     # Lade Anfangsadresse des Arrays ecx ($ecx) ins CPU-Register ECX (%ecx)
    movl %eax, (%ecx)   # Speichere Inhalt des CPU-Registers EAX (%eax) im Array-Element ecx[0]
    movl %ebx, 4(%ecx)  # Speichere Inhalt des CPU-Registers EBX (%ebx) im Array-Element ecx[1]
    movl %ecx, 8(%ecx)  # Speichere Inhalt des CPU-Registers ECX (%ecx) im Array-Element ecx[2]
    ret
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.section .data
eax: .long 0 # Variable eax
ebx: .long 0 # Variable ebx
ecx: .long 0, 0, 0 # Ein Array ecx[3]

.section .text
_Helper:
movl %eax, eax # Speichere Inhalt des CPU-Registers EAX (%eax) in der Variable eax (eax)
movl %ebx, ebx # Speichere Inhalt des CPU-Registers EBX (%ebx) in der Variable ebx (ebx)
movl $eax, %eax # Lade Addresse der Variable eax ($eax) ins CPU-Register EAX (%eax)
movl $ecx, %ecx # Lade Anfangsadresse des Arrays ecx ($ecx) ins CPU-Register ECX (%ecx)
movl %eax, (%ecx) # Speichere Inhalt des CPU-Registers EAX (%eax) im Array-Element ecx[0]
movl %ebx, 4(%ecx) # Speichere Inhalt des CPU-Registers EBX (%ebx) im Array-Element ecx[1]
movl %ecx, 8(%ecx) # Speichere Inhalt des CPU-Registers ECX (%ecx) im Array-Element ecx[2]
ret
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.section .data
eax: .long 0        # Variable eax
ebx: .long 0        # Variable ebx
ecx: .long 0, 0, 0  # Ein Array ecx[3]

.section .text
_Helper:
    movl %eax, eax      # Speichere Inhalt des CPU-Registers EAX (%eax) in der Variable eax (eax)
    movl %ebx, ebx      # Speichere Inhalt des CPU-Registers EBX (%ebx) in der Variable ebx (ebx)
    movl $eax, %eax     # Lade Addresse der Variable eax ($eax) ins CPU-Register EAX (%eax)
    movl $ecx, %ecx     # Lade Anfangsadresse des Arrays ecx ($ecx) ins CPU-Register ECX (%ecx)
    movl %eax, (%ecx)   # Speichere Inhalt des CPU-Registers EAX (%eax) im Array-Element ecx[0]
    movl %ebx, 4(%ecx)  # Speichere Inhalt des CPU-Registers EBX (%ebx) im Array-Element ecx[1]
    movl %ecx, 8(%ecx)  # Speichere Inhalt des CPU-Registers ECX (%ecx) im Array-Element ecx[2]
    ret

Bei indirekten Sprüngen ist es so, dass ein Sternchen benützt werden muss/soll:
Assembler Code:
_Sprung:
    jmpl *1000      # Effektive Adresse 1000
    jmpl *%eax      # Effektive Adresse im CPU-Register EAX (%eax)
    jmpl *4(%eax)   # Effektive Adresse im CPU-Register EAX (%eax) und Displacement = 4
    jmpl *(%eax, %ebx)  # Basis im CPU-Register EAX (%eax), Index im CPU-Register EBX (%ebx)
    jmpl *32(%eax, %ebx, 4) # Basis im CPU-Register EAX (%eax), Index im CPU-Register EBX, Skalierung = 4, Displacement = 32
    ret
Assembler Code:
_Sprung:
jmpl *1000 # Effektive Adresse 1000
jmpl *%eax # Effektive Adresse im CPU-Register EAX (%eax)
jmpl *4(%eax) # Effektive Adresse im CPU-Register EAX (%eax) und Displacement = 4
jmpl *(%eax, %ebx) # Basis im CPU-Register EAX (%eax), Index im CPU-Register EBX (%ebx)
jmpl *32(%eax, %ebx, 4) # Basis im CPU-Register EAX (%eax), Index im CPU-Register EBX, Skalierung = 4, Displacement = 32
ret
Assembler Code:
_Sprung:
    jmpl *1000      # Effektive Adresse 1000
    jmpl *%eax      # Effektive Adresse im CPU-Register EAX (%eax)
    jmpl *4(%eax)   # Effektive Adresse im CPU-Register EAX (%eax) und Displacement = 4
    jmpl *(%eax, %ebx)  # Basis im CPU-Register EAX (%eax), Index im CPU-Register EBX (%ebx)
    jmpl *32(%eax, %ebx, 4) # Basis im CPU-Register EAX (%eax), Index im CPU-Register EBX, Skalierung = 4, Displacement = 32
    ret

Vergisst man ein Sternchen zu setzen, kommt vom gas eine Warnung:
Zitat:
... Warning: indirect jmp without `*'

Warum das so ist, weiss ich ehrlich gesagt nicht, habe im Manual dazu nichts gefunden und habe ehrlich gesagt, nicht intensiv danach gesucht.

Bezüglich Assembler-Inline im C-Code kann ich leider nicht viel sagen. Ich weiss nur, dass man bei Registern zwei % Zeichen setzen muss. Ansonsten lässt sich, denke ich, obige Info auch so übernehmen. Und es gibt noch eine weitere Schar von Regeln für den Inline, die man kennen sollte...

Ich hoffe, ich konnte bisschen Licht auf die AT&T Syntax werfen (die ja zu unrecht verteufelt wird)... ;)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 12:38:07 02.05.2009   Titel:              Zitieren

Zitat:
die ja zu unrecht verteufelt wird
Ich fange an, mich daran zu gewöhnen. Die C-Syntax ist ja auch nicht jedes Coders Lieblingsspeise.

Momentan kämpfe ich gerade mit dem Thema Paging und versuche die Dinge so weit wie möglich zu visualisieren.

Dabei habe ich eine Frage zum Alignment: Wenn die memory_placement_address nach einem k_malloc bei exakt 200000h liegt bei PAGESIZE = 1000h und man belegt nun weitere 2000h, wo muss es dann weiter gehen, bei 202000h oder 203000h? Der Algo, den ich von JM übernommen habe, macht momentan bei 203000h weiter, kommt mir verschwenderisch vor. Aber vielleicht habe ich da etwas noch nicht ganz verstanden. :D

C/C++ Code:
if( align == 1 && (placement_address & 0xFFFFF000) )
{
    placement_address &= 0xFFFFF000;
    placement_address += PAGESIZE;
}
C/C++ Code:
if( align == 1 && (placement_address & 0xFFFFF000) )
{
placement_address &= 0xFFFFF000;
placement_address += PAGESIZE;
}
C/C++ Code:
if( align == 1 && (placement_address & 0xFFFFF000) )
{
    placement_address &= 0xFFFFF000;
    placement_address += PAGESIZE;
}


Wenn ( placement_address == (placement_address & 0xFFFFF000) ) könnte man das Addieren der PAGESIZE doch sparen. Aufrunden muss man doch nur bei placement_address > (placement_address & 0xFFFFF000) ?

Beispiel:
placement_address startet mit 200000h. Wegen align=0 startet es auch genau dort. Bei align=1 hätte es bei 201000h begonnen. Ist das korrekt oder muss ich obige Abfrage auf die letzten 3 Hex-Nuller ergänzen?
Zitat:
setup bitset:
old: 00200000h sz: 00002000h a: 0 new: 00202000h

make a page directory:
old: 00203000h sz: 00002004h a: 1 new: 00205004h


Daher halte ich diese verfeinerte Version für richtig:
C/C++ Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
if( align == 1 /*&& (placement_address & 0xFFFFF000)*/ )
{
    if( !(placement_address == (placement_address & 0xFFFFF000) ) ) // New !!!
    {
        placement_address &= 0xFFFFF000;
        placement_address += PAGESIZE;
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
if( align == 1 /*&& (placement_address & 0xFFFFF000)*/ )
{
if( !(placement_address == (placement_address & 0xFFFFF000) ) ) // New !!!
{
placement_address &= 0xFFFFF000;
placement_address += PAGESIZE;
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
if( align == 1 /*&& (placement_address & 0xFFFFF000)*/ )
{
    if( !(placement_address == (placement_address & 0xFFFFF000) ) ) // New !!!
    {
        placement_address &= 0xFFFFF000;
        placement_address += PAGESIZE;
    }
}


Please comment. :)

Das && (placement_address & 0xFFFFF000) von JM verstehe ich auch nicht. Das kann man doch genau so gut weg lassen? :confused:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:09:22 02.05.2009, insgesamt 10-mal bearbeitet
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 20:01:54 02.05.2009   Titel:              Zitieren

The Intel manuals tells everything about the x86(-64) architecture, including paging. Why would you do that stuff in ASM? But that's you own choice, what I posted is how I would go work.

use:

C/C++ Code:
if(aligned == 1 && (placement_address & 0x00000fff))
{
   placement_address &= 0xfffff000;
   placement_address += 0x1000;
}
C/C++ Code:
if(aligned == 1 && (placement_address & 0x00000fff))
{
placement_address &= 0xfffff000;
placement_address += 0x1000;
}
C/C++ Code:
if(aligned == 1 && (placement_address & 0x00000fff))
{
   placement_address &= 0xfffff000;
   placement_address += 0x1000;
}


Open the WIndows calulcator, science mode, and do something in it like this. Just putting in some number, anding with 0x00000fff or 0xfffff000.

Something everybody here should know: each part of a hexidecimal number (0x12345678, 1 is a part, 2 a part, etc.) is 4 bits in length. so 0xfffff000 makes 12 bits zero :)

Success

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:16:56 02.05.2009   Titel:              Zitieren

Ah, that's o.k. It rounds up to next 1000h, if it is not xxxxx000h. Good.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:22:13 02.05.2009, insgesamt 2-mal bearbeitet
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 20:19:02 02.05.2009   Titel:              Zitieren

No, if address is xxxxx000h, it wont do anything. If it is not, it will make it so. And add a page, so no data will be overwritten.

Calculate it :P

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:21:35 02.05.2009   Titel:              Zitieren

Please excuse, at the first view I thought it's the same as JM's code. But it's the opposite. :) Follows the same logic I proposed. Right?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:26:56 02.05.2009   Titel:              Zitieren

OK, let's compare the three codes:

PHPnerd:
C/C++ Code:
if(aligned == 1 && (placement_address & 0x00000fff))
{
   placement_address &= 0xfffff000;
   placement_address += PAGESIZE;
}
C/C++ Code:
if(aligned == 1 && (placement_address & 0x00000fff))
{
placement_address &= 0xfffff000;
placement_address += PAGESIZE;
}
C/C++ Code:
if(aligned == 1 && (placement_address & 0x00000fff))
{
   placement_address &= 0xfffff000;
   placement_address += PAGESIZE;
}


My proposal:
C/C++ Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
if( align == 1  )
{
    if( !(placement_address == (placement_address & 0xFFFFF000) ) )
    {
        placement_address &= 0xFFFFF000;
        placement_address += PAGESIZE;
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
if( align == 1 )
{
if( !(placement_address == (placement_address & 0xFFFFF000) ) )
{
placement_address &= 0xFFFFF000;
placement_address += PAGESIZE;
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
if( align == 1  )
{
    if( !(placement_address == (placement_address & 0xFFFFF000) ) )
    {
        placement_address &= 0xFFFFF000;
        placement_address += PAGESIZE;
    }
}


JM's code wasting memory - very bad!
C/C++ Code:
if( align == 1 && (placement_address & 0xFFFFF000) )
{
    placement_address &= 0xFFFFF000;
    placement_address += PAGESIZE;
}
C/C++ Code:
if( align == 1 && (placement_address & 0xFFFFF000) )
{
placement_address &= 0xFFFFF000;
placement_address += PAGESIZE;
}
C/C++ Code:
if( align == 1 && (placement_address & 0xFFFFF000) )
{
    placement_address &= 0xFFFFF000;
    placement_address += PAGESIZE;
}


I have to admit that your code is elegant, but my code might be the best to understand. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:22:13 02.05.2009, insgesamt 6-mal bearbeitet
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 20:30:53 02.05.2009   Titel:              Zitieren

Yeah, results the same, but my way will be lots faster. (some cycles, so some billions of a second). Mine is better to understand, i dont understand yours

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix


Zuletzt bearbeitet von PHPnerd am 20:31:28 02.05.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:34:14 02.05.2009   Titel:              Zitieren

OK, let's do it our own way! I will use my code. :live:

I have compared the objdump of both kmalloc (w/o optimization).
There is only a tiny difference in these asm lines:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
//PHPnerd’s Code:  

  31:    a1 90 00 00 00           mov    0x90,%eax
  36:    a9 ff 0f 00 00           test   $0xfff,%eax
  3b:    74 0f                    je     4c <_k_malloc+0x2e>
  3d:    25 00 f0 ff ff           and    $0xfffff000,%eax

//My Code:

  31:    a1 90 00 00 00           mov    0x90,%eax
  36:    25 00 f0 ff ff           and    $0xfffff000,%eax
  3b:    39 05 90 00 00 00        cmp    %eax,0x90
  41:    74 0a                    je     4d <_k_malloc+0x2f>  
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
//PHPnerd’s Code:

31: a1 90 00 00 00 mov 0x90,%eax
36: a9 ff 0f 00 00 test $0xfff,%eax
3b: 74 0f je 4c <_k_malloc+0x2e>
3d: 25 00 f0 ff ff and $0xfffff000,%eax

//My Code:

31: a1 90 00 00 00 mov 0x90,%eax
36: 25 00 f0 ff ff and $0xfffff000,%eax
3b: 39 05 90 00 00 00 cmp %eax,0x90
41: 74 0a je 4d <_k_malloc+0x2f>
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
//PHPnerd’s Code:  

  31:    a1 90 00 00 00           mov    0x90,%eax
  36:    a9 ff 0f 00 00           test   $0xfff,%eax
  3b:    74 0f                    je     4c <_k_malloc+0x2e>
  3d:    25 00 f0 ff ff           and    $0xfffff000,%eax

//My Code:

  31:    a1 90 00 00 00           mov    0x90,%eax
  36:    25 00 f0 ff ff           and    $0xfffff000,%eax
  3b:    39 05 90 00 00 00        cmp    %eax,0x90
  41:    74 0a                    je     4d <_k_malloc+0x2f>  

I need 18 and PHPnerd 17 bytes. Your code is really better? :live:

I think that's a good example for the tutorial: How to compare your own code with other solutions? :)

Well, the topic "alignment" now is clarified. :leak:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:32:52 02.05.2009, insgesamt 7-mal bearbeitet
PHPnerd
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2009
Beiträge: 27
Beitrag PHPnerd Mitglied 21:11:24 02.05.2009   Titel:              Zitieren

Intel's code? No, it is my code :P

I said it was better :P, I think you miss something with the objdump, because your code didnt actually do everything you wrote in C. (do a check on alignment, A == (A AND 0xfffff000) THEN A AND 0xfffff000, ADD A, 0x1000)

// PHPnerd

_________________
Being Dutch. Talking English. On a German community.

Jinix
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:20:02 02.05.2009   Titel:              Zitieren

Zitat:
Intel's code? No, it is my code
Please excuse. You were talking so much about Intel that I thought they have published it in there manual. :D
I corrected it in the thread (Intel -> PHPnerd).

Zitat:
I think you miss something with the objdump
I have checked both dumps, the rest is identical AFAIK: http://www.henkessoft.de/OS_Dev/Downloads/kmalloc_objdump_comparison.zip

Ich habe mal vorsichtig begonnen die Themen:
Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
Eigene Betriebssystementwicklung am PC  -  Teil 2
    - Key Queue und Key Handler
    - Speicher Management
          - Physical Memory Management (PMM)
                - k_malloc( size, align, phys )
          - Virtual Memory Management (VMM)
                - Virtueller Speicher und Swapping
                - Paging
Code:
1
2
3
4
5
6
7
8
Eigene Betriebssystementwicklung am PC - Teil 2
- Key Queue und Key Handler
- Speicher Management
- Physical Memory Management (PMM)
- k_malloc( size, align, phys )
- Virtual Memory Management (VMM)
- Virtueller Speicher und Swapping
- Paging
Code:
1
2
3
4
5
6
7
8
Eigene Betriebssystementwicklung am PC  -  Teil 2
    - Key Queue und Key Handler
    - Speicher Management
          - Physical Memory Management (PMM)
                - k_malloc( size, align, phys )
          - Virtual Memory Management (VMM)
                - Virtueller Speicher und Swapping
                - Paging

zu verarbeiten. Code zum Downloaden biete ich noch keinen an, weil ich mit PHPnerd noch über die Funktion set_page(...) diskutiere:

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
page_t* set_page(ULONG address, page_directory_t* dir)
{
    //ULONG tmp = address;
    address>>=12; // /= PAGESIZE        // index <== address
    ULONG table_index = (address>>10);  // ==> page table containing this address

    //TODO: check it against Intel Manual 3A !!!

    if(
        ( ( (ULONG)(  dir->tablesPhysical[table_index] ) ) & 0x1 )
                  && (dir->tables[table_index])
      )
        putch('!');
    else
    {
        putch('?'); /*printformat(" address: %x\n",tmp)*/;
        ULONG phys;
        dir->tables[table_index] = (page_table_t*) k_malloc( sizeof(page_table_t), 1, &phys );
        k_memset(dir->tables[table_index], 0, PAGESIZE);
        dir->tablesPhysical[table_index] = phys | 0x7; // 111b meaning: PRESENT=1, RW=1, USER=1
    }
    return &dir->tables[table_index]->pages[address%1024];
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
page_t* set_page(ULONG address, page_directory_t* dir)
{
//ULONG tmp = address;
address>>=12; // /= PAGESIZE // index <== address
ULONG table_index = (address>>10); // ==> page table containing this address

//TODO: check it against Intel Manual 3A !!!

if(
( ( (ULONG)( dir->tablesPhysical[table_index] ) ) & 0x1 )
&& (dir->tables[table_index])
)
putch('!');
else
{
putch('?'); /*printformat(" address: %x\n",tmp)*/;
ULONG phys;
dir->tables[table_index] = (page_table_t*) k_malloc( sizeof(page_table_t), 1, &phys );
k_memset(dir->tables[table_index], 0, PAGESIZE);
dir->tablesPhysical[table_index] = phys | 0x7; // 111b meaning: PRESENT=1, RW=1, USER=1
}
return &dir->tables[table_index]->pages[address%1024];
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
page_t* set_page(ULONG address, page_directory_t* dir)
{
    //ULONG tmp = address;
    address>>=12; // /= PAGESIZE        // index <== address
    ULONG table_index = (address>>10);  // ==> page table containing this address

    //TODO: check it against Intel Manual 3A !!!

    if(
        ( ( (ULONG)(  dir->tablesPhysical[table_index] ) ) & 0x1 )
                  && (dir->tables[table_index])
      )
        putch('!');
    else
    {
        putch('?'); /*printformat(" address: %x\n",tmp)*/;
        ULONG phys;
        dir->tables[table_index] = (page_table_t*) k_malloc( sizeof(page_table_t), 1, &phys );
        k_memset(dir->tables[table_index], 0, PAGESIZE);
        dir->tablesPhysical[table_index] = phys | 0x7; // 111b meaning: PRESENT=1, RW=1, USER=1
    }
    return &dir->tables[table_index]->pages[address%1024];
}

Da gibt es noch Unklarheiten bei der Abfrage, ob eine page table wirklich schon assigned ist. JM fragt hier mittels if(dir->tables[table_index]) ab, während PHPnerd der Meinung ist, dass dies nicht reicht und man auch das Present Bit abfragen sollte. Ich habe mal das der Physical Tables beid er Abfrage hinzu gefügt, weil das im else-Zweig auf 1 gesetzt wird. Sollte soweit gehen.

Da bin ich noch nicht ganz sicher in diesem Bereich des Pagings, auch was die Visualisierung der Baumstruktur CR3 -> PD mit PDE -> PT mit PTE -> Page mit Offset -> physikalische Adresse und der jeweils zugehörigen Zustands-Bits von PD, PT und Page angeht.

http://www.henkessoft.de/OS_Dev/OS_Dev2.htm

PHPnerd ist der Meinung, JM's Code im VMM-Bereich sei sehr schlecht und empfiehlt eine "Neukonstruktion" auf Basis Intel Manual 3A (da steht aber nichts drinnen, was ich nicht schon wusste, die Sekundärliteratur ist inzwischen ziemlich gut). Ich verwende zunächst mal obige set_page(...), bis ich etwas Besseres habe. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:15:44 03.05.2009, insgesamt 8-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:50:21 03.05.2009   Titel:              Zitieren

Nochmal eine ganz andere Frage an die Assembler-Spezialisten zum Teil 1:

http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId412221
Dort finden sich [Bits 16] und [Bits 32] in einer Übersetzungseinheit (Übergang von RM nach PM). Vielleicht kann man das so verändern, so dass man COFF (32bit, stringentes Format, akzeptiert keinen 16 bit Bereich) anstelle aout (16 und 32 bit gemischt, tolles Format!) verwenden kann? Benötigen wir diesen Eintrag [Bits 16] wirklich? Andere erzählen mir, man sollte den 16/32 Bit Zirkus im Bootloader abwickeln und den Kernel komplett in 32 Bit halten. Ich weiß, dass ich dies versucht habe (man kann kernel.asm ja als verlängerten Bootloader ansehen), aber ein Sprung aus dem Binär-Format nach C-Funktionen war nicht erlaubt.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 12:17:28 03.05.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:27:46 05.05.2009   Titel:              Zitieren

PMM (Bit Array) und VMM (Paging) ist nun im Tutorial umgesetzt:
http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId918986
http://www.henkessoft.de/OS_Dev/Downloads/20090503_PrettyOS_104.zip

Allerdings bin ich didaktisch noch nicht zufrieden.

EDIT(5.5.): Ich habe nun noch folgende Funktion zur Sichtbarmachung der Paging-Zusammenhänge eingeführt:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void analyze_PD_PT_Pages(ULONG PDE, ULONG PTE, page_directory_t* dir)
{
    k_clear_screen();
    ULONG cr3;
    asm volatile("mov %%cr3, %0": "=r"(cr3)); // read cr3
    printformat( "PDBR cr3:       %x\n", cr3 );
    printformat( "PD phys. addr.: %x\n", dir->physicalAddr );

    int i,j;
    for(i=0;i<PDE;++i)
    {
        printformat( "  PDE %d: phys: %x virt: %x\n", i, dir->tablesPhysical[i], dir->tables[i] );
        for(j=0;j<PTE;++j)
        {
            printformat( "    PTE %d: addr: %x frame-addr: %x\n", j,
                                &(dir->tables[i]->pages[j]),
                         (ULONG)( dir->tables[i]->pages[j].frame_addr)<<12
                       );
        }
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void analyze_PD_PT_Pages(ULONG PDE, ULONG PTE, page_directory_t* dir)
{
k_clear_screen();
ULONG cr3;
asm volatile("mov %%cr3, %0": "=r"(cr3)); // read cr3
printformat( "PDBR cr3: %x\n", cr3 );
printformat( "PD phys. addr.: %x\n", dir->physicalAddr );

int i,j;
for(i=0;i<PDE;++i)
{
printformat( " PDE %d: phys: %x virt: %x\n", i, dir->tablesPhysical[i], dir->tables[i] );
for(j=0;j<PTE;++j)
{
printformat( " PTE %d: addr: %x frame-addr: %x\n", j,
&(dir->tables[i]->pages[j]),
(ULONG)( dir->tables[i]->pages[j].frame_addr)<<12
);
}
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void analyze_PD_PT_Pages(ULONG PDE, ULONG PTE, page_directory_t* dir)
{
    k_clear_screen();
    ULONG cr3;
    asm volatile("mov %%cr3, %0": "=r"(cr3)); // read cr3
    printformat( "PDBR cr3:       %x\n", cr3 );
    printformat( "PD phys. addr.: %x\n", dir->physicalAddr );

    int i,j;
    for(i=0;i<PDE;++i)
    {
        printformat( "  PDE %d: phys: %x virt: %x\n", i, dir->tablesPhysical[i], dir->tables[i] );
        for(j=0;j<PTE;++j)
        {
            printformat( "    PTE %d: addr: %x frame-addr: %x\n", j,
                                &(dir->tables[i]->pages[j]),
                         (ULONG)( dir->tables[i]->pages[j].frame_addr)<<12
                       );
        }
    }
}

in kernel.c:
C/C++ Code:
analyze_PD_PT_Pages(1,10,kernel_directory);
C/C++ Code:
analyze_PD_PT_Pages(1,10,kernel_directory);
C/C++ Code:
analyze_PD_PT_Pages(1,10,kernel_directory);

screen output:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
PDBR cr3:       00202000h
PD phys. addr.: 00202000h
  PDE 0: phys: 00205027h virt: 00205000h
    PTE 0: addr: 00205000h frame-addr: 00000000h
    PTE 1: addr: 00205004h frame-addr: 00001000h
    PTE 2: addr: 00205008h frame-addr: 00002000h
    PTE 3: addr: 0020500Ch frame-addr: 00003000h
    PTE 4: addr: 00205010h frame-addr: 00004000h
    PTE 5: addr: 00205014h frame-addr: 00005000h
    PTE 6: addr: 00205018h frame-addr: 00006000h
    PTE 7: addr: 0020501Ch frame-addr: 00007000h
    PTE 8: addr: 00205020h frame-addr: 00008000h
    PTE 9: addr: 00205024h frame-addr: 00009000h
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
PDBR cr3: 00202000h
PD phys. addr.: 00202000h
PDE 0: phys: 00205027h virt: 00205000h
PTE 0: addr: 00205000h frame-addr: 00000000h
PTE 1: addr: 00205004h frame-addr: 00001000h
PTE 2: addr: 00205008h frame-addr: 00002000h
PTE 3: addr: 0020500Ch frame-addr: 00003000h
PTE 4: addr: 00205010h frame-addr: 00004000h
PTE 5: addr: 00205014h frame-addr: 00005000h
PTE 6: addr: 00205018h frame-addr: 00006000h
PTE 7: addr: 0020501Ch frame-addr: 00007000h
PTE 8: addr: 00205020h frame-addr: 00008000h
PTE 9: addr: 00205024h frame-addr: 00009000h
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
PDBR cr3:       00202000h
PD phys. addr.: 00202000h
  PDE 0: phys: 00205027h virt: 00205000h
    PTE 0: addr: 00205000h frame-addr: 00000000h
    PTE 1: addr: 00205004h frame-addr: 00001000h
    PTE 2: addr: 00205008h frame-addr: 00002000h
    PTE 3: addr: 0020500Ch frame-addr: 00003000h
    PTE 4: addr: 00205010h frame-addr: 00004000h
    PTE 5: addr: 00205014h frame-addr: 00005000h
    PTE 6: addr: 00205018h frame-addr: 00006000h
    PTE 7: addr: 0020501Ch frame-addr: 00007000h
    PTE 8: addr: 00205020h frame-addr: 00008000h
    PTE 9: addr: 00205024h frame-addr: 00009000h


Jetzt versteht man die Zusammenhänge besser und z.B. auch, warum der Bereich von 205000h bis 206000h noch gemappt wurde:
map phys addr to virt addr from 0x0 to the end of used memory:
?old: 00205000h sz: 00001000h a: 1 new: 00206000h

Nun ist schon besser. Das werde ich noch ins Tut einbauen, vielleicht noch mit den wichtigsten Bits der Pages hinter den Adressen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 21:04:27 05.05.2009, insgesamt 4-mal bearbeitet
lmb
Mitglied

Benutzerprofil
Anmeldungsdatum: 04.05.2009
Beiträge: 35
Beitrag lmb Mitglied 16:21:12 06.05.2009   Titel:              Zitieren

übrigend funktioniert der source code vom c-kernel bei mir auch nicht.
weder mit make.exe noch mit einer batch
die gcc.exe und ld.exe habe ich aber ins verzeichniss reinkopiert, die fehlen im zip
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:23:38 06.05.2009   Titel:              Zitieren

Zitat:
gcc.exe und ld.exe habe ich aber ins verzeichniss reinkopiert
Das solltest Du nicht machen, sondern diese nach C:\djgpp installieren. Pfad und Env korrekt setzen wie beschrieben. Nimm genau den DJGPP aus dem im Tutorial angegebenen Link wegen dem aout-Format. Falls dann etwas nicht klappt, bitte erst Fehlermeldung lesen und probieren. Wenn Du nicht mehr weiter kommst, genaue Meldung posten. Hast Du schon mit Assembler und C-Compiler gearbeitet?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:32:31 07.05.2009, insgesamt 2-mal bearbeitet
lmb
Mitglied

Benutzerprofil
Anmeldungsdatum: 04.05.2009
Beiträge: 35
Beitrag lmb Mitglied 18:26:21 06.05.2009   Titel:              Zitieren

upps
stimmt ja *boing*
ich probiers demnächst aus :D
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:08:36 07.05.2009   Titel:              Zitieren

Das Thema Heap ist nun ebenfalls im Tutorial auf Basis des Algos von Doug Lea grundlegend verarbeitet. Wer sich als Leser tiefer hinein bohren möchte, kann es mit den Links machen, für PrettyOS ist nur die Anwendung wichtig.
http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId620585

Der Mechanismus funktioniert grob wie folgt:
Zitat:
- Kleinstes Loch ("hole") für die gesuchte Größe in einem geordneten Array suchen. Wenn dies nicht klappt: Heap expandieren etc.
- Loch in zwei Teile zerlegen
- Nicht mehr existentes ursprüngliches Loch vom Index streichen
- Neuen Header und Footer für den allokierten Block schreiben
- Bei der Zweiteilung erzeugtes zweites nicht besetztes Loch in den Index eintragen
- Rückgabe der Adresse des allokierten Blocks plus sizeof(header_t)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:49:36 07.05.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:57:56 07.05.2009   Titel:              Zitieren

Ich wollte das Ende des Kernelbereichs bestimmen. Dazu veränderte ich das Linker-Skript wie folgt:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
phys = 0x00008000;
SECTIONS
{
  .text phys  : {
    *(.text)
  }
  .data  : {
    *(.data)
  }
  .bss : {
    *(.bss)  
  }
   _endkernel = .;  
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
phys = 0x00008000;
SECTIONS
{
.text phys : {
*(.text)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
_endkernel = .;
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
phys = 0x00008000;
SECTIONS
{
  .text phys  : {
    *(.text)
  }
  .data  : {
    *(.data)
  }
  .bss : {
    *(.bss)  
  }
   _endkernel = .;  
}


C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
//os.c
extern ULONG* endkernel;
ULONG get_end_kernel(){ return *endkernel; }

//ckernel.c
int main()
{
    k_clear_screen();
    printformat("end of kernel %x\n", get_end_kernel());
    //...
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
//os.c
extern ULONG* endkernel;
ULONG get_end_kernel(){ return *endkernel; }

//ckernel.c
int main()
{
k_clear_screen();
printformat("end of kernel %x\n", get_end_kernel());
//...
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
//os.c
extern ULONG* endkernel;
ULONG get_end_kernel(){ return *endkernel; }

//ckernel.c
int main()
{
    k_clear_screen();
    printformat("end of kernel %x\n", get_end_kernel());
    //...
}

liefert:
Zitat:
end of kernel F000FF53h

Nach meinen Berechnungen sollte natürlich ein deutlich niedrigerer Wert heraus kommen. 0x8000 (start) + 0x3540 (Hexeditor MyOS.bin) - 0x0200 (bootloader sector) = 0xB340
Auch wenn ich _endkernel = .; hinter data setze, kommt das Gleiche heraus. Was mache ich verkehrt? :confused:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:00:23 07.05.2009, insgesamt 1-mal bearbeitet
blitzmaster
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 45
Beitrag blitzmaster Mitglied 22:07:59 07.05.2009   Titel:              Zitieren

so wie ich das sehe, deklarierst du mit
C/C++ Code:
extern ULONG* endkernel;
C/C++ Code:
extern ULONG* endkernel;
C/C++ Code:
extern ULONG* endkernel;
die Variable als Zeiger; das ist noch korrekt, aber du willst da die Adresse, und nicht den Inhalt an dieser Stelle, also
C/C++ Code:
ULONG get_end_kernel(){ return endkernel; }
C/C++ Code:
ULONG get_end_kernel(){ return endkernel; }
C/C++ Code:
ULONG get_end_kernel(){ return endkernel; }
(beachte: ohne stern!) somit kannst du den Pointer auch vom Typ void* oder char* machen, da du ja die Daten, die am Ende deines Kernels sind nicht auslesen möchtest, oder vl. schon^^
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:38:24 07.05.2009   Titel:              Zitieren

Klar Adresse der Variablen, nicht Inhalt. Habe da beides durchmischt.
So klappt es:
C/C++ Code:
extern ULONG endkernel;
ULONG get_end_kernel()
{
    return (ULONG) &endkernel;
}
C/C++ Code:
extern ULONG endkernel;
ULONG get_end_kernel()
{
return (ULONG) &endkernel;
}
C/C++ Code:
extern ULONG endkernel;
ULONG get_end_kernel()
{
    return (ULONG) &endkernel;
}

und _endkernel vor bss (Block Started by Symbol)
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
phys = 0x00008000;
SECTIONS
{
  .text phys  : {
    *(.text)
  }
  .data  : {
    *(.data)
  }
  _endkernel = .;  
  .bss : {
    *(.bss)    
  }
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
phys = 0x00008000;
SECTIONS
{
.text phys : {
*(.text)
}
.data : {
*(.data)
}
_endkernel = .;
.bss : {
*(.bss)
}
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
phys = 0x00008000;
SECTIONS
{
  .text phys  : {
    *(.text)
  }
  .data  : {
    *(.data)
  }
  _endkernel = .;  
  .bss : {
    *(.bss)    
  }
}

ergeben:
Zitat:
end of kernel 0000B320h

Das passt gut zu meiner Schätzung.

Hinter dem .bss Block ist der Wert höher:
Zitat:
end of kernel 0000BC00h

bss: http://en.wikipedia.org/wiki/Block_Started_by_Symbol

Was ist das wirkliche Ende des Kernels? B320h (ohne bss) oder BC00h (incl. bss)?
Ich denke incl. bss ist korrekt.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:40:23 07.05.2009, insgesamt 2-mal bearbeitet
lmb
Mitglied

Benutzerprofil
Anmeldungsdatum: 04.05.2009
Beiträge: 35
Beitrag lmb Mitglied 10:19:32 09.05.2009   Titel:              Zitieren

bei der ckernel.c, wozu ist der string gut?
der wird doch nirgendwo ausgegeben oder?
bei mir werdeb nur die strings aus dem bootloader ausgegeben.
mfg
lukas
ps:
es wäre cool, wenn du dein tutorial mit einem dateisystem erweitern würdest.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 13:20:54 09.05.2009   Titel:              Zitieren

Zitat:
bei der ckernel.c, wozu ist der string gut?

Den PrettyOS ...? Ja, den kannst Du streichen, das erfolgt auch in den weiteren Versionen, da man Version und Datum nur an einer Stelle halten sollte. ;)

Zitat:
es wäre cool, wenn du dein Tutorial mit einem Dateisystem erweitern würdest.
Eigenes Dateisystem, VFS, RAM Disk etc. kommt noch. Zur Zeit hänge ich immer noch am Taskswitching fest.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 13:22:56 09.05.2009, insgesamt 1-mal bearbeitet
lmb
Mitglied

Benutzerprofil
Anmeldungsdatum: 04.05.2009
Beiträge: 35
Beitrag lmb Mitglied 15:14:27 09.05.2009   Titel:              Zitieren

gut, ich hab mich schon gewundert.

task switching?
also wie fenster ohne fenster?
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 15:46:12 09.05.2009   Titel:              Zitieren

Zitat:
task switching?
Multitasking, also z.B. Timer-gesteuertes Umschalten zwischen Prozessen mit allem Drum und Dran. Schwieriges Thema, zumindest für mich.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 15:49:59 09.05.2009, insgesamt 2-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 16:55:36 09.05.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Multitasking, also z.B. Timer-gesteuertes Umschalten zwischen Prozessen mit allem Drum und Dran. Schwieriges Thema, zumindest für mich.

das grundprinzip ist doch klar, oder? task wird vom timer-interrupt unterbrochen, der speichert alle registerinhalte der task und beim verlassen setzt er registerinhalte für die nächste task. schwierig sind dabei nur irgendwelche abgefahrenen scheduling-algorithmen, aber darum brauchste dich am anfang nicht zu kümmern, machste einfach primitivstes round-robin scheduling, d.h. einfach mit 'ner festen frequenz immer weiterswitchen und nachdem die letzte task dran war, kommt wieder die erste dran.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 16:09:22 10.05.2009   Titel:              Zitieren

Zitat:
darum brauchste dich am anfang nicht zu kümmern, machste einfach primitivstes round-robin scheduling, d.h. einfach mit 'ner festen frequenz immer weiterswitchen und nachdem die letzte task dran war, kommt wieder die erste dran.
Der Mechanismus funktioniert bereits, über mit vier Tasks.

Zitat:
das grundprinzip ist doch klar, oder?
Ja, mir macht die Abstimmung zwischen TSS entry (nur eine), CR3 (Physikalische Adresse der Page Directory des jeweiligen virtuellen Adressraums), Struktur task_t (für jede Task eine) und eigener Kernel_Stack pro Task noch etwas Probleme. Da stecke ich noch etwas fest. Ich möchte den Task Switch prinzipiell auch außerhalb eines Interrupts durchführen können, um ihn zu studieren. Denn im timer_handler macht es schnell bumm, dann ist es schwer zu analysieren, was eigentlich los ist (GPF, OpcodeF, DebugF, Reset, doing nothing, ...). Erst mit vollständigen log-Funktionen - passend zu den Strukturen task_t und tss_entry_t erkennt man, was im Hintergrund abgeht:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
void task_log(task_t* t)
{
    printformat("id: %d ", t->id);               // Process ID
    printformat("ebp: %x ",t->ebp);              // Base pointer
    printformat("esp: %x ",t->esp);              // Stack pointer
    printformat("eip: %x ",t->eip);              // Instruction pointer
    printformat("PD: %x ", t->page_directory);   // Page directory.
    printformat("k_stack: %x ",t->kernel_stack); // Kernel stack location.
    printformat("next: %x\n",  t->next);         // The next task in a linked list.
}

void TSS_log(tss_entry_t* tss)
{
    printformat("prev_tss: %x ", tss->prev_tss);
    printformat("esp0: %x ", tss->esp0);
    printformat("ss0: %x ", tss->ss0);
    printformat("esp1: %x ", tss->esp1);
    printformat("ss1: %x ", tss->ss1);
    printformat("esp2: %x ", tss->esp2);
    printformat("ss2: %x ", tss->ss2);
    printformat("cr3: %x ", tss->cr3);
    printformat("eip: %x ", tss->eip);
    printformat("eflags: %x ", tss->eflags);
    printformat("eax: %x ", tss->eax);
    printformat("ecx: %x ", tss->ecx);
    printformat("edx: %x ", tss->edx);
    printformat("ebx: %x ", tss->ebx);
    printformat("esp: %x ", tss->esp);
    printformat("ebp: %x ", tss->ebp);
    printformat("esi: %x ", tss->esi);
    printformat("edi: %x ", tss->edi);
    printformat("es: %x ", tss->es);
    printformat("cs: %x ", tss->cs);
    printformat("ss: %x ", tss->ss);
    printformat("ds: %x ", tss->ds);
    printformat("fs: %x ", tss->fs);
    printformat("gs: %x ", tss->gs);
    printformat("ldt: %x ", tss->ldt);
    printformat("trap: %x ", tss->trap); //only 0 or 1
    printformat("iomap_base: %x ", tss->iomap_base);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
void task_log(task_t* t)
{
printformat("id: %d ", t->id); // Process ID
printformat("ebp: %x ",t->ebp); // Base pointer
printformat("esp: %x ",t->esp); // Stack pointer
printformat("eip: %x ",t->eip); // Instruction pointer
printformat("PD: %x ", t->page_directory); // Page directory.
printformat("k_stack: %x ",t->kernel_stack); // Kernel stack location.
printformat("next: %x\n", t->next); // The next task in a linked list.
}

void TSS_log(tss_entry_t* tss)
{
printformat("prev_tss: %x ", tss->prev_tss);
printformat("esp0: %x ", tss->esp0);
printformat("ss0: %x ", tss->ss0);
printformat("esp1: %x ", tss->esp1);
printformat("ss1: %x ", tss->ss1);
printformat("esp2: %x ", tss->esp2);
printformat("ss2: %x ", tss->ss2);
printformat("cr3: %x ", tss->cr3);
printformat("eip: %x ", tss->eip);
printformat("eflags: %x ", tss->eflags);
printformat("eax: %x ", tss->eax);
printformat("ecx: %x ", tss->ecx);
printformat("edx: %x ", tss->edx);
printformat("ebx: %x ", tss->ebx);
printformat("esp: %x ", tss->esp);
printformat("ebp: %x ", tss->ebp);
printformat("esi: %x ", tss->esi);
printformat("edi: %x ", tss->edi);
printformat("es: %x ", tss->es);
printformat("cs: %x ", tss->cs);
printformat("ss: %x ", tss->ss);
printformat("ds: %x ", tss->ds);
printformat("fs: %x ", tss->fs);
printformat("gs: %x ", tss->gs);
printformat("ldt: %x ", tss->ldt);
printformat("trap: %x ", tss->trap); //only 0 or 1
printformat("iomap_base: %x ", tss->iomap_base);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
void task_log(task_t* t)
{
    printformat("id: %d ", t->id);               // Process ID
    printformat("ebp: %x ",t->ebp);              // Base pointer
    printformat("esp: %x ",t->esp);              // Stack pointer
    printformat("eip: %x ",t->eip);              // Instruction pointer
    printformat("PD: %x ", t->page_directory);   // Page directory.
    printformat("k_stack: %x ",t->kernel_stack); // Kernel stack location.
    printformat("next: %x\n",  t->next);         // The next task in a linked list.
}

void TSS_log(tss_entry_t* tss)
{
    printformat("prev_tss: %x ", tss->prev_tss);
    printformat("esp0: %x ", tss->esp0);
    printformat("ss0: %x ", tss->ss0);
    printformat("esp1: %x ", tss->esp1);
    printformat("ss1: %x ", tss->ss1);
    printformat("esp2: %x ", tss->esp2);
    printformat("ss2: %x ", tss->ss2);
    printformat("cr3: %x ", tss->cr3);
    printformat("eip: %x ", tss->eip);
    printformat("eflags: %x ", tss->eflags);
    printformat("eax: %x ", tss->eax);
    printformat("ecx: %x ", tss->ecx);
    printformat("edx: %x ", tss->edx);
    printformat("ebx: %x ", tss->ebx);
    printformat("esp: %x ", tss->esp);
    printformat("ebp: %x ", tss->ebp);
    printformat("esi: %x ", tss->esi);
    printformat("edi: %x ", tss->edi);
    printformat("es: %x ", tss->es);
    printformat("cs: %x ", tss->cs);
    printformat("ss: %x ", tss->ss);
    printformat("ds: %x ", tss->ds);
    printformat("fs: %x ", tss->fs);
    printformat("gs: %x ", tss->gs);
    printformat("ldt: %x ", tss->ldt);
    printformat("trap: %x ", tss->trap); //only 0 or 1
    printformat("iomap_base: %x ", tss->iomap_base);
}

Siehe Intel Manual 3A, "Figure 6-2. 32-Bit Task-State Segment (TSS)"

Die Struktur task_t muss sicher noch erweitert werden. ich möchte diese für das Tutorial aber auch nicht überfrachten, damit man den Überblick nicht verliert.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 17:45:57 10.05.2009, insgesamt 4-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:35:19 10.05.2009   Titel:              Zitieren

Da es im timer_handler mit einer exception ausgestoppt wird, könnte das Problem im asm stub liegen. Ich verwende dort folgenden Code:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
extern _irq_handler

irq_common_stub:
   pusha
   push ds
   push es
   push fs
   push gs

   mov ax, 0x10
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax
   mov eax, esp

   push eax
   mov eax, _irq_handler
   call eax
   pop eax

   pop gs
   pop fs
   pop es
   pop ds
   popa
   add esp, 8
   iret
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
extern _irq_handler

irq_common_stub:
pusha
push ds
push es
push fs
push gs

mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, esp

push eax
mov eax, _irq_handler
call eax
pop eax

pop gs
pop fs
pop es
pop ds
popa
add esp, 8
iret
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
extern _irq_handler

irq_common_stub:
   pusha
   push ds
   push es
   push fs
   push gs

   mov ax, 0x10
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax
   mov eax, esp

   push eax
   mov eax, _irq_handler
   call eax
   pop eax

   pop gs
   pop fs
   pop es
   pop ds
   popa
   add esp, 8
   iret

Der task_switch erfolgt im timer_handler.

Diesen Code verwendet JM:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
extern _irq_handler

irq_common_stub:
   pusha                    ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax

   mov ax, ds               ; Lower 16-bits of eax = ds.
   push eax                 ; save the data segment descriptor

   mov ax, 0x10  ; load the kernel data segment descriptor
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax

   call _irq_handler

   pop ebx        ; reload the original data segment descriptor
   mov ds, bx
   mov es, bx
   mov fs, bx
   mov gs, bx

   popa                     ; Pops edi,esi,ebp...
   add esp, 8     ; Cleans up the pushed error code and pushed ISR number
   sti
   iret           ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
extern _irq_handler

irq_common_stub:
pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax

mov ax, ds ; Lower 16-bits of eax = ds.
push eax ; save the data segment descriptor

mov ax, 0x10 ; load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax

call _irq_handler

pop ebx ; reload the original data segment descriptor
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx

popa ; Pops edi,esi,ebp...
add esp, 8 ; Cleans up the pushed error code and pushed ISR number
sti
iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
extern _irq_handler

irq_common_stub:
   pusha                    ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax

   mov ax, ds               ; Lower 16-bits of eax = ds.
   push eax                 ; save the data segment descriptor

   mov ax, 0x10  ; load the kernel data segment descriptor
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax

   call _irq_handler

   pop ebx        ; reload the original data segment descriptor
   mov ds, bx
   mov es, bx
   mov fs, bx
   mov gs, bx

   popa                     ; Pops edi,esi,ebp...
   add esp, 8     ; Cleans up the pushed error code and pushed ISR number
   sti
   iret           ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP


In tyndur wird das so gemacht:
http://git.tyndur.org/?p=tyndur.git;a=blob;f=src/k ....... h=2672f3ea8bac614ae86ffae2f4043b0444a24259;hb=HEAD

Was ist die beste Lösung und warum?

Zur Ergänzung der Code, den ich im task_switch verwende.
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
void task_switch()
{
    cli();
    // If we haven't initialised tasking yet, just return.
    if(!current_task) return;

    // Read esp, ebp now for saving later on.
    ULONG esp, ebp, eip;

    eip = read_eip();
    if(eip == 0x12345) return; // Have we just switched tasks?

/*
    esp = fetchESP();
    ebp = fetchEBP();
*/


    asm volatile("mov %%esp, %0" : "=r"(esp));
    asm volatile("mov %%ebp, %0" : "=r"(ebp));

    //old_task
    current_task->eip = eip;
    current_task->esp = esp;
    current_task->ebp = ebp;

    //--------------------------
    //old_task ==> new_task

    current_task = current_task->next;
    if(!current_task) current_task = ready_queue;

    // new_task
    current_directory = current_task->page_directory;
    set_kernel_stack(current_task->kernel_stack+KERNEL_STACK_SIZE);
    tss_entry.eip = eip = current_task->eip; //TEST
    tss_entry.cr3 = current_directory->physicalAddr; //TEST
    esp = current_task->esp;
    ebp = current_task->ebp;
    //TSS_log(&tss_entry); //TEST

    asm volatile("       \
    cli;                 \
    mov %%ebx, %%esp;    \
    mov %%edx, %%ebp;    \
    mov %%eax, %%cr3;    \
    mov $0x12345, %%eax; \
    sti;                 \
    jmp *%%ecx;          
"
               : : "c"(eip), "b"(esp), "d"(ebp), "a"(current_directory->physicalAddr) );
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
void task_switch()
{
cli();
// If we haven't initialised tasking yet, just return.
if(!current_task) return;

// Read esp, ebp now for saving later on.
ULONG esp, ebp, eip;

eip = read_eip();
if(eip == 0x12345) return; // Have we just switched tasks?

/*
esp = fetchESP();
ebp = fetchEBP();
*/


asm volatile("mov %%esp, %0" : "=r"(esp));
asm volatile("mov %%ebp, %0" : "=r"(ebp));

//old_task
current_task->eip = eip;
current_task->esp = esp;
current_task->ebp = ebp;

//--------------------------
//old_task ==> new_task

current_task = current_task->next;
if(!current_task) current_task = ready_queue;

// new_task
current_directory = current_task->page_directory;
set_kernel_stack(current_task->kernel_stack+KERNEL_STACK_SIZE);
tss_entry.eip = eip = current_task->eip; //TEST
tss_entry.cr3 = current_directory->physicalAddr; //TEST
esp = current_task->esp;
ebp = current_task->ebp;
//TSS_log(&tss_entry); //TEST

asm volatile(" \
cli; \
mov %%ebx, %%esp; \
mov %%edx, %%ebp; \
mov %%eax, %%cr3; \
mov $0x12345, %%eax; \
sti; \
jmp *%%ecx;
"
: : "c"(eip), "b"(esp), "d"(ebp), "a"(current_directory->physicalAddr) );
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
void task_switch()
{
    cli();
    // If we haven't initialised tasking yet, just return.
    if(!current_task) return;

    // Read esp, ebp now for saving later on.
    ULONG esp, ebp, eip;

    eip = read_eip();
    if(eip == 0x12345) return; // Have we just switched tasks?

/*
    esp = fetchESP();
    ebp = fetchEBP();
*/


    asm volatile("mov %%esp, %0" : "=r"(esp));
    asm volatile("mov %%ebp, %0" : "=r"(ebp));

    //old_task
    current_task->eip = eip;
    current_task->esp = esp;
    current_task->ebp = ebp;

    //--------------------------
    //old_task ==> new_task

    current_task = current_task->next;
    if(!current_task) current_task = ready_queue;

    // new_task
    current_directory = current_task->page_directory;
    set_kernel_stack(current_task->kernel_stack+KERNEL_STACK_SIZE);
    tss_entry.eip = eip = current_task->eip; //TEST
    tss_entry.cr3 = current_directory->physicalAddr; //TEST
    esp = current_task->esp;
    ebp = current_task->ebp;
    //TSS_log(&tss_entry); //TEST

    asm volatile("       \
    cli;                 \
    mov %%ebx, %%esp;    \
    mov %%edx, %%ebp;    \
    mov %%eax, %%cr3;    \
    mov $0x12345, %%eax; \
    sti;                 \
    jmp *%%ecx;          
"
               : : "c"(eip), "b"(esp), "d"(ebp), "a"(current_directory->physicalAddr) );
}


Da ich hier massiv fest hänge, bitte ich um eure Unterstützung.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:43:03 10.05.2009, insgesamt 2-mal bearbeitet
Bitsy
Mitglied

Benutzerprofil
Anmeldungsdatum: 01.05.2001
Beiträge: 499
Beitrag Bitsy Mitglied 04:28:06 11.05.2009   Titel:              Zitieren

Ein wesentlicher Punkt, auf den Du unbedingt achten mußt:
Du musst unbedingt etwas installieren, was das Taskswitching kurzfristig stoppt, denn sonst kommt in der kritischen Phase des Anhängens einer neuen Task just in dem Moment ein switch und alles geht daneben. Bei dem 16-bit-taskswitching, was ich Dir in der Mail geschickt habe, war das ein entscheidender Faktor.
Da ist übrigens auch eine Funktion mit drin, die einen Taskswitch erzwingt.
Hab mich aber nie getraut, das alles auf 32-bit zu erweitern.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 07:06:43 11.05.2009   Titel:              Zitieren

Zitat:
Du musst unbedingt etwas installieren, was das Taskswitching kurzfristig stoppt, denn sonst kommt in der kritischen Phase des Anhängens einer neuen Task just in dem Moment ein switch
Danke für den Hinweis! Ich werde da noch ein ts-flag in meiner ODA (OS Data Area) Struktur einbauen, das zuvor abgefragt wird. Die nutze ich sowieso viel zu wenig.

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct oda
{
    //...    
    //tasking

    UCHAR  ts_flag; // 0: taskswitch off  1: taskswitch on
}oda_t;

//...
pODA->ts_flag = 1;

//...
if( pODA->ts_flag == 1 )
    task_switch();
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct oda
{
//...
//tasking

UCHAR ts_flag; // 0: taskswitch off 1: taskswitch on
}oda_t;

//...
pODA->ts_flag = 1;

//...
if( pODA->ts_flag == 1 )
task_switch();
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct oda
{
    //...    
    //tasking

    UCHAR  ts_flag; // 0: taskswitch off  1: taskswitch on
}oda_t;

//...
pODA->ts_flag = 1;

//...
if( pODA->ts_flag == 1 )
    task_switch();

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:10:31 11.05.2009, insgesamt 2-mal bearbeitet
Bitsy
Mitglied

Benutzerprofil
Anmeldungsdatum: 01.05.2001
Beiträge: 499
Beitrag Bitsy Mitglied 05:39:41 12.05.2009   Titel:              Zitieren

Besser einen counter.

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int task_freeze()
{
  if (!taskstop)
  { ...
  }
  return ++taskstop;
}

void task_unfreeze()
{
   if (taskstop>1)  
     --taskstop;    
   else            
   { taskstop=0;
     ...
   }
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int task_freeze()
{
if (!taskstop)
{ ...
}
return ++taskstop;
}

void task_unfreeze()
{
if (taskstop>1)
--taskstop;
else
{ taskstop=0;
...
}
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int task_freeze()
{
  if (!taskstop)
  { ...
  }
  return ++taskstop;
}

void task_unfreeze()
{
   if (taskstop>1)  
     --taskstop;    
   else            
   { taskstop=0;
     ...
   }
}


und dann überleg mal, wie sich die Timerfunktion eventuell verhalten kann.
Bei mir wurde der Originalvektor auf eine Routine umgelenkt, der erst den Originalvektor bedient hat, und dann noch einen Ticker inkrementiert hat.

Was ich auch noch Wichtiges gefunden habe - Turbo C hatte da eine Semaphore namens INDOS. Solange die gesetzt war, durfte der Switcher nicht umschalten.
So ein Festplattenkopf kann da genervt reagieren ;)


Zuletzt bearbeitet von Bitsy am 05:40:19 12.05.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:26:59 12.05.2009   Titel:              Zitieren

Zitat:
Besser einen counter.
Kannst Du den Mechanismus bitte erklären?

Momentan habe ich auf die task_switch Technik von tyndur (OS einer Community) umgestellt, irgendwo ist aber noch ein müder Fehler versteckt, der zu GPF führt.

Ich benutze nur ein TSS. Was muss alles in diese TSS geschrieben werden beim task_switch?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:29:23 12.05.2009, insgesamt 1-mal bearbeitet
Bitsy
Mitglied

Benutzerprofil
Anmeldungsdatum: 01.05.2001
Beiträge: 499
Beitrag Bitsy Mitglied 07:53:37 13.05.2009   Titel:              Zitieren

Der Counter ermöglicht es Paare von freeze und unfreeze auf verschiedenen Ebenen zu bilden. Erst wenn das 'oberste' unfreeze wieder gerufen wurde, gibt er das switching wirklich wieder frei. Wenn Du nur ein einfaches Bit nimmst, verlierst Du früher oder später den Überblick.
Nimm mal an, Du sperrst per Bit vor einem Diskzugriff und gibst es später wieder frei. Was ist, wenn der User auch einen Grund hatte das Switching zu sperren, und unmittelbar nach dem Diskzugriff wird es aber wieder freigegeben?
Mit dem Counter erschlägst Du alle Probleme. (Außer dem, daß Du Fehler bei der Paarbildung machst ;))

Habt ihr in anderen Fällen nicht auch schon solche Counter drin? Ich dachte, ich hätte da schon was gelesen.
Was in die TSS muß - tja, für 32-bit-mode weiß ich's eben auch nicht!


Zuletzt bearbeitet von Bitsy am 07:56:36 13.05.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:58:44 14.05.2009   Titel:              Zitieren

Danke für diese Information.

Hier ist ein Link zum ersten erfolgreichen Multitasking-Beispiel:
http://www.henkessoft.de/OS_Dev/Downloads/36p.zip :)

Damit ist eine für mich nicht einfache Hürde genommen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 11:37:28 14.05.2009   Titel:              Zitieren

glückwunsch *daumen hoch*
:)
Bitsy
Mitglied

Benutzerprofil
Anmeldungsdatum: 01.05.2001
Beiträge: 499
Beitrag Bitsy Mitglied 12:48:06 15.05.2009   Titel:              Zitieren

Jetzt hast Du Dir aber mal ein freies Wochenende verdient - das Wetter soll gut werden (jedenfalls Samstag und Sonntag). Ab in den Biergarten und das Projekt feiern :)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:01:42 16.05.2009   Titel:              Zitieren

Tut zum Multitasking: http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId114565

Jetzt geht es doch erst richtig los mit PrettyOS. Ich denke gerade über die Darstellung von interessanten Möglichkeiten für Dispatcher (short-term scheduler) und long/middle-term Scheduler nach. :)

Wo bekommt man ein lauffähiges kleines Programm (32 bit ohne BIOS-INT) her? Das könnte man doch über den incbin-Trick und evtl memcpy an eine bestimmte Position laden und anstelle moo() oder baa() ausführen, oder? Man könnte doch z.B. das alte COM-Format als flat Binaries verwenden. Man müsste dort doch nur noch einen Task erstellen (create_task ist ja bereits eingebaut), die Segmentregister sauber setzen und eip auf das erste Byte der Datei einstellen. Das Reinspringen in den Code könnte wieder der Interrupthandler übernehmen, der das auch schon bei den Kerneltasks gemacht hat. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:11:30 16.05.2009, insgesamt 2-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 22:53:07 16.05.2009   Titel:              Zitieren

Erhard Henkes schrieb:
(create_task ist ja bereits eingebaut)

vorschlag: create_task() sollte was zurückgeben, z.b. einen pointer auf die task_t oder die task-ID bzw. im fehlerfall 0 oder einen ungültigen ID-wert, damit der aufrufer die task kontrolliern kann und weiss, ob das erzeugen der task überhaupt geklappt hat. ausserdem wär's gut, der task-entry funktion noch einen void* mitzugeben, damit der aufrufer startparameter an die neue task übergeben kann.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:52:04 17.05.2009   Titel:              Zitieren

Zitat:
create_task() sollte was zurückgeben, z.b. einen pointer auf die task_t
Klar, das ist notwendig, damit man auf die Task-Struktur (noch sehr rudimentär) zugreifen kann, wurde daher sofort erledigt. :)

Zitat:
task-entry funktion noch einen void* mitzugeben, damit der aufrufer startparameter an die neue task übergeben kann.
Ich experimentiere gerade mit Varianten von create_task, die verschiedene Anzahlen Parameter übernehmen. Ich habe z.B. settextcolor(schriftfarbe,hintergrundfarbe) so aufgerufen, dass ich der Task diese beiden Argumente neben einer Dummy-Rücksprungadresse auf den Stack übergebe und dann vom Task aus den Code von "settextcolor" als Konstante mit call aufrufe.
C/C++ Code:
    *(--kernel_stack) = arg2; // arg2
    *(--kernel_stack) = arg1; // arg1
    *(--kernel_stack) = 0x0;  // return address dummy

    *(--kernel_stack) = 0x0202; // eflags = interrupts activated and iopl = 0
C/C++ Code:
*(--kernel_stack) = arg2; // arg2
*(--kernel_stack) = arg1; // arg1
*(--kernel_stack) = 0x0; // return address dummy

*(--kernel_stack) = 0x0202; // eflags = interrupts activated and iopl = 0
C/C++ Code:
    *(--kernel_stack) = arg2; // arg2
    *(--kernel_stack) = arg1; // arg1
    *(--kernel_stack) = 0x0;  // return address dummy

    *(--kernel_stack) = 0x0202; // eflags = interrupts activated and iopl = 0
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
void surprise(ULONG a, ULONG b)
{
  asm volatile ("push %0" :/* no output registers */: "r" (b));
  asm volatile ("push %0" :/* no output registers */: "r" (a));
  while(TRUE)
  {
      asm volatile ("call 0x00008484"); // address from kernel.map
      printformat("%d", getpid());      
  }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
void surprise(ULONG a, ULONG b)
{
asm volatile ("push %0" :/* no output registers */: "r" (b));
asm volatile ("push %0" :/* no output registers */: "r" (a));
while(TRUE)
{
asm volatile ("call 0x00008484"); // address from kernel.map
printformat("%d", getpid());
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
void surprise(ULONG a, ULONG b)
{
  asm volatile ("push %0" :/* no output registers */: "r" (b));
  asm volatile ("push %0" :/* no output registers */: "r" (a));
  while(TRUE)
  {
      asm volatile ("call 0x00008484"); // address from kernel.map
      printformat("%d", getpid());      
  }
}

Der Aufruf läuft dann über einen neuen Task:
C/C++ Code:
create_task2(surprise,4,2);
C/C++ Code:
create_task2(surprise,4,2);
C/C++ Code:
create_task2(surprise,4,2);


Das funktioniert gut. Damit taste ich mich experimentell an Programmaufrufe in PrettyOS heran.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:55:24 17.05.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 12:18:35 17.05.2009   Titel:              Zitieren

Eine Designfrage zum Thema Speicherreservierung für PDs, tasks, kernel stacks etc. mit
1) Verschieben der placement_address bei bereits gemappten frames
2) k_malloc (auf dem Heap)
http://lowlevel.brainsware.org/forum/index.php?topic=2178.msg24534#msg24534

Irgendwie kommt mir ein "Stack auf dem Heap" nicht gerade elegant vor.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:09:23 17.05.2009   Titel:              Zitieren

PrettyOS hat gerade das erste Programm von außen ausgeführt.
Das ist ein richtig guter Moment für PrettyOS. Nun ist es "air borne".
Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Test Program for PrettyOS      ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[BITS 32]
start:
   Mov [0x000b8000], byte 'T'
   Mov [0x000b8002], byte 'e'
   Mov [0x000b8004], byte 's'
   Mov [0x000b8006], byte 't'
   Ret  
Code:
1
2
3
4
5
6
7
8
9
10
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Test Program for PrettyOS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[BITS 32]
start:
Mov [0x000b8000], byte 'T'
Mov [0x000b8002], byte 'e'
Mov [0x000b8004], byte 's'
Mov [0x000b8006], byte 't'
Ret
Code:
1
2
3
4
5
6
7
8
9
10
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Test Program for PrettyOS      ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[BITS 32]
start:
   Mov [0x000b8000], byte 'T'
   Mov [0x000b8002], byte 'e'
   Mov [0x000b8004], byte 's'
   Mov [0x000b8006], byte 't'
   Ret  


Dieses externe Programm wurde binär assembliert und über den Trick mit 'incbin' eingeschleust:
nasmw -f bin file_data.asm -o file_data.dat

process.asm:
Code:
_file_data_start:
incbin "file_data.dat"
_file_data_end:
Code:
_file_data_start:
incbin "file_data.dat"
_file_data_end:
Code:
_file_data_start:
incbin "file_data.dat"
_file_data_end:


ckernel.c:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
void test()
{
  while(TRUE)
  {
      asm volatile ("call _file_data_start");
      printformat("%d", getpid());
      settextcolor(15,0);
  }
}

//...

task_t* task5 = create_task0(test);
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
void test()
{
while(TRUE)
{
asm volatile ("call _file_data_start");
printformat("%d", getpid());
settextcolor(15,0);
}
}

//...

task_t* task5 = create_task0(test);
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
void test()
{
  while(TRUE)
  {
      asm volatile ("call _file_data_start");
      printformat("%d", getpid());
      settextcolor(15,0);
  }
}

//...

task_t* task5 = create_task0(test);


Das von außen eingeschleuste ("geladene") Programm wurde als Task5 ausgeführt. :)

http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId188270
http://www.henkessoft.de/OS_Dev/Downloads/20090517_36v.zip

Das Schlimme und Gute zugleich bei der OS-Entwicklung ist, dass alle Verständnislücken, die man so hat, gleichzeitig und hinterrücks zuschlagen. :D
Ich kann nur hoffen, dass das Tutorial anderen bei dem Finden des richtigen Weges etwas helfen kann.

Kennt jemand einen Link bezüglich Laden/Ausführen von Programmen.
Selbst hier - in dieser genialen Zusammenfassung - steht nichts genaues hierzu: http://ocw.mit.edu/NR/rdonlyres/Electrical-Enginee ....... 2006/9B92FFBC-BA35-468E-971D-F7D6D0BB34DC/0/l2.pdf

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:19:57 17.05.2009, insgesamt 5-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 11:14:17 18.05.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Das Schlimme und Gute zugleich bei der OS-Entwicklung ist, dass alle Verständnislücken, die man so hat, gleichzeitig und hinterrücks zuschlagen.

das liegt nur an der mit, der heissen nadel gestrickten, x86-architektur. ich behaupte mal, jeder andere prozessor würde einem weniger kopfzerbrechen bereiten.
:)
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 12:36:57 18.05.2009   Titel:              Zitieren

+fricky schrieb:
das liegt nur an der mit, der heissen nadel gestrickten, x86-architektur. ich behaupte mal, jeder andere prozessor würde einem weniger kopfzerbrechen bereiten.

Vorsicht, vorsicht, das Eis auf dem Du Dich bewegst, ist sehr sehr dünn... :D
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 12:51:20 18.05.2009   Titel:              Zitieren

abc.w schrieb:
+fricky schrieb:
das liegt nur an der mit, der heissen nadel gestrickten, x86-architektur. ich behaupte mal, jeder andere prozessor würde einem weniger kopfzerbrechen bereiten.

Vorsicht, vorsicht, das Eis auf dem Du Dich bewegst, ist sehr sehr dünn...

welcher ist schlimmer (von totalen exoten mal abgesehen)?
:)
Bitsy
Mitglied

Benutzerprofil
Anmeldungsdatum: 01.05.2001
Beiträge: 499
Beitrag Bitsy Mitglied 13:39:08 18.05.2009   Titel:              Zitieren

Ein lokaler Stack auf der Heap ist mithilfe eines speziellen 'Registers' einfach realisierbar - so funktionierte der 68000er Prozessor.
A7 war das Heapregister, A6 der Userstack.

Die Kommandos link und unlink wurden in etwa so realisiert:
(A7 und A6 beide long).

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void link(const int n)
{
  A7 -= 4;
  *(long*)A7 = A6;
  A6 = A7;
  A7 -= n;
}

void unlk(void)
{
  A7 = A6;
  A6 = *(long*)A7;
  A7 += 4;
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void link(const int n)
{
A7 -= 4;
*(long*)A7 = A6;
A6 = A7;
A7 -= n;
}

void unlk(void)
{
A7 = A6;
A6 = *(long*)A7;
A7 += 4;
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void link(const int n)
{
  A7 -= 4;
  *(long*)A7 = A6;
  A6 = A7;
  A7 -= n;
}

void unlk(void)
{
  A7 = A6;
  A6 = *(long*)A7;
  A7 += 4;
}


Die lokalen Daten werden jetzt im Bereich A6-n ... A6 hinterlegt.
Und A7 verwaltet weiterhin die Rücksprungadressen, sowie alle pushs und pops.

btw: bei 68000er-Simulationen haut die Endianess fürchterlich rein - ich hoffe, das bleibt PrettyOS erspart ;)


Zuletzt bearbeitet von Bitsy am 13:42:34 18.05.2009, insgesamt 1-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 14:18:33 18.05.2009   Titel:              Zitieren

Bitsy schrieb:

btw: bei 68000er-Simulationen haut die Endianess fürchterlich rein

der machts wenigsten richtig rum.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:18:41 18.05.2009   Titel:              Zitieren

Zitat:
Ein lokaler Stack auf der Heap ist mithilfe eines speziellen 'Registers' einfach realisierbar
Du findest Stacks auf dem (die?) Heap also auch nicht schlimm? Hat ja Vorteile wegen der einfachen Speicherfreigabe bei Task-Beendigung.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 09:34:39 19.05.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Du findest Stacks auf dem (die?) Heap also auch nicht schlimm? Hat ja Vorteile wegen der einfachen Speicherfreigabe bei Task-Beendigung.

spricht ja erstmal nix dagegen, alle speicherressourcen eines prozesses (stack, handle-tabellen, usw.) auf dem system-heap anzulegen. der heap, den der prozess selber verwendet (für seine malloc/free aufrufe) sollte natürlich ein anderer sein.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:12:05 19.05.2009   Titel:              Zitieren

Inzwischen habe ich mich auch an die Idee des Stacks auf dem Heap gewöhnt. Das hat gegenüber dem Schieben der placement_address ins "Unendliche" eindeutig die Vorteile eines vernünftigen Speichermanagements. :leak:

Das Tutorial wurde um das Thema Virtuelles Filesystem und Initial RAM Disk erweitert. Hier habe ich den Code von JM übernommen, da er entsprechend POSIX klar strukturiert und für PrettyOS zunächst tauglich ist: http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId676802

Ich habe direkt hinter die RAM Disk, die beispielhaft mit 3 Files bestückt wurde, noch das kleine Test-Programm gehängt.

Vielleicht habt ihr bessere Ideen für einen veränderten RAM-Disk- und File-Header. JM hat hier im RAM-Disk-Header lediglich die Anzahl Files eingetragen und in den File-Headern den Namen, den Offset und die Größe angegeben. Da könnte man evtl. eine interessante Lösung umsetzen, wobei dies keine besondere bedeutung hat, außer das der Leser solche Formate vom Typus her generell kennen lernt. :)

Interessant wäre es vielleicht, in die RAM Disk nicht nur langweilige Text-Files, sondern mehrere Programm-Files aufzunehmen und diese mit einer Auswahl-Routine Run(FileName) aus verschiedenen Tasks im Multitasking zu starten. Damit kämen wir dem Laden/Starten eines Programms/Moduls, in diesem Fall von einer virtuellen Disk auf einem abstrakten File-Node im VFS, doch schon etwas näher? Habt ihr Ideen für kleine Demo-Programme? Assembler-Programmierer nach vorne! Bisher habe ich nur dieses winzige Programm, dessen Ausgabe man nur mit dem Debugger wahr nehmen kann:
Code:
[BITS 32]
start:
   Mov [0x000b8000], byte 'T'
   Mov [0x000b8002], byte 'e'
   Mov [0x000b8004], byte 's'
   Mov [0x000b8006], byte 't'
   Ret
Code:
[BITS 32]
start:
Mov [0x000b8000], byte 'T'
Mov [0x000b8002], byte 'e'
Mov [0x000b8004], byte 's'
Mov [0x000b8006], byte 't'
Ret
Code:
[BITS 32]
start:
   Mov [0x000b8000], byte 'T'
   Mov [0x000b8002], byte 'e'
   Mov [0x000b8004], byte 's'
   Mov [0x000b8006], byte 't'
   Ret

Die Programme dürfen ja noch keine externen Ressourcen anfordern, weil dieses Prozess- und I/O-Management noch fehlt.

EDIT: Syscalls und Usermode (z.Z. leider noch mit Supervisor-Privileg, weil es ansonsten mit PF oder GPF endet) ist in meinem Experimentierfeld bereits eingebaut. Ich frage mich gerade, wie eine API von innen her gesehen funktioniert. Von außen verwendet man diese typischerweise mit api.h/api.lib.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 11:14:29 21.05.2009, insgesamt 11-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:33:02 21.05.2009   Titel:              Zitieren

Ich wollte an dieser Stelle darauf hinweisen, dass die deutsche Übersetzung der dritten Auflage von Tanenbaum's Meisterwerk verfügbar ist und kann dieses Grundlagen- und Nachschlagewerk nur empfehlen: Andrew S. Tanenbaum et.al., Moderne Betriebssysteme, 3. Auflage, Pearson Studium, April 2009 (Übersetzung von "Modern Operating Systems", Prentice Hall, Dec 2007). Der wesentliche Makel der deutschen Ausgabe ist, dass das IMHO gelungene Titelbild des Originals nicht enthalten ist.
deutsch: http://www.pearson-studium.de/media_local/shop_u1bigs_3d/9783827373427.jpg (April 2009)
amerikanisch: http://vig-fp.prenhall.com/bigcovers/0136006639.jpg (Dec 2007)
Für mich neben den Intel Manuals und einem Assemblerbuch eine wesentliche Fundgrube für Fakten und Ideen. :live:
Allerdings staune ich immer wieder, dass selbst so ein Standardwerk noch Fehler, didaktische Luecken und Ungereimtheiten enthaelt. :rolleyes:

Gibt es eigentlich schon so etwas wie "OS Development for Dummies" in engl. oder deutsch? Ist mir bisher nicht unter gekommen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 15:13:13 30.05.2009, insgesamt 4-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:32:20 21.05.2009   Titel:              Zitieren

Kurzer Zwischenstand: z.Z. kämpfe ich mit dem "echten" User Mode (Ring 3).
Da gibt es noch GPF.

EDIT: http://www.henkessoft.de/OS_Dev/Downloads/20090522_43_user_mode.zip
PrettyOS arbeitet zum ersten Mal im "echten" User Mode (Ring 3). Wichtig ist, dass man im ring3 ss und esp vor die eflags "pusht" (Intel Manual 3A, Kap. 5.12).

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
task_t* create_task(void* entry, UCHAR privilege)
{
    cli();
    page_directory_t* directory = clone_directory(current_directory);
    task_t* new_task            = (task_t*)k_malloc(sizeof(task_t),0,0);

    new_task->id  = next_pid++;
    new_task->page_directory = directory;
    new_task->kernel_stack   = k_malloc(KERNEL_STACK_SIZE,1,0)+KERNEL_STACK_SIZE;
    new_task->next = 0;

    task_t* tmp_task = (task_t*)ready_queue;
    while (tmp_task->next)
        tmp_task = tmp_task->next;
    tmp_task->next = new_task; // ... and extend it

    ULONG* kernel_stack = (ULONG*) new_task->kernel_stack;

    ULONG code_segment=0x08, data_segment=0x10;

    if(privilege == 3)
    {
        //Intel 3A Chapter 5.12
        *(--kernel_stack) = new_task->ss = 0x23;    // ss
        *(--kernel_stack) = new_task->kernel_stack; // esp = esp0
        code_segment = 0x1B; // 0x18|0x3=0x1B
    }

    *(--kernel_stack) = 0x0202; // eflags = interrupts activated and iopl = 0
    *(--kernel_stack) = code_segment; // cs
    *(--kernel_stack) = (ULONG)entry; // eip
    *(--kernel_stack) = 0; // error code

    *(--kernel_stack) = 0; // interrupt nummer

    // general purpose registers w/o esp

    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;

    if(privilege == 3) data_segment = 0x23; // 0x20|0x3=0x23

    *(--kernel_stack) = data_segment;
    *(--kernel_stack) = data_segment;
    *(--kernel_stack) = data_segment;
    *(--kernel_stack) = data_segment;

    //setup TSS
    tss_entry.ss0   = 0x10;
    tss_entry.esp0  = new_task->kernel_stack;
    tss_entry.ss    = data_segment;


    //setup task_t
    new_task->ebp = 0xd00fc0de; // test value
    new_task->esp = (ULONG)kernel_stack;
    new_task->eip = (ULONG)irq_tail;
    new_task->ss  = data_segment;

    sti();
    return new_task;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
task_t* create_task(void* entry, UCHAR privilege)
{
cli();
page_directory_t* directory = clone_directory(current_directory);
task_t* new_task = (task_t*)k_malloc(sizeof(task_t),0,0);

new_task->id = next_pid++;
new_task->page_directory = directory;
new_task->kernel_stack = k_malloc(KERNEL_STACK_SIZE,1,0)+KERNEL_STACK_SIZE;
new_task->next = 0;

task_t* tmp_task = (task_t*)ready_queue;
while (tmp_task->next)
tmp_task = tmp_task->next;
tmp_task->next = new_task; // ... and extend it

ULONG* kernel_stack = (ULONG*) new_task->kernel_stack;

ULONG code_segment=0x08, data_segment=0x10;

if(privilege == 3)
{
//Intel 3A Chapter 5.12
*(--kernel_stack) = new_task->ss = 0x23; // ss
*(--kernel_stack) = new_task->kernel_stack; // esp = esp0
code_segment = 0x1B; // 0x18|0x3=0x1B
}

*(--kernel_stack) = 0x0202; // eflags = interrupts activated and iopl = 0
*(--kernel_stack) = code_segment; // cs
*(--kernel_stack) = (ULONG)entry; // eip
*(--kernel_stack) = 0; // error code

*(--kernel_stack) = 0; // interrupt nummer

// general purpose registers w/o esp

*(--kernel_stack) = 0;
*(--kernel_stack) = 0;
*(--kernel_stack) = 0;
*(--kernel_stack) = 0;
*(--kernel_stack) = 0;
*(--kernel_stack) = 0;
*(--kernel_stack) = 0;

if(privilege == 3) data_segment = 0x23; // 0x20|0x3=0x23

*(--kernel_stack) = data_segment;
*(--kernel_stack) = data_segment;
*(--kernel_stack) = data_segment;
*(--kernel_stack) = data_segment;

//setup TSS
tss_entry.ss0 = 0x10;
tss_entry.esp0 = new_task->kernel_stack;
tss_entry.ss = data_segment;


//setup task_t
new_task->ebp = 0xd00fc0de; // test value
new_task->esp = (ULONG)kernel_stack;
new_task->eip = (ULONG)irq_tail;
new_task->ss = data_segment;

sti();
return new_task;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
task_t* create_task(void* entry, UCHAR privilege)
{
    cli();
    page_directory_t* directory = clone_directory(current_directory);
    task_t* new_task            = (task_t*)k_malloc(sizeof(task_t),0,0);

    new_task->id  = next_pid++;
    new_task->page_directory = directory;
    new_task->kernel_stack   = k_malloc(KERNEL_STACK_SIZE,1,0)+KERNEL_STACK_SIZE;
    new_task->next = 0;

    task_t* tmp_task = (task_t*)ready_queue;
    while (tmp_task->next)
        tmp_task = tmp_task->next;
    tmp_task->next = new_task; // ... and extend it

    ULONG* kernel_stack = (ULONG*) new_task->kernel_stack;

    ULONG code_segment=0x08, data_segment=0x10;

    if(privilege == 3)
    {
        //Intel 3A Chapter 5.12
        *(--kernel_stack) = new_task->ss = 0x23;    // ss
        *(--kernel_stack) = new_task->kernel_stack; // esp = esp0
        code_segment = 0x1B; // 0x18|0x3=0x1B
    }

    *(--kernel_stack) = 0x0202; // eflags = interrupts activated and iopl = 0
    *(--kernel_stack) = code_segment; // cs
    *(--kernel_stack) = (ULONG)entry; // eip
    *(--kernel_stack) = 0; // error code

    *(--kernel_stack) = 0; // interrupt nummer

    // general purpose registers w/o esp

    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;
    *(--kernel_stack) = 0;

    if(privilege == 3) data_segment = 0x23; // 0x20|0x3=0x23

    *(--kernel_stack) = data_segment;
    *(--kernel_stack) = data_segment;
    *(--kernel_stack) = data_segment;
    *(--kernel_stack) = data_segment;

    //setup TSS
    tss_entry.ss0   = 0x10;
    tss_entry.esp0  = new_task->kernel_stack;
    tss_entry.ss    = data_segment;


    //setup task_t
    new_task->ebp = 0xd00fc0de; // test value
    new_task->esp = (ULONG)kernel_stack;
    new_task->eip = (ULONG)irq_tail;
    new_task->ss  = data_segment;

    sti();
    return new_task;
}


C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
void test5()
{
  while(TRUE)
  {
      syscall_puts("5");
      //puts("5");
  }
}

//...

task_t* task5 = create_task (test5,3);
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
void test5()
{
while(TRUE)
{
syscall_puts("5");
//puts("5");
}
}

//...

task_t* task5 = create_task (test5,3);
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
void test5()
{
  while(TRUE)
  {
      syscall_puts("5");
      //puts("5");
  }
}

//...

task_t* task5 = create_task (test5,3);


Ohne syscall ( Aufruf Kernel-Fkt. aus Ring 3 ) ==>
Zitat:
44444444444444444444444444444444444444444444444444444444444444444444444444444444
4444444444444444444
Page Fault ( read-only - write operation user-mode) at 000B8C06h - EIP: 00008986h

Für echte User-"Programme" benötigt man ja auch noch Stack und Heap im User-Privileg. Da denke ich gerade nach, wie man das einfach möglichst einfach in Ring3 mappen/allokieren kann. :)

Bei obigem Programm gibt es noch Probleme, wenn man das while in test5 streicht. Da überlege ich gerade eine Umhüllung oder ein exit. Wenn da jemand eine Idee hätte? :confused:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 09:16:42 23.05.2009, insgesamt 5-mal bearbeitet
Bitsy
Mitglied

Benutzerprofil
Anmeldungsdatum: 01.05.2001
Beiträge: 499
Beitrag Bitsy Mitglied 10:56:45 22.05.2009   Titel:              Zitieren

Ich hab noch eine kleine Anmerkung zum Stack.
Zwar weiß ich nicht, was Du da jetzt alles drüber abwickeln willst, (sagst ja, lokale Speicheranforderung extra etc.), und ich weiß deshalb nicht, ob hier ein Problem entstehen kann. Solltest aber einen klitzekleinen Moment drüber verwenden, ob hier memory fragmentation reinspielen kann oder nicht. Wenn ja, unterschätze den Effekt nicht. Ich habe damals an die DJGPP-newsgroup ein sample geschickt (okay, das ist jetzt lokale Speicheranforderung), was den gcc abschiessen konnte, obwohl alles korrekt war. Hatte einfach zufällige Mengen von Speicheranforderungen und -freigaben in rauher Menge laufen lassen.
Auf die Bemerkung, das wäre ja nun sehr willkürlich, habe ich einfach gekontert, dass bei einer OOP-Sprache wie C++ doch kaum noch absehbar ist, was in den vielen kleinen Blackboxes alles passiert. Das haben sie dann doch ernst genommen, und das ganze Kapitel so überarbeitet, dass sich mein Sample auf den Kopf stellen konnte - es blieb stabil! Vielleicht kann man durch debuggen/disassemblen des new-Befehls mal schauen, was für ein Grundprinzip dahinter steckt.
Kann schlecht abschätzen, ob Du so etwas an der bewußten Stelle auch brauchst.
Reine fifo-Dinge werden es wohl auch nicht mehr sein.


Zuletzt bearbeitet von Bitsy am 10:58:55 22.05.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:11:32 22.05.2009   Titel:              Zitieren

@Bitsy: Danke für den Hinweis. Momentan kämpfe ich dermaßen mit Prozessen (Multitasking/Privilegien/Syscall/Interrupts), dass ich gar keine Zeit für das Speichermanagement habe.

Du meinst, wenn ständig irgendein Prozess 4 KB Stack anfordert und anschließend wieder frei gibt? Wir betreiben das Spiel mit den Stacks auf dem Heap. Ich muss mal schauen, wie man diese geordenete Liste aller "freien Löcher" bzw. "belegten Blocks" (Heap Code von James Molloy, Kernel Tutorial, Kap. 7, übernommen) visualisieren kann. Dann könnten wir den Algo testweise stressen.
Vielleicht hat jemand Zeit/Lust für so eine Sonderaufgabe?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 10:44:45 23.05.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 02:52:48 24.05.2009   Titel:              Zitieren

Zum Thema Multitasking/UserMode/Syscalls:

Wenn man früher aus einer Task ausbrechen will, als die Timeslice dauert, lässt sich das leicht über einen Software-Interrupt realisieren:

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void exit_task() //exit to next task
{
  asm volatile("int $0x21"); // <== welchen INT würdet ihr verwenden?
}

void f2()
{
    while(TRUE)
    {
      settextcolor(getpid(),0);
      putch(getpid()+'@');
      exit_task();
    }
}

void f3() //user mode at ring 3 requires syscall_...
{
    while(TRUE)
    {
      syscall_settextcolor(syscall_getpid(),0);
      syscall_putch(syscall_getpid()+'@');
      syscall_exit_task();
    }
}

int main()
{
    //...

    // create two additional tasks

    task_t* task2 = create_task (f2,0); // kernel mode (ring 0)
    task_t* task3 = create_task (f3,3); // user mode   (ring 3)

    pODA->ts_flag = 1; // enable task_switching

    while(TRUE)
    {
        settextcolor(getpid(),0);
        putch(getpid()+'@');
        exit_task();
    }
    return 0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void exit_task() //exit to next task
{
asm volatile("int $0x21"); // <== welchen INT würdet ihr verwenden?
}

void f2()
{
while(TRUE)
{
settextcolor(getpid(),0);
putch(getpid()+'@');
exit_task();
}
}

void f3() //user mode at ring 3 requires syscall_...
{
while(TRUE)
{
syscall_settextcolor(syscall_getpid(),0);
syscall_putch(syscall_getpid()+'@');
syscall_exit_task();
}
}

int main()
{
//...

// create two additional tasks

task_t* task2 = create_task (f2,0); // kernel mode (ring 0)
task_t* task3 = create_task (f3,3); // user mode (ring 3)

pODA->ts_flag = 1; // enable task_switching

while(TRUE)
{
settextcolor(getpid(),0);
putch(getpid()+'@');
exit_task();
}
return 0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void exit_task() //exit to next task
{
  asm volatile("int $0x21"); // <== welchen INT würdet ihr verwenden?
}

void f2()
{
    while(TRUE)
    {
      settextcolor(getpid(),0);
      putch(getpid()+'@');
      exit_task();
    }
}

void f3() //user mode at ring 3 requires syscall_...
{
    while(TRUE)
    {
      syscall_settextcolor(syscall_getpid(),0);
      syscall_putch(syscall_getpid()+'@');
      syscall_exit_task();
    }
}

int main()
{
    //...

    // create two additional tasks

    task_t* task2 = create_task (f2,0); // kernel mode (ring 0)
    task_t* task3 = create_task (f3,3); // user mode   (ring 3)

    pODA->ts_flag = 1; // enable task_switching

    while(TRUE)
    {
        settextcolor(getpid(),0);
        putch(getpid()+'@');
        exit_task();
    }
    return 0;
}


Zitat:
ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCAB
CABCABCABABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCAB
CABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCACABCABCABCAB
CABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCA
BCABCACABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCA
BCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABABCABCABCABCABCABCA
BCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABABCABCABCABCABCABCA
BCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABABCABCABCABCABCABCA
BCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC
ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCBCABCABCABCABCABCABCABC
ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCAB


Syscalls (Überbrückung Ring3 ==> Ring0):
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#define DECL_SYSCALL0(fn)   int syscall_##fn(); //etc.

#define
DEFN_SYSCALL0(fn, num) \
int syscall_##fn() \
{ \
  int a; \
  asm volatile("int $0x7F" : "=a" (a) : "0" (num)); \
  return a; \
}
//etc.

DECL_SYSCALL1(puts,  UCHAR*)
DECL_SYSCALL1(putch, UCHAR)
DECL_SYSCALL2(settextcolor, UCHAR, UCHAR)
DECL_SYSCALL0(getpid)
DECL_SYSCALL0(f3)
DECL_SYSCALL0(nop)
DECL_SYSCALL0(exit_task)


DEFN_SYSCALL1( puts,         0, UCHAR*       )
DEFN_SYSCALL1( putch,        1, UCHAR        )
DEFN_SYSCALL2( settextcolor, 2, UCHAR, UCHAR )
DEFN_SYSCALL0( getpid,       3               )
DEFN_SYSCALL0( f3,           4               )
DEFN_SYSCALL0( nop,          5               )
DEFN_SYSCALL0( exit_task,    6               )

#define
NUM_SYSCALLS 7

static void* syscalls[NUM_SYSCALLS] =
{
    &puts,
    &putch,
    &settextcolor,
    &getpid,
    &f3,
    &nop,
    &exit_task
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#define DECL_SYSCALL0(fn) int syscall_##fn(); //etc.

#define
DEFN_SYSCALL0(fn, num) \
int syscall_##fn() \
{ \
int a; \
asm volatile("int $0x7F" : "=a" (a) : "0" (num)); \
return a; \
}
//etc.

DECL_SYSCALL1(puts, UCHAR*)
DECL_SYSCALL1(putch, UCHAR)
DECL_SYSCALL2(settextcolor, UCHAR, UCHAR)
DECL_SYSCALL0(getpid)
DECL_SYSCALL0(f3)
DECL_SYSCALL0(nop)
DECL_SYSCALL0(exit_task)


DEFN_SYSCALL1( puts, 0, UCHAR* )
DEFN_SYSCALL1( putch, 1, UCHAR )
DEFN_SYSCALL2( settextcolor, 2, UCHAR, UCHAR )
DEFN_SYSCALL0( getpid, 3 )
DEFN_SYSCALL0( f3, 4 )
DEFN_SYSCALL0( nop, 5 )
DEFN_SYSCALL0( exit_task, 6 )

#define
NUM_SYSCALLS 7

static void* syscalls[NUM_SYSCALLS] =
{
&puts,
&putch,
&settextcolor,
&getpid,
&f3,
&nop,
&exit_task
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#define DECL_SYSCALL0(fn)   int syscall_##fn(); //etc.

#define
DEFN_SYSCALL0(fn, num) \
int syscall_##fn() \
{ \
  int a; \
  asm volatile("int $0x7F" : "=a" (a) : "0" (num)); \
  return a; \
}
//etc.

DECL_SYSCALL1(puts,  UCHAR*)
DECL_SYSCALL1(putch, UCHAR)
DECL_SYSCALL2(settextcolor, UCHAR, UCHAR)
DECL_SYSCALL0(getpid)
DECL_SYSCALL0(f3)
DECL_SYSCALL0(nop)
DECL_SYSCALL0(exit_task)


DEFN_SYSCALL1( puts,         0, UCHAR*       )
DEFN_SYSCALL1( putch,        1, UCHAR        )
DEFN_SYSCALL2( settextcolor, 2, UCHAR, UCHAR )
DEFN_SYSCALL0( getpid,       3               )
DEFN_SYSCALL0( f3,           4               )
DEFN_SYSCALL0( nop,          5               )
DEFN_SYSCALL0( exit_task,    6               )

#define
NUM_SYSCALLS 7

static void* syscalls[NUM_SYSCALLS] =
{
    &puts,
    &putch,
    &settextcolor,
    &getpid,
    &f3,
    &nop,
    &exit_task
};

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:55:57 24.05.2009, insgesamt 3-mal bearbeitet
zosxc63Tr
Unregistrierter




Beitrag zosxc63Tr Unregistrierter 23:22:27 27.05.2009   Titel:              Zitieren

Das ist wohl eher ein task_yield(), da der Prozess wieder auftaucht und nicht aus der Liste der lauffaehigen Prozesse ausgetragen wird. Prozesse geben normalerweise nicht freiwillig auf, und wenn, dann mit exit endgueltig. :)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 15:08:37 30.05.2009   Titel:              Zitieren

zosxc63Tr schrieb:
Das ist wohl eher ein task_yield(), da der Prozess wieder auftaucht und nicht aus der Liste der lauffaehigen Prozesse ausgetragen wird. Prozesse geben normalerweise nicht freiwillig auf, und wenn, dann mit exit endgueltig. :)

Ja, alles richtig, werde dies auf ein exit() umbauen. Obiger Mechanismus koennte evtl. fuer ein thread_yield verwendet werden. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
zosxc63Tr
Unregistrierter




Beitrag zosxc63Tr Unregistrierter 00:39:57 12.06.2009   Titel:              Zitieren

Wie geht es weiter mit dem OS Skript? Wann wird nach GRUB und Linux Tools umgestellt wie sonst ueblich?
upperleft
Unregistrierter




Beitrag upperleft Unregistrierter 03:46:11 12.06.2009   Titel:              Zitieren

was soll dieses os überhaupt bringen? es gibt doch schon minix für genau diesen zweck. und das ist auch x86. tut es wirklich not?
Hobby Programmierer
Mitglied

Benutzerprofil
Anmeldungsdatum: 15.03.2009
Beiträge: 75
Beitrag Hobby Programmierer Mitglied 08:49:48 12.06.2009   Titel:              Zitieren

Ich denke mal, es soll dazu dienen, zu verstehen, wie ein OS funktioniert. Deswegen wird es von Grund auf programmiert. Und da so etas nicht einfach ist, muss man etwas geduld mitbringen.
_matze
Mitglied

Benutzerprofil
Anmeldungsdatum: 31.07.2007
Beiträge: 9592
Beitrag _matze Mitglied 09:09:53 12.06.2009   Titel:              Zitieren

upperleft schrieb:
was soll dieses os überhaupt bringen? es gibt doch schon minix für genau diesen zweck. und das ist auch x86. tut es wirklich not?


Genau! Und warum progammieren Anfänger immer diese Hello World Programme? Die gibts doch schon! Ich verstehe wirklich nicht, was das bringen soll... :rolleyes: ;)

_________________
Wie viele atheistische Babys hat man schon aus Versehen - oder gar mit Absicht! - getauft?
sothis_
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.01.2008
Beiträge: 1539
Beitrag sothis_ Mitglied 09:39:47 12.06.2009   Titel:              Zitieren

so ist das nun. bildungsresitenz breitet sich hierzulande immer mehr aus :)
_matze
Mitglied

Benutzerprofil
Anmeldungsdatum: 31.07.2007
Beiträge: 9592
Beitrag _matze Mitglied 09:42:26 12.06.2009   Titel:              Zitieren

sothis_ schrieb:
bildungsresitenz


Vorsicht! Bildungsresistenz falsch zu schreiben, ist ähnlich gefährlich wie bei Intelligenz... :D ;)

_________________
Wie viele atheistische Babys hat man schon aus Versehen - oder gar mit Absicht! - getauft?
FreakY<3Cpp
Mitglied

Benutzerprofil
Anmeldungsdatum: 22.09.2008
Beiträge: 1168
Beitrag FreakY<3Cpp Mitglied 12:12:47 12.06.2009   Titel:              Zitieren

I <3 _matze :D

upperleft schrieb:
was soll dieses os überhaupt bringen? es gibt doch schon minix für genau diesen zweck. und das ist auch x86. tut es wirklich not?


Wie matze schon meinte, es dient zur Übung und ein OS ist eine gute Herausforderung. Hätte ich das Wissen und die Zeit dazu, würde ich mich auch dran versuchen. Wer kann schon von sich sagen, er habe alleine sein eigenes OS gebaut?
sothis_
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.01.2008
Beiträge: 1539
Beitrag sothis_ Mitglied 16:30:00 12.06.2009   Titel:              Zitieren

_matze schrieb:
sothis_ schrieb:
bildungsresitenz


Vorsicht! Bildungsresistenz falsch zu schreiben, ist ähnlich gefährlich wie bei Intelligenz... :D ;)


ich habe nicht behauptet, dass ich mich davon selbst ausschließe :)
upperleft
Unregistrierter




Beitrag upperleft Unregistrierter 17:22:08 12.06.2009   Titel:              Zitieren

nein, ihr habt mein posting nicht verstanden. es gibt schon minix, wsa genau für diesen zweck geschrieben wurde und in einem umfangreichen buch schritt für schritt, sowohl in der theorie als auch in der praxis (anhand des quellcodes) erläutert wie ein OS funktioniert. also wozu genau das gleiche hier nochmal?
sothis_
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.01.2008
Beiträge: 1539
Beitrag sothis_ Mitglied 17:32:41 12.06.2009   Titel:              Zitieren

upperleft schrieb:
also wozu genau das gleiche hier nochmal?


weil es menschen gibt, die besser lernen wenn sie es selbst von grund auf durcharbeiten. wenn sie andere an der arbeit teilhaben lassen kommt dies dem eigenen lernprozess und dem der anderen zu gute. deswegen existieren unzählige halbfertige betriebssystem-kernel, und das ist auch gut so. :)
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 20:18:48 12.06.2009   Titel:              Zitieren

sothis_ schrieb:
deswegen existieren unzählige halbfertige betriebssystem-kernel, und das ist auch gut so.

Ab wann ist denn ein Stück Software fertig... Heisst es nicht, ist Software fertig, dann wohl veraltet ;)
upperleft
Unregistrierter




Beitrag upperleft Unregistrierter 22:46:34 12.06.2009   Titel:              Zitieren

und all dies für dieses frickelicke baumhaus mit zig anbauten namens x86. naja wers sich gern unnötig schwermacht :)

wenn ich mal zeit habe schreibe ich auch mal ein buch über ein kleines betriebssystem, aber das läuft dann auf einem schönen MIPS oder ARM oder so, damit der leser sich aufs wesentliche konzentrieren kann und ned auf x86 frickelei.
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 23:09:09 12.06.2009   Titel:              Zitieren

^^das statement hätte von mir sein können (bis auf das bücher schreiben). aber naja, es war nunmal erhards entscheidung.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 03:13:46 13.06.2009   Titel:              Zitieren

Melde mich aus dem Urlaub zurück. :)

Schaut man sich die in Tanenbaum "Modern OS" konkret untersuchten OS an, so findet man Unix/Linux, MS Vista und Symbian OS. Die meisten Hobby-OS sind wohl Linux/Unix-Clones.

Ich wollte zunächst mit dem starten, was viele als Teenager - in diesem Alter versuchen einige begabte und ehrgeizige jungen Leute ein erstes eigenes OS zu basteln, um die Grundlagen besser zu verstehen - zur Verfügung haben, nämlich einen 80x86 Rechner mit MS Windows. Daher schreibe ich das Tutorial in deutsch und starte von diesem Bezugspunkt.

Das Design-Thema habe ich auf Teil 3 verschoben. Teil 2 ist zunächst noch dem spielerischen Kennenlernen weiterer notwendiger Techniken wie Speichermanagement (Paging, Heap, Virtual File System, Ram Disk) und Prozessmanagement (Multitasking) gewidmet. Das Thema User-Lib und -Programme gehört dort auch noch dazu.

Wie ich GRUB und Cross-Compiler einbeziehen werde, weiß ich noch nicht sicher. Zunächst werde ich das Community-OS tyndur näher unter die Lupe nehmen, um handwerklich dazu zu lernen. Hier existiert ein "noch" lebendiges deutsches Forum zum Thema OS Development, das eine Unterstützung/Belebung verdient und arbeitsteilig seit einigen Jahren ein interessantes Hobby-OS entwickelt:
http://lowlevel.brainsware.org/wiki/index.php/Tyndur

Das Kernproblem für den Einsteiger ist nicht die komplexe x86-Technik, die in den Intel Manuals gut beschrieben ist, sondern die Herausforderung, mit den notwendigen Tools (Intel- und AT&T Assembler-Syntax, Linker-Skripte, Cross Compiler, GRUB Image, Bochs Debugger, ...) und Informationsquellen (Intel Manuals, Foren, Tutorials, Bücher, Sourcecode einiger Vorbild-OS, Wechselspiel C und Assembler, ...) umfassend und tiefschürfend klar zu kommen.

Minix3 http://www.minix3.org/ spielt hierbei nach wie vor nur eine akademische Rolle als Beispiel für einen "Mikrokernel", was nichts über seine Bedeutung für die Zukunft aussagt. Es wurde historisch schlicht und einfach von Linux besiegt. Hier hat der mutige Student über den sturen Professor gesiegt. ;)

In der Praxis findet man momentan bevorzugt monolithische Systeme.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 04:30:48 13.06.2009, insgesamt 6-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 01:09:35 14.06.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Das Kernproblem für den Einsteiger ist nicht die komplexe x86-Technik, die in den Intel Manuals gut beschrieben ist...

x86 prozessoren sind schon übel genug. protected/real-mode, descriptortabellen, segmentregister usw. kommen doch nur daher, dass eine uralt-cpu mit immer mehr funktionalität versehen wurde, aber trotzdem kompatibel zur ursprungsversion bleiben sollte. hinzu kommt noch die hürde der verfrickelten PC-architektur (boot-loader, bussysteme, video-ram, bios, usw). alles in allem eine suboptimale konstruktion, so als hätte jemand einen formel-1 wagen aus 'nem trabbi zusammengezimmert.

Erhard Henkes schrieb:

sondern die Herausforderung, mit den notwendigen Tools (Intel- und AT&T Assembler-Syntax, Linker-Skripte, Cross Compiler, GRUB Image, Bochs Debugger...

hier bietet sich vielleicht an (als unterprojekt z.b.) eine toolchain zusammenzustellen, die ein benutzer leicht installieren (oder im idealfall einfach auf seinen rechner kopieren) kann, um dein OS zu bauen, zu testen und damit zu experimentieren.

Erhard Henkes schrieb:

"Mikrokernel", was nichts über seine Bedeutung für die Zukunft aussagt. Es wurde historisch schlicht und einfach von Linux besiegt.
...
In der Praxis findet man momentan bevorzugt monolithische Systeme.

auch hier, würde ich sagen, hat nicht das bessere gesiegt. ein modularer kernel ist doch wartbarer und leichter erweiterbar, als ein monolithischer klotz. ein system, in dem alle komponenten über wohldefinierte schnittstellen verbunden sind, ist im endeffekt auch weniger komplex.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:39:39 14.06.2009   Titel:              Zitieren

Zitat:
x86 prozessoren sind schon übel genug. protected/real-mode, descriptortabellen, segmentregister

Wenn man die Beiträge zu der "üblen" Situation der x86 Architektur liest, fragt man sich, warum diese komplizierte Struktur - bedingt durch Abwärtskompatibiltät - nicht schon längst durch eine überlegene einfachere Struktur überholt wurde?

Zitat:
toolchain
Ja, das ist richtig. Langfristig bleibt aber einem "OSDever", der in einer OS-Entwickler-Community (Deutschland: lost/tyndur; lowlevel.brainsware.org) eingebettet sein will, nur der Weg über Linux als Hostsystem und GRUB als luxuriöser Bootloader. Das gilt neben Bochs als Emulator und Debugger als Quasi-Standard im PC-Bereich. Linux ist insgesamt ein übermächtiges Vorbild für die gesamte Szene, die alles andere an die Wand drückt. Das ist schade und sollte durchbrochen werden. Vielleicht schaffen wir das noch, sind ja erst ganz am Anfang. Eine OS benötigt Jahre bis ein halbwegs stabiles Team mit Freude daran arbeiten kann. Redesigns und Neuanfänge inbegriffen.

Zitat:
auch hier, würde ich sagen, hat nicht das bessere gesiegt. ein modularer kernel ist doch wartbarer und leichter erweiterbar, als ein monolithischer klotz. ein system, in dem alle komponenten über wohldefinierte schnittstellen verbunden sind, ist im endeffekt auch weniger komplex.
Akzeptiert. Welches Vorbild schwebt Dir hier vor? Minix3?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:47:04 14.06.2009   Titel:              Zitieren

Zitat:
Ich denke mal, es soll dazu dienen, zu verstehen, wie ein OS funktioniert. Deswegen wird es von Grund auf programmiert. Und da so etwas nicht einfach ist, muss man etwas Geduld mitbringen.
Ja, Geduld und die Bereitschaft tief zu bohren, gehören dazu. Ich denke, dass so etwas lange Zeit braucht, bis es "fliegt".
Dann gibt es allerdings ein anderes Problem, nämlich Einsteigern in die Materie die Zusammenhänge darzustellen. Beispielsweise ist es extrem schwierig in "tyndur" (lost) einzusteigen, weil nirgends eine didaktisch durchdachte Step-by-Step-Anleitung, Modul-/Funktions-Übersichten oder grafische Darstellungen zu finden sind, wie dieses OS im Inneren arbeitet. Man muss über die ganz harte Tour zum Insider werden oder man lässt es schnell wieder.

Auf jeden Fall werde ich den Noobie nicht aus den Augen verlieren. Ein Buch "Betriebssystementwicklung - leicht gemacht" ist ein mögliches Ziel, oder zumindest eine brauchbare Tutorial-Reihe. Der Brückenschlag zu den Hobby-Robotern bietet sich ebenfalls an. Microsoft hat mit "Robotics" (seit 2006) http://msdn.microsoft.com/de-de/robotics/default(en-us).aspx einen Anfang gemacht. Daneben ist aber noch viel Platz für Alternativen.

Bisher haben wir nur einige "Bausteine" gezeigt und etwas damit herum experimentiert. Immerhin habe ich bereits argumentativ mit geholfen, dass James Molloy einsieht, dass er seine Tutorial-Reihe komplett überarbeiten sollte. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:54:26 14.06.2009, insgesamt 2-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 02:10:12 14.06.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Wenn man die Beiträge zu der "üblen" Situation der x86 Architektur liest, fragt man sich, warum diese komplizierte Struktur - bedingt durch Abwärtskompatibiltät - nicht schon längst durch eine überlegene einfachere Struktur überholt wurde?

schwer zu sagen. wahrscheinlich sinds wirtschaftliche interessen, an denen sich hard- und softwarehersteller ständig gegenseitig hochziehen. warum eine etablierte technik über den haufen werfen, wenn man einfach was dranflicken und der kundschaft als innovation verkaufen kann? solange der geldhahn sprudelt, besteht kein grund für 'ne radikale änderung, ja es wäre sogar riskant.

Erhard Henkes schrieb:

Welches Vorbild schwebt Dir hier vor? Minix3?

nix konkretes, einfach nur ein gutes, modulares design. klare trennung der aufgaben, hardwareabstraktion, schichtenmodell usw.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 04:02:09 14.06.2009   Titel:              Zitieren

Zitat:
einfach nur ein gutes, modulares design. klare trennung der aufgaben, hardwareabstraktion, schichtenmodell usw.

Schichtenmodell:
http://www.oser.org/~hp/sys_mgm/node4.html
http://de.wikipedia.org/wiki/Schichtenarchitektur#Schichtenmodell_bei_Betriebssystemen
Die Kommunikation muss über die Schnittstellen jeder einzelnen Zwischenschicht erfolgen. Das kostet Zeit und ist der Preis dieser sauberen Architektur.

Damit fiele Minix3 als puristischer Microkernel weg, wenn ich das richtig sehe.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 09:58:27 14.06.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Die Kommunikation muss über die Schnittstellen jeder einzelnen Zwischenschicht erfolgen. Das kostet Zeit und ist der Preis dieser sauberen Architektur.

sowas lässt sich sowieso kaum verhindern, beispiel: filesystem->sektorbasierter zugriff->bustreiber->hardwaretreiber, oder netzwerk->transport protokoll->paketorientierter zugriff->hardwaretreiber, usw. hauptsache verschiedene teilkomponenten sind dabei austauschbar bzw. parallel ausführbar (z.b. ein filesystem kann gleichzeitig mit festplatten, sd-karten und cd-roms arbeiten, was ja unter allen grossen OS selbstverständlich ist).

Erhard Henkes schrieb:

Damit fiele Minix3 als puristischer Microkernel weg, wenn ich das richtig sehe.

kommt drauf an, hauptsache die architektur bleibt flexibel. vielleicht ein 'hybridkernel' wie windows oder so: http://en.wikipedia.org/wiki/File:Windows_2000_architecture.svg
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:30:18 14.06.2009   Titel:              Zitieren

Ich habe hier ein Kapitel zum Thema "Aufruf einer C-Funktion" geschrieben:
http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId342494

Vielleicht könnte mal jemand drüber schauen, ob Fehler/Unklarheiten enthalten sind. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:47:14 14.06.2009, insgesamt 1-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 18:46:15 14.06.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Vielleicht kann man mal jemand drüber schauen, ob Fehler/Unklarheiten enthalten sind.

Vielleicht wäre es noch wichtig zu erwähnen, dass es bestimmte Aufrufkonventionen gibt, wie cdecl, stdcall, pascal und fastcall (gibt es noch welche?) und dass damit geregelt wird, wie die Parameter auf dem Stack abgelegt werden, also in welcher Reihenfolge, und wer sie aufräumen muss (caller oder callee)...
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 19:02:06 14.06.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Vielleicht kann man mal jemand drüber schauen, ob Fehler/Unklarheiten enthalten sind

du solltest noch dazuschreiben, auf welchen compiler du sich beziehst (GCC version 4.x nehme ich an) ein anderer compiler könnte vieles anders machen. ach ja, die benamung der funktion 'exit_task()' finde ich nicht sonderlich gelungen. dem namen nach könnte man vermuten, dass die funktion die task beendet, so dass sie nicht wieder dran kommt (vergl. exit() in standard C). womöglich wäre next_task(), switch_now(), yield(), oder sowas eine alternative?
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:30:52 14.06.2009   Titel:              Zitieren

Zitat:
'exit_task()' finde ich nicht sonderlich gelungen

Ja, das ist eindeutig falsch. "switch_context()" klingt gut, hat vor allem keinen Bezug zu irgendwelchen POSIX-Begriffen. Normalerweise machen Prozesse so was nicht "freiwillig", nur Threads kennen yield(). Da jede task ihren eigenen Adressraum hat, handelt es sich eindeutig um Prozesse. Das Ganze ist noch relativ experimentell und rudimentär. Ich denke gerade über eine vernünftige Weiterentwicklung nach, aber vielleicht ist es an dieser Stelle dafür noch zu früh, denn Scheduling und Threading ist ein zwar wichtiges aber leider ebenso komplexes Thema mit vielen Möglichkeiten. Das Schlimme dabei ist, dass es keine optimale Lösung gibt. Selbst Linux hat hier im Laufe seiner Entwicklung einen vollen Salto hingelegt. Das Thema Deadlock und entsprechende Deadlock-Algos zur Vermeidung oder Vorbeugung lauert bei Multithreading ebenso bereits um der Ecke.

Zitat:
GCC version 4.x nehme ich an

Das ist ein ganz übles Thema, da ich wegen des eigenen Bootloaders und dieses blöden aout-Formats (16/32-Bit-Code gemischt in kernel.asm) beim Linker immer noch an die Version gcc 3.1, ld 2.13 (in DJGPP) gebunden bin.
Hier hilft - nach meinem bisherigen Wissensstand - nur der typische Ausstieg nach Linux und GRUB. Dies werde ich in Teil 3 wohl auch machen müssen. Dann kommen allerdings die ganzen GRUB-Themen (magic numbers, ...) hinzu. Jemand, der auf längere Sicht OS-Development betreibt, muss sich allerdings diese Tool-Basis schaffen, um fremde OS kompilieren/testen zu können.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:28:44 14.06.2009, insgesamt 1-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 22:41:54 14.06.2009   Titel:              Zitieren

Bin in dem neuen Artikel nur über eine eher unwesentliche Kleinigkeit gestolpert:
Zitat:
Es gibt übrigens eine Konvention, dass der callee bevorzugt die Register EAX (z.B. zum Rechnen, Transferieren und als Rückgabewert), ECX (z.B. als Schleifenzähler) und EDX (in obigem Bsp. z.B. zum Rechnen) verwendet.
Das ist weniger eine Konvention sondern mehr eine Vorgabe des Prozessors. Manche Instruktionen arbeiten nur mit bestimmten Registern. "LOOP" als Beispiel funktioniert nur mit ECX als Zähler.
nöö..
Unregistrierter




Beitrag nöö.. Unregistrierter 23:11:01 14.06.2009   Titel:              Zitieren

dat is ne konvention. du musst eax ja ned als rückgaberegister nehmen oder ecx für die l00ps etc. das is schon richtig so wie es da steht.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:38:41 14.06.2009   Titel:              Zitieren

http://de.wikipedia.org/wiki/Aufrufkonvention#stdcall
Zitat:
Die Register EAX, ECX, und EDX sind reserviert für die Verwendung innerhalb der Funktion, werden also unter Umständen verändert. Rückgabewerte werden im EAX-Register zurückgegeben.


http://www.agner.org/optimize/calling_conventions.pdf (Kap. 6, Register Usage)
Zitat:
Scratch registers are registers that can be used for temporary storage without restrictions (also called caller-save or volatile registers): EAX, ECX, EDX

Zitat:
Callee-save registers are registers that you have to save before using them and restore after using them (also called non-volatile registers). You can rely on these registers having the same value after a call as before the call: EBX, ESI, EDI, EBP


Ich habe diese beiden Links in den Artikel übernommen.
Danke für die Durchsicht. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:38:44 15.06.2009, insgesamt 2-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 01:07:58 15.06.2009   Titel:              Zitieren

Eine Frage zum Artikel hätte ich da noch:

Warum ist in dem Beispiel der Wert vom ESP so extrem groß (0x40205xxx), aber der vom EIP (0x00009Cxx) so niedrig ?
wo?
Unregistrierter




Beitrag wo? Unregistrierter 01:32:23 15.06.2009   Titel:              Zitieren

warum nicht? was hat der 1 mit dem anderen zu tun?
Unregistrierter





Beitrag Unregistrierter 01:37:29 15.06.2009   Titel:              Zitieren

Speichermanagement ? Virtualisierung ? Noch mehr ? :)
wo?
Unregistrierter




Beitrag wo? Unregistrierter 01:45:23 15.06.2009   Titel:              Zitieren

häh? ich kenn jetzt erhards OS nicht aber wenns generell gemeint ist versteh ich dein posting nicht. er kann doch die dinge mappen wo er will
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 11:13:59 15.06.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Hier hilft - nach meinem bisherigen Wissensstand - nur der typische Ausstieg nach Linux und GRUB.

das wäre doch doof. die meisten haben windosen. sich extra noch ein OS zu installieren, um dein OS zu bauen, ist nervig.
Erhard Henkes schrieb:

Dies werde ich in Teil 3 wohl auch machen müssen. Dann kommen allerdings die ganzen GRUB-Themen (magic numbers, ...) hinzu. Jemand, der auf längere Sicht OS-Development betreibt, muss sich allerdings diese Tool-Basis schaffen, um fremde OS kompilieren/testen zu können.

es geht bestimmt mit jedem compiler z.b. msvc express edition, watcom, oder dem LCC. natürlich nicht von allein, etwas basteln muss man schon. vorteil: du wärst diese ätzende AT&T-syntax endlich los.
:)
Tobiking2
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 705
Beitrag Tobiking2 Mitglied 11:14:56 15.06.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Das ist ein ganz übles Thema, da ich wegen des eigenen Bootloaders und dieses blöden aout-Formats (16/32-Bit-Code gemischt in kernel.asm) beim Linker immer noch an die Version gcc 3.1, ld 2.13 (in DJGPP) gebunden bin.
Hier hilft - nach meinem bisherigen Wissensstand - nur der typische Ausstieg nach Linux und GRUB.


Wieso muss es eigentlich im aout Format sein? Ich habe vor kurzem das OS + Bootloader unter Ubuntu 9.04 mit recht aktuellem gcc 4.3.3, ld 2.19.1 und nasm 2.05.1 compiliert. Dabei habe ich unter anderem das aout in elf geändert, und es lief ohne Probleme. Das aktuelle DJGPP hat ähnliche Versionen, daher sollte das doch eigentlich auch gehen, oder gibt es da noch einen anderen Unterschied?

Im NASM Manual steht auch, wenn ich das richtig verstehe, dass 16 Bit im ELF Format möglich ist, da NASM die nötigen Informationen übergibt, damit ld weiß was damit zu tun ist: http://www.nasm.us/doc/nasmdoc7.html (7.7.6)


Unter http://pastebin.com/m3b4d8bcd ist mein Makefile. Das Basis Makefile war die aktuelle Testversion am 20. Mai. Ansonsten habe ich nur noch bei sämtlichen Variablen und Funktionen, die von c benutzt wurden, aber in asm definiert waren, den Unterstrich entfernen müssen. Anscheinend ist es nicht mehr Standard, dass gcc den Unterstrich benutzt und ich habe auch kein Compilerflag dafür gefunden das wieder zu aktivieren.


Zuletzt bearbeitet von Tobiking2 am 17:07:55 15.06.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:25:29 16.06.2009   Titel:              Zitieren

@Tobiking2: danke für den Hinweis. Da muss ich doch noch mal probieren.
Ich kopiere das makefile von 'Tobiking2' mal hier rein:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
      all:
      nasm      -f bin file_data.asm -o file_data.dat
      nasm -O32 -f bin boot.asm -o boot.bin            
      nasm -O32 -f elf kernel.asm -o kernel.o
      nasm -O32 -f elf isr.asm -o isr.o
      nasm -O32 -f elf process.asm -o process.o
      nasm -O32 -f elf flush.asm -o flush.o

      gcc  -Wall -O -fno-stack-protector -fno-builtin -fno-stack-protector -fno-builtin -nostdlib  -fno-builtin -fno-stack-protector -fstrength-reduce -fomit-frame-pointer -finline-functions -c ckernel.c -o ckernel.o    

usw.

      ld -T kernel.ld kernel.o isr.o ckernel.o video.o flush.o gdt.o idt.o isrs.o irq.o util.o math.o timer.o keyboard.o process.o ordered_array.o paging.o kheap.o descriptor_tables.o task.o  -o ckernel.bin -Map kernel.map
 
      cat boot.bin > MyOS
      cat ckernel.bin >> MyOS
      mv MyOS MyOS.bin
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
all:
nasm -f bin file_data.asm -o file_data.dat
nasm -O32 -f bin boot.asm -o boot.bin
nasm -O32 -f elf kernel.asm -o kernel.o
nasm -O32 -f elf isr.asm -o isr.o
nasm -O32 -f elf process.asm -o process.o
nasm -O32 -f elf flush.asm -o flush.o

gcc -Wall -O -fno-stack-protector -fno-builtin -fno-stack-protector -fno-builtin -nostdlib -fno-builtin -fno-stack-protector -fstrength-reduce -fomit-frame-pointer -finline-functions -c ckernel.c -o ckernel.o

usw.

ld -T kernel.ld kernel.o isr.o ckernel.o video.o flush.o gdt.o idt.o isrs.o irq.o util.o math.o timer.o keyboard.o process.o ordered_array.o paging.o kheap.o descriptor_tables.o task.o -o ckernel.bin -Map kernel.map

cat boot.bin > MyOS
cat ckernel.bin >> MyOS
mv MyOS MyOS.bin
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
      all:
      nasm      -f bin file_data.asm -o file_data.dat
      nasm -O32 -f bin boot.asm -o boot.bin            
      nasm -O32 -f elf kernel.asm -o kernel.o
      nasm -O32 -f elf isr.asm -o isr.o
      nasm -O32 -f elf process.asm -o process.o
      nasm -O32 -f elf flush.asm -o flush.o

      gcc  -Wall -O -fno-stack-protector -fno-builtin -fno-stack-protector -fno-builtin -nostdlib  -fno-builtin -fno-stack-protector -fstrength-reduce -fomit-frame-pointer -finline-functions -c ckernel.c -o ckernel.o    

usw.

      ld -T kernel.ld kernel.o isr.o ckernel.o video.o flush.o gdt.o idt.o isrs.o irq.o util.o math.o timer.o keyboard.o process.o ordered_array.o paging.o kheap.o descriptor_tables.o task.o  -o ckernel.bin -Map kernel.map
 
      cat boot.bin > MyOS
      cat ckernel.bin >> MyOS
      mv MyOS MyOS.bin


Wenn ich das mit meinem DJGPP (gcc 3.1) ausprobiere erhalte ich vom Linker (ld 2.13) folgende Fehlermeldung:
Zitat:
kernel.o: file not recognized: File format not recognized



Im Linker-Skript habe ich übrigens 'rodata' ergänzt, weil einige Compiler das brauchen:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
phys = 0x00008000;
SECTIONS
{
  .text phys  : {
    *(.text)
  }
  .data  : {
    *(.data)
  }    
  .rodata  : {
    *(.rodata)
  }
  .bss  :  {                    
    *(.bss)
  }
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
phys = 0x00008000;
SECTIONS
{
.text phys : {
*(.text)
}
.data : {
*(.data)
}
.rodata : {
*(.rodata)
}
.bss : {
*(.bss)
}
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
phys = 0x00008000;
SECTIONS
{
  .text phys  : {
    *(.text)
  }
  .data  : {
    *(.data)
  }    
  .rodata  : {
    *(.rodata)
  }
  .bss  :  {                    
    *(.bss)
  }
}

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:59:26 16.06.2009, insgesamt 8-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:36:36 16.06.2009   Titel:              Zitieren

Zitat:
Warum ist in dem Beispiel der Wert vom ESP so extrem groß (0x40205xxx), aber der vom EIP (0x00009Cxx) so niedrig?


Die Kernel-Stacks für die erzeugten Prozesse wurden jeweils auf dem Heap angelegt, und der beginnt bei mir ab 0x40000000.

kheap.h:
C/C++ Code:
#define KHEAP_START         0x40000000 // 1GB
#define
KHEAP_INITIAL_SIZE  0x00200000
#define
KHEAP_MAX           0x4FFFF000
C/C++ Code:
#define KHEAP_START 0x40000000 // 1GB
#define
KHEAP_INITIAL_SIZE 0x00200000
#define
KHEAP_MAX 0x4FFFF000
C/C++ Code:
#define KHEAP_START         0x40000000 // 1GB
#define
KHEAP_INITIAL_SIZE  0x00200000
#define
KHEAP_MAX           0x4FFFF000


Das Programm selbst ist unten bei 0x00008000 (siehe phys = 0x00008000 im Linker-Skript oben) abgelegt, siehe auch Datei 'kernel.map':
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Linker script and memory map

                0x00008000                phys = 0x8000

.text           0x00008000     0x55d0
 *(.text)
 .text          0x00008000       0xd0 kernel.o
                0x00008000                RealMode
 .text          0x000080d0      0x1d8 isr.o
                0x00008178                _isr20
//...

 .text          0x000082b0      0x3c0 ckernel.o
                0x000082b0                _f2
                0x000082f0                _f3
                0x00008430                _main
//...
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Linker script and memory map

0x00008000 phys = 0x8000

.text 0x00008000 0x55d0
*(.text)
.text 0x00008000 0xd0 kernel.o
0x00008000 RealMode
.text 0x000080d0 0x1d8 isr.o
0x00008178 _isr20
//...

.text 0x000082b0 0x3c0 ckernel.o
0x000082b0 _f2
0x000082f0 _f3
0x00008430 _main
//...
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Linker script and memory map

                0x00008000                phys = 0x8000

.text           0x00008000     0x55d0
 *(.text)
 .text          0x00008000       0xd0 kernel.o
                0x00008000                RealMode
 .text          0x000080d0      0x1d8 isr.o
                0x00008178                _isr20
//...

 .text          0x000082b0      0x3c0 ckernel.o
                0x000082b0                _f2
                0x000082f0                _f3
                0x00008430                _main
//...

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:50:19 16.06.2009, insgesamt 3-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:41:25 16.06.2009   Titel:              Zitieren

Zitat:
das wäre doch doof. die meisten haben windosen. sich extra noch ein OS zu installieren, um dein OS zu bauen, ist nervig.

Interessante Bemerkung. Wenn ich das mit dem Compiler mit ELF (16 u. 32 Bit gemischt) unter Windows schaffe (es gibt ja auch cross-compiler), dann bleibt nur noch GRUB als Thema. Alternativ kann man den bootloader aufmotzen. Mal sehen. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:48:54 16.06.2009, insgesamt 6-mal bearbeitet
Tobiking2
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 705
Beitrag Tobiking2 Mitglied 07:51:20 16.06.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Wenn ich das mit meinem DJGPP (gcc 3.1) ausprobiere erhalte ich vom Linker (ld 2.13) folgende Fehlermeldung:
Zitat:
kernel.o: file not recognized: File format not recognized


Habs grad mal mit dem aktuellen djgpp probiert und das gleiche Problem. DJGPP benutzt nur COFF und unterstützt ELF gar nicht (http://www.delorie.com/djgpp/v2faq/faq22_22.html). Bei coff ist darüber hinaus kein 16 Bit möglich.

Ich bin beim Suchen auf http://exec.h1.ru/docs/os-devel-faq/os-faq-elf.html gestoßen, einer Anleitung um binutils mit elf support zu compilieren.
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 12:12:16 16.06.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Wenn ich das mit dem Compiler mit ELF (16 u. 32 Bit gemischt) unter Windows schaffe (es gibt ja auch cross-compiler), dann bleibt nur noch GRUB als Thema.

was willste mit 16 bit? dachte dein OS schaltet beim start schon in den (flat memory model) 32bit protected mode und bleibt da auch. oder hab' ich was übersehen?
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:06:32 16.06.2009   Titel:              Zitieren

Zitat:
was willste mit 16 bit?

Schau mal in kernel.asm ...

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
;org 0x8000     ; code's start offset
[BITS 16]     ; 16 Bit Code
[global RealMode]
[extern _main] ; this is in the c file

;;;;;;;;;;;;;
; Real Mode ;
;;;;;;;;;;;;;

RealMode:
    xor ax, ax         ; set up segments
    mov es, ax
    mov ds, ax
    mov ss, ax
    mov sp, ax

    mov si, welcome
    call print_string

    cli               ; clear interrupts

    lgdt [gdtr]       ; load GDT via GDTR (defined in file "gtd.inc")

; we actually only need to do this ONCE, but for now it doesn't hurt to do this more often when
; switching between RM and PM
    in  al, 0x92      ; switch A20 gate via fast A20 port 92
    cmp al, 0xff      ; if it reads 0xFF, nothing's implemented on this port
    je .no_fast_A20
   
    or  al, 2         ; set A20_Gate_Bit (bit 1)
    and al, ~1        ; clear INIT_NOW bit (don't reset pc...)
    out 0x92, al
    jmp .A20_done
   
.no_fast_A20:         ; no fast shortcut -> use the slow kbc...
    call empty_8042
   
    mov al, 0xD1      ; kbc command: write to output port
    out 0x64, al
    call empty_8042
   
    mov al, 0xDF      ; writing this to kbc output port enables A20
    out 0x60, al
    call empty_8042

.A20_done:
    mov eax, cr0      ; switch-over to Protected Mode
    or  eax, 1        ; set bit 0 of CR0 register
    mov cr0, eax      ;

    jmp 0x8:ProtectedMode ; http://www.nasm.us/doc/nasmdo10.html#section-10.1

;;;;;;;;;
; Calls ;
;;;;;;;;;

empty_8042:
    call Waitingloop
    in al, 0x64
    cmp al, 0xff      ; ... no real kbc at all?
    je .done
   
    test al, 1        ; something in input buffer?
    jz .no_output
    call Waitingloop
    in al, 0x60       ; yes: read buffer
    jmp empty_8042    ; and try again
   
.no_output:
    test al, 2        ; command buffer empty?
    jnz empty_8042    ; no: we can't send anything new till it's empty
.done:
ret

print_string:
    mov ah, 0x0E
.loop_start:
    lodsb              ; grab a byte from SI
    test al, al        ; test AL
    jz .done           ; if the result is zero, get out
    int 0x10           ; otherwise, print out the character!
    jmp .loop_start
.done:
    ret


Waitingloop:                  
    mov ebx,0x9FFFF
.loop_start:
    dec ebx    
    jnz .loop_start
    ret      
   
;;;;;;;;;;;;;;;;;;
; Protected Mode ;
;;;;;;;;;;;;;;;;;;

[Bits 32]

ProtectedMode:
    mov    ax, 0x10
    mov    ds, ax      ; data descriptor --> data, stack and extra segment
    mov    ss, ax          
    mov    es, ax
    xor    eax, eax    ; null desriptor --> FS and GS
    mov    fs, ax
    mov    gs, ax
    mov    esp, 0x200000 ; set stack below 2 MB limit

  call _main ; ->-> C-Kernel
  jmp $

;;;;;;;;;;;
; Strings ;
;;;;;;;;;;;

welcome db 'HenkesSoft 0.08 (May 16, 2009)', 13, 10, 0

;;;;;;;;;;;;
; Includes ;
;;;;;;;;;;;;

%include "gdt.inc"
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
;org 0x8000 ; code's start offset
[BITS 16] ; 16 Bit Code
[global RealMode]
[extern _main] ; this is in the c file

;;;;;;;;;;;;;
; Real Mode ;
;;;;;;;;;;;;;

RealMode:
xor ax, ax ; set up segments
mov es, ax
mov ds, ax
mov ss, ax
mov sp, ax

mov si, welcome
call print_string

cli ; clear interrupts

lgdt [gdtr] ; load GDT via GDTR (defined in file "gtd.inc")

; we actually only need to do this ONCE, but for now it doesn't hurt to do this more often when
; switching between RM and PM
in al, 0x92 ; switch A20 gate via fast A20 port 92
cmp al, 0xff ; if it reads 0xFF, nothing's implemented on this port
je .no_fast_A20

or al, 2 ; set A20_Gate_Bit (bit 1)
and al, ~1 ; clear INIT_NOW bit (don't reset pc...)
out 0x92, al
jmp .A20_done

.no_fast_A20: ; no fast shortcut -> use the slow kbc...
call empty_8042

mov al, 0xD1 ; kbc command: write to output port
out 0x64, al
call empty_8042

mov al, 0xDF ; writing this to kbc output port enables A20
out 0x60, al
call empty_8042

.A20_done:
mov eax, cr0 ; switch-over to Protected Mode
or eax, 1 ; set bit 0 of CR0 register
mov cr0, eax ;

jmp 0x8:ProtectedMode ; http://www.nasm.us/doc/nasmdo10.html#section-10.1

;;;;;;;;;
; Calls ;
;;;;;;;;;

empty_8042:
call Waitingloop
in al, 0x64
cmp al, 0xff ; ... no real kbc at all?
je .done

test al, 1 ; something in input buffer?
jz .no_output
call Waitingloop
in al, 0x60 ; yes: read buffer
jmp empty_8042 ; and try again

.no_output:
test al, 2 ; command buffer empty?
jnz empty_8042 ; no: we can't send anything new till it's empty
.done:
ret

print_string:
mov ah, 0x0E
.loop_start:
lodsb ; grab a byte from SI
test al, al ; test AL
jz .done ; if the result is zero, get out
int 0x10 ; otherwise, print out the character!
jmp .loop_start
.done:
ret


Waitingloop:
mov ebx,0x9FFFF
.loop_start:
dec ebx
jnz .loop_start
ret

;;;;;;;;;;;;;;;;;;
; Protected Mode ;
;;;;;;;;;;;;;;;;;;

[Bits 32]

ProtectedMode:
mov ax, 0x10
mov ds, ax ; data descriptor --> data, stack and extra segment
mov ss, ax
mov es, ax
xor eax, eax ; null desriptor --> FS and GS
mov fs, ax
mov gs, ax
mov esp, 0x200000 ; set stack below 2 MB limit

call _main ; ->-> C-Kernel
jmp $

;;;;;;;;;;;
; Strings ;
;;;;;;;;;;;

welcome db 'HenkesSoft 0.08 (May 16, 2009)', 13, 10, 0

;;;;;;;;;;;;
; Includes ;
;;;;;;;;;;;;

%include "gdt.inc"
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
;org 0x8000     ; code's start offset
[BITS 16]     ; 16 Bit Code
[global RealMode]
[extern _main] ; this is in the c file

;;;;;;;;;;;;;
; Real Mode ;
;;;;;;;;;;;;;

RealMode:
    xor ax, ax         ; set up segments
    mov es, ax
    mov ds, ax
    mov ss, ax
    mov sp, ax

    mov si, welcome
    call print_string

    cli               ; clear interrupts

    lgdt [gdtr]       ; load GDT via GDTR (defined in file "gtd.inc")

; we actually only need to do this ONCE, but for now it doesn't hurt to do this more often when
; switching between RM and PM
    in  al, 0x92      ; switch A20 gate via fast A20 port 92
    cmp al, 0xff      ; if it reads 0xFF, nothing's implemented on this port
    je .no_fast_A20
   
    or  al, 2         ; set A20_Gate_Bit (bit 1)
    and al, ~1        ; clear INIT_NOW bit (don't reset pc...)
    out 0x92, al
    jmp .A20_done
   
.no_fast_A20:         ; no fast shortcut -> use the slow kbc...
    call empty_8042
   
    mov al, 0xD1      ; kbc command: write to output port
    out 0x64, al
    call empty_8042
   
    mov al, 0xDF      ; writing this to kbc output port enables A20
    out 0x60, al
    call empty_8042

.A20_done:
    mov eax, cr0      ; switch-over to Protected Mode
    or  eax, 1        ; set bit 0 of CR0 register
    mov cr0, eax      ;

    jmp 0x8:ProtectedMode ; http://www.nasm.us/doc/nasmdo10.html#section-10.1

;;;;;;;;;
; Calls ;
;;;;;;;;;

empty_8042:
    call Waitingloop
    in al, 0x64
    cmp al, 0xff      ; ... no real kbc at all?
    je .done
   
    test al, 1        ; something in input buffer?
    jz .no_output
    call Waitingloop
    in al, 0x60       ; yes: read buffer
    jmp empty_8042    ; and try again
   
.no_output:
    test al, 2        ; command buffer empty?
    jnz empty_8042    ; no: we can't send anything new till it's empty
.done:
ret

print_string:
    mov ah, 0x0E
.loop_start:
    lodsb              ; grab a byte from SI
    test al, al        ; test AL
    jz .done           ; if the result is zero, get out
    int 0x10           ; otherwise, print out the character!
    jmp .loop_start
.done:
    ret


Waitingloop:                  
    mov ebx,0x9FFFF
.loop_start:
    dec ebx    
    jnz .loop_start
    ret      
   
;;;;;;;;;;;;;;;;;;
; Protected Mode ;
;;;;;;;;;;;;;;;;;;

[Bits 32]

ProtectedMode:
    mov    ax, 0x10
    mov    ds, ax      ; data descriptor --> data, stack and extra segment
    mov    ss, ax          
    mov    es, ax
    xor    eax, eax    ; null desriptor --> FS and GS
    mov    fs, ax
    mov    gs, ax
    mov    esp, 0x200000 ; set stack below 2 MB limit

  call _main ; ->-> C-Kernel
  jmp $

;;;;;;;;;;;
; Strings ;
;;;;;;;;;;;

welcome db 'HenkesSoft 0.08 (May 16, 2009)', 13, 10, 0

;;;;;;;;;;;;
; Includes ;
;;;;;;;;;;;;

%include "gdt.inc"


... und hier auf das Bild:
http://www.henkessoft.de/OS_Dev/Bilder/make_process.PNG

Da liegt der Knackpunkt: 16/32 Bit gemischt in kernel.asm. :rolleyes:

Vielleicht kann man das umbauen (ich sehe gerade, dass ich org 0x8000 schon auskommentiert habe, das geht offenbar bereits über das Linker-Skript), damit man coff-Format(?) verwenden kann. Vielleicht kann man auch in zwei Hälften (16 Bit u. 32 Bit Teil trennen, den ersten könnte man als bin resultieren lassen, den zweiten als o(bjekt)-Datei wegen des 'call _main')

Die wating-loop am Ende des 16-Bit-Teils sieht auch nicht sauber aus (war vorher im 32-Bit-Teil, wurde aber aus 16 Bit aufgerufen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:45:39 16.06.2009, insgesamt 3-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 21:37:47 16.06.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Da liegt der Knackpunkt: 16/32 Bit gemischt in kernel.asm.

aber das ist doch ok so, oder? pc-kisten starten nun mal im real-mode, dein asm-code schaltet in den protected mode und ruft die 'main' des kernels auf. von nun an läuft alles im protected mode ab, egal ob C oder assembler. selbst die portabelsten betriebssysteme haben ein paar plattformabhängige assemblermodule. ich weiss garnicht, was dich daran stört, oder ich hab' heute ne besonders lange leitung.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:07:12 16.06.2009   Titel:              Zitieren

Vielleicht stehe ich heute auf der Leitung. Ich benötige für kernel.asm das aout-Format (verkraftet beim Linken 16/32 bit gemischt) wegen des Linkers! Also ganz sachlich:

So klappt es bestens:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
    nasmw -O32 -f bin boot.asm -o boot.bin            
    nasmw -O32 -f aout kernel.asm -o kernel.o
    nasmw -O32 -f aout isr.asm -o isr.o
    nasmw -O32 -f aout process.asm -o process.o
    nasmw -O32 -f aout flush.asm -o flush.o
       
    gcc  -Wall -O  -c ckernel.c -o ckernel.o    
...
    gcc  -Wall -O  -c syscall.c -o syscall.o  

    ld -T kernel.ld kernel.o ... syscall.o  -o ckernel.bin -Map kernel.map
   
    cmd /c copy /b boot.bin + ckernel.bin MyOS    
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
nasmw -O32 -f bin boot.asm -o boot.bin
nasmw -O32 -f aout kernel.asm -o kernel.o
nasmw -O32 -f aout isr.asm -o isr.o
nasmw -O32 -f aout process.asm -o process.o
nasmw -O32 -f aout flush.asm -o flush.o

gcc -Wall -O -c ckernel.c -o ckernel.o
...
gcc -Wall -O -c syscall.c -o syscall.o

ld -T kernel.ld kernel.o ... syscall.o -o ckernel.bin -Map kernel.map

cmd /c copy /b boot.bin + ckernel.bin MyOS
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
    nasmw -O32 -f bin boot.asm -o boot.bin            
    nasmw -O32 -f aout kernel.asm -o kernel.o
    nasmw -O32 -f aout isr.asm -o isr.o
    nasmw -O32 -f aout process.asm -o process.o
    nasmw -O32 -f aout flush.asm -o flush.o
       
    gcc  -Wall -O  -c ckernel.c -o ckernel.o    
...
    gcc  -Wall -O  -c syscall.c -o syscall.o  

    ld -T kernel.ld kernel.o ... syscall.o  -o ckernel.bin -Map kernel.map
   
    cmd /c copy /b boot.bin + ckernel.bin MyOS    

Nachteil: Modernere Linker kennen kein aout (UNIX assembler out) mehr, wenn ich das richtig verstanden habe.

Versuch 1: nasmw -O32 -f coff kernel.asm -o kernel.o
Zitat:
nasmw -O32 -f coff kernel.asm -o kernel.o
kernel.asm:21: error: COFF format does not support non-32-bit relocations
kernel.asm:26: error: COFF format does not support non-32-bit relocations
kernel.asm:55: error: COFF format does not support non-32-bit relocations
make.exe: *** [all] Error 1


Hier streikt nasm(w) wegen 16 bit relocations.

Versuch 2: nasmw -O32 -f elf kernel.asm -o kernel.o
Zitat:
kernel.o: file not recognized: File format not recognized
make.exe: *** [all] Error 1

Diesmal will der Linker nicht.

Damit hänge ich irgendwie am aout-Format fest. :D

Vielleicht hilft da ein cross-compiler:
1) http://wiki.osdev.org/GCC_Cross-Compiler
2) http://lowlevel.brainsware.org/wiki/index.php/Cross-Compiler

Kennt sich da jemand genau aus? Bin leider (noch) kein Compiler-Experte.

Übrigens ist abc.w hier auch mit mingw gescheitert:
http://www.c-plusplus.de/forum/viewtopic-var-p-is-1687893.html

Ich habe das mit mingw (ist in code::blocks enthalten) noch mal probiert:
Zitat:
C:\Programme\CodeBlocks\MinGW\bin\ld: cannot perform PE operations on non PE output file 'ckernel.bin'.
Hmmm, siehe unten!

Kennt sich da jemand genau aus? Offensichtlich lösen die Cross-Compiler dieses Problem. :confused:

daher bin ich bei meinem DJGPP (gcc 3.1, ld 2.13) und aout geblieben, habe aber das Gefühl, das man da einen Schritt vorwärts kommen sollte.

Kann mir jemand die Hintergründe, warum man diesen Cross-Compiler bauen muss, mal erklären. Da hat sich doch gegen "früher" etwas verschlechtert, denn ich arbeite doch mit dem DJGPP und dem aout-Format sehr gut! Das Problem ist der Wechsel von aout nach elf. ;)

http://wiki.osdev.org/GCC_Cross-Compiler
Zitat:

Why an OS developer should build a cross-compiler

Creating a dedicated (cross-) compiler for your OS development work can save you many headaches. If...

* ...your system compiler drags in references to alloca() or other OS-dependent things,
* ...the ld linker complains about "PE operation on non-PE file",
* ...your compiler and your assembler can't agree on binary formats ("unresolved reference to _kmain()"), or
* ...your bootloader stubbornly insists that it cannot read your kernel binary,
* ...you are using Mac OS

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:55:37 16.06.2009, insgesamt 9-mal bearbeitet
+fricky
Unregistrierter




Beitrag +fricky Unregistrierter 10:06:10 17.06.2009   Titel:              Zitieren

Erhard Henkes schrieb:

So klappt es bestens:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
    nasmw -O32 -f bin boot.asm -o boot.bin            
    nasmw -O32 -f aout kernel.asm -o kernel.o
    nasmw -O32 -f aout isr.asm -o isr.o
    nasmw -O32 -f aout process.asm -o process.o
    nasmw -O32 -f aout flush.asm -o flush.o
       
    gcc  -Wall -O  -c ckernel.c -o ckernel.o    
...
    gcc  -Wall -O  -c syscall.c -o syscall.o  

    ld -T kernel.ld kernel.o ... syscall.o  -o ckernel.bin -Map kernel.map
   
    cmd /c copy /b boot.bin + ckernel.bin MyOS    
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
nasmw -O32 -f bin boot.asm -o boot.bin
nasmw -O32 -f aout kernel.asm -o kernel.o
nasmw -O32 -f aout isr.asm -o isr.o
nasmw -O32 -f aout process.asm -o process.o
nasmw -O32 -f aout flush.asm -o flush.o

gcc -Wall -O -c ckernel.c -o ckernel.o
...
gcc -Wall -O -c syscall.c -o syscall.o

ld -T kernel.ld kernel.o ... syscall.o -o ckernel.bin -Map kernel.map

cmd /c copy /b boot.bin + ckernel.bin MyOS
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
    nasmw -O32 -f bin boot.asm -o boot.bin            
    nasmw -O32 -f aout kernel.asm -o kernel.o
    nasmw -O32 -f aout isr.asm -o isr.o
    nasmw -O32 -f aout process.asm -o process.o
    nasmw -O32 -f aout flush.asm -o flush.o
       
    gcc  -Wall -O  -c ckernel.c -o ckernel.o    
...
    gcc  -Wall -O  -c syscall.c -o syscall.o  

    ld -T kernel.ld kernel.o ... syscall.o  -o ckernel.bin -Map kernel.map
   
    cmd /c copy /b boot.bin + ckernel.bin MyOS    


ok, du kannst nasm- und gcc-output zusammenlinken, also ist doch alles gut. ich sehe jedenfalls keinen grund, die tools zu wechseln (ein solcher wäre für mich z.b. ein ernsthafter bug des gcc oder nasm).
btw, aber wenn du unbedingt wechseln willst, kannste das auch zu einem beliebigen späteren zeitpunkt tun. ist also nix, was die weiterentwicklung deines OS grossartig beeinflussen würde.
:)
chris_g_ivi
Mitglied

Benutzerprofil
Anmeldungsdatum: 28.01.2009
Beiträge: 10
Beitrag chris_g_ivi Mitglied 13:11:02 17.06.2009   Titel:   Fehler mit C-Kernel            Zitieren

Hallo!

Super Topic und Themenwahl!
Ich habe ein kleines Problem! Wenn meine Kernel.bin (ASM + C-Kernel) keine Größe hat, die ohne Rest durch 512 Bytes teilbar ist, dann erhalte Ich einen Triple Fault!
Anfangs habe Ich per "times ??? db 0" die Datei richtig vergrößert, jedoch ist dies bei JEDER Änderung des Kernels notwendig!
Kennt jemand eine Lösung, um dies zu umgehen oder wenigstens das Ergebnis des Linkens auf eine Größe von ?.00 KB zu bringen?

Gruß
Chris

PS: Ich arbeite mit Windoof Vista und habe DJGPP, wie überall angepriesen installiert und in Gebrauch!

_________________
* Der Computer arbeitet so schnell, weil er nicht denkt.
Unregistrierter





Beitrag Unregistrierter 21:04:11 17.06.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Ich benötige für kernel.asm das aout-Format (verkraftet beim Linken 16/32 bit gemischt) wegen des Linkers!

Der [BITS 16]-Code in der kernel.asm passt noch in die boot.asm. Dann stünde in der kernel.asm i.e. nur noch folgendes:

Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[BITS 32]
[extern _main]

 mov    ax, 0x10
 mov    ds, ax      ; data descriptor --> data, stack and extra segment
 mov    ss, ax          
 mov    es, ax
 xor    eax, eax    ; null desriptor --> FS and GS
 mov    fs, ax
 mov    gs, ax
 mov    esp, 0x200000 ; set stack below 2 MB limit

 call _main ; ->-> C-Kernel
(...)
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[BITS 32]
[extern _main]

mov ax, 0x10
mov ds, ax ; data descriptor --> data, stack and extra segment
mov ss, ax
mov es, ax
xor eax, eax ; null desriptor --> FS and GS
mov fs, ax
mov gs, ax
mov esp, 0x200000 ; set stack below 2 MB limit

call _main ; ->-> C-Kernel
(...)
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[BITS 32]
[extern _main]

 mov    ax, 0x10
 mov    ds, ax      ; data descriptor --> data, stack and extra segment
 mov    ss, ax          
 mov    es, ax
 xor    eax, eax    ; null desriptor --> FS and GS
 mov    fs, ax
 mov    gs, ax
 mov    esp, 0x200000 ; set stack below 2 MB limit

 call _main ; ->-> C-Kernel
(...)

Damit wäre das Linker-Problem vom Tisch. Falls du ernsthaft GRUB in Erwägung ziehst, könntest du konsequenterweise die erste Hälfte von Teil 1 des Tutorials ersatzlos streichen. Das wäre schade. :(
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:36:00 17.06.2009   Titel:              Zitieren

Zitat:
Der [BITS 16]-Code in der kernel.asm passt noch in die boot.asm.

Ja, die Idee hatte ich gestern auch, nachdem der Code da jetzt relativ kurz ist.

Zitat:
Falls du ernsthaft GRUB in Erwägung ziehst, könntest du konsequenterweise die erste Hälfte von Teil 1 des Tutorials ersatzlos streichen. Das wäre schade.
Ja, das stimmt. Mir gefällt dieser Weg ohne GRUB und Windows auch sehr gut, vor allem, weil alle es anders machen. GRUB ist eben sehr komfortabel. Dafür ist man im Endeffekt an Linux und diesen Bootloader gebunden. Vielleicht schaffen wir es gemeinsam, den Bootloader bzw. kernel.asm (da ist ja Platz, da keine 512 Byte-Grenze mehr vorhanden) den Anforderungen entsprechend zu gestalten und GRUB zu umgehen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:45:46 17.06.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:29:18 18.06.2009   Titel:              Zitieren

@+gjm+: hast Du die Trennung bereits praktisch durchgeführt?

Ich habe mal versuchsweise getrennt, stürzt aber noch beim Kernel laden ab.

Ansonsten müsste ich nochmal step-by-step versuchsweise den Code in kleineren Häppchen von kernel.asm nach boot.asm schleppen.
Dann könnte man nämlich mal coff testen.

Nachfolgender Code klappt (s.u.).

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:29:13 18.06.2009, insgesamt 5-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:57:33 18.06.2009   Titel:              Zitieren

Einen Fehler habe ich step-by-step gefunden:
Code:
    cli               ; clear interrupts
    lgdt [gdtr]       ; load GDT via GDTR (defined in file "gtd.inc")   
    jmp 0x8:PM        ; http://www.nasm.us/doc/nasmdo10.html#section-10.1
Code:
cli ; clear interrupts
lgdt [gdtr] ; load GDT via GDTR (defined in file "gtd.inc")
jmp 0x8:PM ; http://www.nasm.us/doc/nasmdo10.html#section-10.1
Code:
    cli               ; clear interrupts
    lgdt [gdtr]       ; load GDT via GDTR (defined in file "gtd.inc")   
    jmp 0x8:PM        ; http://www.nasm.us/doc/nasmdo10.html#section-10.1

muss im 16-bit-Teil stehen.

Das macht mir noch ein Problem. So sieht es momentan aus (läuft!):

boot.asm
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
org 0x7C00  ; set up start address of bootloader

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; setup a stack and segment regs ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, ax

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; read kernel from floppy disk ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    mov [bootdrive], dl ; boot drive stored by BIOS in DL.
                        ; we save it to [bootdrive] to play for safety.

load_kernel:
    xor ax, ax         ; mov ax, 0  => function "reset"
    int 0x13        
    jc load_kernel     ; trouble? try again

    mov bx, 0x8000     ; set up start address of kernel

    ; set parameters for reading function
    ; 8-bit-wise for better overview
    mov dl,[bootdrive] ; select boot drive
    mov al, 59         ; read n sectors
    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

    ; show loading message
    mov si,loadmsg
    call print_string

;;;;;;;;;;;;;
; A20-Gate  ;
;;;;;;;;;;;;;   

    in  al, 0x92      ; switch A20 gate via fast A20 port 92
    cmp al, 0xff      ; if it reads 0xFF, nothing's implemented on this port
    je .no_fast_A20
   
    or  al, 2         ; set A20_Gate_Bit (bit 1)
    and al, ~1        ; clear INIT_NOW bit (don't reset pc...)
    out 0x92, al
    jmp .A20_done
   
.no_fast_A20:         ; no fast shortcut -> use the slow kbc...
    call empty_8042
   
    mov al, 0xD1      ; kbc command: write to output port
    out 0x64, al
    call empty_8042
   
    mov al, 0xDF      ; writing this to kbc output port enables A20
    out 0x60, al
    call empty_8042

.A20_done:

   
;;;;;;;;;;;;;;;;;;
; jump to kernel ;
;;;;;;;;;;;;;;;;;;

    jmp 0x8000   ; address of kernel. "jmp bx" might also work.

;;;;;;;;;
; Calls ;
;;;;;;;;;
 
print_string:
    mov ah, 0x0E      ; VGA BIOS fnct. 0x0E: teletype
.loop:  
    lodsb             ; grab a byte from SI
    test al, al       ; NUL?
    jz .done          ; if the result is zero, get out
    int 0x10          ; otherwise, print out the character!
    jmp .loop
.done:
    ret

empty_8042:
    call Waitingloop
    in al, 0x64
    cmp al, 0xff      ; ... no real kbc at all?
    je .done
   
    test al, 1        ; something in input buffer?
    jz .no_output
    call Waitingloop
    in al, 0x60       ; yes: read buffer
    jmp empty_8042    ; and try again
   
.no_output:
    test al, 2        ; command buffer empty?
    jnz empty_8042    ; no: we can't send anything new till it's empty
.done:
ret

Waitingloop:                  
    mov cx,0xFFFF
.loop_start:
    dec cx    
    jnz .loop_start
    ret      
    
   
;;;;;;;;
; data ;
;;;;;;;;

    bootdrive db 0    ; boot drive
    loadmsg db "bootloader message: loading kernel ...",13,10,0
   
    times 510-($-$$) hlt
    db 0x55
    db 0xAA
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
org 0x7C00 ; set up start address of bootloader

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; setup a stack and segment regs ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, ax

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; read kernel from floppy disk ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

mov [bootdrive], dl ; boot drive stored by BIOS in DL.
; we save it to [bootdrive] to play for safety.

load_kernel:
xor ax, ax ; mov ax, 0 => function "reset"
int 0x13
jc load_kernel ; trouble? try again

mov bx, 0x8000 ; set up start address of kernel

; set parameters for reading function
; 8-bit-wise for better overview
mov dl,[bootdrive] ; select boot drive
mov al, 59 ; read n sectors
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

; show loading message
mov si,loadmsg
call print_string

;;;;;;;;;;;;;
; A20-Gate ;
;;;;;;;;;;;;;

in al, 0x92 ; switch A20 gate via fast A20 port 92
cmp al, 0xff ; if it reads 0xFF, nothing's implemented on this port
je .no_fast_A20

or al, 2 ; set A20_Gate_Bit (bit 1)
and al, ~1 ; clear INIT_NOW bit (don't reset pc...)
out 0x92, al
jmp .A20_done

.no_fast_A20: ; no fast shortcut -> use the slow kbc...
call empty_8042

mov al, 0xD1 ; kbc command: write to output port
out 0x64, al
call empty_8042

mov al, 0xDF ; writing this to kbc output port enables A20
out 0x60, al
call empty_8042

.A20_done:


;;;;;;;;;;;;;;;;;;
; jump to kernel ;
;;;;;;;;;;;;;;;;;;

jmp 0x8000 ; address of kernel. "jmp bx" might also work.

;;;;;;;;;
; Calls ;
;;;;;;;;;

print_string:
mov ah, 0x0E ; VGA BIOS fnct. 0x0E: teletype
.loop:
lodsb ; grab a byte from SI
test al, al ; NUL?
jz .done ; if the result is zero, get out
int 0x10 ; otherwise, print out the character!
jmp .loop
.done:
ret

empty_8042:
call Waitingloop
in al, 0x64
cmp al, 0xff ; ... no real kbc at all?
je .done

test al, 1 ; something in input buffer?
jz .no_output
call Waitingloop
in al, 0x60 ; yes: read buffer
jmp empty_8042 ; and try again

.no_output:
test al, 2 ; command buffer empty?
jnz empty_8042 ; no: we can't send anything new till it's empty
.done:
ret

Waitingloop:
mov cx,0xFFFF
.loop_start:
dec cx
jnz .loop_start
ret


;;;;;;;;
; data ;
;;;;;;;;

bootdrive db 0 ; boot drive
loadmsg db "bootloader message: loading kernel ...",13,10,0

times 510-($-$$) hlt
db 0x55
db 0xAA
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
org 0x7C00  ; set up start address of bootloader

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; setup a stack and segment regs ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, ax

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; read kernel from floppy disk ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    mov [bootdrive], dl ; boot drive stored by BIOS in DL.
                        ; we save it to [bootdrive] to play for safety.

load_kernel:
    xor ax, ax         ; mov ax, 0  => function "reset"
    int 0x13        
    jc load_kernel     ; trouble? try again

    mov bx, 0x8000     ; set up start address of kernel

    ; set parameters for reading function
    ; 8-bit-wise for better overview
    mov dl,[bootdrive] ; select boot drive
    mov al, 59         ; read n sectors
    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

    ; show loading message
    mov si,loadmsg
    call print_string

;;;;;;;;;;;;;
; A20-Gate  ;
;;;;;;;;;;;;;   

    in  al, 0x92      ; switch A20 gate via fast A20 port 92
    cmp al, 0xff      ; if it reads 0xFF, nothing's implemented on this port
    je .no_fast_A20
   
    or  al, 2         ; set A20_Gate_Bit (bit 1)
    and al, ~1        ; clear INIT_NOW bit (don't reset pc...)
    out 0x92, al
    jmp .A20_done
   
.no_fast_A20:         ; no fast shortcut -> use the slow kbc...
    call empty_8042
   
    mov al, 0xD1      ; kbc command: write to output port
    out 0x64, al
    call empty_8042
   
    mov al, 0xDF      ; writing this to kbc output port enables A20
    out 0x60, al
    call empty_8042

.A20_done:

   
;;;;;;;;;;;;;;;;;;
; jump to kernel ;
;;;;;;;;;;;;;;;;;;

    jmp 0x8000   ; address of kernel. "jmp bx" might also work.

;;;;;;;;;
; Calls ;
;;;;;;;;;
 
print_string:
    mov ah, 0x0E      ; VGA BIOS fnct. 0x0E: teletype
.loop:  
    lodsb             ; grab a byte from SI
    test al, al       ; NUL?
    jz .done          ; if the result is zero, get out
    int 0x10          ; otherwise, print out the character!
    jmp .loop
.done:
    ret

empty_8042:
    call Waitingloop
    in al, 0x64
    cmp al, 0xff      ; ... no real kbc at all?
    je .done
   
    test al, 1        ; something in input buffer?
    jz .no_output
    call Waitingloop
    in al, 0x60       ; yes: read buffer
    jmp empty_8042    ; and try again
   
.no_output:
    test al, 2        ; command buffer empty?
    jnz empty_8042    ; no: we can't send anything new till it's empty
.done:
ret

Waitingloop:                  
    mov cx,0xFFFF
.loop_start:
    dec cx    
    jnz .loop_start
    ret      
    
   
;;;;;;;;
; data ;
;;;;;;;;

    bootdrive db 0    ; boot drive
    loadmsg db "bootloader message: loading kernel ...",13,10,0
   
    times 510-($-$$) hlt
    db 0x55
    db 0xAA


kernel.asm
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[BITS 16]     ; 16 Bit Code
[global KernelStart]
[extern _main] ; this is in the c file

KernelStart:

;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Load GDT and jump to PM ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;       
   
    cli               ; clear interrupts
    lgdt [gdtr]       ; load GDT via GDTR (defined in file "gtd.inc")   

    mov eax, cr0      ; switch-over to Protected Mode
    or  eax, 1        ; set bit 0 of CR0 register
    mov cr0, eax      ;   
    jmp 0x8:PM        ; http://www.nasm.us/doc/nasmdo10.html#section-10.1

[Bits 32]
PM:
    mov    ax, 0x10
    mov    ds, ax      ; data descriptor --> data, stack and extra segment
    mov    ss, ax          
    mov    es, ax
    xor    eax, eax    ; null desriptor --> FS and GS
    mov    fs, ax
    mov    gs, ax
    mov    esp, 0x200000 ; set stack below 2 MB limit

  call _main ; ->-> C-Kernel
  jmp $
   

;;;;;;;;;;;;
; Includes ;
;;;;;;;;;;;;

%include "gdt.inc"
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[BITS 16] ; 16 Bit Code
[global KernelStart]
[extern _main] ; this is in the c file

KernelStart:

;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Load GDT and jump to PM ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;

cli ; clear interrupts
lgdt [gdtr] ; load GDT via GDTR (defined in file "gtd.inc")

mov eax, cr0 ; switch-over to Protected Mode
or eax, 1 ; set bit 0 of CR0 register
mov cr0, eax ;
jmp 0x8:PM ; http://www.nasm.us/doc/nasmdo10.html#section-10.1

[Bits 32]
PM:
mov ax, 0x10
mov ds, ax ; data descriptor --> data, stack and extra segment
mov ss, ax
mov es, ax
xor eax, eax ; null desriptor --> FS and GS
mov fs, ax
mov gs, ax
mov esp, 0x200000 ; set stack below 2 MB limit

call _main ; ->-> C-Kernel
jmp $


;;;;;;;;;;;;
; Includes ;
;;;;;;;;;;;;

%include "gdt.inc"
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[BITS 16]     ; 16 Bit Code
[global KernelStart]
[extern _main] ; this is in the c file

KernelStart:

;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Load GDT and jump to PM ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;       
   
    cli               ; clear interrupts
    lgdt [gdtr]       ; load GDT via GDTR (defined in file "gtd.inc")   

    mov eax, cr0      ; switch-over to Protected Mode
    or  eax, 1        ; set bit 0 of CR0 register
    mov cr0, eax      ;   
    jmp 0x8:PM        ; http://www.nasm.us/doc/nasmdo10.html#section-10.1

[Bits 32]
PM:
    mov    ax, 0x10
    mov    ds, ax      ; data descriptor --> data, stack and extra segment
    mov    ss, ax          
    mov    es, ax
    xor    eax, eax    ; null desriptor --> FS and GS
    mov    fs, ax
    mov    gs, ax
    mov    esp, 0x200000 ; set stack below 2 MB limit

  call _main ; ->-> C-Kernel
  jmp $
   

;;;;;;;;;;;;
; Includes ;
;;;;;;;;;;;;

%include "gdt.inc"


kernel.ld
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
OUTPUT_FORMAT("binary")
ENTRY(KernelStart)
phys = 0x00008000;
SECTIONS
{
  .text phys  : {
    *(.text)
  }
  .data  : {
    *(.data)
  }    
  .rodata  : {
    *(.rodata)
  }
  .bss  :  {                    
    *(.bss)
  }
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
OUTPUT_FORMAT("binary")
ENTRY(KernelStart)
phys = 0x00008000;
SECTIONS
{
.text phys : {
*(.text)
}
.data : {
*(.data)
}
.rodata : {
*(.rodata)
}
.bss : {
*(.bss)
}
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
OUTPUT_FORMAT("binary")
ENTRY(KernelStart)
phys = 0x00008000;
SECTIONS
{
  .text phys  : {
    *(.text)
  }
  .data  : {
    *(.data)
  }    
  .rodata  : {
    *(.rodata)
  }
  .bss  :  {                    
    *(.bss)
  }
}


Frage: wie werde ich den 16 bit Teil in kernel.asm noch los? Ich springe ja vom bootloader nach 0x8000 (Kernelstart).

Ich schiebe den Code mal hoch:
http://www.henkessoft.de/OS_Dev/Downloads/20090618_47.zip

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:27:27 18.06.2009, insgesamt 2-mal bearbeitet
Eingeklemmt im Kaktus
Unregistrierter




Beitrag Eingeklemmt im Kaktus Unregistrierter 14:17:07 18.06.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Frage: wie werde ich den 16 bit Teil in kernel.asm noch los? Ich springe ja vom bootloader nach 0x8000 (Kernelstart).

Ganz einfach: Im Bootloader in den Protected Mode schalten (lgdt und cr0 laden), und dann mit jmp 0x08:0x8000 in den Kernel springen (d.h. im Bootloader ist auch kein 32 Bit Teil). Im Kernel kannst du dann direkt mit 32 Bit Code anfangen, und musst die Segmentregister erstmal laden. Danach solltest du dann nochmal eine GDT im Kernel laden, falls der Bootloader irgendwann überschrieben wird.
Unregistrierter





Beitrag Unregistrierter 14:56:45 18.06.2009   Titel:              Zitieren

Der boot.asm muß somit nur folgendes hinzugefügt werden:
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(...)
.A20_done:

 cli
 lgdt [gdtr]

 mov eax, cr0
 or  eax, 1
 mov cr0, eax

; jmp 0x8000
 jmp 0x8:0x8000    ; Ist zwar ein 16-bit-FAR-Jmp, allerdings
                   ; wird hier CS mit "index" 8 der GDT geladen (da in PM).
                   ; Deshalb wird der Code ab Sprungziel von der CPU
                   ; als 'BITS 32' interpretiert (s. CODE_Desc in der gdt.inc).
(...)
%include 'gdt.inc' ; <- Achtung : die gdt.inc ist nun hier und nicht mehr in der kernel.asm.

 times 510-($-$$) hlt
 db 0x55
 db 0xAA
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(...)
.A20_done:

cli
lgdt [gdtr]

mov eax, cr0
or eax, 1
mov cr0, eax

; jmp 0x8000
jmp 0x8:0x8000 ; Ist zwar ein 16-bit-FAR-Jmp, allerdings
; wird hier CS mit "index" 8 der GDT geladen (da in PM).
; Deshalb wird der Code ab Sprungziel von der CPU
; als 'BITS 32' interpretiert (s. CODE_Desc in der gdt.inc).
(...)
%include 'gdt.inc' ; <- Achtung : die gdt.inc ist nun hier und nicht mehr in der kernel.asm.

times 510-($-$$) hlt
db 0x55
db 0xAA
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(...)
.A20_done:

 cli
 lgdt [gdtr]

 mov eax, cr0
 or  eax, 1
 mov cr0, eax

; jmp 0x8000
 jmp 0x8:0x8000    ; Ist zwar ein 16-bit-FAR-Jmp, allerdings
                   ; wird hier CS mit "index" 8 der GDT geladen (da in PM).
                   ; Deshalb wird der Code ab Sprungziel von der CPU
                   ; als 'BITS 32' interpretiert (s. CODE_Desc in der gdt.inc).
(...)
%include 'gdt.inc' ; <- Achtung : die gdt.inc ist nun hier und nicht mehr in der kernel.asm.

 times 510-($-$$) hlt
 db 0x55
 db 0xAA
Nun sollte nur noch in der boot.asm "BITS 16"-Code sein. :)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:39:08 18.06.2009   Titel:              Zitieren

Danke! Hat gut funktioniert. Der boot sector ist immer noch halb leer, hat also noch Luft für notwendige Ergänzungen. :)

kernel.asm stellt sich nun wie folgt dar (ich lade GDT dort auf Anraten nochmals, ist das so im Code richtig umgesetzt?):
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[Bits 32]
[global KernelStart]
KernelStart:
    mov    ax, 0x10
    mov    ds, ax        ; data descriptor --> data, stack and extra segment
    mov    ss, ax          
    mov    es, ax
    xor    eax, eax      ; null desriptor --> FS and GS
    mov    fs, ax
    mov    gs, ax
    mov    esp, 0x200000 ; set stack below 2 MB limit

    lgdt [gdtr]          ; load GDT via GDTR (defined in file "gtd.inc")   
   
[extern _main]           ; entry point in ckernel.c
    call _main           ; ->-> C-Kernel
    jmp $
 
;;;;;;;;;;;;
; Includes ;
;;;;;;;;;;;;

    %include "gdt.inc"
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[Bits 32]
[global KernelStart]
KernelStart:
mov ax, 0x10
mov ds, ax ; data descriptor --> data, stack and extra segment
mov ss, ax
mov es, ax
xor eax, eax ; null desriptor --> FS and GS
mov fs, ax
mov gs, ax
mov esp, 0x200000 ; set stack below 2 MB limit

lgdt [gdtr] ; load GDT via GDTR (defined in file "gtd.inc")

[extern _main] ; entry point in ckernel.c
call _main ; ->-> C-Kernel
jmp $

;;;;;;;;;;;;
; Includes ;
;;;;;;;;;;;;

%include "gdt.inc"
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[Bits 32]
[global KernelStart]
KernelStart:
    mov    ax, 0x10
    mov    ds, ax        ; data descriptor --> data, stack and extra segment
    mov    ss, ax          
    mov    es, ax
    xor    eax, eax      ; null desriptor --> FS and GS
    mov    fs, ax
    mov    gs, ax
    mov    esp, 0x200000 ; set stack below 2 MB limit

    lgdt [gdtr]          ; load GDT via GDTR (defined in file "gtd.inc")   
   
[extern _main]           ; entry point in ckernel.c
    call _main           ; ->-> C-Kernel
    jmp $
 
;;;;;;;;;;;;
; Includes ;
;;;;;;;;;;;;

    %include "gdt.inc"


Die 16/32-Bit-Trennung ist damit gelungen, endlich. Ein kleiner Meilenstein. :)

Nun geht auch folgendes:

Code:
nasmw -O32 -f bin boot.asm -o boot.bin            
nasmw -O32 -f coff kernel.asm -o kernel.o
Code:
nasmw -O32 -f bin boot.asm -o boot.bin
nasmw -O32 -f coff kernel.asm -o kernel.o
Code:
nasmw -O32 -f bin boot.asm -o boot.bin            
nasmw -O32 -f coff kernel.asm -o kernel.o


Aber hier gibt es noch ein kleines Problem, auch noch mit KernelStart:
Zitat:

C:\DJGPP\bin/ld.exe: warning: cannot find entry symbol KernelStart; defaulting to 00008000 <--- Wieso dies?
ckernel.o(.text+0x1f8):ckernel.c: undefined reference to `_file_data_end'
ckernel.o(.text+0x1fd):ckernel.c: undefined reference to `_file_data_start'
ckernel.o(.text+0x215):ckernel.c: undefined reference to `_file_data_end'
ckernel.o(.text+0x21a):ckernel.c: undefined reference to `_file_data_start'
ckernel.o(.text+0x220):ckernel.c: undefined reference to `_file_data_start'
gdt.o(.text+0xf6):gdt.c: undefined reference to `_gdt_flush'
gdt.o(.text+0xfb):gdt.c: undefined reference to `_tss_flush'
idt.o(.text+0x70):idt.c: undefined reference to `_idt_flush'
isrs.o(.text+0xe):isrs.c: undefined reference to `_isr0'
isrs.o(.text+0x21):isrs.c: undefined reference to `_isr1'
...
isrs.o(.text+0x29e):isrs.c: undefined reference to `_isr127'
irq.o(.text+0xc5):irq.c: undefined reference to `_irq0'
...
irq.o(.text+0x1f7):irq.c: undefined reference to `_irq15'
paging.o(.text+0x522):paging.c: undefined reference to `_copy_page_physical'
task.o(.text+0x23b):task.c: undefined reference to `_irq_tail'
task.o(.text+0x3c1):task.c: undefined reference to `_irq_tail'
task.o(.text+0x7f2):task.c: undefined reference to `_read_eip'
make.exe: *** [all] Error 1

Ich möchte die Syntax mit dem führenden Unterstrich in C behalten. Tipp?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 18:59:19 18.06.2009, insgesamt 9-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 19:04:18 18.06.2009   Titel:              Zitieren

Zitat:
ich lade GDT dort auf Anraten nochmals, ...
:confused: Das macht hier keinen Sinn weil gelten würde : "alte GDT == neue GDT". Ausserdem müssten dann die Segmentregister erst wieder mit den Deskriptoren der "neuen" GDT initialisiert werden bevor sie "Wirkung" zeigen.
Zitat:
C:\DJGPP\bin/ld.exe: warning: cannot find entry symbol KernelStart; defaulting to 00008000 <--- Wieso dies?
Das Symbol (Label ?) "KernelStart" ist nirgendwo in der kernel.asm definiert. :)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:22:24 18.06.2009   Titel:              Zitieren

Zitat:
ich lade GDT dort auf Anraten nochmals, ...
:confused: Das macht hier keinen Sinn weil gelten würde : "alte GDT == neue GDT". Ausserdem müssten dann die Segmentregister erst wieder mit den Deskriptoren der "neuen" GDT initialisiert werden bevor sie "Wirkung" zeigen.

Also wieder weg. ;)
Der Bereich unter 08:0x8000 wird später nicht beschrieben.

Zitat:
Das Symbol (Label ?) "KernelStart" ist nirgendwo in der kernel.asm definiert. :)


Mit aout war/ist das kein Problem. Braucht coff das anders? Habe da noch nichts gefunden. :confused:

kernel.asm:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Bits 32]
[global KernelStart]

KernelStart:
    mov    ax, 0x10
    mov    ds, ax      ; data descriptor --> data, stack and extra segment
    mov    ss, ax          
    mov    es, ax
    xor    eax, eax    ; null desriptor --> FS and GS
    mov    fs, ax
    mov    gs, ax
    mov    esp, 0x200000 ; set stack below 2 MB limit

[extern _main]         ; entry point in ckernel.c
    call _main ; ->-> C-Kernel
    jmp $
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Bits 32]
[global KernelStart]

KernelStart:
mov ax, 0x10
mov ds, ax ; data descriptor --> data, stack and extra segment
mov ss, ax
mov es, ax
xor eax, eax ; null desriptor --> FS and GS
mov fs, ax
mov gs, ax
mov esp, 0x200000 ; set stack below 2 MB limit

[extern _main] ; entry point in ckernel.c
call _main ; ->-> C-Kernel
jmp $
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Bits 32]
[global KernelStart]

KernelStart:
    mov    ax, 0x10
    mov    ds, ax      ; data descriptor --> data, stack and extra segment
    mov    ss, ax          
    mov    es, ax
    xor    eax, eax    ; null desriptor --> FS and GS
    mov    fs, ax
    mov    gs, ax
    mov    esp, 0x200000 ; set stack below 2 MB limit

[extern _main]         ; entry point in ckernel.c
    call _main ; ->-> C-Kernel
    jmp $


Das war doch vorher auch nicht anders (da hatte ich nur RealMode).
Warum ist COFF so seltsam? :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 21:06:36 18.06.2009, insgesamt 2-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 21:08:41 18.06.2009   Titel:              Zitieren

Ganz schön zickenhaft der ld. Probiere mal folgendes in der kernel.asm:
Assembler Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
[BITS 32]

section .text ; <- jawohl lieber ld, "KernelStart" ist nun auch in der section .text :)

[global KernelStart]

KernelStart:
    mov    ax, 0x10

(...)
Assembler Code:
1
2
3
4
5
6
7
8
9
10
[BITS 32]

section .text ; <- jawohl lieber ld, "KernelStart" ist nun auch in der section .text :)

[global KernelStart]

KernelStart:
mov ax, 0x10

(...)
Assembler Code:
1
2
3
4
5
6
7
8
9
10
[BITS 32]

section .text ; <- jawohl lieber ld, "KernelStart" ist nun auch in der section .text :)

[global KernelStart]

KernelStart:
    mov    ax, 0x10

(...)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:26:32 18.06.2009   Titel:              Zitieren

Hat wirklich geholfen. Warum schluckt der ld das beim aout-Format und motzt erst beim COFF-Format. Merkwürdiges Verhalten. :D Man lernt nie aus.

Hilft auch gegen das Ignorieren der C-Funktionen. :)

Offenbar weiß der Linker beim COFF nicht, wo das Programm anfängt?! :D

Damit sind wir zumindest den Schritt aout --> coff gegangen. :live:
Code:
nasmw -O32 -f coff kernel.asm -o kernel.o
nasmw -O32 -f coff isr.asm -o isr.o
nasmw -O32 -f coff process.asm -o process.o
nasmw -O32 -f coff flush.asm -o flush.o
Code:
nasmw -O32 -f coff kernel.asm -o kernel.o
nasmw -O32 -f coff isr.asm -o isr.o
nasmw -O32 -f coff process.asm -o process.o
nasmw -O32 -f coff flush.asm -o flush.o
Code:
nasmw -O32 -f coff kernel.asm -o kernel.o
nasmw -O32 -f coff isr.asm -o isr.o
nasmw -O32 -f coff process.asm -o process.o
nasmw -O32 -f coff flush.asm -o flush.o

Vielleicht hilft es bei der Benutzung von Linkern höherer Versionen, die bisher mit aout Probleme hatten. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 21:32:16 18.06.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:11:33 18.06.2009   Titel:              Zitieren

Wenn wir schon bei so grausamen Themen sind. Ich wollte mal mein opulentes makefile umstellen auf eine variable Darstellung (vor allem, damit man compiler leicht tauschen kann). Hier klappt aber die Umsetzung c --> o und asm --> coff noch nicht, wenn ich das richtig sehe:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# Makefile for PrettyOS

SOURCES=    kernel.o        \
        ckernel.o            \
        isr.o                \
        video.o                \
        flush.o                \
        gdt.o                \
        idt.o                \
        isrs.o                \
        irq.o                \
        util.o                \
        math.o                \
        timer.o                \
        keyboard.o            \
        process.o            \
        ordered_array.o        \
        paging.o            \
        kheap.o                \
        descriptor_tables.o    \
        task.o                \
        fs.o                \
        initrd.o            \
        syscall.o


CFLAGS=    -Wall        \
        -O          
       
LDFLAGS= -T kernel.ld -Map kernel.map
ASFLAGS= -fcoff

CC=gcc
NASM=nasmw
AS=as


all:
    nasmw      -f bin file_data.asm -o file_data.dat
    nasmw -O32 -f bin boot.asm -o boot.bin            
    make -s link
    make -s image   

link:
    ld $(LDFLAGS) -o ckernel.bin $(SOURCES)
   

image:
    cmd /c copy /b boot.bin + ckernel.bin MyOS    
    cmd /c rename MyOS MyOS.bin
    del MyOS
   
    partcopy MyOS.bin 0 7000 -f0   

.s.o:
    $(NASM) $(ASFLAGS) $<

.c.o:
    $(CC) -c $(CFLAGS) -o $@ $<

.a.o:
    $(AS) $(ASFLAGS) -o $<
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# Makefile for PrettyOS

SOURCES= kernel.o \
ckernel.o \
isr.o \
video.o \
flush.o \
gdt.o \
idt.o \
isrs.o \
irq.o \
util.o \
math.o \
timer.o \
keyboard.o \
process.o \
ordered_array.o \
paging.o \
kheap.o \
descriptor_tables.o \
task.o \
fs.o \
initrd.o \
syscall.o


CFLAGS= -Wall \
-O

LDFLAGS= -T kernel.ld -Map kernel.map
ASFLAGS= -fcoff

CC=gcc
NASM=nasmw
AS=as


all:
nasmw -f bin file_data.asm -o file_data.dat
nasmw -O32 -f bin boot.asm -o boot.bin
make -s link
make -s image

link:
ld $(LDFLAGS) -o ckernel.bin $(SOURCES)


image:
cmd /c copy /b boot.bin + ckernel.bin MyOS
cmd /c rename MyOS MyOS.bin
del MyOS

partcopy MyOS.bin 0 7000 -f0

.s.o:
$(NASM) $(ASFLAGS) $<

.c.o:
$(CC) -c $(CFLAGS) -o $@ $<

.a.o:
$(AS) $(ASFLAGS) -o $<
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# Makefile for PrettyOS

SOURCES=    kernel.o        \
        ckernel.o            \
        isr.o                \
        video.o                \
        flush.o                \
        gdt.o                \
        idt.o                \
        isrs.o                \
        irq.o                \
        util.o                \
        math.o                \
        timer.o                \
        keyboard.o            \
        process.o            \
        ordered_array.o        \
        paging.o            \
        kheap.o                \
        descriptor_tables.o    \
        task.o                \
        fs.o                \
        initrd.o            \
        syscall.o


CFLAGS=    -Wall        \
        -O          
       
LDFLAGS= -T kernel.ld -Map kernel.map
ASFLAGS= -fcoff

CC=gcc
NASM=nasmw
AS=as


all:
    nasmw      -f bin file_data.asm -o file_data.dat
    nasmw -O32 -f bin boot.asm -o boot.bin            
    make -s link
    make -s image   

link:
    ld $(LDFLAGS) -o ckernel.bin $(SOURCES)
   

image:
    cmd /c copy /b boot.bin + ckernel.bin MyOS    
    cmd /c rename MyOS MyOS.bin
    del MyOS
   
    partcopy MyOS.bin 0 7000 -f0   

.s.o:
    $(NASM) $(ASFLAGS) $<

.c.o:
    $(CC) -c $(CFLAGS) -o $@ $<

.a.o:
    $(AS) $(ASFLAGS) -o $<

Zitat:

G:\OSDev\Test\49>make
nasmw -f bin file_data.asm -o file_data.dat
nasmw -O32 -f bin boot.asm -o boot.bin
make -s link
C:\DJGPP\bin/ld.exe: cannot open kernel.o: No such file or directory (ENOENT)
make.exe[1]: *** [link] Error 1
make.exe: *** [all] Error 2

Offensichtlich baut er keine xxx.o aus den xxx.c. und kein coff aus asm. :rolleyes:

Wo ist der Hauptfehler? Baue so was sonst nie selbst.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:14:39 18.06.2009, insgesamt 2-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 22:30:21 18.06.2009   Titel:              Zitieren

Kann ich nicht folgen. Eine "kernel.o" existiert doch, generiert via
Code:
nasmw -O32 -f coff kernel.asm -o kernel.o
Code:
nasmw -O32 -f coff kernel.asm -o kernel.o
Code:
nasmw -O32 -f coff kernel.asm -o kernel.o
?
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:36:39 18.06.2009   Titel:              Zitieren

Zitat:
nasmw -O32 -f coff kernel.asm -o kernel.o

Nein ich wollte das aktuelle makefile komplett durch dieses ersetzen.

habe folgendes noch geändert:
Code:
.asm.o:
    $(NASM) $(ASFLAGS) $<
Code:
.asm.o:
$(NASM) $(ASFLAGS) $<
Code:
.asm.o:
    $(NASM) $(ASFLAGS) $<

Da stand vorher s.o.:

Zitat:
G:\OSDev\Test\49>make
nasmw -f bin file_data.asm -o file_data.dat
nasmw -O32 -f bin boot.asm -o boot.bin
make -s link
C:\DJGPP\bin/ld.exe: cannot open ckernel.o: No such file or directory (ENOENT)
make.exe[1]: *** [link] Error 1
make.exe: *** [all] Error 2

Ich sehe aber kein kernel.o im Verzeichnis.

Wenn ich das -s(ilent) weg nehme:
Zitat:
G:\OSDev\Test\49>make
nasmw -f bin file_data.asm -o file_data.dat
nasmw -O32 -f bin boot.asm -o boot.bin
make link
make.exe[1]: Entering directory `g:/OSDev/Test/49'
ld -T kernel.ld -Map kernel.map -o ckernel.bin kernel.o ckernel.o isr.o video.o
flush.o gdt.o idt.o isrs.o irq.o util.o math.o timer.o keyboard.o process.o orde
red_array.o paging.o kheap.o descriptor_tables.o task.o fs.o initrd.o syscall.o
C:\DJGPP\bin/ld.exe: cannot open ckernel.o: No such file or directory (ENOENT)
make.exe[1]: *** [link] Error 1
make.exe[1]: Leaving directory `g:/OSDev/Test/49'
make.exe: *** [all] Error 2

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:40:43 18.06.2009, insgesamt 1-mal bearbeitet
Schablone
Mitglied

Benutzerprofil
Anmeldungsdatum: 03.05.2009
Beiträge: 25
Beitrag Schablone Mitglied 23:12:09 18.06.2009   Titel:   Eingeklemmt im Kaktus            Zitieren

+gjm+ schrieb:
Zitat:
ich lade GDT dort auf Anraten nochmals, ...
:confused: Das macht hier keinen Sinn weil gelten würde : "alte GDT == neue GDT". Ausserdem müssten dann die Segmentregister erst wieder mit den Deskriptoren der "neuen" GDT initialisiert werden bevor sie "Wirkung" zeigen.

Der Zweck ist wie gesagt Problemen vorzubeugen, wenn der Bootsektor überschrieben wird, weil die GDT beim LGDT nicht in die CPU geladen wird. Wenn die GDT, die sich außerhalb des Kernels befindet, überschrieben wird, weil die Speicherverwaltung den Bereich, wo der Bootsektor war, als freien Speicher empfinden, knallt es beim Nachladen der Segmentregister.

Das Laden der Segmentregister ist nicht zwingend notwendig, sofern alte und neue GDT den selben Inhalt haben. (Und wenn die Segmentregister nicht aus Versehen mit alten Selektoren geladen werden, ist es auch kein Problem eine neue GDT anzulegen.)

Aber wenn Erhard die guten 32 KByte RAM da unten verrotten lassen will, soll mir recht sein. Hat er ja schließlich für bezahlt. ^^

Erhard Henkes schrieb:
Ich sehe aber kein kernel.o im Verzeichnis.

Weil du kein Target abhängig von den $(SOURCES) gemacht hast. Make weiß nicht, dass die Objektdateien vorher gebaut werden müssen, weil du es ihm nicht gesagt hast.

_________________
Für mehr Kühlschränke!
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 04:20:28 19.06.2009   Titel:              Zitieren

Ich dachte, dieses
Code:
.c.o:
    $(CC) -c $(CFLAGS) -o $@ $<  
Code:
.c.o:
$(CC) -c $(CFLAGS) -o $@ $<
Code:
.c.o:
    $(CC) -c $(CFLAGS) -o $@ $<  

kümmert sich bereits darum. Wenn das nur faul rum hängt, fliegt's raus. :D
.c.o sei auch obsolet, habe ich irgendwo gelesen. Dieses $@ $< finde ich auch irgendwie unlesbaren Mist.

Die sechs Assemblerzeilen schreibe ich nun lieber fix rein, nur mit Variable für Format und Flags.

TARGET des Link-Vorgangs ist für mich ckernel.bin, oder?

So wird brav kompiliert, ich kann den Compiler und die Flags zumindest variabel austauschen und verstehe das makefile noch bestens. Das doppelte Aufführen der Dateinamen muss allerdings noch weg, aber unbedingt leserlich und klar nach vollziehbar.

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# Makefile for PrettyOS

ASFLAGS= -O32 -f coff

TARGET= ckernel.bin
OBJ= kernel.o ckernel.o isr.o video.o flush.o gdt.o    \
        idt.o isrs.o irq.o util.o math.o timer.o keyboard.o \
        process.o ordered_array.o paging.o kheap.o descriptor_tables.o \
        task.o fs.o initrd.o syscall.o
       
LDFLAGS= -T kernel.ld -Map kernel.map
LD= ld

CFLAGS=    -Wall -O          
CC= gcc

all:
    nasmw      -f bin file_data.asm -o file_data.dat
    nasmw -O32 -f bin boot.asm -o boot.bin  
    nasmw $(ASFLAGS) kernel.asm -o kernel.o
    nasmw $(ASFLAGS) isr.asm -o isr.o
    nasmw $(ASFLAGS) process.asm -o process.o
    nasmw $(ASFLAGS) flush.asm -o flush.o
    make compile
    make link
    make image   

compile:   
    $(CC)  $(CFLAGS)  -c ckernel.c -o ckernel.o    
    $(CC)  $(CFLAGS)  -c video.c -o video.o -O1
    $(CC)  $(CFLAGS)  -c math.c -o math.o -O1
    $(CC)        -O   -c util.c -o util.o -O1
    $(CC)  $(CFLAGS)  -c gdt.c -o gdt.o
    $(CC)  $(CFLAGS)  -c idt.c -o idt.o
    $(CC)  $(CFLAGS)  -c isrs.c -o isrs.o   
    $(CC)  $(CFLAGS)  -c irq.c -o irq.o
    $(CC)  $(CFLAGS)  -c timer.c -o timer.o    
    $(CC)  $(CFLAGS)  -c keyboard.c -o keyboard.o
    $(CC)  $(CFLAGS)  -c ordered_array.c -o ordered_array.o
    $(CC)  $(CFLAGS)  -c paging.c -o paging.o
    $(CC)  $(CFLAGS)  -c kheap.c -o kheap.o
    $(CC)  $(CFLAGS)  -c descriptor_tables.c -o descriptor_tables.o
    $(CC)  $(CFLAGS)  -c task.c -o task.o
    $(CC)  $(CFLAGS)  -c fs.c -o fs.o
    $(CC)  $(CFLAGS)  -c initrd.c -o initrd.o  
    $(CC)  $(CFLAGS)  -c syscall.c -o syscall.o
     
link:
    $(LD) $(LDFLAGS) -o $(TARGET) $(OBJ)

image:
    cmd /c copy /b boot.bin + ckernel.bin MyOS    
    del *.coff
    del *.o
    del *.bin
    cmd /c rename MyOS MyOS.bin
    del MyOS
   
    partcopy MyOS.bin 0 7000 -f0                   
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# Makefile for PrettyOS

ASFLAGS= -O32 -f coff

TARGET= ckernel.bin
OBJ= kernel.o ckernel.o isr.o video.o flush.o gdt.o \
idt.o isrs.o irq.o util.o math.o timer.o keyboard.o \
process.o ordered_array.o paging.o kheap.o descriptor_tables.o \
task.o fs.o initrd.o syscall.o

LDFLAGS= -T kernel.ld -Map kernel.map
LD= ld

CFLAGS= -Wall -O
CC= gcc

all:
nasmw -f bin file_data.asm -o file_data.dat
nasmw -O32 -f bin boot.asm -o boot.bin
nasmw $(ASFLAGS) kernel.asm -o kernel.o
nasmw $(ASFLAGS) isr.asm -o isr.o
nasmw $(ASFLAGS) process.asm -o process.o
nasmw $(ASFLAGS) flush.asm -o flush.o
make compile
make link
make image

compile:
$(CC) $(CFLAGS) -c ckernel.c -o ckernel.o
$(CC) $(CFLAGS) -c video.c -o video.o -O1
$(CC) $(CFLAGS) -c math.c -o math.o -O1
$(CC) -O -c util.c -o util.o -O1
$(CC) $(CFLAGS) -c gdt.c -o gdt.o
$(CC) $(CFLAGS) -c idt.c -o idt.o
$(CC) $(CFLAGS) -c isrs.c -o isrs.o
$(CC) $(CFLAGS) -c irq.c -o irq.o
$(CC) $(CFLAGS) -c timer.c -o timer.o
$(CC) $(CFLAGS) -c keyboard.c -o keyboard.o
$(CC) $(CFLAGS) -c ordered_array.c -o ordered_array.o
$(CC) $(CFLAGS) -c paging.c -o paging.o
$(CC) $(CFLAGS) -c kheap.c -o kheap.o
$(CC) $(CFLAGS) -c descriptor_tables.c -o descriptor_tables.o
$(CC) $(CFLAGS) -c task.c -o task.o
$(CC) $(CFLAGS) -c fs.c -o fs.o
$(CC) $(CFLAGS) -c initrd.c -o initrd.o
$(CC) $(CFLAGS) -c syscall.c -o syscall.o

link:
$(LD) $(LDFLAGS) -o $(TARGET) $(OBJ)

image:
cmd /c copy /b boot.bin + ckernel.bin MyOS
del *.coff
del *.o
del *.bin
cmd /c rename MyOS MyOS.bin
del MyOS

partcopy MyOS.bin 0 7000 -f0
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# Makefile for PrettyOS

ASFLAGS= -O32 -f coff

TARGET= ckernel.bin
OBJ= kernel.o ckernel.o isr.o video.o flush.o gdt.o    \
        idt.o isrs.o irq.o util.o math.o timer.o keyboard.o \
        process.o ordered_array.o paging.o kheap.o descriptor_tables.o \
        task.o fs.o initrd.o syscall.o
       
LDFLAGS= -T kernel.ld -Map kernel.map
LD= ld

CFLAGS=    -Wall -O          
CC= gcc

all:
    nasmw      -f bin file_data.asm -o file_data.dat
    nasmw -O32 -f bin boot.asm -o boot.bin  
    nasmw $(ASFLAGS) kernel.asm -o kernel.o
    nasmw $(ASFLAGS) isr.asm -o isr.o
    nasmw $(ASFLAGS) process.asm -o process.o
    nasmw $(ASFLAGS) flush.asm -o flush.o
    make compile
    make link
    make image   

compile:   
    $(CC)  $(CFLAGS)  -c ckernel.c -o ckernel.o    
    $(CC)  $(CFLAGS)  -c video.c -o video.o -O1
    $(CC)  $(CFLAGS)  -c math.c -o math.o -O1
    $(CC)        -O   -c util.c -o util.o -O1
    $(CC)  $(CFLAGS)  -c gdt.c -o gdt.o
    $(CC)  $(CFLAGS)  -c idt.c -o idt.o
    $(CC)  $(CFLAGS)  -c isrs.c -o isrs.o   
    $(CC)  $(CFLAGS)  -c irq.c -o irq.o
    $(CC)  $(CFLAGS)  -c timer.c -o timer.o    
    $(CC)  $(CFLAGS)  -c keyboard.c -o keyboard.o
    $(CC)  $(CFLAGS)  -c ordered_array.c -o ordered_array.o
    $(CC)  $(CFLAGS)  -c paging.c -o paging.o
    $(CC)  $(CFLAGS)  -c kheap.c -o kheap.o
    $(CC)  $(CFLAGS)  -c descriptor_tables.c -o descriptor_tables.o
    $(CC)  $(CFLAGS)  -c task.c -o task.o
    $(CC)  $(CFLAGS)  -c fs.c -o fs.o
    $(CC)  $(CFLAGS)  -c initrd.c -o initrd.o  
    $(CC)  $(CFLAGS)  -c syscall.c -o syscall.o
     
link:
    $(LD) $(LDFLAGS) -o $(TARGET) $(OBJ)

image:
    cmd /c copy /b boot.bin + ckernel.bin MyOS    
    del *.coff
    del *.o
    del *.bin
    cmd /c rename MyOS MyOS.bin
    del MyOS
   
    partcopy MyOS.bin 0 7000 -f0                   


Wie kann ich diesen Teil mit "compile:" allgemein ablaufen lassen analog dem Linker-Befehl? Da die o alle aus c kommen, sollte das gehen.

Sollte man die o (OBJECTS) oder die c (SOURCES, wie unten stehend) auflisten? Ich habe das mit den obj-Dateien bevorzugt, also den Linker-Vorgang in den Mittelpunkt gerückt, weil ja auch obj-Dateien von NASM zu verarbeiten sind.

Bei makefiles stehe ich immer grundsätzlich auf dem Schlauch, weil jedes Vorbild anders aussieht und die Tutorials absolut nix taugen, weil diese keine klare Linie vorgeben. Vielleicht gibt es auch einfach keine. :D

So in etwa findet man es z.B. (Bsp. mit C++, mit diesem obsolet-Stil .cpp.o, den Linker finde ich dort z.B. nicht, Compile- und Link-Vorgang verquickt, irgendwie viel unverständliches Zeugs, die letzte Zeile habe ich ja oben gerade gekillt, weil sie noch nicht gearbeitet hat, lag da nur so rum, ich habe sie aber verstanden trotz wildcards):
Zitat:
CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=main.cpp hello.cpp factorial.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=hello

all: $(SOURCES) $(EXECUTABLE)

$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $@

.cpp.o:
$(CC) $(CFLAGS) $< -o $@

Am schlimmsten finde ich so etwas "SOURCES:.cpp=.o" mit diesem Doppelpunkt.
Vielleicht kann mir da jemand auf die Sprünge helfen. Ich finde es gut, wenn Compile- und Link-Vorgang getrennt dargestellt werden, weil dies bei einem OS wichtig ist.

So etwas wie
$(CC) $(CFLAGS) -c $(SOURCES) -o $(OBJECTS)
wäre gut verständlich. Dann müsste man aber die c-Dateien noch allgemein als Sources angeben. Habe dies probiert, hat aber nicht geklappt. Vielleicht kann jemand meine Idee doch noch zum Laufen bringen:
Zitat:
# Makefile for PrettyOS

# Assemble
ASFLAGS= -O32 -f coff

# Compile
SOURCES= ???.c
CFLAGS= -Wall -O
CC= gcc

# Link
OBJ= kernel.o ckernel.o isr.o video.o flush.o gdt.o \
idt.o isrs.o irq.o util.o math.o timer.o keyboard.o \
process.o ordered_array.o paging.o kheap.o descriptor_tables.o \
task.o fs.o initrd.o syscall.o
TARGET= ckernel.bin
LDFLAGS= -T kernel.ld -Map kernel.map
LD= ld

all:
nasmw -f bin file_data.asm -o file_data.dat
nasmw -O32 -f bin boot.asm -o boot.bin
nasmw $(ASFLAGS) kernel.asm -o kernel.o
nasmw $(ASFLAGS) isr.asm -o isr.o
nasmw $(ASFLAGS) process.asm -o process.o
nasmw $(ASFLAGS) flush.asm -o flush.o
make compile
make link
make image

compile:
??? #Idee: $(CC) $(CFLAGS) -c $(SOURCES) -o $(OBJECTS)

link:
$(LD) $(LDFLAGS) -o $(TARGET) $(OBJ)

image:
cmd /c copy /b boot.bin + ckernel.bin MyOS
del *.o
del *.bin
cmd /c rename MyOS MyOS.bin
partcopy MyOS.bin 0 7000 -f0

c.o.:
$(CC) -c $(CFLAGS) -o $@ $<

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:44:05 20.06.2009, insgesamt 25-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 06:17:03 19.06.2009   Titel:              Zitieren

Zitat:
Aber wenn Erhard die guten 32 KByte RAM da unten verrotten lassen will, soll mir recht sein. Hat er ja schließlich für bezahlt. ^^

Ja, aber man muss ja auch andere denken. :) Der Speicher bis 0x00008000 sollte nach dem Boot-Vorgang schon wieder genutzt werden können, aber irgendwo muss das GDT ja dann liegen, z.B. nach dem Kernel-Ende:

Das gute PrettyOS hat das ja alles schon im C-Kernel eingebaut, wenn ich das richtig sehe, und das wird in main() nach Bildschirmlöschen und Begrüßen umgehend installiert:

flush.asm (siehe lgdt [...] )
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
section .text

; flush.asm -- contains global descriptor table and interrupt descriptor table setup code

GLOBAL _gdt_flush    ; Allows the C code to call gdt_flush().

_gdt_flush:
    mov eax, [esp+4]  ; Get the pointer to the GDT, passed as a parameter.
    lgdt [eax]        ; Load the new GDT register

    mov ax, 0x10      ; 0x10 is the offset in the GDT to our data segment
    mov ds, ax        ; Load all data segment selectors
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    jmp 0x08:.flush   ; 0x08 is the offset to our code segment: Far jump!
.flush:
    ret

GLOBAL _idt_flush    ; Allows the C code to call idt_flush().

_idt_flush:
    mov eax, [esp+4]  ; Get the pointer to the IDT, passed as a parameter.
    lidt [eax]        ; Load the IDT register
    ret

GLOBAL _tss_flush    ; Allows our C code to call tss_flush().

_tss_flush:
   mov ax, 0x2B      ; Load the index of our TSS structure - The index is
                     ; 0x28, as it is the 5th selector and each is 8 bytes
                     ; long, but we set the bottom two bits (making 0x2B)
                     ; so that it has an RPL of 3, not zero.
   ltr ax            ; Load 0x2B into the task state register.
   ret
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
section .text

; flush.asm -- contains global descriptor table and interrupt descriptor table setup code

GLOBAL _gdt_flush ; Allows the C code to call gdt_flush().

_gdt_flush:
mov eax, [esp+4] ; Get the pointer to the GDT, passed as a parameter.
lgdt [eax] ; Load the new GDT register

mov ax, 0x10 ; 0x10 is the offset in the GDT to our data segment
mov ds, ax ; Load all data segment selectors
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:.flush ; 0x08 is the offset to our code segment: Far jump!
.flush:
ret

GLOBAL _idt_flush ; Allows the C code to call idt_flush().

_idt_flush:
mov eax, [esp+4] ; Get the pointer to the IDT, passed as a parameter.
lidt [eax] ; Load the IDT register
ret

GLOBAL _tss_flush ; Allows our C code to call tss_flush().

_tss_flush:
mov ax, 0x2B ; Load the index of our TSS structure - The index is
; 0x28, as it is the 5th selector and each is 8 bytes
; long, but we set the bottom two bits (making 0x2B)
; so that it has an RPL of 3, not zero.
ltr ax ; Load 0x2B into the task state register.
ret
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
section .text

; flush.asm -- contains global descriptor table and interrupt descriptor table setup code

GLOBAL _gdt_flush    ; Allows the C code to call gdt_flush().

_gdt_flush:
    mov eax, [esp+4]  ; Get the pointer to the GDT, passed as a parameter.
    lgdt [eax]        ; Load the new GDT register

    mov ax, 0x10      ; 0x10 is the offset in the GDT to our data segment
    mov ds, ax        ; Load all data segment selectors
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    jmp 0x08:.flush   ; 0x08 is the offset to our code segment: Far jump!
.flush:
    ret

GLOBAL _idt_flush    ; Allows the C code to call idt_flush().

_idt_flush:
    mov eax, [esp+4]  ; Get the pointer to the IDT, passed as a parameter.
    lidt [eax]        ; Load the IDT register
    ret

GLOBAL _tss_flush    ; Allows our C code to call tss_flush().

_tss_flush:
   mov ax, 0x2B      ; Load the index of our TSS structure - The index is
                     ; 0x28, as it is the 5th selector and each is 8 bytes
                     ; long, but we set the bottom two bits (making 0x2B)
                     ; so that it has an RPL of 3, not zero.
   ltr ax            ; Load 0x2B into the task state register.
   ret


Dieses gdt_flush wird mittels gdt_install in main() aufgerufen:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void gdt_install()
{
    /* Setup the GDT pointer and limit */
    gdt_register.limit = (sizeof(struct gdt_entry) * NUMBER_GDT_GATES)-1;
    gdt_register.base  = (ULONG) &gdt;

    /* GDT GATES -  desriptors with pointers to the linear memory address */
    gdt_set_gate(0, 0, 0, 0, 0);                // NULL descriptor
    gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // CODE, privilege level 0 for kernel code
    gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // DATA, privilege level 0 for kernel code

    #ifdef
KERNELMODE // in os.h
    gdt_set_gate(3, 0, 0xFFFFFFFF, 0x9A, 0xCF); // CODE, privilege level 0 for kernel code
    gdt_set_gate(4, 0, 0xFFFFFFFF, 0x92, 0xCF); // DATA, privilege level 0 for kernel code
    #endif

    #ifdef
USERMODE   // in os.h
    gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User mode code segment
    gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User mode data segment
    #endif


    write_tss(5, 0x10, 0x0);                    // num, ss0, esp0

    gdt_flush((ULONG)&gdt_register); // inclusive gdt_load() in assembler code
    tss_flush();                     //in flush.asm: privilege level 3 for kernel mode 0x2B
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void gdt_install()
{
/* Setup the GDT pointer and limit */
gdt_register.limit = (sizeof(struct gdt_entry) * NUMBER_GDT_GATES)-1;
gdt_register.base = (ULONG) &gdt;

/* GDT GATES - desriptors with pointers to the linear memory address */
gdt_set_gate(0, 0, 0, 0, 0); // NULL descriptor
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // CODE, privilege level 0 for kernel code
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // DATA, privilege level 0 for kernel code

#ifdef
KERNELMODE // in os.h
gdt_set_gate(3, 0, 0xFFFFFFFF, 0x9A, 0xCF); // CODE, privilege level 0 for kernel code
gdt_set_gate(4, 0, 0xFFFFFFFF, 0x92, 0xCF); // DATA, privilege level 0 for kernel code
#endif

#ifdef
USERMODE // in os.h
gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User mode code segment
gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User mode data segment
#endif


write_tss(5, 0x10, 0x0); // num, ss0, esp0

gdt_flush((ULONG)&gdt_register); // inclusive gdt_load() in assembler code
tss_flush(); //in flush.asm: privilege level 3 for kernel mode 0x2B
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void gdt_install()
{
    /* Setup the GDT pointer and limit */
    gdt_register.limit = (sizeof(struct gdt_entry) * NUMBER_GDT_GATES)-1;
    gdt_register.base  = (ULONG) &gdt;

    /* GDT GATES -  desriptors with pointers to the linear memory address */
    gdt_set_gate(0, 0, 0, 0, 0);                // NULL descriptor
    gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // CODE, privilege level 0 for kernel code
    gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // DATA, privilege level 0 for kernel code

    #ifdef
KERNELMODE // in os.h
    gdt_set_gate(3, 0, 0xFFFFFFFF, 0x9A, 0xCF); // CODE, privilege level 0 for kernel code
    gdt_set_gate(4, 0, 0xFFFFFFFF, 0x92, 0xCF); // DATA, privilege level 0 for kernel code
    #endif

    #ifdef
USERMODE   // in os.h
    gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User mode code segment
    gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User mode data segment
    #endif


    write_tss(5, 0x10, 0x0);                    // num, ss0, esp0

    gdt_flush((ULONG)&gdt_register); // inclusive gdt_load() in assembler code
    tss_flush();                     //in flush.asm: privilege level 3 for kernel mode 0x2B
}


C/C++ Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
int main()
{
    k_clear_screen();
    printformat("Welcome to PrettyOS ... \n");
    // GDT, IDT, ISRS, IRQ, timer, keyboard, paging, interrupts, multitasking
    gdt_install();
//...
}
C/C++ Code:
1
2
3
4
5
6
7
8
int main()
{
k_clear_screen();
printformat("Welcome to PrettyOS ... \n");
// GDT, IDT, ISRS, IRQ, timer, keyboard, paging, interrupts, multitasking
gdt_install();
//...
}
C/C++ Code:
1
2
3
4
5
6
7
8
int main()
{
    k_clear_screen();
    printformat("Welcome to PrettyOS ... \n");
    // GDT, IDT, ISRS, IRQ, timer, keyboard, paging, interrupts, multitasking
    gdt_install();
//...
}

Ist das so o.k.? Die GDT sitzt dann bei der Adresse &gdt. Ich habe zur Kontrolle ein printformat eingebaut:
Zitat:
Welcome to PrettyOS ...
gdt: 0000D480h

Den Verschwendungsvorwurf kann ich so nicht auf mir sitzen lassen. ;) :D

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:29:07 19.06.2009, insgesamt 4-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:31:40 20.06.2009   Titel:              Zitieren

Bezüglich makefile bin ich nun komplett umgeschwenkt und verwende Folgendes:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
SOURCES = kernel.asm $(filter-out file_data.asm boot.asm kernel.asm make_initrd.c,$(wildcard *.asm *.c))
OBJECTS = $(addsuffix .o,$(basename $(SOURCES)))

ASFLAGSBIN= -O32 -f bin
ASFLAGSCOFF= -O32 -f coff
NASM = nasmw

CFLAGS= -Wall -O          
CC= gcc

LDFLAGS= -T kernel.ld -Map kernel.map
LD= ld

all: boot.bin ckernel.bin
    make -s image
    make -s floppyimage

process.asm: file_data.dat file_data.da1

file_data.dat: file_data.asm
    $(NASM) $(ASFLAGSBIN) $< -o $@

boot.bin: boot.asm
    $(NASM) $(ASFLAGSBIN) $< -o $@

%.o: %.asm
    $(NASM) $(ASFLAGSCOFF) $< -o $@

ckernel.bin: $(OBJECTS)
    $(LD) $(LDFLAGS) $+ -o $@
   
image:
    cmd /c copy /b boot.bin + ckernel.bin MyOS    
    del *.o
    del *.bin
    cmd /c rename MyOS MyOS.bin

floppyimage:   
    partcopy MyOS.bin 0 7000 -f0   

# $<    Erste Abhängigkeit
# $@    Name des Targets
# $+    Liste aller Abhängigkeiten
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
SOURCES = kernel.asm $(filter-out file_data.asm boot.asm kernel.asm make_initrd.c,$(wildcard *.asm *.c))
OBJECTS = $(addsuffix .o,$(basename $(SOURCES)))

ASFLAGSBIN= -O32 -f bin
ASFLAGSCOFF= -O32 -f coff
NASM = nasmw

CFLAGS= -Wall -O
CC= gcc

LDFLAGS= -T kernel.ld -Map kernel.map
LD= ld

all: boot.bin ckernel.bin
make -s image
make -s floppyimage

process.asm: file_data.dat file_data.da1

file_data.dat: file_data.asm
$(NASM) $(ASFLAGSBIN) $< -o $@

boot.bin: boot.asm
$(NASM) $(ASFLAGSBIN) $< -o $@

%.o: %.asm
$(NASM) $(ASFLAGSCOFF) $< -o $@

ckernel.bin: $(OBJECTS)
$(LD) $(LDFLAGS) $+ -o $@

image:
cmd /c copy /b boot.bin + ckernel.bin MyOS
del *.o
del *.bin
cmd /c rename MyOS MyOS.bin

floppyimage:
partcopy MyOS.bin 0 7000 -f0

# $< Erste Abhängigkeit
# $@ Name des Targets
# $+ Liste aller Abhängigkeiten
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
SOURCES = kernel.asm $(filter-out file_data.asm boot.asm kernel.asm make_initrd.c,$(wildcard *.asm *.c))
OBJECTS = $(addsuffix .o,$(basename $(SOURCES)))

ASFLAGSBIN= -O32 -f bin
ASFLAGSCOFF= -O32 -f coff
NASM = nasmw

CFLAGS= -Wall -O          
CC= gcc

LDFLAGS= -T kernel.ld -Map kernel.map
LD= ld

all: boot.bin ckernel.bin
    make -s image
    make -s floppyimage

process.asm: file_data.dat file_data.da1

file_data.dat: file_data.asm
    $(NASM) $(ASFLAGSBIN) $< -o $@

boot.bin: boot.asm
    $(NASM) $(ASFLAGSBIN) $< -o $@

%.o: %.asm
    $(NASM) $(ASFLAGSCOFF) $< -o $@

ckernel.bin: $(OBJECTS)
    $(LD) $(LDFLAGS) $+ -o $@
   
image:
    cmd /c copy /b boot.bin + ckernel.bin MyOS    
    del *.o
    del *.bin
    cmd /c rename MyOS MyOS.bin

floppyimage:   
    partcopy MyOS.bin 0 7000 -f0   

# $<    Erste Abhängigkeit
# $@    Name des Targets
# $+    Liste aller Abhängigkeiten

Trotz Verwendung von $<, $+ und $@ finde ich diesen ziel- bzw. abhängigkeitsbezogenen Stil ebenfalls gut nachvollziehbar.
Ich bin immer wieder verblüfft über die vielfältigen Möglichkeiten, die diese Makefile-Syntax bietet. :D

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 09:39:06 20.06.2009, insgesamt 4-mal bearbeitet
Bitsy
Mitglied

Benutzerprofil
Anmeldungsdatum: 01.05.2001
Beiträge: 499
Beitrag Bitsy Mitglied 11:54:40 21.06.2009   Titel:              Zitieren

Von den vielfältigen Möglichkeiten abgesehen, die man in 20 Jahren nicht mal genutzt hat - und die noch vielfältigeren, die man noch gar nicht kennt. ;)
Und bei den ganzen Tools, die in einem Compilerpaket immer dabei sind, fehlt mir immer noch eines, was komplexe zeilenübergreifende Ersetzungen mit Berücksichtigung von Klammerebenen erlaubt. Reguläre Ausdrücke sind viel zu schwach. Aber das wäre ein anderes Projekt ;)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 13:18:54 21.06.2009   Titel:              Zitieren

Da das Verständnis für das Thema (Virtual) Filesystem/Files (Filesystem-Header, File-Header) wichtig ist, habe ich am Beispiel der RAM Disk manuell (mit dem Hex-Editor, damit man mitdenken und abzählen muss, was man macht) ein viertes File (nämlich genau unser winziges 29-Byte-TEST-Programm) in das Filesystem "eingeklinkt". Die Daten werden via Filesystem (Zahl 4 im Filesystem-Header zeigt 4 Files an, File-Header zeigt Name, Offset und Länge an, allerdings nicht Filetyp oder anderes, alos noch sehr primitiv, aber es geht ja noch ums Prinzip) gefunden, in ein lokales Array auf dem Stack gelesen, zur Sicherung an eine neue Stelle in ein globales Array (address_TEST in der Sektion bss; da überlege ich noch, was eigentlich der beste Platz ist) transferiert, im Prozess 'test' als Funktion aufgerufen und ausgeführt.

Damit wurde nun genau genommen ein (zugegebenermaßen kleines) Programm "von Disk geladen" und in Multitasking "ausgeführt". Das Grundprinzip funktioniert aber auch im User-Bereich mit Datenbereich, Stack, User-Lib etc. gleich.

http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId216641
http://www.henkessoft.de/OS_Dev/Downloads/20090621_36x_load_file_TEST.zip

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 16:09:02 21.06.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 03:04:30 24.06.2009   Titel:              Zitieren

Das Thema user mode und syscalls habe ich hier beschrieben:
http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId338709

Ich verzichte bei Systemaufrufen auf einen Task-Wechsel und verwende den fault_handler (exceptions) und syscall_handler zum Aufruf der gewünschten Kernel-Funktion. Die Assemblerroutine kümmert sich um den korrekten Kontextwechsel von Ring 3 nach Ring 0 und zurück.
http://www.henkessoft.de/OS_Dev/Bilder/syscall.PNG

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 03:05:18 24.06.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:49:24 24.06.2009   Titel:              Zitieren

Ein ganz wichtiger Punkt ist nun der Einsatz eines Cross-Compilers/-Linkers, der vor allem auch das ELF-Format erlaubt, das man für andere Hobby-OS und später für User-Programme benötigt. Man benötigt allerdings auch ein brauchbares make-Tool, das alle Anforderungen erfüllt, findet man nun alles hier, natürlich alles einfach und übersichtlich nachzuvollziehen:
http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId42018

Wichtig ist, dass man nun aus Assembler-Quellcode leicht elf-object- und mittels des linkers der cross-compiler-tools daraus elf-executable-Dateien herstellen kann. Es ist nun die nächste Aufgabe diese elf-Programme seitens Pretty-OS im "user space" zum Laufen zu bringen. Dann kann man zur Zeit mittels incbin und Einbinden in die RAM Disk Programme im VFS "loadable" zur Verfügung stellen.
Dort sollte z.B. später die Programme

init,
vielleicht noch einge Treiber
und eine shell

stehen. Das wäre dann eine interessante Aufgabe für das Assembler-Forum, solche kleinen Programme in Assembler zu erstellen.

nasm(w) -felf -o file.o file.asm
i586-elf-ld -T user.ld -nostdinc -o program.elf file.o

user.ld:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ENTRY(_start)
OUTPUT_FORMAT(elf32-i386)
 
SECTIONS
{
    . = 0x400100;
   
    .text :
    {
      *(.text*)
    }
    .data :
    {
      *(.data*)
      *(.rodata*)
    }
    .bss :
    {
      *(.bss*)
    }
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ENTRY(_start)
OUTPUT_FORMAT(elf32-i386)

SECTIONS
{
. = 0x400100;

.text :
{
*(.text*)
}
.data :
{
*(.data*)
*(.rodata*)
}
.bss :
{
*(.bss*)
}
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ENTRY(_start)
OUTPUT_FORMAT(elf32-i386)
 
SECTIONS
{
    . = 0x400100;
   
    .text :
    {
      *(.text*)
    }
    .data :
    {
      *(.data*)
      *(.rodata*)
    }
    .bss :
    {
      *(.bss*)
    }
}


Setzt man kein Linkerscript ein

i586-elf-ld -nostdinc -o program.elf file.o

so ergibt sich die default Adresse: 0x08048000 + program_offset
http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId95189

Kann jemand erklären, warum gerade diese Adresse verwendet wird?

Mit Einsatz der Cross-Tools ist das Thema Linux und GRUB damit vorerst vom Tisch, wie gewünscht. :)

Nächstes kapitel wird richtiger user mode, denn bisher wurde der kernel als user mode / read-only eingesetzt (ein Erbe von JM's Tut.)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:11:25 28.06.2009, insgesamt 8-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:25:57 03.07.2009   Titel:              Zitieren

User-Land macht Fortschritte. User-Programme werden momentan noch via incbin in die RAM Disk geladen, dort mit VFS gefunden und in den User-Page-Bereich geschoben. Dort greifen sie via syscalls (int 0x7F) auf die in syscall.h/.c freigegebenen Kernel-Funktionen zu.

Linkerscript user.ld:
Code:
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
ENTRY(_start)
OUTPUT_FORMAT(elf32-i386)
SECTIONS
{
    . = 0x400100;
    .text : { *(.text*)             }
    .data : { *(.data*) *(.rodata*) }
    .bss :  { *(.bss*)              }
}
Code:
1
2
3
4
5
6
7
8
9
ENTRY(_start)
OUTPUT_FORMAT(elf32-i386)
SECTIONS
{
. = 0x400100;
.text : { *(.text*) }
.data : { *(.data*) *(.rodata*) }
.bss : { *(.bss*) }
}
Code:
1
2
3
4
5
6
7
8
9
ENTRY(_start)
OUTPUT_FORMAT(elf32-i386)
SECTIONS
{
    . = 0x400100;
    .text : { *(.text*)             }
    .data : { *(.data*) *(.rodata*) }
    .bss :  { *(.bss*)              }
}

makefile:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ASFLAGSBIN= -O32 -f bin
ASFLAGSOBJ= -O32 -f elf
NASM = nasmw

CFLAGS=    -O -ffreestanding -fleading-underscore    
CC= i586-elf-gcc

LDFLAGS= -T user.ld -Map kernel.map -nostdinc
LD= i586-elf-ld

all: program.bin program.elf

program.bin: program.asm
    $(NASM) $(ASFLAGSBIN) $< -o $@

program.o: program.asm
    $(NASM) $(ASFLAGSOBJ) $< -o $@

program.elf: program.o
    $(LD) $(LDFLAGS) $+ -o $@

#    $<        Erste Abhängigkeit
#    $+        Liste aller Abhängigkeiten   
#    $@        Name des Targets
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ASFLAGSBIN= -O32 -f bin
ASFLAGSOBJ= -O32 -f elf
NASM = nasmw

CFLAGS= -O -ffreestanding -fleading-underscore
CC= i586-elf-gcc

LDFLAGS= -T user.ld -Map kernel.map -nostdinc
LD= i586-elf-ld

all: program.bin program.elf

program.bin: program.asm
$(NASM) $(ASFLAGSBIN) $< -o $@

program.o: program.asm
$(NASM) $(ASFLAGSOBJ) $< -o $@

program.elf: program.o
$(LD) $(LDFLAGS) $+ -o $@

# $< Erste Abhängigkeit
# $+ Liste aller Abhängigkeiten
# $@ Name des Targets
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ASFLAGSBIN= -O32 -f bin
ASFLAGSOBJ= -O32 -f elf
NASM = nasmw

CFLAGS=    -O -ffreestanding -fleading-underscore    
CC= i586-elf-gcc

LDFLAGS= -T user.ld -Map kernel.map -nostdinc
LD= i586-elf-ld

all: program.bin program.elf

program.bin: program.asm
    $(NASM) $(ASFLAGSBIN) $< -o $@

program.o: program.asm
    $(NASM) $(ASFLAGSOBJ) $< -o $@

program.elf: program.o
    $(LD) $(LDFLAGS) $+ -o $@

#    $<        Erste Abhängigkeit
#    $+        Liste aller Abhängigkeiten   
#    $@        Name des Targets


Erste kleine User-Beispiel-Programme:
Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
[BITS 32]
start:
   mov [0x000b8000], byte 'T'
   mov [0x000b8002], byte 'e'
   mov [0x000b8004], byte 's'
   mov [0x000b8006], byte 't'
   mov [0x000b8008], byte ' '
   mov eax, 4
   int 0x7F
   jmp start
Code:
1
2
3
4
5
6
7
8
9
10
[BITS 32]
start:
mov [0x000b8000], byte 'T'
mov [0x000b8002], byte 'e'
mov [0x000b8004], byte 's'
mov [0x000b8006], byte 't'
mov [0x000b8008], byte ' '
mov eax, 4
int 0x7F
jmp start
Code:
1
2
3
4
5
6
7
8
9
10
[BITS 32]
start:
   mov [0x000b8000], byte 'T'
   mov [0x000b8002], byte 'e'
   mov [0x000b8004], byte 's'
   mov [0x000b8006], byte 't'
   mov [0x000b8008], byte ' '
   mov eax, 4
   int 0x7F
   jmp start


Code:
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
[BITS 32]
start:
   mov ebx, 0x4  ; 1. Argument
   mov ecx, 0x0  ; 2. Argument
   mov eax, 2    ; settextcolor
   int 0x7F
   
   mov ebx, 0x54 ; 'T'
   mov eax, 1    ; putch
   int 0x7F
   
   jmp start
Code:
1
2
3
4
5
6
7
8
9
10
11
12
[BITS 32]
start:
mov ebx, 0x4 ; 1. Argument
mov ecx, 0x0 ; 2. Argument
mov eax, 2 ; settextcolor
int 0x7F

mov ebx, 0x54 ; 'T'
mov eax, 1 ; putch
int 0x7F

jmp start
Code:
1
2
3
4
5
6
7
8
9
10
11
12
[BITS 32]
start:
   mov ebx, 0x4  ; 1. Argument
   mov ecx, 0x0  ; 2. Argument
   mov eax, 2    ; settextcolor
   int 0x7F
   
   mov ebx, 0x54 ; 'T'
   mov eax, 1    ; putch
   int 0x7F
   
   jmp start

Output: http://www.henkessoft.de/OS_Dev/Bilder/userprogram001.PNG

http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId710871 (wird noch ausgebaut)
http://www.henkessoft.de/OS_Dev/Downloads/20090703_61.zip (Download)

Nun gäbe es z.B. folgende Aufgaben:
- elf-exec-Parser
- syscalls systematisch aufbauen
- user-Programme schreiben
- user-lib entwickeln
- user-Programme init und shell schreiben
- Treiber

Hat jemand gute Ideen, was man auf dem jetzigen Stand alles so machen könnte mit kleinen Assembler-Programmen (passt zum Unter-Forum) und dazu passenden Syscalls? :)

Eine Frage ist auch, wie man das Arrangement der Syscalls sinnvoll aufbaut. Vielleicht hat hier jemand eine klare Meinung?

Auf jeden Fall kann man Teil 2 des Tutorials so langsam beenden, denn wesentliche Elemente eines durch einen eigenen Bootloader hochgefahrenen OS auf dem 80x86 wurden bisher konkret gezeigt.

Nun stellt sich die Frage, was man in Teil 3 sinnvoll angehen könnte:
Es kommt bei der Weiterentwicklung von PrettyOS z.B. darauf an, welchen Kernel-Typ man anstrebt. Bei einem monolithischer Kernel umfassen die Syscalls z.B. die POSIX-Funktionen, Win32API bzw. irgendeine eigene API. Dies verlagert die komplette Funktionalität eines Betriebssystems in den Kernel. Beim Mikrokernel-Typ sind die Syscalls vor allem IPC, Speichermanagement und etwas Prozessmanagement. Die IPC stellt die Kommunikation zwischen den Prozessen sicher, um die jeweils benötigtge Funktionalität zu triggern. Der Kernel brennt dann inhaltlich eher auf Sparflamme.
Darüber hinaus könnte man verschiedene Treiber anbieten. Bisher haben wir die Hardware des PC geschont, so dass Ladevorgänge via Emulator oder in einem Rutsch beim Booten von Floppy Disk abliefen.

Falls jemand konkret Lust hat, mich bei (Re-)Design des Kernels, Definition der syscalls und Aufbau der User-Applikations-Landschaft (NASM-Assembler oder nach Aufbau einer API-Lib für die syscalls auch in C) zu unterstützen, da wäre ich nicht abgeneigt. Kein Zeitdruck. Ich denke nicht, dass man das konkrete Development im Forum machen kann. Mein persönliches Ziel (gute Co-Autoren werden akzeptiert): Buch "Betriebssystementwicklung - leicht gemacht" ;)

ICQ: 76194616 :)
http://www.henkessoft.de/OS_Dev/OS_Dev3.htm (development ongoing) :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 17:08:04 04.07.2009, insgesamt 10-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:48:58 04.07.2009   Titel:              Zitieren

Wichtiger Meilenstein:
User-Programme in C mit userlib.h/.c anstelle Assembler-User-Programme. Echt gutes Gefühl, wenn so etwas endlich läuft. :D :live:
Hier sollte sogar C++ möglich sein. ;)

http://www.henkessoft.de/OS_Dev/Downloads/20090705_66.zip

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// userlib.h

#ifndef
USERLIB_H
#define
USERLIB_H

void settextcolor(unsigned int foreground, unsigned int background);
void putch(unsigned char val);

#endif



// userlib.c

#include
"userlib.h"

void settextcolor(unsigned int foreground, unsigned int background)
{
    asm volatile( "int $0x7F" : : "a"(2), "b"(foreground), "c"(background) );
}

void putch(unsigned char val)
{
    asm volatile( "int $0x7F" : : "a"(1), "b"(val) );
}


// program.c

#include
"userlib.h"

int main()
{
  settextcolor(14,1);
  putch('T');
  putch('e');
  putch('s');
  putch('t');
  return 0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// userlib.h

#ifndef
USERLIB_H
#define
USERLIB_H

void settextcolor(unsigned int foreground, unsigned int background);
void putch(unsigned char val);

#endif



// userlib.c

#include
"userlib.h"

void settextcolor(unsigned int foreground, unsigned int background)
{
asm volatile( "int $0x7F" : : "a"(2), "b"(foreground), "c"(background) );
}

void putch(unsigned char val)
{
asm volatile( "int $0x7F" : : "a"(1), "b"(val) );
}


// program.c

#include
"userlib.h"

int main()
{
settextcolor(14,1);
putch('T');
putch('e');
putch('s');
putch('t');
return 0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// userlib.h

#ifndef
USERLIB_H
#define
USERLIB_H

void settextcolor(unsigned int foreground, unsigned int background);
void putch(unsigned char val);

#endif



// userlib.c

#include
"userlib.h"

void settextcolor(unsigned int foreground, unsigned int background)
{
    asm volatile( "int $0x7F" : : "a"(2), "b"(foreground), "c"(background) );
}

void putch(unsigned char val)
{
    asm volatile( "int $0x7F" : : "a"(1), "b"(val) );
}


// program.c

#include
"userlib.h"

int main()
{
  settextcolor(14,1);
  putch('T');
  putch('e');
  putch('s');
  putch('t');
  return 0;
}

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 11:43:32 05.07.2009, insgesamt 5-mal bearbeitet
killerkirsche
Mitglied

Benutzerprofil
Anmeldungsdatum: 10.07.2009
Beiträge: 5
Beitrag killerkirsche Mitglied 16:29:57 10.07.2009   Titel:              Zitieren

Mit was für einem Dateisystem arbeitest du?
bzw. hast du schon eins?
Hobby Programmierer
Mitglied

Benutzerprofil
Anmeldungsdatum: 15.03.2009
Beiträge: 75
Beitrag Hobby Programmierer Mitglied 17:19:45 10.07.2009   Titel:              Zitieren

Wenn du dur mal das Tut zum OS ansehen würdest, oder dir das OS ansiehst, würdest du feststellen, dass dort noch gar kein Festplattenzugriff ist.


Zuletzt bearbeitet von Hobby Programmierer am 17:20:07 10.07.2009, insgesamt 1-mal bearbeitet
killerkirsche
Mitglied

Benutzerprofil
Anmeldungsdatum: 10.07.2009
Beiträge: 5
Beitrag killerkirsche Mitglied 17:30:48 10.07.2009   Titel:              Zitieren

Ich meine gar keinen Festplatten sondern Diskettenzugriff.
Außerdem kann es ja sein, dass schon etwas ins Auge gefasst wurde.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:26:43 10.07.2009   Titel:              Zitieren

Zitat:
Mit was für einem Dateisystem arbeitest du? bzw. hast du schon eins?

Bei User-Programmen wird mit dem ELF-executable-Format gearbeitet. In der RAM disk wird ein von James Molloy selbst gestricktes Format eingesetzt (Quellcode für Erzeuger-Programm liegt bei). Bezüglich der "Datenträger" weiß ich noch nicht wie ich vorgehen soll. Diskettenlaufwerke sind sicher nicht mehr der Hit und an vielen PCs nicht mehr vorhanden. Alle Programme werden bisher via "incbin" innerhalb initrd.img in den Kernel transportiert und dort über das VFS und selbst gestrickte Dateisystem gefunden und "geladen".

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
killerkirsche
Mitglied

Benutzerprofil
Anmeldungsdatum: 10.07.2009
Beiträge: 5
Beitrag killerkirsche Mitglied 11:01:41 11.07.2009   Titel:              Zitieren

Ah ok.
Das hilft mir doch schonmal weiter.
Da ich nicht denke, das Diskettenlaufwerke untergehen sollten und da mein OS die Massen nicht interessieren wird, habe ich ein ext2-System auf der Floppy mit dem OS.
Ich hab gehofft du benutzt das auch und wüsstest einen Treiber dafür.
Aber scheint ja nicht der Fall zu sein.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:09:52 11.07.2009   Titel:              Zitieren

Zitat:
Da ich nicht denke, das Diskettenlaufwerke untergehen sollten

Da stehst Du wohl nicht völlig alleine da mit dieser Meinung, aber aufhalten kann den Niedergang niemand mehr. Das Ende der drehenden Scheiben ist nahe.

Zitat:
ext2-System auf der Floppy mit dem OS

Da ich MS Windows als Host-System mit Cross-Compiler/-Linker für die OS-Entwicklung verwende, wollte ich mich - wenn überhaupt - eher auf ELF und FAT konzentrieren.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 10:57:42 12.07.2009   Titel:              Zitieren

Die bisherige Begrenzung für den Kernel im Bootloader ist endlich gefallen:
http://www.henkessoft.de/OS_Dev/OS_Dev3.htm#mozTocId882541

Der Bootloader und zugehörige Aufgaben vor dem Start der C-Datei ist bisher noch ein gehöriger Schwachpunkt. Die Ratschläge, endlich GRUB einzusetzen, verstummen nicht.

Musste allerdings noch die bss section nullen, das hat noch gefehlt.
Ich könnte echt einen BIOS / Bootloader / ... -Spezialisten brauchen.

Instabiler Code, der auf mehreren PCs getestet wurde und in einigen Fällen zu "Datenverlusten" in der RAM Disk führte, was dann teilweise #PF oder fehlendes User-Programm zur Folge hatte.
http://www.henkessoft.de/OS_Dev/Downloads/20090720_83.zip
(Fehler in fs.h/fs.c muss noch exakt lokalisiert und behoben/abgefangen werden)

Da das Problem eindeutig in dem verwendeten Code von James Molloy für VFS/RAM Disk liegt, wurde das in nachfoglendem Code einfach umgangen:
Hier ist ein stabiler Code, der VFS umgeht, solange der Fehler nicht exakt lokalisiert und behoben wurde: http://www.henkessoft.de/OS_Dev/Downloads/85.zip :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 10:45:10 23.07.2009, insgesamt 8-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:50:28 23.07.2009   Titel:              Zitieren

Ich möchte auf eine hervorragende, bisher 20-teilige Serie (BrokenThorn Entertainment, "Mike") aufmerksam machen: http://www.brokenthorn.com/Resources/OSDev1.html
(didaktisch wirklich gut, da von Grund auf mit eigenem Bootloader und FAT12 System gearbeitet wird; leider noch einige kleine Fehler enthalten, Author wurde von mir über diese informiert)

Zitat:
Ich hab gehofft du benutzt das auch und wüsstest einen Treiber dafür.
Vielleicht sind die ersten Teile des obigen Tutorials für Dich das richtige, verwendet allerdings FAT12 anstelle ext2.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 11:43:05 24.07.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:38:55 24.07.2009   Titel:              Zitieren

Das Thema Analyse des physikalischen Speichers wurde nun auch erfolgreich umgesetzt: http://www.henkessoft.de/OS_Dev/OS_Dev3.htm#mozTocId584885
Allerdings haben wir mit int 15h eax = 820h die 80er verlassen und sind auf neuere Zeiten (spätestens ab 2002, funktioniert aber vielfach bereits bei früheren PCs) umgestiegen. ;)

Der Bootloader ist nun allerdings voll gestopft. Platz für FAT12 ist dort nun nicht. Wir verwenden ja noch "raw format". Die Frage ist, ob man sich überhaupt noch Gedanken über Floppy Disk machen soll.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 11:40:35 24.07.2009, insgesamt 1-mal bearbeitet
supertux
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.07.2004
Beiträge: 3351
Beitrag supertux Mitglied 00:12:24 25.07.2009   Titel:   Re: Eigenes OS?            Zitieren

Erhard Henkes schrieb:
Mich würde mal interessieren, wer alleine oder mit anderen an einem eigenen OS entwickelt, zu welchem Zweck und in welcher Sprache (ASS, C oder C++)? Links?


Für meine Studienarbeit habe ich einen Echtzeit-fähigen Mikrokernel entwickelt mit einem EDF Scheduler. Während der Diplomarbeit erweitere ich den um energieeffiziente Schedulingalgorithmen. Das ganze läuft auf einem gumstix connex400 mit einem Intel PXA255 (ARMvt5). Code darf ich noch nicht veröffentlichen :(

_________________
"Computers are like Old Testament gods; lots of rules and no mercy" by Joseph Campbell
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:52:45 25.07.2009   Titel:              Zitieren

@supertux: Klingt echt toll! Davon musst Du hier berichten, sobald Du dies darfst. Aber vielleicht kannst Du mit Deinen Erkenntnissen hier einige wichtige Weichenstellungen kommentieren und beeinflussen. PrettyOS soll ja vor allem ein Experimentier-OS werden und Einsteiger in diese Materie ansprechen und ermuntern.

Das Bild von einem OS, das man vor Augen hat, wird entscheidend geprägt durch das Interface. Daher habe ich nun auch begonnen die "Shell" (in Ring 3) zu entwickeln:
http://www.henkessoft.de/OS_Dev/OS_Dev3.htm#mozTocId29082

Ich stelle mir momentan vor allem die Frage: Was gehört in die syscall-API (teuer) und was in die user-API (bläht User-Programm auf)? :confused:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:57:52 25.07.2009, insgesamt 2-mal bearbeitet
supertux
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.07.2004
Beiträge: 3351
Beitrag supertux Mitglied 14:35:46 25.07.2009   Titel:              Zitieren

Erhard Henkes schrieb:
@supertux: Klingt echt toll! Davon musst Du hier berichten, sobald Du dies darfst. Aber vielleicht kannst Du mit Deinen Erkenntnissen hier einige wichtige Weichenstellungen kommentieren und beeinflussen. PrettyOS soll ja vor allem ein Experimentier-OS werden und Einsteiger in diese Materie ansprechen und ermuntern.


das hörst sich sehr interessant an, hab ein bisschem im Code nachgeschaut. Leider kenne ich mich mit x86 überhaupt nicht aus, also verstehe ich den Code und viele (für x86) Notwendige Sache gar nicht.

Ich muss meine Ausarbeitung in ca. 2 1/2 Wochen abgeben, dann Vortrag halten und so. Also erst danach werde ich wahrscheinlich meine Sachen (plus Sources) veröffentlichen können.

_________________
"Computers are like Old Testament gods; lots of rules and no mercy" by Joseph Campbell


Zuletzt bearbeitet von supertux am 14:36:57 25.07.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 15:34:39 25.07.2009   Titel:              Zitieren

ARM ist für einige interessant. Vielleicht kannst Du auch einen passenden Emulator verlinken. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 15:40:17 25.07.2009   Titel:              Zitieren

Ich habe PrettyOS nun auch unabhängiger und stabiler gemacht. Da hatten sich nach dem Umstieg von DJGPP nach Cross-Tools doch einige unbehobene Schwachpunkte angesammelt. Nun kann man Kernel und User-Programme mit CFLAGS= -Werror -Wall -O -ffreestanding -fleading-underscore -nostdlib -nostdinc -fno-builtin kompilieren.
Physikalischer Speicher wird nun auch automatisch bestimmt und für das Paging (Anzahl der Frames = Phys. Memory / Pagesize) übernommen.

Das ist die bisher stabilste und beste Version: http://www.henkessoft.de/OS_Dev/Downloads/88.zip (läuft inzwischen mit -Werror und -Wall und benötigt keine Header der Cross-Tools)

Hier habe ich wieder initrd und VFS verwendet, um die shell zu finden/laden:
http://www.henkessoft.de/OS_Dev/Downloads/90.zip
(dabei gibt es aber auf bestimmten PC noch Probleme, die ich bisher nicht lokalisieren und beheben kann):
Die Shell wurde als ELF-Programm via incbin (data.asm) über die Paarung RAM Disk / VFS lokalisiert und gestartet. Der visuelle Eindruck beginnt sich zu entwickeln.

Ich stelle mir für die Zukunft die Fragen:
- wie sollen die syscalls aussehen?
- was gehört in die user-lib?
- Sollte man Standards einsetzen? (POSIX, standardisierte C-userlib)
- Sollte man letztendlich doch GRUB einsetzen oder stur den eigenen Bootloader ausbauen? (niemand hetzt mich)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 10:57:28 26.07.2009, insgesamt 2-mal bearbeitet
Cox
Unregistrierter




Beitrag Cox Unregistrierter 12:34:28 26.07.2009   Titel:              Zitieren

Wenn du mich fragst, ich würde auf jeden Fall einmal das Thema GRUB anschneiden.
Es soll immerhin ein OS- und kein Bootloader-Tutorial bleiben / werden.
Hobby Programmierer
Mitglied

Benutzerprofil
Anmeldungsdatum: 15.03.2009
Beiträge: 75
Beitrag Hobby Programmierer Mitglied 16:46:41 26.07.2009   Titel:              Zitieren

Ich würde Standards einsetzen, weil es dann einfacher ist Programme zu entwickeln bzw. zu portieren.
Deli1
Unregistrierter




Beitrag Deli1 Unregistrierter 21:55:45 27.07.2009   Titel:              Zitieren

Als erstes vorweg: ich beobachte die Entwicklung des Tutorials jetzt schon einige Zeit und bin echt begeistert! Mach auf jeden Fall weiter.

Zum Thema GRUB: Ich fände es schade um die viele Arbeit, die jetzt schon in den eigenen Bootloader investiert wurde. Außerdem find ich es gut, dass man so von Anfang an gut erklärt bekommt, wie so ein Betriebssystem von Grund auf aufgebaut ist. Wenn man den Anfang jetzt GRUB machen lässt, werden wieder Fragen wie "Wie läuft das denn eigentlich mit GRUB ab?" aufgeworfen. Es ist zwar viel Arbeit, doch ist der Lerneffekt zumindest für mich größer, wenn mit dem jetzigen Bootloader weitergearbeitet wird. :)


Übrigens habe ich festgestellt, dass der Bootloader sich im Bochs-Emulator bei folgenden IPS folgendermaßen verhält (Näherungswerte):

400.000 -> Bootloader wird garnicht erst geladen
400.050 -> Bootloader startet verzögert (ca. 7 Sekunden)
400.100 -> Bootloader startet verzögert (ca. 5 Sekunden)
400.500 -> Bootloader startet verzögert (ca. 1 Sekunde)
402.000 -> Bootloader startet vollkommen normal

Getestet wurde übrigens mit jeweils 8 MB RAM (das Niedrigste, ohne eine Fehlermeldung von alloc_frame() zu bekommen, dass es keine freien Frames mehr gebe, um anschließend (außer bei 7MB RAM) im "Page Fault >>> Exception. System Halted! <<<" zu enden ;))

Woran liegt das genau, warum sind so kleine Werte hierbei so entscheidend?
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:19:45 27.07.2009   Titel:              Zitieren

Zitat:
ich beobachte die Entwicklung des Tutorials jetzt schon einige Zeit und bin echt begeistert! Mach auf jeden Fall weiter.
Ich plane im Hintergrund bereits ein neues völlig eigenes OS, muss aber erst noch mehr Erfahrung sammeln. Bei OSDEV zählt Erfahrung mehr als jede noch so tolle Theorie. Jeder baut hier auf den anderen auf. MSDOS auf CP/M, Linux auf Minix, ...

Zitat:
Zum Thema GRUB: Ich fände es schade um die viele Arbeit, die jetzt schon in den eigenen Bootloader investiert wurde. Außerdem find ich es gut, dass man so von Anfang an gut erklärt bekommt, wie so ein Betriebssystem von Grund auf aufgebaut ist.
Sehe ich genau so! Ich war nur deutlich verunsichert, weil ich bei seltsamen Fehlern jedes Mal mühsam belegen muss, das es nicht am Bootloader hängt. Seit ich diesen Schwachpunkt in initrd (buffer overflow durch strcpy; behoben durch Einbau von strncpy in Version 0.1.0090, die läuft schon sehr stabil, aber ich weiß noch nicht, warum manche PC da Blödsinn machen) behoben habe, geht es mir besser. Der Bootloader ist schon echt klasse. Jetzt ist ja auch die Speichererkennung mit dabei. Man könnte noch ein FAT12 einbauen, dann könnte man den kernel als kernel.sys von Floppy laden. Aber das macht die Sache auch nicht besser.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:22:22 27.07.2009   Titel:              Zitieren

Zitat:
400.000 -> Bootloader wird garnicht erst geladen
400.050 -> Bootloader startet verzögert (ca. 7 Sekunden)
400.100 -> Bootloader startet verzögert (ca. 5 Sekunden)
400.500 -> Bootloader startet verzögert (ca. 1 Sekunde)
402.000 -> Bootloader startet vollkommen normal

Getestet wurde übrigens mit jeweils 8 MB RAM (das Niedrigste, ohne eine Fehlermeldung von alloc_frame() zu bekommen, dass es keine freien Frames mehr gebe, um anschließend (außer bei 7MB RAM) im "Page Fault >>> Exception. System Halted! <<<" zu enden ;))

Interessante Untersuchung, mach weiter so! :)
Der minimalistische Denkansatz gefällt mir!

Bei mir sieht das wie folgt aus:
Zitat:

romimage: file=$BXSHARE/BIOS-bochs-latest

cpu: count=1, ips=10000000, reset_on_triple_fault=1

megs: 1024

vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest

vga: extension=vbe

floppya: 1_44=G:\OSDev\User\MyOS.img, status=inserted

ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9

boot: floppy

floppy_bootsig_check: disabled=0

log: bochsout.txt

panic: action=ask
error: action=report
info: action=report
debug: action=ignore

debugger_log: -

parport1: enabled=1, file="parport.out"

vga_update_interval: 300000

keyboard_serial_delay: 250

keyboard_paste_delay: 100000

mouse: enabled=0

private_colormap: enabled=0

keyboard_mapping: enabled=0, map=

i440fxsupport: enabled=0


Momentan bin ich guter Dinge, weil sich das OS die letzten Tage gewaltig stabilisiert hat, sogar die Version mit initrd/VFS läuft jetzt stabil:
Zitat:
PrettyOS [Version 0.1.0090] (C) 2009 henkessoft.de

Usable RAM: 1048124 KB

Ram Disk at: 4008100Ch
<DIR> dev
35 file1
35 file2
35 file3
7719 dummy
1693 shell

$> hi <--
I am PrettyOS. Always at your service!
$> ? <--
Implemented Instructions: help ? hi
$> OK <--
Sorry, I do not know this command.
$>


Ich sehe aus praktischer Sicht vier Komponenten eines OS:
1) PC/BIOS
2) Bootloader
3) Kernel
4) Userspace

Durch Einsatz von GRUB schaltet man Fehler aus 1) und 2) aus. Dafür hat man GRUB am Hals. ;)

Da wir ausgehend von MS Windows entwickeln, werden wir auf GRUB verzichten. Dieses Tutorial macht mir Mut: http://www.brokenthorn.com/Resources/OSDev1.html (zwar einige Fehler enthalten, aber bezüglich des didaktischen Ansatzes richtig gut). Allerdings überfrachtet es den Leser im Sinne eines Nachschlagwerkes mit Theorie-Details. Die Praxis geht dort fast unter.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:45:05 27.07.2009, insgesamt 8-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:05:47 27.07.2009   Titel:              Zitieren

Ich habe das jetzt auch mal getestet:

8MB:
Zitat:
PrettyOS [Version 0.1.0090] (C) 2009 henkessoft.de

Usable RAM: 7740 KB

Ram Disk at: 4008100Ch
<DIR> dev
35 file1
35 file2
35 file3
7719 dummy
1693 shell

$> hi <--
I am PrettyOS. Always at your service!
$>

7MB:
Zitat:
loc_frame: no free frames!!!message from alloc_frame: no free frames!!!message f
rom alloc_frame: no free frames!!!message from alloc_frame: no free frames!!!mes
sage from alloc_frame: no free frames!!!message from alloc_frame: no free frames
!!!message from alloc_frame: no free frames!!!message from alloc_frame: no free
frames!!!message from alloc_frame: no free frames!!!message from alloc_frame: no
free frames!!!message from alloc_frame: no free frames!!!message from alloc_fra
me: no free frames!!!message from alloc_frame: no free frames!!!message from all
oc_frame: no free frames!!!message from alloc_frame: no free frames!!!message fr
om alloc_frame: no free frames!!!message from alloc_frame: no free frames!!!mess
age from alloc_frame: no free frames!!!message from alloc_frame: no free frames!
!!message from alloc_frame: no free frames!!!message from alloc_frame: no free f
rames!!!message from alloc_frame: no free frames!!!message from alloc_frame: no
free frames!!!message from alloc_frame: no free frames!!!message from alloc_fram
e: no free frames!!!message from alloc_frame: no free frames!!!Ram Disk at: 4008
100Ch
<DIR> dev
35 file1
35 file2
35 file3
7719 dummy
1693 shell

$> hi <--
I am PrettyOS. Always at your service!
$>

Stimmt! Allerdings ohne #PF, zumindest bei Version 0.1.0090 :)

8 MB Minimum finde ich gar nicht übel. :live:

PS: Ich sehe gerade: da gehört noch ein Space hinter "no free frames!!!"

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:16:04 27.07.2009, insgesamt 2-mal bearbeitet
Tobiking2
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 705
Beitrag Tobiking2 Mitglied 02:49:20 28.07.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Dieses Tutorial macht mir Mut: http://www.brokenthorn.com/Resources/OSDev1.html (zwar einige Fehler enthalten, aber bezüglich des didaktischen Ansatzes richtig gut). Allerdings überfrachtet es den Leser im Sinne eines Nachschlagwerkes mit Theorie-Details. Die Praxis geht dort fast unter.


Der Code davon gefällt mir aber persönlich ganz gut. Flags als Veroderung von Defines, Code aufgeteilt in Teilbereiche (wie Hal, Lib etc.) und die Trennung von Bootloader- und Kernelcode wären etwas was man sich abgucken könnte.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 03:34:18 29.07.2009   Titel:              Zitieren

zu http://www.brokenthorn.com/Resources/OSDev20.html :
Der Aufbau gegliedert in boot.bin, kernel.sys und kernel.exe unter Verwendung von FAT12 und VC2008 Express ist vorbildhaft, da hast Du Recht. Echt klasse gemacht.

Ob VC++ 2005 od. 2008 unbedingt sein muss, da kann man sich streiten, aber professionell ist es auf jeden Fall. Man lernt halt wenig über makefile und linker script, was ich für einen OSDever für wichtig halte.

Konntest Du sein OS schon booten/starten? :confused:

Mir ist das noch nicht gelungen.
Ich habe bisher aber nur Demo15 aus tut20 getestet:
http://www.brokenthorn.com/Resources/Demos/Demo15.zip

In boot.asm fehlen drei Doppelpunkte bei den Labels, aber auch nach Ergänzung (nasm motzt herum, warum der Autor dies nicht liest?) verschwindet der "Reset" beim Booten nicht. Liegt der Fehler bereits hier?

kernel.sys klappt gut, oder liegt hier im Code das Problem? In zip-Datei mitgeliefertes kernel.sys funktioniert auch nicht.

Kernel.exe: VC++ 2008 Express (bei der Demo sind noch die 2005er Projektdateien dabei, kann man aber updaten) gibt einige Warnungen aus, kompiliert/linkt aber alles und schreibt kernel.exe auf floppy disk.

Hast Du da praktische Tipps, wie man es zum Laufen bekommt, oder muss ich den Autor ansprechen? Auch mit Bochs 2.4.1 gibt es einen Reset (wie bei real PC).

Bei solchen Zeilen:
Assembler Code:
mov ax, 0x0000 ; set the stack
Assembler Code:
mov ax, 0x0000 ; set the stack
Assembler Code:
mov ax, 0x0000 ; set the stack

gibt es normalerweise Kritik (siehe Anmerkungen von NobuoT weiter vorne). Das müsste wirklich nicht sein.

Mein Fazit:
Tutorial: sehr umfassend, viele Rechtschreibfehler, didaktischer Stil gut
Grundlegender Code-Aufbau: Klasse! Davon kann man lernen.
Tools: Mit freien Windows-Tools (nasm, partcopy, VC++ 2005/08 Express) umsetzbar, kein GRUB, sondern eigener Bootloader mit FAT12-Erkennung!
Praktische Umsetzung/Fehlerfreiheit: negativ (bootet, resettet aber, Warnungen von nasm und VC++ 2008, offenbar schaut sich der Autor die Meldungen seiner Tools nicht an, ist mir aber auch schon passiert, typische Verdrängung, Hauptsache vorwärts)

Das ist wirklich schade, denn ansonsten ist das Tutorial hervorragend. Vielleicht liegt das Problem auch in Kernel.exe? Kannst Du Dich näher auslassen über deine Erfahrungen? Welche Demo-Version geht bei Dir?

Zitat:
Flags als Veroderung von Defines

Was gefällt Dir da besonders gut?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 04:14:32 29.07.2009, insgesamt 5-mal bearbeitet
Tobiking2
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 705
Beitrag Tobiking2 Mitglied 10:06:17 29.07.2009   Titel:              Zitieren

Ich habe noch nicht versucht den Code zu kompilieren und zu starten. Werd ich nacher mal ausprobieren. Habe den Code nur durchgesehen um ein paar Anregungen zu bekommen, da C nicht gerade meine Hauptsprache ist, und da sind mir die Sachen aufgefallen. Visual Studio ist auch nicht unbedingt meine Wahl für Betriebsystementwicklung, zumal da auch C++ im Spiel ist. Allerdings sieht das mit dem inline Assembler etwas eleganter aus als beim gcc.

Das mit den Defines ist mir hauptsächlich beim IDT und GDT aufgefallen:
C/C++ Code:
gdt_set_descriptor (1,0,0xffffffff,
    I86_GDT_DESC_READWRITE|I86_GDT_DESC_EXEC_CODE|I86_GDT_DESC_CODEDATA|I86_GDT_DESC_MEMORY,
    I86_GDT_GRAND_4K | I86_GDT_GRAND_32BIT | I86_GDT_GRAND_LIMITHI_MASK);
C/C++ Code:
gdt_set_descriptor (1,0,0xffffffff,
I86_GDT_DESC_READWRITE|I86_GDT_DESC_EXEC_CODE|I86_GDT_DESC_CODEDATA|I86_GDT_DESC_MEMORY,
I86_GDT_GRAND_4K | I86_GDT_GRAND_32BIT | I86_GDT_GRAND_LIMITHI_MASK);
C/C++ Code:
gdt_set_descriptor (1,0,0xffffffff,
    I86_GDT_DESC_READWRITE|I86_GDT_DESC_EXEC_CODE|I86_GDT_DESC_CODEDATA|I86_GDT_DESC_MEMORY,
    I86_GDT_GRAND_4K | I86_GDT_GRAND_32BIT | I86_GDT_GRAND_LIMITHI_MASK);


Ist besser zu erkennen was gesetzt ist, als wenn da einfach als Flag 0x9A steht. Es ist natürlich im Tutorial erklärt, aber wenn man später auf den Code zurück kommt muss man es wieder nachlesen.


Edit: Habs jetzt ausprobiert (Demo15.zip aus Tutorial 20) und es läuft in Virtualbox und QEmu ohne Probleme. Wichtig war vor allem als Debug zu kompilieren, da Release anscheinend nicht richtig konfiguriert ist. Als beim Release Build 740 Fehler kamen wollte ich schon aufgeben. Ansonsten habe ich nichts umgestellt. Allerdings nutze ich Visual Studio Professional und kein Express, was noch einen Unterschied machen könnte.


Zuletzt bearbeitet von Tobiking2 am 11:53:28 29.07.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:38:33 29.07.2009   Titel:              Zitieren

Zitat:
Habs jetzt ausprobiert (Demo15.zip aus Tutorial 20) und es läuft in Virtualbox und QEmu ohne Probleme. Wichtig war vor allem als Debug zu kompilieren, da Release anscheinend nicht richtig konfiguriert ist.

Mit VC++ 2008 Express im Debug-Modus kompiliert, Release geht überhaupt nicht wegen massenweise Fehler. Auf der Diskette befindet sich hinterher kernel.sys und kernel.exe. habe auch mal die hal.dll dazu, bringt aber nichts, besteht ja auch keine Abhängigkeit der kernel.exe.

Keine Ahnung, wie Du das schaffst. Läuft nicht mit Virtual PC 2007 (bootet zwar, hinterher aber nur blauer Bildschirm mit blinkendem Cursor), überhaupt nicht mit Sun xVM VirtualBox und nicht mit Bochs 2.4.1. Dieser Zustand ist gelinde gesagt nicht gerade berauschend. :rolleyes:

Zitat:
gdt_set_descriptor (1,0,0xffffffff, I86_GDT_DESC_READWRITE|I86_GDT_DESC_EXEC_CODE|I86_GDT_DESC_CODEDATA|I86_GDT_DESC_MEMORY,
I86_GDT_GRAND_4K | I86_GDT_GRAND_32BIT | I86_GDT_GRAND_LIMITHI_MASK);

Ja stimmt, das könnte man machen, ist ja bei Windows-Programmierung Standard.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
,fricky
Unregistrierter




Beitrag ,fricky Unregistrierter 20:25:14 29.07.2009   Titel:              Zitieren

huh? hab lange nicht mehr hier reingeschaut, aber wie's ausseiht, seid ihr immer noch dabei, den x86 in betrieb zu nehmen? *heul*
:)
,fricky
Unregistrierter




Beitrag ,fricky Unregistrierter 20:29:39 29.07.2009   Titel:              Zitieren

Erhard Henkes schrieb:
ARM ist für einige interessant. Vielleicht kannst Du auch einen passenden Emulator verlinken.

wieso emulator? nehmt doch 'nen richtigen ARM, z.b. sowas: http://www.mikrocontroller.net/articles/MP2103-Sti ....... troller-Board_mit_USB_und_bis_zu_4MB_Datenspeicher
:)
Tobiking2
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 705
Beitrag Tobiking2 Mitglied 20:46:26 29.07.2009   Titel:              Zitieren

,fricky schrieb:
wieso emulator? nehmt doch 'nen richtigen ARM, z.b. sowas: http://www.mikrocontroller.net/articles/MP2103-Sti ....... troller-Board_mit_USB_und_bis_zu_4MB_Datenspeicher
:)


4 mb könnten aber knapp werden wenn das OS 8 mb braucht um zu booten :D

Erhard Henkes schrieb:
ARM ist für einige interessant. Vielleicht kannst Du auch einen passenden Emulator verlinken.


QEmu kann so einiges emulieren (http://www.qemu.org/status.html), darunter auch ARM und MIPS. Wobei es für den Embedded Bereich ja oft auch spezielle Development Kits mit allem drum und dran gibt.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:47:57 29.07.2009   Titel:              Zitieren

Zitat:
wie's aussieht, seid ihr immer noch dabei, den x86 in betrieb zu nehmen?
yep, wir haben uns bereits bis zum User-Space durch gekämpft, und immer noch eigener Bootloader.

Zitat:
wieso emulator? nehmt doch 'nen richtigen ARM, z.b. sowas
Interessantes I/O Board für den PC.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:08:01 29.07.2009   Titel:              Zitieren

zu brokenthorn: Ich habe es nun mit Tut 19, Demo14 probiert, das klappt mit Bochs, also liegt es in Demo15 offenbar am Code für kernel.exe.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
;fricky
Unregistrierter




Beitrag ;fricky Unregistrierter 10:45:36 30.07.2009   Titel:              Zitieren

Tobiking2 schrieb:

4 mb könnten aber knapp werden wenn das OS 8 mb braucht um zu booten

ein os dass 8MB braucht, kannste gleich bei http://thedailywtf.com/ anmelden.

Tobiking2 schrieb:

Wobei es für den Embedded Bereich ja oft auch spezielle Development Kits mit allem drum und dran gibt.

sogar kostenlos. aber sein OS ständig im simulator laufen zu lassen, ist sehr unbefriedigend (wie alle software, die nur im computer läuft und nicht mit der realen welt interagiert, sondern nur mit einem benutzer, der vor der kiste sitzt).
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:30:36 30.07.2009   Titel:              Zitieren

Zitat:
ein os dass 8MB braucht, kannste gleich bei http://thedailywtf.com/ anmelden.
Ist einiges an Luft drinnen, die man ablassen kann, wenn notwendig. 8 MB ist doch heute kein Thema mehr in einem echten PC.
ARM ist eine andere Welt. Die spielt hier aber keine Geige. :D

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:17:42 30.07.2009   Titel:              Zitieren

Zitat:
Trennung von Bootloader- und Kernelcode wären etwas was man sich abgucken könnte


@Tobiking2:
Ich habe für die Freunde des altehrwürdigen Floppy Disk Formates einen ersten Schuss mit den etwas abgeänderten Startdateien von brokenthorn http://www.brokenthorn.com/Resources/OSDev1.html (schon ziemlich viel Ballast abgeworfen) durchgeführt:

Hier eine erste Version zum Testen und Mitdenken:
http://www.henkessoft.de/OS_Dev/Downloads/94.zip

(Alles mit eingelegter Floppy Disk durchführen, damit der Bootsektor geschrieben wird und boot2.sys sowie ckernel.sys auf die Floppy kopiert werden)

stage1_bootloader und FAT12:
- boot.bin (Bootsektor)

stage2_bootloader:
- boot2.sys (-->formatierte Floppy)

kernel:
- ckernel.sys (-->formatierte Floppy)

user:
- initrd & shell (program.elf)

Als Tools: partcopy, nasm(w), cross-compiler
Die Startadresse von ckernel.sys habe ich nach 0x40000 verlegt. Klappt gut.

Läuft im Gegensatz zu brokenthorn in -Werror -Wall Qualität mit den Cross-Tools. Den Kernel habe ich als Binary gelinkt, damit man das Parsen der ELF-Datei einspart.

Lässt sich mittels Bochs und auf Real PC booten.

Da kann man nun im nächsten Schritt boot.asm / boot2.asm mit unseren bisherigen Routinen, z.B. für Memory-Bestimmung und Sektoren-Lesen bestücken, noch mehr Ballast abwerfen und einige Adressen noch abändern. Sobald alles robust steht, werde ich das (mit Hinweis auf brokenthorn u.a. als Vorlage) ins PrettyOS-Tutorial einbauen. Gutes Exempel für Second-Stage-Bootloader und Lesen von FAT12-Format.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 04:45:03 01.08.2009, insgesamt 6-mal bearbeitet
Tobiking2
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 705
Beitrag Tobiking2 Mitglied 23:17:31 30.07.2009   Titel:              Zitieren

Die Diskette mit Fat12 zu formatieren und nur noch den Bootsektor mit partcopy zu beschreiben find ich auf jeden Fall eine gute Änderung. Was nun natürlich fehlt ist die Möglichkeit Userprogramme von der Diskette zu laden statt aus der initrd. ;)

Mich hat nur etwas gewundert, dass du den Bootloader Code von Brokenthorn übernommen und deine Sachen hinzugefügt hast, statt deinen eigenen Code umzubauen und zu erweitern. Solange du damit zufrieden ist ist es ok, aber ich schreib normalerweise lieber Funktionen sinngemäß nach, als irgendetwas erstmal 1:1 zu übernehmen und dann anzupassen.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:06:52 31.07.2009   Titel:              Zitieren

Zitat:
Mich hat nur etwas gewundert, dass du den Bootloader Code von Brokenthorn übernommen und deine Sachen hinzugefügt hast, statt deinen eigenen Code umzubauen und zu erweitern. Solange du damit zufrieden bist, ist es ok, aber ich schreib normalerweise lieber Funktionen sinngemäß nach, als irgendetwas erstmal 1:1 zu übernehmen und dann anzupassen.


Das war nur ein schneller Versuch, ob das Zusammenschmieden so klappt, wie ich mir das vorgestellt habe, und das hat es. Ich werde meinen Code um die notwendigen Teile erweitern, weil mir der bisherige Aufbau des Bootloaders besser gefällt als der Code von brokenthorn.

Die Erweiterung um einen second stage bootloader ist auf jeden Fall vorteilhaft, weil man Platz gewinnt. Das Laden von Diskette und später anderen Datenträgern ist ebenso ein Ziel. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 17:32:33 31.07.2009   Titel:              Zitieren

@ Tobiking2: Mich würde interessieren, wie Du die Demo15 von Tut20 bei brokenthorn zum Laufen bekommen hast. Ich verwende - wie bereits erwähnt - VC++ 2008 EE.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Tobiking2
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 705
Beitrag Tobiking2 Mitglied 18:35:55 31.07.2009   Titel:              Zitieren

Erhard Henkes schrieb:
@ Tobiking2: Mich würde interessieren, wie Du die Demo15 von Tut20 bei brokenthorn zum Laufen bekommen hast. Ich verwende - wie bereits erwähnt - VC++ 2008 EE.


Ich hab gerade nochmal frisch entpackt um zu prüfen das ich nicht irgendwo etwas verstellt habe und da ist mir aufgefallen, dass ich das Projekt nicht bereinigt habe und so die schon kompilierten libs benutzt habe. Nach einer kompletten Bereinigung läuft es bei mir auch nicht mehr.

Ich habe danach dann gezielt nur einzelnen Projekte bereinigt und es läuft solange ich nicht das Keyboard Projekt bereinige. Nachdem ich bei einem Diff zu Demo14 keinen unterschied gesehen habe, habe ich es dort ausprobiert und auch da tritt der Fehler auf sobald ich Keyboard selber compiliere. Demo12 ist die höchste die ich ohne Keyboard gefunden habe, da diese aber andere Fehler hat, hab ich da nicht weiter probiert.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:53:59 31.07.2009   Titel:              Zitieren

Die brokenthorn downloads scheinen ein ziemlicher Software-Müllhaufen zu sein, allerdings mit einigen Edelsteinen darin. :D

Ich bin auch etwas verblüfft, da ich die gestern schnell zusammen geschusterte Version 94 zum Laufen bringen wollte, diese aber plötzlich im Kernel nur ein gelbes S auf den Screen brachte (wegen dieses Problems hatte ich extra den Kernel nach 0x40000 geschoben, wegen interner Kernel-Schiebereien im Brokenthorn-Code). Ich habe sogar meinen Upload getestet, ging auch nicht mehr. Gestern abend lief der gleiche Code mit Bochs und Floppy, bin etwas verwirrt. Läuft meine Version 94 bei Dir?
http://www.henkessoft.de/OS_Dev/Downloads/94.zip
Das Speichermanagement ist etwas seltsam, muss mal seine Einstiegstuts lesen, in denen er diesen Aufbau beschreibt.

Die GRUB-Verfechter würden sich wieder schief lachen über diese Krämpfe. :D

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 18:57:31 31.07.2009, insgesamt 2-mal bearbeitet
Tobiking2
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 705
Beitrag Tobiking2 Mitglied 19:28:12 31.07.2009   Titel:              Zitieren

Ich hab unter Windows keine ordentliche gcc Toolchain installiert um richtig zu testen. Wenn ich aber unter Linux den Kernel compilier krieg ich folgendes vom Linker:

Zitat:
ld: section .text1 [0000000000044000 -> 0000000000044009] overlaps section .text [0000000000040000 -> 0000000000044162]


Der Code ist wohl über die festgelegten Grenzen im Linkerscript gewachsen.

Edit: Nach ändern der Positionen und starten in QEmu ist mir aufgefallen, dass es gar nicht bis zum C-Kernel durchläuft.


Zuletzt bearbeitet von Tobiking2 am 19:42:42 31.07.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:16:18 31.07.2009   Titel:              Zitieren

Da ist offenbar etwas durcheinander geraten.
boot2.asm, common.inc und kernel.ld müssen sauber aufeinander abgestimmt werden:

common.inc:
Assembler Code:
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
; where the kernel is to be loaded to in protected mode
%define IMAGE_PMODE_BASE 0x40000

; where the kernel is to be loaded to in real mode
%define IMAGE_RMODE_BASE 0x3000

; kernel name
ImageName     db "CKERNEL SYS'
ImageSize     dw 0
Assembler Code:
1
2
3
4
5
6
7
8
9
; where the kernel is to be loaded to in protected mode
%define IMAGE_PMODE_BASE 0x40000

; where the kernel is to be loaded to in real mode
%define IMAGE_RMODE_BASE 0x3000

; kernel name
ImageName db "CKERNEL SYS'
ImageSize dw 0
Assembler Code:
1
2
3
4
5
6
7
8
9
; where the kernel is to be loaded to in protected mode
%define IMAGE_PMODE_BASE 0x40000

; where the kernel is to be loaded to in real mode
%define IMAGE_RMODE_BASE 0x3000

; kernel name
ImageName     db "CKERNEL SYS'
ImageSize     dw 0


boot2.asm:
Assembler Code:
jmp dword CODE_DESC:IMAGE_PMODE_BASE
Assembler Code:
jmp dword CODE_DESC:IMAGE_PMODE_BASE
Assembler Code:
jmp dword CODE_DESC:IMAGE_PMODE_BASE


kernel.ld:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
OUTPUT_FORMAT("binary")
ENTRY(KernelStart)
SECTIONS
{
  . = 0x00040000;
  .text   : { __code_start = .;   *(EXCLUDE_FILE(shared_pages.o data.o).text) }
  . = 0x00045000;
  .text1  : { shared_pages.o(.text)                                    }
  . = 0x00046000;
  .text2  : { data.o(.text)                                            }
  .data   : { __data_start = .;   *(.data)                             }    
  .rodata : { __rodata_start = .; *(.rodata) *(.rdata)                 }
  .bss    : { __bss_start = .;    *(.bss) *(COMMON)                    }
  __end = .;
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
OUTPUT_FORMAT("binary")
ENTRY(KernelStart)
SECTIONS
{
. = 0x00040000;
.text : { __code_start = .; *(EXCLUDE_FILE(shared_pages.o data.o).text) }
. = 0x00045000;
.text1 : { shared_pages.o(.text) }
. = 0x00046000;
.text2 : { data.o(.text) }
.data : { __data_start = .; *(.data) }
.rodata : { __rodata_start = .; *(.rodata) *(.rdata) }
.bss : { __bss_start = .; *(.bss) *(COMMON) }
__end = .;
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
OUTPUT_FORMAT("binary")
ENTRY(KernelStart)
SECTIONS
{
  . = 0x00040000;
  .text   : { __code_start = .;   *(EXCLUDE_FILE(shared_pages.o data.o).text) }
  . = 0x00045000;
  .text1  : { shared_pages.o(.text)                                    }
  . = 0x00046000;
  .text2  : { data.o(.text)                                            }
  .data   : { __data_start = .;   *(.data)                             }    
  .rodata : { __rodata_start = .; *(.rodata) *(.rdata)                 }
  .bss    : { __bss_start = .;    *(.bss) *(COMMON)                    }
  __end = .;
}


Dann klappt das auch:
Zitat:
PrettyOS [Version 0.1.0094] (C) 2009 henkessoft.de

Memory detection does not work. Estimated usable RAM: 32768 KB

Ram Disk at: 4008100Ch
<DIR> dev
35 file1
35 file2
35 file3
1693 shell

$> hi <--
I am PrettyOS. Always at your service!
$>


(Meine memory detection ist ja noch nicht eingebaut)

Bitte alles weg werfen und erneut downloaden:
http://www.henkessoft.de/OS_Dev/Downloads/94.zip (neu upgeloadet)


Ein kompaktes auf Floppy unsichtbares MyOS.img ist eindeutig einheitlicher und vor allem gegen Verwechslungen gesichert. ;) :live:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:51:08 31.07.2009, insgesamt 3-mal bearbeitet
Tobiking2
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 705
Beitrag Tobiking2 Mitglied 20:23:38 31.07.2009   Titel:              Zitieren

Macht die Zeile:
Code:
jmp dword 0x08:0x300060 ; offset 0x60 in kernel.elf
Code:
jmp dword 0x08:0x300060 ; offset 0x60 in kernel.elf
Code:
jmp dword 0x08:0x300060 ; offset 0x60 in kernel.elf


in boot2.asm sinn wenn der Kernel in 0x40000 liegt und kein ELF-Format mehr ist?
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:47:05 31.07.2009   Titel:              Zitieren

Zitat:
Macht die Zeile: jmp dword 0x08:0x300060 ; offset 0x60 in kernel.elf
in boot2.asm sinn wenn der Kernel in 0x40000 liegt und kein ELF-Format mehr ist?
Nein, natürlich nicht. Völliger Blödsinn. :eek:

Da ist beim Hochladen Stage 2 durcheinander geraten.
Da muss alles genau passen. Auch die Namen stehen mehrfach im Code.
Kleiner Fehler bei Änderungen: alles kaputt. :D

Bitte alles weg werfen und erneut downloaden:
http://www.henkessoft.de/OS_Dev/Downloads/94.zip (neu upgeloadet)

(habe jetzt auch etwas mehr Platz geschafft für anderen Compiler, der "dickeren" Code produziert.)

Selbst downgeloadet, extrahiert und getestet: OK.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:57:03 31.07.2009, insgesamt 3-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 22:38:50 31.07.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Kleiner Fehler bei Änderungen: alles kaputt. :D

Irgendwo habe ich mal einen Spruch gehört, Assembler Funktionen seien verdammt schnell, man müsse aber beim Programmieren der Assembler Funktionen verdammt langsam denken... :)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:51:14 31.07.2009   Titel:              Zitieren

Ja, das stimmt wirklich. :D

Klappt das bei Dir mit der Version 94? Dank FAT 12 kann man jetzt aus mehreren Versionen alles schön vermischen, spätestens auf der Floppy. :D
Wer keine Floppy hat, gibts natürlich auch virtuell (VFD).

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:53:51 31.07.2009, insgesamt 2-mal bearbeitet
Tobiking2
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 705
Beitrag Tobiking2 Mitglied 23:14:25 31.07.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Klappt das bei Dir mit der Version 94? Dank FAT 12 kann man jetzt aus mehreren Versionen alles schön vermischen, spätestens auf der Floppy. :D


Ja es klappt. Man muss aber natürlich drauf achten, dass Stage 1 und 2 zusammen passen. Wenn man ein altes Stage 1 oder 2 mit anderen Adressen benutzt kann das schnell schief gehen.

Erhard Henkes schrieb:
Wer keine Floppy hat, gibts natürlich auch virtuell (VFD).


Unter Linux gibt es losetup :D
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 04:39:50 01.08.2009   Titel:              Zitieren

Na, wenn das soweit klappt (bei Vers. 94 ist sogar initrd-Filesystem dabei, das bisher nicht überall lief), ist es wohl an der Zeit, sich nun den Themen Device-Treiber "Floppy Disk" sowie dem File-Format "FAT 12" zu widmen und First und Second Stage Bootloader auszubauen. :)

So sieht momentan nach einigen Speicheranpassungen der First Stage Bootloader aus:

boot.asm:
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
; boot.asm
[Bits 16]
org 0x7C00                             ; start address of bootloader
jmp entry_point                        ; jump to bootloader entry point

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Memory Management:
; org                  7C00 (0x00007C00)
; data/extra segments     0
; stack segment        9000 (0x00090000)  
; root dir -> memory   7E00 (0x00007E00)
; boot2    -> memory    500 (0x00000500)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;##############################################################################
; "FAT 12" file system is build up by four areas at Floppy Disk:
; - Boot Sector (also called BIOS Parameter Block, BPB)
; - File Allocation Table, FAT
; - Root Directory
; - Subdirectories and Files

; boot sector info block
; begins 3 bytes from start. A far jump needs 3 bytes.

OperatingSystemName db "PrettyOS'      ;  8 byte
BytesPerSec         dw 512                            ; used in bootloader code
SecPerClus          db 1                              ; used in bootloader code
ReservedSec         dw 1                              ; used in bootloader code
NumFATs             db 2                              ; used in bootloader code
RootEntries         dw 224                            ; used in bootloader code
TotSec              dw 2880                          
MediaType           db 0xF0
FATSize             dw 9                              ; used in bootloader code
SecPerTrack         dw 18                             ; used in bootloader code
NumHeads            dw 2                              ; used in bootloader code
HiddenSec           dd 0
TotSec32            dd 0
DriveNum            db 0                              ; used in bootloader code
Reserved            db 0
BootSig             db 0x29
VolumeSerialNum     dd 0xD00FC0DE      
VolumeLabel         db "PrettyOS   '   ; 11 byte
FileSys             db "FAT12   '      ;  8 byte
;##############################################################################


;******************************************************************************
;    bootloader entry point
;******************************************************************************
entry_point:
    xor     ax, ax                        ; set registers
    mov     ds, ax
    mov     es, ax
    mov     fs, ax
    mov     gs, ax
   
    mov     ax, 0x9000                   ; set the stack
    mov     ss, ax
    xor     sp, sp
         
    mov  [bootdevice], dl              ; store boot device
    mov si, msgLoading
    call print_string

Load_Root_Directory_Table:
    ; compute size of root directory and store in "cx"
    xor cx, cx
    xor dx, dx
    mov ax, 0x20                             ; 32 byte directory entry
    mul WORD [RootEntries]                   ; total size of directory
    div WORD [BytesPerSec]                   ; sectors used by directory
    xchg ax, cx
       
    ; compute location of root directory and store in "ax"
    mov al, BYTE [NumFATs]                    ; number of FATs
    mul WORD [FATSize]                        ; sectors used by FATs
    add ax, WORD [ReservedSec]                ; adjust for bootsector
    mov WORD [datasector], ax                 ; base of root directory
    add WORD [datasector], cx
         
    ; read root directory into memory (7E00h)
    mov bx, 0x7E00                            ; copy root dir above bootcode
    call ReadSectors

;******************************************************************************
;   Find stage2 bootloader
;******************************************************************************
    ; browse root directory for binary image
    mov cx, WORD [RootEntries]                ; load loop counter
    mov di, 0x7E00                            ; locate first root entry
.LOOP:
    push cx
    mov cx, 0xB                               ; name has 11 characters
    mov si, ImageName                         ; look for this image name
    push di
    rep cmpsb                                 ; test for entry match
    pop di
    je Load_FAT
    pop cx
    add di, 0x20                              ; queue next directory entry
    loop .LOOP
    jmp FAILURE

;******************************************************************************
;   Load File Allocation Table (FAT)
;******************************************************************************
Load_FAT:
    ; save starting cluster of boot image
    mov dx, WORD [di + 0x001A]
    mov WORD [cluster], dx                  ; file's first cluster
         
    ; compute size of FAT and store in "cx"
    xor ax, ax
    mov al, BYTE [NumFATs]                  ; number of FATs
    mul WORD [FATSize]                      ; sectors used by FATs
    mov cx, ax

    ; compute location of FAT and store in "ax"
    mov ax, WORD [ReservedSec]              ; adjust for bootsector
         
    ; read FAT into memory (7E00h)
    mov bx, 0x7E00                          ; copy FAT above bootcode
    call ReadSectors

    ; read image file into memory (0500h)
    xor ax, ax
    mov es, ax                              ; destination for image
    mov bx, 0x0500                          ; destination for image
    push bx

;******************************************************************************
;   Load stage2 bootloader
;******************************************************************************
Load_Image:
    mov ax, WORD [cluster]                  ; cluster to read
    pop bx                                  ; buffer to read into
    call Convert_Cluster_to_LBA             ; convert cluster to LBA
    xor cx, cx
    mov cl, BYTE [SecPerClus]               ; sectors to read
    call ReadSectors
    push bx
         
    ; compute next cluster
    mov ax, WORD [cluster]                  ; identify current cluster
    mov cx, ax                              ; copy current cluster
    mov dx, ax                              ; copy current cluster
    shr dx, 1                               ; divide by two
    add cx, dx                              ; sum for (3/2)
    mov bx, 0x7E00                          ; location of FAT in memory
    add bx, cx                              ; index into FAT
    mov dx, WORD [bx]                       ; read two bytes from FAT
    test ax, 1
    jnz .ODD_CLUSTER
         
.EVEN_CLUSTER:
    and dx, 0000111111111111b               ; take low twelve bits
    jmp .DONE
         
.ODD_CLUSTER:
    shr dx, 4                               ; take high twelve bits
         
.DONE:
    mov WORD [cluster], dx                  ; store new cluster
    cmp dx, 0x0FF0                          ; test for end of file
    jb Load_Image
         
DONE:
    mov si, msgCRLF
    call print_string
    mov dl, [bootdevice]
    push WORD 0x0000
    push WORD 0x0500
    retf
         
FAILURE:
    mov si, msgFailure
    call print_string
    mov ah, 0x00
    int 0x16                                ; wait for keypress
    int 0x19                                ; warm boot reset


;******************************************************************************
;   Convert CHS to LBA
;   LBA = (cluster - 2) * sectors per cluster
;******************************************************************************
Convert_Cluster_to_LBA:
    sub ax, 2                               ; zero base cluster number
    xor cx, cx
    mov cl, BYTE [SecPerClus]               ; convert byte to word
    mul cx
    add ax, WORD [datasector]               ; base data sector
    ret

;******************************************************************************
;   Convert LBA to CHS
;   AX    LBA Address to convert
;
;   absolute sector = (logical sector / sectors per track) + 1
;   absolute head   = (logical sector / sectors per track) MOD number of heads
;   absolute track  = logical sector / (sectors per track * number of heads)
;
;******************************************************************************
Convert_LBA_to_CHS :
    xor dx, dx                              ; prepare dx:ax for operation
    div WORD [SecPerTrack]                  ; calculate
    inc dl                                  ; adjust for sector 0
    mov BYTE [Sector], dl
    xor dx, dx                              ; prepare dx:ax for operation
    div WORD [NumHeads]                     ; calculate
    mov BYTE [Head], dl
    mov BYTE [Cylinder], al
    ret

;******************************************************************************
;   Reads sectors
;   CX     Number of sectors to read
;   AX     Starting sector
;   ES:BX  Buffer to read to
;******************************************************************************
ReadSectors:
.NEXTSECTOR:
    mov di, 5                                ; five retries for error
.LOOP:
    push ax
    push bx
    push cx
    call Convert_LBA_to_CHS                  ; convert starting sector from LBA to CHS
    mov  ah, 2                               ; INT 0x13, AH=2 --> read in CHS mode
    mov  al, 1                               ; read one sector
    mov  ch, BYTE [Cylinder]            ; track/cylinder
    mov  cl, BYTE [Sector]           ; sector
    mov  dh, BYTE [Head]             ; head
    mov  dl, BYTE [DriveNum]                 ; drive
    int  0x13                                
    jnc  .SUCCESS                            ; check read error
    xor  ax, ax                              ; INT 0x13, AH=0 --> reset floppy/hard disk
    int  0x13                                
    dec  di                                  ; decrement error counter
    pop  cx
    pop  bx
    pop  ax
    jnz  .LOOP                               ; read again
    int  0x18
.SUCCESS:
    mov  si, msgProgress
    call print_string
    pop  cx
    pop  bx
    pop  ax
    add  bx, WORD [BytesPerSec]              ; queue next buffer
    inc  ax                                  ; queue next sector
    loop .NEXTSECTOR                         ; read next sector
    ret
   
;******************************************************************************
;   Print String  
;    DS:SI   null-terminated string
;******************************************************************************
print_string:
    mov ah, 0x0E      ; BIOS function 0x0E: teletype
.loop:  
    lodsb             ; grab a byte from SI
    test al, al       ; NUL?
    jz .done          ; if the result is zero: get out
    int 0x10          ; else: print out the character
    jmp .loop
.done:
    ret   
   
;******************************************************************************
;    Parameters
;******************************************************************************
Sector         db 0
Head           db 0
Cylinder       db 0   
bootdevice     db 0
datasector     dw 0
cluster        dw 0
ImageName      db "BOOT2   SYS'
msgCRLF        db 0x0D, 0x0A, 0
msgProgress    db "*', 0
msgLoading     db "Loading Second Stage Bootloader', 0x0D, 0x0A, 0
msgFailure     db 0x0D, 0x0A, "BOOT2.SYS MISSING', 0x0D, 0x0A, 0
 
TIMES 510-($-$$) hlt                         ; fill bytes until boot signature
db 0x55                                      ; boot signature
db 0xAA                                      ; boot signature
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
; boot.asm
[Bits 16]
org 0x7C00 ; start address of bootloader
jmp entry_point ; jump to bootloader entry point

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Memory Management:
; org 7C00 (0x00007C00)
; data/extra segments 0
; stack segment 9000 (0x00090000)
; root dir -> memory 7E00 (0x00007E00)
; boot2 -> memory 500 (0x00000500)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;##############################################################################
; "FAT 12" file system is build up by four areas at Floppy Disk:
; - Boot Sector (also called BIOS Parameter Block, BPB)
; - File Allocation Table, FAT
; - Root Directory
; - Subdirectories and Files

; boot sector info block
; begins 3 bytes from start. A far jump needs 3 bytes.

OperatingSystemName db "PrettyOS' ; 8 byte
BytesPerSec dw 512 ; used in bootloader code
SecPerClus db 1 ; used in bootloader code
ReservedSec dw 1 ; used in bootloader code
NumFATs db 2 ; used in bootloader code
RootEntries dw 224 ; used in bootloader code
TotSec dw 2880
MediaType db 0xF0
FATSize dw 9 ; used in bootloader code
SecPerTrack dw 18 ; used in bootloader code
NumHeads dw 2 ; used in bootloader code
HiddenSec dd 0
TotSec32 dd 0
DriveNum db 0 ; used in bootloader code
Reserved db 0
BootSig db 0x29
VolumeSerialNum dd 0xD00FC0DE
VolumeLabel db "PrettyOS ' ; 11 byte
FileSys db "FAT12 ' ; 8 byte
;##############################################################################


;******************************************************************************
; bootloader entry point
;******************************************************************************
entry_point:
xor ax, ax ; set registers
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax

mov ax, 0x9000 ; set the stack
mov ss, ax
xor sp, sp

mov [bootdevice], dl ; store boot device
mov si, msgLoading
call print_string

Load_Root_Directory_Table:
; compute size of root directory and store in "cx"
xor cx, cx
xor dx, dx
mov ax, 0x20 ; 32 byte directory entry
mul WORD [RootEntries] ; total size of directory
div WORD [BytesPerSec] ; sectors used by directory
xchg ax, cx

; compute location of root directory and store in "ax"
mov al, BYTE [NumFATs] ; number of FATs
mul WORD [FATSize] ; sectors used by FATs
add ax, WORD [ReservedSec] ; adjust for bootsector
mov WORD [datasector], ax ; base of root directory
add WORD [datasector], cx

; read root directory into memory (7E00h)
mov bx, 0x7E00 ; copy root dir above bootcode
call ReadSectors

;******************************************************************************
; Find stage2 bootloader
;******************************************************************************
; browse root directory for binary image
mov cx, WORD [RootEntries] ; load loop counter
mov di, 0x7E00 ; locate first root entry
.LOOP:
push cx
mov cx, 0xB ; name has 11 characters
mov si, ImageName ; look for this image name
push di
rep cmpsb ; test for entry match
pop di
je Load_FAT
pop cx
add di, 0x20 ; queue next directory entry
loop .LOOP
jmp FAILURE

;******************************************************************************
; Load File Allocation Table (FAT)
;******************************************************************************
Load_FAT:
; save starting cluster of boot image
mov dx, WORD [di + 0x001A]
mov WORD [cluster], dx ; file's first cluster

; compute size of FAT and store in "cx"
xor ax, ax
mov al, BYTE [NumFATs] ; number of FATs
mul WORD [FATSize] ; sectors used by FATs
mov cx, ax

; compute location of FAT and store in "ax"
mov ax, WORD [ReservedSec] ; adjust for bootsector

; read FAT into memory (7E00h)
mov bx, 0x7E00 ; copy FAT above bootcode
call ReadSectors

; read image file into memory (0500h)
xor ax, ax
mov es, ax ; destination for image
mov bx, 0x0500 ; destination for image
push bx

;******************************************************************************
; Load stage2 bootloader
;******************************************************************************
Load_Image:
mov ax, WORD [cluster] ; cluster to read
pop bx ; buffer to read into
call Convert_Cluster_to_LBA ; convert cluster to LBA
xor cx, cx
mov cl, BYTE [SecPerClus] ; sectors to read
call ReadSectors
push bx

; compute next cluster
mov ax, WORD [cluster] ; identify current cluster
mov cx, ax ; copy current cluster
mov dx, ax ; copy current cluster
shr dx, 1 ; divide by two
add cx, dx ; sum for (3/2)
mov bx, 0x7E00 ; location of FAT in memory
add bx, cx ; index into FAT
mov dx, WORD [bx] ; read two bytes from FAT
test ax, 1
jnz .ODD_CLUSTER

.EVEN_CLUSTER:
and dx, 0000111111111111b ; take low twelve bits
jmp .DONE

.ODD_CLUSTER:
shr dx, 4 ; take high twelve bits

.DONE:
mov WORD [cluster], dx ; store new cluster
cmp dx, 0x0FF0 ; test for end of file
jb Load_Image

DONE:
mov si, msgCRLF
call print_string
mov dl, [bootdevice]
push WORD 0x0000
push WORD 0x0500
retf

FAILURE:
mov si, msgFailure
call print_string
mov ah, 0x00
int 0x16 ; wait for keypress
int 0x19 ; warm boot reset


;******************************************************************************
; Convert CHS to LBA
; LBA = (cluster - 2) * sectors per cluster
;******************************************************************************
Convert_Cluster_to_LBA:
sub ax, 2 ; zero base cluster number
xor cx, cx
mov cl, BYTE [SecPerClus] ; convert byte to word
mul cx
add ax, WORD [datasector] ; base data sector
ret

;******************************************************************************
; Convert LBA to CHS
; AX LBA Address to convert
;
; absolute sector = (logical sector / sectors per track) + 1
; absolute head = (logical sector / sectors per track) MOD number of heads
; absolute track = logical sector / (sectors per track * number of heads)
;
;******************************************************************************
Convert_LBA_to_CHS :
xor dx, dx ; prepare dx:ax for operation
div WORD [SecPerTrack] ; calculate
inc dl ; adjust for sector 0
mov BYTE [Sector], dl
xor dx, dx ; prepare dx:ax for operation
div WORD [NumHeads] ; calculate
mov BYTE [Head], dl
mov BYTE [Cylinder], al
ret

;******************************************************************************
; Reads sectors
; CX Number of sectors to read
; AX Starting sector
; ES:BX Buffer to read to
;******************************************************************************
ReadSectors:
.NEXTSECTOR:
mov di, 5 ; five retries for error
.LOOP:
push ax
push bx
push cx
call Convert_LBA_to_CHS ; convert starting sector from LBA to CHS
mov ah, 2 ; INT 0x13, AH=2 --> read in CHS mode
mov al, 1 ; read one sector
mov ch, BYTE [Cylinder] ; track/cylinder
mov cl, BYTE [Sector] ; sector
mov dh, BYTE [Head] ; head
mov dl, BYTE [DriveNum] ; drive
int 0x13
jnc .SUCCESS ; check read error
xor ax, ax ; INT 0x13, AH=0 --> reset floppy/hard disk
int 0x13
dec di ; decrement error counter
pop cx
pop bx
pop ax
jnz .LOOP ; read again
int 0x18
.SUCCESS:
mov si, msgProgress
call print_string
pop cx
pop bx
pop ax
add bx, WORD [BytesPerSec] ; queue next buffer
inc ax ; queue next sector
loop .NEXTSECTOR ; read next sector
ret

;******************************************************************************
; Print String
; DS:SI null-terminated string
;******************************************************************************
print_string:
mov ah, 0x0E ; BIOS function 0x0E: teletype
.loop:
lodsb ; grab a byte from SI
test al, al ; NUL?
jz .done ; if the result is zero: get out
int 0x10 ; else: print out the character
jmp .loop
.done:
ret

;******************************************************************************
; Parameters
;******************************************************************************
Sector db 0
Head db 0
Cylinder db 0
bootdevice db 0
datasector dw 0
cluster dw 0
ImageName db "BOOT2 SYS'
msgCRLF db 0x0D, 0x0A, 0
msgProgress db "*', 0
msgLoading db "Loading Second Stage Bootloader', 0x0D, 0x0A, 0
msgFailure db 0x0D, 0x0A, "BOOT2.SYS MISSING', 0x0D, 0x0A, 0

TIMES 510-($-$$) hlt ; fill bytes until boot signature
db 0x55 ; boot signature
db 0xAA ; boot signature
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
; boot.asm
[Bits 16]
org 0x7C00                             ; start address of bootloader
jmp entry_point                        ; jump to bootloader entry point

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Memory Management:
; org                  7C00 (0x00007C00)
; data/extra segments     0
; stack segment        9000 (0x00090000)  
; root dir -> memory   7E00 (0x00007E00)
; boot2    -> memory    500 (0x00000500)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;##############################################################################
; "FAT 12" file system is build up by four areas at Floppy Disk:
; - Boot Sector (also called BIOS Parameter Block, BPB)
; - File Allocation Table, FAT
; - Root Directory
; - Subdirectories and Files

; boot sector info block
; begins 3 bytes from start. A far jump needs 3 bytes.

OperatingSystemName db "PrettyOS'      ;  8 byte
BytesPerSec         dw 512                            ; used in bootloader code
SecPerClus          db 1                              ; used in bootloader code
ReservedSec         dw 1                              ; used in bootloader code
NumFATs             db 2                              ; used in bootloader code
RootEntries         dw 224                            ; used in bootloader code
TotSec              dw 2880                          
MediaType           db 0xF0
FATSize             dw 9                              ; used in bootloader code
SecPerTrack         dw 18                             ; used in bootloader code
NumHeads            dw 2                              ; used in bootloader code
HiddenSec           dd 0
TotSec32            dd 0
DriveNum            db 0                              ; used in bootloader code
Reserved            db 0
BootSig             db 0x29
VolumeSerialNum     dd 0xD00FC0DE      
VolumeLabel         db "PrettyOS   '   ; 11 byte
FileSys             db "FAT12   '      ;  8 byte
;##############################################################################


;******************************************************************************
;    bootloader entry point
;******************************************************************************
entry_point:
    xor     ax, ax                        ; set registers
    mov     ds, ax
    mov     es, ax
    mov     fs, ax
    mov     gs, ax
   
    mov     ax, 0x9000                   ; set the stack
    mov     ss, ax
    xor     sp, sp
         
    mov  [bootdevice], dl              ; store boot device
    mov si, msgLoading
    call print_string

Load_Root_Directory_Table:
    ; compute size of root directory and store in "cx"
    xor cx, cx
    xor dx, dx
    mov ax, 0x20                             ; 32 byte directory entry
    mul WORD [RootEntries]                   ; total size of directory
    div WORD [BytesPerSec]                   ; sectors used by directory
    xchg ax, cx
       
    ; compute location of root directory and store in "ax"
    mov al, BYTE [NumFATs]                    ; number of FATs
    mul WORD [FATSize]                        ; sectors used by FATs
    add ax, WORD [ReservedSec]                ; adjust for bootsector
    mov WORD [datasector], ax                 ; base of root directory
    add WORD [datasector], cx
         
    ; read root directory into memory (7E00h)
    mov bx, 0x7E00                            ; copy root dir above bootcode
    call ReadSectors

;******************************************************************************
;   Find stage2 bootloader
;******************************************************************************
    ; browse root directory for binary image
    mov cx, WORD [RootEntries]                ; load loop counter
    mov di, 0x7E00                            ; locate first root entry
.LOOP:
    push cx
    mov cx, 0xB                               ; name has 11 characters
    mov si, ImageName                         ; look for this image name
    push di
    rep cmpsb                                 ; test for entry match
    pop di
    je Load_FAT
    pop cx
    add di, 0x20                              ; queue next directory entry
    loop .LOOP
    jmp FAILURE

;******************************************************************************
;   Load File Allocation Table (FAT)
;******************************************************************************
Load_FAT:
    ; save starting cluster of boot image
    mov dx, WORD [di + 0x001A]
    mov WORD [cluster], dx                  ; file's first cluster
         
    ; compute size of FAT and store in "cx"
    xor ax, ax
    mov al, BYTE [NumFATs]                  ; number of FATs
    mul WORD [FATSize]                      ; sectors used by FATs
    mov cx, ax

    ; compute location of FAT and store in "ax"
    mov ax, WORD [ReservedSec]              ; adjust for bootsector
         
    ; read FAT into memory (7E00h)
    mov bx, 0x7E00                          ; copy FAT above bootcode
    call ReadSectors

    ; read image file into memory (0500h)
    xor ax, ax
    mov es, ax                              ; destination for image
    mov bx, 0x0500                          ; destination for image
    push bx

;******************************************************************************
;   Load stage2 bootloader
;******************************************************************************
Load_Image:
    mov ax, WORD [cluster]                  ; cluster to read
    pop bx                                  ; buffer to read into
    call Convert_Cluster_to_LBA             ; convert cluster to LBA
    xor cx, cx
    mov cl, BYTE [SecPerClus]               ; sectors to read
    call ReadSectors
    push bx
         
    ; compute next cluster
    mov ax, WORD [cluster]                  ; identify current cluster
    mov cx, ax                              ; copy current cluster
    mov dx, ax                              ; copy current cluster
    shr dx, 1                               ; divide by two
    add cx, dx                              ; sum for (3/2)
    mov bx, 0x7E00                          ; location of FAT in memory
    add bx, cx                              ; index into FAT
    mov dx, WORD [bx]                       ; read two bytes from FAT
    test ax, 1
    jnz .ODD_CLUSTER
         
.EVEN_CLUSTER:
    and dx, 0000111111111111b               ; take low twelve bits
    jmp .DONE
         
.ODD_CLUSTER:
    shr dx, 4                               ; take high twelve bits
         
.DONE:
    mov WORD [cluster], dx                  ; store new cluster
    cmp dx, 0x0FF0                          ; test for end of file
    jb Load_Image
         
DONE:
    mov si, msgCRLF
    call print_string
    mov dl, [bootdevice]
    push WORD 0x0000
    push WORD 0x0500
    retf
         
FAILURE:
    mov si, msgFailure
    call print_string
    mov ah, 0x00
    int 0x16                                ; wait for keypress
    int 0x19                                ; warm boot reset


;******************************************************************************
;   Convert CHS to LBA
;   LBA = (cluster - 2) * sectors per cluster
;******************************************************************************
Convert_Cluster_to_LBA:
    sub ax, 2                               ; zero base cluster number
    xor cx, cx
    mov cl, BYTE [SecPerClus]               ; convert byte to word
    mul cx
    add ax, WORD [datasector]               ; base data sector
    ret

;******************************************************************************
;   Convert LBA to CHS
;   AX    LBA Address to convert
;
;   absolute sector = (logical sector / sectors per track) + 1
;   absolute head   = (logical sector / sectors per track) MOD number of heads
;   absolute track  = logical sector / (sectors per track * number of heads)
;
;******************************************************************************
Convert_LBA_to_CHS :
    xor dx, dx                              ; prepare dx:ax for operation
    div WORD [SecPerTrack]                  ; calculate
    inc dl                                  ; adjust for sector 0
    mov BYTE [Sector], dl
    xor dx, dx                              ; prepare dx:ax for operation
    div WORD [NumHeads]                     ; calculate
    mov BYTE [Head], dl
    mov BYTE [Cylinder], al
    ret

;******************************************************************************
;   Reads sectors
;   CX     Number of sectors to read
;   AX     Starting sector
;   ES:BX  Buffer to read to
;******************************************************************************
ReadSectors:
.NEXTSECTOR:
    mov di, 5                                ; five retries for error
.LOOP:
    push ax
    push bx
    push cx
    call Convert_LBA_to_CHS                  ; convert starting sector from LBA to CHS
    mov  ah, 2                               ; INT 0x13, AH=2 --> read in CHS mode
    mov  al, 1                               ; read one sector
    mov  ch, BYTE [Cylinder]            ; track/cylinder
    mov  cl, BYTE [Sector]           ; sector
    mov  dh, BYTE [Head]             ; head
    mov  dl, BYTE [DriveNum]                 ; drive
    int  0x13                                
    jnc  .SUCCESS                            ; check read error
    xor  ax, ax                              ; INT 0x13, AH=0 --> reset floppy/hard disk
    int  0x13                                
    dec  di                                  ; decrement error counter
    pop  cx
    pop  bx
    pop  ax
    jnz  .LOOP                               ; read again
    int  0x18
.SUCCESS:
    mov  si, msgProgress
    call print_string
    pop  cx
    pop  bx
    pop  ax
    add  bx, WORD [BytesPerSec]              ; queue next buffer
    inc  ax                                  ; queue next sector
    loop .NEXTSECTOR                         ; read next sector
    ret
   
;******************************************************************************
;   Print String  
;    DS:SI   null-terminated string
;******************************************************************************
print_string:
    mov ah, 0x0E      ; BIOS function 0x0E: teletype
.loop:  
    lodsb             ; grab a byte from SI
    test al, al       ; NUL?
    jz .done          ; if the result is zero: get out
    int 0x10          ; else: print out the character
    jmp .loop
.done:
    ret   
   
;******************************************************************************
;    Parameters
;******************************************************************************
Sector         db 0
Head           db 0
Cylinder       db 0   
bootdevice     db 0
datasector     dw 0
cluster        dw 0
ImageName      db "BOOT2   SYS'
msgCRLF        db 0x0D, 0x0A, 0
msgProgress    db "*', 0
msgLoading     db "Loading Second Stage Bootloader', 0x0D, 0x0A, 0
msgFailure     db 0x0D, 0x0A, "BOOT2.SYS MISSING', 0x0D, 0x0A, 0
 
TIMES 510-($-$$) hlt                         ; fill bytes until boot signature
db 0x55                                      ; boot signature
db 0xAA                                      ; boot signature


Any comments?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 09:03:12 01.08.2009, insgesamt 5-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:55:14 02.08.2009   Titel:              Zitieren

Memory Detection klappt nun auch mit dem Second Stage Bootloader, der sich momentan so darstellt:
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
;******************************************************************************
;    boot2.asm
;    Stage2 Bootloader
;******************************************************************************
[Bits 16]
org 0x500
jmp    entry_point             ; go to entry point

;*******************************************************
;    Includes and Defines
;*******************************************************
%include "gdt.inc'            ; GDT definition
%include "A20.inc'            ; A20 gate enabling
%include "Fat12.inc'        ; FAT12 driver
%include "GetMemoryMap.inc' ; INT 0x15, eax = 0xE820

%define IMAGE_PMODE_BASE 0x40000 ; where the kernel is to be loaded to in protected mode
%define IMAGE_RMODE_BASE 0x3000  ; where the kernel is to be loaded to in real mode
ImageName     db "CKERNEL SYS'
ImageSize     dw 0

;*******************************************************
;    Data Section
;*******************************************************
msgLoading db 0x0D, 0x0A, "Jumping to OS Kernel...', 0
msgFailure db 0x0D, 0x0A, "Missing CKERNEL.SYS', 0x0D, 0x0A, 0x0A, 0

entry_point:
    cli                       ; clear interrupts
    xor        ax, ax         ; null segments
    mov        ds, ax
    mov        es, ax
    mov        ss, ax
    mov        sp, 0xFFFF     ; stack begins at 0x9000-0xffff
    sti                       ; enable interrupts

A20:   
    call        EnableA20

;*******************************************************
;   Determine physical memory INT 0x15, eax = 0xE820                    
;   input: es:di -> destination buffer        
;*******************************************************
Get_Memory_Map:
    xor eax, eax
    mov ds, ax
    mov di, 0x1000
    call get_memory_by_int15_e820
    xor ax, ax
    mov es, ax ; important to null es!

Install_GDT:
    call        InstallGDT
    sti   
   
Load_Root:
    call LoadRoot
       mov ebx, 0
       mov ebp, IMAGE_RMODE_BASE
       mov esi, ImageName
    call LoadFile       
       mov DWORD [ImageSize], ecx
    cmp ax, 0
    je EnterProtectedMode
    mov si, msgFailure
    call print_string
    xor ah, ah

;*******************************************************
;   Switch from Real Mode (RM) to Protected Mode (PM)              
;*******************************************************
EnterProtectedMode:
    mov si, msgLoading
    call print_string
   
    ; switch off floppy disk motor
    mov dx,0x3F2      
    mov al,0x0C
    out dx,al        
   
    ; switch to PM
    cli                               ; clear interrupts
    mov    eax, cr0                   ; set bit 0 in cr0--enter pmode
    or    eax, 1
    mov    cr0, eax
    jmp    DWORD CODE_DESC:ProtectedMode     ; far jump to fix CS. Remember that the code selector is 0x8!

[Bits 32]
ProtectedMode:
    mov    ax, DATA_DESC    ; set data segments to data selector (0x10)
    mov    ds, ax
    mov    ss, ax
    mov    es, ax
    mov    esp, 0x9000   

CopyImage:
       mov    eax, DWORD [ImageSize]
       movzx    ebx, WORD  [BytesPerSec]
       mul    ebx
       mov    ebx, 4
       div    ebx
        cld
        mov    esi, IMAGE_RMODE_BASE
        mov    edi, IMAGE_PMODE_BASE
        mov    ecx, eax
        rep    movsd                   ; copy image to its protected mode address

;*******************************************************
;   Execute Kernel
;*******************************************************
EXECUTE:
    jmp DWORD CODE_DESC:IMAGE_PMODE_BASE
       cli
    hlt

   
;*******************************************************
;   calls, e.g. print_string
;*******************************************************
[BITS 16]
print_string:
  lodsb        ; grab a byte from SI
  or al, al    ; logical or AL by itself
  jz .done     ; if the result is zero, get out
  mov ah, 0x0E
  int 0x10       ; otherwise, print out the character!
  jmp print_string
.done:
  ret       
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
;******************************************************************************
; boot2.asm
; Stage2 Bootloader
;******************************************************************************
[Bits 16]
org 0x500
jmp entry_point ; go to entry point

;*******************************************************
; Includes and Defines
;*******************************************************
%include "gdt.inc' ; GDT definition
%include "A20.inc' ; A20 gate enabling
%include "Fat12.inc' ; FAT12 driver
%include "GetMemoryMap.inc' ; INT 0x15, eax = 0xE820

%define IMAGE_PMODE_BASE 0x40000 ; where the kernel is to be loaded to in protected mode
%define IMAGE_RMODE_BASE 0x3000 ; where the kernel is to be loaded to in real mode
ImageName db "CKERNEL SYS'
ImageSize dw 0

;*******************************************************
; Data Section
;*******************************************************
msgLoading db 0x0D, 0x0A, "Jumping to OS Kernel...', 0
msgFailure db 0x0D, 0x0A, "Missing CKERNEL.SYS', 0x0D, 0x0A, 0x0A, 0

entry_point:
cli ; clear interrupts
xor ax, ax ; null segments
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0xFFFF ; stack begins at 0x9000-0xffff
sti ; enable interrupts

A20:
call EnableA20

;*******************************************************
; Determine physical memory INT 0x15, eax = 0xE820
; input: es:di -> destination buffer
;*******************************************************
Get_Memory_Map:
xor eax, eax
mov ds, ax
mov di, 0x1000
call get_memory_by_int15_e820
xor ax, ax
mov es, ax ; important to null es!

Install_GDT:
call InstallGDT
sti

Load_Root:
call LoadRoot
mov ebx, 0
mov ebp, IMAGE_RMODE_BASE
mov esi, ImageName
call LoadFile
mov DWORD [ImageSize], ecx
cmp ax, 0
je EnterProtectedMode
mov si, msgFailure
call print_string
xor ah, ah

;*******************************************************
; Switch from Real Mode (RM) to Protected Mode (PM)
;*******************************************************
EnterProtectedMode:
mov si, msgLoading
call print_string

; switch off floppy disk motor
mov dx,0x3F2
mov al,0x0C
out dx,al

; switch to PM
cli ; clear interrupts
mov eax, cr0 ; set bit 0 in cr0--enter pmode
or eax, 1
mov cr0, eax
jmp DWORD CODE_DESC:ProtectedMode ; far jump to fix CS. Remember that the code selector is 0x8!

[Bits 32]
ProtectedMode:
mov ax, DATA_DESC ; set data segments to data selector (0x10)
mov ds, ax
mov ss, ax
mov es, ax
mov esp, 0x9000

CopyImage:
mov eax, DWORD [ImageSize]
movzx ebx, WORD [BytesPerSec]
mul ebx
mov ebx, 4
div ebx
cld
mov esi, IMAGE_RMODE_BASE
mov edi, IMAGE_PMODE_BASE
mov ecx, eax
rep movsd ; copy image to its protected mode address

;*******************************************************
; Execute Kernel
;*******************************************************
EXECUTE:
jmp DWORD CODE_DESC:IMAGE_PMODE_BASE
cli
hlt


;*******************************************************
; calls, e.g. print_string
;*******************************************************
[BITS 16]
print_string:
lodsb ; grab a byte from SI
or al, al ; logical or AL by itself
jz .done ; if the result is zero, get out
mov ah, 0x0E
int 0x10 ; otherwise, print out the character!
jmp print_string
.done:
ret
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
;******************************************************************************
;    boot2.asm
;    Stage2 Bootloader
;******************************************************************************
[Bits 16]
org 0x500
jmp    entry_point             ; go to entry point

;*******************************************************
;    Includes and Defines
;*******************************************************
%include "gdt.inc'            ; GDT definition
%include "A20.inc'            ; A20 gate enabling
%include "Fat12.inc'        ; FAT12 driver
%include "GetMemoryMap.inc' ; INT 0x15, eax = 0xE820

%define IMAGE_PMODE_BASE 0x40000 ; where the kernel is to be loaded to in protected mode
%define IMAGE_RMODE_BASE 0x3000  ; where the kernel is to be loaded to in real mode
ImageName     db "CKERNEL SYS'
ImageSize     dw 0

;*******************************************************
;    Data Section
;*******************************************************
msgLoading db 0x0D, 0x0A, "Jumping to OS Kernel...', 0
msgFailure db 0x0D, 0x0A, "Missing CKERNEL.SYS', 0x0D, 0x0A, 0x0A, 0

entry_point:
    cli                       ; clear interrupts
    xor        ax, ax         ; null segments
    mov        ds, ax
    mov        es, ax
    mov        ss, ax
    mov        sp, 0xFFFF     ; stack begins at 0x9000-0xffff
    sti                       ; enable interrupts

A20:   
    call        EnableA20

;*******************************************************
;   Determine physical memory INT 0x15, eax = 0xE820                    
;   input: es:di -> destination buffer        
;*******************************************************
Get_Memory_Map:
    xor eax, eax
    mov ds, ax
    mov di, 0x1000
    call get_memory_by_int15_e820
    xor ax, ax
    mov es, ax ; important to null es!

Install_GDT:
    call        InstallGDT
    sti   
   
Load_Root:
    call LoadRoot
       mov ebx, 0
       mov ebp, IMAGE_RMODE_BASE
       mov esi, ImageName
    call LoadFile       
       mov DWORD [ImageSize], ecx
    cmp ax, 0
    je EnterProtectedMode
    mov si, msgFailure
    call print_string
    xor ah, ah

;*******************************************************
;   Switch from Real Mode (RM) to Protected Mode (PM)              
;*******************************************************
EnterProtectedMode:
    mov si, msgLoading
    call print_string
   
    ; switch off floppy disk motor
    mov dx,0x3F2      
    mov al,0x0C
    out dx,al        
   
    ; switch to PM
    cli                               ; clear interrupts
    mov    eax, cr0                   ; set bit 0 in cr0--enter pmode
    or    eax, 1
    mov    cr0, eax
    jmp    DWORD CODE_DESC:ProtectedMode     ; far jump to fix CS. Remember that the code selector is 0x8!

[Bits 32]
ProtectedMode:
    mov    ax, DATA_DESC    ; set data segments to data selector (0x10)
    mov    ds, ax
    mov    ss, ax
    mov    es, ax
    mov    esp, 0x9000   

CopyImage:
       mov    eax, DWORD [ImageSize]
       movzx    ebx, WORD  [BytesPerSec]
       mul    ebx
       mov    ebx, 4
       div    ebx
        cld
        mov    esi, IMAGE_RMODE_BASE
        mov    edi, IMAGE_PMODE_BASE
        mov    ecx, eax
        rep    movsd                   ; copy image to its protected mode address

;*******************************************************
;   Execute Kernel
;*******************************************************
EXECUTE:
    jmp DWORD CODE_DESC:IMAGE_PMODE_BASE
       cli
    hlt

   
;*******************************************************
;   calls, e.g. print_string
;*******************************************************
[BITS 16]
print_string:
  lodsb        ; grab a byte from SI
  or al, al    ; logical or AL by itself
  jz .done     ; if the result is zero, get out
  mov ah, 0x0E
  int 0x10       ; otherwise, print out the character!
  jmp print_string
.done:
  ret       


Test-Download: http://www.henkessoft.de/OS_Dev/Downloads/96.zip
EDIT: includes wurden überarbeitet. Gemeinsames BPB für Stage1 und Stage2 ausgegliedert. Floppy-Motor wurde nun auch ausgeschaltet.

Das ist m.E. eine brauchbare Basis für die weitere Entwicklung. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:30:08 02.08.2009, insgesamt 3-mal bearbeitet
;fricky
Unregistrierter




Beitrag ;fricky Unregistrierter 09:47:49 02.08.2009   Titel:              Zitieren

Erhard Henkes schrieb:

ist es wohl an der Zeit, sich nun den Themen Device-Treiber "Floppy Disk" sowie dem File-Format "FAT 12" zu widmen...

ah, endlich gehts los mit dem OS *daumen_hoch*
kannst ja das hier als grundlage für 'nen FAT-treiber nehmen: http://elm-chan.org/fsw/ff/00index_e.html
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:01:58 02.08.2009   Titel:              Zitieren

Zitat:
endlich gehts los mit dem OS *daumen_hoch*

Ich sagte doch, dass Du etwas Geduld mitbringen musst. Jedes OS wandert im gewissen Sinne durch eine autistische Phase. Bei PrettyOS wurde das durch Verweigern der "Gehhilfe" GRUB noch vertieft. Der Kontakt zur Außenwelt gehört bei vielen Entwürfen im Sinne eines Mikrokernels nicht wirklich zum Systemkern, sondern wird an den User-Space delegiert. Nun wird sich PrettyOS allerdings verstärkt öffnen, sowohl gegenüber dem User als auch dem Computerumfeld. :)

Damit ist allerdings auch die wirklich spannende Phase vorbei.
Nun verstehe ich Autisten. ;)

Danke für den interessanten Link! :live:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 11:43:29 02.08.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:44:21 02.08.2009   Titel:              Zitieren

Nachdem die Version 97 (incl. initrd) überall stabil läuft, habe ich dies nun auch hier beschrieben: http://www.henkessoft.de/OS_Dev/OS_Dev3.htm#mozTocId188479
Zip-Download: http://www.henkessoft.de/OS_Dev/Downloads/97.zip

Besonders interessant finde ich die Analyse der Datenstrukturen auf Diskette mit dem Hex-Editor: http://www.henkessoft.de/OS_Dev/Bilder/FAT12_HexEditor.PNG
Man erkennt sehr schön den Bootsektor, FAT1, FAT2, die Root-Directory und dahinter die Daten. Eine Analyse der Clusterketten in der FAT zeigt die Linked List (folgt noch). Damit wird das Ganze sehr klar und konkret.

Die Basis für die Nachrüstung bezüglich FAT12 ist dieses Tutorial:
http://www.brokenthorn.com/Resources/OSDev6.html

Wenn man nicht auf GRUB umsteigt, lohnt es sich sicher, diesen Code noch etwas zu optimieren.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:53:08 03.08.2009, insgesamt 2-mal bearbeitet
;fricky
Unregistrierter




Beitrag ;fricky Unregistrierter 11:42:15 03.08.2009   Titel:              Zitieren

^^wieso willste eigentlich FAT12 und nicht gleich FAT16 nehmen?
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:42:59 03.08.2009   Titel:              Zitieren

Na ja, ich überlasse die Formatierung noch MS Windows. Der Format-Befehl von MS Windows 98, ME und XP wird eine Diskette immer mit FAT12 und nur alle anderen Laufwerke mit FAT32 bzw. NTFS formatieren. Der Format-Befehl von MS DOS und MS Windows 95A, der nur FAT12 und FAT16 kennt, formatiert eine Diskette mit FAT12 und alle anderen Laufwerke mit FAT16. Daher ist FAT12 das zu erwartende Format, in der unsere Daten mit einem copy BOOT2.SYS A:\BOOT2.SYS bzw. copy CKERNEL.SYS A:\CKERNEL.SYS auf Diskette übertragen und dort abgelegt werden. Mir gefällt das Umgehen mit halben Bytes auch nicht, wäre bei 16 Bit einfacher. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:04:21 03.08.2009   Titel:              Zitieren

Ich habe nun noch diese Abbildung hinzugefügt, damit die - prinzipiell einfachen - Zusammenhänge und Berechnungsformeln klar werden: http://www.henkessoft.de/OS_Dev/Bilder/FAT1_FAT2_Root.PNG

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
n1
Unregistrierter




Beitrag n1 Unregistrierter 10:08:09 04.08.2009   Titel:              Zitieren

Ich habe gerade mal etwas in dem Tutorial gelesen über das OS und hab mir mal aus spass direkt das Programm Bochs runtergeladen ( hab zwar noch n Disketten Laufwerk aber die Diskette sind nicht mehr so gut ^^ ) funktionierte auch sofort alles mit dem Kernel.bin am Anfang.

Aber jetzt würde mich mal interessieren wie viele Leute an dem Tutorial mit arbeiten, das ist ja wahnsinn wie viel da steht da kann man eine menge lernen.
coercedcommission
Unregistrierter




Beitrag coercedcommission Unregistrierter 15:58:30 04.08.2009   Titel:              Zitieren

n1 schrieb:
Ich habe gerade mal etwas in dem Tutorial gelesen über das OS und hab mir mal aus spass direkt das Programm Bochs runtergeladen ( hab zwar noch n Disketten Laufwerk aber die Diskette sind nicht mehr so gut ^^ ) funktionierte auch sofort alles mit dem Kernel.bin am Anfang.

Aber jetzt würde mich mal interessieren wie viele Leute an dem Tutorial mit arbeiten, das ist ja wahnsinn wie viel da steht da kann man eine menge lernen.

naja das sind doch alles basics, die lernst du in jedem informatik erstsemester :-)
n1
Unregistrierter




Beitrag n1 Unregistrierter 18:57:01 04.08.2009   Titel:              Zitieren

O_o Glaub ich nicht^^
Tobiking2
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 705
Beitrag Tobiking2 Mitglied 19:51:54 04.08.2009   Titel:              Zitieren

n1 schrieb:
O_o Glaub ich nicht^^


Die Theorie wird schon in den ersten beiden Semestern behandelt. Dabei wird nur nicht auf technische Besonderheiten einer bestimmten Architektur eingegangen. Aufbau/Funktionsweise einer CPU, Assembler (nicht unbedingt x86), Speicher-/Ressourcenmanagement, Scheduling, sind alles Themen die dran kommen.


Zuletzt bearbeitet von Tobiking2 am 19:52:40 04.08.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:42:24 04.08.2009   Titel:              Zitieren

Zitat:
Aber jetzt würde mich mal interessieren wie viele Leute an dem Tutorial mit arbeiten

Ich arbeite bisher alleine an diesem Tutorial, seit etwa Mitte März diesen Jahres. Schön wäre es, wenn sich so eine Art OS Community bilden würde, habe diesbezüglich aber keine klaren Vorstellungen.

Zitat:
naja das sind doch alles basics, die lernst du in jedem informatik erstsemester :-)


Man hört zumindest davon. Ob man es rein theoretisch versteht, ist allerdings eine andere Sache. Aus den flüchtigen Universitäts-Skripten, die man so im Internet findet, könnte ich allerdings kein OS zimmern. Selbst mit dem Tanenbaum in der Hand ist dies nicht möglich. Man benötigt "echte" Vorbilder. Linux hatte Minix, DOS hatte CP/M als Vorbild, so sieht das aus. ;)

Mich freut es, wenn ich mitbekomme, dass junge Leute mit etwa 13 - 15 Jahren diesbezüglich konkret los legen und nicht nur zu Konsumenten von fertigen OS, Programmen und Spielen werden. Ich denke dies ist die Hauptzielgruppe. Daher schreibe ich das Tutorial auch in Deutsch und nicht in Englisch. ;)

Zitat:
Die Theorie wird schon in den ersten beiden Semestern behandelt. Dabei wird nur nicht auf technische Besonderheiten einer bestimmten Architektur eingegangen.


Die technischen Besonderheiten, gerade bei 80x86, sind aber genau der Clou! Grau, grau ist alle Theorie. :D

Ich würde übrigens empfehlen, parallel mit der Programmierung eines kleinen "Roboters" wie ASURO oder Nibo zu beginnen, damit man auch µC als Vergleich kennen lernt:
http://www.henkessoft.de/Roboter/ASURO.htm
http://www.henkessoft.de/Roboter/Nibo.htm

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:21:54 04.08.2009, insgesamt 4-mal bearbeitet
Cox
Unregistrierter




Beitrag Cox Unregistrierter 21:36:35 04.08.2009   Titel:              Zitieren

Ich weiß, dass das Thema hier zu genüge durchgekaut wurde. Aber gerade ich als jemand, der in deiner Zielgruppe liegt, frage ich mich doch, ob es denn gerade so sinnvoll ist, ständig vom eigentlichen Kern abzulenken, nur weil der liebe x86er unbedingt auf seine Extrawurst besteht.
Das Anschalten des A20-Gates - beispielsweise - könnte sich, ob der nicht unbedingt offensichtlichen Notwendigkeit dieses Gefrickels, für so manchen zum Stolperstein entwickeln. In dieselbe Nische schlägt da auch das gesamte Umschalten zwischen PM / RM usw. usf.
Trotzdem muss ich dir ein dickes Lob aussprechen.
Dein Tutorial ist eine unglaublich willkommene Abwechslung zu den teilweise sehr schwer auffindbaren und verstreuten Informationen zum Thema im Netz.
Weiter so :live:
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:58:20 04.08.2009   Titel:              Zitieren

Danke für das positive Feedback! Es ist eine abwechslungsreiche und interessante Materie, aber auch verflixt viel Arbeit, die Zusammenhänge verständlich und dennoch auf das Wesentliche konzentriert darzustellen. Für konkrete konstruktive Anregungen bin ich dankbar.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Cox
Unregistrierter




Beitrag Cox Unregistrierter 22:36:12 04.08.2009   Titel:              Zitieren

Zitat:
Für konkrete konstruktive Anregungen bin ich dankbar.
In Sachen fachlicher Korrektheit kann dir die "Forenprominenz" ja bestens zur Seite stehen. Was das Hauptproblem der Didaktik angeht, so kann ich eigentlich keine wirklichen Kritikpunkte finden. Allgemein würde ich dir - zumindest was meinen Standpunkt angeht - dazu raten, nicht mit Theorie und Hintergrundinformation zu geizen. Absätze überspringen und im Notfall nachlesen kann man jederzeit, aber nichts ärgert mich mehr, als wenn ein Detail ungeklärt bleibt oder nicht erwähnt wird.
schön_wäre_es.
Unregistrierter




Beitrag schön_wäre_es. Unregistrierter 22:54:06 04.08.2009   Titel:              Zitieren

Tobiking2 schrieb:
Dabei wird nur nicht auf technische Besonderheiten einer bestimmten Architektur eingegangen.

ach das wär zu schön. schätzungsweise 90% der dozenten, die diese dinge lehren, haben ihr skript, was sie ca. 1983 kompiliert haben, worin sie die studenten mit gelaber über uralten x86 kram wie real mode, protected mode, xms, x86 isa und co nerven :-/ die meisten dozenten sind leider vor 20 jahren in der zeit stehen geblieben, als sie selbst das letzte mal irgendwas programmiert haben :-/
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:19:14 04.08.2009   Titel:              Zitieren

Zitat:
die meisten dozenten sind leider vor 20 jahren in der zeit stehen geblieben
So etwas ist eine Schande für unser Ausbildungssystem! :(
Für was zahle ich denn Unmengen von Steuern? Diesen Damen und Herren müsst ihr mal richtig Bescheid stoßen.

Die Abwehr gegen den "x86 Kram" finde ich prinzipiell unberechtigt, denn diese CPUs beherrschen heute immer noch den PC-Markt, nun in 64-Bit-Qualität, was die ganze Sache noch mehr verkompliziert. Ich fände eine vergleichende konkrete Darstellung der Pros und Cons sinnvoll mit Blick auf Windows, Linux, Symbian OS und einem Roboter-Betriebssystem.

Mit "abstrakter" Software kann man zunächst wenig bewegen. Zum Schluss müssen immer auch die "Basics" bedient werden, und diese sind zumeist komplex, weil diese wirtschaftlich und nicht didaktisch getrieben sind, eben Bit-Gefrickel.

Mir geht es bei meinem Tutorial darum, dass man alles praktisch durchführen und analysieren kann, was zu einem grundlegenden OS dazu gehört, vom Bootloader angefangen bis hin zum Dateisystem. Dinge wie kompliziertes Scheduling oder Deadlock-Verhindern kann man im Tanenbaum sehr gut nachlesen und bei einem einfacheren System leicht nachrüsten.

Die größten Probleme bereitet in der Regel der Umgang mit Assemblercode oder das Präparieren von Stacks, soweit ich das bisher sehen kann. Treiber- oder User-Space-Programmierung ist eher Fleissarbeit.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:56:04 04.08.2009, insgesamt 4-mal bearbeitet
Tobiking2
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 705
Beitrag Tobiking2 Mitglied 00:26:29 05.08.2009   Titel:              Zitieren

Zitat:
Die technischen Besonderheiten, gerade bei 80x86, sind aber genau der Clou! Grau, grau ist alle Theorie. :D


Man braucht aber zum verstehen von Paging nicht zu wissen, welches Bit in welchem Register gesetzt werden muss, um es beim x86 zu aktivieren. Es ist natürlich in einem Tutorial wie deinem wichtig zu erwähnen, aber wer selber ein Betriebsystem schreibt und nicht auf ein Tutorial aufbaut, kann sich das auch aus dem Intel Manual oder aus einem der recht guten Wikis zu dem Thema raussuchen. Das sehe ich noch nicht als spannend an. Zu dem Wechsel in den PM dürften sich auch schon genug negativ geäußert haben. :D

Ich find dann erst wieder interessant, wie die verschiedenen Techniken dann in der Praxis wirklich genutzt werden. Das steht dann aber auch oft im Tanenbaum. Ich denke zudem schon das man mit soliden Assembler/C Kenntnissen, dem Tanenbaum und dem Intel Manual ein Betriebsystem schreiben könnte. Es kann ja nicht jeder irgendwo abgucken, irgendwer muss angefangen haben. :D

Die Zielgruppe 13-15 find ich etwas niedrig. Den meisten dürfte es selbst mit dem Tutorial an Vorwissen fehlen und es endet mit stumpfen copy and paste.

Zitat:
Daher schreibe ich das Tutorial auch in Deutsch und nicht in Englisch. ;)


Und wieso kommentierst du den Code (vor allem die Codebeispiele) auf Englisch und nicht auf Deutsch? ;)

Zitat:
ach das wär zu schön. schätzungsweise 90% der dozenten, die diese dinge lehren, haben ihr skript, was sie ca. 1983 kompiliert haben, worin sie die studenten mit gelaber über uralten x86 kram wie real mode, protected mode, xms, x86 isa und co nerven :-/ die meisten dozenten sind leider vor 20 jahren in der zeit stehen geblieben, als sie selbst das letzte mal irgendwas programmiert haben :-/


Wir haben teilweise Glück gehabt. Die Hardware Grundlagen kamen von einem Dozenten der am Lehrstuhl Eingebettete Systeme tätig ist. Das ist warscheinlich der Grund dafür gewesen, dass wir jedes mal MIPS als Referenzarchitektur genommen haben wenn etwas konkret behandelt wurde.

Die Betriebsystem Vorlesung war dafür dann das Tanenbaum Buch in Kurzform. Sogar die Folien waren original von Tanenbaum auf Englisch und zwischendurch mal ein Deutscher Satz als Zusatz drunter gesetzt.

Zitat:
So etwas ist eine Schande für unser Ausbildungssystem! :(
Für was zahle ich denn Unmengen von Steuern? Diesen Damen und Herren müsst ihr mal richtig Bescheid stoßen.


Ich zahl sogar noch 500 Euro pro Semester an Studiengebühren...
s_o_y_t_t_e_r_p
Unregistrierter




Beitrag s_o_y_t_t_e_r_p Unregistrierter 08:10:14 05.08.2009   Titel:              Zitieren

Zitat:
es endet mit stumpfen copy and paste
Das ist erstmal nicht schlimm. Man will sehen, dass etwas geht, bevor man sich tiefer beschäftigt. RM->PM ist blöd, dass BIOS weg ist. Gibt es da keinen Weg, das doch noch zu nutzen? Einschalten A20 kopiert man einfach, basta. Interessant ist Einsatz von FAT12, hoffentlich bald USB, wäre toll. :)

Tutorial ist bisher glaube ich bestes, was es gibt in deutsch, oder? :confused:
Student2.0
Unregistrierter




Beitrag Student2.0 Unregistrierter 10:00:28 05.08.2009   Titel:              Zitieren

Tobiking2: ja dan hattest du wohl Glück. Ich verstehe auch nicht, warum nicht mehr Dozenten einfach auf die wirklich gute Literatur wie Tanenbaum, Silberschatz und Co. zurückgreifen, die es zu diesem Thema ja zur Genüge gibt. Viele Dozenten haben stattdessen ihr didaktisch absolut miserabel gestaltetes Skript, was zusätzlich halt veraltet ist. Schade, daß die Dozenten so ziemlich in jeder Hinsicht tun und lassen können, was sie wollen. Da sollte es mal mehr Vorgaben geben oder so :o
hi_
Unregistrierter




Beitrag hi_ Unregistrierter 12:59:37 05.08.2009   Titel:              Zitieren

Mich würde interessieren, welches Skript zum Thema OS Development das beste an der Hochschule ist.
;fricky
Unregistrierter




Beitrag ;fricky Unregistrierter 13:09:01 05.08.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Die Abwehr gegen den "x86 Kram" finde ich prinzipiell unberechtigt, denn diese CPUs beherrschen heute immer noch den PC-Markt, nun in 64-Bit-Qualität, was die ganze Sache noch mehr verkompliziert. Ich fände eine vergleichende konkrete Darstellung der Pros und Cons sinnvoll mit Blick auf Windows, Linux, Symbian OS und einem Roboter-Betriebssystem.

der 'x86-kram' stellt aber eine äusserst miserabel zusammengeflickte architektur dar (im vergleich z.b. zu ARM-systemen). das design der ersten X86-CPUs war nun mal nicht darauf ausgelegt, immer neue derivate (bis in die heutige zeit) hervorzubringen. dementsprechenden haben wir heute übelsten pfusch in unserern PCs.

Erhard Henkes schrieb:

Mit "abstrakter" Software kann man zunächst wenig bewegen. Zum Schluss müssen immer auch die "Basics" bedient werden, und diese sind zumeist komplex, weil diese wirtschaftlich und nicht didaktisch getrieben sind, eben Bit-Gefrickel.

deshalb sollte man auch besser 'hardware abstraction layer' einsetzen, im einfachsten fall I/O-bitgefummel über makros machen und für komplexere komponenten (z.b. die RTC, RS232, speichermedien usw.) treiber mit 'nem einheitlichen interface schreiben. sowas wie scheduling-algorithmus, exception und interrupt-handling z.b. kann man in portablem C coden, wobei nur sehr wenig plattformabhängiger assembler-code verwendet werden muss (den man hinter funktionen verstecken kann, z.b. switch_context()). wenn ich z.b. so'n tutorial wie deins (bis jetzt) machen würde, dann würde ich es nicht 'betriebssystementwicklung' sondern eher 'programmierung unter nackten x86 systemen' o.ä. nennen.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 17:30:30 05.08.2009   Titel:              Zitieren

Zitat:
der 'x86-kram' stellt aber eine äusserst miserabel zusammengeflickte architektur dar (im vergleich z.b. zu ARM-systemen). das design der ersten X86-CPUs war nun mal nicht darauf ausgelegt, immer neue derivate (bis in die heutige zeit) hervorzubringen. dementsprechenden haben wir heute übelsten pfusch in unserern PCs.
Du kennst die ARM-Systeme in 20 Jahren noch nicht, kann genau so enden wie bei x86. Nennt sich Abwärtskompatibilität.

Zitat:
programmierung unter nackten x86 systemen

Schöner Titel. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 17:31:46 05.08.2009, insgesamt 1-mal bearbeitet
;fricky
Unregistrierter




Beitrag ;fricky Unregistrierter 22:03:38 05.08.2009   Titel:              Zitieren

Erhard Henkes schrieb:

Du kennst die ARM-Systeme in 20 Jahren noch nicht, kann genau so enden wie bei x86. Nennt sich Abwärtskompatibilität.

naja, wenn die ARMs nicht mehr mit zusätzlichen befehlen und macrocells erweitert werden können (z.b. die normalen register R0...R15 auf 64 bits aufgebläht werden o.ä. x86-krankheiten), dann ist's wohl auch damit vorbei. *heul*
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:49:06 05.08.2009   Titel:              Zitieren

Ich habe den gut strukturierten FAT12-Floppy-Treiber von www.brokenthorn.com ,Tut20, Demo15 an PrettyOS angeflanscht, um zu sehen, ob unser OS möglichst leicht neue fremde Teile aufnehmen kann. Dies hat erstaunlich gut geklappt: http://www.henkessoft.de/OS_Dev/Downloads/98.zip
In dieser Version 98 wird der (Boot-)Sektor 0 (bei null beginnende LBA-Zählweise) von Floppy Disk testweise mittels DMA gelesen und auf dem Bildschirm ausgegeben. :)

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    /// //////////////////////// TEST FLOPPY DRIVER
    printformat("\nFloppy Driver Test!\n");
    flpydsk_set_working_drive(0); // set drive 0 as current drive
    flpydsk_install(6);           // install floppy disk to IRQ 6
    ULONG sectornum = 0;
    unsigned char* sector = 0;
    printformat("\nSector %d contents:\n\n", sectornum);
    sector = flpydsk_read_sector( sectornum );
    if(sector)
    {
        int i=0;
        int c,j;
        for(c=0; c<4; ++c)
        {
            for(j=0; j<128; ++j)
                printformat("%d ", sector[i+j]);
            i+=128;
            sleepSeconds(10);
            printformat("\n\n");
        }
    }
    else
        printformat("\n*** Error reading sector from disk");
    printformat("\nDone.\n");
    /// //////////////////////// TEST FLOPPY
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/// //////////////////////// TEST FLOPPY DRIVER
printformat("\nFloppy Driver Test!\n");
flpydsk_set_working_drive(0); // set drive 0 as current drive
flpydsk_install(6); // install floppy disk to IRQ 6
ULONG sectornum = 0;
unsigned char* sector = 0;
printformat("\nSector %d contents:\n\n", sectornum);
sector = flpydsk_read_sector( sectornum );
if(sector)
{
int i=0;
int c,j;
for(c=0; c<4; ++c)
{
for(j=0; j<128; ++j)
printformat("%d ", sector[i+j]);
i+=128;
sleepSeconds(10);
printformat("\n\n");
}
}
else
printformat("\n*** Error reading sector from disk");
printformat("\nDone.\n");
/// //////////////////////// TEST FLOPPY
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    /// //////////////////////// TEST FLOPPY DRIVER
    printformat("\nFloppy Driver Test!\n");
    flpydsk_set_working_drive(0); // set drive 0 as current drive
    flpydsk_install(6);           // install floppy disk to IRQ 6
    ULONG sectornum = 0;
    unsigned char* sector = 0;
    printformat("\nSector %d contents:\n\n", sectornum);
    sector = flpydsk_read_sector( sectornum );
    if(sector)
    {
        int i=0;
        int c,j;
        for(c=0; c<4; ++c)
        {
            for(j=0; j<128; ++j)
                printformat("%d ", sector[i+j]);
            i+=128;
            sleepSeconds(10);
            printformat("\n\n");
        }
    }
    else
        printformat("\n*** Error reading sector from disk");
    printformat("\nDone.\n");
    /// //////////////////////// TEST FLOPPY

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:25:14 06.08.2009, insgesamt 5-mal bearbeitet
Nobuo T
Moderator

Benutzerprofil
Anmeldungsdatum: 09.10.2001
Beiträge: 4737
Beitrag Nobuo T Moderator 01:26:48 06.08.2009   Titel:              Zitieren

;fricky schrieb:
Erhard Henkes schrieb:

Du kennst die ARM-Systeme in 20 Jahren noch nicht, kann genau so enden wie bei x86. Nennt sich Abwärtskompatibilität.

naja, wenn die ARMs nicht mehr mit zusätzlichen befehlen und macrocells erweitert werden können (z.b. die normalen register R0...R15 auf 64 bits aufgebläht werden o.ä. x86-krankheiten), dann ist's wohl auch damit vorbei. *heul*
:)

Tja, keine Architektur lebt ewig. Dann lieber einmal komplett from scratch ueberholen.
Richtig schlimm wird es doch erst, wenn tausend neue obskure Register, krumme OpCodes und irgendwelche (Kompatibilitaets)Modi eingefuehrt werden. :die:

_________________
==Mod im Assembler-Forum==

http://z0r.de/2908
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 08:53:59 06.08.2009   Titel:              Zitieren

Ich bin noch nicht lange dabei beim OSDEV (genau genommen ernsthaft seit dem 13.03.2009, siehe Beginn dieses Threads), mache es auch nur aus grundlegendem Interesse, spielerischer Neugier und basierend auf dem Wunsch, die Dinge möglichst knapp, bildhaft und vor allem praktisch umsetzbar zu erklären. Denn ich denke, dass die Einstiegshürde relativ hoch ist. Da gehören beim x86 das A20-Gate und der Umstieg von RM nach PM dazu. Mir persönlich ist z.B. das Multitasking schwer gefallen, bis ich eine brauchbare Vorgehensweise bei tyndur fand. Auch das Paging bei x86 hat mich oft durcheinander gebracht. Das Wichtigste beim OSDEV ist, dass man "dran" bleibt. Das ist kein Thema für ein Wochenende, sondern ein mehrjähriges Projekt, also nur etwas für Leute, die sich in etwas "hinein bohren" können und wollen und dann auch nicht los lassen, wenn es zäh und holprig wird.

Wenn man aber über diese Einstiegshürde hinweg ist, dann ist es wie beim Tanzen: Man hat Lust dem eigenen Repertoire ab und zu eine neue Figurabfolge hinzu zu fügen. ;)

Hier z.B. das Lesen von Sektoren von Floppy Disk im Kernel:
http://www.henkessoft.de/OS_Dev/OS_Dev3.htm#mozTocId967150
Diesbezüglich ist mir wichtig, dass ich solche externen Module möglichst einfach an PrettyOS anflanschen kann. Bezüglich IRQ-Interface ist unser Aufbau hier einfacher und damit eleganter, so dass man einiges einfach weglassen konnte.

Ich kann nur hoffen, dass ich mit meinem Tutorial im deutschen Sprachraum etwas dazu beitrage, dass Einsteiger in diese absolut empfehlenswerte Materie schnell praktische Erfolgserlebnisse haben. Das würde mich freuen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 10:50:19 06.08.2009, insgesamt 5-mal bearbeitet
´´
Unregistrierter




Beitrag ´´ Unregistrierter 10:51:06 06.08.2009   Titel:              Zitieren

wirst du denn auch versuchen windows und linux konkurrenz zu machen?
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 10:53:45 06.08.2009   Titel:              Zitieren

Mal eine ganz andere Diskussion: Das Blöde und vielleicht zur Zeit dennoch Gute an Computern ist, dass man sie nicht individualisieren kann. Was müsste passieren, um PrettyOS ein lernfähiges oder zumindest adaptives Interface zum User zu verpassen? Ich denke mal, das gehört in den Bereich Shell / User-Space. Gibt es da schon Beispiele?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:21:12 06.08.2009   Titel:              Zitieren

Zitat:
wirst du denn auch versuchen windows und linux konkurrenz zu machen?


http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId533656
Zitat:
Als Gegenleistung bekommt man in der Regel nur den Genuss der intellektuellen Herausforderung, denn gegen MS Windows, Linux oder andere etablierte OS anzutreten, hat sicher keine Einzelperson vor. Wozu sollte das auch gut sein?


MS Windows ist ein hoch-professionelles OS mit Millionen von Code-Zeilen und Heerscharen von Fulltime-Planern, -Codern, -Testern. Linux, das ich bewundere, aber ungern selbst verwende, schafft es kaum, mit diesem Giganten aus USA mitzuhalten.

Nachdem nun die Grundlagen auf Basis x86 dargestellt wurden, würde es mich reizen, auf der User-Ebene etwas Neues zu schaffen, das in Richtung KI geht. Alleine kann ich allerdings nur Impulse setzen. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
u_ser-l
Unregistrierter




Beitrag u_ser-l Unregistrierter 14:00:28 06.08.2009   Titel:   re            Zitieren

Erhard Henkes schrieb:
Linux, das ich bewundere, aber ungern selbst verwende, schafft es kaum, mit diesem Giganten aus USA mitzuhalten.

http://www.top500.org/stats/list/33/osfam
hack0r
Unregistrierter




Beitrag hack0r Unregistrierter 14:27:19 06.08.2009   Titel:   Re: re            Zitieren

u_ser-l schrieb:
Erhard Henkes schrieb:
Linux, das ich bewundere, aber ungern selbst verwende, schafft es kaum, mit diesem Giganten aus USA mitzuhalten.

http://www.top500.org/stats/list/33/osfam

Das sagt leider rein gar nichts über die Code Qualität des Linux Kernels und die nicht gerade vertrauenserweckenden Praktiken des Maintainerteams (Kindergarten!) aus. Ich bin zwar auch ein Fan von Linux, aber ob der Kernel so gut und objektorientiert ist, wie der von Wind00f, da habe ich meine Zweifel.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:11:11 06.08.2009   Titel:              Zitieren

Zur Zeit freue ich mich aber noch über jeden kleinen Schritt, z.B. dass es mir gelungen ist, die Floppy-Sektor-Read-Funktion mit einigen Änderungen auch zu einer zusätzlichen Sektor-Write-Funktion umzuwandeln (alles via DMA). Nun habe ich endlich einen zweiten Ausgabekanal neben dem Bildschirm, allerdings noch rein binär. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
u_ser-l
Unregistrierter




Beitrag u_ser-l Unregistrierter 22:08:15 06.08.2009   Titel:   re            Zitieren

hack0r schrieb:

Das sagt leider rein gar nichts über die Code Qualität des Linux Kernels und die nicht gerade vertrauenserweckenden Praktiken des Maintainerteams (Kindergarten!) aus.



[Ironie on:]

klar - der durchschnittliche Ottonormal-User ist ja in der Wahl seines OS auch kompetenter als der Architekt von mio. $ teurer Hardware in der Spitzenforschung.

[Ironie off:]
Cox
Unregistrierter




Beitrag Cox Unregistrierter 00:05:22 07.08.2009   Titel:              Zitieren

Zitat:
aber ob der Kernel so gut und objektorientiert ist, wie der von Wind00f, da habe ich meine Zweifel.

Ersteres ist hoffentlich ein (schlechter) Witz, und Letzteres ist absolut nicht abzusehen, es sei denn, du verdienst deinen Lebensunterhalt bei jenem mittelständigschem Unternehmen aus Redwood...
Ach kommt, bitte kein Linux vs. Windows Geflame hier. Das Tutorial mal "Linux-kompatibel" zu machen hätte zwar was für sich, aber wenn der Autor nun einmal Windows einsetzt , dann ist das halt so.

Edit:
Sehr richtig. Deshalb werde ich auch alles Weitere in Richtung dieser "Diskussion" loeschen.


Zuletzt bearbeitet von Nobuo T am 11:24:15 07.08.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 17:41:02 08.08.2009   Titel:              Zitieren

Ich habe momentan das Problem, das zwei Sektoren anstelle von einem Sektor geschrieben wird. Wo wird die Zahl der Sektoren bezüglich DMA genau gesteuert?
http://lowlevel.brainsware.org/forum/index.php?topic=2244.0
http://www.henkessoft.de/OS_Dev/Downloads/100.zip
Vielleicht kann jemand helfen? Die Daten werden via DMA gelesen/geschrieben (0x1000 als Puffer).

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:13:14 08.08.2009, insgesamt 1-mal bearbeitet
;fricky
Unregistrierter




Beitrag ;fricky Unregistrierter 21:44:50 08.08.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Ich habe momentan das Problem, das zwei Sektoren anstelle von einem Sektor geschrieben wird.

teste die read/write funktionen separat. wird wirklich nur ein sektor (512 bytes) beschrieben und gelesen (benutze ein externes programm, z.b. 'nen disk-editor wie z.b. 'winhex' zur prüfung)?
falls nicht, schau im user manual des DMA-controllers nach. vielleicht transfererierst du 16-bit words anstelle von bytes oder sowas.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:48:23 09.08.2009   Titel:              Zitieren

siehe: http://lowlevel.brainsware.org/forum/index.php?topic=2244.0

DMA -> floppy sollte track-weise (nicht sektor-weise, ist mir inzwischen klar) erfolgen. Das klappt aber leider noch nicht, obwohl alle Einstellungen nun - soweit ich das recherchieren kann - in Ordnung sein sollten.

Teste das z.B. mit: (zielend auf format a: )
C/C++ Code:
    k_memset((void*)0x1000, 0xF6, 0x2400);
    for( i=33; i<=2847; i+=17 )
    {
        printformat("%d ",i);
        flpydsk_write_sector(i);
    }
C/C++ Code:
k_memset((void*)0x1000, 0xF6, 0x2400);
for( i=33; i<=2847; i+=17 )
{
printformat("%d ",i);
flpydsk_write_sector(i);
}
C/C++ Code:
    k_memset((void*)0x1000, 0xF6, 0x2400);
    for( i=33; i<=2847; i+=17 )
    {
        printformat("%d ",i);
        flpydsk_write_sector(i);
    }

Klappt aber nicht lückenlos. Es werden weniger als 18 Sektoren geschrieben. Die 17 hatte ich schon gewählt, weil in einem Fall waren es immer eins zu wenig. Seltsame Geschichte.

Hier die wichtigsten Code-Fragmente:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// initialize DMA to use physical address 84k-128k
void flpydsk_initialize_dma()
{
    outportb(0x0a, 0x06);    //mask dma channel 2
    outportb(0xd8, 0xFF);    //reset master flip-flop
    outportb(0x04, 0x00);   //address=0x1000
    outportb(0x04, 0x10);
    outportb(0xd8, 0xFF);   //reset master flip-flop
    outportb(0x05, 0xFF);   //count to 0x23FF (number of bytes in a 3.5" floppy disk track: 18*512)
    outportb(0x05, 0x23);

    outportb(0x81, 0x00);   //external page register = 0
    outportb(0x0a, 0x02);   //unmask dma channel 2
}

// prepare the DMA for write transfer
void flpydsk_dma_write()
{
    outportb(0x0a, 0x06); //mask dma channel 2
    outportb(0x0b, 0x5A); //single transfer, address increment, autoinit, write, channel 2
    outportb(0x0a, 0x02); //unmask dma channel 2
}

// convert LBA to CHS
void flpydsk_lba_to_chs(int lba, int* head, int* track, int* sector)
{
   *track  =   lba / ( FLPY_SECTORS_PER_TRACK * 2 );
   *head   = ( lba % ( FLPY_SECTORS_PER_TRACK * 2 ) ) / ( FLPY_SECTORS_PER_TRACK );
   *sector = ( lba % ( FLPY_SECTORS_PER_TRACK * 2 ) ) % FLPY_SECTORS_PER_TRACK + 1;
}

// write a sector
void flpydsk_write_sector_imp(unsigned char head, unsigned char track, unsigned char sector)
{
    ULONG st0, cyl;
    flpydsk_dma_write(); // set the DMA for write transfer

    flpydsk_send_command( FDC_CMD_WRITE_SECT | FDC_CMD_EXT_MULTITRACK | FDC_CMD_EXT_DENSITY );  // write a sector
    flpydsk_send_command( head << 2 | _CurrentDrive );
    flpydsk_send_command( track);
    flpydsk_send_command( head);
    flpydsk_send_command( sector);
    flpydsk_send_command( FLPYDSK_SECTOR_DTL_512 );
    flpydsk_send_command( ( ( sector + 1 ) >= FLPY_SECTORS_PER_TRACK ) ? FLPY_SECTORS_PER_TRACK : sector + 1 );
    flpydsk_send_command( FLPYDSK_GAP3_LENGTH_3_5 );
    flpydsk_send_command( 0xFF );

    flpydsk_wait_irq();

    int j;
    for(j=0; j<7; ++j)
        flpydsk_read_data();      // read status info
    flpydsk_check_int(&st0,&cyl); // let FDC know we handled interrupt
}

// write a sector
int flpydsk_write_sector(int sectorLBA)
{
    if (_CurrentDrive >= 4) return -1;
    // convert LBA sector to CHS
    int head=0, track=0, sector=1;
    flpydsk_lba_to_chs(sectorLBA, &head, &track, &sector);
    // turn motor on and seek to track
    flpydsk_control_motor(TRUE);
    if(flpydsk_seek (track, head)) return -2;
    // write sector and turn motor off
    flpydsk_write_sector_imp(head, track, sector);
    flpydsk_control_motor(FALSE);
    return 0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// initialize DMA to use physical address 84k-128k
void flpydsk_initialize_dma()
{
outportb(0x0a, 0x06); //mask dma channel 2
outportb(0xd8, 0xFF); //reset master flip-flop
outportb(0x04, 0x00); //address=0x1000
outportb(0x04, 0x10);
outportb(0xd8, 0xFF); //reset master flip-flop
outportb(0x05, 0xFF); //count to 0x23FF (number of bytes in a 3.5" floppy disk track: 18*512)
outportb(0x05, 0x23);

outportb(0x81, 0x00); //external page register = 0
outportb(0x0a, 0x02); //unmask dma channel 2
}

// prepare the DMA for write transfer
void flpydsk_dma_write()
{
outportb(0x0a, 0x06); //mask dma channel 2
outportb(0x0b, 0x5A); //single transfer, address increment, autoinit, write, channel 2
outportb(0x0a, 0x02); //unmask dma channel 2
}

// convert LBA to CHS
void flpydsk_lba_to_chs(int lba, int* head, int* track, int* sector)
{
*track = lba / ( FLPY_SECTORS_PER_TRACK * 2 );
*head = ( lba % ( FLPY_SECTORS_PER_TRACK * 2 ) ) / ( FLPY_SECTORS_PER_TRACK );
*sector = ( lba % ( FLPY_SECTORS_PER_TRACK * 2 ) ) % FLPY_SECTORS_PER_TRACK + 1;
}

// write a sector
void flpydsk_write_sector_imp(unsigned char head, unsigned char track, unsigned char sector)
{
ULONG st0, cyl;
flpydsk_dma_write(); // set the DMA for write transfer

flpydsk_send_command( FDC_CMD_WRITE_SECT | FDC_CMD_EXT_MULTITRACK | FDC_CMD_EXT_DENSITY ); // write a sector
flpydsk_send_command( head << 2 | _CurrentDrive );
flpydsk_send_command( track);
flpydsk_send_command( head);
flpydsk_send_command( sector);
flpydsk_send_command( FLPYDSK_SECTOR_DTL_512 );
flpydsk_send_command( ( ( sector + 1 ) >= FLPY_SECTORS_PER_TRACK ) ? FLPY_SECTORS_PER_TRACK : sector + 1 );
flpydsk_send_command( FLPYDSK_GAP3_LENGTH_3_5 );
flpydsk_send_command( 0xFF );

flpydsk_wait_irq();

int j;
for(j=0; j<7; ++j)
flpydsk_read_data(); // read status info
flpydsk_check_int(&st0,&cyl); // let FDC know we handled interrupt
}

// write a sector
int flpydsk_write_sector(int sectorLBA)
{
if (_CurrentDrive >= 4) return -1;
// convert LBA sector to CHS
int head=0, track=0, sector=1;
flpydsk_lba_to_chs(sectorLBA, &head, &track, &sector);
// turn motor on and seek to track
flpydsk_control_motor(TRUE);
if(flpydsk_seek (track, head)) return -2;
// write sector and turn motor off
flpydsk_write_sector_imp(head, track, sector);
flpydsk_control_motor(FALSE);
return 0;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// initialize DMA to use physical address 84k-128k
void flpydsk_initialize_dma()
{
    outportb(0x0a, 0x06);    //mask dma channel 2
    outportb(0xd8, 0xFF);    //reset master flip-flop
    outportb(0x04, 0x00);   //address=0x1000
    outportb(0x04, 0x10);
    outportb(0xd8, 0xFF);   //reset master flip-flop
    outportb(0x05, 0xFF);   //count to 0x23FF (number of bytes in a 3.5" floppy disk track: 18*512)
    outportb(0x05, 0x23);

    outportb(0x81, 0x00);   //external page register = 0
    outportb(0x0a, 0x02);   //unmask dma channel 2
}

// prepare the DMA for write transfer
void flpydsk_dma_write()
{
    outportb(0x0a, 0x06); //mask dma channel 2
    outportb(0x0b, 0x5A); //single transfer, address increment, autoinit, write, channel 2
    outportb(0x0a, 0x02); //unmask dma channel 2
}

// convert LBA to CHS
void flpydsk_lba_to_chs(int lba, int* head, int* track, int* sector)
{
   *track  =   lba / ( FLPY_SECTORS_PER_TRACK * 2 );
   *head   = ( lba % ( FLPY_SECTORS_PER_TRACK * 2 ) ) / ( FLPY_SECTORS_PER_TRACK );
   *sector = ( lba % ( FLPY_SECTORS_PER_TRACK * 2 ) ) % FLPY_SECTORS_PER_TRACK + 1;
}

// write a sector
void flpydsk_write_sector_imp(unsigned char head, unsigned char track, unsigned char sector)
{
    ULONG st0, cyl;
    flpydsk_dma_write(); // set the DMA for write transfer

    flpydsk_send_command( FDC_CMD_WRITE_SECT | FDC_CMD_EXT_MULTITRACK | FDC_CMD_EXT_DENSITY );  // write a sector
    flpydsk_send_command( head << 2 | _CurrentDrive );
    flpydsk_send_command( track);
    flpydsk_send_command( head);
    flpydsk_send_command( sector);
    flpydsk_send_command( FLPYDSK_SECTOR_DTL_512 );
    flpydsk_send_command( ( ( sector + 1 ) >= FLPY_SECTORS_PER_TRACK ) ? FLPY_SECTORS_PER_TRACK : sector + 1 );
    flpydsk_send_command( FLPYDSK_GAP3_LENGTH_3_5 );
    flpydsk_send_command( 0xFF );

    flpydsk_wait_irq();

    int j;
    for(j=0; j<7; ++j)
        flpydsk_read_data();      // read status info
    flpydsk_check_int(&st0,&cyl); // let FDC know we handled interrupt
}

// write a sector
int flpydsk_write_sector(int sectorLBA)
{
    if (_CurrentDrive >= 4) return -1;
    // convert LBA sector to CHS
    int head=0, track=0, sector=1;
    flpydsk_lba_to_chs(sectorLBA, &head, &track, &sector);
    // turn motor on and seek to track
    flpydsk_control_motor(TRUE);
    if(flpydsk_seek (track, head)) return -2;
    // write sector and turn motor off
    flpydsk_write_sector_imp(head, track, sector);
    flpydsk_control_motor(FALSE);
    return 0;
}

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:52:26 09.08.2009, insgesamt 2-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 18:47:28 10.08.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Klappt aber nicht lückenlos. Es werden weniger als 18 Sektoren geschrieben.
Vermutlich ein "Kantenproblem". Folgender Ausdruck :
C/C++ Code:
#define FLPY_SECTORS_PER_TRACK 18

void flpydsk_write_sector_imp(unsigned char head, unsigned char track, unsigned char sector) {
(...)
 flpydsk_send_command( ( ( sector + 1 ) >= FLPY_SECTORS_PER_TRACK ) ? FLPY_SECTORS_PER_TRACK : sector + 1 );
(...)
}
C/C++ Code:
#define FLPY_SECTORS_PER_TRACK 18

void flpydsk_write_sector_imp(unsigned char head, unsigned char track, unsigned char sector) {
(...)
flpydsk_send_command( ( ( sector + 1 ) >= FLPY_SECTORS_PER_TRACK ) ? FLPY_SECTORS_PER_TRACK : sector + 1 );
(...)
}
C/C++ Code:
#define FLPY_SECTORS_PER_TRACK 18

void flpydsk_write_sector_imp(unsigned char head, unsigned char track, unsigned char sector) {
(...)
 flpydsk_send_command( ( ( sector + 1 ) >= FLPY_SECTORS_PER_TRACK ) ? FLPY_SECTORS_PER_TRACK : sector + 1 );
(...)
}
liefert für "sector = 17" und "sector = 18" das gleiche Ergebnis.

Woraus folgt, der Ausdruck unterscheidet nicht zwischen "sector == 17" und "sector == 18". (Und "sector == 1" wird nicht zur Kenntnis genommen).
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 14:05:27 14.08.2009   Titel:              Zitieren

Ja, genau da liegt der Hase im Pfeffer. Diese Zeile ist nicht zielführend. Wurde von mir durch folgendes ersetzt:
C/C++ Code:
flpydsk_send_command( 18 );
C/C++ Code:
flpydsk_send_command( 18 );
C/C++ Code:
flpydsk_send_command( 18 );

Nun werden 18 Sektoren geschrieben (fkt. auch mit anderen Zahlen), allerdings muss man beim Schreiben genau an einem Track-Anfang (gemäß LBA) beginnen: 0, 18, 36, ...
Ansonsten wird nämlich auch noch dort jeweils geschrieben. Merkwürdiger Effekt.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:09:31 15.08.2009   Titel:              Zitieren

Nun habe ich das Thema langsam im Griff, durch FDC und DMA nicht ganz übersichtlich. Hier das Analysieren des Stammverzeichnisses einer Diskette:
http://www.henkessoft.de/OS_Dev/OS_Dev3.htm#mozTocId610721
http://www.henkessoft.de/OS_Dev/Downloads/104.rar

Erste Rückmeldungen: Läuft offenbar nicht auf allen PCs, aber in Bochs. Für Tipps wäre ich dankbar. :)

Hier einige gute Links zu dem Thema:
http://www.isdaman.com/alsos/hardware/fdc/floppy.htm
http://lowlevel.brainsware.org/wiki/index.php/FDC#Data_Address_Mark
http://www.brokenthorn.com/Resources/OSDev20.html
http://www.eit.lth.se/fileadmin/eit/courses/eit015/FAT12Description.pdf

Wenn jemand Lust hat, mich zu unterstützen, würde mich freuen. Es ist jetzt viel Detail-Arbeit angesagt. Ich würde gerne mit engagierten Leuten ohne Zeitdruck eine eigene OS-Community aufbauen:
http://www.c-plusplus.de/forum/viewtopic-var-t-is-247814.html

Ich denke, das Thema OSDEV im leicht fortgeschrittenen Stadium passt nicht mehr richtig in dieses Forum. Die Diskussionen werden unspezifisch. Die anstehenden Aufgaben erfordern Detailwissen über PrettyOS, C, Assembler, Erfahrung mit der Toolchain, konstruktive Kreativität, analytisches Vorgehen, Tiefgang und generell Lust am Thema OS-Development (viel Arbeit, wenig Belohnung). :rolleyes:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 11:10:39 16.08.2009, insgesamt 3-mal bearbeitet
Matzer
Unregistrierter




Beitrag Matzer Unregistrierter 16:14:36 17.08.2009   Titel:              Zitieren

@Erhard: Erstmal ein :live: für die großartigen Tutorials, sehr interessant und informativ.

Nun habe ich aber folgendes Problem:
Ich versuche zur Zeit einige der Beispiele aus deinem Tutorial auf einem Ubuntu-System über Bochs zum Laufen zu bekommen. Allerdings hagelt es bei mir immer wieder "Boot failed: could not read the boot disk" beim Laden meiner selbstgenerierten MyOS.bin-Datei.
Die nasm-Befehle sind ja praktisch die gleichen wie unter Windows, allerdings verwende ich statt dem copy /b-Befehl ein "cat boot.bin kernel.bin>MyOS.bin". Der Pfad zur OS.bin-Datei ist in der Konfigurationsdatei auch korrekt gesetzt. Die Quelldateien entsprechen 1:1 denen des ersten Beispiels im Protected-Mode-Abschnitt.

Benutze ich das bereits vorgefertigte Sourcepaket(inkl. der MyOS.bin), so gibt es in Bochs keinerlei Probleme beim Booten. Könnte es sein, dass hier der cat-Aufruf das Problem verursacht? Denn beim generieren des allerersten Beispiels, das jediglich aus der Datei kernel.bin bestand, gab es auch noch keinerlei Probleme.
Tobiking2
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 705
Beitrag Tobiking2 Mitglied 16:57:39 17.08.2009   Titel:              Zitieren

Ich benutze auch die ganze Zeit Ubuntu und habe keinerlei Probleme gehabt. Allerdings nehme ich QEmu, da der QEmu-Launcher meiner Meinung nach etwas komfortabler ist wenn man öfters mal etwas an den Einstellungen ändert.

Ich hab das mit cat in zwei Befehlen gemacht "cat boot.bin > MyOS" und "cat ckernel.bin >> MyOS" aber sollte auf das gleiche hinauslaufen.
Matzer
Unregistrierter




Beitrag Matzer Unregistrierter 17:37:54 17.08.2009   Titel:              Zitieren

Hi,

das Problem hat sich mittlerweile erledigt. Ich habe beim Aufruf von nasm einfach mal die Option -O32 weggelassen und schon funktionierte es.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:46:48 17.08.2009   Titel:              Zitieren

Zitat:
Erstmal ein :live: für die großartigen Tutorials, sehr interessant und informativ.
Herzlichen Dank für das positive Feedback. Freut mich, wenn das Thema OS Development etwas belebt wird.

Kleines Problem: aktueller 1st stage BL startet bei einigen PC nicht:
http://www.brokenthorn.com/forums/viewtopic.php?f=15&t=1235

Idee? Würde gerne meinen Aufbau weitgehend beibehalten.
Wer Probleme beim Booten hat, nimmt bis zur Lösung diesen 1st stage BL als Austausch in den aktuellen Versionen ab Nr. 95: http://www.henkessoft.de/OS_Dev/Downloads/Version_94_stage1_bootloader.zip

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 17:16:49 19.08.2009, insgesamt 4-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 19:05:43 19.08.2009   Titel:              Zitieren

Hallo,

Erhard Henkes schrieb:
Kleines Problem: aktueller 1st stage BL startet bei einigen PC nicht...


ein Blick in den Quellcode von grub, z.B. aus boot.S:
Zitat:
/*
* This is a workaround for buggy BIOSes which don't pass boot
* drive correctly. If GRUB is installed into a HDD, check if
* DL is masked correctly. If not, assume that the BIOS passed
* a bogus value and set DL to 0x80, since this is the only
* possible boot drive. If GRUB is installed into a floppy,
* this does nothing (only jump).
*/

oder
Zitat:
/*
* Determine the hard disk geometry from the BIOS!
* We do this first, so that LS-120 IDE floppies work correctly.
*/


lässt erahnen, warum es immer mindestens einen problematischen Rechner geben wird...
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:19:20 19.08.2009   Titel:              Zitieren

EDIT: Boot-Problem zunächst wieder gelöst, lag bei dem einen PC am Stack.

FDC funktioniert leider auch nicht überall. Manche melden beim Lesen der Root Directory einfach Funkstille zurück. Schwieriges Thema.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 21:28:34 20.08.2009, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:47:08 04.09.2009   Titel:              Zitieren

Hier könnte sich eine neue OS Community bilden, falls jemand von Anfang an dabei sein möchte:
http://www.c-plusplus.de/forum/viewtopic-var-p-is-1772434.html#1772434
Wichtig: Kein Stress oder Zeitdruck! Spaß sollte im Vordergrund stehen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:53:22 07.10.2009   Titel:              Zitieren

Der Start hat geklappt. Wollte mich bei allen bedanken, die mich auf diesem Weg bisher unterstützten. Nun ist m.E. der richtige Zeitpunkt, um noch dazu zu stoßen, egal ob auf Basis Windows oder Linux.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 19:19:22 07.10.2009   Titel:              Zitieren

Hallo Erhard,

ich habe ja kein eingebautes Disketten-Laufwerk und habe gerade folgendes ausprobiert:
- ein Floppy Driver USB genommen, angeschlossen - scheint noch zu funktionieren :)
- damit eine Diskette formatiert - ja, ich habe bei mir noch eine Diskette gefunden:
Zitat:
mkfs.msdos -F 12 -I /dev/sdc

- Dateien boot2.sys und ckernel.sys (diese habe ich ja am Montag kompilieren können) ins Wurzelverzeichnis der Diskette kopiert und so sieht es aus:
Zitat:
drwxrwxrwx 2 alex root 16384 1. Jan 1970 .
drwxr-xr-x 3 root root 4096 7. Okt 19:04 ..
-rwxr-xr-x 1 alex root 912 7. Okt 18:54 boot2.sys
-rwxr-xr-x 1 alex root 34036 7. Okt 18:54 ckernel.sys

- auf einen USB Stick habe ich mit dd die boot.bin kopiert
- System neugestartet und vom USB Stick gestartet, mein BIOS kann es, wie es aussieht

Nun kommt folgende Ausgabe:
Zitat:
Loading Second Stage Bootloader
**************
BOOT2.SYS MISSING

Heisst das, mein BIOS hat vom USB Stick gestartet und hat erkannt, dass es einen Disketten-USB-Adapter mit einer Diskette drin gibt - nur findet die BOOT2.SYS nicht? :)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:36:27 07.10.2009   Titel:              Zitieren

Ganz genau, er hat gebootet! Er verwendet für das Suchen/Nachladen des second stage Bootloaders das übliche Disketten-Format FAT12.
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
;******************************************************************************
;   Load stage2 bootloader
;******************************************************************************
Load_Image:
    mov ax, WORD [cluster]                  ; cluster to read
    pop bx                                  ; buffer to read into
    call Convert_Cluster_to_LBA             ; convert cluster to LBA
    xor cx, cx
    mov cl, BYTE [SecPerClus]               ; sectors to read
    call ReadSectors
    push bx
         
    ; compute next cluster
    mov ax, WORD [cluster]                  ; identify current cluster
    mov cx, ax                              ; copy current cluster
    mov dx, ax                              ; copy current cluster
    shr dx, 1                               ; divide by two
    add cx, dx                              ; sum for (3/2)
    mov bx, 0x7E00                          ; location of FAT in memory
    add bx, cx                              ; index into FAT
    mov dx, WORD [bx]                       ; read two bytes from FAT
    test ax, 1
    jnz .ODD_CLUSTER
         
.EVEN_CLUSTER:
    and dx, 0000111111111111b               ; take low twelve bits
    jmp .DONE
         
.ODD_CLUSTER:
    shr dx, 4                               ; take high twelve bits
         
.DONE:
    mov WORD [cluster], dx                  ; store new cluster
    cmp dx, 0x0FF0                          ; test for EOF
    jb Load_Image
         
DONE:
    mov si, msgCRLF
    call print_string
    mov dl, [bootdevice]
    push WORD 0x0000
    push WORD 0x0500
    retf
         
FAILURE:
    mov si, msgFailure
    call print_string
    mov ah, 0x00
    int 0x16                                ; wait for keypress
    int 0x19                                ; warm boot reset
;
;
;
msgFailure     db 0x0D, 0x0A, "BOOT2.SYS MISSING', 0x0D, 0x0A, 0
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
;******************************************************************************
; Load stage2 bootloader
;******************************************************************************
Load_Image:
mov ax, WORD [cluster] ; cluster to read
pop bx ; buffer to read into
call Convert_Cluster_to_LBA ; convert cluster to LBA
xor cx, cx
mov cl, BYTE [SecPerClus] ; sectors to read
call ReadSectors
push bx

; compute next cluster
mov ax, WORD [cluster] ; identify current cluster
mov cx, ax ; copy current cluster
mov dx, ax ; copy current cluster
shr dx, 1 ; divide by two
add cx, dx ; sum for (3/2)
mov bx, 0x7E00 ; location of FAT in memory
add bx, cx ; index into FAT
mov dx, WORD [bx] ; read two bytes from FAT
test ax, 1
jnz .ODD_CLUSTER

.EVEN_CLUSTER:
and dx, 0000111111111111b ; take low twelve bits
jmp .DONE

.ODD_CLUSTER:
shr dx, 4 ; take high twelve bits

.DONE:
mov WORD [cluster], dx ; store new cluster
cmp dx, 0x0FF0 ; test for EOF
jb Load_Image

DONE:
mov si, msgCRLF
call print_string
mov dl, [bootdevice]
push WORD 0x0000
push WORD 0x0500
retf

FAILURE:
mov si, msgFailure
call print_string
mov ah, 0x00
int 0x16 ; wait for keypress
int 0x19 ; warm boot reset
;
;
;
msgFailure db 0x0D, 0x0A, "BOOT2.SYS MISSING', 0x0D, 0x0A, 0
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
;******************************************************************************
;   Load stage2 bootloader
;******************************************************************************
Load_Image:
    mov ax, WORD [cluster]                  ; cluster to read
    pop bx                                  ; buffer to read into
    call Convert_Cluster_to_LBA             ; convert cluster to LBA
    xor cx, cx
    mov cl, BYTE [SecPerClus]               ; sectors to read
    call ReadSectors
    push bx
         
    ; compute next cluster
    mov ax, WORD [cluster]                  ; identify current cluster
    mov cx, ax                              ; copy current cluster
    mov dx, ax                              ; copy current cluster
    shr dx, 1                               ; divide by two
    add cx, dx                              ; sum for (3/2)
    mov bx, 0x7E00                          ; location of FAT in memory
    add bx, cx                              ; index into FAT
    mov dx, WORD [bx]                       ; read two bytes from FAT
    test ax, 1
    jnz .ODD_CLUSTER
         
.EVEN_CLUSTER:
    and dx, 0000111111111111b               ; take low twelve bits
    jmp .DONE
         
.ODD_CLUSTER:
    shr dx, 4                               ; take high twelve bits
         
.DONE:
    mov WORD [cluster], dx                  ; store new cluster
    cmp dx, 0x0FF0                          ; test for EOF
    jb Load_Image
         
DONE:
    mov si, msgCRLF
    call print_string
    mov dl, [bootdevice]
    push WORD 0x0000
    push WORD 0x0500
    retf
         
FAILURE:
    mov si, msgFailure
    call print_string
    mov ah, 0x00
    int 0x16                                ; wait for keypress
    int 0x19                                ; warm boot reset
;
;
;
msgFailure     db 0x0D, 0x0A, "BOOT2.SYS MISSING', 0x0D, 0x0A, 0

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:38:50 07.10.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:14:46 07.10.2009   Titel:              Zitieren

http://www.brokenthorn.com/Resources/OSDev3.html ff.
Vielleicht findet sich dort etwas, ansonsten im Forum dort fragen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:37:48 07.10.2009, insgesamt 2-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 01:09:18 08.10.2009   Titel:              Zitieren

abc.w schrieb:
Nun kommt folgende Ausgabe:
Zitat:
Loading Second Stage Bootloader
**************
BOOT2.SYS MISSING
Heisst das, mein BIOS hat vom USB Stick gestartet und hat erkannt, dass es einen Disketten-USB-Adapter mit einer Diskette drin gibt - nur findet die BOOT2.SYS nicht? :)

Laut "boot.asm" (hab leider nur die "104"-Version, könnte also falsch sein meine Vermutung) heißt es eher, daß die "boot.bin" die "BOOT2.SYS" auf dem USB-Stick gesucht hat. Starte mal "vollständig" vom USB-Diskettenlaufwerk.
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 19:24:41 08.10.2009   Titel:              Zitieren

+gjm+ schrieb:
...Starte mal "vollständig" vom USB-Diskettenlaufwerk.

Ausprobiert, geht nicht. Keine Ausgaben, BIOS geht dann weiter und bootet von der Festplatte...
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:41:04 08.10.2009   Titel:              Zitieren

Zitat:
hab leider nur die "104"-Version

Kannst Du Dir hier ziehen: http://www.henkessoft.de/OS_Dev/Downloads/106.zip

Zitat:
BIOS geht dann weiter und bootet von der Festplatte...

Habe im Netz recherchiert, aber leider auf Anhieb nichts bezüglich Booten von USB-Floppy gefunden. Scheint nicht der große Renner zu sein. :)

Hast Du das mal mit Bochs in der Emulation probiert?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:51:42 08.10.2009, insgesamt 2-mal bearbeitet
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 148
Beitrag taljeth Mitglied 20:40:53 08.10.2009   Titel:              Zitieren

Wenn das BIOS es unterstützt, sollte das Laufwerk über int 13h genauso aussehen wie ein ganz normales Floppylaufwerk auch.

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community
Unregistrierter





Beitrag Unregistrierter 18:44:03 09.10.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Kannst Du Dir hier ziehen: http://www.henkessoft.de/OS_Dev/Downloads/106.zip
Vielen Dank! Stell da mal eine Seite rein auf der die Versionen schön sauber aufgelistet sind (zusammen mit den Chat-Protokollen). :)
abc.w schrieb:
Ausprobiert, geht nicht. Keine Ausgaben, BIOS geht dann weiter und bootet von der Festplatte...
Probier mal folgendes:
Assembler Code:
; boot.asm (version 106)
ReadSectors:
(...)
; mov  dl, BYTE [DriveNum]   ; ändern in:
 mov  dl, BYTE [bootdevice]  ; Da unklar ist welche "Nummer" das Bootdevice hat,
(...)                        ; wird "bootdevice" schon die richtige Nummer sein.
Assembler Code:
; boot.asm (version 106)
ReadSectors:
(...)
; mov dl, BYTE [DriveNum] ; ändern in:
mov dl, BYTE [bootdevice] ; Da unklar ist welche "Nummer" das Bootdevice hat,
(...) ; wird "bootdevice" schon die richtige Nummer sein.
Assembler Code:
; boot.asm (version 106)
ReadSectors:
(...)
; mov  dl, BYTE [DriveNum]   ; ändern in:
 mov  dl, BYTE [bootdevice]  ; Da unklar ist welche "Nummer" das Bootdevice hat,
(...)                        ; wird "bootdevice" schon die richtige Nummer sein.
Setzt aber voraus, daß das BIOS "CHS-Zugriffe" auf ein USB-Gerät unterstützt (emuliert).
Die Version 106 startet auch "vollständig" von einem USB-Stick. Allerdings unter folgender Voraussetzung:

- Der USB-Stick muß FAT12-formatiert sein. :)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:35:23 09.10.2009   Titel:              Zitieren

@+gjm+: Danke für den Versuch. Kannst Du noch etwas dazu sagen, wie man einen USB-Stick sauber mit FAT12 formatiert? Siehe z.B. hier: http://forum.chip.de/partition-formatierung/fat12-formatieren-750786.html :confused:

Zitat:
FORMAT Volume [/FS:Dateisystem] [/V:Bezeichnung] [/Q] [/A:Größe] [/C] [/X]
FORMAT Volume [/V:Bezeichnung] [/Q] [/F:Größe]
FORMAT Volume [/V:Bezeichnung] [/Q] [/T:Spuren /N:Sektoren]
FORMAT Volume [/V:Bezeichnung] [/Q]
FORMAT Volume [/Q]

Volume Gibt den Laufwerkbuchstaben (gefolgt von einem Doppel-
punkt), den Bereitstellungspunkt oder den Volume-
namen an.
/FS:Dateisystem Gibt den Typ des Dateisystems an (FAT, FAT32, oder NTFS).
/V:Bezeichnung Gibt die zuzuweisende Volumebezeichnung an.
/Q Führt eine Formatierung mit Schnellformatierung durch.
/C Nur NTFS: Auf dem neuen Volume erstellte Dateien werden
standardmäßig komprimiert.
/X Erzwingt das Aufheben der Bereitstellung des Volumes,
falls erforderlich. Alle zu dem Volume geöffneten Bezüge
werden ungültig.
/A:Größe Überschreibt die Standardgröße der Zuordnungseinheiten.
Standardeinstellungen werden für den Gebrauch empfohlen.
NTFS: 512, 1024, 2048, 4096, 8192, 16 KB, 32 KB, 64 KB.
FAT: 512, 1024, 2048, 4096, 8192, 16 KB, 32 KB, 64 KB
(128 KB, 256 KB für Sektorengröße > 512 Bytes).
FAT32: 512, 1024, 2048, 4096, 8192, 16 KB, 32 KB, 64 KB
(128 KB, 256 KB für Sektorengröße > 512 Bytes).

Bedenken Sie, dass für die Dateisysteme FAT und FAT32
folgende Einschränkungen bezüglich der Anzahl der Cluster
auf einem Volume gelten:

FAT: Anzahl der Cluster <= 65526
FAT32: 65526 < Anzahl der Cluster < 4177918

FORMAT wird sofort abgebrochen, wenn die oben genannten
Bedingungen mit der angegebenen Clustergröße nicht
eingehalten werden können.

NTFS-Komprimierung wird nicht für Zuordnungseinheitsgrößen
über 4096 unterstützt.

/F:Größe Gibt die Größe der zu formatierenden Diskette an (1.44).
/T:Spuren Formatiert jede Seite mit der angegebenen Anzahl an Spuren.
/N:Sektoren Formatiert jede Spur mit der angegebenen Anzahl an Sektoren.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:37:22 09.10.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:40:55 09.10.2009   Titel:              Zitieren

Zitat:
Chat-Protokolle
... befinden sich in unserem Forum (bitte Badestrand anmailen)

Hier ist noch die Version 105 (106 war eine experimentelle Variante wegen des Floppy Treibers, um zu sehen, was bei echten PCs geht und was nicht :rolleyes: ): http://www.henkessoft.de/OS_Dev/Downloads/105.zip

So sieht das bei mir mit Bochs (gebootet von echter Floppy) aus:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
PrettyOS [Version 0.1.0105]  (C) 2009 henkessoft.de

Usable RAM: 1048124 KB

Ram Disk at: 4008100Ch

Floppy Driver Test!

<Floppy Disc Root Dir>
PRETTYOS        0 byte           (lab)  1st phys. sec: 31
BOOT2.SYS       912 byte         (arc)  1st phys. sec: 33
CKERNEL.SYS     33648 byte       (arc)  1st phys. sec: 35

<DIR> dev
35      file1
35      file2
35      file3
1693    shell

$> hi <--
I am PrettyOS. Always at your service!
$>
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
PrettyOS [Version 0.1.0105] (C) 2009 henkessoft.de

Usable RAM: 1048124 KB

Ram Disk at: 4008100Ch

Floppy Driver Test!

<Floppy Disc Root Dir>
PRETTYOS 0 byte (lab) 1st phys. sec: 31
BOOT2.SYS 912 byte (arc) 1st phys. sec: 33
CKERNEL.SYS 33648 byte (arc) 1st phys. sec: 35

<DIR> dev
35 file1
35 file2
35 file3
1693 shell

$> hi <--
I am PrettyOS. Always at your service!
$>
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
PrettyOS [Version 0.1.0105]  (C) 2009 henkessoft.de

Usable RAM: 1048124 KB

Ram Disk at: 4008100Ch

Floppy Driver Test!

<Floppy Disc Root Dir>
PRETTYOS        0 byte           (lab)  1st phys. sec: 31
BOOT2.SYS       912 byte         (arc)  1st phys. sec: 33
CKERNEL.SYS     33648 byte       (arc)  1st phys. sec: 35

<DIR> dev
35      file1
35      file2
35      file3
1693    shell

$> hi <--
I am PrettyOS. Always at your service!
$>


Die obere Auflistung betrifft die Root Directory der Floppy Disk, während nachstehend die RAM Disk Struktur (vom User-Bereich mit incbin in den Kernel eingeschleuste Programme, z.B. shell) dargestellt wird. Details findet man hier: http://www.henkessoft.de/OS_Dev/OS_Dev3.htm#mozTocId610721

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 13:42:51 10.10.2009, insgesamt 7-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 15:42:25 10.10.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Die obere Auflistung betrifft die Root Directory der Floppy Disk, ...

Und genau das ist ein großes Problem. Die boot.asm ist teilweise "hardcoded" und deshalb nur für eine Diskette geeignet. Wenn ein USB-Stick formatiert ist, hat er einen MBR und eine Partition. "Angesprochen" wird er vom BIOS (falls das BIOS das unterstützt) via CHS (wobei gilt: CHS = xxx 255 63 (xxx = je nach Größe)).

Normalerweise gehört die "boot.bin" in den ersten logischen Sektor der Partition (sprich ganz an den Anfang der Partition). Aber dann stimmt die gesamte "CHS-Zugriffslogik" nicht mehr. Prinzipell aber kein Problem das anzupassen.

Allerdings das unangenehmste an der boot.bin ist das Dateisystem:

Wenn man auf der Diskette eine Datei löscht und wieder raufkopiert, dann stimmt die Struktur des Root-Directory nicht mehr. Dummerweise werden gelöschte Dateien nicht gelöscht, sondern nur als gelöscht markiert. Was heißt, daß dann das Root-Directory einen Eintrag zuviel hat und geparst werden muß.

Entweder programmiert jemand einen 510 Byte großen FAT12-Parser (und für den USB-Stick am besten gleich einen FAT32-Parser) oder beim Bootloader muß auf die Vorzüge eines FS verzichtet werden.
Tobiking2
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 705
Beitrag Tobiking2 Mitglied 16:39:33 10.10.2009   Titel:              Zitieren

Spätestens bei Bootmedien mit Partitionen wird aus Stage1 wohl sämtlicher Filesystem Code verschwinden müssen. Die Partitionstabelle liegt nämlich auch im MBR. Es sind also letztendlich nur noch 440 Byte nutzbar für Stage1. Die jetzige Stage1 ist mit 480 Byte also schon zu groß. Die Stage1 von Grub ist auch schon 400 Byte groß ohne jeglichen Filesystem Code.

Allerdings nutzt Grub einen anderen Trick aus. Der MBR besteht zwar nur aus den ersten Sektor des Bootmediums, aber der Rest des ersten Kopfes ist unbenutzt. Grub legt Stage2 also in diesen ungenutzen Platz auf dem ersten Kopf. Die Installationsroutine von Grub überprüft allerdings die Größe und kann die Stelle von Stage2 nachträglich in der compilierten Stage1 patchen.
Unregistrierter





Beitrag Unregistrierter 19:23:02 10.10.2009   Titel:              Zitieren

Wenn Stage 1 die CHS der eigenen Partition selbst ermittelt (z.B. durch Auslesen der Partitionstabelle des MBR), dann müssen "Seltsamkeiten" wie bei GRUB erst nicht in Erwägung gezogen werden.

In der eigenen Partition ist Platz genug für "seltsames" (jedenfalls solange wie PrettyOS noch kein FS hat).
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 148
Beitrag taljeth Mitglied 19:25:56 10.10.2009   Titel:              Zitieren

Dort sitzt aber normal schon ein Dateisystem, das seine eigenen Vorstellungen davon hat, wie der Platz genutzt wird. Ich denke, man wird eher nicht drum herumkommen, in stage1 ein paar Sektornummern von stage2 reinzupatchen.

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community
Unregistrierter





Beitrag Unregistrierter 20:11:05 10.10.2009   Titel:              Zitieren

Wenn die Position von Stage 2 der Stage 1 "nachträglich" mitgeteilt werden muß, dann ist es schlechtes Design.
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 148
Beitrag taljeth Mitglied 21:01:40 10.10.2009   Titel:              Zitieren

Dann hat gutes Design leider die Eigenschaft, dass es nicht funktioniert.
Tobiking2
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 705
Beitrag Tobiking2 Mitglied 22:09:35 10.10.2009   Titel:              Zitieren

Ich hab grad mal meine Grub Installationen geprüft. Auf der Diskette (ext2) und der Festplatte (ext3) liegt Stage2 im Sektor 1, also direkt hinter dem MBR.

Was würde man denn machen wenn das Dateisystem dann doch mal in Sektor 1 beginnt? Stage2 in die Zuordnungstabelle eintragen und hoffen das das Dateisystem nicht auf die Idee kommt die Datei zu verschieben (Stichwort defragmentieren bei ntfs)?
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 148
Beitrag taljeth Mitglied 22:16:16 10.10.2009   Titel:              Zitieren

Du müsstest mal schauen, was GRUB auf einer Diskette macht, dort hat man diesen Platz ja nicht, wenn ich mich grad nicht täusche. Aber stimmt, mit Dateisystem und Defragmentierung hast du wohl verloren.

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community
Tobiking2
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.04.2009
Beiträge: 705
Beitrag Tobiking2 Mitglied 22:57:28 10.10.2009   Titel:              Zitieren

taljeth schrieb:
Du müsstest mal schauen, was GRUB auf einer Diskette macht, dort hat man diesen Platz ja nicht, wenn ich mich grad nicht täusche. Aber stimmt, mit Dateisystem und Defragmentierung hast du wohl verloren.

Stimmt, bei der Diskette ist es doch nicht Sektor 1. Ich habe mir mit Hexdump nur 1 byte anzeigen lassen...

Also bei der Diskette liegt Stage2 mitten auf der Diskette und ist im Dateisystem eingetragen. Also bräuchte man um sicher zu gehen wirklich einen Installer der mit dem Dateisystem auf dem Bootmedium klarkommen muss.
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 23:10:04 10.10.2009   Titel:              Zitieren

+gjm+ schrieb:
Probier mal folgendes:
Assembler Code:
; boot.asm (version 106)
ReadSectors:
(...)
; mov  dl, BYTE [DriveNum]   ; ändern in:
 mov  dl, BYTE [bootdevice]  ; Da unklar ist welche "Nummer" das Bootdevice hat,
(...)                        ; wird "bootdevice" schon die richtige Nummer sein.
Assembler Code:
; boot.asm (version 106)
ReadSectors:
(...)
; mov dl, BYTE [DriveNum] ; ändern in:
mov dl, BYTE [bootdevice] ; Da unklar ist welche "Nummer" das Bootdevice hat,
(...) ; wird "bootdevice" schon die richtige Nummer sein.
Assembler Code:
; boot.asm (version 106)
ReadSectors:
(...)
; mov  dl, BYTE [DriveNum]   ; ändern in:
 mov  dl, BYTE [bootdevice]  ; Da unklar ist welche "Nummer" das Bootdevice hat,
(...)                        ; wird "bootdevice" schon die richtige Nummer sein.
Setzt aber voraus, daß das BIOS "CHS-Zugriffe" auf ein USB-Gerät unterstützt (emuliert).
Die Version 106 startet auch "vollständig" von einem USB-Stick.

Hab's noch nicht ausprobiert, werde es noch nachholen.
Ich beobachte jetzt folgendes Verhalten: Mein BIOS scheint keine Probleme zu haben vom USB Stick zu starten. Ich habe auf dem Stick meinen Dummy-Bootloader kopiert, der mit int 13 einen Sektor lesen soll. Der Dummy-Bootloader scheint vom USB-Diskettenlaufwerk zu lesen (erkennbar an den Geräuschen vom USB-Diskettenlaufwerk :)).
Hier ist mein Dummy-Bootloader:
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
[Bits 16]
org 0x7C00    ; start address of bootloader

    xor ax, ax
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov si, szStartMessage
    call print_string

CheckDriveStatus:
    mov ax, 0x0100    ; Check status of the first floppy disk
    mov dx, 0x0000
    int 0x13

    cmp al, 0x00
    jne DriveStatusError

    mov ax, 0x0000    ; Initialize es:bx buffer address pointer
    mov es, ax
    mov bx, Buffer

    mov ax, 0x0201    ; Read sector to the buffer at es:bx
    mov cx, 0x0001
    mov dx, 0x0000
    int 0x13

    mov si, szReadSectorDone
    call print_string

    jmp CheckDriveStatus

DriveStatusError:
    mov si, szDriveStatusError
    call print_string
    jmp CheckDriveStatus

;******************************************************************************
;   Print String  
;   DS:SI   null-terminated string
;******************************************************************************
print_string:
.loop:  
    mov ah, 0x0E      ; BIOS function 0x0E: teletype
    lodsb             ; grab a byte from SI
    test al, al       ; NUL?
    jz .done          ; if the result is zero: get out
    int 0x10          ; else: print out the character
    jmp .loop
.done:
    ret

szStartMessage db "Started from USB stick', 0x0D, 0x0A, 0
szDriveStatusError db "Drive status error', 0x0D, 0x0A, 0
szReadSectorDone db "Reading sector done', 0x0D, 0x0A, 0
 
TIMES 510-($-$$) hlt    ; fill bytes until boot signature
db 0x55                 ; boot signature
db 0xAA                 ; boot signature

Buffer:    ; Start of buffer
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
[Bits 16]
org 0x7C00 ; start address of bootloader

xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax

mov si, szStartMessage
call print_string

CheckDriveStatus:
mov ax, 0x0100 ; Check status of the first floppy disk
mov dx, 0x0000
int 0x13

cmp al, 0x00
jne DriveStatusError

mov ax, 0x0000 ; Initialize es:bx buffer address pointer
mov es, ax
mov bx, Buffer

mov ax, 0x0201 ; Read sector to the buffer at es:bx
mov cx, 0x0001
mov dx, 0x0000
int 0x13

mov si, szReadSectorDone
call print_string

jmp CheckDriveStatus

DriveStatusError:
mov si, szDriveStatusError
call print_string
jmp CheckDriveStatus

;******************************************************************************
; Print String
; DS:SI null-terminated string
;******************************************************************************
print_string:
.loop:
mov ah, 0x0E ; BIOS function 0x0E: teletype
lodsb ; grab a byte from SI
test al, al ; NUL?
jz .done ; if the result is zero: get out
int 0x10 ; else: print out the character
jmp .loop
.done:
ret

szStartMessage db "Started from USB stick', 0x0D, 0x0A, 0
szDriveStatusError db "Drive status error', 0x0D, 0x0A, 0
szReadSectorDone db "Reading sector done', 0x0D, 0x0A, 0

TIMES 510-($-$$) hlt ; fill bytes until boot signature
db 0x55 ; boot signature
db 0xAA ; boot signature

Buffer: ; Start of buffer
Assembler Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
[Bits 16]
org 0x7C00    ; start address of bootloader

    xor ax, ax
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov si, szStartMessage
    call print_string

CheckDriveStatus:
    mov ax, 0x0100    ; Check status of the first floppy disk
    mov dx, 0x0000
    int 0x13

    cmp al, 0x00
    jne DriveStatusError

    mov ax, 0x0000    ; Initialize es:bx buffer address pointer
    mov es, ax
    mov bx, Buffer

    mov ax, 0x0201    ; Read sector to the buffer at es:bx
    mov cx, 0x0001
    mov dx, 0x0000
    int 0x13

    mov si, szReadSectorDone
    call print_string

    jmp CheckDriveStatus

DriveStatusError:
    mov si, szDriveStatusError
    call print_string
    jmp CheckDriveStatus

;******************************************************************************
;   Print String  
;   DS:SI   null-terminated string
;******************************************************************************
print_string:
.loop:  
    mov ah, 0x0E      ; BIOS function 0x0E: teletype
    lodsb             ; grab a byte from SI
    test al, al       ; NUL?
    jz .done          ; if the result is zero: get out
    int 0x10          ; else: print out the character
    jmp .loop
.done:
    ret

szStartMessage db "Started from USB stick', 0x0D, 0x0A, 0
szDriveStatusError db "Drive status error', 0x0D, 0x0A, 0
szReadSectorDone db "Reading sector done', 0x0D, 0x0A, 0
 
TIMES 510-($-$$) hlt    ; fill bytes until boot signature
db 0x55                 ; boot signature
db 0xAA                 ; boot signature

Buffer:    ; Start of buffer
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 23:40:15 10.10.2009   Titel:              Zitieren

Hab noch ein wenig rumexperimentiert - mein BIOS weigert sich, vom USB-Diskettenlaufwerk zu starten. Geht einfach weiter und bootet von der Festplatte.
Nach dem Booten vom USB Stick ist bei mir übrigens DX = 0x0080. D.h. USB Stick = "1st hard disk" :confused:
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:19:43 11.10.2009   Titel:              Zitieren

Zitat:
mein BIOS weigert sich, vom USB-Diskettenlaufwerk zu starten

Hast Du nicht schon den BL Stage 1 davon gestartet, oder war das vom USB-Stick? :confused:
Er konnte doch nur den BL Stage 2 nicht nachladen, oder verwechsle ich da etwas?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:22:23 11.10.2009, insgesamt 1-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 10:19:03 11.10.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zitat:
mein BIOS weigert sich, vom USB-Diskettenlaufwerk zu starten

Hast Du nicht schon den BL Stage 1 davon gestartet, oder war das vom USB-Stick? :confused:
Er konnte doch nur den BL Stage 2 nicht nachladen, oder verwechsle ich da etwas?

Stage 1 Bootloader habe ich bis jetzt immer nur vom USB-Stick starten können. Und dieser Stage 1 Bootloader kann irgendwie auf den USB-Diskettenlaufwerk zugreifen (der gleichzeitig am anderen USB Port angeschlossen ist), findet aber den Stage 2 Bootloader nicht.
Das habe ich auch alles mit meinem Dummy-Bootloader nachvollzogen. Und wie ich vorhin gepostet habe, USB-Sticks werden von meinem BIOS als "1st hard disk" abgebildet (int 13h mit DL = 0x80) und USB-Diskettenlaufwerke werden als "1st floppy disk" abgebildet (int 13h mit DL = 0x00). Und Booten vom USB-Diskettenlaufwerk geht interessanterweise nicht.
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 148
Beitrag taljeth Mitglied 10:56:35 11.10.2009   Titel:              Zitieren

Du hast nicht zufällig einen GRUB auf der Platte? Ansonsten könntest du es mal mit "chainloader (fd0)+1" versuchen (also GRUB von der Platte booten und den wiederum den Bootloader von der Floppy laden lassen).

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:48:46 11.10.2009   Titel:              Zitieren

Zitat:
Stage 1 Bootloader habe ich bis jetzt immer nur vom USB-Stick starten können. Und dieser Stage 1 Bootloader kann irgendwie auf den USB-Diskettenlaufwerk zugreifen (der gleichzeitig am anderen USB Port angeschlossen ist), findet aber den Stage 2 Bootloader nicht. Das habe ich auch alles mit meinem Dummy-Bootloader nachvollzogen. Und wie ich vorhin gepostet habe, USB-Sticks werden von meinem BIOS als "1st hard disk" abgebildet (int 13h mit DL = 0x80) und USB-Diskettenlaufwerke werden als "1st floppy disk" abgebildet (int 13h mit DL = 0x00). Und Booten vom USB-Diskettenlaufwerk geht interessanterweise nicht.
Danke für die Zusammenfassung.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Unregistrierter





Beitrag Unregistrierter 11:52:06 11.10.2009   Titel:              Zitieren

abc.w schrieb:
Das habe ich auch alles mit meinem Dummy-Bootloader nachvollzogen.
Der Stack sollte noch initialisiert werden. :warning:
abc.w schrieb:
Und Booten vom USB-Diskettenlaufwerk geht interessanterweise nicht.
Lade das Floppy-Image mal irgendwo hoch. Ich will es mir mal genauer ansehen.
abc.w schrieb:
Und wie ich vorhin gepostet habe, USB-Sticks werden von meinem BIOS als "1st hard disk" abgebildet (int 13h mit DL = 0x80) und USB-Diskettenlaufwerke werden als "1st floppy disk" abgebildet (int 13h mit DL = 0x00).
Das ist auch ok so. Das BIOS ist der Ansicht, daß es sich bei dem USB-Stick um eine Festplatte handelt. So soll das auch sein. Nun kannst du via CHS, INT13 und DL = 0x80 beliebig auf den USB-Stick zugreifen. Aber Vorsicht bei DL=0x81! Das wird wahrscheinlich die "echte" Festplatte sein.

Aber wie schon gesagt, die "boot.bin" ist "hardcoded" und nur für eine FAT12-formatierte Diskette geeignet! (FAT12 nur dehalb, weil man da (halbwegs) sicher sein kann, daß sich Dateien im Root-Verzeichnis an einer ganz bestimmten CHS-Position befinden).

Wenn du ganz vom USB-Stick starten willst, dann sind Anpassungen in der CHS-"Leselogik" erforderlich.

Die allgemeine CHS-Konfiguration für einen USB-Stick ist wie folgt:

CHS = xxx 255 63, wobei xxx je nach Größe des Sticks differiert.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 14:31:37 11.10.2009   Titel:              Zitieren

Kennt jemand dieses Programm http://www.nu2.nu/mkbt/ ?
http://www.bootdisk.com/pendrive.htm

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 14:36:15 11.10.2009, insgesamt 1-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 14:49:51 11.10.2009   Titel:              Zitieren

taljeth schrieb:
Du hast nicht zufällig einen GRUB auf der Platte? Ansonsten könntest du es mal mit "chainloader (fd0)+1" versuchen (also GRUB von der Platte booten und den wiederum den Bootloader von der Floppy laden lassen).

Ja, ich habe GRUB. Habe probeweise in der menu.lst eingetragen:
Zitat:
title PrettyOS
chainloader (fd0)+1

Nach dem Neustart ausgewählt und, unglaublich, aber wahr, mein Dummy-Bootloader wurde von der Diskette geladen und ausgeführt :live:
Werde es noch mal mit dem Stage1 BL von Erhard ausprobieren.
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 14:57:56 11.10.2009   Titel:              Zitieren

+gjm+ schrieb:
Der Stack sollte noch initialisiert werden. :warning:
Ach so, ja, das ist ein Fehler, Danke für den Hinweis.
+gjm+ schrieb:
Lade das Floppy-Image mal irgendwo hoch. Ich will es mir mal genauer ansehen.
Ich habe bloss meinen Dummy-Bootloader assembliert und mit dd auf die Diskette kopiert:
Code:
dd if=boot.bin of=/dev/sdc bs=512 count=1
Code:
dd if=boot.bin of=/dev/sdc bs=512 count=1
Code:
dd if=boot.bin of=/dev/sdc bs=512 count=1

+gjm+ schrieb:
Aber Vorsicht bei DL=0x81! Das wird wahrscheinlich die "echte" Festplatte sein.
Ja... das macht mir ein wenig Sorgen. Ich habe mein Laptop in letzter Zeit zig mal neugestartet, weiss nicht, ob's für die Hardware so gut ist... :D
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 15:19:11 11.10.2009   Titel:              Zitieren

Zitat:
Ich habe mein Laptop in letzter Zeit zig mal neugestartet

Vielleicht kann Bochs oder andere Emu-Software helfen, die HW zu schonen. Ich habe manchmal auch das Gefühl, dass ich mein Floppy-LW schon geschrottet habe, wenn es das Schreiben verweigert und nur noch rumstottert. :rolleyes:

Zitat:
Werde es noch mal mit dem Stage1 BL von Erhard ausprobieren.
Sollte eigentlich gehen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 15:20:46 11.10.2009, insgesamt 1-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 15:42:38 11.10.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zitat:
Werde es noch mal mit dem Stage1 BL von Erhard ausprobieren.
Sollte eigentlich gehen.

Nein, geht nicht.
Habe eine Diskette vorbereitet, hier mein Makefile:
Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
PRETTYOS_SRC = /home/abc.w/PrettyOS_106
FLOPPY_DEVICE = /dev/sdc

all:
    mkfs.msdos -F 12 -v -I $(FLOPPY_DEVICE)
    mount $(FLOPPY_DEVICE) /mnt -v
    cp $(PRETTYOS_SRC)/_stage2_bootloader/BOOT2.SYS /mnt -v
    cp $(PRETTYOS_SRC)/kernel/ckernel.sys /mnt -v
    umount /mnt -v
    dd if=$(PRETTYOS_SRC)/_stage1_bootloader/boot.bin of=$(FLOPPY_DEVICE) bs=512 count=1
    eject $(FLOPPY_DEVICE)
Code:
1
2
3
4
5
6
7
8
9
10
11
PRETTYOS_SRC = /home/abc.w/PrettyOS_106
FLOPPY_DEVICE = /dev/sdc

all:
mkfs.msdos -F 12 -v -I $(FLOPPY_DEVICE)
mount $(FLOPPY_DEVICE) /mnt -v
cp $(PRETTYOS_SRC)/_stage2_bootloader/BOOT2.SYS /mnt -v
cp $(PRETTYOS_SRC)/kernel/ckernel.sys /mnt -v
umount /mnt -v
dd if=$(PRETTYOS_SRC)/_stage1_bootloader/boot.bin of=$(FLOPPY_DEVICE) bs=512 count=1
eject $(FLOPPY_DEVICE)
Code:
1
2
3
4
5
6
7
8
9
10
11
PRETTYOS_SRC = /home/abc.w/PrettyOS_106
FLOPPY_DEVICE = /dev/sdc

all:
    mkfs.msdos -F 12 -v -I $(FLOPPY_DEVICE)
    mount $(FLOPPY_DEVICE) /mnt -v
    cp $(PRETTYOS_SRC)/_stage2_bootloader/BOOT2.SYS /mnt -v
    cp $(PRETTYOS_SRC)/kernel/ckernel.sys /mnt -v
    umount /mnt -v
    dd if=$(PRETTYOS_SRC)/_stage1_bootloader/boot.bin of=$(FLOPPY_DEVICE) bs=512 count=1
    eject $(FLOPPY_DEVICE)

Hier die Ausgabe beim Ausführen des Makefiles:
Zitat:
-F 12 -v -I /dev/sdc
mkfs.msdos 3.0.2 (28 Feb 2009)
/dev/sdc has 1 head and 3 sectors per track,
logical sector size is 512,
using 0xf8 media descriptor, with 2880 sectors;
file system has 2 12-bit FATs and 4 sectors per cluster.
FAT size is 3 sectors, and provides 710 clusters.
Root directory contains 512 slots.
Volume ID is 8d70e057, no volume label.
mount /dev/sdc /mnt -v
mount: Es wurde kein Dateisystemtyp für /dev/sdc angegeben
Werde den Typ vfat versuchen
/dev/sdc on /mnt type vfat (rw)
cp /home/abc.w/PrettyOS_106/_stage2_bootloader/BOOT2.SYS /mnt -v
»/home/abc.w/PrettyOS_106/_stage2_bootloader/BOOT2.SYS« ->
»/mnt/BOOT2.SYS«
cp /home/abc.w/PrettyOS_106/kernel/ckernel.sys /mnt -v
»/home/abc.w/PrettyOS_106/kernel/ckernel.sys« -> »/mnt/ckernel.sys«
umount /mnt -v
/dev/sdc ausgehängt
dd if=/home/abc.w/PrettyOS_106/_stage1_bootloader/boot.bin of=/dev/sdc bs=512 count=1
1+0 Datensätze ein
1+0 Datensätze aus
512 Bytes (512 B) kopiert, 0,44804 s, 1,1 kB/s
eject /dev/sdc

Mit GRUB (wie vorhin gepostet) vom USB-Diskettenlaufwerk gestartet. Bekomme die Ausgabe:
Zitat:
Loading Second Stage Bootloader
**************
BOOT2.SYS MISSING
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 16:01:40 11.10.2009   Titel:              Zitieren

Jetzt bootet es! :live:
Es war mein Fehler. Hier das geänderte Makefile:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
PRETTYOS_SRC = /home/abc.w/PrettyOS_106
FLOPPY_DEVICE = /dev/sdc

all:
    mkfs.msdos -F 12 -v -I $(FLOPPY_DEVICE)
    dd if=$(PRETTYOS_SRC)/_stage1_bootloader/boot.bin of=$(FLOPPY_DEVICE) bs=512 count=1
    mount $(FLOPPY_DEVICE) /mnt -v
    cp $(PRETTYOS_SRC)/_stage2_bootloader/BOOT2.SYS /mnt -v
    cp $(PRETTYOS_SRC)/kernel/ckernel.sys /mnt -v
    ls -l /mnt/BOOT2.SYS
    ls -l /mnt/ckernel.sys
    umount /mnt -v
    eject $(FLOPPY_DEVICE)
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
PRETTYOS_SRC = /home/abc.w/PrettyOS_106
FLOPPY_DEVICE = /dev/sdc

all:
mkfs.msdos -F 12 -v -I $(FLOPPY_DEVICE)
dd if=$(PRETTYOS_SRC)/_stage1_bootloader/boot.bin of=$(FLOPPY_DEVICE) bs=512 count=1
mount $(FLOPPY_DEVICE) /mnt -v
cp $(PRETTYOS_SRC)/_stage2_bootloader/BOOT2.SYS /mnt -v
cp $(PRETTYOS_SRC)/kernel/ckernel.sys /mnt -v
ls -l /mnt/BOOT2.SYS
ls -l /mnt/ckernel.sys
umount /mnt -v
eject $(FLOPPY_DEVICE)
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
PRETTYOS_SRC = /home/abc.w/PrettyOS_106
FLOPPY_DEVICE = /dev/sdc

all:
    mkfs.msdos -F 12 -v -I $(FLOPPY_DEVICE)
    dd if=$(PRETTYOS_SRC)/_stage1_bootloader/boot.bin of=$(FLOPPY_DEVICE) bs=512 count=1
    mount $(FLOPPY_DEVICE) /mnt -v
    cp $(PRETTYOS_SRC)/_stage2_bootloader/BOOT2.SYS /mnt -v
    cp $(PRETTYOS_SRC)/kernel/ckernel.sys /mnt -v
    ls -l /mnt/BOOT2.SYS
    ls -l /mnt/ckernel.sys
    umount /mnt -v
    eject $(FLOPPY_DEVICE)

Hier die Ausgabe bei der Abarbeitung des Makefiles:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
mkfs.msdos -F 12 -v -I /dev/sdc
mkfs.msdos 3.0.2 (28 Feb 2009)
/dev/sdc has 1 head and 3 sectors per track,
logical sector size is 512,
using 0xf8 media descriptor, with 2880 sectors;
file system has 2 12-bit FATs and 4 sectors per cluster.
FAT size is 3 sectors, and provides 710 clusters.
Root directory contains 512 slots.
Volume ID is f6235fac, no volume label.
dd if=/home/abc.w/PrettyOS_106/_stage1_bootloader/boot.bin of=/dev/sdc bs=512 count=1
1+0 DatensÀtze ein
1+0 DatensÀtze aus
512 Bytes (512 B) kopiert, 0,029063 s, 17,6 kB/s
mount /dev/sdc /mnt -v
mount: Es wurde kein Dateisystemtyp fÃŒr /dev/sdc angegeben
       Werde den Typ vfat versuchen
/dev/sdc on /mnt type vfat (rw)
cp /home/abc.w/PrettyOS_106/_stage2_bootloader/BOOT2.SYS /mnt -v
»/home/abc.w/PrettyOS_106/_stage2_bootloader/BOOT2.SYS« -> »/mnt/BOOT2.SYS«
cp /home/abc.w/PrettyOS_106/kernel/ckernel.sys /mnt -v
»/home/abc.w/PrettyOS_106/kernel/ckernel.sys« -> »/mnt/ckernel.sys«
ls -l /mnt/BOOT2.SYS
-rwxr-xr-x 1 root root 912 11. Okt 15:53 /mnt/BOOT2.SYS
ls -l /mnt/ckernel.sys
-rwxr-xr-x 1 root root 34036 11. Okt 15:53 /mnt/ckernel.sys
umount /mnt -v
/dev/sdc ausgehängt
eject /dev/sdc
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
mkfs.msdos -F 12 -v -I /dev/sdc
mkfs.msdos 3.0.2 (28 Feb 2009)
/dev/sdc has 1 head and 3 sectors per track,
logical sector size is 512,
using 0xf8 media descriptor, with 2880 sectors;
file system has 2 12-bit FATs and 4 sectors per cluster.
FAT size is 3 sectors, and provides 710 clusters.
Root directory contains 512 slots.
Volume ID is f6235fac, no volume label.
dd if=/home/abc.w/PrettyOS_106/_stage1_bootloader/boot.bin of=/dev/sdc bs=512 count=1
1+0 DatensÀtze ein
1+0 DatensÀtze aus
512 Bytes (512 B) kopiert, 0,029063 s, 17,6 kB/s
mount /dev/sdc /mnt -v
mount: Es wurde kein Dateisystemtyp fÃŒr /dev/sdc angegeben
Werde den Typ vfat versuchen
/dev/sdc on /mnt type vfat (rw)
cp /home/abc.w/PrettyOS_106/_stage2_bootloader/BOOT2.SYS /mnt -v
»/home/abc.w/PrettyOS_106/_stage2_bootloader/BOOT2.SYS« -> »/mnt/BOOT2.SYS«
cp /home/abc.w/PrettyOS_106/kernel/ckernel.sys /mnt -v
»/home/abc.w/PrettyOS_106/kernel/ckernel.sys« -> »/mnt/ckernel.sys«
ls -l /mnt/BOOT2.SYS
-rwxr-xr-x 1 root root 912 11. Okt 15:53 /mnt/BOOT2.SYS
ls -l /mnt/ckernel.sys
-rwxr-xr-x 1 root root 34036 11. Okt 15:53 /mnt/ckernel.sys
umount /mnt -v
/dev/sdc ausgehängt
eject /dev/sdc
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
mkfs.msdos -F 12 -v -I /dev/sdc
mkfs.msdos 3.0.2 (28 Feb 2009)
/dev/sdc has 1 head and 3 sectors per track,
logical sector size is 512,
using 0xf8 media descriptor, with 2880 sectors;
file system has 2 12-bit FATs and 4 sectors per cluster.
FAT size is 3 sectors, and provides 710 clusters.
Root directory contains 512 slots.
Volume ID is f6235fac, no volume label.
dd if=/home/abc.w/PrettyOS_106/_stage1_bootloader/boot.bin of=/dev/sdc bs=512 count=1
1+0 DatensÀtze ein
1+0 DatensÀtze aus
512 Bytes (512 B) kopiert, 0,029063 s, 17,6 kB/s
mount /dev/sdc /mnt -v
mount: Es wurde kein Dateisystemtyp fÃŒr /dev/sdc angegeben
       Werde den Typ vfat versuchen
/dev/sdc on /mnt type vfat (rw)
cp /home/abc.w/PrettyOS_106/_stage2_bootloader/BOOT2.SYS /mnt -v
»/home/abc.w/PrettyOS_106/_stage2_bootloader/BOOT2.SYS« -> »/mnt/BOOT2.SYS«
cp /home/abc.w/PrettyOS_106/kernel/ckernel.sys /mnt -v
»/home/abc.w/PrettyOS_106/kernel/ckernel.sys« -> »/mnt/ckernel.sys«
ls -l /mnt/BOOT2.SYS
-rwxr-xr-x 1 root root 912 11. Okt 15:53 /mnt/BOOT2.SYS
ls -l /mnt/ckernel.sys
-rwxr-xr-x 1 root root 34036 11. Okt 15:53 /mnt/ckernel.sys
umount /mnt -v
/dev/sdc ausgehängt
eject /dev/sdc


Und das ist die Ausgabe von PrettyOS:
Code:
PrettyOS [Version 0.1.0106] (C) 2009 henkessoft.de
Usable RAM: 1047608 KB
RAM Disk at: 4008100Ch
DEBUG ckernel.c: after flpydsk_set_working_drive(0)
Code:
PrettyOS [Version 0.1.0106] (C) 2009 henkessoft.de
Usable RAM: 1047608 KB
RAM Disk at: 4008100Ch
DEBUG ckernel.c: after flpydsk_set_working_drive(0)
Code:
PrettyOS [Version 0.1.0106] (C) 2009 henkessoft.de
Usable RAM: 1047608 KB
RAM Disk at: 4008100Ch
DEBUG ckernel.c: after flpydsk_set_working_drive(0)

:live:
Unregistrierter





Beitrag Unregistrierter 16:13:57 11.10.2009   Titel:              Zitieren

Sieht bei mir so aus:
Code:
PrettyOS [Version 0.1.0106] (C) 2009 henkessoft.de
Usable RAM: 3931391 KB :p
RAM Disk at: 4008100Ch
DEBUG ckernel.c: after flpydsk_set_working_drive(0)
Code:
PrettyOS [Version 0.1.0106] (C) 2009 henkessoft.de
Usable RAM: 3931391 KB :p
RAM Disk at: 4008100Ch
DEBUG ckernel.c: after flpydsk_set_working_drive(0)
Code:
PrettyOS [Version 0.1.0106] (C) 2009 henkessoft.de
Usable RAM: 3931391 KB :p
RAM Disk at: 4008100Ch
DEBUG ckernel.c: after flpydsk_set_working_drive(0)
:) :live:
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 17:09:55 11.10.2009   Titel:              Zitieren

Stark! Probiert bitte mal die 105er. :)
http://www.henkessoft.de/OS_Dev/Downloads/105.zip

@abc.w: Könntest Du das makefile bitte auch auf Windows übertragen?

Ich habe leider keine USB-Floppy. Der Floppy-Treiber scheint nicht zu funktionieren. Kommt die Shell? Gebt bitte 'hi' ein.

Zitat:
mount: Es wurde kein Dateisystemtyp für /dev/sdc angegeben
Werde den Typ vfat versuchen

Kann man da FAT12 eingeben für die Floppy, damit die RootDir gelesen werden kann?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 17:37:49 11.10.2009, insgesamt 6-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 19:05:04 11.10.2009   Titel:              Zitieren

Code:
PrettyOS [Version 0.1.0105] (C) 2009 henkessoft.de
Usable RAM: 3931391 KB  
RAM Disk at: 4008100Ch

Floppy Driver Test!
Code:
PrettyOS [Version 0.1.0105] (C) 2009 henkessoft.de
Usable RAM: 3931391 KB
RAM Disk at: 4008100Ch

Floppy Driver Test!
Code:
PrettyOS [Version 0.1.0105] (C) 2009 henkessoft.de
Usable RAM: 3931391 KB  
RAM Disk at: 4008100Ch

Floppy Driver Test!

Bleibt dann hängen. Keine weitere Ausgabe. Das liegt aber nicht am Bootloader. :)
mitleser
Unregistrierter




Beitrag mitleser Unregistrierter 19:08:26 11.10.2009   Titel:              Zitieren

Zum Thema USB Stick unter WindowsXP kann ich folgendes beitragen:

Da mir die Seite von Erhard Henkes ein bisschen zu fortgeschritten ist,
habe ich erstmal diesen Bootrecord
http://lowlevel.brainsware.org/wiki/index.php/Eigener_Boot_Record
mit dem NASM Assembler als bootrecord.bin assembliert.

Mit dem HP USB Disk Storage Format Tool
http://www.chip.de/downloads/HP-USB-Disk-Storage-Format-Tool_23418669.html
habe ich nen asbachuralt 64MB USB Stick mit dem FAT Dateisystem formatiert.

Mit dem Hexeditor
http://wintotal.de/softw/index.php?id=2286
konnte ich unter Datei/Datenträger/Datenträger öffnen den USB-Stick öffnen, ebenso
die Datei bootrecord.bin.

Dann einfach per Copy and Paste den Bootrecord Salat in den USB-Stick Salat reinkopiert,
den USB Stick salat gespeichert.

Der USB-Stick ließ sich anschließend in der Tat booten, was mir die folgenden
Zeilen am Monitor nach einem Neustart bestätigten:

HELLO World!
This is no OS. Press any key to reboot.



Das könnte für den einen oder anderen hilfreich sein, der sonst nicht weiß, wie er
seinen Bootrecord am USB-Stick testen kann.
Wenn nicht, einfach diesen Beitrag löschen.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:00:40 11.10.2009   Titel:              Zitieren

Zitat:
Bleibt dann hängen. Keine weitere Ausgabe.
Daher hatte ich die Version 106 geschrieben mit DEBUG-Meldungen:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
    // floppy disk with DMA Buffer
    flpydsk_set_working_drive(0); // set drive 0 as current drive
    printformat("DEBUG ckernel.c: after flpydsk_set_working_drive(0)\n");
    sti();
    flpydsk_install(6);           // floppy disk uses IRQ 6
    printformat("DEBUG ckernel.c: after flpydsk_install(6)\n");
    k_memset((void*)DMA_BUFFER, 0x0, 0x2400);
    printformat("DEBUG ckernel.c: after k_memset\n");

    tasking_install(); // ends with sti()
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
// floppy disk with DMA Buffer
flpydsk_set_working_drive(0); // set drive 0 as current drive
printformat("DEBUG ckernel.c: after flpydsk_set_working_drive(0)\n");
sti();
flpydsk_install(6); // floppy disk uses IRQ 6
printformat("DEBUG ckernel.c: after flpydsk_install(6)\n");
k_memset((void*)DMA_BUFFER, 0x0, 0x2400);
printformat("DEBUG ckernel.c: after k_memset\n");

tasking_install(); // ends with sti()
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
    // floppy disk with DMA Buffer
    flpydsk_set_working_drive(0); // set drive 0 as current drive
    printformat("DEBUG ckernel.c: after flpydsk_set_working_drive(0)\n");
    sti();
    flpydsk_install(6);           // floppy disk uses IRQ 6
    printformat("DEBUG ckernel.c: after flpydsk_install(6)\n");
    k_memset((void*)DMA_BUFFER, 0x0, 0x2400);
    printformat("DEBUG ckernel.c: after k_memset\n");

    tasking_install(); // ends with sti()

Die Zeile "DEBUG ckernel.c: after flpydsk_set_working_drive(0)" taucht bei euch noch auf, d.h. es klemmt bei:
C/C++ Code:
flpydsk_install(6);
C/C++ Code:
flpydsk_install(6);
C/C++ Code:
flpydsk_install(6);

... in flpydsk.c:
C/C++ Code:
void flpydsk_install(int irq)
{
    irq_install_handler(irq, i86_flpy_irq);
    flpydsk_initialize_dma();
    flpydsk_reset();
    flpydsk_drive_data(13, 1, 0xF, TRUE);
}
C/C++ Code:
void flpydsk_install(int irq)
{
irq_install_handler(irq, i86_flpy_irq);
flpydsk_initialize_dma();
flpydsk_reset();
flpydsk_drive_data(13, 1, 0xF, TRUE);
}
C/C++ Code:
void flpydsk_install(int irq)
{
    irq_install_handler(irq, i86_flpy_irq);
    flpydsk_initialize_dma();
    flpydsk_reset();
    flpydsk_drive_data(13, 1, 0xF, TRUE);
}

Dort müsste man nun weiter debuggen, wo es in der Funktion blockt. Es ist sicher ein Unterschied zwischen einer USB-Floppy und einer Floppy. Das heißt das Thema Booten und Floppy-/...-/Treiber hängt stark zusammen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:04:04 11.10.2009, insgesamt 1-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 20:13:22 11.10.2009   Titel:              Zitieren

Erhard Henkes schrieb:
@abc.w: Könntest Du das makefile bitte auch auf Windows übertragen?

Ich weiß leider nicht, was wären unter Windows Alternativen für dd, mount, umount und eject...
Linux -> Windows:
mkfs.msdos -> format
dd -> rawwrite ?
mount -> ?
cp -> copy
ls -> dir
umount -> ?
eject -> ?

Erhard Henkes schrieb:
Zitat:
mount: Es wurde kein Dateisystemtyp für /dev/sdc angegeben
Werde den Typ vfat versuchen

Kann man da FAT12 eingeben für die Floppy, damit die RootDir gelesen werden kann?

Die Diskette habe ich mit mkfs.msdos FAT12 formatiert (Parameter -F 12). mount benutzt vfat, weil ich es in der Konfiguration des Linux Kernels aktiviert habe und dort unter Hilfe steht:
Zitat:
CONFIG_VFAT_FS:
This option provides support for normal Windows file systems with
long filenames. That includes non-compressed FAT-based file systems
used by Windows 95, Windows 98, Windows NT 4.0, and the Unix
programs from the mtools package.
The VFAT support enlarges your kernel by about 10 KB and it only
works if you said Y to the "DOS FAT fs support" above...
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:33:26 11.10.2009   Titel:              Zitieren

Könntest Du in der 106er bitte diese ergänzte Funktion in flpydsk.c einbauen, um heraus finden, wo es bei Dir mit der USB-Floppy aussteigt:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
void flpydsk_install(int irq)
{
    irq_install_handler(irq, i86_flpy_irq);
    printformat("DEBUG flpydsk.c: after irq_install_handler");
    flpydsk_initialize_dma();
    printformat("DEBUG flpydsk.c: after flpydsk_initialize_dma");
    flpydsk_reset();
    printformat("DEBUG flpydsk.c: after flpydsk_reset");    
    flpydsk_drive_data(13, 1, 0xF, TRUE);
    printformat("DEBUG flpydsk.c: after flpydsk_drive_data");
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
void flpydsk_install(int irq)
{
irq_install_handler(irq, i86_flpy_irq);
printformat("DEBUG flpydsk.c: after irq_install_handler");
flpydsk_initialize_dma();
printformat("DEBUG flpydsk.c: after flpydsk_initialize_dma");
flpydsk_reset();
printformat("DEBUG flpydsk.c: after flpydsk_reset");
flpydsk_drive_data(13, 1, 0xF, TRUE);
printformat("DEBUG flpydsk.c: after flpydsk_drive_data");
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
void flpydsk_install(int irq)
{
    irq_install_handler(irq, i86_flpy_irq);
    printformat("DEBUG flpydsk.c: after irq_install_handler");
    flpydsk_initialize_dma();
    printformat("DEBUG flpydsk.c: after flpydsk_initialize_dma");
    flpydsk_reset();
    printformat("DEBUG flpydsk.c: after flpydsk_reset");    
    flpydsk_drive_data(13, 1, 0xF, TRUE);
    printformat("DEBUG flpydsk.c: after flpydsk_drive_data");
}

Ich tippe auf "flpydsk_drive_data" als Hemmschuh. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:33:50 11.10.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:36:14 11.10.2009   Titel:              Zitieren

Zitat:
Ich weiß leider nicht, was wären unter Windows Alternativen für dd, mount, umount und eject...
Linux -> Windows:
mkfs.msdos -> format
dd -> rawwrite ?
mount -> ?
cp -> copy
ls -> dir
umount -> ?
eject -> ?

Anstelle rawwrite nehme ich lieber das primitive partcopy, weil ich rawwrite nicht aus dem makefile sauber ansteuern konnte. mount/unmount keine Ahnung. Format macht man vorher.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 21:38:19 11.10.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Könntest Du in der 106er bitte diese ergänzte Funktion in flpydsk.c einbauen, um heraus finden, wo es bei Dir mit der USB-Floppy aussteigt:
C/C++ Code:
...
C/C++ Code:
...
C/C++ Code:
...

Kleiner Verbesserungsvorschlag zu Debug-Ausgaben: gcc kennt __FILE__ und __LINE__, z.B.:
C/C++ Code:
printformat("%s: %u", __FILE__, __LINE__);
printformat("DEBUG %s: after irq_install_handler (line %u)", __FILE__, __LINE__);
C/C++ Code:
printformat("%s: %u", __FILE__, __LINE__);
printformat("DEBUG %s: after irq_install_handler (line %u)", __FILE__, __LINE__);
C/C++ Code:
printformat("%s: %u", __FILE__, __LINE__);
printformat("DEBUG %s: after irq_install_handler (line %u)", __FILE__, __LINE__);
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 21:49:31 11.10.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Könntest Du in der 106er bitte diese ergänzte Funktion in flpydsk.c einbauen, um heraus finden, wo es bei Dir mit der USB-Floppy aussteigt:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
void flpydsk_install(int irq)
{
    irq_install_handler(irq, i86_flpy_irq);
    printformat("DEBUG flpydsk.c: after irq_install_handler");
    flpydsk_initialize_dma();
    printformat("DEBUG flpydsk.c: after flpydsk_initialize_dma");
    flpydsk_reset();
    printformat("DEBUG flpydsk.c: after flpydsk_reset");    
    flpydsk_drive_data(13, 1, 0xF, TRUE);
    printformat("DEBUG flpydsk.c: after flpydsk_drive_data");
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
void flpydsk_install(int irq)
{
irq_install_handler(irq, i86_flpy_irq);
printformat("DEBUG flpydsk.c: after irq_install_handler");
flpydsk_initialize_dma();
printformat("DEBUG flpydsk.c: after flpydsk_initialize_dma");
flpydsk_reset();
printformat("DEBUG flpydsk.c: after flpydsk_reset");
flpydsk_drive_data(13, 1, 0xF, TRUE);
printformat("DEBUG flpydsk.c: after flpydsk_drive_data");
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
void flpydsk_install(int irq)
{
    irq_install_handler(irq, i86_flpy_irq);
    printformat("DEBUG flpydsk.c: after irq_install_handler");
    flpydsk_initialize_dma();
    printformat("DEBUG flpydsk.c: after flpydsk_initialize_dma");
    flpydsk_reset();
    printformat("DEBUG flpydsk.c: after flpydsk_reset");    
    flpydsk_drive_data(13, 1, 0xF, TRUE);
    printformat("DEBUG flpydsk.c: after flpydsk_drive_data");
}

Ich tippe auf "flpydsk_drive_data" als Hemmschuh. :)

Bekomme folgende Ausgabe:
Code:
DEBUG flpydsk.c: after irq_install_handler
DEBUG flpydsk.c: after flpydsk_initialize_dma
Code:
DEBUG flpydsk.c: after irq_install_handler
DEBUG flpydsk.c: after flpydsk_initialize_dma
Code:
DEBUG flpydsk.c: after irq_install_handler
DEBUG flpydsk.c: after flpydsk_initialize_dma
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:12:33 11.10.2009   Titel:              Zitieren

Aha! Der Reset ist also schon das Problem.
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// reset controller
void flpydsk_reset()
{
    ULONG st0, cyl;
    flpydsk_disable_controller();
    flpydsk_enable_controller();
    flpydsk_wait_irq();

    // send CHECK_INT/SENSE INTERRUPT command to all drives
    int i;
    for(i=0; i<4; ++i)
        flpydsk_check_int(&st0,&cyl);
    flpydsk_write_ccr(0);              // transfer speed 500kb/s
    flpydsk_drive_data(3,16,240,TRUE); // pass mechanical drive info: steprate=3ms, load time=16ms, unload time=240ms
    flpydsk_calibrate(_CurrentDrive);  // calibrate the disk
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// reset controller
void flpydsk_reset()
{
ULONG st0, cyl;
flpydsk_disable_controller();
flpydsk_enable_controller();
flpydsk_wait_irq();

// send CHECK_INT/SENSE INTERRUPT command to all drives
int i;
for(i=0; i<4; ++i)
flpydsk_check_int(&st0,&cyl);
flpydsk_write_ccr(0); // transfer speed 500kb/s
flpydsk_drive_data(3,16,240,TRUE); // pass mechanical drive info: steprate=3ms, load time=16ms, unload time=240ms
flpydsk_calibrate(_CurrentDrive); // calibrate the disk
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// reset controller
void flpydsk_reset()
{
    ULONG st0, cyl;
    flpydsk_disable_controller();
    flpydsk_enable_controller();
    flpydsk_wait_irq();

    // send CHECK_INT/SENSE INTERRUPT command to all drives
    int i;
    for(i=0; i<4; ++i)
        flpydsk_check_int(&st0,&cyl);
    flpydsk_write_ccr(0);              // transfer speed 500kb/s
    flpydsk_drive_data(3,16,240,TRUE); // pass mechanical drive info: steprate=3ms, load time=16ms, unload time=240ms
    flpydsk_calibrate(_CurrentDrive);  // calibrate the disk
}

Ja, da ist bereits ein flpydsk_drive_data(...) drinnen, aber auch ein flpydsk_wait_irq(). Ganz schön verschachtelt der ganze Kram. Könntest Du bitte weiter suchen?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Unregistrierter





Beitrag Unregistrierter 22:16:24 11.10.2009   Titel:              Zitieren

Aha! Vielleicht ist ja alles ganz trivial:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// flpydsk.c (version 105+106)

// die 240 hier

void flpydsk_reset()
{
(...)
 flpydsk_drive_data(3,16,240,TRUE); // pass mechanical drive info: steprate=3ms, load time=16ms, unload time=240ms
(...)
}

// hat auf "data" keinen Einfluß: (240 & 0xF) -> 0
void flpydsk_drive_data(ULONG stepr, ULONG loadt, ULONG unloadt, int dma )
{
(...)
 data = ((stepr & 0xf) << 4) | (unloadt & 0xf);
 flpydsk_send_command(data);
(...)
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// flpydsk.c (version 105+106)

// die 240 hier

void flpydsk_reset()
{
(...)
flpydsk_drive_data(3,16,240,TRUE); // pass mechanical drive info: steprate=3ms, load time=16ms, unload time=240ms
(...)
}

// hat auf "data" keinen Einfluß: (240 & 0xF) -> 0
void flpydsk_drive_data(ULONG stepr, ULONG loadt, ULONG unloadt, int dma )
{
(...)
data = ((stepr & 0xf) << 4) | (unloadt & 0xf);
flpydsk_send_command(data);
(...)
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// flpydsk.c (version 105+106)

// die 240 hier

void flpydsk_reset()
{
(...)
 flpydsk_drive_data(3,16,240,TRUE); // pass mechanical drive info: steprate=3ms, load time=16ms, unload time=240ms
(...)
}

// hat auf "data" keinen Einfluß: (240 & 0xF) -> 0
void flpydsk_drive_data(ULONG stepr, ULONG loadt, ULONG unloadt, int dma )
{
(...)
 data = ((stepr & 0xf) << 4) | (unloadt & 0xf);
 flpydsk_send_command(data);
(...)
}
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:22:37 11.10.2009   Titel:              Zitieren

@ +gjm+: Bootest Du auch mittels USB-Floppy?

Zitat:
Aha! Vielleicht ist ja alles ganz trivial

Hast Du einen konkreten Verbesserungsvorschlag? Mit einem klassisch angebundenen Floppy-LW läuft es (fast überall, einige störrische PCs gibt es leider immer).

http://www.isdaman.com/alsos/hardware/fdc/floppy.htm
siehe Abschnitt "Fix Drive Data (x3h)"
http://www.isdaman.com/alsos/hardware/fdc/floppy_files/FixData.gif
Ich denke, dass die ganze Funktion falsch aufgebaut ist, 240 daher ein Fehler und 15 (0xF) als "Head Unload Time Entry" richtig ist.
Passt ja auch zu: flpydsk_write_ccr(0); // transfer speed 500kb/s

Auf jeden Fall erkennt man hier, dass Floppy-Treiber und Bootloader momentan bei PrettyOS von einer gemeinsamen Gruppe bearbeitet werden müssen. Wir sind ja schon mitten drin. :)

Also folgendes probieren:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// reset controller
void flpydsk_reset()
{
    ULONG st0, cyl;
    flpydsk_disable_controller ();
    flpydsk_enable_controller ();
    flpydsk_wait_irq ();

    // send CHECK_INT/SENSE INTERRUPT command to all drives
    int i;
    for(i=0; i<4; ++i)
        flpydsk_check_int(&st0,&cyl);
    flpydsk_write_ccr(0);              // transfer speed 500kb/s
    flpydsk_drive_data(3,16,0xF,TRUE); // pass mechanical drive info: steprate=3ms, load time=16ms, unload time=240ms (entry: 0xF) //http://www.isdaman.com/alsos/hardware/fdc/floppy.htm //Fix Drive Data (x3h)
    flpydsk_calibrate(_CurrentDrive);  // calibrate the disk
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// reset controller
void flpydsk_reset()
{
ULONG st0, cyl;
flpydsk_disable_controller ();
flpydsk_enable_controller ();
flpydsk_wait_irq ();

// send CHECK_INT/SENSE INTERRUPT command to all drives
int i;
for(i=0; i<4; ++i)
flpydsk_check_int(&st0,&cyl);
flpydsk_write_ccr(0); // transfer speed 500kb/s
flpydsk_drive_data(3,16,0xF,TRUE); // pass mechanical drive info: steprate=3ms, load time=16ms, unload time=240ms (entry: 0xF) //http://www.isdaman.com/alsos/hardware/fdc/floppy.htm //Fix Drive Data (x3h)
flpydsk_calibrate(_CurrentDrive); // calibrate the disk
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// reset controller
void flpydsk_reset()
{
    ULONG st0, cyl;
    flpydsk_disable_controller ();
    flpydsk_enable_controller ();
    flpydsk_wait_irq ();

    // send CHECK_INT/SENSE INTERRUPT command to all drives
    int i;
    for(i=0; i<4; ++i)
        flpydsk_check_int(&st0,&cyl);
    flpydsk_write_ccr(0);              // transfer speed 500kb/s
    flpydsk_drive_data(3,16,0xF,TRUE); // pass mechanical drive info: steprate=3ms, load time=16ms, unload time=240ms (entry: 0xF) //http://www.isdaman.com/alsos/hardware/fdc/floppy.htm //Fix Drive Data (x3h)
    flpydsk_calibrate(_CurrentDrive);  // calibrate the disk
}

0xF anstelle 240

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:19:55 11.10.2009, insgesamt 4-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 23:18:20 11.10.2009   Titel:              Zitieren

Erhard Henkes schrieb:
@ +gjm+: Bootest Du auch mittels USB-Floppy?
Asche auf mein Haupt! Das hätte ich lieber mal von Anfang an sagen sollen: Stage 1 in seiner jetzigen Form funktioniert nur mit Floppy-Laufwerken. Das er (scheinbar) auch mit USB-Floppys oder USB-Sticks funktioniert, hat einen ganz trivialen Grund: Das BIOS emuliert! Aber spätestens nach Stage 2 ist der Prozessor im PM. Dann ist Feierabend mit dem BIOS und PrettyOS läuft nur noch solange nach Plan weiter, bis es zum ersten Zugriff im PM auf das Laufwerk kommt. Effektiv testen (was heißt über Stage 2 hinaus) kann man PrettyOS z.Zt. nur mit einem physikalisch vorhandenen Floppy-Laufwerk. (Oder indem der Quellcode gelesen wird). Aber technisch gesehen ist es nach wie vor möglich, PrettyOS von einem USB-Floppy oder einem "pen drive" zu starten. Die Frage ist eigentlich nur, ob man im PM auf das "Bootgerät" zugreifen will oder muß (oder wird). Deshalb gibt es in dem Sinne leider auch keine Verbesserungsvorschläge.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:32:42 11.10.2009   Titel:              Zitieren

@ +gjm+: Du meinst der Floppy-Treiber kann nichts ausrichten, weil er nicht mehr an den Floppy-Controller heran kommt? Ich kann es nicht testen, weil ich kein USB-Floppy-LW besitze.

Auf jeden Fall haben wir einen Fehler im Floppy-Treiber gefunden. Wenn man bei 500K Transfer Rate die 240 ms Head Unload Time haben will, muss man 0xF eingeben und nicht 240. Analog muss man auch noch die Head Load Time Eingabe überprüfen. Da macht das offensichtlich aber nur Faktor 2 aus. :)
http://www.isdaman.com/alsos/hardware/fdc/floppy.htm

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:40:36 11.10.2009, insgesamt 2-mal bearbeitet
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 148
Beitrag taljeth Mitglied 23:35:28 11.10.2009   Titel:              Zitieren

Auf den FDC zugreifen, bringt offensichtlich nichts, wenn das Laufwerk ein USB-Gerät ist. In dem Fall bräuchtest du USB-Treiber. Das BIOS bietet dir halt den passenden Treiber über int 13h an, deswegen funktioniert das, solange du das BIOS benutzt.

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:39:59 11.10.2009   Titel:              Zitieren

Das wirft nun für die OS-Community Grundsatzfragen für das Design auf, denn die meisten User haben heutzutage kein klassisch angeschlossenes Floppy-LW mehr, lediglich die USB-Variante.
@ taljeth: hast Du einen Link auf ein Beispiel, wo jemand mit USB-Treiber auf eine Floppy zugreift? Auf der anderen Seite wäre dann der USB-Stick die bessere Variante. Also entweder klassische Floppy oder USB-Stick?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:03:05 12.10.2009, insgesamt 2-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 00:05:44 12.10.2009   Titel:              Zitieren

Mal nicht so schnell jetzt. Im Prinzip darf in der ckernel.c nur nicht "direkt" (was heißt per Name) auf "irgendwas" in der flpydsk.c zugegriffen werden. Das ist eigentlich schon alles was vielleicht geändert werden sollte. Irgendwann kommt eh noch eine pendrv.c hinzu. :)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:19:26 12.10.2009   Titel:              Zitieren

@ +gjm+: Wir sind noch zusammen.

http://www.usb-center.de/Externe_USB-Floppy_-_USB-Diskettenlaufwerk_USB-1901.html
Zitat:
Technischer Hinweis: Die USB-Diskettenlaufwerke ... sind bootfähig. Voraussetzung ist jedoch ein erweiterter USB-Support des Bios. Sollte Ihr Computer nicht von dem USB-Floppy starten, drücken Sie während des Startvorgangs die Taste "F2" oder "Entf" um in das Bios-Menü zu gelangen. Suchen Sie den Eintrag "USB Legacy Support" und aktivieren Sie die Funktion ("Enabled"). Zum Abschluss müssen Sie über den Menüpunkt "beenden und speichern" (save and exit) das Bios wieder verlassen, damit die Änderungen gespeichert werden. Einige ältere Computer, besonders Fertigrechner aus diversen Supermärkten, unterstützden diese erweiterte USB-Funktion nicht.


Zitat:
Im Prinzip darf in der ckernel.c nur nicht "direkt" (was heißt per Name) auf "irgendwas" in der flpydsk.c zugegriffen werden.
Richtig, da muss eine Abstraktionsebene dazwischen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:26:17 12.10.2009, insgesamt 2-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 01:12:44 12.10.2009   Titel:              Zitieren

Ehrlich gesagt habe ich die USB-Floppy eigentlich für einen Hoax gehalten. Wenn PrettyOS USB im PM unterstützt, dann werden gleichzeitig eine ganze Reihe von Geräten unterstützt. Darauf sollte PrettyOS durch "Abstraktion" langsam vorbeitet werden. Aber bevor die Geräteflut hereinbricht.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 17:25:48 12.10.2009   Titel:              Zitieren

Heute abend um 21.20 h treffen wir uns im Channel #PrettyOS. :live:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
;fricky
Unregistrierter




Beitrag ;fricky Unregistrierter 17:34:56 12.10.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Heute abend um 21.20 h treffen wir uns im Channel #PrettyOS.

^^ vielleich schau ich auch mal rein.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 17:37:19 12.10.2009   Titel:              Zitieren

Zitat:
^^ vielleich schau ich auch mal rein.
Ja, mache das! Wäre schön.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
;fricky
Unregistrierter




Beitrag ;fricky Unregistrierter 00:22:01 13.10.2009   Titel:              Zitieren

erhard:
http://www.usb.org/developers/docs/usb_20_052709.zip
http://www.compaq.com/productinfo/development/openhci.html
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:32:16 13.10.2009   Titel:              Zitieren

Thx :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:37:42 13.10.2009   Titel:              Zitieren

Dass dieser Thread mal die 50000er Lese-Marke knackt, hätte ich mir am 13.03.2009 nicht träumen lassen.

Zitat:
Mich würde mal interessieren, wer alleine oder mit anderen an einem eigenen OS entwickelt, zu welchem Zweck und in welcher Sprache (ASS, C oder C++)? Links?

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
;fricky
Unregistrierter




Beitrag ;fricky Unregistrierter 00:39:09 13.10.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Thx :)

kein problem, ist aber tatsächlich viel holz. wäre ein fulltime job für 1..2 monate (lernaufwand für PCI bussystem und hardware interrupt-handling auf pc-kisten nicht eingerechnet). aber nicht so, wie dieser trottel 'XanClic' erzählt. der scheint das ganze nur sabotieren zu wollen.
:)
Unregistrierter





Beitrag Unregistrierter 01:01:41 13.10.2009   Titel:              Zitieren

Einfach nur den Begriff "DOS" ignorieren:
http://www.frontiernet.net/~fys/usb.htm
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 148
Beitrag taljeth Mitglied 10:59:34 13.10.2009   Titel:              Zitieren

;fricky schrieb:
kein problem, ist aber tatsächlich viel holz. wäre ein fulltime job für 1..2 monate (lernaufwand für PCI bussystem und hardware interrupt-handling auf pc-kisten nicht eingerechnet). aber nicht so, wie dieser trottel 'XanClic' erzählt. der scheint das ganze nur sabotieren zu wollen.

Bei allem gebotenen Respekt, aber der "Trottel" XanClic hat vermutlich etwas mehr OS-Dev-Erfahrung als du (und auch als Erhard). Davon abgesehen scheinst du ja nicht vollkommen anderer Meinung sein, denn wenn du zwei Monate Vollzeit mal auf ein Freizeitprojekt umrechnest, bist du locker mit einem Jahr oder mehr dabei. Ein Jahr wohlgemerkt, in dem du ansonsten nichts anderes weiterentwickeln würdest.

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community
;fricky
Unregistrierter




Beitrag ;fricky Unregistrierter 11:35:45 13.10.2009   Titel:              Zitieren

taljeth schrieb:

Bei allem gebotenen Respekt, aber der "Trottel" XanClic hat vermutlich etwas mehr OS-Dev-Erfahrung als du (und auch als Erhard).

dass er sich besser mit der PC-plattform auskennt, zweifle ich garnicht an. aber dass er meine fragen nicht beantworten konnte und sein allgemein arrogantes gehabe, lassen darauf schliessen, dass er nur ein oberflächlicher frickler ist, dessen kleine erfolge ihn viel schweiss und gehirnschmalz gekostet haben. darauf kann er sich gern ausruhen und es als 'os-dev-erfahrung' verkaufen, aber als berater zum thema USB halte ich ihn für ungeeignet.
btw, ich hab' bisher nur usb-devices mit intelligenten controllern (vinculum) angesteuert, die den ganzen USB-protokollstack schon mitbringen. aber seit der diskussion von gestern, beginnt mich das thema zu interessieren (z.b. selbst mal 'nen USB-host für primitivere controller zu implementieren). der link von +gjm+ sieht auch sehr vielversprechend aus.
@erhard: falls ich in der richtung was machen sollte, kannste das gern in dein OS integrieren. ich werde vermutlich mein selbstgemachtes 'spezial-windows-ddk' dafür verwenden. das ist eine entwicklungsumgebung zur ansteuerung von hardware, die am PC angeschlossen wird (am PCI- bzw. PCMCIA-bus), die unter win-2k läuft. damit habe ich schon ein paar treiber geschrieben, die dann auf diverse mikrocontroller portiert wurden.
:)
DerHartmut
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 27
Beitrag DerHartmut Mitglied 12:34:44 13.10.2009   Titel:   Jetzt mal was von mir            Zitieren

Zitat:
zweifle ich garnicht an. aber dass er meine fragen nicht beantworten konnte und sein allgemein arrogantes gehabe, lassen darauf schliessen, dass er nur ein oberflächlicher frickler ist, dessen kleine erfolge ihn viel schweiss und gehirnschmalz gekostet haben. darauf kann er sich gern ausruhen und es als 'os-dev-erfahrung' verkaufen, aber als berater zum thema USB halte ich ihn für ungeeignet.


Ich habe den Log gelesen (komme aus #lost, Erhard dürfte mich kennen ;)) und habe lediglich daraus schließen können, dass du nicht in der Lage bist, einen Text in einem Zusammenhang zu lesen und gegebene Ratschläge anzunehmen, fricky.

XanClic programmiert seit 3 Jahren Betriebssysteme und hat so einiges auf dem Kasten. Und natürlich hat er wie auch ich und wie auch taljeth und wie eigentlich jeder OS-Dever viel Gehirnschmalz und Fleiß investiert, um auf den heutigen Wissensstand zu kommen. Und natürlich kommt mit dem Lernprozess und den damit verbundenen Tiefschlägen und Fehler die man macht die Erfahrung. Er hat sehr wohl Erfahrung, ja sogar mehr als ich. Und "kleine Erfolge" ist ja wohl subjektiv, für mich war es damals ein großes Erfolg, "Hallo Welt" auf dem Bildschirm ohne Windows/Linux auszugeben.

Wieso hälst du ihn als Berater für das Thema USB ungeeignet? Weil er mehr Ahnung hat als du und du dich in deiner Kompetenz eingeschränkt siehst? Und außerdem hat er es mit Sicherheit nicht nötig, das Projekt zu sabotieren. Wieso auch, wenn er sich stundenlang mit einem so uneinsichtigen Menschen wie dir freiwillig unterhält?

Ps: Bevor du über Menschen urteilst, die du nicht kennst, lerne doch bitte Rechtschreibung sowie allgemeine Form und Schrift. Danke.


Zuletzt bearbeitet von DerHartmut am 12:36:56 13.10.2009, insgesamt 2-mal bearbeitet
;fricky
Unregistrierter




Beitrag ;fricky Unregistrierter 14:03:58 13.10.2009   Titel:   Re: Jetzt mal was von mir            Zitieren

DerHartmut schrieb:

XanClic programmiert seit 3 Jahren Betriebssysteme und hat so einiges auf dem Kasten.

mag ja sein, aber wenn er noch nicht mal 2 einfache fragen beantworten kann, dann hilft das keinen weiter, auch wenn er 30 jahre an seinem hobby-OS rumgebastelt hat.

DerHartmut schrieb:

Wieso hälst du ihn als Berater für das Thema USB ungeeignet? Weil er mehr Ahnung hat als du und du dich in deiner Kompetenz eingeschränkt siehst?

meine kompetenz bezüglich pc-hardware ist nahe bei 0, jedes kind, das schon mal 'nen pc zusammengeschustert hat, kennt sich in der hinsicht besser aus. XanClic ist als berater ungeeignet, weil er sein mühsam erworbenes (halb?)wissen nicht preisgeben kann oder will. wenn ich mich 'nen halben tag hinsetze, google, USB-specs, codebeispiele usw. durchgehe, bringt das sicherlich mehr.
:)
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 95
Beitrag XanClic Mitglied 14:30:17 13.10.2009   Titel:              Zitieren

Ich darf doch auch, oder? :D

fricky schrieb:
mag ja sein, aber wenn er noch nicht mal 2 einfache fragen beantworten kann

Soweit ich das sehe, hab ich sie beantwortet. Du kannst sie mir hier gern nochmal genau stellen, damit ich das weiß.
Ich weiß zum Beispiel noch, dass du wissen wolltest, welche USB-Chipsätze es gebe. Ich hab dir gesagt, es gibt vier Host-Controller-Arten. OHC, UHC, EHC und xHC. Und für die brauchst du jeweils einen Treiber.

fricky schrieb:
XanClic ist als berater ungeeignet

Hab ich mich jemals als Berater bezeichnet? Ich bin gar keiner. Und ich konnte noch nie gut erklären.

fricky schrieb:
wenn ich mich 'nen halben tag hinsetze, google, USB-specs, codebeispiele usw. durchgehe, bringt das sicherlich mehr.

Dann tu das doch. ;)
Das hab ich schließlich auch gemacht.
Unregistrierter





Beitrag Unregistrierter 14:45:26 13.10.2009   Titel:              Zitieren

XanClic schrieb:
Ich weiß zum Beispiel noch, dass du wissen wolltest, welche USB-Chipsätze es gebe. Ich hab dir gesagt, es gibt vier Host-Controller-Arten. OHC, UHC, ...

Ein "nein" hätte gereicht.
DerHartmut
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 27
Beitrag DerHartmut Mitglied 16:04:12 13.10.2009   Titel:              Zitieren

Zitat:
wenn ich mich 'nen halben tag hinsetze, google, USB-specs, codebeispiele usw. durchgehe, bringt das sicherlich mehr.


Wenn du dadurch allerdings kein Wissen erlangst: Prost Mahlzeit.

Aber lass uns das doch einfach in #PrettyOS klären, der Anlaufstelle für einen unterhaltsamen und konstruktiven Abend ;)
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 95
Beitrag XanClic Mitglied 17:00:35 13.10.2009   Titel:              Zitieren

+gjm+ schrieb:
Ein "nein" hätte gereicht.

OK, dann zitiere ich eben korrekt:

fricky in #PrettyOS schrieb:
was ist mit den usb-controllern in PCs? gibt es da einen standardtypen?

Genau das hat er gefragt. Und unter "Controller" verstehe ich bei USB nun einmal "Host Controller". Entschuldigung, dass ich das falsch wiedergegeben habe.

EDIT: Bevor ich hier beschuldigt werde, irgendwas aus dem Zusammenhang zu reißen. Mein Log:

Zitat:
[Mo Okt 12 2009] [22:54:01] <fricky> was ist mit den usb-controllern in PCs? gibt es da einen standardtypen?
[...]
[Mo Okt 12 2009] [22:54:21] <XanClic> fricky: Es gibt OHCI, UHCI, EHCI und seit 3.0 auch xHCI
[...]
[Mo Okt 12 2009] [22:54:49] <fricky> XanClic: heist so der chip(satz)?
[Mo Okt 12 2009] [22:54:55] <XanClic> fricky: Hm?
[Mo Okt 12 2009] [22:55:04] <XanClic> Wieviel weißt du über USB? ^^
[Mo Okt 12 2009] [22:55:07] <fricky> OHCI, UHCI usw?
[Mo Okt 12 2009] [22:55:17] <XanClic> Das nennt sich Host Controller
[Mo Okt 12 2009] [22:55:23] <XanClic> Und danach hast du gefragt
[Mo Okt 12 2009] [22:55:36] <XanClic> Strenggenommen müsste man die Is weglassen, also OHC, UHC, EHC und xHC
[Mo Okt 12 2009] [22:55:52] <fricky> XanClic: welche hardware ist dafür nötig. gibt es einen standard-chip im pc dafür?
[Mo Okt 12 2009] [22:56:04] <fricky> oder viele verschiedene?
[Mo Okt 12 2009] [22:56:07] <XanClic> Es gibt diese.
[Mo Okt 12 2009] [22:56:13] <XanClic> Für USB-1.x-Geräte gibt es OHC und UHC
[Mo Okt 12 2009] [22:56:16] <XanClic> Für 2.0 EHC
[Mo Okt 12 2009] [22:56:19] <XanClic> Und für 3.0 xHC

Hinweis: Die [...]-Sachen waren ein Gespräch mit ehenkes und haben mit diesem Gesprächsfaden nichts zu tun.


Zuletzt bearbeitet von XanClic am 17:02:46 13.10.2009, insgesamt 1-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 17:19:00 13.10.2009   Titel:              Zitieren

Zitat:
Mo Okt 12 2009] [22:54:01] <fricky> was ist mit den usb-controllern in PCs? gibt es da einen standardtypen?
[...]
[Mo Okt 12 2009] [22:54:21] <XanClic> fricky: Es gibt OHCI, UHCI, EHCI und seit 3.0 auch xHCI
[...]
[Mo Okt 12 2009] [22:55:52] <fricky> XanClic: welche hardware ist dafür nötig. gibt es einen standard-chip im pc dafür?
[Mo Okt 12 2009] [22:56:04] <fricky> oder viele verschiedene?
[Mo Okt 12 2009] [22:56:07] <XanClic> Es gibt diese.

@Stasi 2.0: Ein "nein" hätte gereicht.
;fricky
Unregistrierter




Beitrag ;fricky Unregistrierter 18:13:48 13.10.2009   Titel:              Zitieren

XanClic schrieb:

Ich weiß zum Beispiel noch, dass du wissen wolltest, welche USB-Chipsätze es gebe. Ich hab dir gesagt, es gibt vier Host-Controller-Arten. OHC, UHC, EHC und xHC.

und hätte ich dich gefragt: 'was ist ein auto?', dann hätteste du geantwortet: 'es gibt grüne, gelbe und blaue', nicht wahr?

DerHartmut schrieb:

Aber lass uns das doch einfach in #PrettyOS klären, der Anlaufstelle für einen unterhaltsamen und konstruktiven Abend

machen wir. ich schaue da bestimmt bald mal wieder rein.
:)
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 95
Beitrag XanClic Mitglied 19:15:59 13.10.2009   Titel:              Zitieren

fricky schrieb:
und hätte ich dich gefragt: 'was ist ein auto?', dann hätteste du geantwortet: 'es gibt grüne, gelbe und blaue', nicht wahr?

Nö, nur wenn du mich gefragt hättest: "Was für Autos gibt es?" Und dann hätte ich gesagt: "Es gibt PKWs mit Automatik, ohne Automatik, LKWs, ... Du musst nicht wissen, wie du jedes einzelne Auto steuerst, weil sich alle Autos eines Typs gleich steuern lassen."

+gmj+ schrieb:
@Stasi 2.0: Ein "nein" hätte gereicht.

1. Super, wie du meine regionale Herkunft aus meinen Aussagen ableitest. 100 Punkte :D
2. "nein" ist doch gar keine richtige Antwort? Natürlich gibt es keinen Standard-Chip, aber es gibt vier Standardtypen, die sich jeweils gleich ansteuern lassen. btw, schön, dass mir angekreidet wird, nichts zu erklären, ich dann aber dafür als "Stasi" bezeichnet werden (weil ich logge, haha, dabei macht Konversation das doch automatisch für mich), wenn ich mal eine differenzierte Antwort gebe.


Zuletzt bearbeitet von XanClic am 19:16:46 13.10.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:04:03 13.10.2009   Titel:              Zitieren

Also zunächst möchte ich allen danken, die bereit sind, unsere OS-Community in ihren Anfängen zu unterstützen und sich im IRC channel #PrettyOS einfinden. Ich gehe davon aus, dass bei allen Teilnehmern das Interesse an Vermehrung von Wissen und praktischer Erfahrung im OS-Bereich im Vordergrund steht. Bei manchen Themen führt eine emotional engagierte Diskussion auch zu einer wirklichen Klärung anstelle zu fortgesetzten, lauwarmen theoretischen Diskussionen. Wir haben gesehen, dass das Thema USB-Treiber besetzt und bearbeitet werden muss, soweit ok. Ich denke, es ist auch klar geworden, dass wir zunächst ohne GRUB auskommen wollen. Hier lassen wir nicht mit uns reden. Soweit so gut.

Der IRC ist m.E. zur Klärung detaillierter Sachfragen nicht sonderlich gut geeignet. Dafür geht dort momentan noch zuviel durcheinander. Im Forum können wir solchen Themen, gestützt durch vertiefte Recherchen und Nachdenken, hoffentlich besser auf den Grund gehen.

Ich danke ;fricky und XanClic dennoch für die engagierte Diskussion und bitte alle darum, in diesem Thread und diesem wirklich sachlichen Subforum von persönlichen Angriffen und dem Zitieren unseres Chat-Protokolls abzusehen.

Wir sollten das Sachliche wieder rasch in den Mittelpunkt der Diskussion rücken. Gemeinsames Ziel ist ein breit funktionierender USB-Treiber, um auf moderner Hardware zu bestehen. :)

XanClic hat seine Arbeit übrigens großzügig zur Verfügung gestellt. Das macht nicht jeder! :live:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:06:39 13.10.2009, insgesamt 1-mal bearbeitet
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 148
Beitrag taljeth Mitglied 20:26:28 13.10.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Ich denke, es ist auch klar geworden, dass wir zunächst ohne GRUB auskommen wollen. Hier lassen wir nicht mit uns reden. Soweit so gut.

Das ist ja auch in Ordnung. Solange ihr nicht wollt, dass wir euren Bootloader fixen, ist das euer eigenes Problem. ;)

Zitat:
Der IRC ist m.E. zur Klärung detaillierter Sachfragen nicht sonderlich gut geeignet.

Meine Erfahrung sagt, dass man im IRC im allgemeinen schneller zu einer Lösung kommt als im Forum. Ich würde die beiden Dienste ungefähr in einem Verhältnis sehen wie das Telefon zu einem Brief. Der Brief ist verbindlicher, aber Telefon geht schneller.


Zuletzt bearbeitet von taljeth am 20:26:48 13.10.2009, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:48:48 13.10.2009   Titel:              Zitieren

Zitat:
Telefon geht schneller

IRC ist ein Telefonat mit Mitschnitt, also nicht wirklich vergleichbar. So etwas würde niemand privat oder geschäftlich nutzen! Das Ergebnis sieht man oben.

Ich bin wirklich an einer friedlichen Koexistenz im Dienst der Sache interessiert und bitte Dich uns diesbezüglich zu unterstützen.

Zitat:
Solange ihr nicht wollt, dass wir euren Bootloader fixen, ist das euer eigenes Problem.
Wie sagte PorkChicken so nett? Assembler ist etwas für die Elite, also offensichtlich für ihn, und ich denke auch für das Assembler-Forum hier. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:50:09 13.10.2009, insgesamt 1-mal bearbeitet
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 148
Beitrag taljeth Mitglied 21:10:00 13.10.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zitat:
Telefon geht schneller

IRC ist ein Telefonat mit Mitschnitt, also nicht wirklich vergleichbar. So etwas würde niemand privat oder geschäftlich nutzen! Das Ergebnis sieht man oben.

Verallgemeinerungen sind immer falsch.

Wenn IRC weder privat noch geschäftlich genutzt werden würde, würde es mangels Nutzern nicht existieren. Offensichtlich ist es aber doch sehr existent.

Zitat:
Wie sagte PorkChicken so nett? Assembler ist etwas für die Elite, also offensichtlich für ihn, und ich denke auch für das Assembler-Forum hier. ;)

Ironiedetektor nachjustieren lassen? ;)

Mit elitaeren Gruessen
taljeth

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:11:43 13.10.2009   Titel:              Zitieren

Zitat:
Verallgemeinerungen sind immer falsch
Damit auch dieser Satz. :D

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 148
Beitrag taljeth Mitglied 21:29:19 13.10.2009   Titel:              Zitieren

Erklärte Witze sind doof.

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 22:33:11 13.10.2009   Titel:              Zitieren

Anbei die Ausgabe von lspci auf meinem Laptop:
Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
# lspci
...
00:1d.0 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI Controller #1 (rev 02)
00:1d.1 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI Controller #2 (rev 02)
00:1d.2 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI Controller #3 (rev 02)
00:1d.3 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI Controller #4 (rev 02)
00:1d.7 USB Controller: Intel Corporation 82801G (ICH7 Family) USB2 EHCI Controller (rev 02)
...
Code:
1
2
3
4
5
6
7
8
# lspci
...
00:1d.0 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI Controller #1 (rev 02)
00:1d.1 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI Controller #2 (rev 02)
00:1d.2 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI Controller #3 (rev 02)
00:1d.3 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI Controller #4 (rev 02)
00:1d.7 USB Controller: Intel Corporation 82801G (ICH7 Family) USB2 EHCI Controller (rev 02)
...
Code:
1
2
3
4
5
6
7
8
# lspci
...
00:1d.0 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI Controller #1 (rev 02)
00:1d.1 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI Controller #2 (rev 02)
00:1d.2 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI Controller #3 (rev 02)
00:1d.3 USB Controller: Intel Corporation 82801G (ICH7 Family) USB UHCI Controller #4 (rev 02)
00:1d.7 USB Controller: Intel Corporation 82801G (ICH7 Family) USB2 EHCI Controller (rev 02)
...

O je, wie würde man jetzt dafür einen Treiber schreiben :eek:
~~~~
Unregistrierter




Beitrag ~~~~ Unregistrierter 23:26:22 13.10.2009   Titel:              Zitieren

Man setzt sich hin, liest die Spezifikationen für UHCI und EHCI, erkennt die Geräte über PCI und nutzt sie dann gemäß Spezifikation. Ja, so einfach kann das sein.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:46:01 13.10.2009   Titel:              Zitieren

Zitat:
Ja, so einfach kann das sein.
Dann ist ja alles gut. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:46:51 13.10.2009   Titel:              Zitieren

Zitat:
Erklärte Witze sind doof.
Ich dachte, Du meinst das wirklich ernst. :D

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
;fricky
Unregistrierter




Beitrag ;fricky Unregistrierter 00:58:36 14.10.2009   Titel:              Zitieren

Erhard Henkes schrieb:
Zitat:
Ja, so einfach kann das sein.
Dann ist ja alles gut.

er hat aber recht, so wie's aussieht, steht im 'OpenHCI' spec alles wichtige drin, um die meisten USB-controller zum leben zu erwecken (nur eben ohne die USB2.0 funktionalität). man muss sich nur die zeit nehmen und sich damit auseinandersetzen. dann braucht man auch nicht 3 mal neu anzufangen (wer hat das gestern noch erzählt?). *fg*
btw, das buch mit dem vielversprechenden namen: 'USB Design by Example' konnte ich leider noch nirgends finden.
ach ja, für USB 2.0/'ehci': http://developer.intel.com/technology/usb/download/ehci-r10.pdf
:)
;fricky
Unregistrierter




Beitrag ;fricky Unregistrierter 01:14:49 14.10.2009   Titel:              Zitieren

ah, doch gefunden, bei esnips.com. link darf ich leider nicht posten, weil auf dem buch wohl ein copyright ist.
:)
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 148
Beitrag taljeth Mitglied 10:27:21 14.10.2009   Titel:              Zitieren

;fricky schrieb:
Erhard Henkes schrieb:
Zitat:
Ja, so einfach kann das sein.
Dann ist ja alles gut.

er hat aber recht, so wie's aussieht, steht im 'OpenHCI' spec alles wichtige drin, um die meisten USB-controller zum leben zu erwecken (nur eben ohne die USB2.0 funktionalität).

Außer Intelrechner, die benutzen nicht OHCI, sondern UHCI.

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community
;fricky
Unregistrierter




Beitrag ;fricky Unregistrierter 12:06:54 14.10.2009   Titel:              Zitieren

taljeth schrieb:

Außer Intelrechner, die benutzen nicht OHCI, sondern UHCI.

wie ich bis jetzt mitbekommen habe, ist 'uhci' die älteste variante (USB 1.0). wikipedia sagt zwar, 'intel und VIA' benutzen noch UHCI, aber meine kiste zeigt mir 2 openHCI (USB 1.1) interfaces an, obwohl der host-controller von VIA ist.
btw: wie weit wird UHCI heute noch verwendet?
für alle, die wissen wollen um was es geht, hier ein link zur erklärung von OHCI/UHCI/EHCI: http://en.wikipedia.org/wiki/Open_Host_Controller_Interface
:)
taljeth
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.09.2009
Beiträge: 148
Beitrag taljeth Mitglied 12:33:15 14.10.2009   Titel:              Zitieren

OHCI und UHCI sind beide USB 1.x, nur von verschiedenen Herstellern.

_________________
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.
Lowlevel - die deutschsprachige OS-Dev-Community
XanClic
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.10.2009
Beiträge: 95
Beitrag XanClic Mitglied 13:32:51 14.10.2009   Titel:              Zitieren

fricky schrieb:
btw: wie weit wird UHCI heute noch verwendet?

Ich kann dir verraten, dass mein Laptop UHCI hat. Und der ist bald zwei Jahre alt, also noch nicht extrem veraltet.
;fricky
Unregistrierter




Beitrag ;fricky Unregistrierter 14:23:33 14.10.2009   Titel:              Zitieren

XanClic schrieb:
fricky schrieb:
btw: wie weit wird UHCI heute noch verwendet?

Ich kann dir verraten, dass mein Laptop UHCI hat. Und der ist bald zwei Jahre alt, also noch nicht extrem veraltet.

ok danke, aber irgendwo muss man ja anfangen. ich glaub' ich werde mich erstmal auf 'openHCI' konzentrieren.
:)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:47:34 15.10.2009   Titel:              Zitieren

@ abc.w und +gjm+ : Hier eine Version, die mit USB-Floppy booten und bis in die Shell laufen sollte: http://www.henkessoft.de/OS_Dev/Downloads/107.zip
Will nur mal sehen, ob da alles klappt unter Linux mit USB-Floppy o.ä. zum Booten.
Die Shell wird mittels incbin in den Kernel eingeschleust. Das ist program.elf in der user-Subdirectory.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Unregistrierter





Beitrag Unregistrierter 21:45:15 15.10.2009   Titel:              Zitieren

Perfekt! :live:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PrettyOS [Version 0.1.0107] (C) 2009 henkesoft.de

Usable RAM: 3931391 KB

Ram Disk at: 4008100Ch

<DIR> dev

35   file1
35   file2
35   file3
1825 shell

$>_

$>hi <--
I am PrettyOS. Always at your service!
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PrettyOS [Version 0.1.0107] (C) 2009 henkesoft.de

Usable RAM: 3931391 KB

Ram Disk at: 4008100Ch

<DIR> dev

35 file1
35 file2
35 file3
1825 shell

$>_

$>hi <--
I am PrettyOS. Always at your service!
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PrettyOS [Version 0.1.0107] (C) 2009 henkesoft.de

Usable RAM: 3931391 KB

Ram Disk at: 4008100Ch

<DIR> dev

35   file1
35   file2
35   file3
1825 shell

$>_

$>hi <--
I am PrettyOS. Always at your service!
P.S.: Ich habe Windows Vista (64 bit). Das sollte aber für das booten und testen von PrettyOS ohne Bedeutung sein.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:26:07 15.10.2009   Titel:              Zitieren

Schön, das dies alles bestens auch unter Linux und mit USB-Floppy klappt. :)

Zum Erstellen von PrettyOS kann man Linux, WinXP, Vista, Windows7 verwenden.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:53:47 17.10.2009, insgesamt 1-mal bearbeitet
C++ Forumbot
Forumbot

Benutzerprofil
Anmeldungsdatum: 29.02.2004
Beiträge: 16155
Beitrag C++ Forumbot Forumbot 14:02:48 16.10.2009   Titel:              Zitieren

Dieser Thread wurde von Moderator/in Marc++us aus dem Forum Assembler in das Forum Projekt: OS-Development verschoben.

Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?


Dieses Posting wurde automatisch erzeugt.

_________________
Besuchen Sie unsere Bücherecke.
http://www.c-plusplus.de/bucher.php
Mit jeder Bestellung unterstützen Sie das Forum.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:01:50 17.10.2009   Titel:              Zitieren

Wir möchten PrettyOS mittelfristig mit einem USB-Treiber ausstatten, da USB das moderne Bus-System ist. Hier ein Hinweis (aus dem IRC) von XanClic, wie man hierbei vorgehen könnte:
Zitat:
So, wenn ihr also unbedingt USB haben wollt. Ihr schreibt zuerst mal einen PCI-Treiber, der die Geräte auflisten kann und die USB-Host-Controller rausfindet. Dann lest ihr euch bei Wikipedia und in der OS-Dev-Wiki über USB ein.
Dann könnt ihr euch die Spezifikationen (OHCI, UHCI von den Hardwareherstellern bzw. s. Links bei WP; USB 2.0 von usb.org, ebenso die Massenspeicherspezifikation (Bulk only)) runterladen und anschließend damit einen hübschen Treiber schreiben.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:50:22 17.10.2009   Titel:              Zitieren

Tobiking postete im bisherigen Google Groups Forum folgenden grundlegenden Beitrag, den ich für weitere Diskussionen nun hierher transferiere:

Zitat:
Ich habe noch ein paar Punkte die meiner Meinung nach geklärt werden
sollten bevor man groß anfängt Code zu schreiben. Das betrifft den
generellen Aufbau (Buildsystem etc.) und auch den Code selber, um
nicht später alles umschreiben zu müssen sobald sich etwas ändert. Im
IRC ist meist nicht die Zeit etwas größer zu Diskutieren, daher fang
ich das mal hier an.

Zum Buildsystem:
- Wie im IRC auch kurz erwähnt denke ich sollte man den ganzen Build
Prozess auf Makefiles umstellen. Ich sehe keinen Vorteil darin für den
Bootloader .bat dateien zu nehmen. Ob es elegant ist die Makefiles
aufzuteilen oder eine große zu haben kann man dann noch überlegen
- Das Erstellen des Kernels sollte auch leicht unter Linux machbar
sein. Mit einem zweiten Makefile oder mit einem include dürfte es
eigentlich einfach machbar sein das es auf den meisten Linux systemen
problemlos funktioniert.

Zum Code:
- Verschiedene Architekturen sind ja erstmal nicht angedacht, aber man
könnte trotzdem zumindest bei den Typen etwas Abstraktion einführen.
Dann wird statt unsigned int z.B. uint32_t oder u32 verwendet. Benutzt
man irgendwann einen anderen Compiler oder eine andere Architektur (64
Bit) kann man das mit einem typedef korrigieren. Bei den meisten
Strukturen kommt es ja genau auf die Größe an. Der gcc hat dafür sogar
einen Standard Header (stdint.h), den man ohne weiters nutzen kann. Da
gibt es auch noch ein paar andere Header die man nutzen kann und vor
allem Compiler spezifische Konstanten oder Macros enthalten.
- Struktur der Header. Zurzeit gibt es soweit ich gesehen habe einen
Header, der alles andere includiert. Das könnte irgendwann sehr
unübersichtlich werden. Ansonsten überlegen wie man die Header
ordentlich benennt. Mir ist da die Idee gekommen (und habs bei tyndur
ähnlich gesehen) das man sich an den C Standard orientiert.
Letztendlich schreibt man viele Funktionen die exakt so im C Standard
sind. Also kann man die Header auch angleichen.
- Naja Codestil allgemein ist nicht Lebensnotwendig aber schon eine
tolle Sache. Zeichensatz, Einrückung, ein paar Grundlegende Sachen
sollte man schon festlegen.

Mir fällt mit der Zeit bestimmt noch einiges ein. Das ist aber erstmal
alles was mir so gerade einfällt.

Zu guter letzt habe ich einfach mal mein Bastel OS hochgeladen in dem
ein paar der Punkte beachtet habe. Ich bin noch nicht so weit gekommen
und es hat an vielen Stellen noch Probleme, aber kann vielleicht die
ein oder andere Idee geben. Zu finden ist es unter:

http://a.team-exc.com/stuff/TobOS.zip

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:51:07 17.10.2009, insgesamt 1-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 01:57:37 19.10.2009   Titel:              Zitieren

Tutorial, Teil 3, Absatz über Abschnitt "FAT12 - Filesystem der Diskette":
Zitat:
VFS/Initrd wird in 0.1.0091 zum Laden der Shell umgangen, bis der Schwachpunkt (...) bitte ich um entsprechende Information.
Ist das hier geschilderte Problem noch aktuell?
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 02:07:55 19.10.2009   Titel:              Zitieren

Nein, dank ausführlicher Tests mit Cuervo und Unterstützung seitens PorkChicken im Low-Level-Forum wurde dieses Problem lokalisiert und gelöst.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:59:26 21.10.2009   Titel:              Zitieren

[i]Aktuelle Arbeiten:

...

Ich habe diese Übersicht nach "Übersicht über PrettyOS (...)" verschoben.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:33:21 01.11.2009, insgesamt 5-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:33:17 06.11.2009   Titel:              Zitieren

Dies ist ja der Hauptthread, der meinen Einstieg in das "OSDEV" begleitet. Daher möchte ich mich hier sehr herzlich bei allen bedanken, die die bisherigen Gehversuche in die Welt des Kernels, der Treiber und des User-Spaces engagiert und tatkräftig unterstützen, sei es durch kleine Hilfestellungen, Hinweise, Diskussionen, Tests, eigene Experimente, kleine Aufsätze sowie Sourcecode. Ein funktionierendes OS ist die Summe vieler kleiner Schritte und Erkenntnisse. Ich wünsche diesem Subforum und unserer kleinen Gruppe um PrettyOS weiterhin viel Spaß, interessante Diskussionen und gutes Gelingen bei allen Vorhaben. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:30:50 24.12.2009   Titel:              Zitieren

Den Helfern, Freunden und Gönnern dieser Gruppierung um das Thema OS-Development am Beispiel PrettyOS möchte ich aufs Herzlichste danken. Euch allen und euren Familien ein frohes und besinnliches Weihnachtsfest und einen erfolgreichen Start in das Jahr 2010!

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:39:40 20.04.2010   Titel:              Zitieren

Da es heute gelungen ist, das Zusammenspiel von PCI, EHCI und USB 2.0 fehlerfrei zu betreiben, ist es an der Zeit diesen Thread mal wieder "auszupacken". Für mich ist das der Beweis, dass man vieles (nicht alles) bewirken und erreichen kann, wenn man es wirklich will und dran bleibt. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:42:52 12.05.2010   Titel:              Zitieren

Nachtrag: der wirkliche Durchbruch bei USB2 MSD/SCSI fand in der zeit vom 11.05. zum 13.05. statt durch einen Versuch und Hinweis von +gjm+, der diesen Thread und das Projekt von Anfang an wohlwollend verfolgt hat. Ich kann nur hoffen, dass +gjm+ uns auch weiterhin treu verbunden bleibt. :live:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 09:58:01 30.05.2010, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:52:01 23.05.2010   Titel:              Zitieren

Weiterer Meilenstein:
Heute konnten Files von verschiedenen usb-Sticks (512 MB FAT16, 1 GB FAT16, 4 GB FAT32, 16 GB FAT32) per FAT16/32-Filesystem aufgespürt (root dir) und von usb MSD mittels SCSI command "read(10)" in den Speicher geladen (FAT, data area) werden. Damit hat die Floppy Disk (FAT12) als zentrales Speichermedium ausgedient.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:53:42 23.05.2010, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:08:09 30.05.2010   Titel:              Zitieren

Der "Meilenstein" konnte ausgebaut werden: rev. 476: http://www.c-plusplus.de/forum/viewtopic-var-t-is- ....... 0-and-sid-is-e7938c7851b1351fd67c91242b76cae3.html

ttt.elf (unser tic-tac-toe) vom usb-stick (mit FAT16 oder FAT32) wurde geladen und ausgeführt. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 12:31:50 04.06.2010   Titel:              Zitieren

Aber bis es auch mit Fileeinträgen jenseits des ersten Clusters in der root dir ging, dauerte es dann doch noch etwas. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:03:01 10.06.2010   Titel:              Zitieren

Meilenstein:
Heute haben MrX und ich es in einem tollen team work geschafft, mit
Code:
3:\ttt    elf
Code:
3:\ttt elf
Code:
3:\ttt    elf
von einem usb-stick ttt zu laden und zu starten. :live:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:22:21 12.06.2010   Titel:              Zitieren

Nun kann man von Floppy Disk Device und USB Mass Storage Device laden. Der Device Manager hat an Abstraktionsgrad und Mächtigkeit gewonnen.

"1:\ttt.elf" (bei vorhandener Floppy sogar mit "ttt.elf") :)

Der device manager ist nun in seinen Grundzügen realisiert und läuft gut.
Nun kann man von Floppy oder usb MSD mit 1:/ttt.elf (durchgezählte angeschlossene Partitionen) bzw. A:/pqeq.elf eine Datei laden und starten.
A: ist die sogenannte Port-Ansprechweise
Ports sind bei uns: FDD, RAM, usb-slots
Disks sind bei uns: FloppyDisk, RAMDisk, usb-stick
Partitionen sind z.B. FAT12/16/32-Partitionen darauf. Wir zählen die Ports mit A,B,C, ... und die Partitionen mit 1,2,3,...

Wir haben also drei Ebenen:
1) die "Slot"-Ebene, das ist die feste Hardware: RAM, FDD, EHCI-Port
2) das eingeschobene Wechselmedium: RAMDisk, FloppyDisk, usb-MassStorageDevice
3) die Partition, die wir mit Namen und Serial kennen: part->serial

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 18:59:20 12.06.2010, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 14:03:55 26.06.2010   Titel:              Zitieren

... und 14 Tage später trauen wir uns, auf usb Mass Storage Devices zu schreiben! Mit einem FAT12-Stick klappt es bereits analog zur Floppy. :)
FAT16 geht ebenfalls korrekt. Bezüglich FAT32 gibt es noch ein Problem bei vielen bereits vorhandenen Einträgen in der root dir (gelöschte zählen mit). Hier muss im FAT-Modul nachgebessert werden. Aber wie diesen Fehler finden? ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 10:23:46 27.06.2010, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 14:54:12 27.06.2010   Titel:              Zitieren

Durch Zufall ist mir der Fehler beim Code studieren aufgefallen. Es geht eben nichts über Code Review. Da hatte ich eine Zeile testweise ausgeblendet (zum Glück nicht gestrichen), die hatte nun gerade für einige Fälle gefehlt. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 18:00:31 27.06.2010   Titel:              Zitieren

Meilenstein: Version 0.0.1.0 (Rev. 554) :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:28:48 04.07.2010   Titel:              Zitieren

Ein OS (im erweiterten Sinne) besteht nicht nur aus Elementen wie Bootloader, Kernel und Treiber, sondern im Hobby-Bereich auch aus den User-Programmen, die speziell für die API maßgeschneidert wurden. Beispiele sind die Spiele TicTacToe von Mrx und ARROW ATTACK von mir. Der "homo ludens" sucht solche Anwendungen, um sich an den Möglichkeiten der IT zu erfreuen und seine Kreativität zu entfalten. Daher kann ich nur immer wieder ermuntern, unterhaltsame und neuartige Programme für PrettyOS zu schreiben. Die API der Userlib ist noch nicht stabil, aber Programmanpassungen werden sicher kein Problem darstellen, da die API bei ihrem Fortschritt eher verbesserte Möglichkeiten anbieten wird, die das Erstellen erleichtern. Also nix wie ran. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:30:44 04.07.2010, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:38:55 04.07.2010   Titel:              Zitieren

Ich denke es ist Zeit für einen OSDev Review bei PrettyOS.

Beginnen wir mit http://wiki.osdev.org/Beginner_Mistakes als Leitfaden:
Zitat:
Deadlines

Whether for university, hobby, or commercial uses, operating system development takes time. The Linux kernel took over one year of very dedicated work to get into a semblance of usefulness, and all Linus Torvalds did was mimic existing and well-documented behaviour to get an already-existing userspace to run on it. Moreover, for every project as successful as Linux, there are literally hundreds of projects that consumed a man-year or more of work without ever getting as far as hosting a functional shell.

Therefore, plan a reasonable road map of what you want to get done. Do not assume that in 3 months your OS will have a GUI and voice recognition, because operating system development does not contain any RAD tools in it at all. In fact, it is completely void of them. (void. It's a joke. Get it?)

Wir haben nun über ein Jahr Entwicklung von PrettyOS (sicher weniger als 1 Mannjahr in Summe, denn es ist ja ein Hobby-Projekt neben Arbeit, Studium, Schule). Die Shell funktioniert bestens bisher. Die Roadmap wurde eingehalten: Eigener Bootloader anstelle GRUB, Laden/Speichern USB-Stick mit FAT. Netzwerk musste da halt zurück stehen mangels Developer Ressourcen. Man kann nicht alles gleichzeitg machen. EHCI, USB2 und FAT sind schwere Brocken. Nun kommen die "Manager" und die Schnittstellen. Manche machen es umgekehrt, ich möchte zuerst die Funktionalität sehen, wissen, dass es wirklich "geht".

Zitat:

Community Projects

Don't overestimate your chances of getting people interested in your project. Even the more successful projects usually consist of one, perhaps two people actually working on the code. And that is not due to a lack of need.
Brooks' Law states that the more people on a project, the longer it takes. The only way around this is to split the project into parts that you get people working on and only on that part. Good luck.

Wir sind zwei aktive Entwickler, vielleicht werden es ab und zu drei sein, die daran werkeln. Die Aufteilung hat bisher gut geklappt aufgrund der unterschiedlichen Interessengebiete. Aber eine Community von 5-10 Leuten, die daran koordiniert arbeiten, ist Illusion. Das muss man rasch einsehen. Im chat gewinnt man neue Leute, und es erhält die Lebendigkeit, leider geht auch Zeit verloren mit für die praktische Arbeit sinnlosen Debatten. Destruktive Stänkerer muss man leider immer wieder in die Schranken weisen. Ertragen muss man auch die "Idler". PrettyOS hat hier momentan einen guten Mix von Leuten, und es gibt ja auch "virtuelle Hinterzimmer" in den chat-Bezirken, wenn wichtige Dinge im kleinen Kreis zu klären sind.

Zitat:
Commercial OSDEV

There really is no such topic. OSDEV will probably never land you a job. (As shown in the "Jobs" section of the forum.)
Also, don't get your mind set that by building such a great OS that you'll be rich. If anything, history has shown us that the best operating systems never receive any commercial success, while the ones that have a near total lack of design and inspiration do, because of clever business moves and being in the right place, in the right time, with the right cover-up.

Das ist ein interessanter Punkt. PrettyOS wurde nie als Karriere-Sprungbrett oder als kommerzielles Projekt geplant, sondern als didaktische Hilfe zum Einstieg in OSDev. Daher auch mein Tutorial von Anfang an, das eher ein Skript/Logbuch für mich selbst war. Ein begleitendes e-book schwebte mir vor. Allerdings braucht das länger als geplant, bis ein Niveau erreicht wird, dass man die Dinge vernünftig ordnen und weiter geben kann. Man muss hier mit sich selbst und anderen geduldig sein. Die Erfahrung, die man selbst macht beim Aufbau eines OS und einer damit zusammen hängenden Community ist umfassend und tiefgehend. Man muss dazu bereit sein. Ansonsten gibt man auf. OSDev ist streckenweise "langweilig" und gleichzeitig fordernd.

Zitat:

GUI Design

It will likely take you several years, starting from scratch, to get to the point where you actually do anything GUI-related. And, the looks of a GUI are secondary at best, as they can easily be changed retroactively; what really decides the usability of a GUI is the functionality, and that isn't expressed in mock-up graphics. If your aim is creating a better look instead of a better OS, consider implementing an X Window Manager instead of a whole OS.


GUI und Maus, übrigens auch Sound sind sicher ein interessantes Feld, aber dies hält durch hohe Komplexität eher von wesentlichen Dingen ab. Ist momentan nicht auf der konkreten Roadmap.

Zitat:

OS Emulation

My OS will be able to run programs from Windows, Mac OS, Linux, and even PDP-11 programs!!!
I'm sorry to burst your bubble, but it probably won't. Emulating even just a single system takes years of work, especially when it's proprietary, such as Windows or Mac OS (Linux is probably the easiest out of the four.). Wine despite 15 years of development and being written in userspace have still problems with many programs.
So instead of focusing on emulating other systems, focus on your own. Design it, develop it, and be friends with it.


Wir schreiben unsere eigenen Programme, vielleicht wird die eine oder andere Anwendung portiert werden, aber das ist zweitrangig.

Zitat:

Naming

Naming is usually the last problem to be solved, even while we all wish for a cool name to our cool concept. Since the "coolness" of a name is a matter of taste, we cannot help you finding it. Moreover, if you tie your project name to a certain feature, you might discover somewhere down the road that no concept is perfect and that you might want to change what you initially thought a key feature. Nothing would be more stupid not to evolve just because you 'want to stick to a name'...
A lot of good information on naming can be found in this thread. Simply put, naming your operating system <name>OS (JackOS, FredOS, etc) may seem like a good idea, until you get a second project member. A good idea (courtesy of Solar) is to choose a codename (like Longhorn, Chicago, etc) and then make up a better name closer to release time.

Die Bezeichnung "PrettyOS" habe ich bereits sehr früh festgelegt, bisher habe ich es nicht bereut. Eine Namensänderung kommt nicht in Frage. :)
Man kann hier aber nur zu Vorsicht raten. Da hilft nur Intuition.

Zitat:

Programming Languages

Some languages are well suited to write an OS kernel, others are less so. Read the page about using some language other than C.

Zwischen C und C++ wird man wohl immer schwanken. Beides ist möglich, wobei ich bisher nur Erfahrung mit OSDev und C habe. Ich würde es gerne probieren ein OS in C++ zu bauen, aber am Wesentlichen ändert es nichts. Man wird sich mit C++ eher isoliert vorkommen, da die Literatur C oder Assembler einsetzt.

Zitat:

Booting Problems

Especially in early stages and with a self-built boot loader, the reason is frequently that too few sectors are fetched from disk. Either adjust the amount of sectors you fetch from disk, or have the boot loader / second stage loader parse the file system.

Inzwischen verwenden wir ein FAT12-Filesystem in dem verwendeten zweistufigen BL, ein ganz angenehmes aber ziemlich unflexibles Verfahren, wenn man z.B. von ubs-stick booten und nachladen will. Niemand hat die Zeit sich intensiv mit dem BL zu befassen. GRUB muss dennoch etwas warten, wobei wir vorbereitet sein müssen. Der Kernel wächst und wächst.

Zitat:
Strings

When your Kernel is written in C, gcc puts strings and constants in a special section called "read-only data". This section needs to be in your linkscript, in the .text section, otherwise it can cause all sorts of weird problems (unable to print text to the screen, kernel suddenly becoming 1MB larger, GRUB giving a loading error saying "kernel too large", etc). The section is called ".rodata" in ELF and ".rdata" in COFF/PE (the output format for MinGW/Cygwin). Building a GCC Cross-Compiler will help you to safely assume ".rodata" everywhere.

You could also tweak your linker script to include either section:

...
.text 0x100000 {
*(.text)
*(.rodata*) /* <---- ELF Cross Compiler or ELF *NIX (eg. Linux) */
*(.rdata*) /* <---- COFF/PE MinGW or Cygwin on Windows */
}
...


Die beste Antwort hierauf dürfte unser Linker-Script für den Kernel sein:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
OUTPUT_FORMAT("binary")
OUTPUT_ARCH(i386)
STARTUP(object_files/kernel/kernel.o)
SECTIONS
{
    . = 0x00100000;
    __kernel_beg = .;
    .text   : { __code_start = .;                        }
    . = ALIGN(0x1000);
    .text1  : { object_files/kernel/data.o(.text)        }
    .data   : { __data_start = .;   *(.data)             }    
    .rodata : { __rodata_start = .; *(.rodata) *(.rdata) }
    .bss    : { __bss_start = .;    *(.bss) *(COMMON)    }
    __start_cdi_drivers = .;
    .cdi    : { __cdi_start = .;    *(.cdi)              }
    __stop_cdi_drivers = .;
    __kernel_end = .;
    __end = .;
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
OUTPUT_FORMAT("binary")
OUTPUT_ARCH(i386)
STARTUP(object_files/kernel/kernel.o)
SECTIONS
{
. = 0x00100000;
__kernel_beg = .;
.text : { __code_start = .; }
. = ALIGN(0x1000);
.text1 : { object_files/kernel/data.o(.text) }
.data : { __data_start = .; *(.data) }
.rodata : { __rodata_start = .; *(.rodata) *(.rdata) }
.bss : { __bss_start = .; *(.bss) *(COMMON) }
__start_cdi_drivers = .;
.cdi : { __cdi_start = .; *(.cdi) }
__stop_cdi_drivers = .;
__kernel_end = .;
__end = .;
}
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
OUTPUT_FORMAT("binary")
OUTPUT_ARCH(i386)
STARTUP(object_files/kernel/kernel.o)
SECTIONS
{
    . = 0x00100000;
    __kernel_beg = .;
    .text   : { __code_start = .;                        }
    . = ALIGN(0x1000);
    .text1  : { object_files/kernel/data.o(.text)        }
    .data   : { __data_start = .;   *(.data)             }    
    .rodata : { __rodata_start = .; *(.rodata) *(.rdata) }
    .bss    : { __bss_start = .;    *(.bss) *(COMMON)    }
    __start_cdi_drivers = .;
    .cdi    : { __cdi_start = .;    *(.cdi)              }
    __stop_cdi_drivers = .;
    __kernel_end = .;
    __end = .;
}


Fazit: Wir haben den Einstieg ganz brauchbar hingelegt. Nun geht es darum, die Sache rund zu gestalten und sich das Interesse zu erhalten. :live:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:50:17 04.07.2010, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:46:25 16.07.2010   Titel:              Zitieren

Wir hatten intern diskutiert, was wichtiger sei: Netzwerk oder Grafik (wenn auch nur für verbesserte und höheraufgelöste Textdarstellung). Die Antwort fiel eher zugunsten von Grafik aus. Daher haben wir VM86-Tasks eingeführt. Heute haben wir es zum ersten Mal geschafft, den Video-Mode mittels VM86-task stabil umzuschalten und ein paar bunte Tupfer darzustellen.

Der "Sündenfall" ist erfolgt. Das Text-"Paradies" ist beendet.
Nun wird die Pixel-"Hölle" folgen. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:27:17 18.07.2010   Titel:              Zitieren

VM86 Tasks laufen stabil. Damit ist das BIOS innerhalb des Protected Mode wieder zugänglich geworden. Wir verwenden die Interrupt Vector Table (IVT) zum Beispiel zur Ausführung von INT 10h. Das BIOS verzweigt in Speicherregionen oberhalb C0000h.

VM86 erlaubt uns das Umschalten des Video-Modes mittels 16 bit Real Mode Code mitten im Protected Mode.

Nun steigen wir mittels vbe.h/c in den Bereich der Grafik ein und werden Texte langfristig mit in Pixelmustern definierten Zeichen darstellen.

Als erstes Projekt steht der Bootscreen als 256-Farben-Bmp-File an. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 19:54:40 18.07.2010, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 10:55:22 24.07.2010   Titel:              Zitieren

Ein Meilenstein ist sicher die Darstellung eines bmp:
http://www.henkessoft.de/OS_Dev/Bilder/0_0_1_90_bitmap.PNG

Positionierung und Palette sind zwar noch nicht korrekt, aber das Einlesen des bmp-headers und der bmp-Daten von hinten beginnend und das Auffüllen der Zeilen von rechts nach links gelingt schon.

Da liegt aber noch einiges an Arbeit zur Stabilisierung und bezüglich Fehlerabfragen vor dem Team.

EDIT: Mit Revision 0.0.1.112 hats geklappt mit der Geometrie und den Farben der Palette. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 21:26:17 26.07.2010, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:17:58 07.08.2010   Titel:              Zitieren

... und ein weiterer das Senden eines Netzwerk-Paketes: :)
http://www.c-plusplus.de/forum/viewtopic-var-t-is-254893-and-start-is-763.html

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:56:38 08.08.2010, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:34:23 10.08.2010   Titel:              Zitieren

Nun wurde ein weiterer Meilenstein erreicht:
http://www.c-plusplus.de/forum/viewtopic-var-p-is-1938461.html#1938461

Das "Ping" (Ping Request) hat sein "Pong" (Ping Reply) gesehen! :live:
Auf zwei Systemen - einmal qemu via TAP (Linux), einmal PC über Router (WinXP) - unabhängig bestätigt.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 17:48:10 11.08.2010   Titel:              Zitieren

... und nun wurde sogar das timeout - zumindest bei "hrping" - überwunden :)
http://www.c-plusplus.de/forum/viewtopic-var-t-is-254893-and-start-is-796.html

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Unregistrierter





Beitrag Unregistrierter 18:38:05 11.08.2010   Titel:              Zitieren

Sehr interessantes Thema, auch wenn mir die Zeit dafür fehlt. Ich habe schon genug zu tun für ein bestehendes System zu programmieren. Obwohl ich das auch aufgegeben habe und nur noch Qt mit OpenGL setzen werde, damit das System darunter so ziemlich egal ist.

Aber ich schweife ab, ich frage mich ob der Thread hier ein Monolog ist? Und wenn ja warum du da nicht ne eigene Seite daraus machst als sowas in ein fremdes Forum zu posten?


Gruß vom Funcoder
Mr X
Mitglied

Benutzerprofil
Anmeldungsdatum: 18.09.2007
Beiträge: 1073
Beitrag Mr X Mitglied 19:11:22 11.08.2010   Titel:              Zitieren

Volltreffer... äh, Vollpfosten, mein ich.

Wie wärs, bevor man sich über andere Leute beschwert, sich dieses Subforum genauer anzusehen?
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:07:00 11.08.2010   Titel:              Zitieren

@funcoder (nun offenbar unregistriert): ich verstehe, dass Du auch gerne osdev machen würdest, aber da muss man schon in der Lage sein, etwas mehr Tiefgang zu zeigen und sich intensiv in ein Thema hinein graben. Wenn Du keine Zeit hast, wirst Du halt User bleiben, selbst, wenn Du "programmierst". :D

Übrigens: http://www.henkessoft.de/OS_Dev/OS_Dev1.htm

Im übrigen bin ich von Anfang an dabei in diesem Forum, also ist mir das nicht "fremd". :D

Mit deinen <100 Beiträgen solltest du diesen Thread vielleicht mal von Anfang an lesen, um wirklich zu verstehen, was mich hier "treibt". Deine Anwürfe erscheinen mir, wie wenn der Hund den Mond anbellt. ;)

@all: Dieser Thread ist das Rückgrat meines Einstiegs in OSDev. Daher wird er als Logbuch weiter geführt, solange dieses "Projekt" läuft.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 22:30:49 12.12.2010, insgesamt 5-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:07:01 30.08.2010   Titel:              Zitieren

PrettyOS ist momentan relativ stabil. Das ist bei einem OS, bei dem nach dem Zwei-Augen-Prinzip committet werden darf, keine Selbstverständlichkeit. ;)

Habe mal wieder eine kleine kostenlose Anzeigenkampagne geschaltet, damit man weiß, dass auch in Germany an OS gewerkelt wird:
http://forum.osdev.org/viewtopic.php?f=1&t=12087&p=180921#p180921

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 21:57:23 30.08.2010   Titel:              Zitieren

Zitat:
mouse.c/.h
- Cursor Bitmap hinzugefügt...

Nach vm86 mit vbe der nächste Schritt in Richtung GUI. Die Anziehungskraft des klicki-bunti ist nicht zu brechen. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:19:24 31.08.2010   Titel:              Zitieren

... nun auch 24/32 bit Farben. ^^

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:32:18 17.09.2010   Titel:              Zitieren

MrX hat - basierend auf Cuervo's Treiber für COMx - die Funktion serial_log eingebaut, dessen Ausgaben über COMx man z.B. bei VBox oder qemu in eine Textdatei umleiten kann. Ich habe dies sofort im vm86-monitor anstelle printf getestet, und es lief prächtig, langsam in VBox und schnell in qemu. :)
http://henkessoft.de/OS_Dev/Bilder/serielle1.txt

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:45:25 18.09.2010, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:17:44 26.10.2010   Titel:              Zitieren

Nun besitzt der Kernel auch die Fähigkeit, sich als Multi-Boot-fähiges OS laden zu lassen, eines der Ziele von Anfang an. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:56:56 25.11.2010   Titel:              Zitieren

APM sorgt für einen shutdown durch Kommandoeingabe. Funktioniert noch nicht rund, aber ein anfang ist gemacht.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:32:34 12.12.2010   Titel:              Zitieren

Am 30.08.2010 schrieb ich:
Zitat:
Nach vm86 mit vbe der nächste Schritt in Richtung GUI. Die Anziehungskraft des klicki-bunti ist nicht zu brechen.


Ja, nun ist es soweit. PrettyOS hat einen GUI-Ansatz! Mal gespannt, wie weit hier die Neugier und die Kräfte tragen. ;)
Ein interessantes Vorbild aus User-Sicht ist immer noch die klassische WinAPI:
http://www.henkessoft.de/C++/WinAPI/WinAPI%20Kapitel%201%20bis%206/api1.htm
http://www.henkessoft.de/C++/WinAPI/WinAPI_GDI/WinAPI_7_GDI.htm

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:32:35 13.12.2010, insgesamt 1-mal bearbeitet
abc.w
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2008
Beiträge: 1364
Beitrag abc.w Mitglied 22:59:53 13.12.2010   Titel:              Zitieren

Was ist mit dem Vorbild des Framebuffers aus der Linux Welt :)

_________________
E = int * char^2
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 13:48:24 24.12.2010   Titel:              Zitieren

Allen Entwicklern, Nutzern, Beobachtern, Freunden und Gönnern von PrettyOS wünschen wir frohe Festtage und einen Guten Rutsch nach 2011. :live:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 16:08:10 03.01.2011   Titel:              Zitieren

... und ein frohes, erfolgreiches Neues Jahr 2011! Viel Kraft, Gesundheit und gute Ideen. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
USR32
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.12.2010
Beiträge: 44
Beitrag USR32 Mitglied 16:26:04 03.01.2011   Titel:              Zitieren

Erhard Henkes schrieb:

Ja, nun ist es soweit. PrettyOS hat einen GUI-Ansatz!


Mach mal einen Screenshot, Bitte. :D
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 16:29:13 03.01.2011   Titel:              Zitieren

@MrX: kannst Du dies bitte uebernehmen? (habe momentan keinen Rechner hier, nur mail-Zugang)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
DarkShadow44
Mitglied

Benutzerprofil
Anmeldungsdatum: 12.06.2009
Beiträge: 332
Beitrag DarkShadow44 Mitglied 01:07:01 10.01.2011   Titel:              Zitieren

Hi,
Könnt ihr mir sagen mit welcher Toolchain ich das kompilieren muss ?
Ich habe das Tutorial von "http://www.henkessoft.de/OS_Dev/OS_Dev1.htm" ausprobiert, letztens mit Cygwin. Aber ich bekomme beim linken immer den Fehler "File format not recognized"
Und wenn ich statt 'aout' z.b. 'elf' nehme, heißt es "cannot perform PE operations on not PE files" und wenn ich 'bin' nehme kann ich keine externen Referenzen einsetzen :(

Hoffe ihr könnt mir helfen,
Lg Dark
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 02:16:00 10.01.2011   Titel:              Zitieren

Probiere bitte mal das angegebene DJGPP aus:
http://www.osdever.net/downloads/compilers/DJGPP-Installer-nocpp.exe

Bei späteren Versionen des Linkers ld gibt es Probleme mit Mischungen aus 16/32-Bit-Code.

http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId29572

Zitat:
Hinweis:
Ich empfehle diese DJGPP-Toolchain (gcc 3.1, ld 2.13, ...), da bei Einsatz der MinGW (GCC) Compiler Suite über Linker-Probleme mit dem in diesem Tutorial erfolgreich verwendeten NASM Output-Format a.out (assembler output)-Objektdatei-Format (inzwischen durch COFF und ELF abgelöst) berichtet wurde.

Inzwischen wurde im zweiten Ansatz (siehe Teil 2 dieses Tutorials) ein Work-around gefunden:

http://www.henkessoft.de/OS_Dev/OS_Dev2.htm#mozTocId42018
http://www.c-plusplus.de/forum/viewtopic-var-p-is-1736328.html#1736328

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 02:21:35 10.01.2011, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 12:36:32 05.02.2011   Titel:              Zitieren

Momentan haben wir eine "Durchhängephase". Niemand hat Zeit, Energie usw. genug, um ein so komplexes Projekt auf freiwilliger Basis weiter zu treiben. Auch solche Zeiten gehören dazu. :rolleyes:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:36:09 20.02.2011   Titel:              Zitieren

Glücklicherweise zieht es langsam wieder an. Großes Lob an die Developer, die PrettyOS in voller Blüte erhalten und sogar weiter verfeinern. Namentlich erwähnen möchte ich MrX, der nun ca. 1 Jahr bei diesem Thema dabei ist.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Eisflamme
Mitglied

Benutzerprofil
Anmeldungsdatum: 26.06.2009
Beiträge: 1889
Beitrag Eisflamme Mitglied 15:26:12 02.03.2011   Titel:              Zitieren

Wow. Ich habe die ersten Seiten überflogen und dachte nur "Was für ein endlos erscheinender Aufwand". Dennoch bleibt ihr anscheinend bei der Sache (wayne Flauten) und zeigt richtig Durchhaltevermögen!

Ich habe mich bisher nicht intensiv mit solchen Themen beschäftigt, aber es kann gut sein, dass ich das Tutorial Mal reinschauen werde. Und auch sonst großes Lob an euch ;)
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:20:27 02.03.2011   Titel:              Zitieren

Zitat:
großes Lob an euch
Danke für das positive Feedback! Komm einfach dazu. OSDev hat den gigantischen Charme des völlig Ausgefallenen. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
fr33g
Mitglied

Benutzerprofil
Anmeldungsdatum: 07.01.2010
Beiträge: 803
Beitrag fr33g Mitglied 22:58:36 13.04.2011   Titel:              Zitieren

Ich hab mir den Thread nicht komplett durchgelesen, aber dein Tutorial find ich bisher echt richtig gut. Ich habe mich schonmal kurz mit Assembler beschäftigt, dann aber mangels an Verständnis wieder abgebrochen. Bin dann letztens doch wieder auf die Idee gekommen mal ein eigenes kleines OS zu schreiben, da mir kein Projekt( normales Programm ) mit C/C++ eingefallen ist was mich motiviert hat. Ich wollt nicht was machen wo ich recht schnell fertig bin, sondern was wo länger geht und wo ich auch immer weiter ausbauen kann, was aber gleichzeitig auch weiterhin motiviert und mir viel bringt( in Bezug auf lernen ). Dadurch kam ich dann wieder auf die Idee mich mit Assembler und anschließend mit der OS-Entwicklung zu beschäftigen, dabei bin ich dann über dein Tutorial gestoßen und arbeite es gerade durch und es ist echt top. Werds jetzt erst mal durcharbeiten und dann selbst weiter am Ball bleiben;-)

Lg freeG und danke für das super Tutorial;-)

_________________
Das kann ich: C/C++, Asm, HTML, CSS, Javascript;
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 23:42:06 30.04.2011   Titel:              Zitieren

Hi fr33g (netter Name),
stosse doch einfach zu unserer Truppe dazu.

Im Mai starten wir mal wieder richtig durch. :)
Ich melde mich im ICQ demnaechst.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:46:29 30.04.2011, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 14:31:17 15.05.2011   Titel:              Zitieren

Wir suchen weitere Entwickler zur Verstärkung: http://www.c-plusplus.de/forum/286721

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
fishat64
Mitglied

Benutzerprofil
Anmeldungsdatum: 22.05.2011
Beiträge: 2
Beitrag fishat64 Mitglied 16:14:07 22.05.2011   Titel:              Zitieren

Hallo ihr fleißigen Entwickler!

Hab per google das Tutorial gefunden... Ersmal riesen Lob: So ein schweres Thema so einfach erklärt!
Naja auf jeden Fall haben die ersten Teile noch gut funktioniert... Dann wurde der C-Kernel eingeführt und da fingen meine Probleme an...
Auf jedenfall kommt was ich auch mache bei dem Linker die Fehlermeldung:
"kernel.o: file not recognized: File format not recognized"
Hier genaueres:
Zitat:
GNU ld (GNU Binutils) 2.21
Supported emulations:
i386pe
using external linker script:
==================================================
OUTPUT_FORMAT("binary")
ENTRY(RealMode)
SECTIONS
{
.text 0x8000 : {
*(.text)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
}

==================================================
attempt to open kernel.o succeeded
opened script file kernel.o
kernel.o: file not recognized: File format not recognized

Bezieh mich hierbei auf Kapitel 1 des Tutorials.
Ich meine abc.w hatte auf Seite 13 vom selben Problem berichtet. leider hat seine Lösung bei mir irgendwie nicht funktioniert.
Könnte irgendeiner mir erklären wie ich das Problem wegkriege?? Bin wahrscheinlich einfach zu doof dafür...... :confused:

MfG fishat64

p.s. Ich bitte meine Rechtschreibung zu entschuldigen! :)
Mr X
Mitglied

Benutzerprofil
Anmeldungsdatum: 18.09.2007
Beiträge: 1073
Beitrag Mr X Mitglied 17:08:27 22.05.2011   Titel:              Zitieren

Entwickelst Du unter Windows oder Linux?

Wenn unter Windows:
Du musst einen ld für ELF-Dateien verwenden (gibts hier: http://www.lowlevel.eu/wiki/Crosscompiler_f%C3%BCr_Windows). Das "Supported emulations: i386pe" sieht für mich danach aus, dass du einen LD für Windows-Binaries verwendest.
fishat64
Mitglied

Benutzerprofil
Anmeldungsdatum: 22.05.2011
Beiträge: 2
Beitrag fishat64 Mitglied 17:38:45 22.05.2011   Titel:   Super!!! Funktioniert            Zitieren

Super!!! ;) Funktioniert!
Vielen vielen Dank!!
MfG fishat64
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:49:36 25.05.2011   Titel:              Zitieren

Zitat:
So ein schweres Thema so einfach erklärt!

Freut mich, dass Du das so siehst, denn dies war genau mein Ziel. :)
Allerdings wird das Thema OSDev rasch komplex, auch bedingt durch die manuelle Nutzung aller Tools. Man lernt dabei aber eine Menge, vor allem Beharrlichkeit und Tiefgang.

So einfach also manche Wegstrecke ist, OSDev bietet immer wieder harte Hürden, aber genau dafür habe ich "PrettyOS" als konkretes Beispiel für ein Hobby-OS-Projekt, zuerst alleine später mit anderen zusammen, entwickelt. Im Team kommt man eher vom toten Punkt weg hin zu einer Lösung. Es gibt aber auch Gebiete, da bleibt man ziemlich einsam, so hart das auch sein mag. Das sind dann wirkliche Herausforderungen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:19:34 06.06.2011, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 14:42:54 28.05.2011   Titel:              Zitieren

Das Thema "Netzwerk" ist wieder voll in die Gänge gekommen. Ein neuer "developer", der professionelles know-how mitbringt, hat unser Team verstärkt. PrettyOS hat die Durststrecke hinter sich gelassen. Solche Phasen gibt es bei vielen Projekten, wahrlich kein Grund aufzugeben, sondern erst recht beharrlich zu bleiben. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 14:43:58 28.05.2011, insgesamt 1-mal bearbeitet
florida
Mitglied

Benutzerprofil
Anmeldungsdatum: 01.11.2010
Beiträge: 21
Beitrag florida Mitglied 06:20:01 31.05.2011   Titel:   Eigenes OS?            Zitieren

Wenn ich mich jetzt bei der OS-Entwicklung auch anmelden würde, würdet ihr mich dann erstmal über die OS-Entwicklung belehren? Assembler habe ich gestern angefangen.
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 07:21:05 02.06.2011   Titel:              Zitieren

Hast Du bereits einige Tutorials durchgearbeitet?

http://www.henkessoft.de/OS_Dev/OS_Dev1.htm
http://www.lowlevel.eu/wiki/OS-Dev_f%C3%BCr_Einsteiger
http://www.jamesmolloy.co.uk/tutorial_html/index.html (James Molloy auf Basis eines älteren Tutorials)
http://www.brokenthorn.com/Resources/OSDevIndex.html (BrokenThorn Entertainment, Co. )

Am besten kommst du in den Chat: IRC-Server: irc.euirc.net Channel: #PrettyOS
(hierzu ist "Nettalk" als client empfehlenswert)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 07:23:08 02.06.2011, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 02:59:39 12.06.2011   Titel:              Zitieren

PrettyOS steht wieder in voller Blüte. An allen Ecken wird gewerkelt. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:56:00 14.06.2011   Titel:              Zitieren

Nach erfolgreichem DHCP Discover - Offer - Request - ACK können wir erneut einen Meilenstein im Netzwerkbereich bei TCP/IPv4 vermelden:

http://www.c-plusplus.de/forum/p2078200#2078200 TCP 3-way-handshake SYN - SYN/ACK - ACK
http://compsec.org/security/images/pentesting/3way.jpg
http://ironbark.bendigo.latrobe.edu.au/subjects/DC/lectures/17/tcp-handshake.png

Das sind die freudigen Momente bei OSDev.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:19:31 19.06.2011   Titel:              Zitieren

Nach dem "passive open" ist nun auch das "active open" gelungen. Dabei senden wir das SYN und das ACK. :)

Der Datentausch gelingt bereits gut, z.B. sowohl als telnet Client als auch als Server. Server kann PrettyOS sein mit telnet als Client, oder auch umgekehrt mit PrettyOS als Client und dem telnet dienst (in Win XP) als Server bzw. einem selbst geschriebenen Server (z.B. dem von MrX). :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:20:23 19.06.2011, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 13:37:13 19.06.2011   Titel:              Zitieren

PrettyOS goes to Internet. Wir haben es geschafft!
http://www.c-plusplus.de/forum/p2080542#2080542

Das ist ein besonderer Moment, wenn das selbst geschaffene TCP-Modul es schafft, dem Router die Verbindung zum Internet zu entlocken. :live:

Hier geht ein besonderer Dank an unseren Chef-Tester Cuervo, der uns den Link zu diesem herrlichen "Starwars"-Telnet-Server gab. :live: :live: :live:

EDIT: Nun geht auch das "Ziehen" einer HTML-Seite: http://www.c-plusplus.de/forum/p2080629#2080629
C/C++ Code:
tcp_send(connection, "GET / HTTP/1.0\r\nHost: www.henkessoft.de\r\n\r\n", strlen("GET / HTTP/1.0\r\nHost: www.henkessoft.de\r\n\r\n"), ACK_FLAG, connection->tcb.SND_NXT, connection->tcb.SND_UNA);
C/C++ Code:
tcp_send(connection, "GET / HTTP/1.0\r\nHost: www.henkessoft.de\r\n\r\n", strlen("GET / HTTP/1.0\r\nHost: www.henkessoft.de\r\n\r\n"), ACK_FLAG, connection->tcb.SND_NXT, connection->tcb.SND_UNA);
C/C++ Code:
tcp_send(connection, "GET / HTTP/1.0\r\nHost: www.henkessoft.de\r\n\r\n", strlen("GET / HTTP/1.0\r\nHost: www.henkessoft.de\r\n\r\n"), ACK_FLAG, connection->tcb.SND_NXT, connection->tcb.SND_UNA);

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 17:04:08 19.06.2011, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:28:30 26.06.2011   Titel:              Zitieren

Heute ist gelungen, eine kleine Netzwerk-API zum Laufen zu bekommen.
Das erste User-Programm zieht die Daten von dem bekannten telnet-Server:
http://www.c-plusplus.de/forum/p2084431?sid=e87c6e3575b25c6a7266509a9b3b2cf8#2084431

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 20:29:06 26.06.2011, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 17:33:48 03.07.2011   Titel:              Zitieren

Heute ist gelungen, dass sich ein User-Programm aus PrettyOS heraus in den IRC "einwählte" und sich in die Kanäle #PrettyOS und #Lost einloggte. :live:

Wieder ein kleiner Meilenstein. Gerade die Nutzung des Internets macht wirklich Laune, und man lernt die einzelnen Anwendungen und Abläufe hierbei detailliert kennen. Wer Netzwerk bei OSDev macht, der kennt sich wirklich aus. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
neuer_user
Mitglied

Benutzerprofil
Anmeldungsdatum: 28.12.2010
Beiträge: 210
Beitrag neuer_user Mitglied 21:10:13 05.07.2011   Titel:              Zitieren

ich wollt das ganze mit Netzwerk ja mal testen :live: :live: ,
nur hier auf dem PC läuft das fertige Image mit Bochs und Qemu nicht mehr richtig, und neu builden lässt sich das ganze auch nicht :(
der andere computer (laptop) lief gerade bei Bochs 'so nen bischen' heiß,
dann bin ich da auch nicht zu gekommen. :rolleyes: :D
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 01:07:53 08.07.2011   Titel:              Zitieren

@neuer_user: jeder Anfang ist nicht hürdenfrei, dafür aber immer spannend. Also am Ball bleiben. Wir helfen gerne.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 09:10:17 15.07.2011   Titel:              Zitieren

Wie wichtig und nützlich jedes einzelne Modul sein kann, erkennt man z.B. bei der Protokollierung ausgewählter TCP-Paketdaten über die serielle Schnittstelle in ein File mittels serial_log. Thx to Cuervo für den Einbau dieses Serial-Moduls. :live: MrX hat es heute printf-analog adaptiert. Damit kann man hervorragend arbeiten und das OS im Hintergrund debuggen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 01:04:05 16.07.2011, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:24:52 22.07.2011   Titel:              Zitieren

Heute hat MrX seine Überarbeitung der VBE-Shell (Original stammt offenbar von internet) präsentiert. Ein weiterer Meilenstein in der Geschichte von PrettyOS.

Sein Kommentar im chat:
Zitat:
<ehenkes>MrX: tell us a little bit about about your vbe ideas
<MrX>I would like to create an interface that covers all graphical output inclusive text output.
<ehenkes>w/o windows?
<MrX>The aim is, to be able to use any graphics device to use PrettyOS.
<MrX>At the moment, windows are not supported, but support can be added.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 14:14:45 24.07.2011, insgesamt 2-mal bearbeitet
weiopfqweiop
Mitglied

Benutzerprofil
Anmeldungsdatum: 22.07.2011
Beiträge: 4
Beitrag weiopfqweiop Mitglied 14:51:00 22.07.2011   Titel:              Zitieren

gibts auch screenshots?
Mr X
Mitglied

Benutzerprofil
Anmeldungsdatum: 18.09.2007
Beiträge: 1073
Beitrag Mr X Mitglied 19:30:03 26.07.2011   Titel:              Zitieren

Ich hab mal ein PrettyOS-Poster zusammengebastelt: 5 Screenshots, 3 im Textmodus, 2 in einem 24-bit 800x600 VBE-Modus.

http://kloke-witten.dyndns.org/~philipp/Bilder/PrettyOS-Screenshots.png
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:46:46 08.08.2011   Titel:              Zitieren

In version = "0.0.2.292 - Rev: 1144" wurde der bereits legendäre Zug beim Personenwaggon etwas aufgemotzt und ihm ein Schiff zur Seite gestellt. Spaß muss sein. Die Scrolling-Ticker-Line war eigentlich für wechselnde Informationen gedacht. Inzwischen ist dies auch in einigen Fällen geschehen, Z.B. stets aktuelle Floppy- oder malloc/free-Infos. Dieses Feature kann man sicher noch ausbauen. Cuervo hat uns Text-Message-Boxes geliefert. Dort wird z.B. abgefragt, ob man PrettyOS als User oder Developer verwenden will. Dem User könnte man kurzweilige bewegte Motive zeigen, dem Developer zusätzlich Informationen, z.B. über das Innenleben von PrettyOS.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 02:05:38 21.08.2011   Titel:              Zitieren

Das "Umschalten" von 0.0.2.x auf 0.0.3.x kann man als Meilenstein bezeichnen, da die Zeitspanne zwischen zwei derartigen Sub-Versionen inzwischen sehr lange ist. Der nächste Schritt ist Umsetzung und Ausbau des IPC-Konzeptes.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 10:26:48 27.08.2011   Titel:              Zitieren

Es wurde beschlossen, dem EHCI-Treiber (für USB 2.x) nun auch einen UHCI-Treiber (für USB 1.x) beizustellen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:17:23 02.09.2011   Titel:              Zitieren

Kleiner Meilenstein: Ein angesteckter usb-Stick wird am UHCI Port erkannt:
http://www.henkessoft.de/OS_Dev/Bilder/rev.1236_uhci.PNG :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:56:46 04.09.2011   Titel:              Zitieren

Nun geht es mit OHCI weiter. OHCI arbeitet wie EHCI im MMIO Space.
PrettyOS wird die gesamte Bandbreite der USB Host Controller beherrschen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 09:32:01 07.09.2011   Titel:              Zitieren

Ein angesteckter usb-Stick wird am OHCI Port erkannt. :)
Als Emulation eignet sich VBox und qemu.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:48:15 19.09.2011   Titel:              Zitieren

Inzwischen ist usb durch allgemeine Transfers und Transaktionen soweit abstrahiert, dass man beginnen konnte, die HCs (bei PrettyOS: e/o/uhci) alle einzubinden. Heute wurde erstmals mit ohci begonnen, allerdings fehlt noch das saubere Management der nun variablen Ports pro HC. ;)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:48:44 19.09.2011, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 20:38:41 04.10.2011   Titel:              Zitieren

Meilenstein: Die USB 1.1 control-Transfers (mit ohci) laufen auf VBox! Hat länger gedauert, als ich geplant hatte, aber ich war bei ohci selbst leider alleine. Das abstrakte usb-transfer/transaction System ist gut einsetzbar. :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:35:55 11.10.2011   Titel:              Zitieren

Nun wird UHCI ausgebaut und angedockt. Keine große Herausforderung nach EHCI und OHCI. ;)

UHCI verwendet kein MMIO, sondern wird über IO-Ports angesteuert.

Allerdings mag UHCI 512-Byte-Pakete nicht. :D

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 14:50:57 16.10.2011, insgesamt 2-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:53:16 29.10.2011   Titel:              Zitieren

Das Thema mit der Paketgröße ist inzwischen durch Aufteilung in mehrere Transaktionen und ein neues toggle-Steuerungssystem gelöst. Es gibt bei uhci allerdings noch Sticks, die bei den Transfers aussteigen, und bei ohci-Hardware Blockaden durch interrupts bzw. Enable-Probleme.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 11:56:46 29.10.2011   Titel:              Zitieren

Man merkt nun, dass dieses PrettyOS-Projekt in eine neue Phase gelangt. Die Community ist leider wenig lebendig (siehe chat), und die Aufgaben kommen nicht mehr durch echte Notwendigkeiten, das OS funktionsfähig zu gestalten, auf die Developer zu. Verwendbar ist PrettyOS aber auch noch nicht. Dazu fehlt noch zu viel auf der user-Seite, abgesehen von einigen Hardware-Problemen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
webplace
Mitglied

Benutzerprofil
Anmeldungsdatum: 03.05.2011
Beiträge: 1
Beitrag webplace Mitglied 23:52:30 31.10.2011   Titel:              Zitieren

Hallo,
ich verfolge mit Interesse dieses Projekt, hab aber imme wieder vergessen, mich einzulesen und mich zu beteiligen. So ein tolles Projekt will ich eigentlich nicht sterben sehen. Ich würde ein bisschen Werbung machen und versuchen, mich selbst einzubringen. Ich finde euer Projekt unglaublich spannend! Bitte macht weiter! :live:
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 00:39:47 01.11.2011   Titel:              Zitieren

Zitat:
Ich finde euer Projekt unglaublich spannend! Bitte macht weiter!

Danke für das positive Feedback! MrX und ich, und sicher auch noch andere ab und an, werden bei PrettyOS weiter machen, soweit die Zeit es uns erlaubt. Allerdings wäre es wirklich hilfreich, wenn noch ein bis zwei aktive Developer/Tester dazu stoßen würden, wenn auch nur temporär, denn bei der Problemlösung hilft ein größeres Team zumeist (mehr Ideen, breitere Testbasis, höhere Motivation). :)

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 00:40:59 01.11.2011, insgesamt 1-mal bearbeitet
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 19:08:24 01.11.2011   Titel:              Zitieren

Heute kam auch das bereits seit langem eingebaute CDI am Beispiel des e1000 Treibers (Intel PRO/1000) zum Laufen. Der e1000 Treiber wurde von tyndur übernommen.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
Jonas OSDever
Mitglied

Benutzerprofil
Anmeldungsdatum: 26.08.2010
Beiträge: 391
Beitrag Jonas OSDever Mitglied 19:57:09 01.11.2011   Titel:              Zitieren

Erhard Henkes schrieb:
Allerdings wäre es wirklich hilfreich, wenn noch ein bis zwei aktive Developer/Tester dazu stoßen würden, wenn auch nur temporär, denn bei der Problemlösung hilft ein größeres Team zumeist (mehr Ideen, breitere Testbasis, höhere Motivation).

Ich könnt (soweit ich gerade nicht allzuviel mit der Schule bschäftigt bin) auch mal ein wenig mitcoden.
Als Tester bin ich eher wenig geeignet, denn ich hab quälend langsames EDGET-Internet, also sind große Downloads (z.B. Emulatoren) nur sehr schlecht möglich. Ich hätt aber 2 alte Test-PCs da (ich müsste mir nur endlich mal ein USB-Floppy-Drive für meinen Laptop zulegen, um das Ganze dann auch auf Floppys für die PCs zu bekommen). Als Emulator um mein eigenes Zeug zu testen hätt ich VBox im angebot.

Ich werd mir mal am Wochenende den Sourcecode anschauen (in der Woche wie gesagt Schule und deswegen zu wenig Zeit). Mal sehn ob ich auch ein paar Beiträge zu PrettyOS beisteuern kann. :)

_________________
Befehl: SOFORT bei Mafia anmelden. Wer das liest und es nicht macht, wird wegen Befehlsverweigerung angezeigt!!!
neuer_user
Mitglied

Benutzerprofil
Anmeldungsdatum: 28.12.2010
Beiträge: 210
Beitrag neuer_user Mitglied 22:01:14 01.11.2011   Titel:              Zitieren

Zitat:
Heute kam auch das bereits seit langem eingebaute CDI am Beispiel des e1000 Treibers (Intel PRO/1000) zum Laufen

wäre dann internet in vBox möglich (oder geht es doch schon)?
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:07:57 01.11.2011   Titel:              Zitieren

Zitat:
wäre dann internet in vBox möglich (oder geht es doch schon)?

Prinzipiell könnte es gehen. Ich habe Internet bisher nur mit qemu (rtl8139, pcnet, e1000) auf Win XP als Host geschafft. VBox hat eine PRO/1000, die unter "Host only" bis DHCP ACK läuft. Die Karte sendet und empfängt also korrekt. Vielleicht könnte da jemand heraus finden, wie man da weiter kommt. Aber wie gesagt, einfach qemu einsetzen (zur Zeit am besten noch 0.14.1).

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
neuer_user
Mitglied

Benutzerprofil
Anmeldungsdatum: 28.12.2010
Beiträge: 210
Beitrag neuer_user Mitglied 22:40:03 01.11.2011   Titel:              Zitieren

wenn morgen meine grafikkarte zurückkommt kann ich auch wieder was machen...
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 22:50:59 01.11.2011   Titel:              Zitieren

Ich sehe folgende Cluster, in denen man sich betätigen kann:

- BL auf FAT32 erweitern, damit man direkt vom Stick laden kann (muss z.Z. noch FAT12 sein).
- Kernel weiter entwickeln
- CDI-Treiber einbinden http://www.lowlevel.eu/wiki/Common_Driver_Interface#Betriebssysteme.2C_welche_u.a._CDI_benutzen und http://git.tyndur.org/?p=cdi.git;a=tree
- Schnittstellen/Bibliotheken zu User-Programmen ausbauen
- User-Programme schreiben

Durch die ausgebauten USB-Treiber kann man PrettyOS vielleicht auch bereits ohne Floppy-Disk verwenden. Man kann das Floppy-Image mit dd auf einen stick schreiben (der ist dann automatisch FAT12 formatiert) und von/nach dort direkt laden/speichern, oder man verwendet noch einen zweiten Stick (FAT32).

EHCI arbeitet inzwischen so schnell, dass man damit auch real-time größere Datenmengen (z.B. Ergebnisse mathematischer Berechnungen) schreiben kann.

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm


Zuletzt bearbeitet von Erhard Henkes am 23:10:38 01.11.2011, insgesamt 3-mal bearbeitet
neuer_user
Mitglied

Benutzerprofil
Anmeldungsdatum: 28.12.2010
Beiträge: 210
Beitrag neuer_user Mitglied 21:50:30 03.11.2011   Titel:              Zitieren

Zitat:
Zitat:
wäre dann internet in vBox möglich (oder geht es doch schon)?

Prinzipiell könnte es gehen. Ich habe Internet bisher nur mit qemu (rtl8139, pcnet, e1000) auf Win XP als Host geschafft. VBox hat eine PRO/1000, die unter "Host only" bis DHCP ACK läuft. Die Karte sendet und empfängt also korrekt. Vielleicht könnte da jemand heraus finden, wie man da weiter kommt. Aber wie gesagt, einfach qemu einsetzen (zur Zeit am besten noch 0.14.1).


mit NAT und PRO/1000 MT Desktop läufts...
Erhard Henkes
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.04.2000
Beiträge: 11924
Beitrag Erhard Henkes Mitglied 16:17:03 24.12.2011   Titel:              Zitieren

An dieser Stelle darf ich mich ganz herzlich bei allen bedanken, die bei diesem OS-Projekt dabei sind und ihm die Treue halten. Euch allen wünsche ich frohe und gemütliche Festtage und ein glückliches, erfolgreiches und gesundes 2012! :xmas1:

_________________
OS-Development-, C++, Win32-API-, MFC-, Chemie-, Robotik- und Flugsimulator-Tutorials
http://www.henkessoft.de/index.htm
C/C++ Forum :: Projekt: OS-Development  ::  Eigenes OS?   Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können keine Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum nicht antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.de ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info, www.c-sar.de, www.c-plusplus.net und www.baeckmann.de enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.