asm.h #define SEG_ASM(type,base,lim)

トップページ
jupiteroak.hatenablog.com


asm.h
https://github.com/mit-pdos/xv6-public/blob/master/asm.h#L11

#define SEG_ASM(type,base,lim)                                  \
        .word (((lim) >> 12) & 0xffff), ((base) & 0xffff);      \
        .byte (((base) >> 16) & 0xff), (0x90 | (type)),         \
                (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff)

SEG_ASMマクロは、アセンブリ言語ソースコードにおいて、セグメントディスクリプタに値を設定するために使用されます。

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

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

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

処理の内容

前提

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

#define SEG_ASM(type,base,lim)                                  \
        .word (((lim) >> 12) & 0xffff), ((base) & 0xffff);      \
        .byte (((base) >> 16) & 0xff), (0x90 | (type)),         \
                (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff)

#define SEG_ASM(type,base,lim)                                  
        .word (((lim) >> 12) & 0xffff);
        .word ((base) & 0xffff);      
        .byte  (((base) >> 16) & 0xff); 
        .byte  (0x90 | (type));
        .byte  (0xC0 | (((lim) >> 28) & 0xf)); 
        .byte  (((base) >> 24) & 0xff);

セグメントディスクリプタのbit15-0にリミット値を設定する

 .word (((lim) >> 12) & 0xffff);

リミット値の下位16bitをセグメントディスクリプタのbit15-0に設定します。
limの値(32bit)を12bit右シフト演算し0xffffでマスク処理することにより、リミット値の下位16bitを取得しています。
.wordは、アセンブリ言語ソースコードで使用される疑似命令で、(((lim) >> 12) & 0xffff)の値が2バイトであることを示しています。

セグメントディスクリプタのbit39-16にセグメントのベースアドレスを設定する

.word ((base) & 0xffff);  
.byte  (((base) >> 16) & 0xff);    

セグメントのベースアドレス下位24bitをセグメントディスクリプタのbit39-16に設定します。
baseの値(32bit)を0xffffでマスク処理することによりセグメントのベースアドレスbit15-0を取得し、 baseの値(32bit)を16bit右シフト演算し0xffでマスク処理することによりセグメントのベースアドレスbit23-16を取得しています。
.wordは、アセンブリ言語ソースコードで使用される疑似命令で、((base) & 0xffff)の値が2バイトであることを示しています。
.byteは、アセンブリ言語ソースコードで使用される疑似命令で、(((base) >> 16) & 0xff))の値が1バイトであることを示しています。

セグメントディスクリプタのbit47-40に値を設定する

byte  (0x90 | (type));

0x90とtypeの値をビット和演算した結果をセグメントディスクリプタのbit47-40に設定します。
typeの値(4bit)はそのままセグメントディスクリプタのbit43-40に格納され、0x90(1001 0000)の上位4bitである1、00、1が、セグメントディスクリプタのbit47( Pフラグ)、bit46-45 (DPL)、bit44 (Sフラグ)にそれぞれ格納されます。
.byteは、アセンブリ言語ソースコードで使用される疑似命令で、(0x90 | (type))の値が1バイトであることを示しています。

bit43-40(type)

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

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

bit44(Sフラグ)

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

bit46-45(DPL)

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

bit47(Pフラグ)

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

セグメントディスクリプタのbit55-48に値を設定する

.byte  (0xC0 | (((lim) >> 28) & 0xf)); 

0xC0と((lim >> 28) & 0xf)をビット和演算した結果をセグメントディスクリプタのbit55-48に設定します。
)(lim >> 28) & 0xf)の値(4bit)はそのままセグメントディスクリプタのbit51-48に格納され、0xC0(1100 0000)の上位4bitである1、1、0、0が、セグメントディスクリプタのbit55(Gフラグ)、bit54(Dフラグ)、bit53(Lフラグ)、bit52(AVL)にそれぞれ格納されます。
.byteは、アセンブリ言語ソースコードで使用される疑似命令で、(0xC0 | (((lim) >> 28) & 0xf)の値が1バイトであることを示しています。

bit51-48(リミット値)

リミット値の上位4bitをセグメントディスクリプタのbit51-48に設定します。
limの値(32bit)を28bit右シフト演算し0xfでマスク処理することにより、リミット値の上位4bitを取得しています。

bit52(AVL)

常に0の値です。

bit53(Lフラグ)

常に0の値です。

bit54(Dフラグ)

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

bit55(Gフラグ)

リミット値の単位を指定するフラグです。
この値が1の時は、リミット値の単位がページ(4KB)であることを示しています。

セグメントディスクリプタのbit63-56にセグメントのベースアドレスを設定する

.byte  (((base) >> 24) & 0xff);

セグメントのベースアドレス上位8bitをセグメントディスクリプタのbit63-56に設定します。
baseの値(32bit)を24bit右シフト演算し0xffでマスク処理することにより、セグメントのベースアドレスbit31-24を取得しています。
.byteは、アセンブリ言語ソースコードで使用される疑似命令で、(((base) >> 24) & 0xff)の値が1バイトであることを示しています。