---
# System prepended metadata

title: Linux Operating System-Project 1

---

# Linux Operating System
## Content
[TOC]
## 1.Topic
* [1. ](/Rmodl8SeQkCjmaP1MHCm3Q)Write a new system call "void * my_get_physical_addresses(void *)".

>it can use it to get the physical address of a virtual address of a process,and the return value of this system call is physicall address.[color=#20e7ea]
>
* [2. ](/VCgDCdYQT86h1XuxFIuKsA)Using the new system call to show how the following memory areas are shared by these threads.

>show memory areas include code segments, data segments, BSS segments, heap segments, libraries, stack segments, and thread local storages,and figure of memory.[color=#20e7ea]





## 2.Add New Syscall
**新增 get_physical_addresses 資料夾**
```
cd /usr/src/linux-5.15.137
sudo mkdir get_physical_address
cd get_physical_address
```
![螢幕擷取畫面 2023-11-24 162948](https://hackmd.io/_uploads/BJqny1ANa.png)

**建立 get_physical_address.c**
```
sudo vim get_physical_address.c
```
>get_physical_address.c
>
![螢幕擷取畫面 2023-11-24 163453](https://hackmd.io/_uploads/SkGSlyRE6.png)

**建立 Makefile**
```
sudo vim Makefile
```
>Makefile
>
![螢幕擷取畫面 2023-11-24 163554](https://hackmd.io/_uploads/r1-je10Vp.png)

**回到 linux-5.15.137 改 Makefile**
```
cd ..
sudo vim Makefile
```
>在 Makefile 的 core-y 最後面補上 my_get_physical_address
```C=
core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ hello/ get_physical_address/
```
![螢幕擷取畫面 2023-11-24 163747](https://hackmd.io/_uploads/Sy3ZZJ0Ep.png)

**修改 syscall_64.tbl 檔**
```
sudo vim arch/x86/entry/syscalls/syscall_64.tbl
```
>添加 system call
```C=
450    common    get_physical_address    sys_get_physical_address
```
![螢幕擷取畫面 2023-11-24 164107](https://hackmd.io/_uploads/HJwnb1REp.png)
**編輯 syscalls.h 檔**
```
sudo vim include/linux/syscalls.h
```
>syscalls.h 新增內容
```C=
asmlinkage long sys_get_physical_address(void);
```
![螢幕擷取畫面 2023-11-24 164236](https://hackmd.io/_uploads/ry2WGyAEp.png)
## 3.Compile Kernel
**cd 到 linux-5.15.137 資料夾**
```
cd /usr/src/linux-5.15.137
```
**使用12核心編譯 kernel**
```
sudo make -j12
```
![image](https://hackmd.io/_uploads/BJPlXyR4p.png)
**kernel 安裝上 unubntu22.04**
```
sudo make modules_install -j12
```
![image](https://hackmd.io/_uploads/BJ_bVy0Ea.png)
```
sudo make install -j12
```
![image](https://hackmd.io/_uploads/Bk3QN10Ea.png)
**更新作業系統的 bootloader 成新 kernel**
```
sudo update-grub
```
![image](https://hackmd.io/_uploads/HklIEyCET.png)

**重新啟動, 並選擇新 kernel version**
```
reboot
```
![image](https://hackmd.io/_uploads/S1TDV1CNp.png)
**查看版本是否有更新**
```
uname -mrs
```
![image](https://hackmd.io/_uploads/ryh1SJRNp.png)


## 4.Test Syscall
**建立程式碼**
```
sudo vim get_physical_address.c
```
>get_physical_address.c
```C=
#include <linux/kernel.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#define SYS_get_physical_address 450

int main(){

    void* ptr = malloc(512);
    
    long ret = syscall(SYS_get_physical_address, ptr);
    
    printf("The physical address is %lx", ret);
    
    return 0;
    }
```
**編譯 get_physical_address.c 並執行**
```
gcc -o get_physical_address get_physical_address.c
```
```
./get_physical_address
```
**使用 dmesg 查看 kernel 中訊息**
```
sudo dmseg
```
![image](https://hackmd.io/_uploads/S1wPvyRE6.png)

## 5.Kernel Space 
**過程**
![image](https://hackmd.io/_uploads/HJJOyIJSp.png)
>上圖為linux kernel中task_struct結構體, 從中取得mm_strcut中的pgd及mmap, 而mmap則紀錄process使用的VMA(virtual memory area), 透過mm取得目前address

* 64-bits Virtual address 轉成 Physical address
![image](https://hackmd.io/_uploads/B1dtLXCE6.png)

    >64bits的linux kernel 5.15.137架構是使用5層的page table來進行位址轉換(其中p4d是從v4.11之後才出現), 分別是Page Global Directory (PGD), P4D, Page Upper Directory (PUD), Page Middle Directory (PMD), Page Table (PTE),且每一級的table有三個Description marco - size, shift, mask, 並且在Kernel中結構各定義為pgd_t, p4d_t, pmd_t, pte_t




## 6.User Space
**程式碼執行畫面**
![image](https://hackmd.io/_uploads/Sy_lqPkS6.png)
* 其中main thread和其他三個sub thread的data, bss, code segments是在相同的physical address起始位置上, 而stack, thread local, heap segment的address則是不一樣的


**記憶體配置結果圖**
![image](https://hackmd.io/_uploads/SJDUYwkHp.png)







## 7.Kernel Space & User Space Code
### ==Kernel Space Code==
```C=
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/uaccess.h>
#include <linux/mm_types.h>
#include <asm/pgtable.h>
#include <linux/slab.h>

SYSCALL_DEFINE1(get_physical_address,unsigned long , virtual_address) {
    pgd_t *pgd;
    p4d_t *p4d;
    pud_t *pud;
    pmd_t *pmd;
    pte_t *pte;
    
    struct task_struct *task;
    struct mm_struct *mm;
    
    unsigned long phys_addr = 0;
    unsigned long addr = 0;
    unsigned long offset = 0;
    
    // Get the task structure of the current process
    task = current;

    // Get the memory descriptor of the current process
    mm = get_task_mm(task);
    
    pgd = pgd_offset(mm, virtual_address);
    printk(KERN_INFO "PGD: %lx\n", pgd);

    p4d = p4d_offset(pgd, virtual_address);
    printk(KERN_INFO "P4D: %lx\n", p4d);

    pud = pud_offset(p4d, virtual_address);
    printk(KERN_INFO "PUD: %lx\n", pud);

    pmd = pmd_offset(pud, virtual_address);
    printk(KERN_INFO "PMD: %lx\n", pmd);

    pte = pte_offset_kernel(pmd, virtual_address);
    printk(KERN_INFO "PTE: %lx\n", pte);
    
    addr = pte_val(*pte) & PAGE_MASK;
    offset = virtual_address & ~PAGE_MASK;
    phys_addr = addr | offset;

    printk(KERN_INFO "phys_addr: %lx\n", phys_addr);
      
    return phys_addr;
    
}
```
下方為linux kernel中pgtable.h相關的Macro
```C=
#define pgd_offset(mm, address)		pgd_offset_pgd((mm)->pgd, (address))
#define pte_offset_kernel 
#define PAGE_MASK	(~(PAGE_SIZE-1))
#ifdef __ASSEMBLY__
#define PAGE_SIZE	(1 << PAGE_SHIFT)
#else
#define PAGE_SIZE	(1UL << PAGE_SHIFT)
#define PAGE_SHIFT	12
```
### ==User Space Code==
``` c=
 #include <stdio.h>
 #include <pthread.h>
 #include <string.h>
 #include <sys/syscall.h>      /* Definition of SYS_* constants */
 #include <unistd.h>
 #include <stdlib.h>
 #define SYS_get_physical_address 450

 extern void *func1(void *);
 extern void *func2(void *);
 extern int main();
 void * my_get_physical_addresses(void *ptr1){
    syscall(SYS_get_physical_address, ptr1);
 }


 struct data_
 {
    int  id ;
    char name[16] ;
 } ;
 typedef struct data_ sdata ;
 static __thread  sdata  tx ;  //thread local variable

 int a=123;  //global variable
 int d;
 

 
 pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;

 void hello(int pid)
 {  
    pthread_mutex_lock ( &mutex1 ); //lock
    int b=10;   //local varialbe

    b=b+pid;
                 //global variable
    int* c = malloc(sizeof(int));
    printf("(data segment)1.In thread %d \nthe value of gloable varialbe a is %d, the offset of the logical address of  a is %p, ", pid, a, &a);
    printf("the physical address of global variable a is %p\n", my_get_physical_addresses(&a) );
                 //local variable
    printf("(stack segment)2.the value of local varialbe b is %d, the offset of the logical address of b is %p, ", b, &b);
    printf("the physical address of local variable b is %p\n", my_get_physical_addresses(&b));
                 //thread local variable
    printf("(thread local segment)3.the offset of the logical address of thread local varialbe tx is %p, ", &tx);
    printf("the physical address of thread local variable tx is %p\n", my_get_physical_addresses(&tx));
                 //function
    printf("(code segment)4.the offset of the logical address of function hello is %p, ", hello);
    printf("the physical address of function hello is %p\n", my_get_physical_addresses(hello));
    printf("(code segment)5.the offset of the logical address of function func1 is %p, ", func1);
    printf("the physical address of function func1 is %p\n", my_get_physical_addresses(func1));
    printf("(code segment)6.the offset of the logical address of function func2 is %p, ", func2);
    printf("the physical address of function func2 is %p\n", my_get_physical_addresses(func2));
    printf("(code segment)7.he offset of the logical address of function main is %p, ", main);
    printf("the physical address of function main is %p\n", my_get_physical_addresses(main));
                 //library function
    printf("(libraries)8.the offset of the logical address of library function printf is %p, ", printf);
    printf("the physical address of library function printf is %p\n", my_get_physical_addresses(printf));
    printf("(heap)9.the offset of the logical address of c is  %p, ",c);
    printf("the physical address of heap is %p\n",my_get_physical_addresses(c));
    printf("(BSS)10.the value of initializied global variable d is %d, the offset of the logical address of b is %p, ", d, &d);
    printf("the physical address of initializied global variable (in BSS) d is %p\n", my_get_physical_addresses(&d)); 
    printf("====================================================================================================================\n");
    pthread_mutex_unlock( &mutex1 ); //unlock
    free(c);
 }  

 void *func1(void *arg)
 {  
    char *p = (char*) arg ;
    int pid  ;
    pid =  syscall( __NR_gettid );
    tx.id = pid ;
    strcpy(tx.name,p) ;
    printf("I am thread with ID %d executing func1().\n",pid);
    hello(pid);
    while(1)
    {
      //printf("(%d)(%s)\n",tx.id,tx.name) ;
      sleep(1) ;
    }
 }

 void *func2(void *arg)
 {
   
   char *p = (char*) arg ;
   int pid  ;
   pid =  syscall( __NR_gettid );
   tx.id = pid ;
   strcpy(tx.name,p) ;
   printf("I am thread with ID %d executing func2().\n",pid);
   hello(pid);
   while(1)
   {
      //printf("(%d)(%s)\n",tx.id,tx.name) ;
      sleep(2) ;
   }
 }
 int main()
 { 

   pthread_t id[2];
   char p[2][16] ;
   strcpy(p[0],"Thread1") ;
   pthread_create(&id[0],NULL,func1,(void *)p[0]);
   strcpy(p[1],"Thread2") ;
   pthread_create(&id[1],NULL,func2,(void *)p[1] );


   int pid  ;
   pid =  syscall( __NR_gettid );
   tx.id = pid ;
   strcpy(tx.name,"MAIN") ;
   printf("I am main thread with ID %d.\n", pid);
   hello(pid);
   while(1)
   {
     //printf("(%d)(%s)\n",tx.id,tx.name) ;
     sleep(5) ;
   }

 }
```


## 8.Encounter Problem and Solution

*    問題一 : 在 system call 裡加入了copy_to_user() 和 copy_from_user() 這兩個函式出錯(出現 Segmentation Fault or Killed)





>呼叫這兩個函式時，需要傳遞的是兩個 pointer , 是為了可以讓 kernel space 讀到位於 user space 的位址，但由於我們只需傳遞一個 virtual_address 變數，因此最後沒有使用到這兩個函式
>![image](https://hackmd.io/_uploads/r1ePnMAVa.png)
>dmesg所產生詳細的問題
>![image](https://hackmd.io/_uploads/SkM32M0Na.png)


>
>參考自 : [Linux内核和用户空间数据交互copy_to_user和copy_from_user](https://blog.csdn.net/qq_30624591/article/details/88544739)

*    問題二 : 虛擬機磁碟空間不足
>根據本次的經驗，我們的磁碟的容量用了約40GB，因此建議虛擬機的磁碟空間至少要大於40GB
 
 ## Reference
 -get_task_mm函式
 https://zhuanlan.zhihu.com/p/41788388
 -copy_to_user and copy_from_user
[copy_to_user(void __user *to, const void *from, unsigned long n)](https://elixir.free-electrons.com/linux/v3.9/source/arch/x86/lib/usercopy_32.c#L658)
[copy_from_user(void *to, const void __user *from, unsigned long n)](https://elixir.free-electrons.com/linux/v3.9/source/arch/x86/lib/usercopy_32.c#L658)
-mm_struct, Task結構
https://hackmd.io/@eugenechou/H1LGA9AiB
-PGD, P4D, PUD, PMD, PTE, linux轉換頁表
https://hackmd.io/@combo-tw/Linux-%E8%AE%80%E6%9B%B8%E6%9C%83/%2F%40combo-tw%2FBJlTwJUABB
https://github.com/monjjjjj/linux_project1_multithread/blob/main/README.md
-address 轉換表圖片來源
https://www.chegg.com/homework-help/questions-and-answers/given-virtual-memory-areas-used-process-write-system-call-sysgetpageinfo-report-current-st-q46483922
