在单片机上运行Linux(转载)

介绍

在Linux论坛中,常见的问题是询问Linux的最低规格是多少。常见的答案是,它需要32位体系结构,一个MMU和至少一兆字节的RAM以适合内核。该项目旨在(并成功)的粉碎这些概念。您在右侧看到的开发板基于ATmega1284p。我也使用ATmega644a取得了同样的成功。该主板没有其他处理器,并且可以启动Linux 2.6.34。实际上,它甚至可以显示完整的Ubuntu堆栈,包括(如果有时间等的话)X和gnome。

board1.jpg

内存

完整的Linux安装需要兆字节或RAM和带有MMU的32位CPU。这个项目具有所有这些。首先让我们解决RAM。如您所见,板上有一个老式的30针SIMM内存模块。这些已用于基于80286的PC。它与ATmega接口,我编写了代码来访问它以及在规范内对其进行刷新(SDRAM需要不断刷新以避免丢失数据)。有多快?刷新中断每62ms发生一次,占用1.5ms,因此占用了不到3%的CPU。为了便于编程,一次访问一个字节访问RAM。这导致每秒大约300 KB的最大带宽。

存储

随着对RAM要求的降低,我们有两个要处理。存储不是很难解决的问题。SD卡很容易与使用SPI对话,而我的项目做到了这一点。1GB SD卡可以正常工作,尽管512Mb对于该特定文件系统(Ubuntu Jaunty)而言已足够。ATmega确实有一个硬件SPI模块,但是由于某种原因,它并没有完全解决问题,因此我在接口上做一些改动。它仍然足够快-大约每秒200千字节。这也给项目增加了一个很好的感觉-可以在任何具有足够引脚的微控制器上完成-无需使用硬件模块。 board3.jpg

中央处理器

剩下的就是讨厌的32位CPU和MMU要求。那么,AVR没有MMU,而是8位的。为了克服这一障碍,我编写了一个ARM仿真器。ARM是我最熟悉的体系结构,它非常简单,可以轻松编写一个仿真器。为什么要写一个而不是移植一个?好吧,移植别人的代码是没有意思的,再加上我看到的所有仿真器都不是以易于移植到8位设备的方式编写的。原因之一:AVR编译器坚持将ints设置为16位,这样简单的事情如“(1 << 20)”会给您带来麻烦,并产生零。相反,您需要执行“(1UL << 20)”。不用说拖曳其他人的未知代码库,寻找所有假定为int且可能会失败的地方将是一场灾难。另外,我希望有机会编写一个不错的模块化ARM仿真器。所以我做了。

其它功能

该板与现实世界的通信是通过串行端口进行的。目前,它连接到运行minicom的PC上的串行端口,但是可以替代地将键盘和字符LCD连接到板上,使其完全独立。板上也有两个LED。它们发出SD卡访问信号。一读,一写。板上也有一个按钮。按住一秒钟,它将在串行端口上吐出模拟CPU的当前有效速度。AVR的主频为24MHz(比其现有的20MHz略有超频)

速度有多快?

uARM当然不是速度恶魔。引导到bash提示符(“ init = / bin / bash”内核命令行)大约需要2个小时。然后再花4个小时来启动整个Ubuntu(“ exec init”,然后登录)。启动X需要更长的时间。有效的仿真CPU速度约为6.5KHz,与您期望的在8位微控制器上仿真32位CPU和MMU相当。奇怪的是,系统一旦启动,就可以使用了。您可以输入命令并在一分钟内得到答复。也就是说,实际上您可以使用它。例如,我今天用它来格式化SD卡。这绝对不是最快的方法,但我认为它可能是_最便宜_,最慢_,_最容易组装的_,_最低的零件数量_和_最低端的 Linux PC。该板是用电线手工焊接的,甚至不需要印刷电路板。

有关仿真器的详细信息

该仿真器是非常模块化的,可以随意扩展以仿真其他SoC和硬件配置。仿真的CPU是ARMv5TE。前一阵子,我开始支持ARMv6,但是由于不需要,它从未完成(如代码所示)。仿真的SoC是PXA255。由于设计的模块化,您可以替换SoC.c并使用相同的ARMv5TE内核制造一个全新的SoC,或者替换该内核,或者随意替换外围设备。这是有目的的,因为我的意思是该代码也可以作为ARM SoC工作原理的合理清晰演示。CPU模拟器本身的代码不太干净,因为它是一个CPU模拟器。它是几年前写的超过6个月的空闲时间,然后放在一边。最近专门针对该项目复活了它。仿真器实现了一个i-cache来加快处理速度。AVR上有很多功能,与我的外部RAM不同,AVR可以以每秒5兆字节的速度访问内部存储器。我从来没有实现过d-cache,但是它在待办事项列表中。对块设备的访问未模拟为SD设备。事实证明这太慢了。相反,我编写了一个半虚拟化的磁盘设备(pvdisk,请参阅pvDisk.tar.bz2,GPL许可证),该设备使用无效的操作码来调用仿真器并访问磁盘。我映像中的ramdisk加载了该pvdisk,然后将chroots加载到/ dev / pvd1。ramdisk作为“ rd.img”包含在内。我使用的“机器类型”是PalmTE2。为什么?因为我对硬件非常熟悉,所以它是我看到的第一个pxa255机器类型。

超级终端?

您可以使用特殊的操作码向仿真器请求一些服务。在手臂上是0xF7BBBBBB,在拇指上是0xBBBB。选择它们是因为它们在ARM保证未定义的范围内。在R12中传递超级调用号,在R0..R3中传递参数,将返回值放置在R0中。来电:

  • 0 =停止仿真
  • 1 =打印十进制数
  • 2 =打印字符
  • 3 =获取滑枕尺寸
  • 4 =块设备操作(R0 =操作R1 =扇区编号)。请注意,它们不写仿真RAM,而是填充仿真器内部缓冲区,仿真来宾使用另一个超级调用(每次一个字)访问该缓冲区。我本来打算实现DMA,但从未尝试过。操作:
    • 0 = getInfo(如果扇区num为零,则返回num个扇区;如果扇区num为1,则返回以字节为单位的扇区大小)
    • 1 =扇区读取
    • 2 =扇区写入
  • 5 =块设备缓冲区访问(R0 =值输入/值输出,R1 =字号,如果写则R2 = 1,否则为0)

支持Thumb?

完全支持Thumb。不过,我作弊了一点,将每个thumb指令解码为等效的ARM指令,然后使用arm模拟器功能执行该指令。它没有其他方法快,但是它很简单并且代码很小。可以使用256KB的查询表,但是我觉得256KB对于微控制器的闪存来说太大了。有些thumb指令不能转换为ARM,而是可以正确处理。

自己建立

出于非商业目的,您绝对可以这样做。接线如下。RAM DQ0..DQ7-> AVR C0..C7。RAM A0..A7-> AVR A0..A7。RAM A8..A11-> AVR B0..B3。RAM nRAS nCAS nWE-> AVR D7 B4 B5。SD DI SCK DO-> AVR B6 B7 D6。LED读写-> AVR D2 D3(LED的另一脚接地)。按钮-> AVR D4(另一条腿接地)。内存可以是任何30针16MB SIMM,并且可以每64ms进行4K周期的CAS-RAS刷新之前的CAS。我所用的(OWC)可以在线购买,价格为几美元。原理图如图所示。点击查看大图 uARM_big.png  

源代码?

有点混乱,但确实有效。趁热获取:LINK。许可证对于非商业用途,只要您将许可证文件与源保持在一起并发布所有更改,如果用于商业用途,请与我联系,我们会达成协议。要构建仿真器以在PC上进行尝试,请键入“ make”

  • 使用“ ./uARM DISK_IMAGE”。要构建优化的PC版本,
  • 使用“ make BUILD = opt”。为AVR构建,
  • 使用“ make BUILD = avr”。它目前针对ATmega1284p。
  • 要以ATmega644为目标,除了更改makefile之外,还要减少icache.h中的数字,以使icache足够小以适合644中的内部RAM。归档文件中还包括1284p的最终十六进制文件。

启动过程

为了节省AVR中的代码空间,仿真器中几乎没有启动代码。实际上,“ ROM”总共有50个字节:8个字节可切换到拇指模式,还有一些拇指代码可读取SD卡的第一个扇区并以拇指模式跳至该扇区(请参见EmbeddedBoot.c)。SD卡的MBR具有另一个引导加载程序(以拇指模式编写)。这一节着眼于MBR,找到了活动分区并将其内容加载到RAM的末尾。然后,它跳转到目标ram地址+ 512(请参阅mbrBoot.c)。这里有第三大引导加载程序ELLE(请参阅ELLE.c)。这将重定位虚拟磁盘,设置ATAGS,然后调用内核。提供所有二进制文件和源文件,以便您可以随意制作自己的图像。引导过程应让人联想到PC引导。:)包含的mkbootimg。sh工具可用于制作启动分区的工作映像。完整的工作磁盘映像?链接。  

via