2023年8月4日 星期五

Linux Kernel(21.1)- ID Allocation


如同ID Allocation的Overview提到的, kernel提供了對應的一些API, 用以產生與維護identifiers (IDs), 舉凡file descriptor, process IDs, device instance number等等. IDR主要多了ID與pointer的對用能力, 而IDA就是單純的分配ID, 本章透過簡單的程式碼讓大家能瞭解與使用IDA.

首先, 該範例是個簡易的kernel module, 透過DEFINE_IDA(my_ida)宣告一個my_ida變數, 這是我們, 並透過read file operation去取得一個新的ID(ida_simple_get), 在write file operation中透過寫入特定ID移除該ID(ida_simple_remove), 最後在移除kernel module時, 使用ida_destroy(struct ida * ida)把所有的IDA resource都釋放, 不然會造成memory leak.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/idr.h>
#include <linux/moduleparam.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h> // Required for copy_from_user

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Brook");
MODULE_DESCRIPTION("Kernel module to demo IDA");
MODULE_VERSION("0.1");

static DEFINE_IDA(my_ida);

static ssize_t ida_demo_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
    int id, len;
    char tmp_buf[10];

    id = ida_simple_get(&my_ida, 0, 0, GFP_KERNEL);
    if (id >= 0) {
        printk(KERN_INFO "IDR Demo: Successfully allocated ID: %d\n", id);
    } else {
        printk(KERN_ERR "IDR Demo: Failed to allocate ID\n");
        return -ENOMEM;
    }

    len = snprintf(tmp_buf, sizeof(tmp_buf), "%d", id);
    if (len < 0) {
        return -EINVAL;
    }

    if (copy_to_user(buf, tmp_buf, len)) {
        return -EFAULT;
    }

    return 0;
}

static ssize_t
ida_demo_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
    char tmp_buf[20];
    int id;

    if (count >= sizeof(tmp_buf))
        return -EINVAL;

    if (copy_from_user(tmp_buf, buf, count))
        return -EFAULT;

    tmp_buf[count] = '\0';
    // Convert the input string to an integer
    if (kstrtoint(tmp_buf, 10, &id)) {
        printk(KERN_ERR "invalid ID: %s\n", tmp_buf);
        return -EINVAL;
    }

    printk(KERN_INFO "remove ID %d\n", id);
    ida_simple_remove(&my_ida, id);

    return count;
}

// Define a file operation structure for IDA access
static struct file_operations ida_fops = {
    .open = simple_open,
    .read = ida_demo_read,
    .write = ida_demo_write,
    .llseek = default_llseek,
};

static int __init ida_demo_init(void)
{
    struct proc_dir_entry *proc_entry;

    printk(KERN_INFO "IDR Demo: Initializing module\n");

    // Create a file entry to invoke 'ida'
    proc_entry = proc_create("ida", S_IRUGO, NULL, &ida_fops);
    if (!proc_entry) {
        printk(KERN_ERR "Failed to create sysfs entry for 'ida'\n");
        return -ENOMEM;
    }
    return 0;
}

static void __exit ida_demo_exit(void)
{
    printk(KERN_INFO "IDR Demo: Exiting module\n");
    ida_destroy(&my_ida);
}

module_init(ida_demo_init);
module_exit(ida_demo_exit);


簡易的Makefile
KDIR ?= /build/brook/Projects/qemu/linux/
# Modules which are included in the kernel are installed in the
# directory:
#       /lib/modules/$(KERNELRELEASE)/kernel/
# And external modules are installed in:
#       /lib/modules/$(KERNELRELEASE)/extra/
#
# INSTALL_MOD_PATH
# A prefix can be added to the
#       installation path using the variable INSTALL_MOD_PATH:
#
#       $ make INSTALL_MOD_PATH=/frodo modules_install
#       => Install dir: /frodo/lib/modules/$(KERNELRELEASE)/kernel/
export INSTALL_MOD_PATH=/build/brook/Projects/qemu/initrd-arm
obj-m := ida_demo.o
ida_demo-y := ida_main.o

modules modules_install clean:
 $(MAKE) -C $(KDIR) M=$$PWD $@


這是在QEMU下執行的結果, 會先產生ID 0/1/2, 然後移除1, 接著再產生的ID就會把1生出來, 再來就是3了, 所以透過IDA, 可以幫user管理ID(唯一的編號)
/ # uname -a
Linux (none) 5.4.0+ #6 SMP Tue Jan 3 08:39:24 CST 2023 armv7l GNU/Linux
/ # insmod /lib/modules/5.4.0+/extra/ida_demo.ko
ida_demo: loading out-of-tree module taints kernel.
IDR Demo: Initializing module
/ # cat /proc/ida
IDR Demo: Successfully allocated ID: 0
/ # cat /proc/ida
IDR Demo: Successfully allocated ID: 1
/ # cat /proc/ida
IDR Demo: Successfully allocated ID: 2
/ # echo 1 > /proc/ida
remove ID 1
/ # cat /proc/ida
IDR Demo: Successfully allocated ID: 1
/ # cat /proc/ida
IDR Demo: Successfully allocated ID: 3



  • https://www.kernel.org/doc/html/v5.4/core-api/idr.html, ID Allocation




2023年1月1日 星期日

Table Of Content for tag "Linux - kernel"


Linux Kernel(1)- Linux Module簡介
Linux Modules(1.1)module parameters

Linux Kernel(2)- register char device
Linux Kernel(2.1)- MAJRO NUMBER RESERVED FOR DYNAMIC ASSIGNMENT

Linux Kernel(3)- procfs
Linux Kernel(3.1)- procfs之vector方式寫入
Linux Kernel(3.2)- procfs之symlink與mkdir

Linux Kernel(4)- seq_file
Linux Kernel(4.1)- seq_file之範例(fp/proc/devices.c)
Linux Kernel(4.2)- seq_file之single page

Linux Kernel(5)- ioctl

Linux Kernel(6)- miscdev

Linux Kernel(7)- timing
Linux Kernel(7.1)- timer
Linux Modules(7.2)- tasklet
Linux Modules(7.3)- work queue

Linux Kernel(8)- Notification
Linux Kernel(8.1)- Notifier機制剖析

Linux Kernel(9)- Kthread

Linux Kernel(10)- MTD/Memory Technology Device
Linux Kernel(10.1)- drivers/mtd/devices/mtdram.c
Linux Kernel(10.2)- mtd partitions
Linux Kernel(10.3)- Command line partition table parsing
Linux Kernel(10.3.1)- Command line partition table parsing for Kernel 4.19

Linux Kernel(11)- sysfs and device node
Linux Kernel(11.1)- sysfs and hotplug
Linux Kernel(11.2)- mdev.conf

Linux Kernel(12)- netfilter
Linux Kernel(12.1)- netfilter機制之初探

Linux Kernel(13)- syscall

Linux Kernel(14)- Kernel Synchronization
Linux Modules(14.1)- Read Copy Update

Linux Kernel(15)- Platform Devices
Linux Kernel(15.1)- platform_driver_register()之如何调用driver.probe()
Linux Kernel(15.2)- platform_device_register()之如何调用driver.probe()
Linux Kernel(15.3)- The Linux usage model for device tree data

Linux Kernel(16.1)- Network Device Driver, simple snull

Linux Kernel(17)- Device Tree
Linux Kernel(17.1)- Basic Device Tree syntax
Linux Kernel(17.2)- Common Device Tree API

Linux Kernel(18)- Virtual File System
Linux Kernel(18.1)- My First Filesystem
Linux Kernel(18.2)- SysCall mount

Linux Kernel(19)- General Purpose Input/Output
Linux Kernel(19.1)- /sys/class/gpio usage

Linux Kernel(20)- Input device
Linux Kernel(20.1)- Input device user program
Linux Kernel(20.2)- uinput module
Linux Kernel(20.3)- Creating an input device driver

Linux Kernel(21)- ID Allocation
Linux Kernel(21.1)- ID Allocation
Linux Kernel(21.2)- radix tree API
Linux Kernel(21.3)- radix tree implementation

Linux Kernel(22)- Linux Socket
Linux Kernel(22.1)- My Socket Domain and Protocol

Linux Kernel(23)- SKB


Linux Kernel(24)- Multimedia Card
Linux Kernel(24.1)- fdisk Multimedia Card

Linux Kernel(25)- USB(Universal Serial Bus)
Linux Kernel(25.1)- Gadget Configfs




2022年12月31日 星期六

Linux Kernel(19.1)- /sys/class/gpio usage


要能使用/sys/class/gpio就要先開啟相關kernel config如下, 如提示所說, 該ABI已經棄用, 改由character device /dev/gpiochipN取代, 不過這裡還是會簡單交代一下相關資訊, 作為紀錄.
  │ CONFIG_GPIO_SYSFS:                                                                             │
  │                                                                                                │
  │ Say Y here to add the legacy sysfs interface for GPIOs.                                        │
  │                                                                                                │
  │ This ABI is deprecated. If you want to use GPIO from userspace,                                │
  │ use the character device /dev/gpiochipN with the appropriate                                   │
  │ ioctl() operations instead. The character device is always                                     │
  │ available.                                                                                     │
  │                                                                                                │
  │ Symbol: GPIO_SYSFS [=y]                                                                        │
  │ Type  : bool                                                                                   │
  │ Prompt: /sys/class/gpio/... (sysfs interface)                                                  │
  │   Location:                                                                                    │
  │     -> Device Drivers                                                                          │
  │       -> GPIO Support (GPIOLIB [=y])                                                           │
  │   Defined at drivers/gpio/Kconfig:61                                                           │
  │   Depends on: GPIOLIB [=y] && SYSFS [=y]                                                       │                                   

在設定玩kernel config之後, 重新編譯kernel, 就可以看見"/sys/class/gpio"目錄, 裡面幾個重要的檔案,
export Userspace may ask the kernel to export control of a GPIO to userspace by writing its number to this file.
unexport Reverses the effect of exporting to userspace.

"echo 19 > /sys/class/gpio/export" 後, 目錄/sys/class/gpio/gpio19/就會被創建出來, 裡面會包含
direction reads as either "in" or "out"
value reads as either 0 (low) or 1 (high)
edge reads as either "none", "rising", "falling", or "both"
active_low reads as either 0 (false) or 1 (true)

此外還可以透過debugfs來檢查當前的GPIO設定
/ # cat /sys/kernel/debug/gpio
gpiochip3: GPIOs 499-499, parent: platform/basic-mmio-gpio.3.auto, sys_flash:

gpiochip2: GPIOs 500-501, parent: platform/basic-mmio-gpio.2.auto, sys_mci:
 gpio-500 (                    |cd                  ) in  lo
 gpio-501 (                    |wp                  ) in  lo

gpiochip1: GPIOs 502-509, parent: platform/basic-mmio-gpio.1.auto, sys_led:
 gpio-502 (                    |?                   ) out lo
 gpio-503 (                    |?                   ) out lo
 gpio-504 (                    |?                   ) out lo
 gpio-505 (                    |?                   ) out lo
 gpio-506 (                    |?                   ) out hi
 gpio-507 (                    |?                   ) out lo
 gpio-508 (                    |?                   ) out lo
 gpio-509 (                    |?                   ) out lo

gpiochip0: GPIOs 510-511, parent: platform/10000000.sysreg, 10000000.sysreg:

/ # ls -al /sys/class/gpio/
total 0
drwxr-xr-x    2 0        0                0 Jan  3 00:40 .
drwxr-xr-x   36 0        0                0 Jan  3 00:40 ..
--w-------    1 0        0             4096 Jan  3 00:40 export
lrwxrwxrwx    1 0        0                0 Jan  3 00:40 gpiochip499 -> ../../devices/platform/10000000.sysreg/basic-mmio-gpio.3.auto/gpio/gpiochip499
lrwxrwxrwx    1 0        0                0 Jan  3 00:40 gpiochip500 -> ../../devices/platform/10000000.sysreg/basic-mmio-gpio.2.auto/gpio/gpiochip500
lrwxrwxrwx    1 0        0                0 Jan  3 00:40 gpiochip502 -> ../../devices/platform/10000000.sysreg/basic-mmio-gpio.1.auto/gpio/gpiochip502
lrwxrwxrwx    1 0        0                0 Jan  3 00:40 gpiochip510 -> ../../devices/platform/10000000.sysreg/gpio/gpiochip510
--w-------    1 0        0             4096 Jan  3 00:40 unexport

接下來export 510, 511, 然後在unexport 511, 設定510, 相關操作如下
/ # echo 510 > /sys/class/gpio/export
/ # echo 511 > /sys/class/gpio/export
/ # ls -al /sys/class/gpio/
total 0
drwxr-xr-x    2 0        0                0 Jan  3 00:40 .
drwxr-xr-x   36 0        0                0 Jan  3 00:40 ..
--w-------    1 0        0             4096 Jan  3 00:43 export
lrwxrwxrwx    1 0        0                0 Jan  3 00:42 gpio510 -> ../../devices/platform/10000000.sysreg/gpiochip0/gpio/gpio510
lrwxrwxrwx    1 0        0                0 Jan  3 00:43 gpio511 -> ../../devices/platform/10000000.sysreg/gpiochip0/gpio/gpio511
lrwxrwxrwx    1 0        0                0 Jan  3 00:40 gpiochip499 -> ../../devices/platform/10000000.sysreg/basic-mmio-gpio.3.auto/gpio/gpiochip499
lrwxrwxrwx    1 0        0                0 Jan  3 00:40 gpiochip500 -> ../../devices/platform/10000000.sysreg/basic-mmio-gpio.2.auto/gpio/gpiochip500
lrwxrwxrwx    1 0        0                0 Jan  3 00:40 gpiochip502 -> ../../devices/platform/10000000.sysreg/basic-mmio-gpio.1.auto/gpio/gpiochip502
lrwxrwxrwx    1 0        0                0 Jan  3 00:40 gpiochip510 -> ../../devices/platform/10000000.sysreg/gpio/gpiochip510
--w-------    1 0        0             4096 Jan  3 00:40 unexport

/ # echo 511 > /sys/class/gpio/unexport
/ # ls -al /sys/class/gpio/
total 0
drwxr-xr-x    2 0        0                0 Jan  3 00:40 .
drwxr-xr-x   36 0        0                0 Jan  3 00:40 ..
--w-------    1 0        0             4096 Jan  3 00:43 export
lrwxrwxrwx    1 0        0                0 Jan  3 00:42 gpio510 -> ../../devices/platform/10000000.sysreg/gpiochip0/gpio/gpio510
lrwxrwxrwx    1 0        0                0 Jan  3 00:40 gpiochip499 -> ../../devices/platform/10000000.sysreg/basic-mmio-gpio.3.auto/gpio/gpiochip499
lrwxrwxrwx    1 0        0                0 Jan  3 00:40 gpiochip500 -> ../../devices/platform/10000000.sysreg/basic-mmio-gpio.2.auto/gpio/gpiochip500
lrwxrwxrwx    1 0        0                0 Jan  3 00:40 gpiochip502 -> ../../devices/platform/10000000.sysreg/basic-mmio-gpio.1.auto/gpio/gpiochip502
lrwxrwxrwx    1 0        0                0 Jan  3 00:40 gpiochip510 -> ../../devices/platform/10000000.sysreg/gpio/gpiochip510
--w-------    1 0        0             4096 Jan  3 00:43 unexport

/ # grep "" /sys/class/gpio/gpio510/*
/sys/class/gpio/gpio510/active_low:0
/sys/class/gpio/gpio510/direction:in
/sys/class/gpio/gpio510/value:0

/ # echo out > /sys/class/gpio/gpio510/direction
/ # grep "" /sys/class/gpio/gpio510/*
/sys/class/gpio/gpio510/active_low:0
/sys/class/gpio/gpio510/direction:out
/sys/class/gpio/gpio510/value:0

/ # cat /sys/kernel/debug/gpio
gpiochip3: GPIOs 499-499, parent: platform/basic-mmio-gpio.3.auto, sys_flash:

gpiochip2: GPIOs 500-501, parent: platform/basic-mmio-gpio.2.auto, sys_mci:
 gpio-500 (                    |cd                  ) in  lo
 gpio-501 (                    |wp                  ) in  lo

gpiochip1: GPIOs 502-509, parent: platform/basic-mmio-gpio.1.auto, sys_led:
 gpio-502 (                    |?                   ) out lo
 gpio-503 (                    |?                   ) out lo
 gpio-504 (                    |?                   ) out lo
 gpio-505 (                    |?                   ) out lo
 gpio-506 (                    |?                   ) out hi
 gpio-507 (                    |?                   ) out hi
 gpio-508 (                    |?                   ) out lo
 gpio-509 (                    |?                   ) out lo

gpiochip0: GPIOs 510-511, parent: platform/10000000.sysreg, 10000000.sysreg:
 gpio-510 (                    |sysfs               ) out lo

/ # grep "" /sys/class/gpio/gpiochip*/*
/sys/class/gpio/gpiochip499/base:499
/sys/class/gpio/gpiochip499/label:sys_flash
/sys/class/gpio/gpiochip499/ngpio:1
/sys/class/gpio/gpiochip500/base:500
/sys/class/gpio/gpiochip500/label:sys_mci
/sys/class/gpio/gpiochip500/ngpio:2
/sys/class/gpio/gpiochip502/base:502
/sys/class/gpio/gpiochip502/label:sys_led
/sys/class/gpio/gpiochip502/ngpio:8
/sys/class/gpio/gpiochip510/base:510
/sys/class/gpio/gpiochip510/label:10000000.sysreg
/sys/class/gpio/gpiochip510/ngpio:2



熱門文章