読者です 読者をやめる 読者になる 読者になる

φ(・・*)ゞ ウーン jailhouseのコードを読んでみるの3

kernel linux virtualization

φ(・・*)ゞ ウーン jailhouseのコードを読んでみるの2」の続きでinit_early()を。
init_early()の呼び出し元はhypervisor/setup.cのentry()。

最初に行われるのはGlobal Offset Tableの初期化。

static void init_early(unsigned int cpu_id)
{
        unsigned long size;

        master_cpu_id = cpu_id;

        /* must be first, printk/arch_dbg_write uses the GOT */
        got_init();

gotの初期化はhypervisor/arch/x86/entry.Sにてアセンブラで書かれています。

/* Fix up Global Offset Table with absolute hypervisor address */
        .globl got_init
got_init:
        lea __got_start(%rip),%rdx
        lea __got_end(%rip),%rcx
        lea hypervisor_header(%rip),%rax

got_loop:
        cmp %rdx,%rcx
        je got_done

        add %rax,(%rdx)
        add $8,%rdx
        jmp got_loop

got_done:
        ret

処理の内容自体は単純ですね。

dbgはdebugの略かなと何となく予想ができるところ。

        arch_dbg_write_init();

x86の場合はhypervisor/arch/x86/dbg-write.cに関数があります。ここで使われているUART_XXXXというマクロ名、outb()であーやっぱりなと思ってみたりする訳です。

void arch_dbg_write_init(void)
{
        outb(UART_LCR_DLAB, UART_BASE + UART_LCR);
#ifdef CONFIG_UART_OXPCIE952
        outb(0x22, UART_BASE + UART_DLL);
#else
        outb(1, UART_BASE + UART_DLL);
#endif
        outb(0, UART_BASE + UART_DLM);
        outb(UART_LCR_8N1, UART_BASE + UART_LCR);
}

( ´∀`)bグッ!

        printk("\nInitializing Jailhouse hypervisor on CPU %d\n", cpu_id);
        printk("Code location: %p\n",
               __start + sizeof(struct jailhouse_header));

ここは名前の通りだろうから後で読む。paging_init()はhypervisor/paging.cに。

        error = paging_init();
        if (error)
                return;

ページを確保してハイパーバイザ用にページテーブルを作成。細かいところは後で読む。page_map_create()はhypervisor/paging.cに。

        if (system_config->config_memory.size > 0) {
                size = PAGE_ALIGN(system_config->config_memory.size);

                config_memory = page_alloc(&remap_pool, size / PAGE_SIZE);
                if (!config_memory) {
                        error = -ENOMEM;
                        return;
                }

                error = page_map_create(hv_page_table,
                                system_config->config_memory.phys_start,
                                size, (unsigned long)config_memory,
                                PAGE_READONLY_FLAGS, PAGE_DEFAULT_FLAGS,
                                PAGE_DIR_LEVELS);
                if (error)
                        return;
        }

メモリアドレスの範囲とかアクセス属性などのチェック(hypervisor/control.c

        error = check_mem_regions(&system_config->system);
        if (error)
                return;

アーキテクチャ固有の初期化。これも後で読む。 hypervisor/arch/x86/setup.cで実施。

        error = arch_init_early(&linux_cell, &system_config->system);
        if (error)
                return;

cellの初期化。後で読む。hypervisor/control.c

        error = cell_init(&linux_cell, &system_config->system, false);
        if (error)
                return;

        cell_list = &linux_cell;

初期化の第一段階が終了!

        page_map_dump_stats("after early setup");
        printk("Initializing first processor:\n");
}

ここまでで「後で読む」としたのは以下の4個。

init_early()が行っている内容は

  • GOTを設定してprintk、UARTでデバッグ用の表示が行えるようにする
  • ハイパーバイザ用のページング設定
  • アーキテクチャ固有の初期化(x86APICと割り込みの設定をしている模様)
  • cellの初期化