Mercurial > hg > Papers > 2020 > tobaru-master
view paper/cbc_interface.tex @ 11:f7ed2b4874f4
xv6 reference
author | tobaru |
---|---|
date | Tue, 04 Feb 2020 11:16:19 +0900 |
parents | a882e390f9a2 |
children | 9cf9e0b086c7 |
line wrap: on
line source
\chapter{CbC インターフェース} 構造図書く(今のcbcxv6と同じか確認してから) \par Gears OS では Meta Code Gear で Context から値を取り出し、ノーマルレベルの Code Gear に値を渡す。 しかし、Code Gaer がどの Data Gear の番号に対応するかを指定する必要があったり、 % ぱるすさんコード必要? ノーマルレベルとメタレベルで見え方が異なる Data Gear を Meta Code Gear によって 調整する必要があったりと、 % みつきさん メタレベルからノーマルレベルの継続の記述が煩雑になるため、Interface 化をしている。 Interface は Data Gear に対しての操作を行う Code Gear であり、実装は別で定義する。 % Interface で定義した Code Gear に % Xv6 の書き換えは Interface を用いてモジュール化する。 そうすることで Gears OS の機能を置き換えることできるようになる。 \section{インターフェースの定義} インターフェースはある Data Gear の定義と、 それに対する操作を行う Code Gear の集合を表現する Meta Data Gear である。 Context では全ての Code Gaer と Data Gear の集合を表現していることに対し、 インターフェースは一部の Code Gear と一部の Data Gear の集合を表現する。 \par インターフェースを記述することによってノーマルレベルとメタレベルの分離が可能となる。 Paging のインターフェースを記述したコードを \ref{interface} に示す。 \begin{lstlisting}[frame=lrbt,label=interface,caption={\footnotesize vm のインターフェース}] typedef struct vm<Type,Impl> { union Data* vm; uint low; uint hi; struct proc* p; pde_t* pgdir; char* init; uint sz; char* addr; struct inode* ip; uint offset; uint oldsz; uint newsz; char* uva; uint va; void* pp; uint len; uint phy_low; uint phy_hi; __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(...)); __code clearpteu(Impl* vm, pde_t* pgdir, char* uva, __code next(...)); __code copyuvm(Impl* vm, pde_t* pgdir, uint sz, __code next(...)); __code uva2ka(Impl* vm, pde_t* pgdir, char* uva, __code next(...)); __code copyout(Impl* vm, pde_t* pgdir, uint va, void* pp, uint len, __code next(...)); __code paging_int(Impl* vm, uint phy_low, uint phy_hi, __code next(...)); __code void_ret(Impl* vm); __code next(...); } vm; \end{lstlisting} \par 2行目から19行目で引数の Data Gear 郡を定義している。 初期化された Data Gear が Code Gear の引数として扱われる。 例として、2行目で定義された vm が21行目から32行目までの引数と対応している。 \par % インターフェースの Code Gear の goto による継続先は基本的に不定となっており、継続元から渡される。 \_\_code next(...) の引数 ... は複数の Input Data Gear を持つという意味である。 後述する実装によって条件分岐によって複数の継続先が設定されることがある。 \par Code Gaer は 20行目から33行目のように "\_\_code [Code Gear名]([引数])"で定義する。 この引数が input Data Gear になる。 % 実装側に書く % 引数の Data Gear はその Code Gear の Input Data Gear になり、引数の Code Gear の中の引 数が Output Data Gear になる。Code Gear の第一引数には Interface を実装した Data Gear を渡す。これは、Code Gear の操作の対象となる Data Gear を設定し ており、後述する継続構文では引数として記述を行わない。 \section{インターフェースの実装} インターフェースは Data Gear に対しての Code Gear とその Code Gear で扱われている Data Gear の集合を抽象化した Meta Data Gear で、vm.c に対応する実装は別で定義する。 \par \begin{lstlisting}[frame=lrbt,label=impl_vm,caption={\footnotesize vm インターフェースの実装}] #include "../../context.h" #interface "vm.h" vm* createvm_impl(struct Context* cbc_context) { struct vm* vm = new vm(); struct vm_impl* vm_impl = new vm_impl(); vm->vm = (union Data*)vm_impl; vm_impl->vm_impl = NULL; vm_impl->i = 0; vm_impl->pte = NULL; vm_impl->sz = 0; vm_impl->loaduvm_ptesize_check = C_loaduvm_ptesize_checkvm_impl; vm_impl->loaduvm_loop = C_loaduvm_loopvm_impl; vm_impl->allocuvm_check_newsz = C_allocuvm_check_newszvm_impl; vm_impl->allocuvm_loop = C_allocuvm_loopvm_impl; vm_impl->copyuvm_check_null = C_copyuvm_check_nullvm_impl; vm_impl->copyuvm_loop = C_copyuvm_loopvm_impl; vm_impl->uva2ka_check_pe_types = C_uva2ka_check_pe_types; vm_impl->paging_intvm_impl = C_paging_intvmvm_impl; vm_impl->copyout_loopvm_impl = C_copyout_loopvm_impl; vm_impl->switchuvm_check_pgdirvm_impl = C_switchuvm_check_pgdirvm_impl; vm_impl->init_inituvm_check_sz = C_init_inituvm_check_sz; 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; vm->switchuvm = C_switchuvmvm_impl; vm->init_inituvm = C_init_inituvmvm_impl; vm->loaduvm = C_loaduvmvm_impl; vm->allocuvm = C_allocuvmvm_impl; vm->clearpteu = C_clearpteuvm_impl; vm->copyuvm = C_copyuvmvm_impl; vm->uva2ka = C_uva2kavm_impl; vm->copyout = C_copyoutvm_impl; vm->paging_int = C_paging_intvm_impl; return vm; } extern struct { struct spinlock lock; struct run *freelist; } kpt_mem; __code init_vmmvm_impl(struct vm_impl* vm,__code next(...)) { initlock(&kpt_mem.lock, "vm"); kpt_mem.freelist = NULL; goto next(...); } extern struct run { struct run *next; }; static void _kpt_free (char *v) { struct run *r; r = (struct run*) v; r->next = kpt_mem.freelist; kpt_mem.freelist = r; } __code kpt_freerangevm_impl(struct vm_impl* vm, uint low, uint hi, __code next(...)) { if (low < hi) { _kpt_free((char*)low); goto kpt_freerangevm_impl(vm, low + PT_SZ, hi, next(...)); } goto next(...); } __code kpt_allocvm_impl(struct vm_impl* vm, __code next(...)) { acquire(&kpt_mem.lock); goto kpt_alloc_check_impl(vm_impl, next(...)); } typedef struct proc proc; __code switchuvmvm_impl(struct vm_impl* vm , struct proc* p, __code next(...)) { //:skip goto switchuvm_check_pgdirvm_impl(...); } __code init_inituvmvm_impl(struct vm_impl* vm, pde_t* pgdir, char* init, uint sz, __code next(...)) { Gearef(cbc_context, vm_impl)->pgdir = pgdir; Gearef(cbc_context, vm_impl)->init = init; Gearef(cbc_context, vm_impl)->sz = sz; Gearef(cbc_context, vm_impl)->next = next; goto init_inituvm_check_sz(vm, pgdir, init, sz, next(...)); } __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(...)); } __code allocuvmvm_impl(struct vm_impl* vm, pde_t* pgdir, uint oldsz, uint newsz, __code next(...)) { goto allocuvm_check_newszvm_impl(vm, pgdir, oldsz, newsz, next(...)); } __code clearpteuvm_impl(struct vm_impl* vm, pde_t* pgdir, char* uva, __code next(...)) { goto clearpteu_check_ptevm_impl(vm, pgdir, uva, next(...)); } __code copyuvmvm_impl(struct vm_impl* vm, pde_t* pgdir, uint sz, __code next(...)) { goto copyuvm_check_nullvm_impl(vm, pgdir, sz, __code next(...)); } __code uva2kavm_impl(struct vm_impl* vm, pde_t* pgdir, char* uva, __code next(...)) { goto uva2ka_check_pe_types(vm, pgdir, uva, next(...)); } __code copyoutvm_impl(struct vm_impl* vm, pde_t* pgdir, uint va, void* pp, uint len, __code next(...)) { vm->buf = (char*) pp; goto copyout_loopvm_impl(vm, pgdir, va, pp, len, va0, pa0, next(...)); } __code paging_intvm_impl(struct vm_impl* vm, uint phy_low, uint phy_hi, __code next(...)) { goto paging_intvmvm_impl(vm, phy_low, phy_hi, next(...)); } __code vm_void_ret(struct vm_impl* vm) { return; } \end{lstlisting} \section{インターフェース内の private メソッド} インターフェースで定義した Code Gear 以外の Code Gaer も記述することができる。 この Code Gear は基本的にインターフェースで指定された Code Gear 内からのみ継続されるため、 Java の private メソッドのように扱われる。 \par インターフェースと同じようにヘッダーファイルを \ref{impl_vm_privateh} で定義する。 \begin{lstlisting}[frame=lrbt,label=impl_vm_privateh,caption={\footnotesize vm private のヘッダーファイル}] typedef struct vm_impl<Impl, Isa> impl vm{ union Data* vm_impl; uint i; pte_t* pte; uint sz; pde_t* pgdir; char* addr; struct inode* ip; uint offset; uint pa; uint n; uint oldsz; uint newsz; uint a; int ret; char* mem; char* uva; pde_t* d; uint ap; uint phy_low; uint phy_hi; uint va; void* pp; uint len; char* buf; char* pa0; uint va0; proc_struct* p; char* init; __code kpt_alloc_check_impl(Type* vm_impl, __code next(...)); __code loaduvm_ptesize_check(Type* vm_impl, __code next(int ret, ...)); __code loaduvm_loop(Type* vm_impl, uint i, pte_t* pte, uint sz, __code next(int ret, ...)); __code allocuvm_check_newsz(Type* vm_impl, pde_t* pgdir, uint oldsz, uint newsz, __code next(...)); __code allocuvm_loop(Type* vm_impl, pde_t* pgdir, uint oldsz, uint newsz, uint a, __code next(...)); __code copyuvm_check_null(Type* vm_impl, pde_t* pgdir, uint sz, __code next(...)); __code copyuvm_loop(Type* vm_impl,pde_t* pgdir, uint sz, pde_t* d, pte_t* pte, uint pa, uint i, uint ap, char* mem, __code next(int ret, ...)); __code clearpteu_check_ptevm_impl(Type* vm_impl, pde_t* pgdir, char* uva, __code next(...)); __code uva2ka_check_pe_types(Type* vm_impl, pde_t* pgdir, char* uva, __code next(...)); __code paging_intvm_impl(Type* vm_impl, uint phy_low, uint phy_hi, __code next(...)); __code copyout_loopvm_impl(Type* vm_impl, pde_t* pgdir, uint va, void* pp, uint len, __code next(...)); __code switchuvm_check_pgdirvm_impl(struct vm_impl* vm_impl, struct proc* p, __code next(...)); __code init_inituvm_check_sz(struct vm_impl* vm_impl, pde_t* pgdir, char* init, uint sz, __code next(...)); __code void_ret(Type* vm_impl); __code next(...); } vm_impl; \end{lstlisting} インターフェースを vm で インターフェースの実装を \ref{impl_vm_private} で示す。 \par \begin{lstlisting}[frame=lrbt,label=impl_vm_private,caption={\footnotesize vm private の実装}] #include "../../context.h" #interface "vm.h" vm* createvm_impl(struct Context* cbc_context) { struct vm* vm = new vm(); struct vm_impl* vm_impl = new vm_impl(); vm->vm = (union Data*)vm_impl; vm_impl->vm_impl = NULL; vm_impl->i = 0; vm_impl->pte = NULL; vm_impl->sz = 0; vm_impl->loaduvm_ptesize_check = C_loaduvm_ptesize_checkvm_impl; vm_impl->loaduvm_loop = C_loaduvm_loopvm_impl; vm_impl->allocuvm_check_newsz = C_allocuvm_check_newszvm_impl; vm_impl->allocuvm_loop = C_allocuvm_loopvm_impl; vm_impl->copyuvm_check_null = C_copyuvm_check_nullvm_impl; vm_impl->copyuvm_loop = C_copyuvm_loopvm_impl; vm_impl->uva2ka_check_pe_types = C_uva2ka_check_pe_types; vm_impl->paging_intvm_impl = C_paging_intvmvm_impl; vm_impl->copyout_loopvm_impl = C_copyout_loopvm_impl; vm_impl->switchuvm_check_pgdirvm_impl = C_switchuvm_check_pgdirvm_impl; vm_impl->init_inituvm_check_sz = C_init_inituvm_check_sz; 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; vm->switchuvm = C_switchuvmvm_impl; vm->init_inituvm = C_init_inituvmvm_impl; vm->loaduvm = C_loaduvmvm_impl; vm->allocuvm = C_allocuvmvm_impl; vm->clearpteu = C_clearpteuvm_impl; vm->copyuvm = C_copyuvmvm_impl; vm->uva2ka = C_uva2kavm_impl; vm->copyout = C_copyoutvm_impl; vm->paging_int = C_paging_intvm_impl; return vm; } extern struct { struct spinlock lock; struct run *freelist; } kpt_mem; __code init_vmmvm_impl(struct vm_impl* vm,__code next(...)) { initlock(&kpt_mem.lock, "vm"); kpt_mem.freelist = NULL; goto next(...); } extern struct run { struct run *next; }; static void _kpt_free (char *v) { struct run *r; r = (struct run*) v; r->next = kpt_mem.freelist; kpt_mem.freelist = r; } __code kpt_freerangevm_impl(struct vm_impl* vm, uint low, uint hi, __code next(...)) { if (low < hi) { _kpt_free((char*)low); goto kpt_freerangevm_impl(vm, low + PT_SZ, hi, next(...)); } goto next(...); } __code kpt_allocvm_impl(struct vm_impl* vm, __code next(...)) { acquire(&kpt_mem.lock); goto kpt_alloc_check_impl(vm_impl, next(...)); } typedef struct proc proc; __code switchuvmvm_impl(struct vm_impl* vm , struct proc* p, __code next(...)) { //:skip goto switchuvm_check_pgdirvm_impl(...); } __code init_inituvmvm_impl(struct vm_impl* vm, pde_t* pgdir, char* init, uint sz, __code next(...)) { Gearef(cbc_context, vm_impl)->pgdir = pgdir; Gearef(cbc_context, vm_impl)->init = init; Gearef(cbc_context, vm_impl)->sz = sz; Gearef(cbc_context, vm_impl)->next = next; goto init_inituvm_check_sz(vm, pgdir, init, sz, next(...)); } __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(...)); } __code allocuvmvm_impl(struct vm_impl* vm, pde_t* pgdir, uint oldsz, uint newsz, __code next(...)) { goto allocuvm_check_newszvm_impl(vm, pgdir, oldsz, newsz, next(...)); } __code clearpteuvm_impl(struct vm_impl* vm, pde_t* pgdir, char* uva, __code next(...)) { goto clearpteu_check_ptevm_impl(vm, pgdir, uva, next(...)); } __code copyuvmvm_impl(struct vm_impl* vm, pde_t* pgdir, uint sz, __code next(...)) { goto copyuvm_check_nullvm_impl(vm, pgdir, sz, __code next(...)); } __code uva2kavm_impl(struct vm_impl* vm, pde_t* pgdir, char* uva, __code next(...)) { goto uva2ka_check_pe_types(vm, pgdir, uva, next(...)); } __code copyoutvm_impl(struct vm_impl* vm, pde_t* pgdir, uint va, void* pp, uint len, __code next(...)) { vm->buf = (char*) pp; goto copyout_loopvm_impl(vm, pgdir, va, pp, len, va0, pa0, next(...)); } __code paging_intvm_impl(struct vm_impl* vm, uint phy_low, uint phy_hi, __code next(...)) { goto paging_intvmvm_impl(vm, phy_low, phy_hi, next(...)); } __code vm_void_ret(struct vm_impl* vm) { return; } \end{lstlisting} \section{インターフェースの呼び出し} CbC の場合 goto による遷移を行うので、関数呼び出しのように goto 以降のコードを実行できない。 例として、\ref{cbc_goto} の16行目のように goto によってインターフェースで定義した命令を行うと、戻ってこれないため17行目以降が実行されなくなる。 \begin{lstlisting}[frame=lrbt,label=cbc_goto,caption={\footnotesize cbc インターフェースのgoto}] 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?"); } goto cbc_init_vmm_dummy(&p->cbc_context, p, p->pgdir, _binary_initcode_start, (int)_binary_initcode_size); p->sz = PTE_SZ; // craft the trapframe as if memset(p->tf, 0, sizeof(*p->tf)); \end{lstlisting} \begin{lstlisting}[frame=lrbt,label=dummy,caption={\footnotesize dummy を使った呼び出し}] void dummy(struct proc *p, char _binary_initcode_start[], char _binary_initcode_size[]) { // inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size); goto cbc_init_vmm_dummy(&p->cbc_context, p, p->pgdir, _binary_initcode_start, (int)_binary_initcode_size); } __ncode cbc_init_vmm_dummy(struct Context* cbc_context, struct proc* p, pde_t* pgdir, char* init, uint sz){//:skip 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?"); } dummy(p, _binary_initcode_start, _binary_initcode_size); \end{lstlisting}