# Linux Project 1
## Environment
- Kernel vesion : 5.15.137
- 作業系統 : ubuntu 22.04
## Kernel 編譯過程
下載欲編譯的kernel source code, 新增system call後執行以下指令:
```bash=
sudo apt install build-essential libncurses-dev libssl-dev libelf-dev bison flex -y
sudo make oldconfig
sudo make -j4
sudo make modules_install -j4
sudo make install -j4
```
## 編譯時遇到的問題d
- 我們有遇到無法編譯成功的情況,發生的問題每次、每個組員都遇到不同問題,但是經過幾次更換版本之後問題就大部分解決了
- 執行sudo make時遇到其中一個問題:"FAILED: load BTF from vmlinux: No such file or directory", 只要下載套件dwarves即可解決
```
sudo apt install dwarves
```
## 新增System Call過程
#### 在linux-5.15.137 directory中創建資料夾vtop, 並在創建的資料夾中新增system call:
```
cd /usr/src/linux-5.15.137
mkdir vtop
cd vtop
vim vtop.c
```
#### 同時創建Makefile並寫入:
```
obj-y := vtop.o
```
#### 接著回上個目錄改 Makefile, 將剛剛新增的資料夾加到路徑中:
```
cd ..
vim Makefile
```

#### 修改syscall_64.tbl:
```
vim arch/x86/entry/syscalls/syscall_64.tbl
```

#### 修改syscalls.h(添加syscall原型)
```
vim include/linux/syscalls.h
```

## System Call
- Linux 在 2.6.10 中引入了四層的頁表輔助虛擬地址的轉換(PGD、PUD、PMD、PTE),在 4.11 中引入了五層的頁表結構(多了一層P4D,也就是:PGD、P4D、PUD、PMD、PTE)。
- 與pud_none(pud_t), pmd_none(pmd_t)不同的是,p4d_none(p4d_t)=True並不一定代表程式出錯,linux kernel會自動幫我們映射到下一層,即回傳(p4d_t)*pgd。
- 依照題目要求,大多system call失敗時會回傳-1,這邊我們改成:失敗return 0,成功則return傳入function之virtual address所對應的physical address。
```C=
#include <linux/mm.h> // struct mm_struct
#include <linux/sched.h> // current 宏
#include <linux/syscalls.h> // SYSCALL_DEFINE 宏
#include <linux/uaccess.h> // __user 宏
#include <asm/pgtable.h> // 頁表相關的結構和宏 (pgd_t, pmd_t, pte_t)
```
## Multithread.c
```C=
#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <semaphore.h>
sem_t sem;
__thread int TLS = 0;
int data = 0;
int bss ;
void code(){
return ;
}
void* thread_function(void* thread_num){
sem_wait(&sem);
printf("----------------Thread %d -------------------\n", (int) thread_num);
int stack = 7;
char* sname[] = {"TLS","data","bss","code","stack","heap","lib"};
int *heap = malloc(sizeof(int));
unsigned long linear_address[] = {
(unsigned long) &TLS,
(unsigned long) &data,
(unsigned long) &bss,
(unsigned long) &code,
(unsigned long) &stack,
(unsigned long) heap,
(unsigned long) &printf
};
for(int i=0;i<stack;i++){
unsigned long vaddr = linear_address[i];
unsigned long paddr = syscall(449,vaddr);
printf("%s: Linear address: %#lx , Physical address: %#lx \n", sname[i],vaddr,paddr);
}
sem_post(&sem);
return NULL;
}
void main(){
pthread_t thread1 , thread2, thread3;
sem_init(&sem,0,1);
pthread_create(&thread1, NULL, thread_function, (void*)1);
pthread_create(&thread2, NULL, thread_function, (void*)2);
pthread_create(&thread3, NULL, thread_function, (void*)3);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
pthread_join(thread3, NULL);
sem_destroy(&sem);
return;
}
```
### 編譯
```
gcc -o mt multithread.c -pthread
```
## multithread.c 執行結果

## 各Thread在Physical Memory的Layout
### Thread1

### Thread2

### Thread3

## Example Code
- 增加了heap區段
- 加入semaphore,避免thread交互執行導致難以觀察結果
```C=
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <sys/syscall.h> /* Definition of SYS_* constants */
#include <unistd.h>
#include <semaphore.h>
extern void *func1(void *);
extern void *func2(void *);
extern int main();
void * my_get_physical_addresses(void *);
void * my_get_physical_addresses(void *v_addr){
unsigned long vaddr = (unsigned long)v_addr;
unsigned long p_addr = syscall(449, vaddr);
unsigned long *p_ptr = (unsigned long *)p_addr;
return p_ptr;
}
struct data_
{
int id ;
char name[16] ;
};
typedef struct data_ sdata ;
static __thread sdata tx ; //thread local variable
sem_t sem;
int a=123; //global variable
void hello(int pid)
{
int b=10; //local varialbe
int *heap = malloc(sizeof(int)); //heap area
b=b+pid;
//global variable
printf("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("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));
//heap
printf("the value of the logical address of heap area is %p, ", heap);
printf("the physical address of heap area is %p\n", my_get_physical_addresses(heap));
//thread local variable
printf("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("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("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("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("the 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("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("====================================================================================================================\n");
}
void *func1(void *arg)
{
char *p = (char*) arg ;
int pid ;
pid = syscall( __NR_gettid );
tx.id = pid ;
strcpy(tx.name,p) ;
sem_wait(&sem);
printf("I am thread with ID %d executing func1().\n",pid);
hello(pid);
sem_post(&sem);
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) ;
sem_wait(&sem);
printf("I am thread with ID %d executing func2().\n",pid);
hello(pid);
sem_post(&sem);
while(1)
{
//printf("(%d)(%s)\n",tx.id,tx.name) ;
sleep(2) ;
}
}
int main()
{
pthread_t id[2];
sem_init(&sem, 0, 1);
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") ;
sem_wait(&sem);
printf("I am main thread with ID %d.\n", pid);
hello(pid);
sem_post(&sem);
sem_destroy(&sem);
while(1)
{
//printf("(%d)(%s)\n",tx.id,tx.name) ;
sleep(5) ;
}
}
```
### Example Code 執行結果

## Reference
1.[add a system call教學網址 by 助教](https://hackmd.io/aist49C9R46-vaBIlP3LDA?both)
2.[新增system call](https://hackmd.io/@combo-tw/Linux-%E8%AE%80%E6%9B%B8%E6%9C%83/%2F%40combo-tw%2FBJPoAcqQS#%E5%A6%82%E4%BD%95%E6%96%B0%E5%A2%9E%E4%B8%80%E5%80%8B-System-Call)
3.[Linux轉址以及Virtural Memory](https://iter01.com/510311.html)
4.[Linux Page Tables](https://docs.kernel.org/mm/page_tables.html)
5.[copy_to_user©_from_user](https://blog.51cto.com/u_16087831/6223592)