将 LinuxBIOS 移植到 AMD SC520

作者:Ron Minnich

在本文中,我们描述了洛斯阿拉莫斯国家实验室集群研究团队将 LinuxBIOS 移植到 AMD SC520 CPU 所做的工作。虽然篇幅有限,无法详细描述所有涉及的工作,但我们希望您能了解移植到新主板所需的一些步骤。

AMD SC520 是一款小型、低功耗的集成 CPU。它被用于许多嵌入式应用中,其中一个更有趣的应用是波特兰航空航天协会的开源火箭。这款火箭使用 Kontron 的标准主板来控制所有车载计算功能。该主板具有许多不错的控制总线,包括用于火箭子系统电源控制的 CAN 总线。

我们被问及是否可以将 LinuxBIOS 移植到火箭团队使用的主板上。我们购买了他们使用的主板,并发现了一个主要问题:BIOS 闪存是焊接在主板上的。如果您刷入错误的 BIOS,主板就会变成一个漂亮的镇纸。拥有一块烧坏的精美主板作为镇纸可能不错,但我们更希望拥有可以正常工作的主板。

经过一番研究,我们了解到 Advanced Digital Logic (ADL) 生产了一款不错的 SC520 主板,其 BIOS 闪存部件是可拆卸的。我们决定使用这款主板进行开发。我们过去在迷你集群中使用过 ADL 的主板,它们运行良好。

我们首先从移植到带有可拆卸闪存的主板开始工作。一旦移植稳定下来,我们的计划是深吸一口气,然后在带有不可拆卸闪存的主板上尝试。当然,如果失败了,我们就光荣地拥有了一块价值 400 美元的砖头!

移植 LinuxBIOS 的步骤

任何 LinuxBIOS 移植过程中的步骤在不同主板之间变化不大。首先,枚举主板上提供的资源,例如 CPU、I/O 部件等等。接下来,创建配置文件来描述这些资源,并将这些文件填充到目录树中。然后,用代码填充空白。

LinuxBIOS 本身大约 98% 是 C 代码。少量涉及的汇编代码对于给定 CPU 的几乎所有主板都是通用的。从这个意义上说,LinuxBIOS 是一段比专有 BIOS 更好的代码,我们被告知专有 BIOS 几乎完全是汇编代码。当然,我们没有见过这些源代码。

LinuxBIOS 构建过程的工作原理

LinuxBIOS 构建过程与 Linux 内核构建过程几乎没有相似之处。相反,LinuxBIOS 构建过程的灵感来自 Plan 9 和 BSD 内核构建过程,尽管 LinuxBIOS 过程增加了更多的形式化和控制。构建 BIOS 需要进行大量检查,因为错误的代价很高。由于我们的集群可能拥有 1,024 或 2,048 个节点,因此我们希望确保一次性刷入所有节点的 BIOS 是良好的。然而,正如我们将看到的,如果我们使用 LinuxBIOS 的后备 BIOS 功能,即使刷入错误的 BIOS 也是可以承受的。

目标是主板上 LinuxBIOS 的特定实例。作为为目标构建的 LinuxBIOS 镜像,它由资源管理代码的粘合代码和资源代码本身组成。资源可以被认为是一个或多个 .c 文件,用于控制硬件组件,无论是主板、CPU 还是其他芯片。资源代码可以调用其他资源的代码作为配置过程的一部分。例如,主板资源调用 CPU 启动的代码。

每个资源都有一个目录,因此对于 SC520,我们需要有一个名为 src/cpu/amd/sc520 的目录。该目录包含源代码和两个配置文件,其中一个配置文件指定资源使用的选项和默认选项值。另一个配置文件指定要构建哪些部件以及如何构建它们。给定资源的配置文件可以指定要使用的其他资源,在这种情况下,将读取并处理这些资源的配置文件。

LinuxBIOS 配置工具从名为目标配置文件的初始配置文件开始,创建一个构建目录。一旦配置工具运行,用户切换到构建目录并键入make。此时,将构建该目标的 LinuxBIOS 镜像,并可以将其烧录到闪存中。

给定主板可以有多个目标配置文件。可以为这些不同的目标设置不同的选项。一个目标可能有很多调试信息,另一个目标可能使用不同的引导加载程序等等。所有这些控制都由构建过程中的选项设置。

选项在 LinuxBIOS 源代码树中定义,并且只能使用已定义的选项。选项具有默认值,并且只能设置一次,以避免在如何设置选项以及它们可能具有哪些值方面造成混淆。

此过程的目标是使在一台机器上轻松、快速地构建所有目标成为可能,同时只保留一份源代码副本。第二个目标是避免在早期版本的 LinuxBIOS 中出现的错误,当时选项不受控制或在太多地方设置。该过程支持交叉编译,因此我们可以在 x86 机器上构建我们的 PowerPC 目标。

LinuxBIOS 目录树结构

图 1 显示了 LinuxBIOS 目录树结构的一部分。从树的顶部开始,有三个主要目录:src、targets 和 util。src 目录包含所有 BIOS 的所有源代码——所有主板、所有 CPU、所有设备等等。您可以使用配置文件在 target 目录中构建特定的 BIOS。例如,对于我们的项目,我们使用 targets/digitallogic/msm586seg 目录中的 Config.lb 文件在该目录中构建了我们的 BIOS。最后,util 目录包含许多用于创建 BIOS 文件或将 BIOS 镜像烧录到主板闪存部件中的实用程序。

Porting LinuxBIOS to the AMD SC520

图 1. LinuxBIOS 目录树包括三个顶级目录,分别用于源代码、配置文件和实用程序。

配置文件

LinuxBIOS 中的配置文件描述了资源以及如何在目标的构建中使用它们。每个资源都可以有一组为其定义的选项。所有可用选项的集合在一个文件 src/config/Options.lb 中定义;只有在该文件中定义的选项才能在配置文件中使用或设置。一旦在配置文件中命名了资源,在该资源范围内定义的资源将继承该资源的选项设置。选项具有词法作用域;一旦资源的块结束,选项将恢复到块开始之前的值。选项可能在 Options.lb 文件中设置了默认值,或者可能未设置;它们可能在主板配置文件中设置了默认值;或者它们可能在目标配置文件中设置。为了避免我们在早期版本的配置工具中看到的混乱,选项只能在少数几个地方设置:目标文件、主板文件和 CPU 文件。选项只能设置一次。因此,一个选项可能有一个默认值,该默认值可以在配置文件中更改一次且仅更改一次。强制执行一次设置规则避免了我们之前看到的由于互相冲突的配置文件而导致的问题。

关于配置语言的完整说明将占据整篇文章。因此,本文仅触及要点,但我们无法涵盖配置语言的所有方面。

静态信息与动态信息

在所有主板中,一些资源硬件可以被查询以确定它需要的其他资源,例如,它需要多少内存和 I/O 空间。还有一些硬件无法查询,例如将 PCI 插槽连接到中断控制器的线路。对于后一种类型的资源,告知 BIOS 的唯一方法是将信息直接放入 BIOS 中。不幸的是,此信息包含在 PC BIOS 的许多位置。中断路由可能在 $PIR(单处理器)、_MP_(多处理器或 IO-APIC)或 ACPI 表中找到。配置工具必须生成这些表,但用户反过来必须告诉工具在表中放入哪些值。

超级 I/O 芯片无法动态查询,并且必须在主板配置文件中指定超级 I/O 芯片在 I/O 空间中的位置和类型。

较新的 PC 主板在运行时更难弄清楚。例如,Opteron 处理器有三个 HyperTransport 端口,可以在不同的主板上以任意配置进行布线。主板的配置文件必须指定这些端口是如何布线的。

在没有内存的情况下编译 C 代码:romcc

在带有同步 DRAM 芯片的现代系统中,在完成大量设置之前,内存是不可访问的。DRAM 的大小和参数是通过称为 SMBUS 的双线总线读取的。因此,为了建立工作内存,BIOS 必须:

  • 在一定程度上开启芯片组。

  • 启用 SMBUS,通常在超级 I/O 或南桥上。

  • 通过 SMBUS 读取 DRAM 的参数;在某些情况下超过 20 个。

  • 执行复杂的计算以确定时序。

  • 使用正确的值初始化 DRAM 控制寄存器。

  • 执行复杂的从 DRAM 读取而非写入的序列以使其运行。

所有这些都必须在没有堆栈的情况下完成,这意味着函数调用和变量几乎不可能使用。在没有内存的情况下,编程仅限于寄存器。函数调用只能进行一级深度。在过去糟糕的日子里,曾经使用一大堆糟糕的汇编代码来完成这项工作。汇编代码专家使用了书中的所有技巧来使这段代码工作。编写这段代码是任何 BIOS 中最困难的部分。

2002 年,Linux NetworX 的 Eric Biederman 开发了一个名为 romcc 的编译器。romcc 是一个简单的优化 C 编译器——一个文件,25,043 行代码——它只使用寄存器,不使用内存。编译器可以使用扩展寄存器集,例如 MMX、SSI 或 3DNOW。romcc 使我们能够抛弃 LinuxBIOS 中几乎所有的汇编代码,因此即使是最早的代码,在没有工作 DRAM 的情况下运行,也可以用 C 编写。

romcc 仅用于早期的、内存之前的代码。对于内存启动后运行的代码,我们使用 GCC。

构建过程构建的内容

构建过程构建一个二进制镜像,该镜像被加载到闪存部件中。LinuxBIOS 提供了一个实用程序 flash_rom 用于此目的。或者,您可以使用 Linux 内核中的 MTD 驱动程序。

典型的 ROM 镜像布局如图 2 所示。顶部 16 个字节包含两个跳转向量,一个跳转到后备 BIOS,另一个跳转到正常 BIOS。LinuxBIOS 始终首先跳转到后备 BIOS。如果一切正常,它会跳回到内存顶部的跳转到正常 BIOS 向量,然后从那里跳转到正常镜像。如果后备代码检测到问题,或者 CMOS 设置指示应运行后备 BIOS,则运行后备 BIOS。

Porting LinuxBIOS to the AMD SC520

图 2. 典型的 ROM 镜像包括一个后备 BIOS,以便在主 BIOS 出现问题时允许启动。

为 SC520 主板构建树

概述足够了,让我们开始工作吧。要构建对新主板的支持,我们首先从主板开始,最简单的方法是选择一个类似的主板。由于 Digital Logic ADL855 与 SC520 非常相似,因此我们从它开始。我们可以为 SC520 主板克隆 ADL855 的大部分目录结构。

主板树和文件

LinuxBIOS 中目录的基本命名过程是命名资源类型,在本例中为 mainboard(主板);供应商,此处为 digitallogic;以及部件名称,在本例中为 msm586seg。在我们开始主板配置文件之前,我们需要知道此主板上有什么。我们不必一开始就了解所有内容;事实上,我们可以省略很多内容,只是为了让某些东西能够工作。通常,最好的方法是确保您知道是什么驱动了串口,并确保您获得了它。要启动 DRAM,您需要确保您设置了驱动 SMBUS 的任何设备。当主板开启时,这些芯片都没有处于正确的状态;您需要设置一些位才能使事情运转起来。

为了弄清楚这一切,您有几个选择。几乎总是,最简单的事情是启动 Linux 并键入lspci。对于这种类型的主板的工作,最简单的方法是拥有一个安装了小型 Linux 发行版的 CompactFlash 部件,这样您就可以启动足够长的时间来运行 lspci 命令。您也可以使用 lspci 来转储配置空间寄存器,这有时对于发现如何设置供应商可能忘记告诉您的控制位非常宝贵。setpci 命令也很方便,用于探测位并了解设置和清除它们的效果。在几块主板上,我们使用 setpci 来探测芯片组,以找到板载设备未记录的使能线。

设备

虽然 lspci 显示的是离散设备,但在 SC520 上,它们集成到了部件中。在过去,即使部件集成到 CPU 中,我们也会创建一个新的资源。根据之前的经验,我们已经决定,如果部件集成到 CPU 中,我们不将其视为单独的资源。因此,没有单独的目录用于北桥和南桥。这些设备的代码在 CPU 设备中支持。LinuxBIOS 代码库在这方面是灵活的。给定的 BIOS 可以使用不同类型的部件来实现,但实际上它们都不是必需的。

为使主板设置资源,我们的第一步是命名 CPU 并为其设置目录。给定 CPU 的代码包含在 src/cpu 目录中。幸运的是,本例中的 CPU 是 x86 系统,因此无需添加架构目录。

本文从我们的角度——LinuxBIOS 开发人员——追溯了开发过程。但是,如果您想开发新的树,您可以克隆 LinuxBIOS arch 存储库,进行开发并将补丁提交给开发人员。我们将检查您的补丁并帮助将其放入存储库中。在大多数情况下,对于新的开发人员,如果他们的代码良好,我们允许他们成为我们团队的开发人员。

CPU

我们创建一个目录 src/cpu/amd/sc520,并用支持 CPU 的文件填充它。我们不会展示我们在此移植中所做的一切操作的所有命令,但对于第一个更改,我们展示这些命令是为了让您了解它是如何工作的。即使是这个简单的部分也解释了 LinuxBIOS 构建方式的许多重要方面。

cd src/cpu/amd
mkdir sc520
tla commit

这设置了目录;现在我们需要填充它。src/amd/socket_754 目录是提供模型文件的良好候选者,因此我们使用它们

cd sc520
cp ../socket_754/* .

这为我们提供了一组初始文件

rminnich@q:~/src/freebios2/src/cpu/amd/sc520> ls
chip.h Config.lb socket_754.c

chip.h 文件定义了一个简单的数据结构,该结构由 config 工具生成的 Makefile 链接到 BIOS 镜像中。对于此部件,它基本上是空的

rminnich@q:~/src/freebios2/src/cpu/amd/sc520> catchip.h

extern struct chip_operations cpu_amd_socket_754_ops;

struct cpu_amd_socket_754_config {

};

这是什么意思?首先,我们为此部件创建一个名为 cpu_amd_socket_754_ops 的 chip_operations 结构实例。这是一个通用结构,所有芯片都使用它。这个通用结构看起来像这样

/* Chip operations */

struct chip_operations {

        void (*enable_dev)(struct device *dev);

#if CONFIG_CHIP_NAME == 1

        char *name;

#endif

};

src/include/device/device.h 中的 chip_operations 结构定义了一种访问芯片的通用方法。它目前有两个结构成员:一个指向启用设备的函数指针 enable_dev;以及一个可选名称,用于调试打印,称为 name。请注意,在 Linux 内核的风格中,C 预处理器启用的代码是通过测试预处理器符号的值来控制的,而不是通过测试它是否已定义。正如您所看到的,enable_dev 函数接受指向 device 结构的指针。

我们为什么要这样做?虽然一种类型的芯片有一个 chip_operations 结构,但每个芯片的可能实例都有一个 device 结构。我们说可能,是因为为系统中可能存在的每个芯片定义了一个 device 结构。考虑一个 SMP 主板,它有一个到四个甚至八个 CPU;并非所有 CPU 都可能在那里。启用功能的部分工作是确定芯片是否真的在那里。

device 结构看起来像这样

struct device {
   struct bus * bus; /* bus this device is on, for
                      * bridge devices, it is the
                      * upstream bus */

   device_t sibling; /* next device on this bus */
   device_t next;    /* chain of all devices */
   struct device_path path;
   unsigned vendor;
   unsigned device;
   unsigned int class; /* 3 bytes:
                        * (base,sub,prog-if) */
   unsigned int hdr_type; /* PCI header type */
   unsigned int enabled : 1; /* set if we should
                              * enable the device */
   unsigned int initialized : 1;
    /* set if we have initialized the device */
   unsigned int have_resources : 1;
    /* Set if we have read the device's resources */
   unsigned int on_mainboard : 1;
   unsigned long rom_address;
   uint8_t command;

   /* Base registers for this device. I/O, MEM and
      Expansion ROM */

   struct resource resource[MAX_RESOURCES];
   unsigned int resources;

   /* links are (downstream) buses attached to the
    * device, usually a leaf device with no child
    * has 0 busses attached and a bridge has 1 bus */

   struct bus link[MAX_LINKS];

   /* number of buses attached to the device */
unsigned int links;

   struct device_operations *ops;
   struct chip_operations *chip_ops;
   void *chip_info;

};

这是一个相当复杂的结构,我们在此不深入探讨所有问题。在配置步骤中,LinuxBIOS 配置工具通过将 C 代码写入构建目录中的文件来实例化每个芯片的 struct device。配置工具生成的 C 代码具有初始值,以便 device 结构数组形成一个树,其中包含兄弟节点和子节点。LinuxBIOS hardwaremain() 函数遍历此树,从根节点开始,并执行设备探测和初始化。

最后一个结构成员是 void *——也就是说,一个可以指向任何东西的指针。倒数第二个元素是指向 chip_operations 的指针。作为创建初始化的 C 结构的一部分,配置工具使用指向每个芯片配置结构和每个芯片类型结构的指针填充 chip_info 和 chip_operations 指针。因此,树中的每个设备都具有指向芯片类型结构和芯片的各个实例结构的指针。类型芯片的启用结构成员(它是函数指针)在调用时会传递指向芯片的每个实例的设备结构的指针。device 结构具有许多通用结构成员,正如您所看到的,并且它具有指向非通用芯片组件结构的指针。

对于每个芯片,我们可以选择性地提供两个结构的声明,但这不是必需的。chip_operations 结构或芯片类型结构具有由 LinuxBIOS 本身固定的类型;chip_info 结构具有由芯片固定的结构。chip_operations 结构中的 enable 函数可以未初始化,在这种情况下,没有要为芯片调用的启用函数——芯片始终处于启用状态。SC520 CPU 就是这种情况——只有一个,并且它始终在那里。

现在我们需要更改这些文件以匹配 SC520。我们展示更改前后的文件,以便您了解它的外观。

chip.h 更改后如下所示

extern struct chip_operations cpu_amd_sc520_ops;

struct cpu_amd_sc520_config {

};

enable_dev 指针为空,并且未被调用。我们暂时将其留空,但可能会在以后根据需要填充它。同样,chip_info 结构也没有特殊的结构成员。

C 代码如下所示

#include <device/device.h>
#include "chip.h"

struct chip_operations cpu_amd_socket_754_ops =
  { CHIP_NAME("socket 754") };

更改很简单;我们将文件重命名为 sc520.c,然后将其更改为

#include <device/device.h>
#include "chip.h"

struct chip_operations cpu_amd_sc520_ops =
  { CHIP_NAME("AMD SC520") };

最终文件是 Config.lb 文件。在这里,我们第一次了解配置文件是什么样的。原始文件如下所示

uses CONFIG_CHIP_NAME

if CONFIG_CHIP_NAME

        config chip.h

end

object socket_754.o

dir /cpu/amd/model_fxx

第一行声明我们正在使用 CONFIG_CHIP_NAME 选项。该语言要求我们在使用变量之前声明我们要使用的变量。在本例中,该文件看起来微不足道,但在较长的文件中,此要求非常有用。其次,如果我们正在使用 CONFIG_CHIP_NAME 选项,我们使用 chip.h 文件。请注意,除非我们正在使用 CHIP_NAME 宏,否则 chip.h 中未设置任何内容,这就是为什么存在此测试的原因。我们声明在此目录中生成的任何目标文件,在本例中为 socket_754。最后,我们使用 dir 关键字包含另一个目录。配置语言中其他目录的命名方案是,如果路径名不是以 / 开头,则它是相对路径名。否则,它以 LinuxBIOS 源代码树的根目录为根目录。在本例中,dir 指令指向 src/cpu/amd/model_fxx。碰巧的是,这是 Opteron 的代码,对 SC520 没有用处。在为 SC520 修改此文件后,它看起来像这样

uses CONFIG_CHIP_NAME

if CONFIG_CHIP_NAME

        config chip.h

end

object sc520.o

差不多就是这样了。我们现在已经设置了对 SC520 的支持。

主板

现在我们设置主板。我们首先cd到 mainboard/digitallogic 并执行

mkdir msm586seg

然后我们从相邻的 adl855pc 目录填充它。

这里有很多文件。我们没有足够的空间在此处详细介绍每个文件的更改,但我们可以总结我们对每个文件所做的操作。

auto.c

此文件由 romcc 编译,在专有 BIOS 中,它将是一个大型汇编代码块。首先,我们完全清空此文件——它应该只包含一个打印函数。这是启动新移植的最简单方法——确保您有能力获得一些输出。没有空间显示整个文件,但您可以在存储库中看到它,或者使用viewarch。但是,有两件事需要正确处理。首先是选择包含文件。对于 romcc,不会链接额外的 C 代码;它被包含在内。包含文件看起来像这样

#define ASSEMBLY 1

#define ASM_CONSOLE_LOGLEVEL 8

#include <stdint.h>
#include <device/pci_def.h>
#include <arch/io.h>
#include <device/pnp_def.h>
#include <arch/romcc_io.h>
#include <arch/hlt.h>
#include "pc80/mc146818rtc_early.c"
#include "pc80/serial.c"
#include "arch/i386/lib/console.c"
#include "ram/ramtest.c"
#include "cpu/x86/mtrr/earlymtrr.c"
#include "cpu/x86/bist.h"
#include "cpu/amd/sc520/raminit.c"

对于 romcc,我们将 ASSEMBLY 值定义为 1。我们还将汇编的控制台日志级别设置为非常高的级别——在本例中为 8。LinuxBIOS 使用宏进行打印,以便在构建生产 BIOS 时,可以将调试打印宏编译掉以节省空间。控制台日志级别为 8 可确保编译每个打印调用。

这是 main 函数,它什么也不做

static void main(unsigned long bist)

{
    print_err("Hello\n");
}

有了这个简单的 main 函数,我们可以测试很多东西。我们可以构建 BIOS,加载它,看看是否得到打印输出。仅仅让打印工作起来是启动 BIOS 的一大步。

chip.h

我们看到了 CPU 的 chip.h;它对于主板来说是否不同?事实上,它真的没有什么不同

extern struct chip_operations
    mainboard_digitallogic_msm586seg_ops;

struct mainboard_digitallogic_msm586seg_config {
};

与之前一样,有一个通用的 chip_operations 结构和一个用于芯片的专用结构,在本例中它是主板。LinuxBIOS 中的每个设备都以相同的方式处理。这种统一的结构已被证明是强大的。

cmos.layout

cmos.layout 定义了 CMOS 存储器的结构,CMOS 存储器是主板上的电池供电存储器。我们暂时保持此文件不变。

Config.lb

Config.lb 在各个平台之间非常标准,因此出于篇幅考虑,我们在此处仅显示一个子集,即特定于主板的部分。我们将介绍一些要点,但要了解更多详细信息,您需要研究存档中的完整文件。

driver mainboard.o

此语句声明了一个驱动程序文件 mainboard.o,该文件包含在链接到最终镜像的二进制文件集中

##
## Build our 16 bit and 32 bit linuxBIOS entry code
##

mainboardinit cpu/x86/16bit/entry16.inc
mainboardinit cpu/x86/32bit/entry32.inc
ldscript /cpu/x86/16bit/entry16.lds
ldscript /cpu/x86/32bit/entry32.lds

这些命令与早期初始化有关。配置工具为 BIOS 构建加载器脚本、汇编代码文件以及 C 文件和 Makefile。mainboardinit 命令告诉配置工具将 entry16.inc 和 entry32.inc 汇编代码文件添加到主板的汇编代码文件中。.lds 文件在 ld 脚本中用于确定如何链接汇编代码。

此文件中包含许多 mainboardinit 和 ldscript 指令。这些指令与架构相关,例如,对于 x86 架构;与 CPU 相关,例如,特定于 SC520 CPU;并且在某些情况下,与主板相关。

现在我们来到了文件的复杂部分,出于篇幅考虑,我们将简化该部分

chip cpu/amd/sc520
     device pci_domain 0 on
          device pci 0.0 on end
          device pci 1.0 on end
   end
end

我们正在声明 CPU 以及该 CPU 下的嵌套设备。第一个设备是 PCI 域,域 0,这是此 CPU 拥有的唯一域。我们声明设备 0:0.0 和 0:0.1。目前就这些——但是,稍后会变得更加复杂。

其中一些文件很复杂,在某些情况下运行到 100 行或更多行,因为有些主板很复杂。

failover.c

Failover.c 包含在 auto.c 中,是用于管理后备 BIOS 镜像的故障转移的代码,以防正常 BIOS 镜像以某种方式损坏。

irq_tables.c

PC 硬件没有定义 PCI 插槽中断线到中断控制器上的中断引脚的映射方式。BIOS 中有一个名为 $PIR 结构的结构,操作系统读取该结构以了解如何映射中断。

irq_tables.c 文件具有一个初始化的 C 结构,该结构定义了中断线的连接。此结构被编译到 LinuxBIOS 中并形成 $PIR 表。

此文件由 linuxbios 提供的实用程序 getpir 自动生成。它位于 util/getpir 中。您在 Linux 下运行此实用程序,当在出厂 BIOS 下启动时。该实用程序将 $PIR 表打印为 C 代码。一个需要注意的地方:我们发现许多 BIOS 上的 $PIR 表都存在错误。有时,我们不得不修复这些表以使其与实际硬件相符。

mainboard.c

此代码由 GCC 编译,而不是 romcc。此文件中目前没有太多内容

#include <console/console.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include <device/pci_ops.h>
#include "chip.h"

struct chip_operations
mainboard_digitallogic_msm586seg_ops = {
  CHIP_NAME("Digital Logic MSM586SEG mainboard ")

};

Options.lb

此文件包含用于此主板的选项名称。首先,列出要使用的所有选项,例如

uses HAVE_FALLBACK_BOOT

如果选项具有某些期望的值,则可以在此文件中设置它

## Build code for the fallback boot
default HAVE_FALLBACK_BOOT=1

这将选项设置为 1。此选项可以在目标文件中被覆盖;也就是说,我们可以在 targets/digitallogic/msm586seg/Config.lb 中设置以下内容

option HAVE_FALLBACK_BOOT=1

并且可以构建没有后备引导镜像的 BIOS。通常,无需更改在此文件中设置的默认值。

我们需要更改默认的 ROM 大小,因为它对于其他主板设置为 1024*1024

default ROM_SIZE  = 256*1024

为什么要将此设置为默认值?以便具有较大 ROM 大小的目标可以覆盖它。如果您为 1MB ROM 构建目标,则应在目标配置文件中放入命令

option ROM_SIZE = 256*1024

在目标配置文件中。

reset.c

此文件包含执行 CPU 硬复位的代码。

目标配置文件

现在我们为主板添加目标目录

cd targets/digitallogic
mkdir msm586seg
tla add msm586seg
cp adl855pc/Config.lb msm586seg/
tla add Config.lb

然后我们提交,代码就进入了。接下来,我们修复 msm586seg 的 Config.lb

target msm586seg
mainboard digitallogic/msm586seg
option DEFAULT_CONSOLE_LOGLEVEL=10
option MAXIMUM_CONSOLE_LOGLEVEL=10
romimage "normal"
        option USE_FALLBACK_IMAGE=0
        option ROM_IMAGE_SIZE=0x10000
        option LINUXBIOS_EXTRA_VERSION=".0Normal"
        payload /etc/hosts
end

romimage "fallback"
        option USE_FALLBACK_IMAGE=1
        option ROM_IMAGE_SIZE=0x10000
        option LINUXBIOS_EXTRA_VERSION=".0Fallback"
        payload /etc/hosts

end

buildrom ./linuxbios.rom ROM_SIZE "normal" "fallback"

该文件定义了七个基本内容

  1. 目标构建目录是 msm586seg;它可以是任何东西。

  2. 主板是 digitallogic/msm586seg。

  3. 默认控制台日志级别为 10;这控制打印哪些编译后的消息。它可以被正常 BIOS 镜像中的 CMOS 设置覆盖。

  4. 最大控制台日志级别为 10;这控制编译哪些打印宏。

  5. 正常的 romimage 不是后备镜像;它是 0x10000 字节 (64KB),具有版本标签 .0Normal,有效负载为 /etc/hosts。

  6. 后备 romimage 是后备镜像;它是 0x10000 字节 (64KB),具有版本标签 .0Fallback,有效负载为 /etc/hosts。

  7. ROM 目标是 linuxbios.rom;它的大小为 ROM_SIZE,如上面的主板 Options.lb 中定义的那样,并且其中包含两个镜像,normal 和 fallback。

掷骰子和蒙上眼睛

好吧,让我们看看情况如何。我们为此部分编写了一个脚本,以节省一些打字时间

cd src/targets

./buildtarget digitallogic/msm586seg

此步骤有效。它可以构建,但我们得到了错误,这是预期的。顺便说一句,上面涵盖的版本是

linuxbios@linuxbios.org--devel/freebios--devel--2.0--patch-21

如果您想查看哪里出错了。经过一些修改,我们得到了一个工作版本,该版本存储在

linuxbios@linuxbios.org--devel/freebios--devel--2.0--patch-22

它可以构建了!下一步是看看我们是否可以获得任何串口输出。当然,请确保将要烧录的闪存部件放入闪存插槽,否则您会非常不高兴。更好的是,在您开始烧录之前,备份您的出厂 BIOS 以防万一。

flash_rom -r /tmp/backup

放入一个新的闪存部件

flash_rom /tmp/backup

并将闪存部件存放在安全的地方。

我们正在笔记本电脑上构建,并使用运行 Linux 的 SC520 作为烧录节点。因此使用

scp linuxbios.rom root@burnnode:
ssh root@burnnode flash_rom linuxbios.rom
它工作了吗?

让我们来看看它是否工作。请务必关注我们在 Linux Journal 网站上的进展。

后续步骤

您可以在网页或 LinuxBIOS Wiki(请参阅在线资源)上跟踪我们的进展——我们在那里设置了一个状态页面,以便您可以了解进展情况。

我们试图向您展示如何快速概述如何将 LinuxBIOS 移植到新系统。如果您真的想尝试一下,请加入邮件列表并告诉人们您正在做什么。那里有很多专业知识,人们随时准备提供帮助。记录显示,一个完全不熟悉此系统的人花了四个小时从头开始构建一个新的 BIOS 移植。这还不错。虽然看起来相当复杂,但一旦您了解如何构建 BIOS,您可能会发现它非常容易。

这项研究部分由美国能源部科学办公室的数学信息和计算机科学 (MICS) 计划以及洛斯阿拉莫斯计算机科学研究所 (ASCI Institutes) 资助。洛斯阿拉莫斯国家实验室由加利福尼亚大学为美国能源部国家核安全管理局运营,合同号为 W-7405-ENG-36。洛斯阿拉莫斯,NM 87545 LANL LA-UR-05-3336。

如何设置 LinuxBIOS 端口系统

我们在 LANL 不使用闪存芯片烧录器,大多数其他地方也不使用。为了烧录新的闪存芯片,我们实际上是将闪存芯片从运行中的机器中取出,放入新的芯片,然后运行 flash_rom 程序来擦除和重写芯片。到目前为止,设置 LinuxBIOS 端口工作站最简单的方法是拥有一台机器用于构建,一台机器用于烧录,还有一台机器用于测试。

最糟糕的情况是让烧录、构建和测试机器是同一台。换句话说,用户必须启动机器,构建 LinuxBIOS,取出闪存 BIOS 芯片并放入测试芯片,烧录它,重启机器进行测试,并且在很可能失败的情况下——毕竟这是一个新的端口——放回出厂 BIOS 并启动。编辑/编译/测试周期时间可能很长,长达 3-5 分钟。在某些情况下,烧录和构建机器可以是同一台。

对于 SC520,我们有一台构建机器,即我们的 x24 笔记本电脑;一台烧录机器,这是一块 MSM586SEG 板;以及一台测试机器,另一块 MSM586SEG 板。为了进一步简化情况,我们使用 Clustermatic 软件套件将两块 MSM586SEG 板作为两个 bproc 从节点运行。Clustermatic 让我们设置这两个没有本地磁盘的从节点。所有状态和控制都从笔记本电脑管理。我们以这种方式进行端口移植已经五年了,这是我们发现的最简单的方法。

我们已经在 LinuxBIOS Wiki 上提供了一个 64MB 的 compact Flash 镜像,因此您可以轻松地制作一台从机器。有关更多详细信息,请参阅 Clustermatic 网站,以获取有关如何将笔记本电脑设置为主节点的说明。

本文资源: /article/8327

Ron Minnich 是洛斯阿拉莫斯国家实验室集群研究团队的团队负责人。他在集群计算领域工作的时间比他愿意回忆的还要长。

加载 Disqus 评论