1. 一言でまとめる メモリ仮想化は、仮想マシン内のプロセスが物理マシン上のメモリにアクセスする方法の問題を解決します。 GuestOS 自体には、GVA で表される仮想アドレス空間があります。仮想マシンは、GPA で表されるメモリ空間全体を排他的に使用しているとみなします。 HostOS 自体には、HVA で表される仮想マシン アドレス空間があります。ホスト マシン自体には、HPA で表される物理メモリ空間があります。 つまり、メモリ仮想化の問題は、GVA -> HPA マッピングの問題になります。
GVA->GPA は、GuestOS ページ テーブルを介してマップされます。 HVA->HPA は HostOS ページ テーブルを介してマップされます。したがって、GPA->HVA のマッピング関係が確立されていれば、メモリ仮想化の問題を解決できます。ただし、3 つのセグメントを 1 つずつマッピングするのは非効率的です。 ソフトウェアでシミュレートされたシャドウ ページ テーブルとハードウェア支援の EPT ページ テーブルを導入します。 シャドウ ページ テーブル: GuestOS が GVA->GPA ページ テーブルを作成すると、kvm は GVA に対応する HPA を認識し、マッピング関係 GVA->HPA を秘密に記録します。後で GVA から GPA へのマッピングが必要になった場合は、シャドウ ページ テーブルに基づいて HPA を見つけることができます。 EPT ページ テーブル: EPTP レジスタはハードウェア レベルで導入されます。ゲストの CR3 をホストの MMU に直接ロードします。同時に、EPT ページ テーブルが専用の EPT ページ テーブル ポインタ レジスタ EPTP にロードされます。つまり、GVA->GPA->HPA の両方のアドレス変換はハードウェアによって実装されます。 2. 概要 80386 で保護モードが導入された後、メモリ空間が仮想アドレス空間と物理アドレス空間に分割されたことがわかっています。次に、仮想マシン アドレスを MMU に送信するためにページ テーブル メカニズムが導入されます。 MMU が TLB の検索に失敗した場合、ページ テーブルを順番に検索することで、対応する物理アドレスを見つけることができます。 仮想化シナリオでは状況は少し複雑になり、次のカテゴリに分類できます。 ①ゲストOS仮想アドレス(GVA) 簡単に言えば、ゲストOS のプロセスによって使用される仮想アドレスは GVA であり、これは論理メモリにアクセスするプログラムのアドレスです。 ②ゲストOS物理アドレス(GPA) GuestOS が考慮する物理アドレスも、仮想マシンの mmu がページ テーブルを検索して取得したアドレスですが、本質的には論理アドレスであり、仮想化の導入後に生成された論理概念です。メモリにアクセスするには、メモリ仮想化を使用してホストマシンの物理アドレスにマッピングする必要があります。 ③ホスト仮想アドレス(HVA) ホスト マシン内の仮想アドレス、ホスト プロセスによって使用される仮想アドレス空間。 ④ホスト物理アドレス(HPA) ホスト マシンの実際のメモリ アドレス、つまり実際にアクセス可能な物理メモリ空間。 これまでのところ、仮想マシンのシナリオでは、GVA->HPA に移行する方法がメモリ仮想化の作業です。このうち、Qemu は仮想マシンのメモリ サイズの管理と、メモリに対応する HVA アドレスの記録を担当します (Qemu はユーザー モード プロセスであり、HPA を管理できないため)。 HPAに変換するには、KVMカーネル、つまりシャドウページテーブルSPT(シャドウページテーブル)とEPT(エクステントページテーブル)を使用する必要があります。 2.1 シャドウページテーブル GuestOS がページ テーブルを作成すると、KVM はホスト マシンの物理アドレスを指すページ テーブルのセットを秘密裏に作成します。ゲスト内の各ページ テーブル エントリには、そのシャドウと同様に、対応するシャドウ ページ テーブル エントリがあります。 クライアントがメモリにアクセスすると、ホスト マシンの MMU に実際にロードされるのは、クライアントの現在のページ テーブルに対応するシャドウ ページ テーブルです。このようにして、シャドウ ページ テーブルを通じて実際のメモリ アクセスを実現できます。仮想マシン ページ テーブルとシャドウ ページ テーブルは、ハッシュ テーブルを通じて関連付けられます。このようにして、ページ ディレクトリ/ページ テーブルのクライアントの物理アドレスを通じて、ハッシュ リスト内で対応するシャドウ ページ ディレクトリ/ページ テーブルをすばやく見つけることができます。クライアントがプロセスを切り替えると、クライアントのオペレーティング システムは、切り替えるプロセスのページ テーブル ベース アドレスを CR3 にロードし、KVM はこの特権命令をインターセプトして新しい処理を実行します。つまり、このページ テーブル ベース アドレスに対応するシャドウ ページ テーブル ベース アドレスをハッシュ テーブルで見つけ、それをクライアントの CR3 にロードします。これにより、クライアントが操作を再開すると、CR3 は実際に新しく切り替えられたプロセスに対応するシャドウ ページ テーブルを指します。 2.2 EP EPT テクノロジーは、クライアント仮想アドレスをクライアント物理アドレスにマッピングする元のクライアント ページ テーブルに基づいて EPT ページ テーブルを導入し、クライアント物理アドレスからホスト物理アドレスへの別のマッピングを実現します。両方のアドレス マッピングはハードウェアによって自動的に完了します。クライアントが実行中の場合、クライアント ページ テーブルは CR3 にロードされ、EPT ページ テーブルは専用の EPT ページ テーブル ポインター レジスタ EPTP にロードされます。 クライアントの物理アドレスをホストの物理アドレスに変換するプロセス中に、ページの欠落、書き込み権限の不足などによりクライアントが終了し、EPT 例外が発生する可能性があります。 EPT ページ フォールト例外の場合、KVM はまず例外の原因となったクライアントの物理アドレスを対応するホストの仮想アドレスにマッピングし、次にこの仮想アドレスに新しい物理ページを割り当て、最後に EPT ページ テーブルを更新して例外の原因となったクライアントの物理アドレスとホストの物理アドレス間のマッピングを確立します。 EPT 書き込み権限によって発生した例外については、KVM は対応する EPT ページ テーブルを更新することで解決します。 このことから、EPT ページ テーブルの実装は、前述のシャドウ ページ テーブルと比較して大幅に簡素化されていることがわかります。さらに、クライアント内部でページ フォールト例外が発生してもクライアントが終了しないため、クライアント操作のパフォーマンスが向上します。さらに、KVM はクライアントごとに 1 セットの EPT ページ テーブルを維持するだけで済むため、追加のメモリ オーバーヘッドが大幅に削減されます。 3. Qemu から KVM へのメモリ管理 3.1 フックの設定 main(vl.c)==>configure_accelerator==>kvm_init(kvm_all.c)==>memory_listener_register(&kvm_memory_listener,NULL);kvm_memory_listener を memory_listeners リストに追加し、address_spaces をリスナーに関連付けます 3.2 メモリオブジェクトの初期化 main(vl.c)==>cpu_exec_init_all(exec.c)==>memory_map_init(exec.c) Qemu では、システム メモリは system_memory によって管理され、io メモリは system_io によって管理されます。 static MemoryRegion *system_memory.MemoryRegion にはサブ領域を含めることができます。 memory_lister は、メモリ領域の追加と削除の管理を担当します。 3.3 メモリのインスタンス化 pc_init1 (hw\pc_piix.c) ==> pc_memory_init ここでは主にメモリ領域全体を割り当てます。memory_region_init_ram メソッドに注目してください。memory_region_init_ram ==> qemu_ram_alloc (メモリの HVA レコードを取得します) ==> qemu_ram_alloc_internal ==> ram_block_add (RAMBlock を生成して ram_list に追加します。hva はホスト フィールドに配置されます) ==> phys_mem_alloc ==> qemu_anon_ram_alloc ==> mmap 3.4 VM終了処理 mmio による終了のため、関連する処理は次のようになります kvm_cpu_exec==> case KVM_EXIT_MMIO==> cpu_physical_memory_rw==> address_space_rw==> io_mem_write 3.5 qemu から kvm へのメモリ呼び出しインターフェース 前述したように、メモリを設定するときに呼び出されるリスナーを登録しました。 静的メモリリスナー kvm_memory_listener = { .region_add = kvm_region_add、 リージョンの追加==>kvm_region_add==>kvm_set_phys_mem ① 物理開始アドレスと長さ、kvm_stateで確立されたKVMSlot *mem領域を検索 ②スロットが見つからない場合は作成する ==>kvm_set_user_memory_region (メモリ領域を確立するためにカーネル状態を通知する) ==>kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem) 3.6 KVM メモリ処理 kvm_vm_ioctl==>kvm_vm_ioctl_set_memory_region==>kvm_set_memory_region==>__kvm_set_memory_region カーネル状態もスロットを維持します。カーネル状態スロットの管理戦略は、ユーザー空間スロットの slot_id =id_to_memslot(kvm->memslots, mem->slot); に 1 つずつ対応させることです。 ① ユーザー状態のスロットを介してカーネル状態の対応する構造を取得する ②スロット内の値と設定する値から操作するカテゴリーを決定する ③2のアクションを実行する a.KVM_MR_CREATE: kvm_arch_create_memslot (3 レベルのページ テーブルを作成します) b.KVM_MR_DELETE または KVM_MR_MOVE: スロットを申請し、kvm->memslots をここに一時的に保存します。まず、id_to_memslot を使用して、挿入する kvm スロットに対応するスロットを取得します。削除または移動する場合は、まず KVM_MEMSLOT_INVALID としてマークします。次に install_new_memslots が実行されます。これは実際に slots->generation の値を更新します。 4. EPT関連 4.1 EPTの初期化 kvm_arch_init==> kvm_mmu_module_init ① pte_list_desc_cacheキャッシュ構造を確立する ② kvm_mmu_pageに使用されるmmu_page_header_cacheキャッシュ構造を確立する ③register_shrinker(&mmu_shrinker);システムメモリリカバリが呼び出されたときにフックする vcpu_create==>vmx_create_vcpu==>init_rmode_identity_map==>alloc_identity_pagetable==>__x86_set_memory_region 4.2 EPTの読み込み vcpu_enter_guest(struct kvm_vcpu *vcpu)==> kvm_mmu_reload (ゲストの MMU 初期化、メモリ仮想化の準備)==> kvm_mmu_load==>mmu_topup_memory_caches==>mmu_alloc_roots-->mmu_alloc_direct_roots (現在の vcpu ページング モードに従って ept トップレベル ページ テーブルの管理構造を確立)==>kvm_mmu_sync_roots 4.3 gfn_to_page この関数は、GPA のページ番号を HPA のページ構造に処理します。
4.4 ページテーブルの割り当て
4.5 EPT VMエントリ ①KVM_REQ_MMU_RELOAD-->kvm_mmu_unload-->mmu_free_roots ②KVM_REQ_MMU_SYNC-->kvm_mmu_sync_roots-->mmu_sync_roots-->mmu_sync_children-->kvm_sync_page-->__kvm_sync_page ③KVM_REQ_TLB_FLUSH-->kvm_vcpu_flush_tlb-->tlb_flush-->vmx_flush_tlb-->__vmx_flush_tlb-->ept_sync_context-->__invept 非ルート モードに入り、さまざまなイベントに応じてメモリ上で関連する処理を実行します。 4.6 EPT VM終了 ①cr3をセットする mmu_alloc_direct_roots で arch.mmu.root_hpavcpu_enter_guest が割り当てられると、ルート ページ テーブルとして使用するためのメモリを申請するために kvm_mmu_load==> vcpu->arch.mmu.set_cr3(vcpu,vcpu->arch.mmu.root_hpa) が呼び出されます。同時に、root_hpa はルート ページ テーブルの物理アドレスを指します。すると、vcpu の cr3 レジスタのアドレスがこのルート ページ テーブルの物理アドレスを指していることがわかります。 ②違反を処理する
__direct_map 関数は、渡された gpa に基づいて、レベル 4 のページ テーブル ページから計算し、対応するページ テーブル エントリを 1 レベルずつ入力します。これらはすべて、マクロ定義 for_each_shadow_entry(vcpu, (u64)gfn << PAGE_SHIFT, iterator) で実装されています。 2つのケースは以下のとおりです。 a.現在のページ テーブル ページのレベル (iterator.level) がページ テーブル ページの最後のレベル (level) である場合は、mmu_set_spte (後で詳しく説明します) を呼び出してページ テーブル エントリを直接設定します。 b.現在のページテーブルページAが最後のレベルではなく、中間のレベル(レベル4、レベル3、レベル2)である場合 ページ テーブル エントリが以前に初期化されていない場合 (!is_shadow_present_pte(*iterator.sptep))、kvm_mmu_get_page を呼び出して新しいページ テーブル ページ B を取得または作成し、link_shadow_page を介してページ テーブル ページ A に対応するページ テーブル エントリにリンクする必要があります。 4.7 EPTトラバーサル操作 for_each_shadow_entry は mmu.c で定義されたマクロであり、ページ テーブルのレベルを継続的に移動するために使用されます。 4.8 シャドウページテーブル init_kvm_mmu==>init_kvm_softmmu 上記の ept プロセスでは、パラメータに応じて異なる分岐が発生しますが、言うまでもなく、一般的なロジックは同じです。 |
<<: Docker コンテナと仮想マシンの違いは何ですか?
編集者注: 統計によると、すべてのアプリケーションのうち、ダウンロード数が 100 万回を超えるアプ...
dedipath の VPS の最大の利点は、1Gbps の帯域幅、無制限のトラフィック、20Gbp...
主要なアプリケーションやサービスをクラウド プラットフォームでホストする企業が増えるにつれて、Inf...
Sina Wirelessの収益は前年比で減少NetEase Technology Newsは12月...
クラウド コンピューティングを導入すると、課金、管理、コンプライアンスの問題が発生する可能性があり、...
インタールード: この記事はこの観光客のメッセージのために書かれました (luoli はあなたがそれ...
現在、中国のほとんどのウェブサイトはBaiduで自然ランキングされています。最近の不安定さにより、ウ...
[現在、中国では30以上の地方政府がクラウドコンピューティング産業計画を発表し、土地、税制、資金面で...
ウェブマスターとして、誰もが新しいウェブサイトにできるだけ早くトラフィックを集め、できるだけ早くラン...
これまで新製品の発売には控えめだったByteDanceは、最近、Toutiao Searchの独立ア...
月収10万元の起業の夢を実現するミニプログラム起業支援プラン著者丨ルーティン編集部出典: Opera...
多くのウェブマスターは、毎日百度のアルゴリズムを研究しています。実は、検索エンジンはユーザーに役立つ...
クラウド コンピューティングの構築の出発点は、クラウド コンピューティング インフラストラクチャの構...
格安サーバーについてお話ししましょう。2010 年のクラウド サーバー市場は、ハイエンド クラウド ...
クリーブランド クリニックの CIO である Matthew Kull 氏は、医療とマーケティングと...