Autor Thema: Global Descriptor Table  (Gelesen 10363 mal)

nico

  • Beiträge: 16
    • Profil anzeigen
Gespeichert
« am: 10. April 2008, 16:57 »
Hi,

ich habe ein kleines Verständnisproblem worum es sich genau bei der GDT handelt.
Soweit ich das Verstanden habe, kann mit in der GDT Segment Desktiptoren für
(beliebige) Hauptspeicherbereiche ablegen, die verschiedene Eigenschaften haben (r/w, daten, code, etc...). Wenn mein kernel vom Grub geladen wird, befindet sich
das Programm ja schon im protected mode und hat auch schon eine GDT eingerichtet.
Also sind die Segmentregister auch schon richtig eingestellt? Bzw. wie wurde diese eingestellt?

Wenn die GDT nun überschrieben wird, woher weiß ich ob mein aktueller Code/Daten (Kernel) auch in diesem Segment liegt?

bg nico

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 10. April 2008, 17:57 »
Wenn du eine neue GDT einrichtest, werden die neuen Werte erst dann übernommen, wenn du das entsprechende Register neu lädst. Deswegen wirst du z.B. in LOST sehen, daß ds, es, fs, gs und ss neu geladen werden und außerdem ein ljmp durchgeführt wird, um auch noch cs neu zu laden.

GRUB sichert dir nur zu, daß du beim Start jeweils ein Code- und ein Datensegment mit Basis 0 und Größe 4 GB hast. Das reicht dir für ein Hello World, aber auf Dauer brauchst du deine eigene GDT.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

nico

  • Beiträge: 16
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 10. April 2008, 18:28 »
danke für die antwort. ich hätte dazu auch gleich noch eine frage, ich habe in einigen
referenzprojekten gesehen, dass für die einzelnen level(0...3) jeweils ein code und datensegment mit basis 0B und limit 4GB angelegt wurde. was hat das für einen sinn, dass sich die segemente überlagern?

bg nico

FreakyPenguin

  • Administrator
  • Beiträge: 301
    • Profil anzeigen
    • toni.famkaufmann.info
Gespeichert
« Antwort #3 am: 10. April 2008, 18:37 »
In den meisten Betriebssystemen wird die Segmentierung heute nicht mehr benutzt, für den Zugriffsschutz und das Aufteilen des Speichers wird Paging benutzt.
In der GDT muss aber trotzdem für jede Privilegstufe, die bentuzt wird (meist 0 und 3), ein Deskriptor angelegt werden. Mit Paging wird dann meist ein flaches Speichermodell benutzt, also alle Deskriptoren mit Basis 0 und Limit 4G.

nico

  • Beiträge: 16
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 10. April 2008, 18:49 »
gut. also initialisiere ich die gdt mit 9 deskriptoren und nach laden der gdt update ich die segmentregister und mache einen jump zum kernel label.

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #5 am: 10. April 2008, 21:04 »
Du brauchst eigentlich nur 4 (für Ring0 und Ring3) und dann halt den Nulldeskriptor. Ring 1 und 2 wird meisten überhaupt nicht verwendet.
Später brauchst du dann noch einen pro CPU für jeweils einen TSS-Deskriptor (TSS = Task-State-Segment, Da wird der CPU-Status beim Wechsel von einem Thread/Prozess in den Kernel gespeichert).
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

Korona

  • Beiträge: 94
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 10. April 2008, 21:06 »
Wozu 9 Deskriptoren? Ring 1 und 2 werden von "modernen" Systemen nicht mehr benutzt, Hardwarezugriffe werden über Ring0 bzw. den Kernel durchgeführt, Treiber laufen je nach Kernelmodell (Microkernel oder Monolith) in Ring3 oder 0. Generell brauchst du für Ring0 und 3 jeweils ein Code und ein Datensegment. Für Multitasking brauchst du noch einen TSS Deskriptor, evt. können zusätzliche Deskriptoren nützlich sein, wenn du mithilfe von FS oder GS auf thread-lokale Datenstrukturen oder andere wichtige Strukturen zugreifen willst.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 10. April 2008, 21:09 »
Ring 1 und 2 werden von "modernen" Systemen nicht mehr benutzt,
Nicht mehr? Wurden sie denn jemals weit verbreitet benutzt? Aber davon abgesehen, um ein aktuelles, "modernes" System zu nennen, das sie benutzt: Xen benutzt auf i386 Ring 1 für die Kernel der Domains.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Korona

  • Beiträge: 94
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 10. April 2008, 21:16 »
OS/2 benutzte z.B. Ring2 (ich denke auch Ring1, bin mir aber nicht sicher). Es läuft daher nicht auf früheren Versionen von VMWare.
Mit "modern" wollte ich ausdrücken, das heutige Desktopsysteme wie Linux, BSD Varianten oder Windows die Ringe 1 & 2 nicht nutzen. Ich hab das Wort absichtlich in Anführungsstriche geschrieben, da modern immer sehr relativ ist. :D
Dass Xen Ring1 benutzt habe ich nicht gewusst; es ist aber interessant, dass Ring1 doch noch benutzt wird, danke für die Info.

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #9 am: 10. April 2008, 21:58 »
Xen benutzt auf i386 Ring 1 für die Kernel der Domains.
Aber doch auch nur für die Paravirtualisierung, d.h. für modifizierte Gastsysteme, oder?
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 10. April 2008, 22:23 »
Ja, aber zumindest für Dom0 ist das immer der Fall. ;)

Wie svm bzw. vmx genau funktionieren, weiß ich ehrlichgesagt nicht. Als die Technik neu war, wurde gelegentlich von einer Art "Ring -1" geredet. Ob das eine halbwegs zutreffende Beschreibung ist, müßte ich mich aber selber erst einmal schlau machen.

Edit: Wenn ich schon am Klarstellen bin: i386 ist hier in der Tat auch abgrenzend gegenüber x86_64 gemeint. Auf 64 Bit läuft auch der Kernel in Ring 3.
« Letzte Änderung: 10. April 2008, 22:24 von taljeth »
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

nico

  • Beiträge: 16
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 11. April 2008, 00:15 »
noch ne kurze frage, woher weiß ich ob meine gdt richtig initialisiert ist, also ob alles geklappt hat? ich hab jetzt 3 segmente eingerichtet und nach der segmentregisteraktualisierung springe ich in eine endlosschleife. das funktioniert soweit, also bochs meckert nicht rum. ich hab mal testweise die base-adressen der deskriptoren verändert und da kommt auch kein fehler.

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #12 am: 11. April 2008, 20:59 »
Wenn du bochs beendest stehen normalerweise im Log/Terminal alle Register aufgelistet und dabei auch eine Liste der Segmentregister, mit Selektor, Basisadresse, Limit und Flags. Einfach mal schauen ob die stimmen.
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

nico

  • Beiträge: 16
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 23. May 2008, 22:25 »
ich irgendwie nicht wirklich weitergekommen. habe jetzt folgendes programm:

boot.asm
Zitat
[bits 32]

[global start]
[section .text]

mboot_header:
  align 4
  dd 0x1BADB002 ; mboot magic number
  dd 0x00000005 ; mboot flags
  dd 0xe4524ff9 ; mboot checksum

_start:
start:
  cli

  mov edx,eax
  mov edi,0xB8000
  mov ah,0x0F
  mov al,0x00
  mov ecx,(80*25)
  rep stosw

  lgdt [gdt_ptr]

  mov bx,0x38
  mov ds,bx
  mov es,bx
  mov fs,ax
  mov gs,ax

  jmp 0x48:_loop

_halt:
  hlt

_loop:
  jmp _loop

%include "gdt.asm"

gdt.asm

Zitat
[bits 32]

[section .data]
  align 4, db 0

gdt_ptr:
  .limit dw (gdt_end-gdt-1)
  .base dd 0x00000000

gdt:
  align 4
  null_desc dw  0x0000,0x0000,0x0000,0x0000
  user_code dw  0xFFFF,0x0000,0xFA00,0x00CF
  user_data dw  0xFFFF,0x0000,0xF200,0x00CF
  kern_code dw  0xFFFF,0x0000,0x9A00,0x00CF
  kern_data dw  0xFFFF,0x0000,0x9200,0x00CF
gdt_end:

bochs beendet das programm mit folgenden status:

Zitat
...
00069269588i[CPU0 ] protected mode
00069269588i[CPU0 ] CS.d_b = 32 bit
00069269588i[CPU0 ] SS.d_b = 32 bit
00069269588i[CPU0 ] | EAX=2bad0f00  EBX=00020028  ECX=00000000  EDX=2badb002
00069269588i[CPU0 ] | ESP=00067efc  EBP=00067f1c  ESI=00020e74  EDI=000b8fa0
00069269588i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf ZF af PF cf
00069269588i[CPU0 ] | SEG selector     base    limit G D
00069269588i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00069269588i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
00069269588i[CPU0 ] |  DS:0028( 0005| 0|  0) f053f000 0000ff53 0 0
00069269588i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00069269588i[CPU0 ] |  ES:0028( 0005| 0|  0) f053f000 0000ff53 0 0
00069269588i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00069269588i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00069269588i[CPU0 ] | EIP=01000044 (01000044)
00069269588i[CPU0 ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00069269588i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00069269588i[CPU0 ] >> mov fs, ax : 8EE0
00069269588e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00069269588i[SYS  ] bx_pc_system_c::Reset(SOFTWARE) called
00069269588i[APIC0] local apic in CPU 0 initializing
00069269588e[CPU0 ] CPU_LOOP bx_guard.interrupt_requested=1
Next at t=69269588
(0) [0x01000044] 0008:1000044 (unk. ctxt): mov fs, ax                ; 8ee0
<bochs:2> q
00069269588i[     ] dbg: Quit
00069269588i[CPU0 ] real mode
00069269588i[CPU0 ] CS.d_b = 16 bit
00069269588i[CPU0 ] SS.d_b = 16 bit
00069269588i[CPU0 ] | EAX=00000000  EBX=00000000  ECX=00000000  EDX=00000f00
00069269588i[CPU0 ] | ESP=00000000  EBP=00000000  ESI=00000000  EDI=00000000
00069269588i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf zf af pf cf
00069269588i[CPU0 ] | SEG selector     base    limit G D
00069269588i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00069269588i[CPU0 ] |  CS:f000( 1e00| 0|  0) ffff0000 0000ffff 0 0
00069269588i[CPU0 ] |  DS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00069269588i[CPU0 ] |  SS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00069269588i[CPU0 ] |  ES:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00069269588i[CPU0 ] |  FS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00069269588i[CPU0 ] |  GS:0000( 0000| 0|  0) 00000000 0000ffff 0 0
00069269588i[CPU0 ] | EIP=0000fff0 (0000fff0)
00069269588i[CPU0 ] | CR0=0x00000010 CR1=0 CR2=0x00000000
00069269588i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00069269588i[CPU0 ] >> jmp far f000:e05b : EA5BE000F0
00069269588i[SYS  ] Last time is 1211581172
00069269588i[XGUI ] Exit.
00069269588i[CTRL ] quit_sim called with exit code 0

offensichtlich hat es nicht geklappt. sieht jmd vielleicht den fehler? noch eine frage zu den segement deskriptoren in der gdt. ich habe das auch im pm tutorial gesehen: warum fängt man mit den LSB im deskriptor an? somit liegt der deskriptor doch "falschherum" im speicher?
« Letzte Änderung: 24. May 2008, 10:09 von nico »

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #14 am: 24. May 2008, 10:52 »
Du solltest evtl. die Basisadresse von gdt_ptr setzen, sonst meint die CPU deine GDT wäre wirklich bei 0. Außerdem müsstest du evtl. ein ORG einsetzten, um dem Assembler zu sagen, wo den die Offsets überhaupt liegen.
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

nico

  • Beiträge: 16
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 24. May 2008, 11:28 »
hab das mal abgeändert (hat aber nicht funktioniert):
Zitat
gdt_ptr:
  .limit  dw gdt_end-gdt-1
  .base   dd gdt

da er offentsichtlich die gdt falsch lädt, hier nochmal meine ld.conf
Zitat
ENTRY(start)

SECTIONS {
  .text 0x00100000 : {
    Kernel_Base = .;
    *(.text)
  }

  .data : {
    *(.data)
  }

  .bss : {
    *(.bss)
  }
  Kernel_End = .;
}

soweit wie ich das verstanden habe, wird nach dem linken das textsegment bei 0x00100000 beginnen. da ich aber im code kein org... drin habe rechnet der assembler mit 0 als basis und addiert darauf die offset's (?). wenn ich den code mit nasm -felf ... assembliere und nen org... drin hab meckert der rum. für grub muss aber das format elf und nicht bin sein (?!?).
« Letzte Änderung: 24. May 2008, 12:31 von nico »

FreakyPenguin

  • Administrator
  • Beiträge: 301
    • Profil anzeigen
    • toni.famkaufmann.info
Gespeichert
« Antwort #16 am: 24. May 2008, 14:15 »
soweit wie ich das verstanden habe, wird nach dem linken das textsegment bei 0x00100000 beginnen. da ich aber im code kein org... drin habe rechnet der assembler mit 0 als basis und addiert darauf die offset's (?). wenn ich den code mit nasm -felf ... assembliere und nen org... drin hab meckert der rum. für grub muss aber das format elf und nicht bin sein (?!?).

Nein der Assembler rechnet da garnichts. ;-) Das org ist nur notwendig, wenn der Assembler selbst linkt, wie das bei -fbin notwendig ist. Bei elf übernimmt das aber der Linker.


Edit:
Der Fehler müsste hier liegen, wenn ich mich nicht verrechnet hab:
  mov bx,0x38
  mov ds,bx
  mov es,bx
  mov fs,ax
  mov gs,ax

  jmp 0x48:_loop

Der Datendeskriptor hat die Nummer 4 (bei 0 angefangen mit zählen) das ergibt für den Selektor 4 << 3 = 32 = 0x20. Für den Codedeskriptor genau das selbe, diesmal mit index 3: 3 << 3 = 24 = 0x18
« Letzte Änderung: 24. May 2008, 14:21 von FreakyPenguin »

nico

  • Beiträge: 16
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 24. May 2008, 14:36 »
oha, da hab ich mich aber derbe vertan. jetzt funktioniert es. außerdem habe ich das
align-statement sowie die padbytes entfernt.

besten dank
nico

 

Einloggen