Kernel và ranh giới cô lập
- 1Intro and Overview
- 2Kernel và ranh giới cô lậpThis article
- 3Page Tables
Yêu cầu của một hệ điều hành
Mục tiêu đầu tiên của một hệ điều hành là cho phép nhiều việc chạy cùng lúc. Ví dụ, ta dùng fork và exec để chạy đồng thời một compiler và một editor. Để làm được điều đó, hệ điều hành phải có ba khả năng:
- Multiplexing: chia sẻ tài nguyên, để một CPU có thể chạy xen kẽ giữa compiler và editor.
- Isolation: cô lập các tiến trình, để tiến trình này lỗi không làm hỏng tiến trình khác. Nếu editor bị crash, compiler vẫn chạy bình thường.
- Interaction: các tiến trình vẫn phải trao đổi được thông tin với nhau khi cần. Từ đây nảy sinh một vấn đề: isolation không thể tuyệt đối, vì nếu cô lập hoàn toàn thì pipe sẽ không hoạt động. Do đó, hệ điều hành phải cân bằng được giữa isolation và interaction.
Android là một ví dụ thực tế rất rõ. Mỗi ứng dụng chạy dưới một Linux UID riêng, trong một sandbox riêng, không đọc được file và không nhìn thấy bộ nhớ của ứng dụng khác. Đó là isolation rất mạnh, và nhờ nó, một ứng dụng quảng cáo rác không dễ gì móc được dữ liệu ngân hàng của bạn.
Nhưng cũng chính vì thế, một việc tưởng chừng tầm thường như mở một tấm ảnh do ứng dụng khác tạo ra lại phải đi qua ContentProvider, qua Binder IPC, qua FileProvider với URI tạm thời có thời hạn, rồi qua hộp thoại xin quyền. Lập trình viên phải viết hàng chục dòng code chỉ để làm điều mà trên desktop Linux cũ chỉ cần một lời gọi open() với đường dẫn.
Tăng cô lập thêm một nấc thì interaction phải trả giá bằng độ trễ, độ phức tạp, và cả những khoảnh khắc người dùng phải đứng đó bấm “Allow”.
Tại sao cần hệ điều hành?
Có một cách suy nghĩ khác: biến các system call thành một thư viện để ứng dụng link vào, và để ứng dụng tự điều khiển phần cứng. Một số hệ thống nhúng và hệ điều hành thời gian thực (RTOS) như Zephyr hay ThreadX làm đúng như vậy, vì cách này nhanh và dễ dự đoán thời gian chạy.
Nhưng khi có nhiều ứng dụng, mọi ứng dụng đều phải hoạt động một cách đúng đắn, ví dụ phải tự nhường CPU định kỳ. Cách này gọi là cooperative time-sharing (chia sẻ thời gian kiểu hợp tác). Nó chỉ ổn khi mọi ứng dụng tin nhau và không có lỗi. Thực tế thì lại khác: các ứng dụng thường không tin nhau và có lỗi. Chỉ cần một vòng lặp vô hạn là đủ khiến cả hệ thống bị treo.
Do đó, để cô lập mạnh, hệ điều hành không cho ứng dụng chạm thẳng vào phần cứng, mà bọc tài nguyên thành các dịch vụ trừu tượng. Ví dụ:
| Tài nguyên | Thay vì truy cập trực tiếp | Unix cung cấp | Lợi ích |
|---|---|---|---|
| Ổ đĩa | Đọc/ghi từng sector | open, read, write, close | Có đường dẫn file tiện dụng. Kernel toàn quyền quản lý đĩa |
| CPU | Ứng dụng tự nhường CPU | Kernel tự động chuyển CPU giữa các tiến trình, lưu và khôi phục thanh ghi | Ứng dụng không cần biết mình đang bị chia sẻ. Kể cả vòng lặp vô hạn cũng không làm treo máy |
| Bộ nhớ | Ứng dụng tự chọn vùng RAM vật lý | exec dựng ảnh bộ nhớ cho tiến trình | Kernel quyết định đặt tiến trình ở đâu, thậm chí đẩy bớt dữ liệu ra đĩa khi thiếu RAM. Chương trình được lưu dưới dạng file |
| Giao tiếp | Tự trao đổi dữ liệu | File descriptor | Ẩn chi tiết dữ liệu nằm ở pipe hay file. Nếu tiến trình trước trong pipeline thoát, kernel tự báo end-of-file cho tiến trình sau |
Giao diện system call của Unix được thiết kế để vừa tiện cho lập trình viên, vừa cho phép cô lập mạnh. Đây không phải cách duy nhất, nhưng đã được chứng minh là một cách tốt.
User mode, supervisor mode và system call
Cô lập mạnh nghĩa là ứng dụng, dù có lỗi hay cố tình phá hoại, cũng không được sửa, thậm chí đọc, dữ liệu và code của kernel, hay truy cập bộ nhớ của tiến trình khác. Phần mềm thuần tuý không làm được việc này, mà cần CPU hỗ trợ bằng phần cứng thông qua các mức quyền (privilege levels).
Ba mức quyền của RISC-V

Hiểu đơn giản thì:
- Code chạy ở user mode thuộc user space.
- Code chạy ở supervisor mode thuộc kernel space. Phần mềm chạy ở đây gọi là kernel.
Tổ chức kernel
Có một câu hỏi được đặt ra: phần nào của hệ điều hành nên chạy ở supervisor mode? Từ đó hình thành hai trường phái chính.
Monolithic kernel (kernel nguyên khối)
Toàn bộ hệ điều hành nằm trong kernel. Mọi system call đều được xử lý ở supervisor mode, và cả hệ điều hành là một chương trình duy nhất.
Comming soon.
Microkernel
Mục tiêu của microkernel là giảm bug trong kernel, bằng cách chỉ giữ lại tối thiểu chức năng trong kernel. Khi đó, rất ít code chạy ở supervisor mode, và kernel dễ hiểu, dễ kiểm chứng tính đúng đắn.
Phần lớn hệ điều hành chạy dưới dạng các server ở user mode.
Comming soon.














