{%hackmd BJrTq20hE %} # Project 1 ###### tags: `Linux` ## Kernel Version * Ubuntu 22.04.2 LTS * Kernel Version 5.19 * virtual box 6.1.38 ## :hammer: Description 1. Requirement : * In this project, you need to write a new system call void * my_get_physical_addresses(void *) so that a process can use it to get the physical address of a virtual address of a process. * The return value of this system call is either 0 or an address value. 0 means that an error occurs when executing this system call. A non-zero value means the physical address of the logical address submitted to the system call as its parameter. 2. //prototype of the new system call is as follows: ```clike= void * my_get_physical_addresses(void *) ``` 3. Write a multi-thread program with three threads using the new system call to show how the following memory areas are shared by these threads. Your program must use variables with storage class __thread. The memory areas include code segments, data segments, BSS segments, heap segments, libraries, stack segments, and thread local storages. You need to draw a figure as follows to show your results. 4. What follows is an example code which you can use to check how the threads of a multi-thread application share their memory. However, you need to add extra code to check whether the threads of a multi-thread application share their heap areas. The heap area of a thread is created by malloc() and released by free(). ```clike= #include <stdio.h> #include <pthread.h> #include <string.h> #include <sys/syscall.h> /* Definition of SYS_* constants */ #include <unistd.h> 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 void hello(int pid) { 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", 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)); //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) ; 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) ; } } ``` 5. Hint * Two threads show a physical memory cell (one byte) if both of them have a virtual address that is translated into the physical address of the memory cell. * The kernel usually does not allocate physical memories to store all code and data of a process when the process starts execution. Hence, if you want kernel to allocate physical memories to a piece of code, execute the code first. If you want kernel to allocate physical memories to a variable, access the variable first. * Inside the Linux kernel, you need to use function copy_from_user() and function copy_to_user() to copy data from/to a user address buffer. * Check the "Referenced Material" part of the Course web site to see how to add a new system call in Linux. --- ## :notebook: NOTE ### Question 1 : How do we create a system call function and compile the kernel? ### Question 2 : How do we get the physical address of a process? * In Linux, there are 4 page tables levels to go through to get to the page table entry. Normally the levels are pgd (page table directory), pud (page upper directory), pmd (page mid directory), and pte (page table entry). (Perhaps p4d was added as an extra page table level.) Typically, the address of the page directory (top-level page table) is stored in the CR3 register. So you use that address to access the directory, then use the pgd_index and pgd_offset to find the address of the next level (p4d) you need to look into, and repeat till you hit the pte. A useful file to see this in action is the [mm/page_walk.c](https://elixir.bootlin.com/linux/latest/source/mm/pagewalk.c) file. * https://stackoverflow.com/questions/41090469/linux-kernel-how-to-get-physical-address-memory-management * https://stackoverflow.com/questions/12040303/how-to-access-physical-addresses-from-user-space-in-linux * https://stackoverflow.com/questions/68499503/how-can-i-convert-virtual-address-from-user-space-to-physical-addressin-linux * https://stackoverflow.com/questions/5748492/is-there-any-api-for-determining-the-physical-address-from-virtual-address-in-li/5748589#5748589 * https://www.kernel.org/doc/html/latest/core-api/printk-formats.html * https://stackoverflow.com/questions/67670169/compiling-kernel-gives-error-no-rule-to-make-target-debian-certs-debian-uefi-ce * https://phoenixnap.com/kb/build-linux-kernel * https://stackoverflow.com/questions/61657707/btf-tmp-vmlinux-btf-pahole-pahole-is-not-available * https://forum.openwrt.org/t/ubuntu-20-04-compile-zstd-error/66619 --- ## Reference : * G. T. Wang, [C 語言 pthread 多執行緒平行化程式設計入門教學與範例。](https://blog.gtwang.org/programming/pthread-multithreading-programming-in-c-tutorial/) * Jason/cntofu.com, [深入 Linux 多線程編程。](https://cntofu.com/book/46/linux_system/shen_rulinux_duo_xian_cheng_bian_cheng.md) * Will, [C pthread_create 傳遞參數的用法 * Chin-Hung Liu,[ Work Note-pthread。](https://medium.com/@chinhung_liu/work-note-pthread-e908d53b557e) * MIT, Thread-Local Storage * [Adding a Hello World System Call to Linux Kernel](https://medium.com/anubhav-shrimal/adding-a-hello-world-system-call-to-linux-kernel-dad32875872) * [在Linux系統中新增system call](https://finonglager2145.pixnet.net/blog/post/63664471-%E5%9C%A8linux%E7%B3%BB%E7%B5%B1%E4%B8%AD%E6%96%B0%E5%A2%9Esystem-call)