mmu.h #define SEG16(type, base, lim, dpl)

トップページ
jupiteroak.hatenablog.com


mmu.h
https://github.com/mit-pdos/xv6-public/blob/master/mmu.h#L47

#define SEG16(type, base, lim, dpl) (struct segdesc)  \
{ (lim) & 0xffff, (uint)(base) & 0xffff,              \
  ((uint)(base) >> 16) & 0xff, type, 1, dpl, 1,       \
  (uint)(lim) >> 16, 0, 0, 1, 0, (uint)(base) >> 24 }

SEG16マクロは、最大サイズが1MBとなるセグメントが、引数で指定されたtype(種類)、base(セグメントのベースアドレス)、lim(リミット値)、dpl(ディスクリプタ特権レベル)を持つように、セグメントディスクリプタ(segdesc構造体)の値を設定します。

引数 type
セグメントの種類を指定する値(4bit)です。
typeはセグメントディスクリプタのbit43-40(segdesc構造体のtype)に格納されます。

引数 base
セグメントのベースアドレスとなる値(32bit)です。
ベースアドレスの上位8bitはセグメントディスクリプタのbit63-56(segdesc構造体のbase_31_24)に格納され、ベースアドレスの下位24bitはセグメントディスクリプタのbit39-16(segdesc構造体のbase_23_16とbase_15_0)に格納されます。

引き数 lim
セグメントのサイズを指定するリミット値(セグメントのサイズ-1)を含んだ値(32bit)です。
limの値(32bit)のうち下位20bitをリミット値として利用します。リミット値の上位4bitはセグメントディスクリプタのbit51-48(segdesc構造体のlim_19_16)に格納され、リミット値の下位16bitはセグメントディスクリプタのbit15-0(segdesc構造体のlim_15_0)に格納されます。

引数 dpl
セグメントのアクセスに必要なCPUの特権レベルです。
dplの値はセグメントディスクリプタのbit46-45(segdesc構造体のdpl)に格納されます。


処理の内容

前提1

セグメントディスクリプタを表現したデータ構造であるsegdesc構造体(8バイト)です。
mmu.h
https://github.com/mit-pdos/xv6-public/blob/master/mmu.h#L25

// Segment Descriptor
struct segdesc {
  uint lim_15_0 : 16;  // Low bits of segment limit
  uint base_15_0 : 16; // Low bits of segment base address
  uint base_23_16 : 8; // Middle bits of segment base address
  uint type : 4;       // Segment type (see STS_ constants)
  uint s : 1;          // 0 = system, 1 = application
  uint dpl : 2;        // Descriptor Privilege Level
  uint p : 1;          // Present
  uint lim_19_16 : 4;  // High bits of segment limit
  uint avl : 1;        // Unused (available for software use)
  uint rsv1 : 1;       // Reserved
  uint db : 1;         // 0 = 16-bit segment, 1 = 32-bit segment
  uint g : 1;          // Granularity: limit scaled by 4K when set
  uint base_31_24 : 8; // High bits of segment base address
};

前提2

説明の都合上、便宜的にマクロを書き換えます。

#define SEG16(type, base, lim, dpl) (struct segdesc)  \
{ (lim) & 0xffff, (uint)(base) & 0xffff,              \
  ((uint)(base) >> 16) & 0xff, type, 1, dpl, 1,       \
  (uint)(lim) >> 16, 0, 0, 1, 0, (uint)(base) >> 24 }

#define SEG16(type, base, lim, dpl) 
(struct segdesc) 
{ (lim) & 0xffff, 
  (uint)(base) & 0xffff,
  ((uint)(base) >> 16) & 0xff, 
  type, 
  1, 
  dpl, 
  1,
  (uint)(lim) >> 16, 
  0, 
  0, 
  1, 
  0, 
  (uint)(base) >> 24 }

セグメントディスクリプタのbit15-0(segdesc構造体のlim_15_0)にリミット値を設定する

 (lim) & 0xffff,

セグメントディスクリプタ(segdesc構造体のlim_15_0)のbit15-0にリミット値の下位16bitを設定します。
limの値(32bit)を0xffffでマスク処理することにより、リミット値の下位16bitを取得しています。

セグメントディスクリプタのbit39-16(segdesc構造体のbase_23_16とbase_15_0)にセグメントのベースアドレスを設定する

(uint)(base) & 0xffff,
((uint)(base) >> 16) & 0xff, 

セグメントディスクリプタのbit39-16(segdesc構造体のbase_23_16とbase_15_0)にセグメントのベースアドレス下位24bitを設定します。
baseの値(32bit)を0xffffでマスク処理することによりセグメントのベースアドレスbit15-0を取得し、 baseの値(32bit)を16bit右シフト演算し0xffでマスク処理することによりセグメントのベースアドレスbit23-16を取得しています。

セグメントディスクリプタのbit47-40(segdesc構造体のp、dpl、s、type)に値を設定する

type, 
1, 
dpl, 
1,

セグメントディスクリプタのbit43-40、bit44、bit46-45、bit47(segdesc構造体のtype、s、dpl、p)にそれぞれ値を設定します。

bit43-40(type)

セグメントの種類を指定するフィールドです。
typeの値とセグメントの種類の対応例を以下に示します。

typeの値 セグメントの種類
0010 読み書き可能データセグメント
1010 実行と読み出し可能コードセグメント

bit44(Sフラグ)

セグメントディスクリプタでは常に1の値です。

bit46-45(DPL)

セグメントへのアクセスに必要なCPUの特権レベルを指定するフィールドです。
00...セグメントへのアクセスに必要なCPUの特権レベルがカーネルモードであることを示しています。
11...セグメントへのアクセスに必要なCPUの特権レベルユーザーモードであることを示しています。

bit47(Pフラグ)

セグメントがメモリ上に存在するかしないかを示すフィールドです。
この値が1の時は、セグメントがメモリ上に常に存在することを示しています。

セグメントディスクリプタのbit55-48(segdesc構造体のg、db、rsv1、avl、lim_19_16)に値を設定する

(uint)(lim) >> 16, 
0, 
0, 
1,
0, 

セグメントディスクリプタのbit51-48、bit52、bit53、bit54、bit55(segdesc構造体のlim_19_16、avl、rsv1、db、g)にそれぞれ値を設定します。

bit51-48(リミット値)

リミット値の上位4bitをセグメントディスクリプタのbit51-48(segdesc構造体のlim_19_16)に設定します。
limの値(32bit)を16bit右シフト演算することにより、リミット値の上位4bitを取得しています。

bit52(AVL)

常に0の値です。

bit53(Lフラグ)

常に0の値です。

bit54(Dフラグ)

セグメントで使用されるアドレスサイズやデータサイズを指定するフラグです。
この値が1の時は、セグメントで使用されるアドレスサイズやデータサイズが32bitであることを示しています。

bit55(Gフラグ)

リミット値の単位を指定するフラグです。
この値が0の時は、リミット値の単位が1バイトであることを示しています。

セグメントディスクリプタのbit63-56(segdesc構造体のbase_31_24)にセグメントのベースアドレスを設定する

(uint)(base) >> 24 

セグメントのベースアドレス上位8bitをセグメントディスクリプタのbit63-56(segdesc構造体のbase_31_24)に設定します。
baseの値(32bit)を24bit右シフト演算し0xffでマスク処理することにより、セグメントのベースアドレスbit31-24を取得しています。