質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

OS

OS(オペレーティングシステム)は、システムソフトウェアの一種であり、一般的に、ハードウェアを直接的に管理・操作する最も中心的な機能を有するソフトウェアがオペレーティングシステムとして呼ばれます。

x86

x86はIntel 8086 CPU シリーズの命令セットアルキテクチャーです。

アーキテクチャ

アーキテクチャとは、情報システム(ハードウェア、OS、アプリケーション、ネットワーク等)の設計方法、設計思想、設計思想に基づいて構築されたシステム構造をアーキテクチャと呼びます

Q&A

解決済

1回答

2472閲覧

アセンブリ言語 プロテクトモード移行 CS,DS再設定 命令群先読みしてしまう問題について

kazuyakazuya

総合スコア193

アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

OS

OS(オペレーティングシステム)は、システムソフトウェアの一種であり、一般的に、ハードウェアを直接的に管理・操作する最も中心的な機能を有するソフトウェアがオペレーティングシステムとして呼ばれます。

x86

x86はIntel 8086 CPU シリーズの命令セットアルキテクチャーです。

アーキテクチャ

アーキテクチャとは、情報システム(ハードウェア、OS、アプリケーション、ネットワーク等)の設計方法、設計思想、設計思想に基づいて構築されたシステム構造をアーキテクチャと呼びます

0グッド

0クリップ

投稿2020/01/22 08:07

編集2020/01/22 12:57

プロテクトモード移行するには思いつく限り(以下間違えて認識しているところがありましたら教えてください。)

direction

1・セグメントディスクリプタ(とりあえず1個でも作ればアクセスできるはず) 2・IDT (これがないとソフトウエア割り込みを呼び出せない) 3・IR0レジスタのPEビットを1にセットする。 4・レジスタの値をセグメントベースからセレクタへ書き換える。(ここで先読みの問題が出てくる。)

この中の4つ目に関して不明点があるので教えてください。
今回の内容と非常に似た質問 ・・・ほぼ同じ
IR0のビットを1にセットした時点でメモリ空間へのアクセス方法
リアルモードでのセグメント方式のアクセス方法

セグメントベース × 10 + オフセット 

ではなく

セグメントセレクタ(ディスクリプタからベースアドレス参照) + オフセット

このアクセス方法に変化する。
つまり、CR0レジスタのPEビットを1にしたあとも
リアルモードで使っていたCS,DSの値をそのまま使っていると
おそらく対応セグメントディスクリプタが見つからずエラーになる。

なので、・・・
プロテクトモード用にCS,DSを再セットする。

s

1MOV CS, 0xXX 2MOV DS, 0xXX

このようにしてDS,CDともに再セットしたかったところだがCPUは命令を先読するため、
CR0レジスタのPEビットをONにした時点で
CPUはリアルモード値がセットされたCS,DSが使われた命令群をすでに読み込んでしまっていることになる。

ここから本題 どうやってそれを解消するのか

s

1jmp $+2

この命令を使う。
このjmp命令を使うとCPUが先読みしていた命令群をクリアできる。

s

1;/_/_/_/_/_/_/_/ 2;CR0レジスタPEオン 3;/_/_/_/_/_/_/_/ 4mov eax, cr0 5or eax, 0x00000001 6mov cr0, eax 7 8 9;/_/_/_/_/_/_/_/ 10;先読みクリア 11;/_/_/_/_/_/_/_/ 12jmp $+2

!ここから勘違いが発生してる可能性があります!
間違えてたらお願いします。

CR0レジスタのPEビットを1にした時点で
プロテクトモード用のアクセスに切り替わるが
その時点ですでにCPUに先に読み込まれていた命令群は
プロテクトモードではなくリアルモードで動くのですよね?
似た質問
なので

s

1;/_/_/_/_/_/_/_/ 2;CR0レジスタPEオン 3;/_/_/_/_/_/_/_/ 4mov eax, cr0 5or eax, 0x00000001 6mov cr0, eax 7 8 9;/_/_/_/_/_/_/_/ 10;先読みクリア 11;/_/_/_/_/_/_/_/ 12jmp $+2 13nop 14nop 15 16jmp [セレクタ:32bitオフセット] ;← 17

リンク先の質問者さんは明示的に32bitで指定するための専用の命令が必要だといっておりますが
jmp $ + 2
で先読みをクリアしたあとならその命令というのは必要ありませんよね?

仮に、32bitオフセットができないとしても
mov cs,0xXX
でセレクタを指定することはできますよね?(命令が増えるけど)

0から作るOS
こちらでは
・先読みのクリア
・レジスタ再セット
をいっぺんにやっているように見えますが

s

1  MOV EAX, CR0 ; CR0レジスタの値を読み出します 2 OR EAX, 0x00000001 ; PEビットをOR命令でONします 3 MOV CR0, EAX ; そのままCR0に書き込みます 4 JMP CODE_DESC:Pmode_start ; CODE_DESCは0x08が入っています 5

このさいに32bitと認識されるための(?)専用命令を使っていますが
これはさきほどのように
CR0レジスタのPEビットを1にセットしたあとでも
その時点で先読みしていた命令群はリアルモード前提で実行され、16ビットレジスタを使えないから
という解釈であっていますか?

気になったのでお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

過去の質問の回答にもありますが、最後の

JMP CODE_DESC:Pmode_start

FAR JUMP が、

  • CS レジスタのロード(これによりプロテクトモード用のセグメントディスクリプタがロードされる)
  • 命令プリフェッチキューのクリア

を同時に行います。

同じ CS 内でのジャンプが NEAR JUMP、セグメントを異なる場所にするジャンプが FAR JUMP です。つまり FAR JUMP は CS レジスタのロードを伴います。
また、ジャンプすることで命令プリフェッチキューはクリアされる(それまで読んだのとは別の場所から処理が継続されるのですから、プリフェッチは全部捨てねば意味がありません)ので、上手くいくのです。

※32bit プレフィックスは不要です。必要なのは FAR JUMP です

投稿2020/01/24 09:01

tacsheaven

総合スコア13703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazuyakazuya

2020/01/24 13:44 編集

回答ありがとうございます。 FAR JUMPをすると一石二鳥なことに 先読みクリアとレジスタセットを同時に行える。 ですが、ここであえて jmp $ + 2 を使うことによって先読みをクリアし、そのすぐあと mov 0xXX,cs のようにしてセグメントレジスタをセットすることは可能ですか?
tacsheaven

2020/01/24 14:58

変えることはできますけど、CS レジスタをロードした以上、次に動く命令は mov の次とはならないのですよ? そんなトリッキーなことをするくらいなら、far jump した方がよっぽど楽です。
asm

2020/01/24 15:40

インテルのマニュアルに 「CR0書き換えたら即far jump/callしろ、far jump/callせずにメモリ触ってたりするとランダムで失敗する可能性がある。」 的な事が書かれてるわけですし変なことをするのはただのリスクですね
kazuyakazuya

2020/01/25 05:15

すみません。 >次に動く命令は mov の次とはならないのですよ? どういうことですか? >※32bit プレフィックスは不要です。必要なのは FAR JUMP です セグメント間ジャンプを実行して レジスタ設定とクリアを同時に行う際に32bitプレフィックスはいらないって話ですよね? 仮にその命令をする直前にCR0のPEビットをオンにする命令があった場合 リアルモードで動いている時点で セグメント間ジャンプ命令が先読みされるのだから プレフィックスは必要だと思うのですが なぜ必要ないのですか?
tacsheaven

2020/01/26 12:51

>次に動く命令は mov の次とはならないのですよ? jmp $+2 の near jump で命令プリフェッチキューはクリアされましたが、次の mov 0xX, cs をしたことでコードセグメントが変わりますね。ということは、この次に命令フェッチが行われるのは、「新しい CS が示すセグメントディスクリプタ」+IP の場所からになります。これが mov 命令の次であるのは、CS が示す(ロードした)セグメントディスクリプタが、それまでのリアルモード時と同じセグメントを示している場合だけです。 そういう組み方ができないわけではありませんが、面倒ですね。
tacsheaven

2020/01/26 12:58

PE ビットをオンにする=32bit になる、ではありません。これが成り立つのはセグメントディスクリプタ上のDフラグによって、32bit のコードセグメントやデータセグメントを指定している場合だけです。 ※セグメントディスクリプタは 80286 とも互換をとるため、16bit もありなのです
kazuyakazuya

2020/01/26 13:12

ありがとうございます。 >そういう組み方ができないわけではありませんが、面倒ですね。 そこまで考えていませんでした・・・。 csを変えると次の命令アドレスにも影響を与えてしまうのですね。 実際にコードを書くときはfar jmpを使うことにします。
tacsheaven

2020/01/27 05:16

CPU がどのメモリアドレスから命令をフェッチするかを決めるのが CS レジスタと IP レジスタです。 ですから CS レジスタを変更したら、当然ながら次に読み込む命令の場所は変わります。 この仕組みはリアルモードでもプロテクトモードでも変わりません(ただし CS レジスタの使い方は違う)
kazuyakazuya

2020/01/27 07:28

追加で悪いのですが 例えば・・・ /_/_/_/_/_/_/_/_/ jmp $+2 nop nop nop mov 0xXX,cs nop nop /_/_/_/_/_/_/_/_/ のようなコードがあったとして jmp命令で先読みがクリアされますよね。 (たぶん ここから勘違いあります) それで、ジャンプ先のnopの時点で再度フェッチが行われると思います。 で、フェッチで読み込まれるのは命令そのものですよね? なので、フェッチが行われると mov 0xXX,cs nop nop といった命令自体がフェッチされるわけで csの内容が変わったところでフェッチされた命令自体には干渉できないのではないか? と思ったのですがこれは違うのでしょうか? (csレジスタの値が変わると先読みをクリアして再度フェッチするということ?)
tacsheaven

2020/01/27 07:47 編集

確かに mov 命令を実際に実行する段階でプリフェッチキューに入っている分は干渉されませんが、結局その後読み込む場所が違ってきます。 ちなみに CS レジスタの値を、mov もしくは pop で更新した場合はプリフェッチキューがクリア「されない」というのが 8086/8088 の挙動としてあるので、実は mov しちゃダメなのです。 ※CPU が違うとプリフェッチキューの長さが違うので、どこまでキューに入るかが実行環境依存してしまう 確実にプリフェッチがクリアされて新しい場所からはじめることができると分かっている far jump を使いましょう、と Intel が推奨しているのは故あってのことなのですよ。
kazuyakazuya

2020/01/27 08:52

となると その次に動く命令は mov の次とはならない というのは csレジスタの値を変えてからフェッチされる命令という認識であっていますか?
kazuyakazuya

2020/01/28 07:32 編集

すみません なんでもないです理解できました。 mov命令でcsレジスタを変更した後から フェッチした時点の命令は読みこむ場所が変わってきてしまう。 さらにCPUによってフェッチの長さが違うから うまくそこをコントロールするのが難しい。 jmp命令で先読みクリアとcsセットを同時に行えて一石二鳥というより そうする以外に方法がないのですね。 (クリアとレジスタセットを同時に行わなければいけない。)
kazuyakazuya

2020/02/06 09:15

今更なのですが >※32bit プレフィックスは不要です。必要なのは FAR JUMP です プレフィックスを付けずにセグメント間ジャンプを使用したところシステムエラーが発生するので プレフィックスを付けずのセグメント間ジャンプはできませんでした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問