---
# System prepended metadata

title: 2022q1 Homework3 (quiz3)
tags: [linux2022]

---

---
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



---
