x86 Linux のメモリモデル、プロセス空間切り替え、カーネルスタック


 id:naoya:20070924:1190653790  Linux 退/

 (switch_to()  pushl %ebp )


 48632 調


: 




x86 Linux (0) (3)  = 

 x86 使 TSS () 使

 TSS 退 Linux 退 TSS 使 task_struct  thread  Linux 

486 


 Linux 3

Linux2.6

Linux (UNIXMAGAZINE COLLECTION)


3調 i386 (not x86_64)  (*) 

Linux のメモリモデル

x86 Linux はセグメント機構はほとんど使わず、論理アドレスとリニアアドレスが一致する「基本フラットモデル」を採用しています。

  • Linux では x86 のセグメント機構はごく一部しか使っていない。
    • すべてのセグメントディスクリプタはベースアドレスが 0、リミット値が 0xfffffh (G ビット有効)
    • 論理アドレスとリニアアドレスが一致している → 常に論理アドレスのオフセットフィールドがリニアアドレスと一致する
    • これを「基本フラットモデル」と呼ぶ
    • モードとセグメントが異なる組として __USER_CS、__USER_DS、__KERNEL_CS、__KERNEL_DS の 4 つのセグメントのみが用意されている
    • (*) C 言語での関数呼び出しは基本的に同一セグメント間でのジャンプに変換される。セグメント間ジャンプはしない、ということ
  • プロセス空間の分離やメモリの保護はページング機構を利用して実現される
    • 具体的には? → 後述

なぜフラットモデルか。

Linux の GDT と LDT

  • 各CPUごとにひとつの GDT を持つ
    • 基本的に各CPUの GDT の中のディスクリプタの構成は全部一緒。
    • 異なるのは以下のもの
      • TSS → Linux は TSS も限定的にしか使用しない。1CPU につき一つの TSS セグメントのディスクリプタのみを GDT に登録する
      • CPU が実行しているプロセスに依存している GDT → LDT、TLSディスクリプタ
  • Linuxユーザーモードアプリケーションのほとんどは LDT を利用しない
    • iBCS 実行コード用のコールゲート、Solaris/x86 実行コードのコールゲートに利用する

Pentium 



Page Size Extension (PSE)

Pentium  4KB  4MB 

cr4  PSE 

PDE 7PDE  4MB  4KB or 4MB 


4MB  Pros: TLB / Cons: 

Linux  4MB 




TLB 

Pentium Pro  PTE  Global  TLB 

 cr4  PGE 1

(*) invlpg ?




PAE (Physical Address Extension)

Pentium Pro 36   2^36 = 64GB 

32 CPU 363236 PAE

 (PDPT) 

PAE 6432OS 64GB  4GB

(*)  x86_64 使32


Linux のページングモデル

  • 32ビット PAE 無効/有効、64 ビットなどに関わらずすべて共通のページング機構を利用。汎用的なページングモデル。
  • 4階層5分割でリニアアドレスを扱う
    • ページグローバルディレクトリ、ページアッパーディレクトリ、ページミドルディレクトリ、ページテーブル
    • PAE なし 32 ビットの場合アッパー、ミドルを実質アドレス変換から取り除き、ハードウェアのページング機構のそれとほぼ同一の対応を行う

Linux のプロセス空間切り替え (= ページグローバルディスクリプタの切り替え)


使


Linux 

(*) PAE 


 cr3 

cr3  = 

cr3  TLB  ()

TLB 

使2  

 TLB 




 CPU 使




 mm_struct task_struct 

mm_struct  pgd 

 pgd  cr3 



context_switch()  switch_mm 
static inline void switch_mm(struct mm_struct *prev,
                 struct mm_struct *next,
                 struct task_struct *tsk)
{
    int cpu = smp_processor_id();

    if (likely(prev != next)) {
        /* stop flush ipis for the previous mm */
        cpu_clear(cpu, prev->cpu_vm_mask);
#ifdef CONFIG_SMP
        per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK;
        per_cpu(cpu_tlbstate, cpu).active_mm = next;
#endif
        cpu_set(cpu, next->cpu_vm_mask);

        /* Re-load page tables */
        load_cr3(next->pgd);

        /*
         * load the LDT, if the LDT is different:
         */
        if (unlikely(prev->context.ldt != next->context.ldt))
            load_LDT_nolock(&next->context);
    }
#ifdef CONFIG_SMP
    else {
        per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK;
        BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next);

        if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
            /* We were in lazy tlb mode and leave_mm disabled
             * tlb flush IPI delivery. We must reload %cr3.
             */
            load_cr3(next->pgd);
            load_LDT_nolock(&next->context);
        }
    }
#endif
}

prev != next load_cr3(next->pgd)  cr3  next->pgd 

カーネルスタックとは


 TSS 使


Linux 

Linux 

1 8,192  thread_info 

union thread_union {
    struct thread_info thread_info;
    unsigned long stack[THREAD_SIZE/sizeof(long)];
};


x86 

  


GDT  TSS  (03) ss esp x86  TSS (Linux  CPU  TSS 1)  ss:esp 

Linux  0  3 (Xen 使1使)    ss0:esp0 

 ss0esp0 



Linux  TSS  tss_struct include/asm-i386/processor.h  tss_struct 
struct tss_struct {
    unsigned short  back_link,__blh;
    unsigned long   esp0;
    unsigned short  ss0,__ss0h;
    ...
} __attribute__((packed));

 esp0  ss0 

 TSS 退 Linux TSS 


x86 

I/O 


2 TSS  TSS  TSS 

Linuxシステムコール


(  )








eflags, cs, eip, ss, esp () 退

system_call()  sysenter_entry()  SAVE_ALL  gs, es, ds, ebp 

 ebxecxedxesiediebp 6


Linux  int 0x80  sysenter 使






SAVE_ALL arch/i386/kernel/entry.S 
#define SAVE_ALL \
        cld; \
        pushl %gs; \
        CFI_ADJUST_CFA_OFFSET 4;\
        /*CFI_REL_OFFSET gs, 0;*/\
        pushl %es; \
        CFI_ADJUST_CFA_OFFSET 4;\
        /*CFI_REL_OFFSET es, 0;*/\
        pushl %ds; \
        CFI_ADJUST_CFA_OFFSET 4;\
        /*CFI_REL_OFFSET ds, 0;*/\
        pushl %eax; \
        CFI_ADJUST_CFA_OFFSET 4;\
        CFI_REL_OFFSET eax, 0;\
        pushl %ebp; \
        CFI_ADJUST_CFA_OFFSET 4;\
        CFI_REL_OFFSET ebp, 0;\
        pushl %edi; \
        CFI_ADJUST_CFA_OFFSET 4;\
        CFI_REL_OFFSET edi, 0;\
        pushl %esi; \
        CFI_ADJUST_CFA_OFFSET 4;\
        CFI_REL_OFFSET esi, 0;\
        pushl %edx; \
        CFI_ADJUST_CFA_OFFSET 4;\
        CFI_REL_OFFSET edx, 0;\
        pushl %ecx; \
        CFI_ADJUST_CFA_OFFSET 4;\
        CFI_REL_OFFSET ecx, 0;\
        pushl %ebx; \
        CFI_ADJUST_CFA_OFFSET 4;\
        CFI_REL_OFFSET ebx, 0;\
        movl $(__USER_DS), %edx; \
        movl %edx, %ds; \
        movl %edx, %es; \
        movl $(__KERNEL_PDA), %edx; \
        movl %edx, %gs




 Linux 

Linux  (cr3 ) 

x86  TSS 退 task_struct 

退/ (1)  (2) 

使TSS  LDT 使使UNIXOS




 

参考文献


48632 


808616 ()

MASM 


 486  486 OSOSLinux OS