文章目录
前言
本系列内容力求将nvdla的用户态驱动整理清楚,如果有分析不对的请指出。
前面已经花了不少章节详细解释NVDLA内核态驱动代码,链接分别如下:
系列文章1:NVDLA内核态驱动代码整理一
系列文章2:NVDLA内核态驱动代码整理二
系列文章3:NVDLA内核态驱动代码整理三
系列文章4:NVDLA内核态驱动代码整理四
系列文章5:NVDLA内核态驱动代码整理五
系列文章6:NVDLA内核态驱动代码整理六
系列文章7:NVDLA内核态驱动代码整理七
系列文章8:NVDLA内核态驱动代码整理八
系列文章8:NVDLA内核态驱动代码整理汇总篇
欢迎阅读硬件信号和架构分析系列文章1:
架构开篇介绍文章:NVDLA内核态驱动代码整理三
系列文章1:NVDLA硬件信号和架构设计整理一
系列文章2:NVDLA硬件信号和架构设计整理二
系列文章3:NVDLA硬件信号和架构设计整理三
一、整理和规划
先从Makefile
开始看,确定哪些文件更为关键!
COMPILER_SUBDIRS = core/src/compiler \
apps/compiler
RUNTIME_SUBDIRS = core/src/runtime \
apps/runtime
# $(MAKE) -C $$dir; 这行执行了make命令,-C选项指定了要切换到的子目录。
compiler:
for dir in $(COMPILER_SUBDIRS); do \
$(MAKE) -C $$dir; \
done
runtime:
for dir in $(RUNTIME_SUBDIRS); do \
$(MAKE) -C $$dir; \
done
clean:
rm -rf out/
首先Makefile
清楚显示使用规则分为三条:compiler
、runtime
和clean
。与compiler
密切相关的文件是core/src/compiler
和apps/compiler
,与runtime
密切相关的文件是core/src/runtime
和apps/runtime
。因为用户态已经靠近上层,因此不再像内核态一样深入解读,而是会抓住几个核心问题进行思考。
另外,刚解读完内核态驱动,我们都知道驱动向上暴露供更上一层使用的API
,那么这堆API
如何被定义?可以发现umd
文件夹中包含了port/linux
文件夹,文件夹内容有nvdla_os.c
和nvdla.c
,我们可以先看nvdla.c
文件夹的开头,会发现这里出现了一位内核态驱动加载时出现的老朋友:
#include <drm.h>
#include <drm_mode.h>
#include "nvdla.h"
#include "nvdla_inf.h"
#include "nvdla_ioctl.h"
#include "nvdla_os_inf.h"
#define NVDLA_DEVICE_NODE "/dev/dri/renderD128" // 定义了 NVDLA 设备节点的路径。
#define NVDLA_MEM_READ (PROT_READ)
#define NVDLA_MEM_WRITE (PROT_WRITE)
这里的/dev/dri/renderD128
最早出现modprobe
驱动之后查看驱动路径的时候出现,如下:
然后看一下官网对于运行时的博文介绍,链接在这里。根据运行时的若干函数去检索,大致可以确定core/src/runtime/Runtime.cpp
是运行时功能的核心文件,而编译模块的核心文件落在core/src/compiler/Compiler.cpp
。
二、需要回答的几个问题
那接下来就有几个问题:
1、用户态驱动做了什么?如何与AI编译器协作?
2、用户态驱动程序如何调用封装好的内核态驱动API?
3、根据流程,内核态驱动编译为.ko
之后使用mdprobe
加载到Ubuntu
上,用户态驱动程序如同应用程序一样编译运行到Ubuntu
上,那怎么理解一段已经运行好的二进制(内核态驱动)会帮到待运行的二进制(用户态驱动)?
1、第一个问题的回答比较容易,其实就是借助POSIX的线程库和两个驱动节点card0
和renderD128
的file operation
实现下陷后的调用,用户态驱动向上暴露接口提供给AI编译器。由于大佬在这篇文章中提到NVDLA的软件栈分为两个部分,一个是Compiler,Compiler在自己的主机上编译是与硬件无关的,而Runtime则需要调用KMD程序调度加速器,只能在板卡上运行。在这小节我们的目标是在ARM处理器上编译出Runtime,打通软件栈
,所以我并不打算针对编译器部分进行解释。
2、第二个问题值得深究,可以在nvdla.c
文件中找到两个很关键的fd
,NvDlaDeviceHandle
和NvDlaMemHandle
结构体中各自定义了一个fd
,这两个不同的fd
可以追溯到renderD128
和card0
。那怎么调用?举个open
的例子,用户态open
=>内核态do_sys_open
=>内核态文件操作中的open
,用户态的close
可以向下追溯到内核态的release
。
3、第三个问题本质上就是第二个问题。但是注意内核版本需要保持一致。
总结
本文开篇用户态驱动,并对将要分析的.c
文件进行了过滤。