# 2025 NCU Linux Project 2 [Group 5]
### 組長:林緯宸(114525001)
### 組員:簡文勝(114522008)、林暐智(114522014)、張文瀚(114522087)
##
## Part 1: Source Code
```c
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/uaccess.h> // copy_to_user
struct my_thread_info_record {
unsigned long pid;
unsigned long tgid;
void *process_descriptor_address;
void *kernel_mode_stack_address;
void *pgd_table_address;
};
SYSCALL_DEFINE1(my_get_thread_kernel_info, void __user *, ubuf)
{
struct my_thread_info_record info;
struct task_struct *task = current;
void *stack_addr;
void *pgd_addr;
if (!ubuf)
return 0; // 0 means that an error occurs when executing this system call
info.pid = task->pid;
info.tgid = task->tgid;
info.process_descriptor_address = (void *)task;
// get the kernel stack address
stack_addr = task_stack_page(task);
info.kernel_mode_stack_address = stack_addr;
// get the pgd (page global directory)
if (task->mm)
pgd_addr = (void *)task->mm->pgd; // user thread using mm
else if (task->active_mm)
pgd_addr = (void *)task->active_mm->pgd; // kernel thread using active_mm
else
pgd_addr = NULL;
info.pgd_table_address = pgd_addr;
// copy to user-space buffer
if (copy_to_user(ubuf, &info, sizeof(info)) != 0)
return 0; // 0 means that an error occurs when executing this system call
return 1; // A non-zero value means that the system is executed successfully.
}
```
### 說明
- 新增了名為my_get_thread_kernel_info的System Call,接受一個型別為void __user * 的參數ubuf,其中__user代表必須是指向user space的指標
- Process Id可透過task->tgid獲取
- Thread Id可透過task->pid獲取
- process_descriptor的位址就是當前運行的Process current所指向的task_struct
- Kernel mode stack起始位址(stack bottom)可透過task_stack_page巨集獲取
- User Process有自己的mm_struct,故可直接取得其中的gdt
- Kernel Process沒有自己的mm_struct,故會使用前一個User Process的mm,即task->active_mm
- 最後使用copy_to_user將以上取得的my_thread_info_record複製到user space的ubuf中
## Part2: Tests
### Test 1
```c
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#define __NR_my_get_thread_kernel_info 548
struct my_thread_info_record{
unsigned long pid;
unsigned long tgid;
void * process_descriptor_address;
void * kernel_mode_stack_address;
void * pgd_table_address;
};
int main(void)
{
struct my_thread_info_record data;
long ret = syscall(__NR_my_get_thread_kernel_info, &data);
if (ret != 0) {
printf("pid=%lu\n", data.pid);
printf("tgid=%lu\n", data.tgid);
printf("process descriptor address=%p\n", data.process_descriptor_address);
printf("kernel mode stack address=%p\n", data.kernel_mode_stack_address);
printf("pgd table address=%p\n", data.pgd_table_address);
} else {
printf("Cannot execute the new system call correctly\n");
}
return 0;
}
```

### Test 2
```c
#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <sys/syscall.h>
#include <unistd.h>
#define __NR_my_get_thread_kernel_info 548
struct my_thread_info_record{
unsigned long pid;
unsigned long tgid;
void * process_descriptor_address;
void * kernel_mode_stack_address;
void * pgd_table_address;
} data;
struct data_
{
int id ;
char name[16] ;
};
typedef struct data_ sdata ;
static __thread sdata tx ; // thread local variable
void hello(int tid)
{
long ret = syscall(__NR_my_get_thread_kernel_info, &data);
if (ret != 0) {
printf("[tid=%d] pid=%lu\n", tid, data.pid);
printf("[tid=%d] tgid=%lu\n", tid, data.tgid);
printf("[tid=%d] process descriptor address=%p\n", tid, data.process_descriptor_address);
printf("[tid=%d] kernel mode stack address=%p\n", tid, data.kernel_mode_stack_address);
printf("[tid=%d] pgd table address=%p\n", tid, data.pgd_table_address);
} else {
printf("[tid=%d] Cannot execute the new system call correctly\n", tid);
}
}
void *func1(void *arg)
{
char *p = (char*) arg ;
int 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) sleep(1);
}
void *func2(void *arg)
{
char *p = (char*) arg ;
int 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) sleep(2);
}
int main(void)
{
pthread_t id[2];
char p[2][16] ;
int pid;
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]);
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) sleep(5);
return 0;
}
```
