# 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