×
嵌入式 > 嵌入式开发 > 详情

领略Linux操作系统魅力:TiVo 揭秘

发布时间:2020-05-20 发布时间:
|

每个人都已经知道 TiVo 可以“运行 Linux”。在这一期的“Linux 进展”中,Peter 将介绍一下在 TiVo 上安装的 Linux 系统。研究 TiVo 系统可以展示出一个公司是如何从桌面操作系统转换到嵌入式系统的。

有很多有关 TiVo“黑客”的站点会介绍这样那样的事情(通常总还有其他一些事情)。毕竟,对于拥有运行 Linux 的设备,有一半的乐趣是让它做比我们想做的更多(或者略有不同)。但是我们大部分人都只需要使用 Web 服务器(在我的印象中,在我家里已经有 10 台到 15 台 Web 服务器了,包括嵌入式系统)。

下面我们为计划的 TiVo 黑客攻击给出一些建议。您可能应该假设:您要排除所有的保证,以及它不能像一台录像机那样工作。这并不是您喜欢去修补问题,而是因为,试图在发生任何微小的变化时就对机器进行修改会导致问题恶化,但是这种恶化将被对问题的意识而抵消。

如果您正在试图升级硬盘,有些在线的指南会告诉您,首先从硬件仓库找到 T10 和 T15 Torx 螺丝起子。这从某个方面来说是个好建议:TiVo 的确使用了 T10 和 T15 Torx 螺丝。然而,如果您不是那种早已搜集了很多 Torx 工具的人,那就可能并不希望搞混这个问题。幸亏有了 Kuro 和 Mac Mini,您可以选择其他价格合理的 PowerPC® 的硬件。

对于这个实验,我的选择是 40 小时的 TiVo。这是一台 Series2 机器,这意味着它不如 Series1 灵活和开放。不幸的是,这是目前它们所销售的惟一产品,好在价格不贵。

备份

通常,在计划要做一些可能会修改电子器件的修改时,首先要进行备份。在对 TiVo 进行加电之前,我对整个磁盘进行了备份。这要打开机器(使用 T10 Torx 工具),松开驱动器(还是使用 T10),并拔出驱动器(使用 T15)。现在您得到了一个 40 GB 的硬盘。将这个硬盘放到一个老的 x86 Linux 机器中,您会看到一个不能识别的分区表。因此,在 Tivo 上并不存在分区(例如 /dev/hde1),而是一整块磁盘。这并没有什么问题。

图 1. TiVo 内视图

在我的系统中,我将这块磁盘放到了一个驱动器插槽中,系统将其识别为 /dev/hde。如果您使用一个外部的驱动器插槽,那么系统可能将其识别为 /dev/sdX,其中“X”是一个字母;如果您没有其他 SCSI 或者伪 SCSI 设备,那么这个字母可能就是“a”,也可能是后面的某个字母。确保您清楚自己要使用哪块硬盘! [page]

# bzip2 -1c < /dev/hde > tivo.img.bz2

注意开始可能会出现一些严重的错误;而且一段时间内可能不会有任何输出结果。这个磁盘中包含了很多 空扇区,一开始整个扇区的内容都为 0,bzip2 负责对磁盘上的内容进行压缩 —— 在到达 4,096 字节之前可能需要 1 分钟,在到达 8,192 字节时还需要几分钟。最后的文件大小大约是 560 MB,对于一个 40 GB 的磁盘映像文件来说这还不错。如果您希望从这个备份进行还原,只需要执行下面的命令:

# bzip2 -dc < tivo.img.bz2 > /dev/hde

如果您的磁盘上已经有一些数据,这个映像文件可能会远远大于 560 MB。此处假设您具有与 TiVo 磁盘差不多的空闲空间。

那么,磁盘上有什么内容呢?

由于磁盘并没有进行分区,我们很容易就猜想它使用了某种专用的格式。研究其格式需要花费一定的时间。 当然,要做的第一件事情是将磁盘看成裸字节。磁盘上数据的开头有点类似于启动引导程序的

root=/dev/hda7
            runfinaltest=2 contigmem8=16M brev=0x10

接下来是真相大揭密 —— 这个磁盘上包含了一个 Apple 分区映射:

0x0200  50 4d 00 00  00 00 00 0d  00 00 00 01  00 00 00 3f  'PM.............?'
            0x0210  41 70 70 6c  65 00 00 00  00 00 00 00  00 00 00 00  'Apple...........'
            0x0220  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  '................'
            0x0230  41 70 70 6c  65 5f 70 61  72 74 69 74  69 6f 6e 5f  'Apple_partition_'
            0x0240  6d 61 70 00  00 00 00 00  00 00 00 00  00 00 00 00  'map.............'
            0x0250  00 00 00 00  00 00 00 3f  00 00 00 33  00 00 00 00  '.......?...3....'
 

您还怀疑吗?

回顾一下,对于运行 Linux 的 PowerPC 机器来说,使用一个 Apple 分区映射是非常合理的。对于 Apple 分区映射的支持并没有什么特殊,也有很好的文档进行介绍。这对于 MIPS 系统来说并不是非常典型,但是却可以选择与 Series1 系统兼容,后者是在 PowerPC 上运行的。

严格来说,这仍然是一种专有格式;不过它已经是大家都知道了的一种格式。不幸的是,这些分区使用的都不是 OS X 所熟悉的格式,但是我的 Mac Mini 可以读取这个分区表。下面是这个分区表映射的内容:

Partition map (with 512 byte blocks) on '/dev/rdisk1'
     #:                type name                       length   base     ( size )
     1: Apple_partition_map Apple                          63 @ 1
     2:               Image Bootstrap 1                     1 @ 44161324
     3:               Image Kernel 1                     8192 @ 44161325 (  4.0M)
     4:                Ext2 Root 1                     524288 @ 44169517 (256.0M)
     5:               Image Bootstrap 2                     1 @ 44693805
     6:               Image Kernel 2                     8192 @ 44693806 (  4.0M)
     7:                Ext2 Root 2                     524288 @ 44701998 (256.0M)
     8:                Swap Linux swap                 262144 @ 45226286 (128.0M)
     9:                Ext2 /var                       262144 @ 45488430 (128.0M)
     10:                 MFS MFS application region     524288 @ 45750574 (256.0M)
     11:                 MFS MFS media region         33494098 @ 46799150 ( 16.0G)
     12:                 MFS MFS application region 2   524288 @ 46274862 (256.0M)
     13:                 MFS MFS media region 2       44161260 @ 64       ( 21.1G)
     Device block size=512, Number of Blocks=80293248 (38.3G)
     DeviceType=0x0, DeviceId=0x0

这为我们能够期望得到什么内容提供了很好的思想。首先,它好像是设计用来更新一个文件系统,同时在另外一个文件系统上运行,这样能使更新更加安全。奇怪的是:这为文件系统提供了精确的块偏移量和大小。这说明现在可以重新在 Linux 机器上装上这个磁盘并查看这些文件系统的内容了。

# dd if=/dev/hde bs=512 count=524288 skip=44169517 of=root1.img
            # dd if=/dev/hde bs=512 count=524288 skip=44701998 of=root2.img
            # dd if=/dev/hde bs=512 count=262144 skip=45488430 of=var.img

这显示 Root 1 文件系统尚未格式化;它只是 256 MB 的空字节。而 Root 2 文件系统的内容非常理想:

# file root2.img
            root2.img: Linux rev 0.0 ext2 filesystem data
            # mount -o loop root2.img /mnt
            # ls /mnt
            .   bin  diag  etc       initrd   lib         mnt  proc  sbin  tvbin  var
            ..  dev  dist  etccombo  install  lost+found  opt  res   tmp   tvlib
            # mount -o loop var.img /mnt/var
            # ls /mnt/var
            .   a    dev   etc  lost+found  mnt   packages  run    tmp
            ..  bin  dist  log  mess        mtab  persist   state  utils
 

安全性

采用专用系统的缺点之一是,TiVo 具有一些旨在防止别人修改它的“安全性”特性。这是一个非常简单的经济学问题 —— 以 100 美元的价格销售具有硬盘和 TV 谐调器的通用 MIPS 系统的任何公司很快就破产了。对于现在来说,我们只是要了解一下 Linux 是如何在这个系统上运行的,而不是了解如何修改它。

注意,ext2 文件系统在不同系统之间的兼容性意味着您可以选择使用一个普通的 Linux 机器。您甚至可以设置一个交叉编译器以及相关的工具,后面我们会更详细地进行介绍。然而,不要期望能够很容易地修改内容;尽管已经可以这样做了,但是这并不意味着这非常简单。记住,这是一个专有的可以实现录像功能的硬件。更不必说,有很多公司都非常希望难以对它做较大修改。

在这个特定的 TiVo 模型中,在加载内核之前,要进行一个硬件安全性检查。然后,内核本身具有一个内嵌的 RAMdisk,其中包含了一些安全性特性;我们可以对在硬盘上找到的代码进行比较,例如 /var/utils/checkkernel.tcl 脚本。

值得指出的是,在原始安装中有大量的额外空间。根文件系统使用了 54 MB 的空间,还有 182 MB 的剩余空间;/var 使用了 3 MB,还有 116 MB 的空闲空间。当然,这样做的目的是为了存储大量的数据,例如您需要监视的程序。 [page]

看一看软件

关于 TiVo 最有趣的一件事情是它有很多特殊用途的应用程序。虽然从理论上来说它有一个显示设备,但是实际上它只能通过在屏幕上卷屏来显示文本。系统中有一个可执行文件 /tvbin/text2osd,它听起来像是一个将数据作为屏幕显示写到输出磁带上的应用程序。还有一些非常有趣的 PNG 文件,所有这些文件的大小都是典型的视频文件的大小,其中包含了可能需要显示的一些消息。

虽然这些软件有点混乱,但是实际上并不需要在一些直观的位置上具有真正的内容;只有开发团队需要这些内容。有些内容对于其他用户来说可能并没有太多意义,所有的 TiVo 软件都位于 /tvbin 和 /tvlib 中,但是很多程序的配置文件都位于 /opt/tivo 中。更传统的 Linux 文件系统的布局应该将这些文件放到 /opt/tivo/bin、/opt/tivo/lib 和 /opt/tivo/etc 中。

来看一下 Tcl 脚本,我注意到它是由 /tvbin/tivosh 解释的。这可能是一个 tcl 解释器。但是稍等一下,它实际上是一个符号链接,链接到一个名为 tivoapp 的程序。很多不同的程序都会链接到 tivoapp 上。它看起来就像是一个包含多个不同程序的统一的二进制文件。为什么要这样编译程序的原因并不非常直观 —— 它可以降低内存的使用,或者可以让系统更难以崩溃。

混合与匹配

非常值得注意的一件事情是 TiVo 具有一个非常松散的 shell 脚本、Tcl 程序和二进制程序的组合。查看一下程序,就可以了解到该程序到底做什么。例如 installNFS 脚本,是使用 bash 编写的,它调用 text2osd 来显示消息。这个脚本中甚至内嵌了一个 Tcl 脚本!

对于开发来说,Linux 的一大魅力就在于它可以自由地混合并适应开发工具的要求,例如 TiVo 就充分说明了这种优点。

系统启动

与任何 Linux 系统一样,TiVo 也会派生 /sbin/init,后者又会查看 /etc/inittab 的内容来确定要执行哪些操作。它所做的第一件事情是运行 /etc/rc.d/rc.sysinit,后者又会运行诸如 StageA_PreKickstart 和 StageG_PostApplication 之类的目录中的文件。它们都是按照顺序来执行的。

每个这种目录中都包含很多的脚本,这些脚本的名字类似于 rc.Sequence_150.CheckForDebug.sh。这些文件与常见的 Linux 系统上的 /etc/rc.d/rc3.d/S12sshd 文件类似。注意 shell 的扩展顺序(例如 rc.Sequence_*.sh)用来确定这些文件的执行顺序。如果一个脚本的名字中包含字符串 .Platform,那么它就只能在所匹配的硬件上运行。

对于供应商来说这是一个很好的设计,因为他们并不需要为每台机器都构建不同的磁盘。.Implementation 和 .Implementer 标记与此类似,它们用来标识只在某些系统上运行的脚本。Stage 目录替换了 rcN.d 目录,后者在 TiVo 系统上已经不存在了。

这种组织方式使查看在启动的每个步骤中到底执行了哪些功能变得相当简单。有趣的是,这些 shell 脚本被引入了父 shell 中,这样,早期的脚本就可以为以后的脚本设置一些环境变量了。

结束语

TiVo 是众多不同 Linux 哲学中一个非常迷人的例子,它还在不断发展,与公司通过向用户销售服务和提供简单健壮的应用程序来赚钱的哲学形成了显著的对比。黑客发现的最有效的很多特性可能是让其他人不能使用完全定制的系统的客户技术支持,同时纳闷它们为何不能工作。

从另外一方面来说,现在已经进行了大量的努力来使得对系统的攻击更加困难。早期的 TiVo 系统通常被修改成 Web 服务器。我正在查看的一个特性正如任何人都了解的一样,不能用来运行新内核;也不可能不经过对硬件(PROM,用来检查对软件的未经授权的修改)的攻击就对系统进行大量的改变。

值得一提的是,尽管 GPL 要求 TiVo 必须公开自己的内核源代码,但是并没有不让它们构建一个不许您做任何更改的运行 Linux 的系统。这种系统有趣的方面在于,了解系统如何来实现自己的功能,以及如何使用各种开源工具和技术来构建一个嵌入式应用程序。


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
RIOS实验室联手Imagination.共同助力RISC-V生态发展