Linux Kernel Project

開發環境和版本資訊

安裝fedora Core 6 2.6.18

Vmware 16 安裝不成功..
使用virtualbox安裝 需開啟I/O APIC

  • I/O APIC VirtualBox 文檔
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    這是VirtualBox文檔:

    啟用I / O APIC

    高級可編程中斷控制器(APIC)是一種較新的x86硬件功能,近年來已取代了舊式的可編程中斷控制器(PIC)。通過I / O APIC,操作系統可以使用16個以上的中斷請求(IRQ),因此避免了IRQ共享,從而提高了可靠性。

    注意注意:對於64位客戶機操作系統,尤其是Windows Vista,需要啟用I / O APIC。如果要在一台虛擬機中使用多個虛擬CPU,則也需要這樣做。

    但是,對於Windows以外的某些操作系統,對I / O APIC的軟件支持一直不可靠。另外,使用I / O APIC會稍微增加虛擬化的開銷,因此會稍微降低客戶機OS的速度。

    警告注意:從Windows 2000開始的所有Windows操作系統都根據I / O APIC是否可用安裝不同的內核。因此,與ACPI一樣,在安裝Windows來賓操作系統之後,不得關閉I / O APIC。但是,安裝後將其打開將無效。

Kernel編譯

1
2
3
4
5
6
7
# make clean
# make mrproper
# cp /boot/config... ./.config
# make bzImage
# make modules
# make modules_install
# make install

Virtual Memory概念

1
基本上每個Process都有獨立的虛擬記憶體空間,32位元機器虛擬記憶體定址為4GB,64位元機器可達到2^64 bytes。
  • process為OS分配系統資源(memory)的單位,thread為OS分配CPU time的單位

  • Process

    1
    2
    3
    一個elf binary檔案在 disk 上叫 user program, load進memory 開始執行後就變成 process
    有自己的address space =>code section, data section, bss section、stack、heap
    Linux 通常把process當做是task,PCB (processing control block) 通常也稱為 struct tast_struct
  • thread:

    1
    2
    3
    4
    Thread 被稱為輕量級process,它是系統調度最小單位,thread與process差別在於process有獨立的資源空間,而thread則共享process的address
    共享process的address space => code section, data section
    thread有自己的program counter, cpu register, stack
    Linux 並沒有特定的data structure來標示thread or process,thread與process都使用process的PCB

1
2
Process and task_struct
Linux用task_struct來描述一個process,透過task_struct->mm->mmap可以找到vm_area_struct,linux用利用VMA(virtual memory area)來描述每個segment特性,大小

  • mm_sturct
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    struct mm_struct {
    struct vm_area_struct * mmap; /* list of VMAs */
    struct rb_root mm_rb;
    unsigned long mmap_base; /* base of mmap area */
    unsigned long task_size; /* size of task vm space */
    pgd_t * pgd;
    atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */
    int map_count; /* number of VMAs */

    unsigned long start_code, end_code, start_data, end_data;
    unsigned long start_brk, brk, start_stack;
    unsigned long arg_start, arg_end, env_start, env_end;

    struct file *exe_file;

    /* ... some code omitted ... */
    };

編譯結果

1
2
3
4
5
大致上的想法在kernel space的mm_struct取得segment info,
再回傳到user space

data、bss、code、libary segment共享記憶體
stack、local storage、heap segment記憶體區塊不相同


程式碼

  • user space

    1
    2
    撰寫 tmp/test.c 
    user呼叫三個線程,分別呼叫syscall 318
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

    void* thread_func(void *arg){
    unsigned long start_code_size, start_code_start, start_code_end;
    int ret;

    ret = syscall(318,1);

    return NULL;
    }
    int
    main(){
    pthread_t threadl, thread2, thread3;

    pthread_create(&thread1, NULL, thread_func, NULL);
    pthread_create(&thread2, NULL, thread_func, NULL);
    pthread_create(&thread3, NULL, thread func, NULL);

    pthread_join(threadl, NULL);
    pthread_join(thread2, NULL);
    pthread_join(thread3, NULL) ;
    return 0;

    }
  • kernel space

    1
    2
    3
    添加syscall 318 kernel/project.c
    利用task_struct->mm_struct->vm_area_struct結構去找所有virtual address的start,end
    利用Printk印出每個segment的start,end
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    //syscall(318)


    #ifndef _LINUX_PROJECT
    #define _LINUX PROJECT

    #include <linux/linkage.h>
    #include <linux/kernel.h>
    #include <linux/sched.h>
    #include <linux/mm.h>
    #include <asm/uaccess.h>

    struct segment info{

    unsigned long start;
    unsigned long end;
    char type[16];
    };

    asmlinkage long sys_project(struct segment_info *info){

    struct mm_struct *mm;
    struct vm area struct *vma;

    mm = &current->mm;
    int i = 0;
    for (vma = mm->mmap; vma; vma= vma->vm_next){

    if (vma->vm_flags & VM_EXEC){
    printk("Code segment: %lx - %lx\n", vma->vm_start,vma->vm_end);
    //strcpy(info[1].type, "code") ;
    }else if (vma->vm_flags & VM_WRITE){
    if (vma->vm flags & VM_GROWSDOWN){
    printk("Stack Segment: %lx - %lx\n", vma->vm_start, vma->vm_end);

    //strcpy(info[1].type, "Stack");
    }else{
    printk("Data/Heap Segment: &lx - %lx\n", vma->vm_start, vma->vm_end);
    //strcpy(info[1].type, "Data/Heap");
    }
    }else{

    printk("Other Segment: %lx - %lx\n", vma->vm_start, vma->vm_end);
    //strcpy(info[1].type, "Other") ;
    }
    //_put_user(vma->vm_start, &info[i].start, unsigned long);
    //_put_user(vma->vm_end, &info[i].end, unsigned long);
    //i++;
    }

    //copy to user(info, info, sizeof(struct segment_info));
    return 0;
    }

    #endif

QA

  1. 哪些segment是共享的?

    data bss code libary這四個segment是共享記憶體,stack、local storage、heap這三個segment則是不相同記憶體位置。

  2. heap的位置不一樣,為什麼?

    因為 heap 區域是一個記憶體區域,用於動態分配記憶體,每個 thread 都有自己的 heap 區域可以使用,所以它們的位置會不同。

    雖然heap位置不相同,但其實也是共享的,其會根據libary或OS不同會有特殊的情況,例如linux是用C語言,heap會用malloc的方式實做,它會先去memory pool找一個可以使用的記憶體區塊(free list),會在從free list裡面分給每個線程heap,所以heap段會是不同的。

  3. Thread local storage是用甚麼東西實作?

    會使用__thread,在宣告的時候加__thread就代表這個東西是TLS。

  4. 每個thread的TLS會不同,這些thread之間可以去存取對方的TLS嗎?

    TLS是不同的,但是他們之間是可以互相存取的。

  5. 建造多執行緒的寫法是?

    pthread_create。
    pthread 的 pthread_create 函數可以用來建立新的執行緒,並以函數指標指定子執行緒所要執行的函數,子執行緒在建立之後,就會以平行的方式執行,在子執行緒的執行期間,主執行緒還是可以正常執行自己的工作,最後主執行緒再以 pthread_join 函數等待子執行緒執行結束,處理後續收尾的動作。

    參考資料:
    https://ascii-iicsa.blogspot.com/2011/10/thread-local-storage.html

  6. pthread_create函數會去使用什麼system call?如何調用?

    pthread_create會使用clone()這個system call,clone()會再去call do_fork這個function,do_fork會再去call copy_process,copy_process中有個copy_mm,linux實做共享記憶體的部分就是靠copy_mm達成。

  7. 為什麼要使用copy from user?

    原理:因為安全機制的考量,程式載入的資料不會馬上放到記憶體上,會一直等到真的使用的時候才放到記憶體上。kernel要去使用這個資料的時候假如不在記憶體上,這種時候kernel會直接crash。

    copy_from_user首先會檢查傳入地址的合法性,檢查後合法才會去做copy,同時也有修復機制避免系統直接crash。

    這個問題主要涉及到2個層面,一個是copy_from_user()有自帶的access_ok檢查,如果用戶傳進來的buffer不屬於用戶空間而是內核空間,根本不會拷貝;二是copy_from_user()有自帶的page fault後exception修復機制。


Linux Kernel Project
https://luoming1995125.github.io/2023/08/22/Linux-Kernel-Project/
作者
Peter Luo
發布於
2023年8月22日
許可協議