1. Giới thiệu chung
System call là một cơ chế trong Linux cho phép các ứng dụng trong user space có thể tương tác với kernel space
Khi người dùng tương tác với các chương trình khác nhau yêu cầu tài nguyên hệ thống như mạng, hệ thống tệp, bộ nhớ và CPU. Chương trình này sẽ gửi yêu cầu sử dụng tài nguyên đó đến kernel thông qua việc gọi các system call.
Ngoài ra, việc gọi các system call được thực hiện như cơ chế exception.
Ví dụ: Thực hiện ghi dữ liệu vào file thông qua system call write
![](https://vinalinux.com.vn/wp-content/uploads/2024/01/image.png)
Mã assembly của hàm write (ví dụ kiến trúc trên chip Intel):
![](https://vinalinux.com.vn/wp-content/uploads/2024/01/image-1.png)
Khi đó, hệ điều hành sẽ thực hiện push số hiệu của sys_write (số hiệu 4) vào thanh ghi đặc biệt. Sau đó, ngắt 0x80 (giá trị này sẽ khác nhau ứng với từng kiến trúc chip) sẽ được gọi ra để kernel thực hiện xử lý công việc ghi dữ liệu vào file.
![](https://vinalinux.com.vn/wp-content/uploads/2024/01/image-2.png)
2. Triển khai System call
System call table
Như đã nói ở trên, việc thực hiện 1 system call cũng tuân theo cơ chế như khi thực hiện các exception. Chính vì vậy, tương tự như với exception, hệ điều hành quản lý các system call qua một bảng – system call table
![](https://vinalinux.com.vn/wp-content/uploads/2024/01/image-3.png)
Cột đầu tiên là offset của các system call tương ứng trong system call table. Giá trị offset này với số hiệu (số thự tự trong bảng)đã đề cập ở trên là 2 giá trị khác nhau. Mỗi offset sẽ được định nghĩa bởi các macro để dễ dàng sử dụng. Cột sys_call_table chứa địa chỉ của hàm thực hiện system call tương ứng.
Ngắt 0x80 sẽ tìm kiếm tới bảng sys_call_table để tìm kiếm system call tương ứng với yêu cầu từ người dùng và thực hiện nó. Mỗi system call sẽ được định nghĩa trong các file C riêng biệt.
Ví dụ: system call write có offset là 16 trong sys_call_table. Hàm xử lý System call nằm trên đỉa chỉ 0x100
![](https://vinalinux.com.vn/wp-content/uploads/2024/01/image-4.png)
Luồng thực hiện một system call
![](https://vinalinux.com.vn/wp-content/uploads/2024/01/image-5.png)
Hình trên mô tả cách hoạt động của hàm printf(), nó sẽ gọi ra system call write trên hệ thống và ghi buffer đã nhập vào file STDOUT (có fd = 1) để in chuỗi ra màn hình.
Sau đó, hệ thống thực hiện gọi ra exception (0x64 – system call interrupt trên kiến trúc ARM) trong Interrupt table của kernel. Hàm syscall này sẽ tìm kiếm trong sys_call_table hàm xử lý system call write (sys_write) và thực hiện gọi ra hàm này để xử lý công việc ghi chuỗi ký tự ra màn hình.
Memory checking
Do dữ liệu truyền vào trong hàm gọi trên user space và dưới kernel khi thực hiện system call nằm trên 2 vùng không gian địa chỉ ảo khác nhau (ví dụ địa chỉ 0x10 trên không gian của kernel sẽ có thể không mang cùng 1 giá trị với địa chỉ 0x10 trên khôn gian của user space)
Vì vậy, kernel cần có cơ chế để truy cập vào không gian địa chỉ khác và đồng thời cũng cần kiểm tra xem địa chỉ đó đã được mapping vào địa chỉ vật lý nào hay không. Cơ chế này gọi là memory checking, nó thông qua 2 hàm:
- access_ok()
- verify_area()
Kernel thực hiện việc trao đổi dữ liệu với user space bằng các hàm: get_user(), put_user(), coppy_from_user(), coppy_to_user()
System call switch context
Process sẽ rơi vào trạng thái ngủ khi gọi ra các system call. Chính vì điều này, chúng ta cần phải cân nhắc việc sử dụng system call trong các ứng dụng yêu cầu ghi dữ liệu với tốc độ cao. Để khắc phục được điều này, thường sử dụng shared memory.
Các system call sẽ được cấp toàn quyền trên hệ thống. Trên thực tế, chúng ta thường gặp lỗi permission denied khi cố gắng ghi vào một file không cấp quyền write. Điều này xảy ra không phải do kernel không thể thực hiện mà là do kernel sẽ thực hiện check quyền trước khi thực hiện và trả về permission denied nếu như không được phép.