---
# System prepended metadata

title: 嵌入式安全HW1

---

# 嵌入式安全HW1

> 核心想法:
> Data存入mem前，做漢明碼的計算，並保存在map中。
> Data取出時，利用Addr來對應，並取得當初設定的漢明碼，做ECC修正

> 程式碼:https://github.com/likeyou600/NCU_GEM5_ECC_HW1

## Part 1 (Setting Up Gem5)
>設定 Gem5：安裝 Gem5 並執行基本模擬以確保設定正確。 模擬可以是簡單的記憶體存取場景。
### 1. 安裝依賴
```bash!
sudo apt install build-essential git m4 scons zlib1g zlib1g-dev \ libprotobuf-dev protobuf-compiler libprotoc-dev libgoogle-perftools-dev \ python3-dev libboost-all-dev pkg-config python3-tk
```
### 2. build gem5
```bash!
scons build/X86/gem5.opt -j 6
```
### 3. run
```bash!
build/X86/gem5.opt configs/ncu_lab1_config/ecc_memobj.py

//with debug flag
build/X86/gem5.opt --debug-flags=ECCMemobj configs/ncu_lab1_config/ecc_memobj.py
```

## Part 2 
>設計 ECC 模組：設計一個能夠偵測並修正單位錯誤的簡單 ECC 模組。 這個模組可以是獨立的 C++ 或 Python 類，用於實現基本的糾錯程式碼（如漢明碼）。

### 1. 產生漢明碼

- 漢明碼為2的冪次方位置，其他位置把原始資料(10101101)擺上去，我們將bit數為1的地方，轉成二進制。
- 將這些轉成二進制的地方( 紅色字 )，拿出來做XOR運算，可得1010
![image](https://hackmd.io/_uploads/HkcOmFjf0.png)
- 然後我們將漢明碼反者填回去表格(0101填回去)
![image](https://hackmd.io/_uploads/HklqNFiz0.png)

- 實作部分
    - 實際上我們不需要把漢明碼填回表格，只需記住data對應的漢明碼是多少就好
```cpp!=
int ECCMemobj::generateHammingCode(std::vector<int>& input, int n_bits_data, int  m_bits_parity) {
    int parity = 0, idx = 0, cnt = 0; //idx為input的index //i為input+parity位數
    for (int i = 1; i <= n_bits_data + m_bits_parity; ++i) {
        if (i == pow(2, cnt)) {
            ++cnt;
            continue;
        }
        else if (input[idx]) {
            parity ^= i;
            ++idx;
        }
        else
            ++idx;
    }
    return parity;
}
```
---

###  2. ECC修正
- 將隨便一筆Data(包括漢明碼)填入表格(1101110101)，並且將有1的地方都轉成2進制
![image](https://hackmd.io/_uploads/BJFxDKoGC.png)
- 將這些轉成二進制的地方( 紅色字 )，拿出來做XOR運算，可得0110，代表bit6有錯，將第6bit反轉
![image](https://hackmd.io/_uploads/H1g0UDYsGR.png)
- 實作部分
    - 與實際邏輯相同
```cpp!=
void ECCMemobj::ECC_fix(std::vector<int>& input, int parity, int n_bits_data, int m_bits_parity) {
    int combine[n_bits_data + m_bits_parity] = { 0 }, cnt = 0, idx = 0, input_parity = 0;
    for (int i = 1; i <= n_bits_data + m_bits_parity; ++i) {
        if (i == pow(2, cnt)) {
            ++cnt;
            continue;
        }
        else if (input[idx]) {
            input_parity ^= i;
        }

        combine[i] = idx; //conbine只是記input 的 index
        ++idx;

    }

    input_parity ^= parity;
    if (input_parity != 0) {
        DPRINTF(ECCMemobj, "find Error Bit index : %d \n", combine[input_parity] + 1); //從1開始看
        input[combine[input_parity]] ^= 1; //利用combine vector 找回原本input index
    }
}
```


## Part 3
>將 ECC 整合到 Gem5 中：修改 Gem5 的記憶體系統以整合 ECC 模組。 這涉及確定 Gem5 程式碼庫中的適當位置以添加 ECC 檢查、修改記憶體讀取/寫入操作以包括 ECC 編碼和解碼，以及確保正確儲存和檢索 ECC 元資料（例如奇偶校驗位）。

想法有2個
### 1.直接修改mem_ctrl部分
- 修改recvTimingReq()
    - 在pkt->isWrite() 、 addToWriteQueue之前 做漢明碼生成
    - 在pkt->isRead() 做ECC修正
    - 改到太底層程式碼，有更好的做法，用方法2.
---
### 2.創立simple memory object
![image](https://hackmd.io/_uploads/HJ4JmqsGA.png)

---
#### 2-1.檔案作用解釋
![image](https://hackmd.io/_uploads/H12jQ5jz0.png)
- configs/ecc_memobj.py
    - System介面設計
    - 需要System執行什麼Process
    - 系統效能分析
- src/ecc_memobj.cc
    - 主要simple mem object程式碼
    - handleRequest、handleResponse
- src/ecc_memobj.hh
    - ecc_memobj.cc 標頭檔
    - 定義global變數、function
- src/ECCMemobj.py
    - 定義這個模擬對象的類型名稱
    - 指定標頭文件
    - 定義物件接口(port)
- src/SConscript.py
    - 定義 SimObject
---
#### 2-2.ecc_memobj.cc
重點在於ecc_memobj.cc
修改部分如下

##### 1. handleRequest (cpu->mem)
簡單步驟如下
```cpp!=
ECCMemobj::handleRequest(PacketPtr pkt)
    ||
    vv
if (pkt->isWrite())
    ||
    vv
//輸出pkt基本資訊
DPRINTF(ECCMemobj, "cpu->mem Got request for addr %#x\n", pkt->getAddr());
DPRINTF(ECCMemobj, "size %#x\n", pkt->getSize());
uint8_t* data = pkt->getPtr<uint8_t>();
    ||
    vv
//輸出binary_data
std::vector<int> data_vector(8 * size);
for (size_t i = 0; i < size; i++) {
    std::bitset<8> binary(data[i]);
    for (int j = 7; j >= 0; j--) { // 從高位到低位逐位複製
        data_vector[index++] = static_cast<int>(binary[j]); // 將二進制位轉換為字符
    }
}
DPRINTF(ECCMemobj, "data : %s \n", vector_int_to_string(data_vector).c_str());
    ||
    vv
//產生hamming code，並存入map，供response使用
int parity = generateHammingCode(data_vector, n_bits_data, m_bits_parity);
hammingCodeMap[pkt->getAddr()].first = parity;
hammingCodeMap[pkt->getAddr()].second = size;
DPRINTF(ECCMemobj, "hamming code : %d \n", parity);
```
##### 2. handleResponse (mem->cpu)
簡單步驟如下
```cpp!=
ECCMemobj::handleResponse(PacketPtr pkt)
    ||
    vv
if (pkt->isRead() &&
    hammingCodeMap.find(pkt->getAddr()) != hammingCodeMap.end() &&
    hammingCodeMap[pkt->getAddr()].second == pkt->getSize())
    ||
    vv
//輸出pkt基本資訊
DPRINTF(ECCMemobj, "cpu->mem Got request for addr %#x\n", pkt->getAddr());
DPRINTF(ECCMemobj, "size %#x\n", pkt->getSize());
uint8_t* data = pkt->getPtr<uint8_t>();
    ||
    vv
//輸出binary_data
std::vector<int> data_vector(8 * size);
for (size_t i = 0; i < size; i++) {
    std::bitset<8> binary(data[i]);
    for (int j = 7; j >= 0; j--) { // 從高位到低位逐位複製
        data_vector[index++] = static_cast<int>(binary[j]); // 將二進制位轉換為字符
    }
}
DPRINTF(ECCMemobj, "data : %s \n", vector_int_to_string(data_vector).c_str());
    ||
    vv
//map 找對應的hamming code
int out_parity = hammingCodeMap[pkt->getAddr()].first;
DPRINTF(ECCMemobj, "hamming code out: %d \n", out_parity);
    ||
    vv
//尋找錯誤位置並修正data_vector
ECC_fix(data_vector, out_parity, n_bits_data, m_bits_parity);
    ||
    vv
//把修正後的再次設定進Pkt
int s = pkt->getSize();
int idx = 0;
int output = 0;
unsigned char c;
for (int i = 0; i < s; ++i) {
    for (int j = 7; j >= 0; --j) {
        if (data_vector[idx]) {
            output += 1 << j;
        }
        ++idx;
    }
    c = (unsigned char)output;
    output = 0;
    data[i] = c;
}
    ||
    vv
//輸出fix_binary_data
data_vector.resize(8 * size, 0);
for (size_t i = 0; i < size; i++) {
    std::bitset<8> binary(data[i]);
    for (int j = 7; j >= 0; j--) { // 從高位到低位逐位複製
        data_vector[index++] = static_cast<int>(binary[j]); // 將二進制位轉換為字符
    }
}
DPRINTF(ECCMemobj, "fix data : %s \n", vector_int_to_string(data_vector).c_str());
```

## Part 4、Part 5 
>模擬：使用修改後的 Gem5 運行模擬，以評估 ECC 對記憶體可靠性和系統效能的影響。 學生應該在記憶體存取中引入錯誤，並演示 ECC 模組如何檢測和糾正這些錯誤。

>報告和演示：您應該包括 ECC 模組的設計決策和實現細節、整合過程中面臨的挑戰以及如何克服這些挑戰，以及模擬結果，重點關注 ECC 的影響關於系統性能和可靠性。


- (情況:對單個pkt，做全長的漢明碼生成)嘗試每10次write data，就壞掉1個  ->成功 時間0.63~0.68s
![image](https://hackmd.io/_uploads/Bk6BUqiGR.png)

- (情況:對單個pkt，做全長的漢明碼生成)嘗試每次write data都翻轉1bit  ->失敗
![image](https://hackmd.io/_uploads/HJLDLYsfA.png)



>[!Warning]
>問題 為何嘗試每次write data都翻轉1bit會發生失敗的情形
>若考慮最小單位為8bit來做漢明碼呢
- (情況:對單個pkt，分別做8bit最小單位的漢明碼生成)
- 暫時失敗
![image](https://hackmd.io/_uploads/SkPoWyhz0.png)
