Autor Thema: [Gelöst] GDT über Inline-Assembler  (Gelesen 4771 mal)

grebaldi

  • Beiträge: 8
    • Profil anzeigen
    • Offizielle Seite von Donkel Oktor
Gespeichert
« am: 06. November 2008, 00:12 »
Guten Abend!

Ich habe mich beim Thema OSDev nun bis hin zum GDT durchgeforstet. Ich entwickle nebenbei einen kleinen Kernel in Pascal (dieses, weil ich mich in dieser Sprache am besten auskenne und ja nur OSDev lernen möchte und nicht gleich C). Der Kernel hat erstmal keinen weiteren Sinn, sondern soll mir helfen die Materie zu verstehen.

Als Bootloader verwende ich GRUB, welcher ja gleich den Protected Mode aktiviert und eine GDT schreibt. Diese muss nun überschrieben werden und dies wollte ich realisieren, indem ich innerhalb meines Pascal-Kernels Inline Assembler anwende.

Ich frage mich nun: Ist das überhaupt die richtige Phase der Ausführung, um das zu tun?

Und wenn ja: Wie sieht so ein ganz einfacher Code in Assembler aus, der einerseits den Null-Deskriptor+2 weitere Deskriptoren definiert und diese dann in eine neue GDT schreibt?

Die meisten Tutorials, die ich so gefunden habe beschäftigen sich mit der GDT nur in dem Zusammenhang, dass man sie schriebt, um dann in den Protected Mode zu springen. Bei der Verwendung von GRUB ist das allerdings schon geschehen...

Ich hoffe ich habe verständlich ausgedrückt, was mein Problem ist. Ich bedanke mich im Voraus für alle Antworten.

mfg, grebaldi
« Letzte Änderung: 07. November 2008, 12:43 von grebaldi »
XOR GOD, GOD

;now type whatever you want

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 06. November 2008, 11:35 »
Ich fang mit den Antworten einfach mal von oben an.

Jo, irgendwo am Anfang des Kernels paßt schon. Aber du willst die Deskriptoren gar nicht in Assembler definieren. Du kannst dir da schöne Pascal-Records dafür basteln (packed nicht vergessen!) und das alles im Pascal-Code initialisieren. Zum Laden der GDT hast du dann eben noch das lgdt in Inline-Assembler, aber das war's.

Ich glaube, dein eigentliches Problem ist, daß du noch nicht verstanden hast, wofür die GDT gut ist. ;) Letztendlich geht es dabei um Segmentierung. Im Real Mode war das einfach, da war ein Segment durch die Basisadresse definiert und fertig. Im Protected Mode ist das etwas mehr (unterschiedliche Längen, Zugriffsberechtigung und solches Zeug) und paßt nicht mehr ganz in ein 16-Bit-Register rein. Deswegen bastelt man sich eine Tabelle, wo die ganzen Informationen drinnen stehen, und die Segmentregister haben nur noch einen Verweis auf die Tabelle (ist nicht hundertprozentig korrekt, die aktuellen Segmente werden tatsächlich in versteckten Registern gehalten, die CPU greift also tatsächlich nicht ständig auf die GDT zu).

So, und damit kommen wir zu der Frage, wann oder warum du eine GDT brauchst: Offensichtlich, sobald du ein Segmentregister neu laden willst, weil du dann den Index in der GDT brauchst - und was GRUB gemachst hast, weißt du laut Spezifikation nicht. Das Segment wechseln wirst du spätestens beim Multitasking müssen. Solange du das nicht tust, brauchst du strenggenommen auch keine neue GDT aufsetzen.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

grebaldi

  • Beiträge: 8
    • Profil anzeigen
    • Offizielle Seite von Donkel Oktor
Gespeichert
« Antwort #2 am: 06. November 2008, 19:03 »
Ich bedanke mich erstmal für die Informationen. Ich bin gerade dabei einen entsprechenden Pascal Code zu schreiben. Bis jetzt ist mir auch Code-technisch alles klar bis auf eine Sache, wo es bei mir noch ein wenig hakt. Und dies wäre der Far Jump ins Code Segment, von dem ich keine Ahnung habe, wie ich ihn im Inline Assembler realisieren kann. Vielleicht kriege ich es ja noch von selbst raus, aber wenn jemand bescheid weiß, so würde ich natürlich gern die Erkenntnis teilen wollen^^

Vielen Dank nochmal,
grebaldi
XOR GOD, GOD

;now type whatever you want

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 06. November 2008, 20:11 »
Du benutzt FPC? Dessen Inline-Assembler kommt mir jedem Mal, das ich ihn anschaue, kaputter vor. ;)

asm
    jmpl .L1, $0x08
.L1:
end;
Das da könnte es tun. Also jmp statt ljmp und die Operanden grad falschrum hinschreiben...
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

grebaldi

  • Beiträge: 8
    • Profil anzeigen
    • Offizielle Seite von Donkel Oktor
Gespeichert
« Antwort #4 am: 06. November 2008, 20:48 »
hmmm... FPC mag das Label nicht. "Unknown Identifier "L1"" heißt es da im Compiler-Auswurf. Nun bin ich mir nicht ganz sicher, ob Labels irgendwie anders deklariert werden müssen... Das wäre aber sehr schräg...
XOR GOD, GOD

;now type whatever you want

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 06. November 2008, 20:57 »
Also meiner mag das. Du hast ihn schon auf AT&T-Syntax gelassen, oder?

Welche Version? Ich habe 2.0.4.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

grebaldi

  • Beiträge: 8
    • Profil anzeigen
    • Offizielle Seite von Donkel Oktor
Gespeichert
« Antwort #6 am: 06. November 2008, 22:43 »
Ich hab die 2.2.2 und hab gerade gesehen, dass meine fpc.cfg tot ist (quasi leer), weiß der fuchs warum. Das wird's wohl sein, ich muss sie mal wiederherstellen.

edit: Schon lustig, fpc.cfg ist wieder da, jetz mag er die register nicht. Mit dem Label hat er kein problem, obwohl ich glaube, dass er es sich gar nicht anschaut. Ich werde wohl noch etwas herumprobieren müssen....

edit2: Habe doch wieder auf Intel Syntax zurückgeschalten, da einfacher und gewohnter. Labels müssen dann aber mit vorangestelltem '@' deklariert werden - manchmal ist es zum Haare ausraufen.
Jetz muss ich noch ein wenig Kleinkram fertig stellen und dann müsste es gehen. Ich bedanke mich nochmal vielmals für die Hilfe!
« Letzte Änderung: 06. November 2008, 23:09 von grebaldi »
XOR GOD, GOD

;now type whatever you want

grebaldi

  • Beiträge: 8
    • Profil anzeigen
    • Offizielle Seite von Donkel Oktor
Gespeichert
« Antwort #7 am: 07. November 2008, 02:38 »
So, meine gdt-unit ist fertig und funktioniert natürlich nicht. Ich habe sie von einem passenden C-Beispiel übersetzt, es kann natürlich sein, dass ich in vielerlei hinsicht unrecht hatte (c ist ja nunmal ein wenig anders, und viel davon verstehe ich nicht). Der Code ist aber erstmal eine Basis. Ich dachte mir, ihn während meiner fehlersuche öffentlich zur schau zu stellen (denn vielleicht kommt jemand früher als ich auf den entscheidenden fehler).

unit moloGDT;

interface

type
 gdt_entry = packed record
      limit_low   : Word;
  base_low    : Word;
  base_middle : Byte;
  access      : Byte;
  granularity : Byte;
  base_high   : Byte;
 end;
 
 gdt_ptr = packed record
      limit : Word;
  base  : Word;
 end;

procedure gdt_flush; Assembler;
procedure gdt_set_gate(num:Word; base,limit:Cardinal; access,gran:Byte);
procedure gdt_install;
 
implementation

var gdt : array[0..2] of gdt_entry;
    gp  : gdt_ptr;

procedure gdt_flush; Assembler;
asm
  lgdt gp
  movw $0x10, %ax
  movw %ax, %ds
  movw %ax, %es
  movw %ax, %fs
  movw %ax, %gs
  movw %ax, %ss
  jmpl $0x08, .L1
 
.L1:
end;

procedure gdt_set_gate(num:Word; base,limit:Cardinal; access,gran:Byte);
begin
gdt[num].base_low := (base AND $FFFF);
gdt[num].base_middle := (base SHR 16) AND $FF;
gdt[num].base_high := (base SHR 24) AND $FF;

gdt[num].limit_low := (limit AND $FFFF);
gdt[num].granularity := (limit SHR 16) AND $0F;

gdt[num].granularity := gdt[num].granularity XOR (gran AND $F0);
gdt[num].access := access;
end;

procedure gdt_install;[public , alias: 'gdt_install'];
begin
  gdt_set_gate(0,0,0,0,0);
  gdt_set_gate(1,0,$FFFFFFFF,$9A,$CF);
  gdt_set_gate(2,0,$FFFFFFFF,$92,$CF);
 
  gp.limit := (sizeOf(gdt_entry)*3)-1;
  gp.base  := word(@gdt);
 
  gdt_flush;
end;

end.

Die Unit wird im Kernelcode eingebunden und gdt_install wird gleich als erstes im Kernel aufgerufen. Ich werde mich auf die Suche machen, aber bin natürlich über Unterstützung immer glücklich^^.

Vielen Dank an taljeth bis hier hin! (Bin doch auf AT&T-Syntax umgestiegen, weil in der Intel-Syntax keine Manipulation von Segment-registern möglich ist, arrrgh.)

mfg, grebaldi
XOR GOD, GOD

;now type whatever you want

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 07. November 2008, 09:12 »
Zitat
gdt_ptr = packed record
      limit : Word;
     base  : Word;
 end;
16 Bit sind etwas wenig für einen Pointer, ein dword sollte es schon sein. Oder am besten nimmst du auch als Datentyp einfach das, was es in Wirklichkeit ist, nämlich ein Pointer. Dann bist du auch die Warnung "moloGDT.pas(63,15) Warning: Conversion between ordinals and pointers is not portable" los.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

grebaldi

  • Beiträge: 8
    • Profil anzeigen
    • Offizielle Seite von Donkel Oktor
Gespeichert
« Antwort #9 am: 07. November 2008, 09:52 »
Ich habe die words korrigiert und gdt_ptr.base als pointer definiert (bzw. ich habs auch einmal mit gp komplett als pointer probiert), aber das hat's leider nicht gebracht.

Die bitweise Operationen müssten so eigentlich stimmen (wenn ich sie in C richtig interpretiert habe, versteht sich). Wie gesagt, der Code ist einem Tutorial entnommen (hier zu finden) und von mir übersetzt. Ich bin etwas stark verwirrt, da es sich ja um ziemlich einfache definitionen handelt.....
XOR GOD, GOD

;now type whatever you want

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 07. November 2008, 10:04 »
Funktioniert nicht heißt, die VM semmelt ab? Dreh mal in bochs das Loglevel ganz auf, spätestens dann sagt er dir auch, was kaputt ist. Das Problem ist dann nur noch, zu verstehen, was er eigentlich meint. ;)

Ob die Records so richtig sind, kann ich nicht sagen, ich kenn die nicht auswendig. Vergleichen mit anderem Code kannst du ja selber genauso gut. An dieser Stelle hängt aber irgendwie jeder eine Weile lang, das ist wohl normal.

Edit: Mal kurz mit dem Link verglichen... | ist ein or, ^ wäre xor.
« Letzte Änderung: 07. November 2008, 10:06 von taljeth »
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

grebaldi

  • Beiträge: 8
    • Profil anzeigen
    • Offizielle Seite von Donkel Oktor
Gespeichert
« Antwort #11 am: 07. November 2008, 10:14 »
Den operator hatte ich schon geändert, ich bin da an eine falsche tabelle geraten.

Aktuell ist es quasi ein OR. (und es funktioniert natürlich trotzdem nicht - aber es ist vrmtl. wie du schon sagst. GDT- eine Art Feuertaufe für jeden (Pascal-)Programmierer^^)

Ich habe gerade einen Code entdeckt, der so ziemlich ähnlich aussieht, wie meiner (also Pascal). Jetzt will ich mal schauen, ob der funktioniert und dann vergleichen, was ich falsch mache.

Ich kann mich nur nochmal für deine Hilfe bedanken.

Edit: Ich bin schockiert und begeistert zugleich, der andere Code funktioniert - sogar mit Intel-Syntax im Inline-Assembler. Jetz werde ich nochmal genauso viel Zeit benötigen um das zu begreifen. Aber so ist wenigstens vorwärtskommen angesagt.
« Letzte Änderung: 07. November 2008, 10:29 von grebaldi »
XOR GOD, GOD

;now type whatever you want

grebaldi

  • Beiträge: 8
    • Profil anzeigen
    • Offizielle Seite von Donkel Oktor
Gespeichert
« Antwort #12 am: 07. November 2008, 11:23 »
Für alle Pascal-Interessierten hier jetzt mal der funktionierende Code meiner Unit:

unit moloGDT;

interface

type
 gdt_entry = packed record
      limit_low   : Word;
  base_low    : Word;
  base_middle : Byte;
  access      : Byte;
  granularity : Byte;
  base_high   : Byte;
 end;
 
 gdt_ptr = packed record
      limit : Word;
  base  : LongWord;
 end;

var gdt : array[0..2] of gdt_entry;
    gp  : gdt_ptr;

procedure gdt_set_gate(num:LongInt; base,limit:LongWord; access,gran:Byte);
procedure gdt_install;
 
implementation

procedure gdt_flush; Assembler; nostackframe;
label
  flush;
asm
  lgdt [gp]
  mov  ax,$10
  mov  ds,ax
  mov  es,ax
  mov  fs,ax
  mov  gs,ax
  mov  ss,ax
  jmp  $08,flush   // don't know the correct syntax in FPC inline assembler, but it works!
flush:
end;

procedure gdt_set_gate(num:LongInt; base,limit:LongWord; access,gran:Byte);
begin
gdt[num].base_low := (base AND $FFFF);
gdt[num].base_middle := (base SHR 16) AND $FF;
gdt[num].base_high := (base SHR 24) AND $FF;

gdt[num].limit_low := (limit AND $FFFF);
gdt[num].granularity := (limit SHR 16) AND $0F;

gdt[num].granularity := gdt[num].granularity OR (gran AND $F0);
gdt[num].access := access;
end;

procedure gdt_install;[public , alias: 'gdt_install'];
begin
  gdt_set_gate(0,0,0,0,0);
  gdt_set_gate(1,0,$FFFFFFFF,$9A,$CF);
  gdt_set_gate(2,0,$FFFFFFFF,$92,$CF);
 
  gp.limit := (sizeOf(gdt))-1;
  gp.base  := LongWord(@gdt);
 
 
  gdt_flush;
end;

end.

XOR GOD, GOD

;now type whatever you want

 

Einloggen