iT邦幫忙

2024 iThome 鐵人賽

DAY 2
0
自我挑戰組

LDD3 (Linux Device Drivers, 3th) 學習筆記系列 第 2

[Day02] Chapter 2: Building and Running Modules (1)

  • 分享至 

  • xImage
  •  

Summarize

  • A module runs in kernel space, whereas applications run in user space. This concept is at the base of operating systems theory
  • One way in which kernel programming differs greatly from conventional application
    programming is the issue of concurrency
  • Kernel code cannot do floating point arithmetic

Outline

  • The Hello World Module
  • Kernel Modules Versus Applications
  • User Space and Kernel Space
  • Concurrency in the Kernel
  • The Current Process
  • A Few Other Details

The Hello World Module

// KOBJ File: hello.ko
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
 printk(KERN_ALERT "Hello, world\n");
 return 0;
}
static void hello_exit(void)
{
 printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);

應該不太需要解釋,見操作:

insmod ./hello.ko
Hello, world
root# rmmod hello
Goodbye cruel world

Kernel Modules Versus Applications

https://ithelp.ithome.com.tw/upload/images/20240904/20138643wHFwtIavlO.png

  • This kind of approach to programming is similar to eventdriven programming, but while not all applications are event-driven, each and every kernel module is
  • As a programmer, you know that an application can call functions it doesn’t define:
    • the linking stage resolves external references using the appropriate library of functions
    • printf is one of those callable functions and is defined in libc
    • A module, on the other hand, is linked only to the kernel, and the only functions it can call are the ones exported by the kernel; there are no libraries to link to
      • The printk function used in hello.c earlier, for example, is the version of printf defined within the kernel and exported to modules

User Space and Kernel Space

A module runs in kernel space, whereas applications run in user space. This concept is at the base of operating systems theory

  • All current processors have at least two protection levels, and some, like the x86
    family, have more levels; when several levels exist, the highest and lowest levels are
    used
  • Under Unix, the kernel executes in the highest level (also called supervisor
    mode), where everything is allowed, whereas applications execute in the lowest level
    (the so-called user mode), where the processor regulates direct access to hardware
    and unauthorized access to memory
  • These terms encompass not only the different privilege levels inherent in the two modes, but also the fact that each mode can have its own memory mapping—its own address
    space—as well
  • The role of a module is to extend kernel functionality; modularized code runs in kernel space
    • Usually a driver performs both the tasks outlined previously: some functions in the module are executed as part of system calls, and some are in charge of
      interrupt handling

Concurrency in the Kernel

One way in which kernel programming differs greatly from conventional application
programming is the issue of concurrency

  • As a result, Linux kernel code, including driver code, must be reentrant
  • it must be capable of running in more than one context at the same time. Data structures must be carefully designed to keep multiple threads of execution separate, and the code
    must take care to access shared data in ways that prevent corruption of the data

The Current Process

  • most actions performed by the kernel are done on behalf of a specific process
  • Kernel code can refer to the current process by accessing the global item current, defined in <asm/current.h>, which yields a pointer to struct task_struct, defined by <linux/sched.h>
  • The current pointer refers to the process that is currently executing. During the execution of a system call, such as open or read, the current process is the one that invoked the call

The following statement prints the process ID and the command name of the current process by accessing certain fields in struct task_struct:

printk(KERN_INFO "The process is \"%s\" (pid %i)\n", current->comm, current->pid);

A Few Other Details

as you dig into the kernel, the following issues should be kept in mind:

  • Applications are laid out in virtual memory with a very large stack area. The stack, of course, is used to hold the function call history and all automatic variables created by currently active functions
  • The kernel, instead, has a very small stack; it can be as small as a single, 4096-byte page. Your functions must share that stack with the entire kernel-space call chain
    • Thus, it is never a good idea to declare large automatic variables; if you need larger structures, you should allocate them dynamically at call time

as you look at the kernel API, you will encounter function names starting with
a double underscore (__)

  • Functions so marked are generally a low-level component of the interface and should be used with caution
  • Essentially, the double underscore says to the programmer: “If you call this function, be sure you know what you are doing.”

Kernel code cannot do floating point arithmetic

  • Enabling floating point would require that the kernel save and restore the floating point processor’s state on each entry to, and exit from, kernel space—at least, on some architectures
  • The extra overhead is not worthwhile

Reference

  1. LDD3

上一篇
[Day01] Chapter 1: An Introduction to Device Drivers
下一篇
[Day03] Chapter 2: Building and Running Modules (2)
系列文
LDD3 (Linux Device Drivers, 3th) 學習筆記5
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言