# 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) ![截圖 2023-11-25 20.28.09](https://hackmd.io/_uploads/BJqiODkHa.png) - 編譯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 ![截圖 2023-11-25 20.28.09](https://hackmd.io/_uploads/BJqiODkHa.png) - 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 ![image](https://hackmd.io/_uploads/rJOVywkra.png) 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 ================================================================================= ``` ![image](https://hackmd.io/_uploads/BkpobRWBa.png) ## 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