annotate paper/xv6.tex @ 35:52521f53f29d

update
author mir3636
date Thu, 07 Feb 2019 10:45:28 +0900
parents ed7a29ed96b7
children 68f10de82b87
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
11
mir3636
parents:
diff changeset
1 \chapter{xv6 の CbC への書き換え}
mir3636
parents:
diff changeset
2 Gears OS をハードウェア上で実装するために、ARM\cite{arm} プロセッサを搭載したシングルボードコンピュータである Raspberry Pi\cite{rpi} 上で Gears OS 実装したい。
33
mir3636
parents: 31
diff changeset
3 ハードウェア上でのメタレベルの計算や並列実行を行うために、Linax 等に比べてシンプルである xv6 の機能の一部を Gears OS に置き換えることで実現させる。
11
mir3636
parents:
diff changeset
4 xv6 は UNIX V6 を x86 へ再実装したものであるが、
33
mir3636
parents: 31
diff changeset
5 ここでは xv6 を Raspberry pi 用に移植した xv6\_rpi\cite{xv6rpi} を用いて実装する。
11
mir3636
parents:
diff changeset
6
31
mir3636
parents: 14
diff changeset
7 Xv6 は 2006 年に MIT のオペレーティングシステムコースで教育用の目的として開発されたオペレーティングシステムである。
mir3636
parents: 14
diff changeset
8 Xv6 はプロセス、仮想メモリ、カーネルとユーザの分離、割り込み、ファイルシステムなどの基本的な Unix の構造を持つにも関わらず、
mir3636
parents: 14
diff changeset
9 シンプルで学習しやすい。
mir3636
parents: 14
diff changeset
10
33
mir3636
parents: 31
diff changeset
11 \section{xv6 の構成要素}
31
mir3636
parents: 14
diff changeset
12 xv6 はカーネルと呼ばれる形式をとっている。
mir3636
parents: 14
diff changeset
13 カーネルは OS にとって中核となるプログラムである。
mir3636
parents: 14
diff changeset
14 xv6 ではカーネルとユーザープログラムは分離されており、カーネルはプログラムにプロセス管理、メモリ管理、I/O やファイルの管理などのサービスを提供する。
mir3636
parents: 14
diff changeset
15 ユーザープログラムがカーネルのサービスを呼び出す場合、システムコールを用いてユーザー空間からカーネル空間へ入りサービスを実行する。
mir3636
parents: 14
diff changeset
16 カーネルは CPU のハードウェア保護機構を使用して、ユーザー空間で実行されているプロセスが自身のメモリのみアクセスできるように保護している。
mir3636
parents: 14
diff changeset
17 ユーザープログラムがシステムコールを呼び出すと、ハードウェアが特権レベルを上げ、カーネルのプログラムが実行される。
mir3636
parents: 14
diff changeset
18 この特権レベルを持つプロセッサの状態をカーネルモード、特権のない状態をユーザーモードという。
mir3636
parents: 14
diff changeset
19
34
mir3636
parents: 33
diff changeset
20 \subsection{システムコール}
mir3636
parents: 33
diff changeset
21
mir3636
parents: 33
diff changeset
22 ユーザープログラムがカーネルの提供するサービスを呼び出す際にはシステムコールを用いる。
mir3636
parents: 33
diff changeset
23 ユーザープログラムがシステムコールを呼び出すと、トラップが発生する。
mir3636
parents: 33
diff changeset
24 トラップが発生すると、ユーザープログラムは中断され、カーネルに切り替わり処理を行う。
35
mir3636
parents: 34
diff changeset
25 ソースコード \ref{syscall_list} は xv6 のシステムコールのリストである。
34
mir3636
parents: 33
diff changeset
26
35
mir3636
parents: 34
diff changeset
27 \begin{lstlisting}[frame=lrbt,label=syscall_list,caption={\footnotesize xv6 のシステムコールのリスト}]
34
mir3636
parents: 33
diff changeset
28 static int (*syscalls[])(void) = {
mir3636
parents: 33
diff changeset
29 [SYS_fork] =sys_fork,
mir3636
parents: 33
diff changeset
30 [SYS_exit] =sys_exit,
mir3636
parents: 33
diff changeset
31 [SYS_wait] =sys_wait,
mir3636
parents: 33
diff changeset
32 [SYS_pipe] =sys_pipe,
mir3636
parents: 33
diff changeset
33 [SYS_read] =sys_read,
mir3636
parents: 33
diff changeset
34 [SYS_kill] =sys_kill,
mir3636
parents: 33
diff changeset
35 [SYS_exec] =sys_exec,
mir3636
parents: 33
diff changeset
36 [SYS_fstat] =sys_fstat,
mir3636
parents: 33
diff changeset
37 [SYS_chdir] =sys_chdir,
mir3636
parents: 33
diff changeset
38 [SYS_dup] =sys_dup,
mir3636
parents: 33
diff changeset
39 [SYS_getpid] =sys_getpid,
mir3636
parents: 33
diff changeset
40 [SYS_sbrk] =sys_sbrk,
mir3636
parents: 33
diff changeset
41 [SYS_sleep] =sys_sleep,
mir3636
parents: 33
diff changeset
42 [SYS_uptime] =sys_uptime,
mir3636
parents: 33
diff changeset
43 [SYS_open] =sys_open,
mir3636
parents: 33
diff changeset
44 [SYS_write] =sys_write,
mir3636
parents: 33
diff changeset
45 [SYS_mknod] =sys_mknod,
mir3636
parents: 33
diff changeset
46 [SYS_unlink] =sys_unlink,
mir3636
parents: 33
diff changeset
47 [SYS_link] =sys_link,
mir3636
parents: 33
diff changeset
48 [SYS_mkdir] =sys_mkdir,
mir3636
parents: 33
diff changeset
49 [SYS_close] =sys_close,
mir3636
parents: 33
diff changeset
50 };
mir3636
parents: 33
diff changeset
51 \end{lstlisting}
mir3636
parents: 33
diff changeset
52
33
mir3636
parents: 31
diff changeset
53 \subsection{プロセス}
31
mir3636
parents: 14
diff changeset
54 プロセスとは、カーネルが実行するプログラムの単位である。
mir3636
parents: 14
diff changeset
55 xv6 のプロセスは、ユーザー空間メモリとカーネル用のプロセスの状態を持つ空間で構成されている。
mir3636
parents: 14
diff changeset
56 プロセスは独立しており、他のプロセスからメモリを破壊されたりすることはない。
mir3636
parents: 14
diff changeset
57 また、独立していることでカーネルそのものを破壊することもない。
mir3636
parents: 14
diff changeset
58 各プロセスの状態は struct proc によって管理されている。
mir3636
parents: 14
diff changeset
59 プロセスは fork システムコールによって新たに生成される。
mir3636
parents: 14
diff changeset
60 fork は新しく、親プロセスと呼ばれる呼び出し側と同じメモリ内容の、子プロセスと呼ばれるプロセスを生成する。
mir3636
parents: 14
diff changeset
61 fork システムコールは、親プロセスであれば子プロセスのID、子プロセスであれば 0 を返す。
mir3636
parents: 14
diff changeset
62 親プロセスと子プロセスは最初は同じ内容を持っているが、それぞれ異なるメモリ、レジスタで実行されているため、片方のメモリ内容を変更してももう片方に影響はない。
mir3636
parents: 14
diff changeset
63 exit システムコールはプロセスの停止を行い、メモリを解放する。
mir3636
parents: 14
diff changeset
64 wait システムコールは終了した子プロセスのIDを返す。子プロセスが終了するまで待つ。
mir3636
parents: 14
diff changeset
65 exec システムコールは呼び出し元のプロセスのメモリをファイルシステムのファイルのメモリイメージと置き換え実行する。
mir3636
parents: 14
diff changeset
66 ファイルには命令、データなどの配置が指定されたフォーマット通りになっていなければならない。
mir3636
parents: 14
diff changeset
67 xv6 は ELF と呼ばれるフォーマットを扱う。
mir3636
parents: 14
diff changeset
68
33
mir3636
parents: 31
diff changeset
69 \subsection{ファイルディスクリプタ}
31
mir3636
parents: 14
diff changeset
70 ファイルディスクリプタは、カーネルが管理するプロセスが読み書きを行うオブジェクトを表す整数値である。
mir3636
parents: 14
diff changeset
71 プロセスは、ファイル、ディレクトリ、デバイスを開く、または既存のディスクリプタを複製することによって、
mir3636
parents: 14
diff changeset
72 ファイルディスクリプタを取得する。
33
mir3636
parents: 31
diff changeset
73 xv6 はプロセス毎にファイルディスクリプタのテーブルを持っている。
mir3636
parents: 31
diff changeset
74 ファイルディスクリプタは普通、0 が標準入力、1 が標準出力、2 がエラー出力として使われる。
mir3636
parents: 31
diff changeset
75 ファイルディスクリプタのテーブルのエントリを変更することで入出力先を変更することができる。
mir3636
parents: 31
diff changeset
76 1 の標準出力を close し、ファイルを open することでプログラムはファイルに出力することになる。
mir3636
parents: 31
diff changeset
77 ファイルディスクリプタはファイルがどのように接続するか隠すことでファイルへの入出力を容易にしている。
mir3636
parents: 31
diff changeset
78
mir3636
parents: 31
diff changeset
79 \subsection{ファイルシステム}
mir3636
parents: 31
diff changeset
80 xv6 のファイルシステムはバイト配列であるデータファイルとデータファイルおよび他のディレクトリの参照を含むディレクトリを提供する。
mir3636
parents: 31
diff changeset
81 ディレクトリは root と呼ばれる特別なディレクトリから始まるツリーを形成している。
mir3636
parents: 31
diff changeset
82 絶対パスである "/dir1/dir2/file1" というパスは root ディレクトリ内の dir1 という名前のディレクトリ内の dir2 という名前のディレクトリ内の file というデータファイルを指す。
mir3636
parents: 31
diff changeset
83 相対パスである "dir2/file2" のようなパスは、現在のディレクトリ内の dir2 という名前のディレクトリ内の file というデータファイルを指す。
mir3636
parents: 31
diff changeset
84
14
mir3636
parents: 11
diff changeset
85 \section{xv6-rpi の CbC 対応}
11
mir3636
parents:
diff changeset
86
35
mir3636
parents: 34
diff changeset
87 オリジナルの xv6 は x86 アーキテクチャで実装されたものだが、xv6-rpi は Raspberry Pi 用に実装されたものである。
11
mir3636
parents:
diff changeset
88
mir3636
parents:
diff changeset
89 xv6-rpi を CbC で書き換えるために、
35
mir3636
parents: 34
diff changeset
90 GCC 上で実装した CbC コンパイラを ARM 向けに build し xv6-rpi をコンパイルした。
mir3636
parents: 34
diff changeset
91 これにより、 xv6-rpi を CbC で書き換えることができるようになった。
mir3636
parents: 34
diff changeset
92
mir3636
parents: 34
diff changeset
93 ソースコード \ref{syscall} は syscall() におけるシステムコールの呼び出しを行うコードである。
mir3636
parents: 34
diff changeset
94 システムコールはソースコード \ref{syscall_list} の関数のリストから呼び出される。
mir3636
parents: 34
diff changeset
95 CbC でも同様に num で指定された番号の cbccodes のリストの Code Gear へ goto する。
mir3636
parents: 34
diff changeset
96 引数に持つ cbc\_ret は 継続した先でトラップに戻ってくるための Code Gear である。
mir3636
parents: 34
diff changeset
97
mir3636
parents: 34
diff changeset
98 \begin{lstlisting}[frame=lrbt,label=syscall,caption={\footnotesize syscall()}]
mir3636
parents: 34
diff changeset
99 if((num >= NELEM(syscalls)) && (num <= NELEM(cbccodes)) && cbccodes[num]) {
mir3636
parents: 34
diff changeset
100 proc->cbc_arg.cbc_console_arg.num = num;
mir3636
parents: 34
diff changeset
101 goto (cbccodes[num])(cbc_ret);
mir3636
parents: 34
diff changeset
102 }
mir3636
parents: 34
diff changeset
103
mir3636
parents: 34
diff changeset
104
mir3636
parents: 34
diff changeset
105 if((num > 0) && (num <= NELEM(syscalls)) && syscalls[num]) {
mir3636
parents: 34
diff changeset
106 ret = syscalls[num]();
mir3636
parents: 34
diff changeset
107
mir3636
parents: 34
diff changeset
108 // in ARM, parameters to main (argc, argv) are passed in r0 and r1
mir3636
parents: 34
diff changeset
109 // do not set the return value if it is SYS_exec (the user program
mir3636
parents: 34
diff changeset
110 // anyway does not expect us to return anything).
mir3636
parents: 34
diff changeset
111 if (num != SYS_exec) {
mir3636
parents: 34
diff changeset
112 proc->tf->r0 = ret;
mir3636
parents: 34
diff changeset
113 }
mir3636
parents: 34
diff changeset
114 }
mir3636
parents: 34
diff changeset
115 \end{lstlisting}
mir3636
parents: 34
diff changeset
116
mir3636
parents: 34
diff changeset
117
mir3636
parents: 34
diff changeset
118
mir3636
parents: 34
diff changeset
119
11
mir3636
parents:
diff changeset
120
33
mir3636
parents: 31
diff changeset
121
mir3636
parents: 31
diff changeset
122
11
mir3636
parents:
diff changeset
123 \section{システムコールの書き換え}
mir3636
parents:
diff changeset
124