网卡是硬件设备,那为什么安装了linux虚拟机,会自带网卡呢,安装虚拟机不是完完全全的软件操作吗_-invalid s
想搞明白这个问题,你首先要知道“在数字信号层面,硬件设备究竟是什么样子”。
这是一颗典型的台式机CPU:

可以看到,CPU的屁股下面是一片片整整齐齐的铜刺。
这些刺的作用主要是给猫梳毛,用了那是人好猫也好:

谁用谁知道。
当然,这是CPU退休后的主要工作。
退休之前,这些刺的作用是插入这些洞洞:

我们可以看到,CPU的宝座下方,印刷电路板上有密密麻麻无数条细线一样的东西,就好像蜗牛爬出的痕迹一样。CPU那些“铜刺”实际上就连接在这些“细线”上面。
这些细线就是所谓的“印刷电路”,它的作用主要是给CPU上电刑。
这玩意儿你不严刑拷打,它就不乖乖干活……
咳咳。
好吧,说正经的。
CPU引脚的作用,一个是接受主板供电;另一个就是和形形色色的外部设备通讯:电信号通过印刷电路板,连通到线路板上大大小小方方正正的集成电路,指挥南桥北桥、集成网卡、声卡之类芯片工作;同时也接受它们发来的各种信号,针对性的解决外设们提出的问题。
CPU电信号并不仅仅和焊在主板上的芯片通讯;实际上,信号也会直接或间接的联通到旁边那些黑色蓝色的插槽里(在上面照片你看不见的地方,还会有白色褐色的各种插槽),管理你插在上面的各种东西。
咦?这板子怎么就喜欢特立独行,非要用黑的红的插槽?您就凑合着用吧。本质上是一回事——想玩电脑,你就要学会看本质。反正你早晚都要养成看本质不看颜色/形状的好习惯……什么?养不成?养不成你肯定不混这行了。
这些引脚的作用都是事先规定好的。较新的台式机CPU引脚实在太多,我找了个老古董:

标红的那些引脚就可以和外设(以及内存)通讯。
现代CPU的引脚当然要多得多,但基本功能大同小异——除了换汤不换药的几百点差别之外,都是一回事。
嗯,大概就好像你玩的烟花和登月飞船的差别一样,大差不差。哈哈。
你可能马上会意识到一件事:
我买的主板可能来自很多很多不同的厂商,上面PCI/PCI-E插槽的数量、位置各不相同,将来用户插什么更是随心所欲——甚至,哪怕主板上用的声卡芯片本身,光小螃蟹一家都可能有alc882、883、887等等区别;再加上创旧啥的……
这么多五花八门的硬件,CPU怎么知道它们在哪里?怎么知道哪条线上连着哪种硬件?
简单说,当你按下电源键时,将会触发一个“自检”程序;这个程序会遍历总线上的所有硬件,把它们的信息搜集起来、存入BIOS指定区域(或其他平台规范的指定区域)。
在Linux下,这个表格的其中一部分(PCI总线上的设备)可以用lspci命令查看(这个说法并不准确,lspci可能并非简单的读取smbios数据;不过这里就不深入探讨了):

上面的信息含义如下:
对第一行:
00:00.0 Host bridge: Intel Corporation 440FX - 82441FX PMC [Natoma] (rev 02)其中:
00:00.0- The bus number, device number, and function number, in that order.
依次分别是总线号、设备号和功能号;这相当于设备地址。
Host bridge:- Device class.
设备类型;它实际上另外的一串十六进制数字,这里做了转换,显示成了更用户友好的文本。
Intel Corporation- Device vendor.
设备提供商
440FX - 82441FX PMC- Device name.
设备名称
[Natoma]- Mode of operation.
操作(控制?)类型
(rev 02)- Revision number.
版本号
如果改用lspci -n,我们就能看到它的数字形式了:

在Linux下,如果你有个设备无法被正确驱动;那么用lspci看一下上面的型号信息,然后上网搜索驱动,多半就能解决问题了。
事实上,Linux内核也是用类似方式搜索磁盘上和每个硬件相匹配的设备驱动、然后用insmod相关调用自动加载的。
我们可以用lspci -k看到PCI总线上每个设备对应的驱动:

红线标出的内核模块可以用lsmod命令查看,也可以用rmmod命令从内核卸载、然后再用insmod加载(想玩的话,可以在本地机上拿声卡、网卡练练手;但别折腾显示器、硬盘等关键设备的驱动,会把系统搞死的)。
有了设备驱动之后,操作系统终于可以骄傲的宣布,我有打印机支持!我有网卡支持!
然后,我们的程序就可以把自己的工作转交给设备驱动程序,让它帮我们完成任务了。
这个我之前写过文章,这里就不再啰嗦了:
为什么显卡、声卡甚至鼠标键盘有驱动,而CPU、内存没有驱动?驱动程序又是什么?
前面提到了,我们的程序需要委托设备驱动和设备打交道;那么,设备驱动又是什么样子呢?
很简单,它是一组等待操作系内核调用的、由操作系统统一定义了接口界面规范的标准函数;这些函数内部会把我们的请求翻译成设备自己能够识别的“命令字”,通过CPU引脚发送到对应总线地址上——当设备收到了某个数字(命令字)时,它就知道自己该做什么了。
知道了这个之后,我们是不是马上就可以起很多“坏心思”了?
比如,机器上并没有显卡;但我们在机器自检过程中往SMBIOS写个:
00.0f.0 0300:15ad:0405
是不是就可以“欺骗”操作系统,让它以为总线00、设备号0f、功能号0对应的设备就是一块显卡?
然后,既然识别到了显卡,操作系统是不是就会傻呵呵的尝试为它加载一个驱动?
好了,驱动加载了,现在我们可以有两个办法“整活”。
办法一,驱动是我们自己写的;那么,当需要“把内容显示到屏幕”时,我不执行out指令(intel CPU上,in/out指令转门用来和外设通讯)——因为显卡就不存在,我能out到哪里?——而是搞一个vnc服务端,把屏幕内容转发到网卡或别的什么地方。
实际上,某些驱动甚至都不需要和SMBIOS中的信息对应。我说有,它就有。反正你想要显示什么,找我!
网卡也是类似路数。不过,Linux/Windows下,标准做法是搞一个假的“tun/tap设备”,它将被识别为网卡;而这个设备会把用户调用socket之类接口发来的网络报文给它(也就是我们写的程序);我们再把这个报文转发给物理网卡、USB或者声卡(比如把信号调制在音频中);反过来也对,我们可以把物理网卡、USB、声卡的mic接口传来的信息解码,再通过tun/tap设备发给用户,这就成功制造了一块虚拟网卡。
办法二,驱动就用标准的intel/nVidia自己的驱动;但我把驱动程序最终输出的IN/OUT指令都截掉,别让它真的发出去(因为设备并不在那个地址,或者虽然在,但不能让它用,否则会把宿主机的状态搞乱)——比如,可以利用AMD/intel的硬件虚拟化功能,这种功能会把最外层的、物理机上的操作系统置于ring -1,虚拟机程序则位于ring 0;当ring 0想执行特权指令时,CPU不会直接执行,而是触发一个中断,交给位于ring -1的物理机操作系统决定是否放行(或者是否需要改写,比如把本应传给物理网卡的数据传递到tun/tap设备)。这样一来,物理机操作系统就可以阻止或者重定向这些操作,既允许虚拟机执行各种动作、又避免它访问到敏感区域造成破坏了。
当然,很多设备,比如显卡,它的具体控制指令字以及详细参数是商业秘密,因此蹲在IN/OUT层面是没法有效模拟的。
那么,VMware等虚拟机就需要搞一个自己的虚拟显卡(或其他设备),直接从驱动层面就把用户请求截下来、然后渲染到自己的窗口里(或转发给其他设备)——驱动接口是标准化的,在这里截,动作就是可理解、可转发、可模拟的;不然到了IN/OUT水平,你都没人家的spec,还怎么搞?这也是为什么绝大多数虚拟机没法支持显卡物理加速的根本原因(当然,可以从openGL/DX 3D层面转发,不过技术上仍然存在很多麻烦,总之很难做到功能完整、性能不打折扣)。
而通讯协议有成文标准的,比如标准网卡、硬盘之类无需特殊驱动的设备,就可以在更低的层面(可以是IN/OUT指令,也可以是块设备层面;或者像网卡一样,专门搞出一个tun/tap设备来)拦下相关访问,从而搞出一个性能几乎不打折扣的、功能完整的虚拟设备——实际上,对于显卡,如果不使用它的2d/3d加速功能、仅仅当一块标准的VGA兼容显卡用的话,也是可以在较低层次兼容的。
原因很简单,这些东西有标准,任何厂商做都一个样,那么自然就可以“指令级模拟”它;相应的,没有统一标准、一家一个样的,那自然就没法“指令级模拟”,这种就必须装人家自带的驱动、我们也至多能模拟到“标准驱动接口”水平。
当然,如你所见,我这里很“糊涂”的把Windows/Linux以及虚拟/半虚拟混在一块乱说。
原因很简单,这些东西基本原理就这么个样子;但具体实现各家都不一样;甚至同一家在不同设备上都各有不同。因此这里只泛泛的讲一下基本思路,故意让你没法对号入座——前面就提到过,请学会看本质,不要纠结于细节。
除非你现在就有个任务,比如在Windows平台上实现一个半虚拟化的虚拟机、且要求你实现一个支持OpenGL/DX 3D的虚拟显卡:但你真能接到这种任务,还需要看我的入门科普吗?
总之,一言以蔽之:硬件设备对CPU来说是不存在的,它仅仅是往一组引脚输出电信号或者从引脚接受电信号而已(真·缸中之脑);而CPU对软件来说也是不存在的,软件仅仅是一组指令序列而已,这组指令你用人脑解读、草稿纸执行都行——除了慢点,没啥区别。
那么,只要你能接受CPU的电信号、并正确按设备标准把响应反馈回CPU的引脚,那么你就完全可以通过USB、网卡或别的什么东西远程模拟一个硬件,就好像它真的插在电脑主板上一样。
类似的,只要你有办法执行程序中的每条指令、并给出符合期望的执行结果——不管你是用真实的CPU执行还是写一个程序“假装”CPU存在(比如在intel CPU上用模拟器软件跑摩托罗拉CPU的程序),只要行为符合预期,程序就会“觉得”自己被人在“真实”的硬件上执行了。
换句话说,电脑系统的本质就是数字信号。只要你想办法把一组正确的数字信号适时混进输入输出流中去,你就可以模拟一切——就好像人脑的一切都是神经信号,那么理论上完全可以用模拟出来的神经信号欺骗一个泡在培养皿里的、孤零零的大脑,让它觉得自己是一个完整的人、享受了精彩的人生一样。
评论区
WilliamGong: 废旧cpu你不拿来炼金拿来刷猫?[doge] 👍🏽80 💭N/A IP 🕐2022-03-31 00:09:26
│ └── 陈凝风: 突然发现这个用法似乎令我无法抗拒…目光不由自主的瞟向那台用了十多年的Linux主机… 👍🏽26 💭N/A IP 🕐2022-03-31 01:32:54
│ └── amber dang: 刷猫 👍🏽2 💭N/A IP 🕐2023-07-30 23:40:10
Really Pan: 省流:电脑系统的本质就是数字信号。只要你想办法把一组正确的数字信号适时混进输入输出流中去,你就可以模拟一切——就好像人脑的一切都是神经信号,那么理论上完全可以用模拟出来的神经信号欺骗一个泡在培养皿里的、孤零零的大脑,让它觉得自己是一个完整的人、享受了精彩的人生一样。 👍🏽54 💭N/A IP 🕐2022-04-01 17:47:49
│ └── Dj passby: 这就像我们的宇宙,也许我们真的被侵泡在营养液里[惊喜] 👍🏽0 💭N/A IP 🕐2022-04-02 14:47:58
│ └── 羿羿: 有个电影叫《源代码》就是像你说的那样。。。 👍🏽4 💭N/A IP 🕐2022-04-03 09:59:39
│ └── 叉丫: 缸中大脑 👍🏽1 💭N/A IP 🕐2022-04-10 21:26:02
茄子: [思考]能用来刷猫的U都是老AU了,IU新AU都刷不了 👍🏽33 💭N/A IP 🕐2022-03-31 14:20:16
│ └── smog: AU?A÷! 👍🏽15 💭N/A IP 🕐2022-04-01 15:14:21
│ │ └── 闫雨煌: 收收味 👍🏽11 💭N/A IP 🕐2022-04-02 00:37:48
│ │ │ └── smog: 哎呀是我吗[惊喜] 👍🏽0 💭N/A IP 🕐2022-04-02 01:12:58
│ │ │ └── Wobbuffet: 最甜甜的小草莓捏 👍🏽0 💭N/A IP 🕐2022-04-03 10:28:27
│ │ └── 七宫智音: 皮套√早该图图了😡 👍🏽2 💭N/A IP 🕐2022-04-02 12:14:52
│ │ └── 陈易祁: acg😡 👍🏽1 💭N/A IP 🕐2022-04-02 14:06:28
│ │ └── Horri zzzen: 啥玩意? 👍🏽0 💭N/A IP 🕐2022-04-02 14:36:08
│ └── 千荷: R7 5800还可以刷毛,更新的估计刷不了了 👍🏽2 💭N/A IP 🕐2022-04-02 04:28:48
beepnow: 好答案,这个回答看到一半就想起了黑客帝国,CPU可以想象自己插了块3080 ti,但并不真的需要有一块连接到总线上 👍🏽25 💭N/A IP 🕐2022-03-30 21:44:46
│ └── 白如雪: 知乎遗风 👍🏽2 💭N/A IP 🕐2022-04-02 10:18:22
溯流光: woc, 最近在用学校制作的虚拟机写操作系统,写各种driver时非常困惑为什么能连上,看到这篇文章真是醍醐灌顶,醍醐灌顶 👍🏽6 💭N/A IP 🕐2022-11-27 14:18:15
Kafgra: 插腚,开机,午安大电牛 👍🏽6 💭N/A IP 🕐2022-03-31 13:10:59
│ └── EdenPrime: 三板斧,淦! 👍🏽1 💭N/A IP 🕐2022-04-01 20:03:33
tgis-top: 所有CPU能访问的设备,在CPU看来都是内存或者寄存器,控制设备就是往对应地址写入数据。搞无操作系统嵌入式开发的应该很熟悉。 👍🏽5 💭N/A IP 🕐2023-08-11 08:27:39
烬热余晖: 其实用*nix的万物皆文件解释是不是简单点?虽然实际上不是[doge] 👍🏽3 💭N/A IP 🕐2022-03-30 23:45:28
落梦: 反正有问题就加一层代理,然后起个名字叫虚拟X 👍🏽4 💭N/A IP 🕐2022-04-02 10:46:56
欢乐马: 什么是“色色的外部设备”?[思考] 👍🏽4 💭N/A IP 🕐2022-04-02 14:09:12
紧张不安的人: 难得的好问题配好答案的组合[爱] 👍🏽2 💭N/A IP 🕐2022-03-31 00:29:54
风中的小菊: 我也有个差不多的赛扬800,拿来梳头真是爽 👍🏽2 💭N/A IP 🕐2022-04-01 17:07:46
YeeZiee: I家的U退役后猫都嫌弃啊。。。 👍🏽2 💭N/A IP 🕐2022-04-02 00:01:27
uplink: 知乎遗风 👍🏽2 💭N/A IP 🕐2022-04-02 13:54:44
king: 深入浅出[滑稽],通俗易懂[机智] 👍🏽3 💭N/A IP 🕐2022-04-02 14:32:17
诚哥: 同样的还有显卡欺骗器,让显卡以为自己插在显示器上狠狠滴输出视频信号,但实际上显卡还是处男呢[惊喜] 👍🏽3 💭N/A IP 🕐2023-06-25 19:23:32
YifengChennnn: 看得我毛骨悚然。。。[飙泪笑] 👍🏽1 💭N/A IP 🕐2022-04-04 20:08:25
yubing911: 大部分能看懂,我是说字儿都认识…… 👍🏽1 💭N/A IP 🕐2024-02-16 19:00:04
看门喵: 创新:你礼貌吗? 👍🏽1 💭N/A IP 🕐2022-04-01 18:57:08
Cerberus: 虚拟化工程师:用户说需要高性能虚拟机啊,好了,现在我们来搞一把IOMMU所有的努力,全部木大[捂脸] 👍🏽1 💭N/A IP 🕐2022-04-01 16:29:32
爱国青年: 今年看到的最好的回答,没有之一[赞同] 👍🏽1 💭N/A IP 🕐2022-04-02 04:27:23
DamnLuckyGuy: qaq虽然自己对很多硬件技术都了解的不是很多,但是最近还是鼓起勇气买了点十几块或是十块以下的旧CPU用来观赏把玩,然后刚才我买的应该型号是速龙X4 830的处理器到货了,然后发现居然针脚部分没有想象中那么扎人,然后想起来了这篇大佬写的文章就试着用它真的给猫梳了下毛( )虽然其实一次能刷下来的毛并不是很多但是用起来也不会让猫感觉疼,但是有个小问题就是梳完毛之后有一些毛卡在了针脚中间挺难拿掉的,也许我可以试下用键盘清洁泥把这点卡在里面的毛粘掉(…?)[图片] 👍🏽1 💭N/A IP 🕐2025-01-24 13:32:04
未来为我而来: 8086,这我熟,刚学 👍🏽1 💭N/A IP 🕐2022-11-22 13:05:31
│ └── 卜史: 单片机嘛,好玩 👍🏽0 💭N/A IP 🕐2023-03-11 00:15:42