Hello world kernel module

1. Tổng quan

Linux kernel

Linux Kernel là trái tim của các hệ điều hành Linux. Nó là một phần mềm mã nguồn mở (mã nguồn có thể được sử dụng bởi bất kỳ ai một cách tự do) phổ biến nhất và được sử dụng rộng rãi.

Kernel là thành phần cốt lõi của một hệ điều hành. Kernel cung cấp một nền tảng cho các chương trình và các dịch vụ khác nhau để chúng có thể hoạt động trên nó. Linux kernel có thể sửa đổi theo nhu cầu của người dùng. Từ đó ta có khái niệm về Kernel module

Kernel module

Hệ điều hành Linux được thiết kế cho phép người sử dụng nạp thêm một đoạn mã chương trình vào bên trong kernel và trở thành một phẩn của nó. Cơ chế này được gọi là kernel module.

Các kernel module là các đoạn mã có thể được load và unload vào kernel theo yêu cầu của người dùng. Chúng mở rộng chức năng của kernel mà không cần khởi động lại hệ thống.

Có 2 phương pháp để thêm đoạn mã code trên vào Linux kernel:

  • Thêm code vào kernel source và thực hiện biên dịch lại kernel
  • Thêm code vào kernel source khi kernel đang chạy. Quá trình này được thực hiện bằng cách sử dụng các câu lệnh insmod và rmmod các file kernel module (đuôi .ko)

Kernel module không có hàm main. Thay vào đó, nó có 2 hàm init_module() và hàm cleanup_module()

  • init_module() được gọi ra khi module được load vào kernel bằng câu lệnh “insmod”
  • cleanup_module() được gọi ra khi module bị unload ra khỏi kernel bằng câu lệnh “rmmod”

Ngoài ra, chúng ta có thể tùy ý đặt tên hàm bắt đầu kết thúc một module bằng cách sử dụng macro:

2. Tạo một kernel module trên Linux (ubuntu)

Setup Environment:

Hệ thống phải được cài bộ soucre Linux kernel header để có thể build được đoạn code kernel. Linux kernel header là thành phần được sử dụng để biên dịch cho module của kernel. Kernel header được cài đặt phải trùng với kernel version trên máy tính của mình (uname –r).

Để cài đặt kernel header, ta sử dụng cú pháp:

Sau khi được cài đặt, kernel header nằm trong thư mục /lib/modules/

Makefile:

Kernel module thường được compile bằng Makefile:

obj-m: trỏ vào tên file code (đuôi .o)

pwd: lưu đường dẫn hiện tại, nơi chứa file output

KDIR: trỏ vào đường dẫn chứa bộ code của kernel

Sau khi Make thành công, sẽ có một file có đuôi “.ko” được tạo ra. Nó chứa mã nguồn đã được build ra.

Ví dụ hello kernel module:

Trong đoạn code trên, hàm pr_info() được dùng để ghi chuỗi kí tự lên log của hệ thống. Để xem log của hệ thống, ta dùng cmd “dmesg”

Sau khi dùng Makefile để complie chương trình hello.c trên, ta thu được file hello.ko chính là file kernel module.

Hàm init_module() được gọi ra khi ta sự dụng cmd “sudo insmod hello.ko”, ta thu được dòng log đúng với chuỗi string trong pr_info()

Để xem các module đang được chạy trên hệ thống, ta dùng câu lệnh “lsmod”

Tương tự với hàm cleanup_init() khi unload module với câu lệnh “sudo rmmod hello”:

Ngoài ra, các macro MODULE_LICENSE, MODULE_AUTHOR,… được sử dụng để mô tả các thông tin của module. Ta có thể xem các thông tin này qua cmd “modinfo hello.ko”:

3. Hello kernel module trên beaglebone black

Tương tự với môi trường trên Linux (x86), đoạn mã code kernel module cũng giống như với ví dụ trên:

Tuy nhiên, với beaglebone black do có phần cứng khá hạn chế nên thông thường, chúng ta sẽ không thực hiện compile trực tiếp trên board. Thay vào đó sẽ sử dụng kỹ thuật cross-compile: nơi build file binary sẽ là trên máy tính x86 (ubuntu), nơi thực thi chương trình đã được compile là trên beaglebone black

Do đó, trước khi thực hiện cross-compile, chúng ta cần cài đặt các package và các công cụ cần thiện để thực hiện biên dịch cho kiến trúc ARM trên beaglebone black – gọi là toolchain.

Makefile được dùng để thực hiện việc biên dịch:

ARCH: chỉ ra bộ code build cho kiến trúc gì

CROSS: trỏ vào đường dẫn của toolchain, bỏ hậu tố “gcc”

KER_DIR: trỏ vào đường dẫn chứa bộ code của kernel và chính bộ kernel này build ra image đang chạy trên beaglebone black

Khi thực hiện chạy kernel module trên beaglebone black, ta cũng thu được kết quả như đã thực hiện trên máy Linux:

Thực hiện unload kernel module:

4. Tạo kernel module bink led trên beaglebone black

Ở phần này, chúng ta cùng nhau thực hiện một ví dụ bink led trên chân GPIO31 của beaglebone black với pinout như hình sau:

Với hàm init_module() thực hiện khởi tạo chân GPIO31:

Hàm xử lý timer sẽ thực hiện bink led với khoảng thời gian 1s 1 lần:

Hàm cleanup_module() thực hiện giải phóng timer đã khởi tạo ra khỏi hệ thống khi không sử dụng:

Ví dụ chương trình kernel module:

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top