可以通过 LFU 设想许多用例。下面列出了这些用例。A、B、C、D 等指固件版本。
- A→B →C →D →E
- 这是我们准备的典型用例
- A 用作构建 B 的参考映像,B 用作 C 的参考映像,依此类推
- A→B →A →B →A
- 我们可能会遇到的另一个用例,会用于测试目的,或者在现场,如果您希望当在新映像中发现问题时恢复到原始映像
- A 将用作构建 B 的参考映像,因此,当您从 A 切换到 B 时,可以使用编译器的热初始化例程。因为 A 是作为参考提供的,所以编译器知道 A 和 B 之间的变量差异,并将 B 特有的变量放在“TI.update”段。当 LFU 从 A 切换到 B 时,这是将由编译器在其 __TI_auto_init_warm() 例程中进行初始化的唯一段
- 当从 B 切换到 A 时,情况就不同了。A 是独立编译的,因此它没有“.TI.update”段,编译器不知道哪些变量是 A 所特有的(相对于 B),因此 __TI_auto_init_warm() 不会执行任何操作
- 这个用例是否可行?是,用户仍可以从 B 切换回 A。只是用户无法利用编译器的 __TI_auto_init_warm() 来初始化 A 所特有的任何变量。用户需要使用宏来手动初始化 A 的 main() 中的这些特有变量。例如,如果 A 在闪存组 0 中,而 B 在闪存组 1 中,则 A 在 main() 中可以具有如下初始化代码:
#ifdef BANK0
[初始化 A 所特有的变量]
#endif - 事实上,当前 LFU 示例说明了 A-B-A-B 切换。不同之处在于,在当前示例中,B 与 A 相比具有新变量,但 A 与 B 相比没有任何特有变量。还请记住,并未使用由编译器提供的热启动例程,因此,即使从 A 切换到 B 使用的也是手动初始化
- 跳过了更新 – 假设现场位置在固件版本变为可用时并不进行更新,而是跳过更新。例如:
现场位置 1:A→B →C →D →E
现场位置 2:A →C →D →E
现场位置 3:A→B → D →E
这个用例是否可行?否。这里有两个问题。
- 第一,LFU 本质上是递增的。因此,每个映像都建立在另一个映像的基础上。由编译器生成的 .TI.update 段特定于生成该映像时使用的参考 elf。如果用户希望相对于较旧的映像进行更新,则需要通过手动方式来了解这两个映像之间的变量差异,并且需要对特有变量进行手动初始化。更大的问题是状态。假设 B 引入了一个新变量“var_x”,该变量随后成为所有将来映像的公用变量。用户正在从 A 更新到 D。现在,D 假设 var_x 是一个公用变量,因为它位于 C 中,所以不会将其初始化。然而,相对于 A 而言,var_x 是新变量。因此,不对它进行初始化可能会导致问题。
- 第二,在我们的实现方案中,用户还需要知道映像所针对的特定组。所以,在这个例子中,A、C、E 将位于组 0 上,而 B、D 将位于组 1 上。因此,不可能如现场位置 2 中所示从 A 更新到 C。
- 如果用户在不使用旧固件作为参考的情况下构建新固件,则无法保证公用全局变量保留在相同地址,因此无法保留状态。因此,在 LFU 切换之后,除非在切换期间执行了整个 C 初始化例程,否则应用程序的行为可能会出乎意料。这可能会耗时太多,超过可用的 LFU 切换时间。