应用程序访问设备

应用程序访问设备

2025 南京大学《操作系统原理》
应用程序访问设备

用程序访问设备

程序不能直接访问寄存器

center

  • 设备是可以在程序之间共享

仔细想:CPU 和内存也都是 “设备”

  • 操作系统实现了虚拟化
  • 我们也实现设备的虚拟化就行了!
2025 南京大学《操作系统原理》
应用程序访问设备

Everything is a File

File = 实现了文件操作的 “Anything”

struct file_operations {
 struct module *owner;
 loff_t (*llseek) (struct file *, loff_t, int);
 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
 ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
 ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
 int (*iopoll)(struct kiocb *kiocb, struct io_comp_batch *, uint flags);
 int (*iterate_shared) (struct file *, struct dir_context *);
 __poll_t (*poll) (struct file *, struct poll_table_struct *);
 long (*unlocked_ioctl) (struct file *, uint, ul);
 long (*compat_ioctl) (struct file *, uint, ul);
 int (*mmap) (struct file *, struct vm_area_struct *);
 ul mmap_supported_flags;
 int (*open) (struct inode *, struct file *);
 int (*flush) (struct file *, fl_owner_t id);
 int (*release) (struct inode *, struct file *);
 int (*fsync) (struct file *, loff_t, loff_t, int datasync);
 int (*fasync) (int, struct file *, int);
 int (*lock) (struct file *, int, struct file_lock *);
 ul (*get_unmapped_area)(struct file *, ul, ul, ul, ul);
 int (*check_flags)(int);
 int (*flock) (struct file *, int, struct file_lock *);
 ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, uint);
 ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, uint);
 void (*splice_eof)(struct file *file);
 int (*setlease)(struct file *, int, struct file_lease **, void **);
 long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len);
 void (*show_fdinfo)(struct seq_file *m, struct file *f);
 ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, loff_t, size_t, uint);
 loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in, struct file *file_out,
   loff_t pos_out, loff_t len, uint remap_flags);
 int (*fadvise)(struct file *, loff_t, loff_t, int);
 int (*uring_cmd)(struct io_uring_cmd *ioucmd, uint issue_flags);
 int (*uring_cmd_iopoll)(struct io_uring_cmd *, struct io_comp_batch *,
    uint poll_flags);
} __randomize_layout;
2025 南京大学《操作系统原理》
应用程序访问设备

设备驱动程序

一个 struct file_operations 的实现

  • 把系统调用 “翻译” 成与设备能听懂的数据
    • 就是一段普通的内核代码

例子

  • devfs 中的 “虚拟” 文件
    • /dev/pts/[x] - pseudo terminal
    • /dev/zero, /dev/null (实现), /dev/random, ...
  • procfs 中的 “虚拟文件”
2025 南京大学《操作系统原理》
应用程序访问设备

驱动 Nuclear Launcher

center

我们也可以实现一个

  • 把对 /dev/nuke0 “路由” 我们的 file_operations
  • 向 GPIO 的 memory-mapped address 写入正确的电平
  • (当然,我们只是模拟一下)
2025 南京大学《操作系统原理》
应用程序访问设备

配置设备

设备不仅仅是数据,还有配置

  • 打印机的卡纸、清洁、自动装订……
    • 一台几十万的打印机可不是那么简单 😂
  • 键盘的跑马灯、重复速度、宏编程……
  • 磁盘的健康状况、缓存控制……

两种实现方法

  • 控制作为数据流的一部分 (ANSI Escape Code)
  • 提供一个新的接口 (request-response)
2025 南京大学《操作系统原理》
应用程序访问设备

ioctl

The ioctl() system call manipulates the underlying device parameters of special files. In particular, many operating characteristics of character special files (e.g., terminals) may be controlled with ioctl() requests. The argument fd must be an open file descriptor.

“非数据” 的设备功能几乎全部依赖 ioctl

  • “Arguments, returns, and semantics of ioctl() vary according to the device driver in question”
2025 南京大学《操作系统原理》
应用程序访问设备

ioctl (cont'd)

堆叠的 💩

  • 设备的复杂性是无法降低的
    • “就是有那么多功能”
    • UNIX 的负担:复杂的 “hidden specifications”
      • 另一个负担:procfs

例子

  • 终端:为什么 libc 能 “智能” 实现 buffer mode?
  • 网卡,GPU,……
  • KVM Device (代码示例)
2025 南京大学《操作系统原理》