「φ(・・*)ゞ ウーン jailhouseのコードを読んでみるの3」で残した4つの関数のうち、paging_init()
とpage_map_create()は「φ(・・*)ゞ ウーン jailhouseのコードを読んでみるの4」で確認したので
まずはhypervisor/arch/x86/setup.carch_init_early()を。
この関数自体はそんなに複雑では無いです。
int arch_init_early(struct cell *linux_cell, struct jailhouse_cell_desc *config) { unsigned long entry; unsigned int vector; int err; err = apic_init(); if (err) return err;
apicの初期化を行い、次にIDTの初期化。
entry = (unsigned long)exception_entries; for (vector = 0; vector < NUM_IDT_DESC; vector++) { if (vector == NMI_VECTOR || vector == 15) continue; idt[vector * 4] = (entry & 0xffff) | ((GDT_DESC_CODE * 8) << 16); idt[vector * 4 + 1] = 0x8e00 | (entry & 0xffff0000); idt[vector * 4 + 2] = entry >> 32; entry += 16; } entry = (unsigned long)nmi_entry; idt[NMI_VECTOR * 4] = (entry & 0xffff) | ((GDT_DESC_CODE * 8) << 16); idt[NMI_VECTOR * 4 + 1] = 0x8e00 | (entry & 0xffff0000); idt[NMI_VECTOR * 4 + 2] = entry >> 32;
exception_entriesやnmi_entryはhypervisor/arch/x86/entry.Sで定義。
idtの定義はファイル先頭の方で以下のような感じに。
#define NUM_IDT_DESC 20 static u32 idt[NUM_IDT_DESC * 4];
IDTの設定内容をコードだけで見るとちょっと分かり辛いのでIntel SDM Volume 3: System Programmingで見るとこんな感じの構造にデータを入れてます。サイズは64bitで上の2個が下位32bit、下の6個が上位32bit分。
bit | 内容 |
0-15 | 割り込みを受けるエントリポイントまでのオフセットの下位16bit |
16-31 | セグメントセレクタ |
0-4 | 予約済み |
5-7 | 0をセット |
8-12 | 8~10ビットまでは1、11ビット目のDビットはゲートのサイズが32bitなら1、16bitなら0、12ビット目は0 |
13-14 | DPL 特権レベル |
15 | P セグメントの存在フラグ |
16-31 | 割り込みを受けるエントリポイントまでのオフセットの上位16bit |
hypervisor/arch/x86/vmx.cで定義されてる関数。この関数はMSRにx2APICを使用するための設定をするだけ。
vmx_init();
hypervisor/arch/x86/vmx.cで定義されてる関数。EPTで使うメモリの設定が行われる。
err = vmx_cell_init(linux_cell, config); if (err) return err; return 0; }
apic_init()はこのような関数。
int apic_init(void) { unsigned long apicbase; int err; apicbase = read_msr(MSR_IA32_APICBASE); if (apicbase & APIC_BASE_EXTD) { /* set programmatically to enable address fixup */ apic_ops.read = read_x2apic; apic_ops.read_id = read_x2apic_id; apic_ops.write = write_x2apic; apic_ops.send_ipi = send_x2apic_ipi; using_x2apic = true; } else if (apicbase & APIC_BASE_EN) { xapic_page = page_alloc(&remap_pool, 1); if (!xapic_page) return -ENOMEM; err = page_map_create(hv_page_table, XAPIC_BASE, PAGE_SIZE, (unsigned long)xapic_page, PAGE_DEFAULT_FLAGS | PAGE_FLAG_UNCACHED, PAGE_DEFAULT_FLAGS, PAGE_DIR_LEVELS); if (err) return err; apic_ops.read = read_xapic; apic_ops.read_id = read_xapic_id; apic_ops.write = write_xapic; apic_ops.send_ipi = send_xapic_ipi; } else return -EIO; printk("Using x%sAPIC\n", using_x2apic ? "2" : ""); return 0; }
色々やっているけど主な処理としてはAPIC関連の操作に対する処理を実行する関数を登録するというのが目的ですね。
vmx_cell_init()はページングの設定がメイン。
int vmx_cell_init(struct cell *cell, struct jailhouse_cell_desc *config) { struct jailhouse_memory *mem; u32 page_flags, table_flags; u32 pio_bitmap_size, size; u8 *pio_bitmap; int n, err;
まずはページを1ページ確保。
/* build root cell EPT */ cell->vmx.ept = page_alloc(&mem_pool, 1); if (!cell->vmx.ept) return -ENOMEM;
このcellのメモリに関する設定を読み込む。
mem = (void *)config + sizeof(struct jailhouse_cell_desc) + config->cpu_set_size;
この構造体の内容は以下の通り。定義はhypervisor/include/jailhouse/cell-config.hに。各変数の内容は名前見れば分かりますね。
struct jailhouse_memory {
__u64 phys_start;
__u64 virt_start;
__u64 size;
__u64 access_flags;
};
ループしながらページングの設定。
for (n = 0; n < config->num_memory_regions; n++, mem++) { page_flags = EPT_FLAG_WB_TYPE; if (mem->access_flags & JAILHOUSE_MEM_READ) page_flags |= EPT_FLAG_READ; if (mem->access_flags & JAILHOUSE_MEM_WRITE) page_flags |= EPT_FLAG_WRITE; if (mem->access_flags & JAILHOUSE_MEM_EXECUTE) page_flags |= EPT_FLAG_EXECUTE; table_flags = page_flags & ~EPT_FLAG_WB_TYPE; err = page_map_create(cell->vmx.ept, mem->phys_start, mem->size, mem->virt_start, page_flags, table_flags, PAGE_DIR_LEVELS); if (err) /* FIXME: release vmx.ept */ return err; }
ページの属性にはread・write・execute可として、ページテーブルの属性からはAビット、Dビットをクリア(俺が間違えていなければ)・・・
page_map_create()は「φ(・・*)ゞ ウーン jailhouseのコードを読んでみるの4」で見た通りでx86_64環境なので4段階のページテーブルを作成する。
次にアドレスにapic_access_pageを指定してページテーブルの作成。
page_flags = EPT_FLAG_READ | EPT_FLAG_WRITE | EPT_FLAG_WB_TYPE; table_flags = EPT_FLAG_READ | EPT_FLAG_WRITE; err = page_map_create(cell->vmx.ept, page_map_hvirt2phys(apic_access_page), PAGE_SIZE, XAPIC_BASE, page_flags, table_flags, PAGE_DIR_LEVELS); if (err) /* FIXME: release vmx.ept */ return err;
この辺はやっていることはともかく、どのようなところで使われるのかまだ不明orz
pio_bitmap = (void *)mem + config->num_irq_lines * sizeof(struct jailhouse_irq_line); pio_bitmap_size = config->pio_bitmap_size; memset(cell->vmx.io_bitmap, -1, sizeof(cell->vmx.io_bitmap)); for (n = 0; n < 2; n++) { size = pio_bitmap_size <= PAGE_SIZE ? pio_bitmap_size : PAGE_SIZE; memcpy(cell->vmx.io_bitmap + n * PAGE_SIZE, pio_bitmap, size); pio_bitmap += size; pio_bitmap_size -= size; } return 0; }
- 作者: Daniel P. Bovet,Marco Cesati,高橋浩和,杉田由美子,清水正明,高杉昌督,平松雅巳,安井隆宏
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2007/02/26
- メディア: 大型本
- 購入: 9人 クリック: 269回
- この商品を含むブログ (67件) を見る