有助于理解宏观

时间:2010-10-26 00:52:05

标签: c linux-kernel

我在理解MTD驱动程序中的某些代码时遇到问题

#define ROUNDUP(x, y)       ((((x)+((y)-1))/(y))*(y))
...
static struct mtd_partition my_parts[] =
{
   {
      .name = "boot",
      .size = 0,
      .offset = 0,
      .mask_flags = MTD_WRITEABLE
   },
   {
      .name = "linux",
      .size = 0,
      .offset = 0
   },
   {
       .name = "rootfs",
       .size = 0,
       .offset = 0,
       .mask_flags = MTD_WRITEABLE
   },
   {
       .name = "nvram",
       .size = 0,
       .offset = 0
   },
   {
       .name = 0,
       .size = 0,
       .offset = 0
   }
}
...

i = (sizeof(bcm947xx_parts)/sizeof(struct mtd_partition)) - 2;

bcm947xx_parts[i].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
bcm947xx_parts[i].offset = size - bcm947xx_parts[i].size;

所以这是我的任务: 1)为什么有必要对分区的大小进行舍入? 2)你能帮助理解舍入的工作原理吗? 3)同一平台上的引导加载程序中的闪存驱动程序不会对此特定分区进行舍入,因此内核端和引导加载程序中的闪存布局具有不同的偏移量。这是什么原因?

提前感谢任何有价值的评论!

1 个答案:

答案 0 :(得分:6)

(1)闪存的擦除大小是其倍数。 (显然。至少,这是引用代码告诉我的内容。)这意味着NVRAM的结尾与接下来的内容之间存在差距。该间隙小于一个擦除尺寸的大小。在flash中,不方便将两个具有不同重写时间表的对象放在一个擦除块中 - 更改任一对象都需要闪存存储控制器将块复制到临时存储,对存储应用部分更新,擦除块(慢速),并将更新的块写入主存储。 (它可以重复使用不同的先前擦除的块并将其线程化回原始块的位置。但这被认为是高科技优化。)

(2)如何解析宏:

((((x)+((y)-1))/(y))*(y))

步骤1,删除参数周围的parens,确保作为参数传递的复杂表达式不会因运算符优先级而以意外方式突然重新绑定。

(((x+(y-1))/y)*y)

步骤2,删除偏执的parens以获得明确具有指示优先权的操作。

(x+y-1)/y*y

步骤3,使用您的C解析规则,而不是您的代数规则。如果x和y是整数类型(在代码中没有足够的信息来确定这一点),则除法是整数除法,因此从C转换为数学。

 floor((x+y-1)/y)*y

第4步,阅读。如果x是y的倍数,那么由于y-1太小而不是y的倍数,因此操作只返回x。如果x比y的倍数大1,那么+ y-1将分子推到y的下一个倍数上,结果是y的最小倍数恰好大于x。事实上,如果x比y的倍数多1和y-1之间,则“+ y-1”将分子颠覆到y的下一个倍数上,并且向上舍入的结果是y的最大倍数。比x。

因此,我们发现ROUNDUP(x,y)将x向y舍入到恰好大于或等于x的y的最小倍数。此外,此宏不止一次评估其第二个参数:不要在第二个插槽中放置带副作用的表达式,除非您希望每次调用发生三次这样的副作用。 (考虑int i = 3; ROUNDUP(6,i ++)并想知道在i的三个增量中的每一个之前和之后评估哪些子表达式。)

(3)不知道。没有人告诉引导程序作者NVRAM只有擦除倍数?