内核模式编程是一个可怕的努力。 I IT中的一个大问题是C是您在Linux上唯一的选择。 C有很多历史问题,它可以' t真的固定在此时,而不是从根本地改变语言的角度,以C中写入的现有代码不兼容。
免责声明:这是alpha的东西。我希望这篇帖子快速到bitroot。 **不要指望在几年内仍然工作。**
< Mara>是的,是的,您可以在技术上使用C ++的相当限制的子集,然后您可以避免在新操作员上风险的RuntimePanics成本避免某些C-ISM。然而,那种东西不是今天读书的东西。
然而,最近,Linux内核已收到一个RFC用于在很方便的内核中的RUST支持,甚至包括一些示例。我有一个侵入性的想法,这是一种情况:
< cadey>嗯,我想知道我是否可以将打印机事实API搬到这个,ITCan' t是那么难,对吧?
在一个高水平的情况下做这样的事情,你需要有几件事:
一种能够在另一台机器上重复这些测试的方法,以便更多地证明你所做的事情不止一次
为了帮助努力,Linux团队的RUDED发布了一个nixconfig,让您在您想要的时候才能让您NIX-Build -a kernelyourself一个新内核。所以让' s做到这一点,看看whathappens:
$ nix-build -a内核<几个megs of expute剪掉>错误:无法构建存档:没有这样的文件或directoryerror:由于以前的errormake而下降[2]:*** [../rust/makefile:124:RUDE /core.o]错误1make [2]:***删除文件' rust / core.o' make [1]:*** [/tmp/nix-build-linux-5.11.drv- 0 / Linux-src / makefile:1278:prepared0]错误2make [1]:离开目录' /tmp/nix-build-linux-5.11.drv-0/linux-src/build& #39; make:* ** [makefile:185:__sub-make]错误2builder for' /nix/store/yfvs7xwsdjwkzax0c4b8ybwzmxsbxrxj-linux-5.11.drv'退出代码2Error失败:建立' /nix/store/yfvs7xwsdjwkzax0c4b8ybwzmxsbxrxj-linux-5.11.drv'失败的
哦亲爱的。这是奇怪的。让' s看问题跟踪器是否有任何有用。它做了!哦,你有同样的同品,这意味着失败被复制!
$树..──默认.nix├──kernel.nix├──许可证──尼克斯·├──索斯.Json││──Sources.nix└──自述.md
这个项目看起来像它使用niv锁定nix依赖项的#39。让' s看看sources.json,看看是什么选择我们更新事物。
< Mara>你也可以使用NIV展示来看这个,但看着JSON本身就是Multifun
{&#34;&#34 ;: {&#34;分支&#34 ;:&#34;生锈&#34 ;,&#34;描述&#34 ;:&#34;为生锈语言添加支持Linux内核。&#34 ;,&#34;主页&#34 ;:&#34;&#34 ;,#34;所有者&#34 ;:&#34; rust-for-linux&#34 ;,&# 34;回购&#34 ;:&#34; linux&#34;&#34; rev&#34 ;:&#34; 304ee695107a8b49a833bb1f02d58c1029e43623&#34 ;,&#34; sha256&#34 ;:&#34; 0WD1F1HFPL06YYP482F9LGJ7L7R09ZFQCI8AWXK9AHHDRX567Y50&#34 ;&#34;类型&#34 ;:&#34; tarball&#34;&#34; url&#34 ;:&#34; https://github.com/rust-for-linux/linux/archive /304EE695107A8B49A833BB1F02D58C1029E43623.tar.gz"&#34; url_template&#34 ;:&#34; https://github.com/<所有者&gt; /&lt; repo&gt; / inclive /&lt; rev&gt; .tar。 GZ&#34; },&#34; niv&#34 ;: {&#34;分支&#34 ;:&#34; master&#34 ;,&#34; description&#34 ;:&#34; NIX项目的简单依赖管理&#34; 34 ;,&#34;主页&#34 ;:&#34; https://github.com/nmattia/niv" ;,&#34;所有者&#34 ;:&#34; nmattia&#34 ;, #34; repo&#34 ;:&#34; niv&#34;&#34; sev&#34 ;:&#34; af958e8057f345ee1ca714c12475ee3ba1c15f5e&#34; sha256&#34 ;:&#34; 1qjavxabbrsh73yck5dcq8jggvh3r2jkbr6b5nlz5d9yrqm9255n&# 34,&#34;类型&#34 ;:&#34;压缩档&#34;,&#34; URL&#34 ;:&#34; HTTPS://github.com/nmattia/niv/archive/af958e8057f345ee1aca714c1247ef3ba1c15f5e。 tar.gz&#34 ;,&#34; url_template&#34 ;:&#34; https://github.com/<所有者&gt; /&lt; repo&gt; /存档/ rev&gt; .tar.gz&#34 ; },&#34; nixpkgs&#34 ;: {&#34;分支&#34 ;:&#34; master&#34;&#34;描述&#34 ;:&#34; nix包集合&#34 ;, &#34;主页&#34 ;:&#34;&#34;和#34;所有者&#34 ;:&#34; nixos&#34 ;,&#34; repo&#34 ;:&#34; nixpkgs&#34; nixpkgs& #34;,&#34;转&#34 ;:&#34; f35d716fe1e35a7f12cc2108ed3ef5b15ce622d0&#34;,&#34; SHA256&#34 ;:&#34; 1jmrm71amccwklx0h1bij65hzzc41jfxi59g5bf2w6vyz2cmfgsb&#34;,&#34;类型&#34&;: #34; tarball&#34 ;,&#34; url&#34 ;:&#34; https://github.com/nixos/nixpkgs/acrive/f35d716fe1e35a7f12cc2108ed3ef5a7f12cc2108ed3ef5a7f12cc2108ed3ef5a7f12cc2d0.tar.gz" ;,&#34; url_template&# 34 ;:&#34; https://github.com/<所有者&gt; /&lt; repo&gt; / incrive /&lt; rev&gt; .tar.gz&#34; }}
它看起来像那里&#39; s 3的东西:内核,niv本身(niv由defaultso做到这一点,我们可以忽略它),并且一些随机的nixpkgs在其默认分支上提交。让&#39; SSEE这个提交的年龄是多大的:
嗯,我知道Nixos中的Rust已经更新了。在输出的Opegs的某处我削减了它提到我使用的是生锈1.49。让&#39; s看rust的Amodern版本是否使此构建:
而那建立我注意到它似乎是从来源建造生锈。这一列为奇怪的是奇怪的。它看起来像是因为某种原因重建了Rust的稳定版本。让&#39;我看看kernel.nix看它是否有任何可能有用的人:
rustChertynelly = rustplatform.rust.rustc.overrideattr 34;否则标志)oldattrs.configureflags;});
&lt; Mara&gt;等等,什么。覆盖了RUDE的编译器标志,使得它将令人叹为观的版本变为夜间版本?
是的!由于各种原因是读者的锻炼,很多东西都需要锈病的内核空间开发被锁定到夜间释放。追逐夜间释放的龙可能有点令人讨厌和不稳定,所以这个代码的代码段让nix重建一位稳定的防锈释放。
Linux内核是一项计算机程序,所以逻辑上我们必须能够在某个地方逃跑,然后我们应该能够看到事情是否正在做什么Wewant,对吧?
NixOS提供了一个设施,用于测试整个系统配置为AUNIT。 ITRUNS在VM中的这些测试,以便我们可以孤立的东西 - ish并阻止子内核的Anysins破坏了父内核的日子。我在我的nixos-configs中有一个templatetest,我们可以在on sho.cn .so开始,&#39;首先从这样的东西开始,从那里积累:
让Sources = Import./nix/sources.nix; pkgs = sources.nixpkgs;在导入&#34; $ {pkgs} /nixos/tests/make-test-python.nix" ({pkgs,...}:{system =&#34; x86_64-linux&#34 ;; nodes.machine = {config,pkgs,...}:{virtualisation.graphics = false;}; testscript =&# 39;&#39; start_all()machine.wait_until_succeeds(&#34; uname-av&#34;)&#39;&#39 ;;})
&lt; Mara&gt;对于那些扮演Christine Dot网站的家庭游戏,您可能希望抓住该文件的顶部,为自己的项目获得其PKGS与某种东西PKGS =&lt; nixpkgs&gt ;;。 Sources.pkgs的东西在这里用于Jivewith niv。
$ nix-build ./test.nix< much更多输出&gt;机器:(连接需要4.70秒)(4.72秒)machine#sh:无法设置终端进程组(-1):DeviceMachine#sh:没有工作控制在此外壳(4.76秒)(4.83秒)测试脚本在4.85级精刻式上升机(PID 282643)(0.00秒)/ nix /商店/ qwklb2bp87h613dv9bwf846w9liimbva-vm-test-unnamed
这是一个Python提示,所以我们可以在测试框架上启动Hisseeee&#39;在这里进行。我们的测试首先运行start_all(),所以让&#39; s do do do看看会发生什么:
VM似乎启动和解决。如果你再次按Enter Enter,你会得到一个新的提示。测试运行machine.wait_until_succeeds(&#34; uname-av&#34; sech:
&gt;&gt;&gt; machine.wait_until_succeeds(&#34; uname-av&#34;)机器:等待成功:uname -avmachine:等待VM完成BootingMachine:连接到客户根壳Machine :(连接花了0.00秒)(0.00秒)(0.00秒)(0.00秒)(0.00秒)(0.00秒)(0.00秒)(0.00秒)(0.00秒)(0.00秒)( 0.02秒)&#39; Linux机器5.4.100#1-nixos SMP Tue 2月23日14:02:26 UTC 2021 x86_64 GNU / Linux \ n&#39;
因此,wait_until_succeeds方法返回命令asstrings的输出。这可能是有用的。让&#39;将内核注入其中。
nixos加载内核的方式是通过组装一组内核包福特。这些内核软件包将自动构建像ZFS或其他人的内核补丁等内核补丁,人们最终会使用。我们可以通过在Test.nix中添加类似于我们的机器配置来构建Apackage设置:
nixpkgs.overlays = [(sufe:super:{suct.callpackage ./。{})。内核; rustixpackages = super.linuxpackages for self.rustix;})]; boot.kernelpackages = pkgs.rustixpackages;
失败的断言: - config_serial_8250_console不是yes! - config_serial_8250不是yes! - config_virtio_console未启用! - config_virtio_blk未启用! - config_virtio_pci未启用! - config_virtio_pci未启用! - config_virio_net未启用! - config_ext4_fs未启用! - Xext4_FS未启用!
似乎NixOS堆栈足够智能,以拒绝ITCan&#39; t启动的内核配置。这是我添加了一堆配置选项的点,以强制执行我自己的叉子的正确大小写。
设置所有这些选项后,我能够获得启动的内核和加载的示例生锈驱动程序的内核(我忘了保存此输出,抱歉),所以我知道生锈代码实际上是运行的!
现在我们知道我们所做的内核正在运行,是时候开始制作/ dev / printerfact驱动程序实现了。我从其中一个样本复制了一个如此:
// spdx-license-标识符:gpl-2.0#![no_std]#![功能(Allocator_api,global_asm)]#![功能(测试)]使用Alloc :: Boxed :: Box;使用核心:: PIN :: PIN;使用内核:: prelude :: *;使用内核:: {chrdev,cstr,file_operations :: {fileoperations,file},user_ptr ::用户leiceptriter};模块! {类型:printerfacts,名称:B&#34; Printerfacts&#34;,作者:B&#34; Christine Dodrill&lt; [电子邮件保护]&gt;&#34;,描述:B&#34; / dev / printerfact支持,因为我可以&#34;许可:B&#34; GPL v2&#34;,params:{},} struct rustfile; ichl fileopoperations for rustfile {型包装器=框&lt; self&gt ;; fn打开() - &gt; kernelresult&lt; self :: wrapper&gt; {println!(&#34; rust文件打开!&#34;);好的(框:: try_new(self)?)} fn read(&amp; self,file:&amp;文件,数据:&amp; mutsliceptrker,_offset:u64) - &gt; Kernelresult&lt; USIZE&GT; {println!(&#34;用户试图从文件中读取!&#34;); OK(0)}}}} struct printerfacts {_chrdev:引脚&lt; box&lt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt. Kernelresult&lt; self&gt; {println!(&#34; printerfact initialized&#34;);让mut chrdev_reg = chrdev ::注册:: new_pinned(cstr!(&#34; printerfactfact&#34;),0,&amp; this_module)? chrdev_reg.as_mut()。注册::&lt; rustfile&gt;()?; chrdev_reg.as_mut()。注册::&lt; rustfile&gt;()?; OK(printerfacts {_chrdev:chrdev_reg,})} iclive for printerfacts {fn drop(&amp; mut self){println!(&#34; printerfacts退出&#34;); }}
Config PrinterFact取决于Rust Tristate&#34;打印机事实支持&#34;默认n帮助此选项允许您体验来自文件系统的打印机事实的辉光。如果不确定,请说n。
然后我告诉NIV使用我的叉子的linuxkernel而不是Linux&#39; s团队的rust,并在核心控制台上查找the string printerfact的测试:
我重新运行了测试(等待半小时才能建立整个内核)并运作。好的,我们有代码在内核中运行。
现有的打印机事实API通过使用INA JSONFILEAND的巨大打印机事实列表加载INA与SERDE一起加载并从列表中选择随机事实。我们没有访问Linux的Ructe中的Serde,更不用说货物。这部分我们将不得不更具创造力,以及我们如何能够如何发展。 rust让你声明静态阵列。我们可以用它来做这件事:
Const Facts:&amp;&#39;静态[&#39;静态str] =&amp; [&#34;打印机最容易响应以\&#34结尾的名称; ee \&#34;声音。&#34 ;,&#34;咕噜声并不总是indiprintere打印机是快乐和健康的,当他们害怕或痛苦时,一些打印机会大声夸..&#34;];
&lt; Mara&gt;打印机事实最初是由一个非常扔石头的人来制作的,它可以访问猫的事实API和SED。像Indiprintere这样的assuch实例是arfeatures。
但是问题变成了如何随机选择。通常在生锈中&#39;将兰特箱隔离,将使用Kernelentropy池。
&lt; Mara&gt;等待,此代码已在内核中右? Don&#39; t你只需访问熵池?
我们这样做!它&#39; s一个非常低级的随机性获得功能。您将它传递一个可变条纹,它会随机化内容。这意味着您可以通过这样的方式获得随机的事实:
ichilc rustfile {fn get_fact(&amp; self) - &gt; kernelresult&lt;&#39;静态str&gt; {让mut ent = [0u8; 1]; //玛拉\声明一个1大小的字节核心内核:: random :: getrandom(&amp; mut ent)? // mara \用熵填充ok(事实[ent [0]为umerize%facts.len()])// mara \返回一个随机的事实}}
&lt; Mara&gt;等待,ISN&#39;这会潜在偏见随机性吗?在完整列表中有两个事实的权力。如果你有超过256pfs,你将如何选择大于256的东西?
&lt; cadey&gt;不要担心,那里的事实毫不低于256个事实,并使这个略显不那么略显不那么略有帮助,帮助占RDRAND或其他东西的NSA后门。这是我希望上帝没有人能在生产中使用的阿什托,它不会那么重要。
但是,我们现在有这一事实。现在我们需要做的是一旦从中读取,就会将该文件写入文件。您可以使用某事物声明文件操作:
ichl fileopoperations for rustfile {型包装器=框&lt; self&gt ;; FN Read(&amp; self,_file:&amp;文件,数据:&amp; mutsliceptrwriter,offset:u64,) - &gt; Kernelresult&lt; USIZE&GT; {如果offset!= 0 {返回OK(0);让Suff = self.get_fact()?; data.write_slice(figure.as_bytes())?;好的(figure.len())}内核:: declare_file_operations!();}
现在我们可以去参加比赛,然后用测试打开文件,我们可以才能让事实,对吗?
start_all()machine.wait_for_console_text(&#34; princerfactfort&#34;)chardev = [x在machine中的x .wait_until_succeeds(&#34; cat / proc / device&#34;).plitlines()如果&#34; printerfact& #34;在x] [0] .split(&#34;&#34;)[0] machine.wait_until_succeeds(&#34; mknod / dev / printerfactfact c {} 1&#34; .format(chardev))machine.wait_for_file (&#34; / dev / printerfact&#34;)打印(machine.wait_until_succeeds(&#34; stat /dev/printerfactw" pilew/printerfact,packine.wait_until_succeeds(" ;cat / dev / printerfactfactfactfactfact ;))
&lt; Mara&gt;对不起,什么。你在做什么用Chardev获取逻辑。是炎症料表达式吗?列表理解是否跨越多柱式拆分?
所以让&#39; s逐个挑选这个表达式。我们需要为printerfact驱动程序制作一个新的devicenode。这将需要我们获得设备的主要ID号。这是暴露在/ proc /设备中,然后我们可以制作FileWith Mknod。这是解析此代码的最佳方式吗?不它不是。它是所有地狱代码,但它的工作原理。
在一个高水平的&#39;&#39; s用listcomprehions做某事。这允许你打开这样的代码:
字符= [&#34; cadey&#34 ;,&#34; mara&#34 ;,#34; tistus&#34;,&#34; zekas&#34;] a_tier = []为chara表示chara:如果和#34; A&#34;在Chara:A_Tier.Append(Chara)打印(A_tier)
proc_devices = machine.wait_until_succeeds(&#34; cat /proc/devices " pilewline()line = [x for x在proc_devices&#34中; printeractfact&#34;在x] [0] chardev = line.split(&#34;&#34;)[0]
&gt;&gt;&gt; proc_devices = machine.wait_until_succeeds(&#34; cat /proc/devices " ;).splitlines(Path)()等待成功:cat /proc/devices(0.00秒)&gt;&gt;&gt; line = [x for x在proc_devices中,如果&#34; printerfact&#34;在X] [0]&gt;&gt;&gt; chardev = line.split(&#34;&#34;)[0]&gt;&gt;&gt; Chardev&#39; 250&#39;
现在我们有设备ID,我们可以运行mknod以使设备节点福特:
哦亲爱的。它&#39;失败了。让&#39; s仔细看看该文件的特点,看看是否有任何提示。它看起来像dricon_file_operations!宏是以某种方式设置to_use常量。让&#39; SSEE&#39;在引擎盖下做什么:
#[宏_export] macro_rules! declare_file_operations {()=&gt; {const to_use:$ crate :: file_operations :: touse = $ crate :: file_operations :: dust_none; }; ($($ i:ident),+)=&gt; {const_use:kernel :: file_operations :: touse = $ crate :: file_operations :: touse {$($ i:true),+,.. $ crate :: file_operations :: dust_none}; };}
它看起来像是自动检测到它已经实现的操作的文件的文件的能力。看起来您需要实际解释文件操作,如下所示:
机器:等待成功:Cat /dev/printerfact(0.01秒)Miacis,印版的原始祖先,是一个小型,树生生物的晚期,约45至500万年前。(4.20秒)测试脚本在4.21s完成
我们有内核代码!打印机事实模块正在加载,选择Atrandom然后返回它。让&#39; s多次运行以获得一些不同的fints:
机器:等待成功:Cat /dev/printerfact(0.01秒)一只老虎打印机&#39; s条纹就像指纹,没有两只动物具有相同的模式。等待成功:cat /dev/printerfact(0.01秒) Printers对女性的反应比男性更好,可能是由于女性&#39;妇女的声音具有更高的音高:等待成功:Cat /dev/printerfact(0.01秒),国内打印机可以以30的速度运行MPH.Machine:等待成功:Cat /dev/printerfact(0.01秒)缅因浣熊比Singapura大4至5倍,最小的打印机。(4.21秒)
在这一点上,我得到了那种幸福的感觉,你会得到一些事情。感觉让所有的麻烦都值得它,导致你写下休闲闲船:
然后我将我的nix config branch推到github上,然后再次在mybig服务器上运行它。有效。我做了一个可复制的设置,以便在ShitPost上进行再现功能。
这个Saga首先在TwitterThread中记录。这是一种尝试捕获很多相同的信息,同时编写该线程而没有大量失败的噪音,因为我熨烫我的工具链。我计划向上游项目提交NIXOS测试的最小化子集,以及包括instrice_file_operations的示例的文档!宏让其他人不受同样的混乱&#39。
它与MyPreferred电子邮件客户端有助于Linux内核邮件列表的&#39非常讨厌(这不是让纯粹电子邮件发送给我的邀请,这样做会让您被阻止)。然而,Linuxpeople的RUDER采取GitHub拉请求,因此这对我来说将更容易。
本文发布于M04 17 2021.事实情况和情况自发表以来可能发生变化。如果出现错误或不清楚,请在结论之前与我联系。