ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

naos-riscv源码分析:device.h如何把设备注册、查找与读写串起来

naos-riscv源码分析:device.h如何把设备注册、查找与读写串起来 这篇原来主要列出设备类型和结构成员。这次围绕一个问题重新串起来调用者手里只有设备号为什么公共入口能调用到具体设备的 read本次补充以提交490d5f0d3adf83c5670a181a2708a5c4a670d4c6的kernel/src/dev/device.h和device.c为参照。该版本与原图的数组、分类和五类操作相符但不声称已找回截图时的精确提交。新版已修改数据结构和回调参数阅读时不要混用。历史 device.h历史 device.c。1. 表容量、名字、分类先分清不同用途DEVICE_NR256是数组容量历史分配函数从下标 1 开始找空位不能直接说它支持 256 个可分配设备。NAMELEN16是字符数组容量。若名字作为 C 字符串使用就要给终止符留位置通常最多 15 个字节。原实现使用strncpy(..., NAMELEN)长度达到容量时不会自动保证终止符。这是需要检查的边界不是头文件替调用者保证的安全条件。type表示字符、块、网络等大类subtype区分控制台、输入、磁盘、分区等。不要仅因为存在 type 字段就推断所有代码都按它分组所选实现的device_find实际按 subtype 筛选。2. 一个设备对象同时保存身份、数据和操作成员用途name展示或注册用的名字type、subtype分类dev公共设备号parent父设备号具体关系由注册者提供ptr驱动私有上下文不等于设备号ioctl、poll、read、write、map操作回调未实现的操作可以为空读回调的历史声明ssize_t (*read)(void *dev, void *buf, uint64_t offset, size_t size, uint64_t flags);这里是内核接口摘录依赖内核类型不是独立程序。尤其要注意回调参数名虽然叫dev实际传入的是结构体中的ptr不是数值设备号。这就是统一接口的价值调用者通过设备号进入公共层负责找到对象驱动通过私有上下文工作。公共层不用了解每个驱动的内部结构。3. 从注册到读取连成一条路径历史注册函数的过程是找空槽位保存分类和 ptr分配设备号保存回调调用devfs_register_device返回设备号。设备号构造为device-dev (dev_major 8) | dev_minor;这里dev_major来自 subtypedev_minor来自该子类型的递增计数。这是所选版本的编码规则不代表任意操作系统都这样编码。计数超出低八位时怎样处理仍需要额外检查。实际读入口摘录ssize_t device_read(uint64_t dev, void *buf, uint64_t idx, size_t count, uint64_t flags) { device_t *device device_get(dev); if (!device) return -ENODEV; if (device-read) return device-read(device-ptr, buf, idx, count, flags); return -ENOSYS; }可以按下面的路径理解调用者提供设备号 dev、缓冲区、位置、数量、flags - device_get(dev) 搜索设备对象 - 找不到-ENODEV - 找到但没有 read-ENOSYS - 有 read把 ptr 和其余参数交给回调 - 回调结果原样返回例如一次演示读设备号选中对象后回调接到的是该对象保存的上下文、位置 2、长度 3而不是设备号本身。若演示驱动的数据为abcdef返回的三个字节可以是cde。这是本次用户态替身测试的例子不是 naos 磁盘驱动实测结果。device_get(dev)按设备号找对象device_find(subtype, idx)找的是某子类型中的第 idx 个对象。后者的 idx 不是数组下标也不能无条件当设备号使用。4. 和 block.h 的差别统一入口不等于统一单位控制命令里有起始 LBA、扇区数量和扇区大小不代表每一种设备都必须支持它们。device.h是通用设备对象和分发接口block.h 专门处理块设备相关属性与请求。两篇参照的是不同历史提交不把它们拼成一个已验证的共同运行版本。尤其不能看到通用 read 的 offset/size 就断言它们在所有设备中都是字节公共层在这里原样透传参数真正约定由具体回调决定。想确认磁盘或分区的单位要继续追踪对应适配函数不能停在头文件。5. 验证与尚未解决的边界本次对照固定提交的注册、查找与分发实现用用户态替身核对 ptr、位置、长度和 flags 的传递另测不存在设备、缺少回调两个分支。不运行完整内核也不冒充硬件验证。历史代码还有值得追问的地方表满时注册者是否处理空指针设备名是否终止编号计数是否限制热拔插后怎么处理已持有的引用并发查找与修改怎样同步。它们是后续审查问题不是因为提供一个结构体就自动解决了。新人可以先看懂“注册保存对象读取查找对象再调用回调”熟悉 C 的读者则可以从接口契约继续追问单位、所有权、错误码和并发。这样一份头文件才真正连到了程序行为上。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进