Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: Cheebi am 14. September 2006, 16:11
-
Hallo,
wenn ich im Real-Mode über den BIOS-Interrupt 013h einen Sektor von Diskette an die Stelle [es:bx] im RAM lade, darf dann [es:bx] auch auf eine höhere Speicherstelle als 1MB zeigen? Weil, wie kann man denn sonst den 32-Bit-Kernel im RM an eine höhere Adresse als 1MB laden, was ja nun einige Kernel sind...
Gruß Cheebi
-
Dafür musst du das A20 Gate enablen. Tutorial dazu (http://www.jay-code.de/scripts/htmlgenerator.php?page=a20gate&directory=tutorials)
Entweder erledigst du das schon im Bootloader oder du lässt das den Kernel machen, der sich dann auch an die neue Adresse kopiert. Dann musst du einfach nur noch zur neuen Adresse springen, bzw. einen anderen Entry Point nehmen um das kopieren nicht nochmal zu erledigen.
-
Durch die Eigenart der Adressierung im RM ist es möglich 65520 Byte des ersten MiBs anzusprechen wenn das a20 eingeschaltet ist.
FFFF0h
+ FFFFh
=10FFEFh
Für einen Bootloader ist der UnrealMode dabei eventuell etwas interessanter.
-
Für einen Bootloader ist der UnrealMode dabei eventuell etwas interessanter.
Ich hab mich schon oft um Infos für den Unreal Mode bemüht, auch ein paar Materialien dazzu gefunden.
Leider alls nur Englisch bzw. die Teile, die Deutsch waren, verlangten einiges an Wissen um den Protected Mode.
Kennst du einfach ein Stück Code, dass ich in den Bootloader einbauen kann und in den Protected Mode schaltet, benötigte Operationen macht und wieder in den RM schaltet?
Die Codebeispiele, die ich gefunden habe, waren nur dazu geeignet, um in DOS ausgeführt zu werden.
Jegliche Versuche, den Code umzuschreiben, um für mein OS kompatibel zu sein, schlugen fehl ( :-) ), was auch daran lag, dass ich Probleme hatte, den ASM Code für den FASM umzuschreiben.
-
Das hab ich jetzt so spontan gefunden: http://de.wikipedia.org/wiki/Benutzer:INFNIC/Makro_um_FS_und_GS_auf_4_GB_zu_erh%C3%B6hen
Aber ich würde ehrlich gesagt nicht im Bootloader in den Unreal Mode wechseln, nur um später den Kernel dann doch im Pmode laufen zu lassen. Also wenn schon dann gleich in den Protected Mode.
-
Aber ich würde ehrlich gesagt nicht im Bootloader in den Unreal Mode wechseln, nur um später den Kernel dann doch im Pmode laufen zu lassen. Also wenn schon dann gleich in den Protected Mode.
Soviel ich weiß, ist das aber die beste Methode um mit dem BIOS-Funktionen zu lesen und gleichzeitig auf den hohen Speicher zu zugreifen. Also für einen Bootloader optimal.
-
Hm, stimmt. Wenn man die BIOS Funktionen noch braucht, ist das sicher besser als der PMode ;) Alternativ kann man den Kernel natürlich unter die 1MB Grenze laden, und dann im Bootloader nach dem PM Switch kopieren.
-
Das hab ich jetzt so spontan gefunden: http://de.wikipedia.org/wiki/Benutzer:INFNIC/Makro_um_FS_und_GS_auf_4_GB_zu_erh%C3%B6hen
Aber ich würde ehrlich gesagt nicht im Bootloader in den Unreal Mode wechseln, nur um später den Kernel dann doch im Pmode laufen zu lassen. Also wenn schon dann gleich in den Protected Mode.
THX.
Werd ich ausprobieren, sobald ich Zeit hab.
Ich hab eigentlich vor, das BiehlOS die ganze Zeit im Unreal Mode laufen zu lassen.
Im protected Mode müsste ich erstmal Treiber für alles mögliche schreiben.
Und so kann ich jetzt schon 4GB Speicher nutzen und dann nach und nach die BIOS INT's durch eigene Treiber ersetzen.
Ich hab mal irgendwas gelesen, dass der prozessor aus dem Unreal Mode zurück in den Real Mode springt, wenn man einen Befehl verwendet, wie Push oder Pop.
Stimmt das?
weil das wär dann irgendwie blöd :lol:
-
Ich glaube nicht, dass der Unrealmode für den Dauerbetrieb geeignet ist. Da kann man besser in den PM gehen und von dort aus intensiv mit dem v86-Modus arbeiten.
Oder für alles einen Treiber schreiben und nur den PM benutzen. ;]
-
von dort aus intensiv mit dem v86-Modus arbeiten.
Der ist aber auch nicht für den Dauerbetrieb zu empfehlen ;) Also lieber gleich gescheite Treiber schreiben (für die Sachen die das BIOS unterstützt ist das nun auch wieder nicht so schwer) und nicht so ein gefrickel betreiben (Ausnahme sind natürlich VBE Treiber, leider).
-
naja, ich will jetzt nicht unbedingt meinen ganzen Code auf PM umstellen.
wenn alles ausnahmsweise schon mal richtig läuft :mrgreen:
Mir ist schon klar, dass das eher ne äußerste Notlösung ist.
naja.
ich hoffe, der Threadersteller verzeiht mir, wenn ich seinen Thread weiter missbrauche :-(
ich hab nun versucht, den Code ( http://de.wikipedia.org/wiki/Benutzer:INFNIC/Makro_um_FS_und_GS_auf_4_GB_zu_erh%C3%B6hen ) für den FASM umzuschreiben.
Das kam dabei raus:
jmp 07c0h:start
start:
;sw_to_pm macro
mov ax, cs
mov [cs:rmseg], ax ;sprung adresse berechnen
and eax, 0ffffh
shl eax, 4
mov [cs:basis15], ax
mov ebx, eax
shr ebx, 16
mov [cs:basis23], bl
add eax, ptr cs:GDT_start ;GDT adresse berechnen
mov [cs:gdt_DADR], eax
lgdt [cs:gdt_adr]
CLI ; intterupts sperren
mov eax, cr0 ; in den pm wechseln
or eax, 1
mov cr0, eax
db 0eah ; sprung um schlange zu lerren
dw (pm);(offset pm)
dw 8
gdt_adr:
dw 32
gdt_DADR dd 0
GDT_start:
; DUMMY DESKRIPTOR
dw 0
dw 0
db 0
db 0
db 0
db 0
; CS DESKRIPTOR
dw 0ffffh
basis15 dw ?
basis23 db ?
db 09ah
db 00h
db 0
; fs/gs DESHRIPTOR
dw 0ffffh
dw 1
db 1
db 092h
db 11001111b
db 0
pm: mov ax, 10h ; segmentregister fs und gs laden
mov fs, ax
mov gs, ax
mov eax, cr0 ; zurück in den rm
btr eax, 0
mov cr0, eax
db 0eah
dw (rm)
rmseg: dw 0
rm: sti ; interupt wieder erlauben
; endm
mov [cs:0ffffffh], byte 56
mov al, [cs:0ffffffh]
jmp $
db 510-$ DUP(0)
dw 0aa55h
Leider scheint das nicht zu funktionieren.
Wenn ich das unter Bochs teste, startet sich der Bootloader ständig neu.
Die Fehlermeldung dürfte folgende sein:
//edit:
00002336258e[CPU0 ] jump_protected: dpl > CPL
00002336258e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
Wo liegt der Fehler?
Und mit welchem Assembler wurde der originalcode erstellt?
NASM brachte mir ne Menge Fehler, FASM sowieso.
Und TASM oder MASM bringen mir auch Fehlermeldungen, allerdings ziemlich unterschiedliche.
Und nehmen wir an, der Code würde funktionieren.
Und ich will auf den RAM zugreifen.
Dann muss ich in die Segmentregister ja trotzdem irgendeinen Wert laden, oder?
-
Hat keiner ne Ahnung?
Kann mir vielleicht jemand den Originalen Code durch nen geeigneten Assembler jagen und mir die Binärdatei schicken?
Das ich die nur noch in dem Bootloader aufrufen brauche?
-
Hi,
keine Ahnung für welchen Assembler der Code ursprünglich war.
Aber hier nochmal was allgemeines aus Wikipedia:
To enable unreal mode, the program has to enter protected mode, locate a flat descriptor in the GDT or LDT or create such, load some of the segment registers with the respective protected mode "selector" , then cancel back protected mode. When jumping back to RM, the processor will continue using the cached descriptors as established in PM, at least until the segment registers are reloaded - thus allowing access to 4 GiB of "extended" memory from inside real mode.
Also ich versteh das so, dass das auch nur solange funktioniert wie die Segment Register unverändert bleiben.
The catch however is that the reloading of the segment descriptor caches now holding "unreal" values might occur asynchronously inside an exception/interrupt handler, and then even if the handler correctly attempts to reload the segment before IRET (returning from the interrupt/exception), it will fail as the hidden descriptor would be reloaded under the rules of the real mode resulting in the loss of the flat descriptor and imminent catastrophe! Hence one must either forbid interrupts while accessing "unreal" addresses - which can be for a small duration only, - or use a segment register (FS or GS) that the OS/BIOS/any drivers are absolutely guaranteed not to touch.
Hier steht nochmal ein Beispiel: Im Fall von einem Interrupt oder einer Exception werden die Segment Register natürlich verändert, beim IRET werden wieder die alten Werte wiederhergestellt. Problem: Jetzt ist man ja im Real Mode, das heißt, das ganze endet im totalen Chaos.
Einzige Lösung: Unreal Mode nur temporär benutzen mit deaktivierten Interrupts, oder halt FS/GS benutzen, da die vom Bios, etc. nicht geändert werden.
Naja, überzeugt mich noch nicht so, der Unreal Mode :)
-
Mist, ich benutze FS und GS zum temporären Zwischenspeichern von Daten :lol:
Naja, aber kein Problem, das nicht lösbar wäre :mrgreen:
Ich glaube jetzt wenigstens zu wissen, woran es liegt, dass ein Fehler ausgelöst wird.
Und zwar habe ich mal ein paar JMP $ gesetzt.
z.b. Hier:
org 07c0h
;sw_to_pm macro
mov ax, cs
mov [cs:rmseg], ax ;sprung adresse berechnen
and eax, 0ffffh
shl eax, 4
mov [cs:basis15], ax
mov ebx, eax
shr ebx, 16
mov [cs:basis23], bl
add eax, ptr cs:GDT_start ;GDT adresse berechnen
mov [cs:gdt_DADR], eax
lgdt [cs:gdt_adr]
CLI ; intterupts sperren
mov eax, cr0 ; in den pm wechseln
or eax, 1
mov cr0, eax
---> jmp $
db 0eah ; sprung um schlange zu lerren
dw pm
dw 8
Und siehe da: Bochs zeigt ganz brav an:
00048740000i[SYS ] Last time is 1158590493
00048740000i[CPU0 ] protected mode
00048740000i[CPU0 ] CS.d_b = 16 bit
00048740000i[CPU0 ] SS.d_b = 16 bit
OK.
Dann setze ich ein weiteres JMP $ (beim Label 'pm'):
org 07c0h
;sw_to_pm macro
mov ax, cs
mov [cs:rmseg], ax ;sprung adresse berechnen
and eax, 0ffffh
shl eax, 4
mov [cs:basis15], ax
mov ebx, eax
shr ebx, 16
mov [cs:basis23], bl
add eax, ptr cs:GDT_start ;GDT adresse berechnen
mov [cs:gdt_DADR], eax
lgdt [cs:gdt_adr]
CLI ; intterupts sperren
mov eax, cr0 ; in den pm wechseln
or eax, 1
mov cr0, eax
db 0eah ; sprung um schlange zu lerren
dw pm
dw 8
gdt_adr:
dw 32
gdt_DADR dd 0
GDT_start:
; DUMMY DESKRIPTOR
dw 0
dw 0
db 0
db 0
db 0
db 0
; CS DESKRIPTOR
dw 0ffffh
basis15 dw ?
basis23 db ?
db 09ah
db 00h
db 0
; fs/gs DESHRIPTOR
dw 0ffffh
dw 1
db 1
db 092h
db 11001111b
db 0
pm:
--> jmp $
mov ax, 10h ; segmentregister fs und gs laden
mov fs, ax
mov gs, ax
mov eax, cr0 ; zurück in den rm
btr eax, 0
mov cr0, eax
db 0eah
dw rm
rmseg: dw 0
rm: sti ; interupt wieder erlauben
; endm
;mov ax, 0
;mov ds, ax
;mov [ds:0ffffffh], byte 56
;mov al, [ds:0ffffffh]
jmp $
db 510-($-7c0h) DUP(0)
dw 0aa55h
Das läuft jetzt wiederum nichtmehr.
00000776212e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00000776212i[SYS ] bx_pc_system_c::Reset(SOFTWARE) called
00000776212i[APIC0] local apic in CPU apicid=00 initializing
00000780659i[BIOS ] rombios.c,v 1.138.2.1 2005/07/06 19:30:36 vruppert Exp $
00001110062i[KBD ] reset-disable command received
00001231775i[VBIOS]
VGABios $Id: vgabios.c,v 1.62 2005/07/02 18:39:43 vruppert Exp $
00001231846i[CLVGA] VBE known Display Interface b0c0
00001231878i[CLVGA] VBE known Display Interface b0c3
00001234803i[VBIOS] VBE Bios $Id: vbe.c,v 1.47 2005/05/24 16:50:50 vruppert Exp $
00001506756e[HD ] device set to 0 which does not exist
00001507049e[HD ] device set to 1 which does not exist
00001556224i[CPU0 ] -----------------------------------
00001556224i[CPU0 ] selector->index*8 + 7 = 15
00001556224i[CPU0 ] gdtr.limit = 0
00001556224i[CPU0 ] fetch_raw_descriptor: GDT: index > limit
00001556224i[CPU0 ] protected mode
00001556224i[CPU0 ] CS.d_b = 16 bit
00001556224i[CPU0 ] SS.d_b = 16 bit
00001556224i[CPU0 ] | EAX=00000011 EBX=00000000 ECX=00100001 EDX=00000000
00001556224i[CPU0 ] | ESP=0000fffe EBP=00000000 ESI=0000733c EDI=0000ffde
00001556224i[CPU0 ] | IOPL=0 NV UP DI PL NZ NA PE NC
00001556224i[CPU0 ] | SEG selector base limit G D
00001556224i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00001556224i[CPU0 ] | CS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00001556224i[CPU0 ] | DS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00001556224i[CPU0 ] | SS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00001556224i[CPU0 ] | ES:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00001556224i[CPU0 ] | FS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00001556224i[CPU0 ] | GS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00001556224i[CPU0 ] | EIP=00007c41 (00007c3c)
00001556224i[CPU0 ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00001556224i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
Heißt rein theoretisch:
Es muss an folgender Codesequenz liegen:
db 0eah ; sprung um schlange zu lerren
dw pm
dw 8
Blos wie kann ich das nun lösen?
-
Ersetz das am besten erstmal durch nen echten Befehl:
jmp 0x08:pm
Und hinter dem pm: muss evtl. ein [BITS 32] (oder wie auch immer das bei Fasm heißt) stehen, kann zwar auch sein dass das in dem Fall überflüssig ist, aber schaden kanns nicht. Wenn man das ergänzt, braucht man natürlich auch ein [BITS 16] vor dem rm:
-
Ersetz das am besten erstmal durch nen echten Befehl:
jmp 0x08:pm
Und hinter dem pm: muss evtl. ein [BITS 32] (oder wie auch immer das bei Fasm heißt) stehen, kann zwar auch sein dass das in dem Fall überflüssig ist, aber schaden kanns nicht. Wenn man das ergänzt, braucht man natürlich auch ein [BITS 16] vor dem rm:
In Fasm benutzt man useX, bzw use32 oder use16.
Es ist auf jeden Fall vor dem PM Code zu setzen!
-
du hast geschreiben
ORG 0x07C0
das muss aber entweder
ORG 0x0000
JMP 0x07C0:Start
oder
ORG 0x7C00
heißen
-
Hat leider nix gebracht.
Egal.
Ich hab jetzt einen Code, der scheint zu funktionieren:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Enable "unreal" mode
; This code is public domain (no copyright).
; You can do whatever you want with it.
;
; Unreal mode is identical with real mode with one exception: 32-bit
; addresses are allowed (they do not cause INT 0Dh, as they do in real mode)
;
; This code will fail if run in virtual 8086 mode (Windows DOS box
; or EMM386 loaded). Oh yeah, a 32-bit CPU is required (386+)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; we're in real mode
use16
DATA_SEL equ 8
jmp 07c0h:start
start:
mov ax, cs
mov ds, ax
mov es, ax
; ...
push ds
push es
xor eax,eax ; point gdt_ptr to gdt
mov ax,ds
shl eax,4
add eax,gdt ; EAX=linear address of gdt
mov [gdt_ptr + 2],eax
cli ; interrupts off
lgdt [gdt_ptr]
mov eax,cr0
or al,1
mov cr0,eax ; partial switch to 32-bit pmode
mov bx,DATA_SEL ; selector to segment w/ 4G limit
mov fs,bx
mov gs,bx ; set seg limits in descriptor caches
dec al
mov cr0,eax ; back to (un)real mode
pop es ; segment regs back to old values,
pop ds ; but now 32-bit addresses are OK
; ...
mov ds, bx
mov ah, 0eh
mov al, "k"
int 10h
mov edi,0B8000h ; point to screen
mov cx,160 ; just two lines
mov ah,1Eh ; yellow on blue screen attrib
mov al, 1
loops:
mov [gs:edi], AX
inc ax
inc edi
loop loops
jmp $
gdt: dw 0 ; limit 15:0
dw 0 ; base 15:0
db 0 ; base 23:16
db 0 ; access byte (descriptor type)
db 0 ; limit 19:16, flags
db 0 ; base 31:24
DATA_SEL equ $-gdt
dw 0FFFFh
dw 0
db 0
db 92h ; present, ring 0, data, expand-up, writable
db 0CFh ; page-granular, 32-bit
db 0
gdt_end:
gdt_ptr:
dw gdt_end - gdt - 1 ; GDT limit
dd 0 ; linear adr of GDT (set above)
db 510-$ dup(0)
dw 0aa55h
Bochs sagt dazu:
00034788000p[WGUI ] >>PANIC<< POWER button turned off.
00034788000i[SYS ] Last time is 1158674124
00034788000i[CPU0 ] real mode
00034788000i[CPU0 ] CS.d_b = 16 bit
00034788000i[CPU0 ] SS.d_b = 16 bit
00034788000i[CPU0 ] | EAX=00001ea1 EBX=00000008 ECX=000f0000 EDX=00000000
00034788000i[CPU0 ] | ESP=0000fffe EBP=00000000 ESI=0000733c EDI=000b80a0
00034788000i[CPU0 ] | IOPL=0 NV UP DI PL NZ AC PE NC
00034788000i[CPU0 ] | SEG selector base limit G D
00034788000i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00034788000i[CPU0 ] | CS:07c0( 0000| 0| 0) 00007c00 0000ffff 0 0
00034788000i[CPU0 ] | DS:0008( 0000| 0| 0) 00000080 0000ffff 0 0
00034788000i[CPU0 ] | SS:0000( 0000| 0| 0) 00000000 0000ffff 0 0
00034788000i[CPU0 ] | ES:07c0( 0000| 0| 0) 00007c00 0000ffff 0 0
00034788000i[CPU0 ] | FS:0008( 0001| 0| 0) 00000000 000fffff 1 1
00034788000i[CPU0 ] | GS:0008( 0001| 0| 0) 00000000 000fffff 1 1
00034788000i[CPU0 ] | EIP=00000058 (00000058)
00034788000i[CPU0 ] | CR0=0x00000010 CR1=0 CR2=0x00000000
00034788000i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00034788000i[ ] restoring default signal behavior
00034788000i[CTRL ] quit_sim called with exit code 1
Müsste also alles glatt laufen.
Allerdings einige Fragen:
1. CS steht ja weiterhin auf 07c0h.
AUf den Speicher über 1 MB kann ich jetzt nur mittels FS und GS zUgreifen.
Wenn ich jetzt aber z.b. irgendwelche Daten mit CS addressiere?
Z.B.: MOV AX; [CS:0B8000H]
Dann tritt wohl ein ganz normaler Fehler auf (Speicherzugriffsfehler o.ä.)?
2. Ich kann also sowohl mit dem ganz normalen Segmentregister Zeugs auf den 1MB Speicher zugreifen, als auch mit dem Selektor auf den Teil über 1MB?
Der User (auch Anwendugsprogrammierer) merkt also praktisch nix davon?
3. Kann ich auch Programme in dem Speicher ausführen?
Weil:
CS steht ja weiterhon auf 07c0h.
Wenn ich nun den Kernel an z.b. 0x20000 lade, wie kann ich diesen anspringen?
4. Angenommen ich will jetzt mit dem INT13H einen Sektor über die 1MB hinaus kopieren.
Mit dem BIOS INT dürfte das ja wohgl nicht gehen?
Ich müsste wohl zuerst den Sektor in das untere MB laden und anschliesend die 512Byte irgendwo über die 1MB hinaus kopieren?
Ich weis, dass all dies eigentlich Fragen sind, die ich durch Ausprobieren selber rausfinden könnte, aber ich bin, wies leider so ist, zu faul :oops:
Ich denke, das kennt ihr auch und hoffe, ihr helft mir trotzdem. :-)
-
1. Ich glaube das CS Register ist im Unrealmod auch auf 16 Bit, also nur mit einem Word als Offset benutzbar.
2. Ka was du damit meinst. Aber die Register FS / GS dürfen nicht verändert werden, da sie ansonsten wieder mit der 1MiB Begränzung arbeiten.
3. Normalerweise geht der Bootloader nach dem Laden selber in den PM und springt dann zum Kernel. Der Kernel muss den PM also nicht mehr selber einschalten. Ich glaube GRUB bietet das auch an.
4. Korrekt!
-
2. Ka was du damit meinst. Aber die Register FS / GS dürfen nicht verändert werden, da sie ansonsten wieder mit der 1MiB Begränzung arbeiten.
Damit mein ich, dass ich z.b. mit folgendem Code auf den speicher zugreifen kann
mov [0a00h:102h], BYTE "a"
als auch mittels FS und GS so auf den Speicher zugreifen kann:
mov [fs:0fffffh], BYTE "a"
Naja, auch egal :mrgreen:
3. Normalerweise geht der Bootloader nach dem Laden selber in den PM und springt dann zum Kernel. Der Kernel muss den PM also nicht mehr selber einschalten. Ich glaube GRUB bietet das auch an.
Ich will ja das BiehlOS komplett im FRM laufen lassen.
Deshalb die Frage, wie ich dann dorthin springen könnte.
-
Soweit ich das jetzt richtig verstanden hab, müsste man dafür CS im Protected Mode auf nen GDT Eintrag setzen, weil ja CS automatisch für den auszuführenden Code als Segment Register genommen wird und man das auch nicht ändern kann. Problem sind halt hier die Bios Interrupts (s. Wikipedia Zitat oben). Die einzige Möglichkeit wäre also nach jeder Aktion bei der CS geändert werden könnte, wieder den Unreal Mode neu zu aktivieren.
Oder man versucht sich was zu schreiben, was Code automatisch in einen ausführbaren Bereich kopiert, wenn dorthin gesprungen wird.