Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: nico 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
-
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.
-
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
-
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.
-
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.
-
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).
-
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.
-
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.
-
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.
-
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?
-
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.
-
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.
-
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.
-
ich irgendwie nicht wirklich weitergekommen. habe jetzt folgendes programm:
boot.asm
[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
[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:
...
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?
-
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.
-
hab das mal abgeändert (hat aber nicht funktioniert):
gdt_ptr:
.limit dw gdt_end-gdt-1
.base dd gdt
da er offentsichtlich die gdt falsch lädt, hier nochmal meine ld.conf
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 (?!?).
-
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
-
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