是否可以用Java编写设备驱动程序?

介绍

我听说过用Java编写设备驱动程序(听说“用我的耳朵”,而不是来自互联网)并且想知道……我一直认为设备驱动程序在操作系统级别上运行,因此必须用同一种语言编写作为操作系统(因此主要是CI假设)

问题

  1. 这个假设我一般都错了吗? (看起来如此)
  2. 如何在操作系统中使用“外星人”语言的驱动程序?
  3. 无论如何,对于设备驱动程序有什么要求(从编程语言的角度来看)?

谢谢阅读

有几种方法可以做到这一点。

首先,在“OS级别”运行的代码不需要用与OS相同的语言编写。 它只需要能够与OS代码链接在一起。 实际上,所有语言都可以与C进行互操作,这实际上就是所需要的。

语言方面,技术上没有问题。 Java函数可以调用C函数,C函数可以调用Java函数。 如果操作系统不是用C语言编写的(比如说,为了论证它是用C ++编写的),那么OS C ++代码可以调用一些中间的C代码,这些代码转发到Java,反之亦然。 C几乎是编程的通用语言

程序编译后(到本机代码),其源语言不再相关。 无论在编译之前编写源代码的语言是什么,汇编程序看起来都大致相同。 只要您使用与操作系统相同的调用约定,就没有问题。

更大的问题是运行时支持。 操作系统中没有很多软件服务可用。 例如,通常没有Java虚拟机。 (没有理由在技术上不可能,但通常,但通常,假设它不存在是安全的)。

不幸的是,在其“默认”表示中,作为Java字节码,Java程序需要大量的基础结构。 它需要Java VM来解释和JIT字节码,它需要类库等等。

但是有两种方法:

  • 在内核中支持Java。 这将是一个不寻常的步骤,但它可以做到。
  • 或者将Java源代码编译为本机格式。 Java程序不必编译为Java字节码。 您可以将其编译为x86汇编程序。 您使用的任何类库都是如此。 那些也可以编译到汇编程序。 当然,Java类库的某些部分需要某些不可用的OSfunction,但是可以避免使用这些类。

是的,它可以做到。 但这并不简单,而且还不清楚你会获得什么。

当然另一个问题可能是Java不允许你访问任意内存位置,这会使很多硬件通信变得非常棘手。 但也可以通过调用非常简单的C函数来解决这个问题,这些函数只是将相关的内存区域作为Java的数组返回。

用Java编写Solaris设备驱动程序包括用Java编写的A RAM磁盘设备。

Linux的另一个 。 更深入地了解为什么你可能也想要Java中的DD(因为有些人对其他post和评论的外观感到疑惑)

这不是不可能,但可能很难,可能没有多大意义。

可能是这样,因为Java是一种普通的编程语言,只要你有办法访问数据,就没问题了。 通常在现代操作系统中,内核有一层允许以某种方式对硬件进行原始访问。 在用户空间中也已存在驱动程序,至少用户空间部分在Java中实现应该没有问题。

它可能没有多大意义,因为内核必须启动JVM来执行驱动程序。 JVM实现通常也会占用大量内存。

您还可以使用编译的Java代码在平台上本机执行(而不是在JVM的帮助下)。 这通常效率不高,但它可能适用于设备驱动程序。

问题是,用Java实现驱动程序是否有意义? 或者以另一种方式说明:如果您使用Java实现驱动程序而不是其他替代方案,您希望获得的好处是什么? 如果你能回答这个问题,你应该找到一种方法来实现它。

最后给JNode提示, 这是一个试图完全基于Java实现完整操作系统的项目。

您的设备驱动程序视图太窄。

我已经在汽车应用中在MOST上编写了这样的设备驱动程序。 如果Java有一个像样的USB库,更广泛的使用可能是USB设备的驱动程序。

在这些情况下,有一个通用的低级协议,用本机代码处理,Java驱动程序处理设备细节(数据格式,状态机,……)。

您是否听说过JDDK ?

如果没有本机代码来提供100%的Java设备驱动程序,则无法提供(1)特定于操作系统的驱动程序入口点和约定,以及(2)JVM实例之间的交互。 JVM实例可以“在进程中”启动(并且“进程内”可能具有不同的含义,具体取决于操作系统以及驱动程序是内核模式还是用户模式驱动程序),或者作为单独的用户区域薄的本机驱动器适配层可以与之通信的过程,并且所述驱动器适配层可以卸载实际的用户 – 土地工作。

设备驱动程序可能很多东西

我实际上用java编写设备驱动程序: 工业设备的驱动程序 ,如秤或称重设备,包装机,条形码扫描仪,称重桥,包和盒式打印机…… Java是一个非常好的选择。

工业设备与家庭/办公设备(例如扫描仪,打印机)很大不同 。 特别是在制造业(例如食品)中,公司越来越多地选择运行MES应用程序的集中式服务器(例如用Java开发) MES服务器需要与生产线的设备连接,但也包含业务逻辑。 Java是一种可以兼顾两者的语言。

如果您的家庭/办公设备通常内置于您的计算机或通过USB电缆连接,这些工业设备通常使用以太网或RS232连接器。 所以,从本质上讲,几乎每种语言都可以完成这项工作。

该领域尚未实现太多标准化。 大多数供应商更喜欢为他们的设备创建自己的协议。 毕竟他们是硬件构建者,而不是软件天才。 结果是协议的多样性很高。 一些供应商更喜欢简单的纯文本协议,但其他供应商更喜欢具有CRC代码,成帧的复杂二进制协议……有时他们喜欢堆叠多个协议(例如,在OPC层之上的供应商特定的握手算法)。 强大的OOP语言在这里有很多优点。

例如,我以100毫秒/周期的连续速度看过java打印。 这包括生成唯一标签,将其发送到打印机,接收确认,将其打印在纸上并使用气压将其应用于产品。

总之,java的力量:

  • 它对于作为复杂接口的业务逻辑都很有用。
  • 它与Csockets的通信一样可靠。
  • 一些驱动程序可以从Java的OOPfunction中受益。
  • Java足够快。

可以将Java代码编译为硬件本机(即非JVM字节码)指令。 例如参见GCJ 。 有了这个,你就可以比以前更接近编译设备驱动程序了。

不过,我不知道它有多实用。

可能?

是的,但仅限于特殊情况。 因为您可以用Java和C#编写操作系统,然后,应该能够为它编写设备驱动程序。 这些驱动程序和操作系统的内存将是巨大的。

可能?

不见得。 至少不是在Windows或MacOS甚至Linux的世界……至少不会很快。 因为像C#和Java这样的语言依赖于CLR和JVM。 这些语言的工作方式意味着它们无法有效地加载到ring0中。

此外,如果在设备驱动程序中使用托管语言,性能损失将相当大。

为了动力,请记住,有很多快速语言比C语言更适合编程; 它们可能没有C那么快,但它们是安全的语言:如果你犯了一个错误,你就不会得到未定义的行为。 并且“未定义的行为”包括执行由格式化HD的攻击者提供的任意代码。 许多函数语言通常编译为本机代码。

设备驱动程序包含操作系统内核中的大多数错误 – 我知道对于Linux(Linus Torvalds和其他人一直这样说)我听说过Windows。 而对于磁盘或以太网驱动程序,您需要一流的性能,而在Linux驱动程序中,今天 10G以太网或SSD磁盘的瓶颈,大多数驱动程序不需要那么快的速度 – 所有计算机都以相同的速度等待。

这就是为什么有各种项目允许编写在内核之外运行的驱动程序,即使这会导致速度减慢; 当你能做到这一点时,你可以使用你想要的任何语言; 然后你需要为你使用的硬件控制库进行Java绑定 – 如果你用C编写驱动程序,你仍然会有一个带有C绑定的库。

对于内核模式适当的驱动程序,我还没有提到两个问题:

  • 垃圾收集,这是一个艰难的要求。 你需要编写一个内核垃圾收集器; 一些GC算法依赖于虚拟内存,您无法使用它们。 此外,您可能需要扫描整个OS内存以找到GC的根。 最后,我只相信一种保证(软)实时GC的算法,这会使开销更大。 阅读在Linux之上提到的关于Java设备驱动程序的文章,他们只是放弃了,并要求程序员手动释放内存。 他们试图争辩说这不会危及安全,但我不认为他们的论点是令人信服的 – 他们是否理解垃圾收集是否需要安全语言甚至不清楚。

  • 反思和类加载。 即使在运行本机代码时,完整的Java实现也需要能够加载新代码。 这是一个你可以避免的库,但是如果你在内核中有一个解释器或JIT编译器(并且没有真正的原因让它在技术上不可能)。

  • 性能。 关于Linux上的JVM的论文非常糟糕,它们的性能数据并不令人信服 – 事实上,它们测试的是USB 1.1网络驱动程序,然后表明性能并不是那么糟糕! 但是,如果付出足够的努力,肯定可以做得更好。

最后两件事:

  • 我想提一下Singularity,这是一个用C#变体编写的完整操作系统,只有一个本地语言的硬件抽象层。
  • 关于picoJava,使用它是一个坏主意,除非你的系统是一个真正受内存限制的系统,比如智能卡。 Cliff Click已经解释了原因:它为编写一个好的JIT提供了更好的性能,而现在甚至智能手机也可以支持它。

设备驱动程序必须使用可在内核中执行的语言编写,或者编译到其中,或者在运行时作为模块加载。 这通常会妨碍用Java编写设备驱动程序,但我认为理论上你可以在设备驱动程序中实现JVM并让它执行Java代码。 并不是说任何理智的人都想要这样做。

在Linux上有几个文件系统的用户域(即非内核)实现,它们使用一个称为(fuse)的通用抽象层,允许用户域程序实现通常在内核中完成的事情。

Windows Driver Foundation(WDF)是一个Microsoft API,允许编写用户和内核模式设备驱动程序。 这是在今天完成的,它现在与w2k及更高版本兼容(曾经没有将w2k作为支持的目标)。 没有理由不能让JNI调用在JRE中做一些工作。 。 。 (假设JNI仍然是从C / C ++调用Java的方式……我的知识在那个领域已经过时了)。 这可能是一种有趣的方法,让高级算法直接咀嚼USB管道中的数据,以实现这种效果。 。 。 很酷的东西!

PCIe用户空间设备驱动程序可以用Pure Java编写。 有关基于内存的直接硬件访问的详细信息,请参阅JVerbs ,在OFED的上下文中。 这是一种可用于创建高性能系统的技术。

您可以检查PCI总线以确定给定设备的内存区域,它具有的端口等。内存区域可以映射到JVM的进程中。

当然,你自己负责实现一切

我没说简单。 我说可能。 ;)

另请参阅用户空间中的设备驱动程序 ,其中讨论了使用UIO框架构建用户空间驱动程序。

首先,请注意我不是设备驱动程序方面的专家(虽然我当天写了一些自己的东西),更不用说Java专家了。

让我们留下这样一个事实:用高级语言编写设备驱动程序并不是一个好主意(出于性能和可能的其他原因)暂时搁置,并回答你的问题。

可以用几乎任何语言编写设备驱动程序,至少在理论上是这样。

但是, 大多数设备驱动程序需要执行大量低级操作,例如使用操作系统API和系统调用来处理中断和与操作系统通信,我相信你不能用Java做。

但是,如果您的设备使用串行端口或USB进行通信,并且操作系统不一定需要知道设备(只有您的应用程序将访问设备*),那么您可以在任何设备中编写驱动程序提供访问设备的必要手段的语言。

因此,例如,您可能无法用Java编写SCSI卡驱动程序,但您可以为专有控制设备,USB熔岩灯,许可证加密狗等编写驱动程序。

*这里显而易见的问题当然是否算作司机?