Việc phát triển trình điều khiển thiết bị cho các phiên bản kernel Linux cũ, chẳng hạn như Linux 2.6.10, thường đặt ra những thách thức đáng kể do sự không tương thích của các bộ công cụ biên dịch hiện đại. Mặc dù hệ thống hiện tại của bạn có thể đang chạy một kernel khá cũ (ví dụ: RHEL 5.8 với kernel 2.6.18), nhưng để biên dịch kernel 2.6.10 và các module của nó, bạn sẽ cần một bộ công cụ biên dịch (toolchain) tĩnh tương thích với thời điểm đó.
1. Chuẩn bị Kernel Linux 2.6.10
Đầu tiên, tải xuống mã nguồn kernel Linux 2.6.10:
wget https://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.10.tar.gz
tar -xzvf linux-2.6.10.tar.gz
cd linux-2.6.10
2. Xây dựng Bộ Công cụ Biên dịch Cũ (GCC 3.4.6 và Binutils 2.16.1)
Các phiên bản GCC hiện đại thường không thể biên dịch kernel 2.6.10 một cách chính xác hoặc không tương thích với các header của nó. Vì vậy, chúng ta sẽ xây dựng một bộ công cụ biên dịch tĩnh cũ hơn.
2.1. Tải xuống Mã nguồn Công cụ
Tải xuống các phiên bản cụ thể của GCC và Binutils:
# Tải xuống GCC 3.4.6
curl -O http://ftp.gnu.org/gnu/gcc/gcc-3.4.6/gcc-3.4.6.tar.bz2
curl -O http://ftp.gnu.org/gnu/gcc/gcc-3.4.6/gcc-core-3.4.6.tar.bz2
curl -O http://ftp.gnu.org/gnu/gcc/gcc-3.4.6/gcc-g++-3.4.6.tar.bz2
# Tải xuống Binutils 2.16.1
curl -O http://ftp.gnu.org/gnu/binutils/binutils-2.16.1.tar.bz2
2.2. Giải nén Mã nguồn
tar xjf gcc-3.4.6.tar.bz2
tar xjf gcc-core-3.4.6.tar.bz2 -C gcc-3.4.6
tar xjf gcc-g++-3.4.6.tar.bz2 -C gcc-3.4.6
tar xjf binutils-2.16.1.tar.bz2
2.3. Biên dịch Binutils 2.16.1
Binutils cung cấp các công cụ như trình hợp dịch (as) và trình liên kết (ld). Chúng ta sẽ biên dịch nó trước.
cd binutils-2.16.1
mkdir build && cd build
# Cấu hình biên dịch Binutils
# --prefix: Đường dẫn cài đặt
# --disable-nls: Vô hiệu hóa hỗ trợ ngôn ngữ bản địa
# --disable-werror: Không coi cảnh báo là lỗi
# --enable-64-bit-bfd: Hỗ trợ BFD 64-bit
# --enable-targets: Chỉ định các kiến trúc mục tiêu
# --enable-multilib: Hỗ trợ nhiều kiến trúc (32/64 bit)
../configure --prefix=/opt/old_toolchain \
--disable-nls \
--disable-werror \
--enable-64-bit-bfd \
--enable-targets=i386-linux,x86_64-linux \
--enable-multilib
# Biên dịch và cài đặt
make -j$(nproc) # Sử dụng tất cả các nhân CPU có sẵn để tăng tốc
make install
2.4. Biên dịch GCC 3.4.6
Sau khi Binutils được cài đặt, chúng ta sẽ biên dịch GCC.
cd ../../gcc-3.4.6 # Quay lại thư mục gốc của GCC
mkdir build && cd build
# Cấu hình biên dịch GCC
# --enable-languages=c: Chỉ biên dịch hỗ trợ ngôn ngữ C
# --with-as, --with-ld: Chỉ định trình hợp dịch và trình liên kết từ Binutils đã cài đặt
# --disable-libstdcxx, --disable-libgcc, --disable-shared, --enable-static: Xây dựng GCC tĩnh
../configure --prefix=/opt/old_toolchain \
--enable-languages=c \
--enable-multilib \
--disable-nls \
--with-as=/opt/old_toolchain/bin/as \
--with-ld=/opt/old_toolchain/bin/ld \
--disable-libstdcxx \
--disable-libgcc \
--disable-shared \
--enable-static
# Biên dịch và cài đặt
make -j$(nproc)
make install
3. Thiết lập Môi trường Biên dịch
Tạo một script để dễ dàng kích hoạt bộ công cụ biên dịch cũ:
cat > /opt/old_toolchain/activate_env.sh << 'EOF'
#!/bin/bash
export PATH="/opt/old_toolchain/bin:$PATH"
export CC="/opt/old_toolchain/bin/gcc"
export CXX="/opt/old_toolchain/bin/g++"
export LD="/opt/old_toolchain/bin/ld"
export AS="/opt/old_toolchain/bin/as"
export AR="/opt/old_toolchain/bin/ar"
export NM="/opt/old_toolchain/bin/nm"
export RANLIB="/opt/old_toolchain/bin/ranlib"
export STRIP="/opt/old_toolchain/bin/strip"
export LIBRARY_PATH="/opt/old_toolchain/lib:$LIBRARY_PATH"
export C_INCLUDE_PATH="/opt/old_toolchain/include:$C_INCLUDE_PATH"
export CPLUS_INCLUDE_PATH="/opt/old_toolchain/include:$CPLUS_INCLUDE_PATH"
echo "Môi trường bộ công cụ cũ (GCC 3.4.6) đã được kích hoạt!"
EOF
chmod +x /opt/old_toolchain/activate_env.sh
source /opt/old_toolchain/activate_env.sh
4. Kiểm tra Trình biên dịch Cũ
Để xác minh rằng trình biên dịch cũ đã được kích hoạt thành công và giải quyết được vấn đề liên kết động với các thư viện hệ thống hiện đại, hãy kiểm tra với một chương trình C đơn giản.
# Tạo tệp C để kiểm tra
cat > check_gcc.c << 'EOF'
#include <stdio.h>
int main() {
printf("Xin chào từ GCC phiên bản %d.%d.%d!\n",
__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
return 0;
}
EOF
# Thử biên dịch với GCC mặc định của hệ thống (trước khi kích hoạt script)
# gcc check_gcc.c -o test_default
# ./test_default # Sẽ hiển thị phiên bản GCC hệ thống, ví dụ 4.1.2
# Kích hoạt bộ công cụ cũ
source /opt/old_toolchain/activate_env.sh
# Biên dịch với bộ công cụ cũ và liên kết tĩnh để tránh vấn đề libc
gcc check_gcc.c -o test_old_static -static
./test_old_static # Sẽ hiển thị phiên bản GCC 3.4.6
Nếu bạn gặp lỗi như file not recognized: File format not recognized khi không dùng -static, điều đó cho thấy trình biên dịch cũ không thể liên kết với các thư viện động mới hơn của hệ thống. Việc sử dụng -static giải quyết vấn đề này, đảm bảo chương trình được liên kết hoàn toàn tại thời điểm biên dịch.
5. Biên dịch Kernel Linux 2.6.10
Bây giờ chúng ta đã có bộ công cụ biên dịch phù hợp, hãy biên dịch kernel. Đảm bảo bạn đang trong thư mục mã nguồn linux-2.6.10 và bộ công cụ cũ đang hoạt động.
cd /path/to/linux-2.6.10 # Đảm bảo bạn đang ở thư mục kernel
# Cấu hình kernel với cấu hình mặc định cho kiến trúc x86_64
# Sử dụng HOSTCC, HOSTLD, HOSTCFLAGS, HOSTLDFLAGS để chỉ định rõ ràng bộ công cụ biên dịch host
make ARCH=x86_64 defconfig \
HOSTCC="/opt/old_toolchain/bin/gcc -B/opt/old_toolchain/bin/ -L/opt/old_toolchain/lib" \
HOSTLD="/opt/old_toolchain/bin/ld" \
HOSTCFLAGS="-static" HOSTLDFLAGS="-static"
# Biên dịch kernel
make -j$(nproc) ARCH=x86_64 \
HOSTCC="/opt/old_toolchain/bin/gcc -B/opt/old_toolchain/bin/ -L/opt/old_toolchain/lib" \
HOSTLD="/opt/old_toolchain/bin/ld" \
HOSTCFLAGS="-static" HOSTLDFLAGS="-static"
Nếu gặp lỗi "Macro with this name was already defined" trong các tệp .S, đôi khi việc dùng các tùy chọn biên dịch hoặc phiên bản Binutils/GCC khác nhau có thể cần thiết. Tuy nhiên, bộ công cụ được đề xuất ở trên thường giải quyết được nhiều vấn đề tương thích.
5.1. Cài đặt Module và Kernel
# Cài đặt các module kernel
make modules_install
# Kiểm tra các module đã cài đặt
ls /lib/modules/2.6.10/
ls -la /lib/modules/2.6.10/kernel/
# Cài đặt ảnh kernel và các tệp liên quan vào /boot
make install
# Lưu cấu hình kernel đã dùng
cp .config /boot/config-2.6.10-custom
Sau khi cài đặt, bạn cần cập nhật cấu hình GRUB (hoặc bộ nạp khởi động tương đương) để thêm tùy chọn khởi động với kernel 2.6.10 mới. Sau đó, khởi động lại hệ thống và chọn kernel 2.6.10 để vào môi trường phát triển.
6. Biên dịch Module Kernel "Hello World"
Để kiểm tra môi trường đã thiết lập, chúng ta sẽ biên dịch và tải một module kernel "Hello World".
6.1. Tạo Mã nguồn Module
Tạo tệp my_hello.c:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h> /* KERN_INFO */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Developer");
MODULE_DESCRIPTION("A simple kernel module for testing.");
MODULE_VERSION("1.0");
static int __init my_module_entry(void)
{
printk(KERN_INFO "MyKernelModule: Xin chào từ module kernel!\n");
return 0;
}
static void __exit my_module_exit(void)
{
printk(KERN_INFO "MyKernelModule: Tạm biệt từ module kernel!\n");
}
module_init(my_module_entry);
module_exit(my_module_exit);
6.2. Tạo Makefile
Tạo tệp Makefile trong cùng thư mục với my_hello.c:
obj-m += my_hello.o
# Đường dẫn đến thư mục build của kernel 2.6.10 đã cài đặt
KDIR := /lib/modules/2.6.10/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
Đảm bảo bạn đã khởi động vào kernel 2.6.10 trước khi biên dịch module này.
6.3. Biên dịch và Tải Module
# Biên dịch module
make clean
make
# Tải module vào kernel
sudo insmod ./my_hello.ko
# Kiểm tra log kernel
dmesg | tail -n 5
# Gỡ bỏ module
sudo rmmod my_hello
# Kiểm tra log kernel lại
dmesg | tail -n 5
Nếu bạn gặp lỗi "version magic" (ví dụ: '2.6.10 SMP gcc-4.1' should be '2.6.10 SMP gcc-3.4'), điều này có nghĩa là module của bạn đã được biên dịch bằng một phiên bản GCC khác với phiên bản được dùng để biên dịch kernel 2.6.10. Hãy đảm bảo bạn đã kích hoạt đúng bộ công cụ cũ (source /opt/old_toolchain/activate_env.sh) trước khi chạy make cho module.
7. Sao chép và Dọn dẹp Mã nguồn Kernel
Để giữ cho thư mục mã nguồn kernel sạch sẽ và ở một vị trí tiêu chuẩn, bạn có thể sao chép nó sau khi đã biên dịch:
# Xóa thư mục kernel cũ nếu có vấn đề
sudo rm -rf /usr/src/linux-2.6.10
# Tạo thư mục mới và sao chép mã nguồn sạch
sudo mkdir -p /usr/src/linux-2.6.10
(cd /path/to/original/linux-2.6.10 && sudo tar cf - .) | (cd /usr/src/linux-2.6.10 && sudo tar xf -)
# Dọn dẹp các tệp biên dịch trong thư mục đã sao chép
cd /usr/src/linux-2.6.10
sudo find . -name "*.o" -delete
sudo find . -name ".*.cmd" -delete
sudo find . -name "*.ko" -delete
Với các bước này, bạn đã thiết lập thành công môi trường phát triển để lập trình trình điều khiển thiết bị trên Linux Kernel 2.6.10, sẵn sàng cho các dự án phát triển tiếp theo.