Linux Kernel Project
開發環境和版本資訊
- Virtual Machine: VirtualBox
- Linux Release: Fedora 6 (32-bit)
— http://archive.fedoraproject.org/pub/archive/fedora/linux/core/6/i386/iso/FC-6-i386-DVD.iso - Kernel Version: Linux-2.6.18(32-bit)
— https://mirrors.edge.kernel.org/pub/linux/kernel/v2.6/linux-2.6.18.tar.gz
—tar -zxvf linux-2.6.18.tar.gz -C /usr/src
安裝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 |
|
Virtual Memory概念
1 |
|
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_structthread:
1
2
3
4Thread 被稱為輕量級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 |
|
- mm_sturct
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17struct 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 |
|
程式碼
user space
1
2撰寫 tmp/test.c
user呼叫三個線程,分別呼叫syscall 3181
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,end1
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 = ¤t->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
哪些segment是共享的?
data bss code libary這四個segment是共享記憶體,stack、local storage、heap這三個segment則是不相同記憶體位置。
heap的位置不一樣,為什麼?
因為 heap 區域是一個記憶體區域,用於動態分配記憶體,每個 thread 都有自己的 heap 區域可以使用,所以它們的位置會不同。
雖然heap位置不相同,但其實也是共享的,其會根據libary或OS不同會有特殊的情況,例如linux是用C語言,heap會用malloc的方式實做,它會先去memory pool找一個可以使用的記憶體區塊(free list),會在從free list裡面分給每個線程heap,所以heap段會是不同的。
Thread local storage是用甚麼東西實作?
會使用__thread,在宣告的時候加__thread就代表這個東西是TLS。
每個thread的TLS會不同,這些thread之間可以去存取對方的TLS嗎?
TLS是不同的,但是他們之間是可以互相存取的。
建造多執行緒的寫法是?
pthread_create。
pthread 的 pthread_create 函數可以用來建立新的執行緒,並以函數指標指定子執行緒所要執行的函數,子執行緒在建立之後,就會以平行的方式執行,在子執行緒的執行期間,主執行緒還是可以正常執行自己的工作,最後主執行緒再以 pthread_join 函數等待子執行緒執行結束,處理後續收尾的動作。參考資料:
https://ascii-iicsa.blogspot.com/2011/10/thread-local-storage.htmlpthread_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達成。
為什麼要使用copy from user?
原理:因為安全機制的考量,程式載入的資料不會馬上放到記憶體上,會一直等到真的使用的時候才放到記憶體上。kernel要去使用這個資料的時候假如不在記憶體上,這種時候kernel會直接crash。
copy_from_user首先會檢查傳入地址的合法性,檢查後合法才會去做copy,同時也有修復機制避免系統直接crash。
這個問題主要涉及到2個層面,一個是copy_from_user()有自帶的access_ok檢查,如果用戶傳進來的buffer不屬於用戶空間而是內核空間,根本不會拷貝;二是copy_from_user()有自帶的page fault後exception修復機制。