CbCインターフェースによる CbCXv6 の書き換え


概要


OS の信頼性を上げたい


メタレベルとノーマルレベル


Continuation based C


goto による継続


Data Gear の継続


Meta Code Gear


Meta Data Gear


Xv6


Xv6の構成


カーネル空間


system call


Paging


Xv6の書き換え方針


CbCインターフェース


CbCインターフェース


インターフェースの定義

typedef struct vm<Type,Impl> {
    __code init_vmm(Impl* vm, __code next(...));
    __code kpt_freerange(Impl* vm, uint low, uint hi, __code next(...));
    __code kpt_alloc(Impl* vm ,__code next(...));
    __code switchuvm(Impl* vm ,struct proc* p, __code next(...));
    __code init_inituvm(Impl* vm, pde_t* pgdir, char* init, uint sz, __code next(...));
    __code loaduvm(Impl* vm,pde_t* pgdir, char* addr, struct inode* ip, uint offset, uint sz,  __code next(...));
    __code allocuvm(Impl* vm, pde_t* pgdir, uint oldsz, uint newsz, __code next(...));


インターフェースの命名

typedef struct vm<Type,Impl> {

インターフェースの Code Gear

typedef struct vm<Type,Impl> {
    __code init_vmm(Impl* vm, __code next(...));
    __code kpt_freerange(Impl* vm, uint low, uint hi, __code next(...));
    __code kpt_alloc(Impl* vm ,__code next(...));
    __code switchuvm(Impl* vm ,struct proc* p, __code next(...));
    __code init_inituvm(Impl* vm, pde_t* pgdir, char* init, uint sz, __code next(...));
    __code loaduvm(Impl* vm,pde_t* pgdir, char* addr, struct inode* ip, uint offset, uint sz,  __code next(...));
    __code allocuvm(Impl* vm, pde_t* pgdir, uint oldsz, uint newsz, __code next(...));


next(…)

    __code kpt_freerange(Impl* vm, uint low, uint hi, __code next(...));
//....
    __code next(...);
} vm;
__code exit(){
//....
}

goto vm->kpt_freerange(vm, low, hi, exit);

Interface の実装の型

typedef struct vm_impl<Impl, Isa> impl vm{
...
    __code loaduvm_ptesize_check(Type* vm_impl, uint i, pte_t* pte, uint sz,
__code next(...));

インターフェースの実装

#interface "vm.h"

vm_impl のコンストラクタ

vm* createvm_impl(struct Context* cbc_context) {
    struct vm* vm  = new vm();
....
    vm->void_ret  = C_vm_void_ret;
    vm->init_vmm = C_init_vmmvm_impl;
    vm->kpt_freerange = C_kpt_freerangevm_impl;
    vm->kpt_alloc = C_kpt_allocvm_impl;
__code init_vmmvm_impl(struct vm_impl* vm,__code next(...)) {
    initlock(&kpt_mem.lock, "vm");
    kpt_mem.freelist = NULL;

    goto next(...);
}

インターフェース実装内の CbC


実装内の明示的な遷移の処理

__code loaduvmvm_impl(struct vm_impl* vm, pde_t* pgdir, char* addr, struct inode* ip, uint offset, uint sz,  __code next(...)) {
    Gearef(cbc_context, vm_impl)->pgdir = pgdir;
    Gearef(cbc_context, vm_impl)->addr = addr;
    Gearef(cbc_context, vm_impl)->ip = ip;
    Gearef(cbc_context, vm_impl)->offset = offset;
    Gearef(cbc_context, vm_impl)->sz = sz;
    Gearef(cbc_context, vm_impl)->next = next;

    goto loaduvm_ptesize_checkvm_impl(vm, next(...));
}
vm* createvm_impl(struct Context* cbc_context) {
...
    struct vm_impl* vm_impl = new vm_impl();
...
    vm_impl->loaduvm_ptesize_check = C_loaduvm_ptesize_checkvm_impl;
....
    vm->loaduvm = C_loaduvmvm_impl;
....
}

loaduvmの CbCによる書き換え

int loaduvm (pde_t *pgdir, char *addr, struct inode *ip, uint offset, uint sz)
{
    uint i, pa, n;
    pte_t *pte;

    if ((uint) addr % PTE_SZ != 0) {
        panic("loaduvm: addr must be page aligned");
    }

    for (i = 0; i < sz; i += PTE_SZ) {
        if ((pte = walkpgdir(pgdir, addr + i, 0)) == 0) {
            panic("loaduvm: address should exist");
        }

        pa = PTE_ADDR(*pte);

        if (sz - i < PTE_SZ) {
            n = sz - i;
        } else {
            n = PTE_SZ;
        }

        if (readi(ip, p2v(pa), offset + i, n) != n) {
            return -1;
        }
    }

    return 0;
}
__code loaduvmvm_impl(struct vm_impl* vm, pde_t* pgdir, char* addr, struct inode* ip, uint offset, uint sz,  __code next(...)) {
    Gearef(cbc_context, vm_impl)->pgdir = pgdir;
    Gearef(cbc_context, vm_impl)->addr = addr;
    Gearef(cbc_context, vm_impl)->ip = ip;
    Gearef(cbc_context, vm_impl)->offset = offset;
    Gearef(cbc_context, vm_impl)->sz = sz;
    Gearef(cbc_context, vm_impl)->next = next;

    goto loaduvm_ptesize_checkvm_impl(vm, next(...));
}
#interface "vm_impl.h"

__code loaduvm_ptesize_checkvm_impl(struct vm_impl* vm_impl, __code next(...)) {
    char* addr = vm_impl->addr;

    if ((uint) addr %PTE_SZ != 0) {
       // goto panic
    }

    goto loaduvm_loopvm_impl(vm_impl, next(...));
}

__code loaduvm_loopvm_impl(struct vm_impl* vm_impl, __code next(...)) {
    uint i = vm_impl->i;
    uint sz = vm_impl->sz;

    if (i < sz) {
        goto loaduvm_check_pgdir(vm_impl, next(ret, ...));
    }

    goto loaduvm_exit(vm_impl, next(...));
}


__code loaduvm_check_pgdir(struct vm_impl* vm_impl, __code next(...)) {
    pte_t* pte = vm_impl->pte;
    pde_t* pgdir = vm_impl->pgdir;
    uint i = vm_impl->i;
    char* addr = vm_impl->addr;
    uint pa = vm_impl->pa;

    if ((pte = walkpgdir(pgdir, addr + i, 0)) == 0) {
        // goto panic
    }
    pa = PTE_ADDR(*pte);

    vm_impl->pte = pte;
    vm_impl->pgdir = pgdir;
    vm_impl->addr = addr;
    vm_impl->pa = pa;

    goto loaduvm_check_PTE_SZ(vm_impl, next(...));
}

__code loaduvm_check_PTE_SZ(struct vm_impl* vm_impl, __code next(int ret, ...)) {
    if (sz - i < PTE_SZ) {
        n = sz - i;
    } else {
        n = PTE_SZ;
    }

    if (readi(ip, p2v(pa), offset + i, n) != n) {
        ret = -1;
        goto next(ret, ...);
    }

    vm_impl->n = n;

    goto loaduvm_loopvm_impl(vm_impl, next(ret, ...));
}

__code loaduvm_exit(struct vm_impl* vm_impl, __code next(int ret, ...)) {
    ret = 0;
    goto next(ret, ...);
}


int loaduvm (pde_t *pgdir, char *addr, struct inode *ip, uint offset, uint sz)
{
    uint i, pa, n;
    pte_t *pte;

    if ((uint) addr % PTE_SZ != 0) {
        panic("loaduvm: addr must be page aligned");
    }

    for (i = 0; i < sz; i += PTE_SZ) {
        if ((pte = walkpgdir(pgdir, addr + i, 0)) == 0) {
            panic("loaduvm: address should exist");
        }

        pa = PTE_ADDR(*pte);

        if (sz - i < PTE_SZ) {
            n = sz - i;
        } else {
            n = PTE_SZ;
        }

        if (readi(ip, p2v(pa), offset + i, n) != n) {
            return -1;
        }
    }

    return 0;
}

stub


C を CbC に部分的に書き直す手法


CbC から C への遷移

void cbc_init_vmm_dummy(struct Context* cbc_context, struct proc* p, pde_t* pgdir, char* init, uint sz)
{
    // inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size);

    struct vm* vm = createvm_impl(cbc_context);
    // goto vm->init_vmm(vm, pgdir, init, sz , vm->void_ret);
        Gearef(cbc_context, vm)->vm = (union Data*) vm;
        Gearef(cbc_context, vm)->pgdir = pgdir;
        Gearef(cbc_context, vm)->init = init;
        Gearef(cbc_context, vm)->sz = sz ;
        Gearef(cbc_context, vm)->next = C_vm_void_ret ;
    goto meta(cbc_context, vm->init_inituvm);
}

void userinit(void)
{
    struct proc* p;
    extern char _binary_initcode_start[], _binary_initcode_size[];

    p = allocproc();
    initContext(&p->cbc_context);

    initproc = p;

    if((p->pgdir = kpt_alloc()) == NULL) {
        panic("userinit: out of memory?");
    }

    cbc_init_vmm_dummy(&p->cbc_context, p, p->pgdir, _binary_initcode_start, (int)_binary_initcode_size);


まとめ