---
# System prepended metadata

title: Yocto Project (4)：OpenBMC Hello World using devtool
tags: [Yocto Project]

---

##    Yocto Project (4)：OpenBMC Hello World using devtool

Purpose: Walk through compiling and running an OpenBMC application in QEMU.


##    Clone and Build a Repo

當我們要對 image 進行任何操作時，流程都是：
```
cd ~/openbmc -> . setup romulus build/romulus #進入 bitbake 的環境 ->
bitbake ... #編譯 -> devtool ... #修改 recipe 或原始碼
```

首先回到 openbmc 目錄
```bash
$ cd ~/openbmc
```

進入 bitbake 環境
```bash
$ . setup romulus build/romulus
```

使用 devtool 來抽出原始碼
```bash
$ devtool modify phosphor-state-manager
```
:::info
devtool 是 yocto 提供的工具，用來抽取出目標的原始碼進行修改
:::

在原始檔中加入 cout
```bash
$ nano workspace/sources/phosphor-state-manager/bmc_state_manager_main.cpp
```

在最上面加入
```c    
#include <iostream>
```

並在 bus.request_name(BMCState::interface) 下面加入 
```c    
std::cout<<"Hello World" <<std::end1
```

完成之後按下 ^x 存檔離開

重新 bitbake 一次，它就會編譯到有更改的地方
```bash
$ bitbake obmc-phosphor-image
```

之後就是重複 [Yocto Project (3)](https://hackmd.io/@zhonwei/BksIxb9hWl) QEMU 啟動的流程

複製生成好的 image 到跟 qemu-system-arm 同一層（在 /build/romulus 底下）
```bash
$ cp ~/openbmc/build/romulus/tmp/deploy/images/romulus/obmc-phosphor-image-romulus.static.mtd ./
```

Romulus image 開始進行 QEMU
```bash
$ ./qemu-system-arm -m 256 -machine romulus-bmc -nographic \
 -drive file=./obmc-phosphor-image-romulus.static.mtd,format=raw,if=mtd \
 -net nic \
 -net user,hostfwd=:127.0.0.1:2222-:22,hostfwd=:127.0.0.1:2443-:443,hostfwd=tcp:127.0.0.1:2080-:80,hostfwd=tcp:127.0.0.1:2200-:2200,hostfwd=udp:127.0.0.1:2623-:623,hostfwd=udp:127.0.0.1:2664-:664,hostname=qemu
```

等待 QEMU 模擬的 BMC 開機，登入使用預設的使用者 root 和密碼 0penBmc (0 是數字零)
```bash
romulus login: root
Password: 0penBmc
```
成功之後就會看到
```bash
root@romulus:~#
```
接下來因為是 QEMU，所以要初始化一些服務（詳情參考 [Yocto Project (3)](https://hackmd.io/@zhonwei/BksIxb9hWl)）

```bash
$ echo '{}' > /tmp/led-empty.json

$ mkdir -p /etc/systemd/system/xyz.openbmc_project.LED.GroupManager.service.d/

$ cat > /etc/systemd/system/xyz.openbmc_project.LED.GroupManager.service.d/override.conf << 'EOF'
[Service]
ExecStart=
ExecStart=/usr/libexec/phosphor-led-manager/phosphor-ledmanager -c /tmp/led-empty.json
EOF

$ systemctl daemon-reload
$ systemctl restart xyz.openbmc_project.LED.GroupManager.service
```

檢查 OpenBMC 的服務狀態
```bash
root@romulus:~# obmcutil state
```

QEMU 成功登入啟動之後，確認 "Hello World" 有成功加入到新的 image 中
```bash
root@romulus:~# journalctl | grep "Hello World"
Apr 21 06:43:15 romulus phosphor-bmc-state-manager[330]: Hello World
```

這樣我們就成功更改設定，並重新 build 了一個有包含我們更改設定的 image。



---

## Loading an Application Directly into a Running QEMU

接下來這段我們也是要做跟前面一樣的事情，更改設定，並讓它在新的 image 上可以實行，只不過跟前面不同的是：前面的方法是 build 一個新的 image；現在這個方法是編譯單一個 package，然後直接利用網路塞進運行中的 QEMU。

在虛擬機上更改跟之前相同的檔案，改成 "Hello World Again"
```bash
$ nano workspace/sources/phosphor-state-manager/bmc_state_manager_main.cpp
```

只 Bitbake 這個 phosphor-state-manager 的儲存庫（在 bitbake 中，可以只 build 你想更改的儲存庫）
```bash
$ bitbake phosphor-state-manager
```

新的執行檔（binary）會在 build 目錄底下：`~/openbmc/build/romulus/workspace/sources/phosphor-state-manager`

:::info
在 BitBake 的建置流程中，流程通常是：

Source Code (原始碼)：人類看得懂的 C++/C 程式碼。

Compile & Link (編譯與連結)：透過編譯器處理。

Binary (執行檔)：編譯後的結果，也就是你提到的 phosphor-bmc-state-manager。這個檔案是給機器看的二進位格式（通常是 ELF 格式）。
:::

接下來使用 overlay 的方式把這個更改的設定放入 QEMU 裡頭，在 QEMU 中輸入：
```bash
root@romulus:~# mkdir -p /tmp/persist/usr
root@romulus:~# mkdir -p /tmp/persist/work/usr
root@romulus:~# mount -t overlay -o lowerdir=/usr,upperdir=/tmp/persist/usr,workdir=/tmp/persist/work/usr overlay /usr
```
:::info
Overlay 檔案系統的概念是：

/usr 原本的內容（lowerdir）保持不變
修改或新增的檔案放在 /tmp/persist/usr（upperdir）
掛載後看起來像是同一個 /usr，但實際上原始檔案完全沒有被動到

讀取時：先看 upperdir 有沒有，有的話用 upperdir 的版本，沒有的話才去 lowerdir 找
寫入時：所有修改都只寫進 upperdir，lowerdir 永遠不會被碰到
:::

在虛擬機上，使用 scp 把新的 phosphor-bmc-state-manager 複製到 /usr/bin/，但實際上是寫進了 `/tmp/persist/usr/bin/phosphor-bmc-state-manager`
```bash
$ ~/openbmc/build/romulus/workspace/sources/phosphor-state-manager$ scp -P 2222 ./oe-workdir/package/usr/bin/phosphor-bmc-state-manager root@127.0.0.1:/usr/bin/

The authenticity of host '[127.0.0.1]:2222 ([127.0.0.1]:2222)' can't be established.
ED25519 key fingerprint is SHA256:zsT1InNSk710ixoCanTy9AOd95JSxCiOC8kq9V1LmUw.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[127.0.0.1]:2222' (ED25519) to the list of known hosts.
root@127.0.0.1's password: 
phosphor-bmc-state-manager                                                   100%  126KB   4.2MB/s   00:00  
```

:::info
scp 是 Secure Copy 的縮寫，它是 Linux 系統中透過 SSH 連線在不同電腦（或虛擬機）之間「安全地傳輸檔案」的指令。

-P 2222：指定連接埠（Port）。因為 QEMU 模擬器通常會把虛擬機的 22 埠對應到本機的 2222 埠。

./path/to/...：你電腦上剛編譯好的那個 binary (執行檔) 位置。

root@localhost：目的地。表示以 root 帳號登入你本機上的虛擬機。

:/usr/bin/：檔案要放進去虛擬機裡的哪個路徑。
:::

現在我們就成功把更改的設定放入到 QEMU 中了



---

##    Run the Application in QEMU

驗證剛剛更改的設定可不可以在 QEMU 中生效

停止 BMC state manager service
```bash
root@romulus:~# systemctl stop xyz.openbmc_project.State.BMC.service
```

跑剛剛更改的設定
```bash
root@romulus:~# phosphor-bmc-state-manager
Hello World again
```

但一般情況都是使用 systemd service 來啟用設定
```bash
root@romulus:~# systemctl restart xyz.openbmc_project.State.BMC.service
```

使用 systemd service 來啟用設定時，不會顯示出來，但可以在日記中看到
```bash
root@romulus:~# journalctl | tail
Apr 21 08:48:26 romulus phosphor-bmc-state-manager[734]: Hello World again
```



---

##    總結

更改設定和增加應用有兩種方法
* 一個是改完重新 build image
* 一個是只編譯單一的 package，然後直接推進跑著的 QEMU，可節省時間

流程
```
修改程式碼 → bitbake 單一 package → overlay 保護 → scp 推進 QEMU → 驗證
```

**重點一：只 build 單一 package**
```bash
$ bitbake phosphor-state-manager
```
不用跑 bitbake obmc-phosphor-image，只編譯你改動的那個 repo，速度快很多。

**重點二：Overlay 檔案系統**

為什麼不直接丟 `/usr/local/bin/`：PATH 會優先找 `/usr/local/bin/` 沒錯，但 systemd service 檔寫死絕對路徑，不吃 PATH

Overlay 的好處：

* 原始檔案完全不動
* 重開機自動回復原始狀態
* 不會把系統搞壞

```bash
root@romulus:~# mkdir -p /tmp/persist/usr
root@romulus:~# mkdir -p /tmp/persist/work/usr
root@romulus:~# mount -t overlay -o lowerdir=/usr,upperdir=/tmp/persist/usr,workdir=/tmp/persist/work/usr overlay /usr
```

**重點三：scp 推進 QEMU**

從 Ubuntu 執行，注意要在正確的目錄下：
```bash
# 在 phosphor-state-manager 目錄下執行
$ cp -P 2222 ./oe-workdir/package/usr/bin/phosphor-bmc-state-manager root@127.0.0.1:/usr/bin/
```

**重點四：兩種驗證方式**

直接執行（手動測試）：
```bash
root@romulus:~# systemctl stop xyz.openbmc_project.State.BMC.service
root@romulus:~# phosphor-bmc-state-manager  
# 會直接看到 Hello World Again
```
透過 systemd（正式方式）：
```bash
root@romulus:~# systemctl restart xyz.openbmc_project.State.BMC.service
root@romulus:~# journalctl | tail  
# 從 journal 確認輸出
```
systemd 啟動的服務輸出不會顯示在終端機，只會記錄在 journal，這是 OpenBMC 管理應用程式的方式。