# **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
---

<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/>

<br/>

<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/>

<br/>
接著可以畫出下面的圖片

<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 四層分頁表詳解