--- tags: linux2022 --- # 2022q1 Homework3 (quiz3) contributed by < [laneser](https://github.com/laneser) > > [作業要求](https://hackmd.io/@sysprog/BJJMuNRlq) ## 2022q1 第 3 週測驗題 ### 測驗 1 > 已知我們使用的微處理器架構為 64 位元,且 unsigned long 為 8 位元組寬度 (符合 LP64 資料模型),> 以下是可能的 GENMASK 巨集的定義: > ```cpp > #define GENMASK(h, l) \ > (((~0UL) >> (LEFT)) & ((~0UL) >> (l) << (RIGHT))) > ``` #### 想法 & 思考 先拆解題目的結果, 會是兩個值做 bitwise AND: - `((~0UL) >> (LEFT))` : 這個值是 `~0` (all 1) 往低位移 bits, 所以一定是高位 0, 低位 1 的形式. - `((~0UL) >> (l) << (RIGHT))` : 先把 ~0 往低位移, 再往高位移, 所以會是高位跟低位為 0, 中間為 1 的形式. 所以這樣就可以得知, 如果我們需要 `h` 表示高位的 1 起點, `l` 表示低位的 1 終點, 那麼 - `((~0UL) >> (LEFT))` : 這個值是 ~0 (all 1) 往低位移 bits, 所以一定是高位 0, 直到 `h` 低位 1 的形式. - `((~0UL) >> (l) << (RIGHT))` : 先把 ~0 往低位移, 再往高位移, 所以會是高位跟低位為 0, 中間 為 1 的形式. 而高位的 `h` 以前的 0 交給前者負責, 所以這裡的值只要確保低位的 `l` 右邊都是 0 就可以. 那麼, `LEFT` 就是 `63-h`, `RIGHT` 是 `l`. 想到 `((~0UL) >> (l) << (RIGHT))` 如果目的只是高位為 1, 低位為 0 的格式會更合理, 所以 `((~0UL) << (l))` 難道不好嗎 ? #### 延伸問題 > 比較 Linux 核心 GENMASK 巨集的實作,闡述其額外的考量 Linux 當中的 GENMASK 在 [bits.h](https://github.com/torvalds/linux/blob/34c5c89890d6295621b6f09b18e7ead9046634bc/tools/include/linux/bits.h#L37): ```cpp #define __GENMASK(h, l) \ (((~UL(0)) - (UL(1) << (l)) + 1) & \ (~UL(0) >> (BITS_PER_LONG - 1 - (h)))) #define GENMASK(h, l) \ (GENMASK_INPUT_CHECK(h, l) + __GENMASK(h, l)) ``` `GENMASK_INPUT_CHECK` 如文字所述就是檢查輸入的參數是否合格. 所以本體是 `__GENMASK(h, l)` , 而也是兩個部分, 只是把往高位移的部分放在前面: - ((~UL(0)) - (UL(1) << (l)) + 1) : 並不是單純的 `~UL(0) << (l)`, 而是 `~0UL - (1UL << l)`, 這樣會做出一個從低位元算過來第 `l` 位是 0 , 其他都是 1 的 mask, 接著再 `+ 1` 就會讓第 `l` 位置 0 右邊的 `1` 都變 `0`, 然後讓原本 `l` 位置的 `0` 進位變成 `1`. - (~UL(0) >> (BITS_PER_LONG - 1 - (h))): 的確跟 `((~0UL) >> (63 - h))` 格式一樣 > 舉出 Linux 核心原始程式碼中二處 GENMASK 巨集和 include/linux/bitfield.h 的應用案例 --- ### 測驗 2 ---