# **Linux OS Project 1** <br/> <br/> <br/> **第1組 111522015 陳萬鈿 110522156 陳明威** Goal --- <br/> Linux的虛擬記憶體儲存方式是,將資料分段存入3GB大小的虛擬位置中, 此專案的目的是建立一條system call,功能包含解決以下問題, "*建立三條threads,並確認各個分段位置,在不同的thread中是否共享分段位置*"。** <br/> Method --- <br/> 目標是確認不同thread各個分段是否共享相同位置,故想法是先在kernel中加入一條system call,功能為將虛擬位置轉換為實體位置,並將不同thread各個分段的虛擬位置傳入並傳回實體位置,最後進行比對判斷是否相同。 <br/> Kernel & Linux version --- **Kernel 4.4.1 + ubuntu 16.04** <br/> Compile --- https://blog.kaibro.tw/2016/11/07/Linux-Kernel%E7%B7%A8%E8%AD%AF-Ubuntu/ 透過以上步驟,逐步建立syscall並編譯 編譯前要裝的套件 sudo apt install build-essential libncurses-dev libssl-dev libelf-dev bison flex -y 每次編譯完成改syscall後,只需要重開機選擇原本的kernel輸入以下指令即可 ``` sudo make sudo make modules_install sudo make install ``` <br/> Test code --- ```C= #include <stdio.h> #include <sys/syscall.h> #include <unistd.h> #include <stdlib.h> #include <pthread.h> #include <string.h> #include <semaphore.h> #define mask 0x00000000ffffffff char label[100] = {"Stack Lib Heap Bss Data Code "}; sem_t s1,s2; int data = 0; int bss ; int code(){ return 0; } void* thread_1(){ sem_wait(&s1); int index = 0; int stack = 54088; int *heap = malloc(sizeof(int)); unsigned long address[6] = {(unsigned long)&stack, (unsigned long)&printf, (unsigned long)heap, (unsigned long)&bss, (unsigned long)&data, (unsigned long)&code}; unsigned long temp =0; unsigned long *p2 = &temp; printf("I'm THREAD_1 !\n\n"); for(int i = 0 ;i < 6;i++){ unsigned long *p1 = &address[i]; long a = syscall(546,p1,p2); while(1){ printf("%c",label[index]); index++; if(label[index] ==' '){index++; break;}}; printf(" vaddr: %#lx\t paddr: %#lx\n",*p1,*p2 & mask ); } printf("\n"); sem_post(&s2); } void* thread_2(){ sem_wait(&s2); int index = 0; int stack = 54088; int *heap = malloc(sizeof(int)); unsigned long address[6] = {(unsigned long)&stack, (unsigned long)&printf, (unsigned long)heap, (unsigned long)&bss, (unsigned long)&data, (unsigned long)&code}; unsigned long temp =0; unsigned long *p2 = &temp; printf("I'm THREAD_2 !\n\n"); for(int i = 0 ;i < 6;i++){ unsigned long *p1 = &address[i]; long a = syscall(546,p1,p2); while(1){ printf("%c",label[index]); index++; if(label[index] ==' '){index++; break;}}; printf(" vaddr: %#lx\t paddr: %#lx\n",*p1,*p2 & mask ); } } int main(){ sem_init(&s1,0,0); sem_init(&s2,0,0); pthread_t t_1,t_2; pthread_create(&t_1,NULL,thread_1,NULL); pthread_create(&t_2,NULL,thread_2,NULL); int index = 0; int stack = 54088; int *heap = malloc(sizeof(int)); unsigned long address[6] = {(unsigned long)&stack, (unsigned long)&printf, (unsigned long)heap, (unsigned long)&bss, (unsigned long)&data, (unsigned long)&code}; unsigned long temp =0; unsigned long *p2 = &temp; printf("I'm MAIN thread !\n\n"); for(int i = 0 ;i < 6;i++){ unsigned long *p1 = &address[i]; long a = syscall(546,p1,p2); while(1){ printf("%c",label[index]); index++; if(label[index] ==' '){index++; break;}}; printf(" vaddr: %#lx\t paddr: %#lx\n",*p1,*p2 & mask ); } printf("\n"); sem_post(&s1); pthread_join(t_1,NULL); pthread_join(t_2,NULL); return 0; } ``` System call --- ```C= #include <linux/kernel.h> #include <linux/uaccess.h> #include <linux/syscalls.h> #include <linux/mm_types.h> #include <linux/sched.h> #include <linux/mm.h> #include <asm/pgtable.h> #include <asm/current.h> SYSCALL_DEFINE2(v_to_p,unsigned long* ,vaddr,unsigned long* ,paddr){ pgd_t *pgd; pud_t *pud; pmd_t *pmd; pte_t *pte; unsigned long t1; unsigned long t2; unsigned long *va = &t1; unsigned long *pa = &t2; unsigned long p_index=0,p_offset=0; copy_from_user(va,vaddr,sizeof(unsigned long)); printk("va : %lx",t1); pgd = pgd_offset(current->mm,t1); if (pgd_none(*pgd) || pgd_bad (*pgd)){ return -1; } pud = pud_offset(pgd,t1); if(pud_none(*pud) || pud_bad(*pud)){ return -1; } pmd = pmd_offset(pud,t1); if(pmd_none(*pmd) || pmd_bad(*pmd)){ return -1; } pte = pte_offset_kernel(pmd,t1); if(!pte){ return -1; } p_index = pte_val(*pte) & PAGE_MASK; p_offset = t1 & ~PAGE_MASK; t2 = p_index | p_offset; printk("pa :%lx",t2); copy_to_user(paddr,pa,sizeof(unsigned long)); return 0; } ``` Result --- ![](https://i.imgur.com/mZ8Zxt1.png) <br/> 由以上結果可比對得知各個thread的stack_segment和heap_segment並不共享實體位置,但Bss、Data、Code、Lib段都是共享實體位置。 <br/> 關於linux的virtual address 轉 physical address --- <br/> x86_64架構 在64位元的linux系統中,虛擬位置是用64位元表示0x0000,0000,0000,0000 -> 0xffff,ffff,ffff,ffff 但實際只使用後48個位元,詳細的介紹可參考連結 https://stackoverflow.com/questions/25852367/x86-64-canonical-address 並採用4層地址映射 <br/> ![](https://i.imgur.com/eAwphJi.png) <br/> ![](https://i.imgur.com/Mb8ntaF.png) <br/> 要找到Page table的位置,我們首先要從linux儲存porcess資料的結構task_struct, 存取其中的mm point,mm指標儲存mm_struct位置,而mm_struct是用來儲存該process虛擬位置資料的結構,在該結構中我們就可以找到pgd的初始位置,使用pgd_offset即可存取pgd page中的entry,接著可以透過entry中的資料加上offset使用pud_offset存取pud page entry,依此類推最後可得到pte entry中的實體位置再將後面的offset 12 bits 清成0,加上正確的offset可得到正確的實體位置。 task_struct https://blog.csdn.net/bit_clearoff/article/details/54292300 https://elixir.bootlin.com/linux/v4.4.1/source/arch/x86/include/asm/current.h#L8 mm_struct https://blog.csdn.net/qq_26768741/article/details/54375524 https://elixir.bootlin.com/linux/v4.4.1/source/arch/x86/include/asm/pgtable.h <br/> Virtual address spaces --- <br/> 由觀察執行結果中的虛擬位置,可以得到此process在virtual address spaces的位置,上面的結果是三個執行緒的code_segment取值為code funtion的實體位置,在這裡我們稍作修改將thread_1 code_segment 取thread_1 function虛擬位置,thread_2 main 同理,可得到以下結果。 <br/> ![](https://i.imgur.com/Yio2ntz.png) <br/> 接著可以畫出下面的圖片 ![](https://i.imgur.com/PV8Q0xN.png) <br/> Conclusion --- <br/> 在本次的專案中可以發現,main thread、thread_1、thread_2 都是共享data、bss、lib、code這些分段位置,而stack,heap則各自配置不同的記憶體位置,此次專案中的加分題需要找出各個分段的起始到結束位置和大小,我認為可以從mm_struct儲存的start_code、end_code、start_data、end_data等等提出虛擬位置,回傳後做運算進而算出size。 可能有幫助的連結 https://blog.csdn.net/menogen/article/details/24664833 刪kernel https://www.twblogs.net/a/5d122e90bd9eee1ede04cb76 mm結構 https://blog.csdn.net/lijzheng/article/details/23618365 proc/pid/maps文件詳解 https://hackmd.io/@RinHizakura/S1wfy6nQO 查詢process使用哪個sycall/如何定義SYSCALL_DEFINE https://www.linuxquestions.org/questions/slackware-14/difference-between-make-mrproper-and-make-clean-473144/ 清理上次編譯一堆文件 https://blog.csdn.net/qq_30624591/article/details/88544739 copy_to_user使用方式 https://blog.gtwang.org/linux/linux-tmux-terminal-multiplexer-tutorial/ tmux使用方式 https://elixir.bootlin.com/linux/v4.4.1/source/arch/x86/include/asm 查kernel標頭檔資料位置/內容結構 https://www.cnblogs.com/muahao/p/10297852.html 四層分頁表詳解