TRƯỜNG ĐẠI HỌC BÁCH KHOA - ĐẠI HỌC QUỐC GIA TP HỒ CHÍ MINH KHOA KHOA HỌC VÀ KỸ THUẬT MÁY TÍNH MƠN HỌC: HỆ ĐIỀU HÀNH Bài tập lớn System Call GVHD: La Hoàng Lộc SVTH: Nguyễn Xuân Trực - 1513804 Lớp: Hồ Chí Minh, 05/2020 L01 Trường Đại học Bách Khoa – Đại học Quốc Gia TP Hồ Chí Minh Khoa Khoa học Kỹ thuật Máy tính Mục lục Biên dịch Linux Kernel 1.1 Chuẩn bị 1.2 Cấu hình 1.3 Xây dựng kernel cấu hình 1.4 Cài đặt kernel Làm gọn kernel (trim the kernel) System Call 3.1 Hiện thực system call 3.2 Testing 3.3 Wrapper 3.4 Validation Bài tập lớn - Hệ điều hành , 2019 - 2020 Trang 1/9 Trường Đại học Bách Khoa – Đại học Quốc Gia TP Hồ Chí Minh Khoa Khoa học Kỹ thuật Máy tính Biên dịch Linux Kernel 1.1 Chuẩn bị Thiết lập máy ảo (Virtual machine): Trong tập lớn này, cài đặt Ubuntu 18.04 máy ảo VirtuaBox Và cấp phát cho máy ảo đủ RAM cần thiết, dung lượng ổ cứng tối thiểu 40GB Cài đặt core packages: Sau cài xong máy ảo, cài Ubuntu’s toolchain (gcc, make): $ sudo apt-get update $ sudo apt-get install build-essential Sau cài kernel-package: $ sudo apt-get install kernel-package Câu hỏi: Tại phải cài kernel-package? Trả lời: Bởi kernel-package có nhiều phiên hạt nhân (kernel) để lựa chọn cho phù hợp với cấu hình phần cứng máy ảo (hay máy thật) bạn Tạo thư mục biên dịch kernel: Tiếp theo, ta tạo thư mục kernelbuild Home Sau tải kernel source giải nén, tập lớn này, ta sử dụng phiên kernel 5.0.5: $ mkdir ~/kernelbuild $ cd ~/kernelbuild $ wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.0.5.tar.xz $ tar -xvJf linux-5.0.5.tar.xz Câu hỏi: Tại phải sử dụng kernel source khác từ server http://www.kernel.org Chúng ta biên dịch kernel source gốc (kernel OS hành) trực tiếp không? Trả lời: Được, biên dịch hạt nhân gốc (the original kernel) tệp OS sử dụng, kernel mặc định vận chuyển với Debian xử lý hầu hết cấu hình Ngồi ra, Debian thường cung cấp số kernel thay thế, cần kiểm tra trước kernel tương thích tốt với cấu hình phần cứng, nhiên lợi ích cụ thể biên dịch từ kernel từ server để: • Xử lý nhu cầu phần cứng đặc biệt, xung đột phần cứng với kernel cung cấp trước • Sử dụng tùy chọn sử dụng kernel mà không hỗ trợ kernel cung cấp trước (chẳng hạn hỗ trợ nhớ cao) • Tối ưu hóa kernel cách loại bỏ trình điều khiển vơ ích để tăng tốc độ khởi động • Tạo monolithic thay kernel modularized • Chạy cập nhật kernel dành cho nhà phát triển 1.2 Cấu hình Cấu hình kernel nằm file config, cách cài đặt lại tùy chỉnh file cấu hình giúp kernel máy tính hoạt động cách hiệu Chúng ta copy file cấu hình kernel OS sang thư mục linux-5.0.5: Bài tập lớn - Hệ điều hành , 2019 - 2020 Trang 2/9 Trường Đại học Bách Khoa – Đại học Quốc Gia TP Hồ Chí Minh Khoa Khoa học Kỹ thuật Máy tính $ cp /boot/config-$(uname -r) ~/kernelbuild/.config Sau đó, đổi tên lại phiên kernel Để tùy chỉnh file cấu hình thơng qua terminal interface, ta phải cài đặt thêm package cần thiết: $ sudo apt-get install fakeroot ncurses-dev xz-utils bc flex libelf-dev bison libncurses5-dev openssl libssl-dev Và chạy lệnh make menuconfig make nconfig để mở Kernel Configuration: $ make nconfig Để thay đổi phiên kernel, chọn General setup option -> (-ARCH) Local version - append to kernel release, sau nhập vào 1513804 Lưu file lại thoát 1.3 Xây dựng kernel cấu hình Đầu tiên ta phải biên dịch kernel tạo máy ảo vmlinuz Việc khoảng thời gian dài Trong terminal, di chuyển đến thư mục linux-5.0.5 command: $ make Hoặc $ make -j Sau xây dựng loadable kernel modules: $ make modules Hoặc $ make -j modules Câu hỏi: Ý nghĩa command make make modules gì? Những tạo để làm gì? Trả lời: • make: biên dịch liên kết kernel image Kết tạo file có tên vmlinuz • make modules: biên dịch module Kết tạo file nhị phân 1.4 Cài đặt kernel Đầu tiên cài đặt modules: $ sudo make modules_install Hoặc $ sudo make -j modules_install Sau cài đặt kernel mới: Bài tập lớn - Hệ điều hành , 2019 - 2020 Trang 3/9 Trường Đại học Bách Khoa – Đại học Quốc Gia TP Hồ Chí Minh Khoa Khoa học Kỹ thuật Máy tính $ sudo make install Hoặc $ sudo make -j install Sẽ thời gian để hoàn thành việc cài đặt kernel Sau cài đặt xong, khởi động lại máy: $ sudo reboot Sau khởi động lại, kiểm tra việc cài đặt command sau: $ uname -r Kết quả: kết có chứa MSSV, việc biên dịch cài đặt thành công Làm gọn kernel (trim the kernel) Sau cài đặt kernel thành công, có kernel với cấu hình mặc định Nó bao gồm gói hỗ trợ tất thứ, dẫn đến dư thừa không cần thiết Với cấu hình này, nhiều thời gian để biên dịch Trong khuôn khổ tập lớn này, cần cấu hình kernel khác cho máy Cụ thể, nên mở lại make nconfig để chọn cấu hình phù hợp cho máy Nó cung cấp cho loạt menu, từ chọn tùy chọn ta muốn đưa vào Sau cấu hình, biên lại lại kernel System Call 3.1 Hiện thực system call Trong thư mục kernelbuild, tạo thư mục có tên get_proc_info, sau tạo file sys_get_proc_info.c bên thư mục get_proc_info: $ cd ~/kernelbuild $ mkdir get_proc_info $ cd get_proc_info $ touch sys_get_proc_info.c Sau viết code vào file sys_get_proc_info.c: Bài tập lớn - Hệ điều hành , 2019 - 2020 Trang 4/9 Trường Đại học Bách Khoa – Đại học Quốc Gia TP Hồ Chí Minh Khoa Khoa học Kỹ thuật Máy tính #include #include #include #include #include 10 struct proc_info { pid_t pid; char name[16]; } 11 12 13 14 15 16 17 struct procinfos { long studentID; struct proc_info proc; struct proc_info parent_proc; struct proc_info oldest_child_proc; }; 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 asmlinkage long sys_get_proc_info(pid_t pid, struct procinfos *info){ struct task_struct *task = pid_task ( find_vpid ( pid ) , PIDTYPE_PID); printk("Finding \n"); for_each_process(task) { printk("[%d] - [%s]\n", task->pid, task->comm); if(task->pid == pid) { if(task->mm != NULL){ //struct proc_info proc; struct procinfos buff; buff.studenID = 1513804; buff.proc.pid = task->pid; buff.proc.name = task->comm; buff.parent_proc.pid = task->real-parent->pid; buff.oldest_child_proc.pid = task->children->pid; int res = copy_to_user(info, &buff, sizeof(buff)); if(res == 0) printk("success!"); else printk("fail"); return 0; } } } return -1; } Sau đó, tạo Makefile: $ pwd ~/kernelbuild/get_proc_info $ touch Makefile $ echo "obj-y := get_proc_info.o" » Makefile Sau vào kernel Makefile, tìm dịng: Bài tập lớn - Hệ điều hành , 2019 - 2020 Trang 5/9 Trường Đại học Bách Khoa – Đại học Quốc Gia TP Hồ Chí Minh Khoa Khoa học Kỹ thuật Máy tính core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ bổ sung thành: core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ get_proc_info/ Tiếp theo, bổ sung system call vào system call table: $ pwd ~/kernelbuild/ $ cd arch/x86/entry/syscalls/ $ echo "548 64 get_proc_info sys_get_proc_info" » syscall_64.tbl Câu hỏi: Ý nghĩa thông tin thêm vào system call table (548 64 get_proc_info sys_get_proc_info)? Trả lời: Các system call system call table có định dạng: • 548: (số thứ tự) • 64: : chứa giá trị: "common", "64" hệ thống 64-bit, "x32" hệ thống 32-bit • get_proc_info: : tên system call • sys_get_proc_info: Tiếp theo, bổ sung system call vào file system call header: $ ~/kernelbuild/include/linux/ Mở file syscalls.h bổ sung dòng sau vào trước #endif : struct proc_info; struct procinfos; asmlinkage long sys_get_proc_info(pid_t pid, struct procinfos *info); Câu hỏi: Ý nghĩa dòng trên? Trả lời: Các dòng bổ sung vào file header (syscalls.h) nhằm mục đích khai báo struct proc_info, procinfos hàm sys_get_proc_info(pid_t pid, struct procinfos *info) Cuối cùng, biên dịch lại kernel khởi động lại hệ thống để áp dụng kernel mới: $ make -j $ make modules -j $ sudo make modules_install $ sudo make install $ sudo reboot Bài tập lớn - Hệ điều hành , 2019 - 2020 Trang 6/9 Trường Đại học Bách Khoa – Đại học Quốc Gia TP Hồ Chí Minh Khoa Khoa học Kỹ thuật Máy tính 3.2 Testing Sau khởi động vào kernel mới, tạo chương trình C nhỏ để kiểm tra system call tích hợp chưa vào kernel hay chưa: #include #include #include #define SIZE 200 10 11 12 int main(){ long sys_return_value; unsigned long info[SIZE]; sys_return_value = syscall(548, -1, &info); printf("My student ID: %lu\n", info[0]); return 0; } Câu hỏi: Tại chương trình cho biết liệu hệ thống chúng tơi có hoạt động hay khơng? Trả lời: Chương trình in MSSV thêm vào file sys_get_proc_info.c Nếu không in MSSV, system call thất bại 3.3 Wrapper Mặc dù system call get_proc_info hoạt động đúng, cần phải cải tiến để thuận tiện cho lập trình viên khác Chúng ta cần triển khai C wrapper để dễ dàng sử dụng Để tránh biên dịch kernel lại lần nữa, tạo thư mục khác để lưu trữ mã nguồn cho chương trình wapper Trước tiên tạo header file chương trình wrapper cấu trúc procinfos, proc_info Chúng ta đặt tên cho header file get_proc_info.h chứa nội dung sau: #ifndef _GET_PROC_INFO_H_ #define _GET_PROC_INFO_H_ #include #include struct proc_info { pid_t pid; char name[16]; }; 10 11 12 13 14 15 16 struct procinfos { long studentID; struct proc_info proc; struct proc_info parent_proc; struct proc_info oldest_child_proc; }; 17 18 19 long sys_get_proc_info(pid_t pid, struct procinfos *info); #endif // _GET_PROC_INFO_H_ Câu hỏi: Tại phải định nghĩa lại cấu trúc procinfos proc_info định nghĩa bên kernel? Bài tập lớn - Hệ điều hành , 2019 - 2020 Trang 7/9 Trường Đại học Bách Khoa – Đại học Quốc Gia TP Hồ Chí Minh Khoa Khoa học Kỹ thuật Máy tính Trả lời: Sau tạo file get_proc_info.c để giữ mã nguồn cho wrapper Nội dung file sau: #include #include #include #include "get_proc_info.h" long get_proc_info(pid_t pid, struct procinfos *info) { return syscall(548, pid, info); } 3.4 Validation Tiếp theo, copy file header get_proc_info.h vào /usr/include: $ sudo cp /usr/include Câu hỏi: Tại root lại đặc quyền? (Ví dụ phải thêm sudo trước cp để copy file header sang /usr/include)? Trả lời: thư mục /usr thuộc quền sử hữu root nên cần copy phải đc cho phép root Sau ta biên dịch source code đối tượng chia phép người dùng truy cập system call ta thông qua ứng dụng họ: $ gcc -shared -fpic get_proc_info.c -o libget_proc_info.so Sau biên dịch thành công, copy file libget_proc_info.so sang /usr/lib: $ sudo cp libget_proc_info.so /usr/lib Câu hỏi: Tại ta phải thêm -shared -fpic gcc command? Trả lời: Bước cuối để kiểm tra toàn cơng việc, sử dụng chương trình sau biên dịch với tùy chọn get_proc_info option: #include #include #include #include #include 10 11 12 13 14 15 int main() { pid_t mypid = getpid(); printf("PID: %d\n", mypid); struct procinfos info; if(get_proc_info(mypid, &info) == 0) { printf("My student ID: %lu/n", info.studentID); printf("Process with pid or current process: %llu\n", info.proc.pid); printf("Parent process: %llu\n", info.parent_proc.pid); printf("Oldest child process: %llu\n", info.oldest_child_proc.pid); Bài tập lớn - Hệ điều hành , 2019 - 2020 Trang 8/9 Trường Đại học Bách Khoa – Đại học Quốc Gia TP Hồ Chí Minh Khoa Khoa học Kỹ thuật Máy tính } else { printf("Cannot get information from the process %d\n", mypid); } return 0; 16 17 18 19 20 } Bài tập lớn - Hệ điều hành , 2019 - 2020 Trang 9/9 ... Bài tập lớn - Hệ điều hành , 2 019 - 2020 Trang 1/ 9 Trường Đại học Bách Khoa – Đại học Quốc Gia TP Hồ Chí Minh Khoa Khoa học Kỹ thuật Máy tính Biên dịch Linux Kernel 1. 1 Chuẩn bị Thiết... pid; char name [16 ]; }; 10 11 12 13 14 15 16 struct procinfos { long studentID; struct proc_info proc; struct proc_info parent_proc; struct proc_info oldest_child_proc; }; 17 18 19 long sys_get_proc_info(pid_t... printf("Cannot get information from the process %d
", mypid); } return 0; 16 17 18 19 20 } Bài tập lớn - Hệ điều hành , 2 019 - 2020 Trang 9/9