User mode và kernel mode trong hđh linux

Trong bài trước tôi đã giới thiệu với các bạn những kiến thức cơ bản về các thành phần chính của Windows OS. Bạn có thể tham khảo trước tại đây. Trong bài này, tôi xin trình bày về hai chế độ User Mode và Kernel Mode trong Windows OS.

User mode and kernel mode

Một bộ vi xử lý khi chạy Windows OS sẽ có hai chế độ khác nhau được gọi là: User Mode và Kernel Mode. Các chương trình (applications) thường chạy trên User Mode, còn các thành phần lõi của hệ điều hành sẽ chạy ở Kernel Mode. Thường thì khái niệm Driver dùng cho những chương trình chạy tại Kernel Mode, nhưng cũng có một vài Driver chạy trên User Mode. Hình minh họa phía dưới mô phỏng sự kết nối giữa các thành phần ở User Mode và Kernel Mode

Khi viết các ứng dụng chạy trên Windows, Microsoft cung cấp các hàm lập trình ứng dụng (Windows applications programming interface – Win API) để lập trình viên sử dụng. Với việc sử dụng các Windows API, bạn sẽ phát triển được các ứng dụng hoạt động ổn định trên tất cả các phiên bản của Windows.

Các Windows API này có thể giao tiếp với các UserMode Drivers để thực hiện một số nhiệm vụ nhất định trên UserMode. Ngoài ra, Microsoft cũng hỗ trợ các Native API (thực chất cũng là các Windows API, nhưng được cung cấp bởi một subsystem module như Kernel32.dll hoăc NTDLL.dll). Đó là một cơ chế cho phép chương trình ở UserMode có thể gọi các chương trình con (a subroutine) thực thi ở KernelMode. Ví dụ: DbgPrint function…

Ở KernelMode, sẽ có một cơ chế phục vụ những yêu cầu từ ứng dụng trên UserMode và tương tác với các thiết bị (device) theo một cách nào đó. Cơ chế này đảm bảo cho việc các tham số sử dụng đều là hợp lệ, và đảm bảo việc không cho phép xử lý tới vùng dữ liệu hoặc địa chỉ mà chương trình ở UserMode không được phép thao tác tới.

User mode

Khi một chương trình khởi tạo trên User Mode, Windows sẽ tạo một tiến trình (process) cho chương trình đó. Một tiến trình cung cấp cho chương trình đó một không gian địa chỉ ảo (Virtual address space). Bởi vì mỗi không gian  địa chỉ ảo của mỗi tiến trình là riêng biệt, nên một chương trình khó hay còn có thể nói là không thể thay đổi dữ liệu thuộc về một chương trình khác. Do mỗi chương trình chạy một cách cô lập như vậy, nên nếu một chương trình bị đổ vỡ (crash), thì sự đổ vỡ này sẽ được giới hạn trong chương trình đó. Những chương trình khác và hệ điều hành sẽ không bị ảnh hưởng bởi sự đổ vỡ này.

Kernel mode

Không gian địa chỉ ảo của mỗi tiến trình ở User Mode bị giới hạn. Một chương trình chạy tại User Mode sẽ không xử lý được những địa chỉ ảo (Vrtual address) được dự trữ để sử dụng bởi hệ điều hành. Sự giới hạn không gian địa chỉ nhằm bảo vệ những chương trình khỏi việc xử lý nhầm vào những vùng dữ liệu quan trọng, có thể gây hại tới hệ điều hành. Tất cả đoạn mã được viết ở Kernel Mode chia sẻ một không gian địa chỉ duy nhất. Điều đó có nghĩa một kernel-mode driver sẽ không bị cô lập với những driver khác và bản thân hệ điều hành. Nếu một kernel mode driver ghi nhầm địa chỉ hoặc dữ liệu thuộc về hệ điều hành hoặc một driver khác thì những chương trình này sẽ bị tổn hại. Khi đó, việc xử lý sai này có thể khiến driver đó bị crash. Mà khi một driver bị crash ở Kernel Mode thì có thể dẫn tới toàn bộ hệ điều hành bị crash. Khi đó máy tính của bạn sẽ xảy ra hiện tượng bị treo hoặc xuất hiện màn hình xanh (Blue Screen of Death – BSoD). Ở phần này, tôi xin phép được nói về khái niệm cơ bản của Kernel Mode và User Mode, trong đó có một khái niệm được nhắc tới nhiều là không gian địa chỉ ảo (Virtual Address Space). Trong bài tiếp theo, tôi sẽ đi vào trình bày chi tiết về Virtual Address Space cũng như đi sâu  hơn vào User Mode và Kernel để các bạn thấy được Windows sử dụng hai chế độ này với mỗi chương trình có sự khác biệt như thế nào.

User mode và kernel mode trong hđh linux

Giới thiệu

Trước khi học về Linux device driver, chúng ta sẽ tìm hiểu về hệ điều hành nói chung và Linux kernel nói riêng. Bài học này tập trung vào các vấn đề sau:

  • Hệ thống máy tính gồm những thành phần nào?
  • Hệ điều hành là gì? Hệ điều hành có vai trò gì trong hệ thống máy tính?
  • Linux kernel có cấu trúc như thế nào?
  • Các khái niệm hay dùng trong Linux kernel.

Hệ thống máy tính.

Hệ thống máy tính bao gồm 2 thành phần: phần cứng và phần mềm. Phần cứng bao gồm các thành phần sau:

  • RAM: chứa phần mềm. Phần mềm là một tập hợp các lệnh và dữ liệu.
  • CPU: liên tục lấy các lệnh từ RAM vào rồi thực thi. Chuỗi các lệnh này sẽ hướng dẫn CPU xử lý dữ liệu trong RAM hoặc dữ liệu từ I/O module, nhằm đạt được một chức năng nào đó. CPU cũng phát ra các tín hiệu điều khiển hoạt động của toàn bộ hệ thống.
  • I/O module: cung cấp dữ liệu cho CPU xử lý và trả ra kết quả xử lý của CPU.
  • Hệ thống bus: kết nối CPU, RAM, I/O module lại với nhau. Hệ thống bus được chia làm 3 loại:
    • Bus dữ liệu: vận chuyển các lệnh từ RAM đến CPU. Bus dữ liệu cũng vận chuyển dữ liệu giữa CPU, RAM và I/O module.
    • Bus địa chỉ: vận chuyển địa chỉ được phát ra từ CPU để xác định vị trí của lệnh và dữ liệu.
    • Bus điều khiển: vận chuyển các tín hiệu điều khiển từ CPU, như đọc hay ghi, trao đổi dữ liệu với RAM hay I/O module. Ngoài ra, bus điều khiển cũng vận chuyển các tín hiệu báo hiệu từ RAM hoặc I/O module tới CPU.

User mode và kernel mode trong hđh linux

Hình 1 Sơ đồ khối của một hệ thống máy tính

Xét hệ thống nhấp nháy đèn LED. Đây là một hệ thống máy tính đơn giản, chỉ có một chức năng. Trong hệ thống này, ta chỉ cần viết một phần mềm, rồi nạp lên vi điều khiển. Phần mềm đó được quyền sử dụng toàn bộ phần cứng, như CPU, RAM, I/O module.

Xét máy tính cá nhân. Đây là một hệ thống máy tính phức tạp, có nhiều chức năng. Trong hệ thống này, có nhiều phần mềm cùng chạy, ví dụ như phần mềm Microsoft Word, Window Media Player, Internet Download Manager... Vì phần cứng chỉ có một CPU đơn lõi, một ổ cứng, nhưng lại có nhiều phần mềm cùng sử dụng, nên sẽ xảy ra tranh chấp. Để tránh xảy ra vấn đề này, cần có một phần mềm đứng ra quản lý việc sử dụng phần cứng. Phần mềm ấy là hệ điều hành (Operating System).

Hệ điều hành.

Thuật ngữ "hệ điều hành" có thể được hiểu theo 2 nghĩa:

  • Theo nghĩa hẹp, hệ điều hành là một phần mềm quản lý tài nguyên phần cứng. Phần mềm này còn được gọi là nhân (kernel). Ví dụ Linux kernel.
  • Theo nghĩa rộng, hệ điều hành là một gói phần mềm gồm:
    • Phần mềm quản lý các tài nguyên phần cứng.
    • Các phần mềm quan trọng khác như phần mềm giao diện dòng lệnh (CLI – Command Line Interpreter), phần mềm giao diện đồ họa (GUI – Graphic User Interface), …

Các thuật ngữ ta vẫn thường dùng như hệ điều hành Windows 7, Ubuntu, macOS, Android… đều được hiểu theo nghĩa rộng. Tuy nhiên, trong khóa học này, chúng ta sẽ hiểu rằng: hệ điều hành đồng nghĩa với kernel.

Với sự ra đời của hệ điều hành, phần mềm được chia làm 2 loại: hệ điều hành và chương trình ứng dụng (gọi tắt là chương trình)Chương trình được tạo ra sau quá trình biên dịch mã nguồn (source code). Các lệnh và dữ liệu của chương trình được đóng gói thành một file và được lưu trong ổ cứng. Chương trình có một hàm main, là nơi bắt đầu quá trình thực thi.

Quá trình CPU thực thi một chương trình được gọi là tiến trình (process). Tiến trình được tạo ra khi ta khởi chạy chương trình, ví dụ bằng cách nhấp đúp chuột vào biểu tượng của chương trình. Khi đó, hệ điều hành sẽ cấp phát một vùng nhớ trên RAM, rồi đưa chương trình (hoặc một phần chương trình) vào trong vùng nhớ đó. Hệ điều hành cũng tạo ra một cấu trúc dữ liệu, chứa các thông tin như số định danh (ID), tên, thời điểm tạo, vị trí trên RAM,... Sau đó, CPU sẽ bắt đầu thực thi từ hàm main. Kể từ lúc này, ta có một tiến trình.

Để cho dễ hình dung, các bạn hãy liên tưởng như sau: bạn tương tự như CPU, kế hoạch học ngoại ngữ của bạn tương tự như chương trình, còn quá trình bạn thực hiện kế hoạch đó tương tự như tiến trình. Ngoài ra, bạn cũng đang thực hiện nhiều kế hoạch khác, như kế hoạch tán gái, kế hoạch tập thể hình,... Mỗi quá trình đó được quản lý bởi một bản mô tả. Dưới đây là một ví dụ về bản mô tả của quá trình tán gái:

Định danh của quá trìnhTên quá trìnhNgày bắt đầuTrạng thái hiện tại
10 Tán gái 10/10/2010 Đang tạm dừng

Ngoài giữ vai trò quản lý phần cứng, hệ điều hành còn cung cấp các dịch vụ sử dụng phần cứng cho các tiến trình (hình 2). Vì vậy, các lập trình viên không cần phải hiểu phần cứng có cấu tạo như thế nào, hoạt động ra làm sao. Họ chỉ cần biết phần cứng có những chức năng gì, hệ điều hành cung cấp những dịch vụ nào để sử dụng các chức năng ấy, là đã có thể tạo ra các chương trình ứng dụng.

User mode và kernel mode trong hđh linux

Hình 2 Sơ đồ khối chức năng của hệ điều hành

Linux kernel.

Vào năm 1991, dựa trên UNIX kernel, Linus Torvalds đã tạo ra Linux kernel chạy trên máy tính của ông ấy. Dựa vào chức năng của hệ điều hành, Linux kernel được chia làm 6 thành phần (hình 3):

  • Process management: có nhiệm vụ quản lý các tiến trình, bao gồm các công việc:
    • Tạo/hủy các tiến trình.
    • Lập lịch cho các tiến trình. Đây thực chất là lên kế hoạch: CPU sẽ thực thi chương trình khi nào, thực thi trong bao lâu, tiếp theo là chương trình nào.
    • Hỗ trợ các tiến trình giao tiếp với nhau.
    • Đồng bộ hoạt động của các tiến trình để tránh xảy ra tranh chấp tài nguyên.
  • Memory management: có nhiệm vụ quản lý bộ nhớ, bao gồm các công việc:
    • Cấp phát bộ nhớ trước khi đưa chương trình vào, thu hồi bộ nhớ khi tiến trình kết thúc.
    • Đảm bảo chương trình nào cũng có cơ hội được đưa vào bộ nhớ.
    • Bảo vệ vùng nhớ của mỗi tiến trình.
  • Device management: có nhiệm vụ quản lý thiết bị, bao gồm các công việc:
    • Điều khiển hoạt động của các thiết bị.
    • Giám sát trạng thái của các thiết bị.
    • Trao đổi dữ liệu với các thiết bị.
    • Lập lịch sử dụng các thiết bị, đặc biệt là thiết bị lưu trữ (ví dụ ổ cứng).
  • File system management: có nhiệm vụ quản lý dữ liệu trên thiết bị lưu trữ (như ổ cứng, thẻ nhớ). Quản lý dữ liệu gồm các công việc: thêm, tìm kiếm, sửa, xóa dữ liệu.
  • Networking management: có nhiệm vụ quản lý các gói tin (packet) theo mô hình TCP/IP.
  • System call Interface: có nhiệm vụ cung cấp các dịch vụ sử dụng phần cứng cho các tiến trình. Mỗi dịch vụ được gọi là một system call.

User mode và kernel mode trong hđh linux

Hình 3 Kiến trúc của Linux kernel đứng ở góc độ quản lý (management point of view)

Khi triển khai thực tế, mã nguồn của Linux kernel gồm các thư mục sau:

Bảng 1 Một số thư mục trong mã nguồn của Linux kernel

Thư mục

Vai trò

/arch

Chứa mã nguồn giúp Linux kernel có thể thực thi được trên nhiều kiến trúc CPU khác nhau như x86, alpha, arm, mips, mk68, powerpc, sparc,…

/block

Chứa mã nguồn triển khai nhiệm vụ lập lịch cho các thiết bị lưu trữ.

/drivers

Chứa mã nguồn để triển khai nhiệm vụ điều khiển, giám sát, trao đổi dữ liệu với các thiết bị.

/fs

Chứa mã nguồn triển khai nhiệm vụ quản lý dữ liệu trên các thiết bị lưu trữ.

/ipc

Chứa mã nguồn triển khai nhiệm vụ giao tiếp giữa các tiến trình

/kernel

Chứa mã nguồn triển khai nhiệm vụ lập lịch và đồng bộ hoạt động của các tiến trình.

/mm

Chứa mã nguồn triển khai nhiệm vụ quản lý bộ nhớ

/net

Chứa mã nguồn triển khai nhiệm vụ xử lý các gói tin theo mô hình TCP/IP.

Các khái niệm thường dùng.

Trong phần này, chúng ta sẽ tìm hiểu về một số khái niệm rất hay được sử dụng:

  • User space và kernel space.
  • User mode và kernel mode.
  • System call và ngắt.
  • Process context và interrupt context.

Bộ nhớ RAM chứa các lệnh/dữ liệu dạng nhị phân của Linux kernel và các tiến trình. RAM được chia làm 2 miền (hình 4):

  • Kernel space là vùng không gian chứa các lệnh và dữ liệu của kernel.
  • User space là vùng không gian chứa các lệnh và dữ liệu của các tiến trình.

User mode và kernel mode trong hđh linux

Hình 4 Kiến trúc Linux kernel đứng ở góc độ thực thi của CPU (execution point of view)

CPU có 2 chế độ thực thi (hình 4):

  • Khi CPU thực thi các lệnh của kernel, thì nó hoạt động ở chế độ kernel mode. Khi ở chế độ này, CPU sẽ thực hiện bất cứ lệnh nào trong tập lệnh của nó, và CPU có thể truy cập bất cứ địa chỉ nào trong không gian địa chỉ.
  • Khi CPU thực thi các lệnh của tiến trình, thì nó hoạt động ở chế độ user mode. Khi ở chế độ này, CPU chỉ thực hiện một phần tập lệnh của nó, và CPU cũng chỉ được phép truy cập một phần không gian địa chỉ.

Để cho dễ hình dung, ta hãy liên tưởng thế này: CPU giống như bạn, tiến trình giống như công việc của sếp giao cho bạn, còn kernel giống như công việc của vợ giao cho bạn. Khi bạn thực thi các việc của sếp, bạn chỉ thực hiện cho xong, không nỗ lực hết mình, những việc nào mà ảnh hưởng đến quyền lợi của bạn thì bạn không làm. Thái độ làm việc này của bạn giống như chế độ user mode của CPU. Khi bạn thực thi các việc của vợ, bạn thực hiện các việc đó toàn tâm toàn ý, nỗ lực hết mình, dù cho đó là việc gì. Thái độ làm việc này của bạn giống như chế độ kernel mode của CPU.

Để hiểu rõ hơn, ta xét tiến trình 1 trong hình 4. Tiến trình này gồm nhiều lệnh nhị phân, tương ứng với 2 lệnh C. CPU sẽ lần lượt lấy các lệnh này ra và thực thi. Lệnh thứ nhất, "a = 5 + 10", là một lệnh tính toán, sẽ được CPU thực thi ở chế độ user mode. Lệnh thứ hai, "printf("%d", a)", là một lệnh vào/ra. Hàm "printf" sẽ gọi system call "write" để yêu cầu Linux kernel in thông tin ra màn hình. Khi đó, CPU sẽ chuyển sang chế độ kernel mode để thực thi các lệnh của Linux kernel.

User mode và kernel mode trong hđh linux

Hình 5 Các chế độ hoạt động của CPU

Khi một tiến trình cần sử dụng một dịch vụ nào đó của kernel, tiến trình sẽ gọi một system call. System call cũng tương tự như các hàm bình thường khác (library call). Chỉ có điều, các library call được cung cấp bởi các thư viện trong user space, còn các system call được cung cấp bởi kernel. Do đó, khi tiến trình gọi các library call, CPU vẫn giữ nguyên chế độ thực thi user mode. Còn khi tiến trình gọi các system call, CPU phải chuyển sang chế độ kernel mode để thực thi các lệnh của kernel (hình 5). Lúc này, ta nói rằng, CPU đang thực thi ở chế độ kernel mode, trong ngữ cảnh process context. Sau khi kernel thực hiện xong yêu cầu, kernel gửi trả kết quả cho tiến trình. Lúc này, CPU lại chuyển sang chế độ user mode để thực thi tiếp các lệnh của tiến trình.

Ngoài system call, ngắt cũng là một nguyên nhân khiến CPU chuyển chế độ thực thi sang kernel mode (hình 5). Khi có một thiết bị muốn trao đổi dữ liệu với CPU, nó sẽ gửi một tín hiệu ngắt tới CPU bằng cách nâng điện áp trên chân INT của CPU. Khi đó, CPU sẽ ngừng thực thi các lệnh của tiến trình lại, chuyển sang chế độ kernel mode rồi thực thi một chương trình đặc biệt của kernel để xử lý tín hiệu ngắt đó. Lúc này, ta nói CPU đang thực thi ở chế độ kernel mode, trong ngữ cảnh interrupt context. Sau khi xử lý xong, CPU trở lại chế độ user mode và tiếp tục thực hiện các lệnh tiếp theo của tiến trình.

Case study.

Các bản phân phối Linux.

Cùng với sự đóng góp của cộng đồng, ngày nay, Linux kernel đã được sử dụng trên rất nhiều thiết bị, từ máy tính cá nhân (PC), máy chủ (server) cho tới các hệ thống nhúng như bộ định tuyến (router), bộ truy cập không dây (Wireless Access Point), điện thoại thông minh (smartphone), tivi thông minh (smart tivi), thiết bị hỗ trợ tivi (set-top box), …

Để dễ sử dụng hơn, ngoài Linux kernel, các thiết bị nói trên cũng sử dụng thêm các phần mềm tiện ích (utility software). Nhưng trong quá trình phát triển, cả Linux kernel và các phần mềm tiện ích đều có nhiều phiên bản khác nhau. Do đó, việc chọn phiên bản của các phần mềm tiện ích tương thích với phiên bản của Linux kernel rất khó khăn.

Để giải quyết vấn đề trên, Linux kernel và các phần mềm tiện ích được đóng gói lại với nhau, tạo thành bản phân phối Linux (Linux distribution). Các bản phân phối này khác nhau về một số yếu tố như hỗ trợ các thiết bị khác nhau, các phần mềm tiện ích đi kèm khác nhau, khả năng bảo mật khác nhau,…

  • Các bản phân phối của Linux được sử dụng phổ biến trên PC và server là: Ubuntu, RedhatFedora, Centos, Debian, Gentoo, Open Suse.
  • Các bản phân phối của Linux hay dùng trên các thiết bị nhúng là: MontaVista, TimeSys, KaeilOS.

Cài đặt bản phân phối Ubuntu.

Khóa học này hướng dẫn các bạn phát triển Linux driver cho các hệ thống máy tính sử dụng bộ xử lý của Intel. Để hiểu lý thuyết hơn, chúng ta cần có một môi trường để thực hành. Do đó, việc đầu tiên chúng ta cần làm là cài đặt môi trường phát triển cho những bài học sau. Vì nhiều bạn đang sử dụng hệ điều hành Windows, nên chúng ta sẽ cài đặt một bản phân phối Linux trên máy ảo. Do Ubuntu được sử dụng phổ biến ở Việt Nam, nên khóa học này chọn bản phân phối Ubuntu làm môi trường phát triển. Các bước cài đặt như sau:

Bước 1: tải bộ phần mềm VirtualBox tại đây và cài đặt.

Bước 2: tải bản phân phối Ubuntu 16.04 cho máy PC 32 bit hoặc 64 bit.

Bước 3: tạo máy ảo chạy hệ điều hành Ubuntu 16.04 theo video sau.

User mode và kernel mode trong hđh linux

Hình 6 Ubuntu 16.04 sử dụng Linux kernel 4.4

Sau khi cài đặt xong, ta mở Terminal lên (Ctrl + Alt + T), và gõ lệnh uname -ra. Ta sẽ được kết quả như hình 6. Có thể thấy rằng, bản phân phối Ubuntu 16.04 đang sử dụng Linux kernel 4.4. Các bạn có thể tham khảo mã nguồn Linux kernel 4.4 tại đây.

Kết luận.

Hệ thống máy tính gồm phần cứng và phần mềm. Phần cứng gồm 4 khối chức năng: CPU, RAM, I/O module và hệ thống bus. RAM là nơi chứa các phần mềm. Phần mềm là một tập các lệnh và dữ liệu. CPU có nhiệm vụ đọc lần lượt từng lệnh trong RAM ra và thực thi.

Hệ điều hành là một phần mềm quản lý các tài nguyên phần cứng. Nó có tên gọi khác là kernel. Nếu có nhiều người dùng cùng sử dụng hệ thống, hoặc nhiều chương trình cùng chạy trong hệ thống, thì hệ thống đó buộc phải sử dụng hệ điều hành. Mục đích là để tránh xảy ra tranh chấp tài nguyên giữa nhiều người dùng, hoặc giữa các chương trình. Ngoài ra, hệ điều hành giúp che giấu sự phức tạp của phần cứng, cung cấp dịch vụ cho các tiến trình thông qua system call. Tiến trình là quá trình CPU đang thực thi một chương trình.

Xét về mặt chức năng, Linux kernel bao gồm 6 thành phần: process management, memory management, device management, file system management, networking management và system call interface.

Bộ nhớ được chia làm 2 vùng: user space chứa các tiến trình, và kernel space chứa kernel. Khi thực thi các lệnh trong user space, CPU hoạt động ở chế độ user mode. Khi thực thi các lệnh trong kernel space, CPU hoạt động ở chế độ kernel mode. CPU chuyển từ chế độ user mode sang kernel mode khi tiến trình phát ra một system call để yêu cầu kernel cung cấp dịch vụ, hoặc khi một thiết bị gửi tín hiệu ngắt tới CPU. Nếu là do system call, ta nói CPU đang hoạt động ở chế độ kernel mode, trong ngữ cảnh process context. Nếu là do ngắt, ta nói CPU đang hoạt động ở chế độ kernel mode, trong ngữ cảnh interrupt context.