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

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

linux kernel virtualization

前回でとりあえずarch_init_early()は大体読んだので次はinit_early()に戻ってcell_init()から。

cell_init()はhypervisor/control.cにある。

int cell_init(struct cell *cell, struct jailhouse_cell_desc *config,
              bool copy_cpu_set)
{
        unsigned long *config_cpu_set =
                (unsigned long *)(((void *)config) +
                                  sizeof(struct jailhouse_cell_desc));
        unsigned long cpu_set_size = config->cpu_set_size;
        struct jailhouse_memory *config_ram =
                (struct jailhouse_memory *)(((void *)config_cpu_set) +
                                            cpu_set_size);
        struct cpu_set *cpu_set;

ここまでで変数定義+データの初期化でconfigで示されるアドレス範囲から各種データが設定される。

cell名の設定とcellのidの設定。

        memcpy(cell->name, config->name, sizeof(cell->name));
        cell->id = get_free_cell_id();

cellに対してidをget_free_cell_id()で設定。このget_free_cell_id()はそんなにたいしたことはしていないので省略。関数はhypervisor/control.cに。

ここはcpu_setが何者か分からないとだめですね(´ε`;)ウーン…

        if (cpu_set_size > PAGE_SIZE)
                return -EINVAL;
        else if (cpu_set_size > sizeof(cell->small_cpu_set.bitmap)) {
                cpu_set = page_alloc(&mem_pool, 1);
                if (!cpu_set)
                        return -ENOMEM;
                cpu_set->max_cpu_id =
                        ((PAGE_SIZE - sizeof(unsigned long)) * 8) - 1;
        } else {
                cpu_set = &cell->small_cpu_set;
                cpu_set->max_cpu_id =
                        (sizeof(cell->small_cpu_set.bitmap) * 8) - 1;
        }

        cell->cpu_set = cpu_set;

まず最初にcell->small_cpu_set.bitmapに関する部分を見ます。cell構造体はhypervisor/arch/x86/include/asm/cell.hにて定義されています。そしてif文ではcell構造体のメンバ変数のsmall_cpu_set構造体のメンバ変数であるbitmapを見てますね。

struct cell {
        struct {
                /* should be first as it requires page alignment */
                u8 __attribute__((aligned(PAGE_SIZE))) io_bitmap[2*PAGE_SIZE];
                pgd_t *ept;
        } vmx;

        struct {
                pgd_t *page_table;
        } vtd;

        char name[JAILHOUSE_CELL_NAME_MAXLEN+1];
        unsigned int id;

        struct cpu_set *cpu_set;
        struct cpu_set small_cpu_set;

        unsigned long page_offset;

        struct cell *next;
};

という訳でhypervisor/arch/x86/include/asm/types.hを見てみると

struct cpu_set {
        unsigned long max_cpu_id;
        /* Note: The bitmap is supposed to be extended by embedding this
         * struct into a larger buffer. */
        unsigned long bitmap[1];
};

これで何となく分かった気が。このcpu_set構造体で使用しているbitmapはcpu0~cpuNまでを表しているんでしょう、きっと。そしてcell_init()のif文に戻って

else if (cpu_set_size > sizeof(cell->small_cpu_set.bitmap)) {

これはホストのcpu数がsizeof(cell->small_cpu_set.bitmap)個以上(x86_64ならsizeof(unsigned long)は64のはず)で64以上有る場合はbitmapの大きさが足りないので1ページをプールから取得してcpu_set構造体として扱う。64個もcpuが無ければcell->small_cpu_setを使うってことですね。

cell_init()の引数にあるcopy_cpu_setがtrueだったら実施。

        if (copy_cpu_set)
                memcpy(cell->cpu_set->bitmap, config_cpu_set, cpu_set_size);

cellが使用するメモリの開始アドレス設定。

        cell->page_offset = config_ram->phys_start;

        return 0;
}

とりあえずこれにてinit_early()は一通り終了。
これでhypervisor/setup.cのentry()に戻り、cpu_init()に入っていきます。

        if (master_cpu_id == -1) {
                master = true;
                init_early(cpu_data->cpu_id);
        }

        if (!error) {
                cpu_init(cpu_data);

                if (master && !error)
                        init_late();
        }