Linux Kernel ו-Device Drivers: לכתוב קוד ברמת הליבה

עודכן לאחרונה: 2 יוני, 2026

כתיבת Device Drivers ב-Linux Kernel היא היכולת לדבר ישירות עם החומרה — בלי שכבות הפשטה, בלי frameworks שמחביאים את המציאות. זה הקוד שגורם לחיישן לדווח, ל-GPU לעבד, לכרטיס רשת לשדר. מהנדסים שכותבים ברמת הליבה הם אלה שבונים את התשתית שעליה כל השאר רץ — מ-Android ועד שרתי ענן ועד בקרי תעופה. אם תמיד תהיתם איך להגיע לשם, הפוסט הזה הוא נקודת ההתחלה שלכם.

הסיפור של ארז: מסקריפט ב-Python לקוד ב-Kernel Space

ארז הגיע אלינו אחרי שש שנים בתעשייה. מפתח Embedded מוצלח, C ו-C++ שוטפים, ניסיון עם FreeRTOS ופלטפורמות ARM. הוא ידע לכתוב firmware מצוין. אבל כל פעם שנתקל בבעיה ברמת הדרייבר של Linux — הוא נתקע.

"ישבתי מול קוד של דרייבר בליבה ולא הבנתי למה הוא עושה את מה שהוא עושה," הוא סיפר לנו בשיחה הראשונה. "ידעתי לקרוא C, אבל הקוד הזה נראה כמו שפה אחרת. מאקרואים מוזרים, מבנים שלא הכרתי, כל השגרות של ניהול הזיכרון — הרגשתי שאני צריך להתחיל מאפס."

ארז לא היה צריך להתחיל מאפס. הוא היה צריך מי שיפרק לו את הארכיטקטורה שלב אחרי שלב, עם ידיים על המקלדת. אחרי שעבר את קורס Linux Kernel And Device Drivers, הוא כתב דרייבר עובד לחיישן I2C תוך שבועיים — משהו שלפני כן היה נראה לו כמו קסם שחור.

הסיפור של ארז לא ייחודי. אנחנו רואים את זה שוב ושוב: מהנדסים מבריקים שעובדים שנים ב-User Space ומרגישים שהליבה היא מבצר סגור. היא לא. היא פשוט דורשת גישה שונה — וזה בדיוק מה שנפרוס כאן.

מה בעצם קורה ב-Kernel Space? הבנת הארכיטקטורה

ההבדל הקריטי בין User Space ל-Kernel Space

כשאפליקציה רגילה רצה על Linux, היא חיה ב-User Space — סביבה מוגנת שבה טעות בקוד גורמת לקריסת התהליך בלבד. ב-Kernel Space, הכללים שונים לחלוטין. קוד שרץ כאן פועל עם הרשאות מלאות — גישה ישירה לזיכרון פיזי, לרגיסטרים של החומרה, לטבלאות ה-page tables של ה-MMU.

טעות ב-Kernel Space לא מפילה תהליך — היא מפילה את כל המערכת. Kernel Panic. המסך קופא, הלוגים נעצרים, ומה שנשאר זה לעשות reboot ולנסות להבין מה קרה. לפי נתוני Red Hat מ-2024, כ-65% מתקלות הייצור הקריטיות במערכות Linux מקורן בבאגים ברמת הדרייברים — לא בקוד האפליקציה.

בגלל זה בדיוק מהנדסים שכותבים קוד ליבה הם מבוקשים כל כך. לפי סקר Stack Overflow Developer Survey 2024, מפתחי Kernel ו-Systems Programming מדורגים ב-top 5 של השכר הגבוה ביותר בתעשייה, עם ממוצע שנתי של כ-$150,000 גלובלית. בישראל, חברות כמו Mobileye, Mellanox (NVIDIA), Qualcomm ו-Habana Labs מחפשות באופן קבוע מהנדסים עם ניסיון ב-Linux Kernel development.

Loadable Kernel Modules: הדלת לכתיבת דרייברים

אחד הדברים הגאוניים בארכיטקטורה של Linux הוא המנגנון של Loadable Kernel Modules — או בקיצור LKM. במקום לקמפל מחדש את כל הליבה בשביל להוסיף תמיכה בהתקן חדש, אפשר לכתוב מודול נפרד, לקמפל אותו, ולטעון אותו לליבה בזמן ריצה.

זה הבסיס של כל Device Driver מודרני ב-Linux. כשמחברים מקלדת USB — הליבה מזהה את ההתקן, טוענת את המודול המתאים, והמקלדת עובדת. מאחורי הקלעים, התרחש תהליך מורכב: הליבה זיהתה Vendor ID ו-Product ID, חיפשה דרייבר מתאים, הקצתה משאבים, ורשמה את ההתקן בתוך מערכת ה-sysfs.

הנה המודול הפשוט ביותר שאפשר לכתוב — הקוד שממנו הכול מתחיל:


#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("RT-ED Student");
MODULE_DESCRIPTION("A minimal Linux Kernel Module");

static int __init hello_init(void)
{
    printk(KERN_INFO "Hello from Kernel Space!\n");
    return 0;
}

static void __exit hello_exit(void)
{
    printk(KERN_INFO "Goodbye from Kernel Space!\n");
}

module_init(hello_init);
module_exit(hello_exit);

שימו לב: אין כאן printf — יש printk. אין stdlib — יש linux/kernel.h. המבנה שונה, כי הסביבה שונה. כל פונקציה שאתם רגילים אליה מ-User Space פשוט לא קיימת כאן. הליבה מספקת API משלה — ולימוד ה-API הזה הוא מהדברים שלוקחים הכי הרבה זמן למהנדסים שעושים את המעבר.

הנה איך בונים ומריצים את המודול הזה:


# Makefile למודול ליבה
cat > Makefile << 'EOF'
obj-m += hello_module.o

KDIR := /lib/modules/$(shell uname -r)/build

all:
	make -C $(KDIR) M=$(PWD) modules

clean:
	make -C $(KDIR) M=$(PWD) clean
EOF

# קימפול
make

# טעינת המודול לליבה
sudo insmod hello_module.ko

# בדיקה שהמודול נטען
lsmod | grep hello_module

# קריאת הודעת הליבה
dmesg | tail -5

# הסרת המודול
sudo rmmod hello_module

# בדיקת הודעת היציאה
dmesg | tail -5

כשתריצו את זה, תראו ב-dmesg את ההודעה "Hello from Kernel Space!" — וזה הרגע שבו מבינים: הקוד שלי רץ בתוך הליבה. אין רשת ביטחון, אין sandboxing. אני חלק מהמנוע של מערכת ההפעלה.

כתיבת דרייבר אמיתי: מה-Hello World לחומרה אמיתית

Character Device Driver — הדרייבר הראשון שכל מהנדס כותב

ב-Linux, כמעט כל התקן חומרה מיוצג כקובץ ב-/dev. זה רעיון ישן ומבריק — "everything is a file". כשפותחים קובץ, קוראים ממנו או כותבים אליו, ה-Kernel מנתב את הפעולה לדרייבר שרשום כאחראי על אותו קובץ.

Character Device הוא התקן שמאפשר גישה לנתונים כזרם של בייטים — בניגוד ל-Block Device שעובד עם בלוקים קבועים של מידע כמו דיסק קשיח. חיישנים, ממשקי תקשורת סריאליים, ו-GPIO — כולם character devices.

ארז, הבחור שסיפרתי עליו קודם, כתב את הדרייבר הראשון שלו למד-טמפרטורה שמחובר דרך I2C. "הרגע שבו עשיתי cat /dev/temp_sensor וקיבלתי קריאת טמפרטורה אמיתית — זה היה אחד הרגעים הכי מספקים בקריירה שלי," הוא אמר. "פתאום הבנתי שאני שולט בחומרה דרך הליבה, לא דרך ספרייה כלשהי."

הנה מבנה בסיסי של Character Device Driver:


#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>

#define DEVICE_NAME "mychardev"
#define BUF_SIZE    256

MODULE_LICENSE("GPL");

static dev_t dev_num;
static struct cdev my_cdev;
static struct class *my_class;
static char kernel_buf[BUF_SIZE];
static int buf_len = 0;

static int dev_open(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "mychardev: device opened\n");
    return 0;
}

static ssize_t dev_read(struct file *file, char __user *ubuf,
                        size_t count, loff_t *ppos)
{
    int bytes_to_read = min((int)count, buf_len);
    if (*ppos >= buf_len)
        return 0;

    if (copy_to_user(ubuf, kernel_buf, bytes_to_read))
        return -EFAULT;

    *ppos += bytes_to_read;
    return bytes_to_read;
}

static ssize_t dev_write(struct file *file, const char __user *ubuf,
                         size_t count, loff_t *ppos)
{
    int bytes_to_write = min((int)count, BUF_SIZE - 1);

    if (copy_from_user(kernel_buf, ubuf, bytes_to_write))
        return -EFAULT;

    kernel_buf[bytes_to_write] = '\0';
    buf_len = bytes_to_write;
    printk(KERN_INFO "mychardev: received %d bytes\n", bytes_to_write);
    return bytes_to_write;
}

static int dev_release(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "mychardev: device closed\n");
    return 0;
}

static struct file_operations fops = {
    .owner   = THIS_MODULE,
    .open    = dev_open,
    .read    = dev_read,
    .write   = dev_write,
    .release = dev_release,
};

static int __init mychardev_init(void)
{
    alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME);
    cdev_init(&my_cdev, &fops);
    cdev_add(&my_cdev, dev_num, 1);
    my_class = class_create(DEVICE_NAME);
    device_create(my_class, NULL, dev_num, NULL, DEVICE_NAME);
    printk(KERN_INFO "mychardev: registered with major %d\n", MAJOR(dev_num));
    return 0;
}

static void __exit mychardev_exit(void)
{
    device_destroy(my_class, dev_num);
    class_destroy(my_class);
    cdev_del(&my_cdev);
    unregister_chrdev_region(dev_num, 1);
    printk(KERN_INFO "mychardev: unregistered\n");
}

module_init(mychardev_init);
module_exit(mychardev_exit);

אחרי הקימפול והטעינה, אפשר לתקשר עם הדרייבר ככה:


# טעינת המודול
sudo insmod mychardev.ko

# בדיקה שנוצר קובץ ההתקן
ls -la /dev/mychardev

# כתיבה להתקן
echo "Hello Kernel Driver" | sudo tee /dev/mychardev

# קריאה מההתקן
sudo cat /dev/mychardev

# צפייה בלוגים
dmesg | tail -10

# הסרה
sudo rmmod mychardev

מ-Character Device לעולם האמיתי: Platform Drivers ו-Device Tree

הדרייבר שראינו למעלה הוא טוב ללמידה, אבל בעולם האמיתי — במיוחד במערכות Embedded — הדברים עובדים אחרת. מערכות מבוססות ARM כמו Raspberry Pi, i.MX של NXP, או Snapdragon של Qualcomm משתמשות ב-Device Tree כדי לתאר את החומרה למערכת ההפעלה.

ה-Device Tree הוא קובץ (עם סיומת .dts) שמתאר אילו התקנים מחוברים, באילו כתובות, ואילו פרמטרים הם צריכים. הדרייבר לא מחפש חומרה בעצמו — הליבה מתאימה בין תיאור ב-Device Tree לבין דרייבר רשום, וקוראת לפונקציית probe של הדרייבר.

זהו שינוי תפיסתי. ב-x86, ה-BIOS וה-ACPI מספרים לליבה מה מחובר. ב-ARM, ה-Device Tree עושה את העבודה. ולפי נתוני kernel.org מ-2024, מעל 78% מהדרייברים החדשים שנכנסים ל-mainline Linux Kernel הם Platform Drivers שמתבססים על Device Tree — לא דרייברים ישנים מסגנון legacy.

כלים וגישות: מה משתמשים בו בתעשייה הישראלית

סביבות פיתוח וכלי דיבוג

פיתוח Kernel Modules דורש כלים ספציפיים. אי אפשר פשוט לפתוח VS Code ולהתחיל — צריך להבין את ה-toolchain ואת שיטות הדיבוג הייחודיות לקוד ליבה.

כלי / גישה שימוש עיקרי יתרונות חסרונות
printk + dmesg דיבוג בסיסי — הדפסת הודעות מהליבה פשוט, זמין תמיד, אין צורך בהגדרות לא מאפשר breakpoints, מציף לוגים
KGDB דיבוג אינטראקטיבי עם GDB דרך חיבור סריאלי Breakpoints אמיתיים, step-by-step ברמת הליבה דורש שתי מכונות, קומפילציה עם debug symbols
ftrace / trace-cmd מעקב אחרי קריאות פונקציה בליבה overhead נמוך, מובנה בליבה, לא דורש recompile עקומת למידה תלולה, פלט עשיר מדי
QEMU + Buildroot סביבת פיתוח וירטואלית למערכות Embedded אין צורך בחומרה פיזית, ניתן לסמלץ ארכיטקטורות שונות לא תמיד מדמה נכון התנהגות חומרה אמיתית
Yocto Project בניית הפצת Linux מותאמת אישית כולל דרייברים שליטה מלאה על כל רכיב, תקן תעשייתי תהליך בנייה ארוך, תצורה מורכבת

בחברות ישראליות כמו Mobileye, הצוותים עובדים עם שילוב של QEMU לפיתוח מוקדם ו-KGDB לדיבוג על חומרה אמיתית. ב-Mellanox (NVIDIA Networking), צוותי הדרייברים של כרטיסי ה-ConnectX משתמשים ב-ftrace באופן אינטנסיבי לאופטימיזציה של ביצועים.

מה המהנדסים של אינטל באמת עושים אחרת

שאלתם למה הכותרת מזכירה את אינטל? כי אינטל היא אחת התורמות הגדולות ביותר ל-Linux Kernel. לפי נתוני Linux Foundation מ-2023, אינטל אחראית לכ-12.5% מכלל ה-commits ל-Kernel — והרבה מהפיתוח הזה קורה פה בישראל, במשרדים בחיפה ובפתח תקווה.

מה שמבדיל מהנדסי Kernel ותיקים מכולם הוא לא רק ידע טכני — זה אופן החשיבה. הם חושבים על concurrency כברירת מחדל. הם יודעים ש-spinlock לא מתנהג אותו דבר ב-single-core וב-multi-core. הם מכירים את ההבדל בין atomic context ל-process context, ויודעים למה אסור לישון בתוך interrupt handler.

הדברים האלה נשמעים אקדמיים, אבל הם ההבדל בין דרייבר שעובד בלאב לדרייבר שעובד בפרודקשן תחת עומס. ארז גילה את זה כשהדרייבר שלו קרס תחת עומס גבוה — הוא השתמש ב-mutex בתוך interrupt handler. ברגע שהבין את העיקרון ושינה ל-spinlock_irqsave, הבעיה נעלמה.

המסלול המעשי: איך מתחילים היום

שלב 1: סביבת העבודה

לא צריך חומרה מיוחדת כדי להתחיל. מכונה וירטואלית עם Ubuntu ו-Kernel Headers מספיקה למודולים הראשונים. הנה ההגדרה המינימלית:


# התקנת כלי פיתוח וכותרות ליבה
sudo apt update
sudo apt install -y build-essential linux-headers-$(uname -r)

# בדיקה שהכול מותקן
ls /lib/modules/$(uname -r)/build
# אם התיקייה קיימת — אתם מוכנים

# כלים נוספים שימושיים
sudo apt install -y git vim dkms kmod

# לפיתוח מתקדם יותר עם QEMU
sudo apt install -y qemu-system-arm gcc-arm-linux-gnueabihf

שלב 2: מהתיאוריה לפרויקט

אחרי שכתבתם Hello World Module ו-Character Device בסיסי, הצעד הבא הוא לבנות דרייבר שעושה משהו אמיתי. הנה כמה פרויקטים שאנחנו ממליצים עליהם ושמהנדסים עשו בהצלחה:

פרויקט 1: GPIO Driver ל-Raspberry Pi — כתיבת דרייבר שחושף ממשק ב-sysfs לשליטה על פינים. זה מלמד עבודה עם memory-mapped I/O ורגיסטרים של חומרה אמיתית.

פרויקט 2: Network Filter Module — שימוש ב-Netfilter hooks כדי לכתוב מודול שמסנן חבילות לפי כללים. זה מלמד עבודה עם ה-networking stack של הליבה.

פרויקט 3: דרייבר SPI לחיישן — חיבור חיישן תאוצה (כמו MPU-6050) דרך SPI, כתיבת Platform Driver עם Device Tree binding, וחשיפת הנתונים דרך ה-IIO subsystem של Linux.

כל אחד מהפרויקטים האלה דורש 40-80 שעות עבודה. זה לא קל. אבל בסוף יש לכם קוד שאפשר לשים ב-GitHub ולהציג למעסיק — וזה שווה יותר מכל תעודה.

שאלות נפוצות

האם צריך ידע מוקדם ב-C כדי ללמוד פיתוח Linux Kernel?

כן, ובאופן מוצק. Linux Kernel כתוב כמעט כולו ב-C — ולא ב-C רגיל, אלא עם שימוש נרחב ב-macros, pointer arithmetic, ו-bitwise operations. מי שלא שולט ב-C ברמה טובה — כדאי לחזק את זה קודם. אין קיצורי דרך פה.

מה ההבדל בין Kernel Module ל-Device Driver?

כל Device Driver הוא Kernel Module, אבל לא כל Kernel Module הוא דרייבר. מודול ליבה הוא כל קוד שאפשר לטעון ולהסיר מהליבה בזמן ריצה. דרייבר הוא סוג ספציפי של מודול שמספק ממשק לחומרה — או יותר נכון, שמתרגם בין ממשק אחיד (קריאות read/write/ioctl) לבין הפרוטוקול הספציפי של ההתקן.

האם אפשר לפתח דרייברים בלי חומרה פיזית?

בהחלט, ולרוב אפילו כדאי להתחיל ככה. QEMU מאפשר לסמלץ פלטפורמות ARM, RISC-V ו-x86 עם התקנים וירטואליים. אפשר גם ליצור "virtual devices" ב-User Space עם UIO (Userspace I/O) או לכתוב מודולים שעובדים עם pseudo-devices. כשהקוד מתייצב — עוברים לחומרה אמיתית.

כמה זמן לוקח להגיע לרמה של כתיבת דרייברים בפרודקשן?

לרוב, מהנדסים עם רקע חזק ב-C ו-Embedded Systems מגיעים ליכולת לכתוב דרייברים בסיסיים תוך 3-4 חודשים של לימוד ממוקד. לרמת פרודקשן — כולל טיפול ב-concurrency, power management, ו-error handling מקיף — מדובר בשנה עד שנתיים של עבודה מעשית. אין פה חוכמות: ככל שכותבים יותר קוד ומדבגים יותר קריסות, כך מתפתחים.

האם כדאי לתרום ל-Linux Kernel כקוד פתוח?

תרומה ל-mainline Linux Kernel היא אחת הדרכים החזקות ביותר לבנות מוניטין מקצועי. גם תיקון של באג קטן או שיפור תיעוד נחשבים. תהליך ה-review הוא קשוח — ה-maintainers לא מפרגנים סתם — אבל בדיוק בגלל זה patch שהתקבל שווה כל כך הרבה. טיפ: תתחילו עם staging drivers, שם הסף נמוך יותר.

מה ההבדל בין פיתוח דרייברים ב-Linux לבין Windows?

ב-Windows, פיתוח דרייברים עובד עם WDM (Windows Driver Model) או KMDF/UMDF, עם כלים ייעודיים של Microsoft. ב-Linux, הכול בקוד פתוח — אפשר לקרוא את קוד המקור של כל דרייבר קיים, ללמוד ממנו, ולהשתמש בו כבסיס. זה יתרון עצום ללמידה. בנוסף, Linux דומיננטי ב-Embedded (לפי Eclipse Foundation, כ-72% ממערכות ה-Embedded החדשות רצות על Linux), מה שאומר שהביקוש למפתחי דרייברים של Linux גבוה משמעותית.

אילו subsystems בליבה הכי חשוב להכיר?

זה תלוי בתחום. למערכות Embedded: הכירו את I2C, SPI, GPIO, ו-IIO subsystems. לרשתות: Netfilter, tc (traffic control), ו-eBPF. לאחסון: Block Layer ו-SCSI subsystem. לכולם: הכירו את מנגנוני ה-interrupt handling, workqueues, ו-DMA — אלה חוצי-תחומים ורלוונטיים בכל סוג של דרייבר.

הצעד הבא

כתיבת קוד ברמת הליבה היא לא עניין של גאונות — זה עניין של סבלנות, סקרנות, ונכונות לשבור את הראש מול dmesg בשעות לא סבירות. ארז עשה את זה. מהנדסים שמגיעים אלינו בכל שנה עושים את זה. ואם אתם קוראים את זה ומרגישים שהסקרנות דופקת — אתם בדרך הנכונה.

מי שרוצה לבנות את היכולת הזו בצורה מסודרת, עם ליווי מעשי, פרויקטים על חומרה אמיתית, ומנטורים שכתבו דרייברים בפרודקשן — מוזמנים לבדוק את מסלול Embedded Linux שלנו. המסלול בנוי בדיוק בשביל מהנדסים שרוצים לעשות את הקפיצה הזו.

ובינתיים — יש באתר rt-ed.co.il מדריכים נוספים, מאמרים טכניים, ותכנים שיעזרו לכם להתקדם. הדלת פתוחה. תיכנסו.


תחומי לימוד הכי מבוקשים בהייטק בשנת 2026

© כל הזכויות שמורות Real Time Group