カーネル空間

読み:カーネルくうかん
外語:kernel space
品詞:名詞

オペレーティングシステム(OS)のカーネルが稼働しているアドレス空間のこと。

オペレーティングシステムにも様々なものがあるが、一般的なものは二つの「層」に分けることができる。

そのうち下位の層にあり、よりハードウェアに近い処理、機能を担うのがカーネルで、このカーネルが動作する層をカーネル空間と呼ぶ。

空間の分離

アドレス空間をどのように分けて扱うかは、OSごとに様々である。パーソナルコンピュータ用OSと、組み込み機器用OSとでは、かなり違うことが予想される。

ここでは、このうち組み込み用のものとし、SuperH用のNetBSDの実装を例とする。

SuperHでは、アドレス空間4Giバイトを二分割し、上位2Giバイトをユーザ空間、下位2Giバイトをカーネル空間とする。

  • 0x00000000〜0x7fffffff ‐ ユーザ空間(P0/U0領域)
  • 0x80000000〜0xffffffff ‐ カーネル空間

SuperHの場合、0x00000000〜0x1fffffffの512Miバイト程度をよく用い、この中に様々なものが割り付けられる。この空間は、MMUの有無、キャッシュの有無等の各条件で、0x80000000〜0xdfffffffの範囲にもマッピングされている。

  • 0x80000000〜0x9fffffff ‐ P1領域 ‐ MMU無し、キャッシュあり
  • 0xa0000000〜0xbfffffff ‐ P2領域 ‐ MMU無し、キャッシュ無し
  • 0xc0000000〜0xdfffffff ‐ P3領域 ‐ MMUあり、キャッシュあり

NetBSDの実装はこの特徴を用いており、下位の領域のうちストアキュー領域以外は特権モード以外では利用できないように設定し、ここをカーネル空間としている。

P3領域であれば、通常のP0/U0領域からのアクセスと何ら変わらない環境となり、またフラッシュメモリの書き換え処理のようにキャッシュがあっては邪魔な場合はP2領域にアクセスすれば良いことになる。

なお、物理的なメモリはユーザ領域、カーネル領域とも同じものであるので、この管理もCPUとOSがすることになる。

プログラム

カーネル空間のプログラミングは、ユーザ空間とは異なっている。標準関数の一切は、基本的に利用できず、別途カーネル用の関数が用意される。

例えば、printfが使えないカーネルは多い。mallocも、一応使えるが引数などが全く違っている。

カーネル空間用のプログラムを書くときには、その作法を知らねばならない。

相互のやりとり

ユーザ空間から、カーネル空間に直接アクセスする術は無いのが一般的である。カーネル空間にアクセスすれば、通常はアドレスエラーが発生する。

そこで、カーネル空間にデバイスドライバ等を用意し、このデバイスを経由してカーネル空間にアクセスすることになる。

カーネル空間から、ユーザ空間に直接アクセスできるかどうかは実装による。カーネルそのものであれば特権があるためアクセスは自在であろうが、カーネル空間で動くデバイスドライバとなると、若干権限が落とされており、出来ないことが多いようである。

そこで、ユーザ空間の領域にアクセスするための関数が用意される。この仕様はOSごとに様々であり、互換性はない。

NetBSD

NetBSDでは、copy関数群、fetch関数群、store関数群という関数が用意されている。これらは、FreeBSDでも同様と思われる。

fetch/storeは、1バイト〜1ワードまでの単位でのアクセス手段を提供し、copy関数群はデータ列、文字列単位でのアクセス手段を提供する。

copy関数群

ユーザー空間とカーネル空間をまたぐ、memcpyやstrncpy相当の関数群である。

#include <sys/systm.h>

int copyin(const void *uaddr, void *kaddr, size_t len);

int copyout(const void *kaddr, void *uaddr, size_t len);

int copystr(const void *kfaddr, void *kdaddr, size_t len, size_t *done);

int copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done);

具体的な機能は次の通り。

copyin
ユーザ空間→カーネル空間。アドレスuaddrからアドレスkaddrに、lenバイトのデータを複写する
copyout
カーネル空間→ユーザ空間。アドレスkaddrからアドレスuaddrに、lenバイトのデータを複写する
copystr
カーネル空間→ユーザ空間。アドレスkaddrからアドレスuaddrに、NUL文字で終端された最大len文字の文字列を複写する。実際に複写された文字数は、*doneに返される。
copyinstr
ユーザ空間→カーネル空間。アドレスuaddrからアドレスkaddrに、NUL文字で終端された最大len文字の文字列を複写する。実際に複写された文字数は、*doneに返される。
fetch関数群

ユーザー空間からカーネル空間にデータを取り込む関数群である。

#include <sys/types.h>

#include <sys/time.h>

#include <sys/systm.h>

#include <sys/resourcevar.h>

int fubyte(const void *base);

int fusword(void *base);

int fuswintr(void *base);

int fuword(const void *base);

具体的な機能は次の通り。

fubyte
ユーザ空間のアドレスbaseから、1バイトのデータを取り込む。
fusword
ユーザ空間のアドレスbaseから、1ショートワードのデータを取り込む。
fuswintr
ユーザ空間のアドレスbaseから、1ショートワードのデータを取り込む。割り込みコンテクスト中でも利用可能。
fuword
ユーザ空間のアドレスbaseから、1ワードのデータを取り込む。
store関数群

カーネル空間からユーザ空間にデータを格納する関数群である。

#include <sys/time.h>

#include <sys/systm.h>

#include <sys/resourcevar.h>

int subyte(void *base, int byte);

int susword(void *base, int word);

int suswintr(void *base, int word);

int suword(void *base, int word);

具体的な機能は次の通り。

subyte
ユーザ空間のアドレスbaseに、1バイトのデータを格納する。
susword
ユーザ空間のアドレスbaseに、1ショートワードのデータを格納する。
suswintr
ユーザ空間のアドレスbaseに、1ショートワードのデータを格納する。割り込みコンテクスト中でも利用可能。
fuword
ユーザ空間のアドレスbaseに、1ワードのデータを格納する。