# Linux project 1
## 最佳報告
https://hackmd.io/@Mes/make_phy_addr_syscall
## 題目:
https://staff.csie.ncu.edu.tw/hsufh/COURSES/FALL2023/linuxos.html
## 系統環境
虛擬機:virtualBox
OS: ubuntu22
kernel: linux 6.0.1
## 編譯過程
- 下載kernel
```
mv linux-x.x.x /usr/src/
cd /usr/src/linux-x.x.x/
```
- 以下命令建立 syscall
1. mkdir new_syscall
2. cd new_syscall
3. nano Makefile
`obj-y := my_new_syscall.o`
4. nano my_new_syscall.c
編寫system call程式碼
- 加入新的syscall
1. nano usr/src/linux-6.0.1/arch/x86/entry/syscalls/syscall_64.tbl
`549 common my_new_syscall sys_my_new_syscall`
- 函示宣告設定
1. nano /usr/src/linux-6.0.1/include/linux/syscalls.h
`asmlinkage unsigned long* my_new_syscall(unsigned long*,initial);`
加上 "asmlinkage" 後,C function 就會由 stack 取參數,而不是從 register 取參數
2. nano /usr/src/linux-6.0.1/Makefile
找到`core-y`並加入new_syscall(放新的syscall的folder)

- 編譯kernel
1. make menuconfig
2. scripts/config --disable SYSTEM_TRUSTED_KEYS
3. scripts/config --disable SYSTEM_REVOCATION_KEYS
4. make -j12
`Kernel: arch/x86/boot/bzImage is ready (#1)`出現這段代表成功
- 安裝
1. sudo make modules_install -j12
2. sudo make install -j12
3. sudo update-grub
4. reboot
## kernel space
### 實際更動
path:`/usr/src/linux6.0.1/myFunction`
(新的system call)
**my_get_physical_addresses.c**
```cpp=
#include <linux/syscalls.h>
#include <linux/printk.h>
#include <linux/mm_types.h>
#include <linux/slab.h>
SYSCALL_DEFINE1(my_get_physical_addresses, unsigned long*, initial)
{
pgd_t* pgd;
pud_t* pud;
pmd_t* pmd;
pte_t* pte;
unsigned long page_addr = 0;
unsigned long page_offset = 0;
unsigned long* va;
unsigned long* pa;
unsigned long* result;
long ret = 0;
//GFP_KERNEL —— 正常分配内存;
va = (unsigned long*)kmalloc(sizeof(unsigned long),GFP_KERNEL);
pa = (unsigned long*)kmalloc(sizeof(unsigned long),GFP_KERNEL);
ret = copy_from_user(va, initial, sizeof(*va));
pgd = pgd_offset(current->mm, *va);
//強制轉換 (p4d_t*)
pud = pud_offset((p4d_t*)pgd, *va);
pmd = pmd_offset(pud, *va);
pte = pte_offset_kernel(pmd, *va);
//清除頁表項中的頁內偏移部分
page_addr = pte_val(*pte) & PAGE_MASK;
page_offset = *va & ~PAGE_MASK;
*pa = page_addr | page_offset;
ret = copy_to_user(result, pa, sizeof(*pa));
kfree(va);
kfree(pa);
return result;
}
```
- nano /usr/src/linux-6.0.1/myFunction/Makefile
`obj-y := my_get_physical_addresses.o`
- nano /usr/src/linux-6.0.1/include/linux/syscalls.h
`asmlinkage unsigned long* sys_my_get_physical_addresses(unsigned long*,initial);`
- nano /usr/src/linux-6.0.1/Makefile

- nano usr/src/linux-6.0.1/arch/x86/entry/syscalls/syscall_64.tbl
`335 common my_get_physical_addresses sys_my_get_physical_addresses`
### 說明
- SYSCALL_DEFINE1
system call定義
- virtaul address to physical address

64bits的linux kernel 有四層的page table,分別為:
1. Page Global Directory (PGD)
2. Page Upper Directory (PUD)
3. Page Middle Directory (PMD)
4. Page Table (PTE)
>圖中P4D 並不是標準 x86_64 Linux 內核頁的一部分。在正常情况下,Linux 内核使用 PGD、PUD、PMD 和 PTE 這四級就足夠映射。
- copy_from_user & copy_to_user
user-space 無法「直接」存取 kernel-space 的記憶體,因此不能使用memcpy!
所以需要這兩個kernel 的API來傳遞參數
>但由於這一次的project只需要一次轉一個virtual address,並不需要相互讀取記憶體,所以在這份程式碼中可以省略。
- Current 指標
`#define current get_current()`
current指標就是用來儲存task的各種資料用的,這一邊我們需要的是裡面的`mm`參數,而`mm`結構又標示了一個process的memory 管理訊息,包含:
1. page table資訊
2. Stack, BSS, Data, Code...段的資訊
## user space
### 程式碼
>在各個thread中加入了heapAddress,用於觀察heap段
(測試並觀察的程式碼)
**getMultithreadPhysAddr.cpp**
```cpp=
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <sys/syscall.h> /* Definition of SYS_* constants */
#include <unistd.h>
#include <stdlib.h>
#define __NR_sys_my_get_physical_addresses 335
extern void *func1(void *);
extern void *func2(void *);
extern int main();
// void * my_get_physical_addresses(void *);
struct data_
{
int id ;
char name[16] ;
} ;
typedef struct data_ sdata ;
static __thread sdata tx ; //thread local variable
int a=123; //global variable
/* hello.c */
#include <linux/kernel.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
// void * my_get_physical_addresses(void * ptr)
void hello(int pid, int* heapAddress)
{
int b=10; //local varialbe
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", syscall(__NR_sys_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", syscall(__NR_sys_my_get_physical_addresses,&b));
// //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", syscall(__NR_sys_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", syscall(__NR_sys_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", syscall(__NR_sys_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", syscall(__NR_sys_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", syscall(__NR_sys_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 %ld\n", syscall(__NR_sys_my_get_physical_addresses,printf));
printf("=================================================================================\n");
printf("pid : %d\n", pid);
printf("a(Data) ---(va/pa) %p / %p\n", &a, syscall(__NR_sys_my_get_physical_addresses, &a));
printf("b(stack) ---(va/pa) %p / %p\n", &b, syscall(__NR_sys_my_get_physical_addresses, &b));
printf("tx(thread) ---(va/pa) %p / %p\n", &tx, syscall(__NR_sys_my_get_physical_addresses, &tx));
printf("hello(code) ---(va/pa) %p / %p\n", hello, syscall(__NR_sys_my_get_physical_addresses, hello));
printf("func1(code) ---(va/pa) %p / %p\n", func1, syscall(__NR_sys_my_get_physical_addresses, func1));
printf("func2(code) ---(va/pa) %p / %p\n", func2, syscall(__NR_sys_my_get_physical_addresses, func2));
printf("main(code) ---(va/pa) %p / %p\n", main, syscall(__NR_sys_my_get_physical_addresses, main));
printf("printf(lib) ---(va/pa) %p / %p\n", printf, syscall(__NR_sys_my_get_physical_addresses, printf));
printf("heapAddress(heap) ---(va/pa) %p / %p\n", heapAddress, syscall(__NR_sys_my_get_physical_addresses, heapAddress));
printf("=================================================================================\n");
}
void *func1(void *arg)
{
char *p = (char*) arg ;
int pid ;
pid = syscall( __NR_gettid );
tx.id = pid ;
int* heapAddress = (int*)malloc(sizeof(int));
strcpy(tx.name,p) ;
printf("I am thread with ID %d executing func1().\n",pid);
hello(pid, heapAddress);
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 ;
int* heapAddress = (int*)malloc(sizeof(int));
strcpy(tx.name,p) ;
printf("I am thread with ID %d executing func2().\n",pid);
hello(pid, heapAddress);
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 ;
int* heapAddress = (int*)malloc(sizeof(int));
strcpy(tx.name,"MAIN") ;
printf("I am main thread with ID %d.\n", pid);
hello(pid, heapAddress);
// while(1)
// {
// //printf("(%d)(%s)\n",tx.id,tx.name) ;
sleep(5) ;
// }
}
```
> 在一個多Thread的程式中,不同Thread使用 malloc 或其他動態記憶體分配函數分配的空間通常是共用的。這是因為 malloc 返回的記憶體位於進程的heap區域,而heap區域是進程中所有Thread共享的。
## 結果
**output**
```
I am thread with ID 24651 executing func2().
=================================================================================
pid : 24651
a(Data) ---(va/pa) 0x563e81929010 / 0xc1d581929010
b(stack) ---(va/pa) 0x7f09c51fde04 / 0xeaa0c51fde04
tx(thread) ---(va/pa) 0x7f09c51fe62c / 0xeaa0c51fe62c
hello(code) ---(va/pa) 0x563e81926219 / 0xc1d581926219
func1(code) ---(va/pa) 0x563e819264a9 / 0xc1d5819264a9
func2(code) ---(va/pa) 0x563e81926545 / 0xc1d581926545
main(code) ---(va/pa) 0x563e819265e1 / 0xc1d5819265e1
printf(lib) ---(va/pa) 0x7f09c5a606f0 / 0xeaa0c5a606f0
heapAddress(heap) ---(va/pa) 0x7f09b8000b70 / 0xeaa0b8000b70
=================================================================================
I am main thread with ID 24648.
=================================================================================
pid : 24648
a(Data) ---(va/pa) 0x563e81929010 / 0xc1d581929010
b(stack) ---(va/pa) 0x7ffd44dabc24 / 0xeb9444dabc24
tx(thread) ---(va/pa) 0x7f09c5da472c / 0xeaa0c5da472c
hello(code) ---(va/pa) 0x563e81926219 / 0xc1d581926219
func1(code) ---(va/pa) 0x563e819264a9 / 0xc1d5819264a9
func2(code) ---(va/pa) 0x563e81926545 / 0xc1d581926545
main(code) ---(va/pa) 0x563e819265e1 / 0xc1d5819265e1
printf(lib) ---(va/pa) 0x7f09c5a606f0 / 0xeaa0c5a606f0
heapAddress(heap) ---(va/pa) 0x563e82fb8500 / 0xc1d582fb8500
=================================================================================
I am thread with ID 24650 executing func1().
=================================================================================
pid : 24650
a(Data) ---(va/pa) 0x563e81929010 / 0xc1d581929010
b(stack) ---(va/pa) 0x7f09c59fee04 / 0xeaa0c59fee04
tx(thread) ---(va/pa) 0x7f09c59ff62c / 0xeaa0c59ff62c
hello(code) ---(va/pa) 0x563e81926219 / 0xc1d581926219
func1(code) ---(va/pa) 0x563e819264a9 / 0xc1d5819264a9
func2(code) ---(va/pa) 0x563e81926545 / 0xc1d581926545
main(code) ---(va/pa) 0x563e819265e1 / 0xc1d5819265e1
printf(lib) ---(va/pa) 0x7f09c5a606f0 / 0xeaa0c5a606f0
heapAddress(heap) ---(va/pa) 0x7f09c0000b70 / 0xeaa0c0000b70
=================================================================================
```

## Reference
新增syscall
>https://home.gamer.com.tw/creationDetail.php?sn=5696940
切換實際版本kernel
>https://blog.csdn.net/weixin_40837318/article/details/123798456
安裝kernel
>https://0xzx.com/zh-tw/2022111502502852474.html