Ads by Google
新しい記事を書く事で広告が消せます。
私は知識に何ものかを付け加え,また他の人々がより多くのものを付け加える手助けをした --- G.H.ハーディ
ja.wikipedia リアルモード
Intel 80386では、プロテクトモードに移行した後、セグメントリミットを設定した後にリアルモードに復帰すると、命令にプレフィックスをつけることでそのセグメントリミットまでの実メモリ空間にアクセスすることが可能になるバグと思われるものもあり、この状態を Unreal mode と呼ぶことがある。この仕様は以降のすべてのCPUで有効となっている。
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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+)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 現在はリアルモード
BITS 16
push ds ; データセグメントレジスタとエクストラセグメントレジスタ
push es ; を退避
xor eax,eax ; eax を 0 に
mov ax,ds ; ax にデータセグメント基底を代入
shl eax,4 ; 基底 (eax) を 16 倍する (セグメント先頭のリニアアドレス算出)
add eax,gdt ; GDT のオフセットアドレスを eax に加算
mov [gdt_ptr + 2],eax ; GDT のリミット値を計算
cli ; 割り込み停止
lgdt [gdt_ptr] ; GDT レジスタをセット
; プロテクトモードへ以降 (GR0 の PE ビットを 1 にするだけ)
mov eax,cr0 ; Control Register 0 の値を eax に代入
or al,1 ; PE ビットを立てる
mov cr0,eax ; CR0 の PE ビットを立てる
mov bx,DATA_SEL ; 4 G リミットのセグメントセレクタ (GDT[1]) を
mov ds,bx ; DS と ES に代入
mov es,bx ; ES はセグメントキャッシュ (らしい)
; リアルモードへ以降
dec al ; PE ビットを落とす
mov cr0,eax ; (un)real モードへ以降
pop es ; セグメントレジスタを復旧
pop ds
; unreal モードに突入
; ここからは 32 bit (4 G) のアドレス空間をフルに使用できる
; Global segment Descriptor Table (8 バイトの構造体の配列)
gdt:
; GDT[0] は使われない (NULL Descriptor)
dw 0
dw 0
db 0
db 0
db 0
db 0
; GDT[1]
; リアルモードのディスクリプタテーブルとの互換性を保つため
; 複雑な構造になっている
DATA_SEL equ $-gdt
dw 0FFFFh ; リミット値の下位 16 bit
dw 0 ; セグメントベースの下位 3 バイト
db 0 ; 0 〜 4 G までアクセスできる巨大セグメントとなる
db 92h ; セグメント属性の下位 1 バイト
; ちなみに…
; 0x00 : 未使用
; 0x92 : システム専用の読み書き可能なセグメント (実行は不可)
; 0x9a : システム専用の実行・読み込み可能セグメント (書き込み不可)
; 0xf2 : アプリケーション用,読み書き可能 (実行不可)
; 0xfa : アプリケーション用,読み込み・実行可能 (書き込み不可)
db 0CFh ; 上位 4 bit (= 0xC) が属性の上位 4 bit (計 12 bit)
; G ビット (粒度が 4096 倍) と D ビット (32 ビットセグメント)
; つまり第 4 と第 3 ビットが立つので,0b1100 = 0xC となる
; 下位 4 bit (= 0xF) がリミット値の上位 4bit (計 20 bit)
; つまり 0xFFFFF (1 M) がリミット値になる
; そして,G ビットを立てることにより,1 M * 4096 = 4 G がリミットになる
db 0 ; セグメントベースの上位 1 バイト (計 4 バイト)
gdt_end:
; GDT レジスタに代入する値
; GDT のリミット値 (16 bit) + GDT の先頭アドレス (32 bit)
gdt_ptr:
dw gdt_end - gdt - 1 ; ディスクリプタテーブルのバイト数 - 1
dd 0 ; GDT の先頭アドレス (上のコードでセットされる)
コメント