xv6: bootmain.c 读段 () "round down to sector boundary"

xv6: bootmain.c readseg() "round down to sector boundary"

来自 xv6 的代码 bootmain.c:

// Read 'count' bytes at 'offset' from kernel into physical address 'pa'.
// Might copy more than asked.

void
readseg(uchar* pa, uint count, uint offset)
{
  uchar* epa;

  epa = pa + count;

  // Round down to sector boundary.
  pa -= offset % SECTSIZE;

  // Translate from bytes to sectors; kernel starts at sector 1.
  offset = (offset / SECTSIZE) + 1;

  // If this is too slow, we could read lots of sectors at a time.
  // We'd write more to memory than asked, but it doesn't matter --
  // we load in increasing order.
  for(; pa < epa; pa += SECTSIZE, offset++)
    readsect(pa, offset);
}

我不明白下面的说法:

pa -= offset % SECTSIZE;

"Round down to sector boundary" 到底是什么意思? 我不明白为什么我们要减去物理地址(当偏移量不为零时)。

为简单起见,假设 pa = 100(十进制),count = 50,offset = 5,SECTSIZE = 100。

那么epa就变成了100+(50*1)=150。

new pa = 100 - (5%100) = 95。(有什么意义?)

循环运行了 3 次(多了 1 个扇区,为什么没关系?)

内存被分解为每个 SECTSIZE 字节的扇区。 该代码正在减少目标地址,因为它将其工作委托给 readsect,它只读取整个扇区。 如果它传递了一个不在扇区边界上的地址,它会读取比需要更多的内容(如评论所警告的),到一个低于调用者指定的地址的地址(not警告)。这可能是低效的,并且可能是灾难性的,但这个实现至少将调用者请求的字节放在他们指定的地址上。

考虑以下示例,扇区大小为 4 字节。用户调用 readseg(pa, 2, 14); 并且为了论证我们假设内核内存中的每个字节都设置为等于其偏移量的值,并且 pa 指向 "Hello world" 中的第二个字。

readsect 将被调用一次,它将读取一个 4 字节的扇区。引起混淆的行 pa -= offset % SECTSIZE; 是代码如何确保字节 14 结束于调用者指定的地址(pa 的初始值)。

    Before      After
    'H'         'H'
    'e'         'e'
    'l'         'l
    'l'         'l'
    'o'      pa 12
    ' '         13
 pa 'w'         14
    'o'         15
epa 'r'     epa 'r'
    'l'         'l'
    'd'         'd'
    0           0