2025年8月6日 星期三

Linux kernel minor upgrade

 今天嘗試把 kernel v4.19.98 作微升級,要升級到 v4.19.325,因為我們原本的 kernel 並不是原生最乾淨的 Linux kernel v4.19.98(是拿MTK平台的 SDK),先講我打上了這兩個版本中間的 patch,但最終編譯,卻有一堆error,解不完

 但我認為,作這件事情,中間的過程,是值得作個記錄的,因此寫了這篇文章,來記錄中間所做的步驟。

1. 下載 Linux 的 branch,使用指令如下:
git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git

2. 每個版本都有打上tag,因此我們可以先 checkout 到 v4.19.325
git checkout v4.19.325

3. git log 確認一下 v4.19.325 與 v4.19.98 分別的 commit hash 號碼是多少










4. 使用指令,把 98 ~ 325 這中間的 commit 都作成 patch 檔,指令如下:
git format-patch d183c8e2647a7d45202c14a33631f6c09020f8ac..a67e7cdde7cc7984ae24c3c81a70dc1aa34424b1 -o patch/

5. 可以看到,目前目錄底下,會產出資料夾 patch/ ,裡面有 19xxx個patch 檔,依序都做好了編號

6. 接著我們準備要來打 patch,先說明一下,我目前的目錄環境是這樣,
apps/src/kernel/linux/4.19/,我目前專案的 repository 是在 apps底下,也就是我可以在 apps底下執行 git log,可以看到以往的 commit 資訊,而目前是要把 linux patch 打到   apps/src/kernel/linux/4.19/ 底下

7. 因為第6.的關係,我們把 patch/ 移動到 apps底下,我們打patch 的指令會如下:
cd apps/
git am --directory=src/kernel/linux/v4.19 patch/* -3  

(加上 -3(或 --3way)後,如果直接套用失敗,Git 會嘗試用三方合併的方式來解決衝突,這樣有時候可以自動解決一些簡單的衝突)

8. 打patch 的途中,會遇到許多的 conflict,你會需要開啟檔案,去解衝突,但我發現 19xxx筆patch,要解的 conflict 實在太多了,後來遇到 conflict 直接使用以下command,意思是直接幫我把衝突的舊檔案的部分刪除,把新的patch 新增的內容,改到檔案裡面: 
git checkout --theirs $file (file帶入中途的檔案路徑 與 名稱)

9. 途中會遇到一些,甚麼都沒改的 patch,會需要手動執行 git am --skip 來繼續,另外解完 conflict 的檔案,要手動執行 git am --continue 來讓 git am 繼續跑

10. 另外有遇到一個,git am 打patch,我發現有一個限制,就是打到 9999個 patch的時候,你再輸入 git am --continue 會沒辦法繼續,如下圖,這時候你必須要先 git push,把先前打的patch 都git push,然後再繼續從第 10000筆繼續打,我的作法是




   







   a. 在作第4部的時候,也順便把檔案列表資訊,輸出到一個檔案:
git format-patch d183c8e2647a7d45202c14a33631f6c09020f8ac..a67e7cdde7cc7984ae24c3c81a70dc1aa34424b1 -o patch/ > patch_list.txt
   b. 想辦法使用 note 或是 Notepad++ 把這些列表改成
rm 0001-xxxx
rm 0002-xxxx
..
rm 9999-xxxx
   c. 切換到 patch/ 資料夾,把 0001~9999 的patch 檔案都刪除
   d. 在接著使用git am 的命令繼續打剩餘的 patch:
git am --directory=src/kernel/linux/v4.19 patch/* -3  


結論: 
   1. 我在這次的過程中,寫了以下兩隻script,當發生conflict,就使用git checkout --theirs $file 去解conflict,因此可以一直遞迴去處理patch,但遇到 git am --continue 無法繼續的空內容,目前就是手動去下 git am --skip
   2. 其實比較好的做法,應該要是以下步驟
        a. 先 git checkout 到 linux pure v4.19.98
        b. 把vendor最一開始給的 kernel 覆蓋到
 linux pure v4.19.98
        c. git diff 看一下改了那些檔案
        d. 直接把 
linux pure v4.19.98,checkout 到 v4.19.325,然後試著把 前一步驟,git diff 的改回去,但如果真的差異太大,就是一個很大的工程了....

以下分享我的兩個 shell script: (主要就是執行 ./for_loop.sh)

主程式:  for_loop.sh

#!/bin/sh
for i in {1..20000}
do
    ./fail_process.sh
    if [ $? -eq 2 ]; then
        echo "fail_process.sh failed, stopping loop."
        break
    fi
done

副程式:  fail_process.sh

#!/bin/sh

# Get the list of files marked as "both modified" from gg (git status)
files0=$(git status | grep "both modified:" | awk -F: '{print $2}' | xargs)

# For each file, run git add
for file in $files0; do
    echo "Processing $file ..."
    git checkout --theirs $file
    git add $file
done


# Get the list of files marked as "deleted by them:" from gg (git status)
files1=$(git status | grep "deleted by them:" | awk -F: '{print $2}' | xargs)

# For each file, run git add
for file in $files1; do
    echo "Processing $file ..."
    git add $file
done

# Get the list of files marked as "deleted by us:" from gg (git status)
files2=$(git status | grep "deleted by us:" | awk -F: '{print $2}' | xargs)

# For each file, run git add
for file in $files2; do
    echo "Processing $file ..."
    git add $file
done


# Get the list of files marked as "both added" from gg (git status)
files3=$(git status | grep "both added:" | awk -F: '{print $2}' | xargs)

# For each file, run git add
for file in $files3; do
    echo "Processing $file ..."
    git checkout --theirs $file
    git add $file
done

if [ -z "$files0" ] && [ -z "$files1" ] && [ -z "$files2" ] && [ -z "$files3" ]; then
        exit 2
fi

git status
git am --continue



2025年8月3日 星期日

C 語言裡面 Static 宣告 function或變數,的用途與意義

 static 在 C/C++ 有幾個不同的用途,根據用在不同地方意義不同:

(A) 用在函式或變數前面(檔案層級)
作用範圍只限於本檔案,其他檔案無法看到或使用這個函式/變數。
常用來避免命名衝突,或是只在本檔案內部使用的工具函式。

(B) 用在區域變數前面(函式內部)
變數只會初始化一次,之後的呼叫會保留上次的值(類似全域變數,但作用範圍只在這個函式內)。

2025年6月25日 星期三

core dump 以及透過 gdb 來debug,問題點出在哪

 今天我們拿 systemd-journald 的 core dump 來當範例
 解壓縮 core_systemd-journald.tar 可以看到資料夾內有以下檔案


我們這篇,主要是去拿 exe.lz4 與 core.lz4 來放到 gdb 裡面,來做debug

所以我們先把者兩個 lz4 檔案,放到linux 系統中使用以下 command 把他解開,得到兩個檔案,分別是 core 與 exe,
core 是 core dump 紀錄的錯誤資訊,exe 則是此執行檔(systemd-journald)
=>
lz4 -d core.lz4 core
lz4 -d exe.lz4 exe

接著我們把 core 與 exe 丟到有gdb 的 device上,如果編譯的時候,也有編譯出 symbol 的 library 或是 執行檔,也可以準備一下,等等 gdb 會使用到 (symbol 就是沒有被 strip 的檔案)
symbol資料夾如下:


接著到平台上,執行 gdb,command 如下:
=>
gdb exe core


可以看到Core was generated by `/lib/systemd/systemd-journald'.
Program terminated with signal SIGABRT, Aborted.
=> systemd-journald 因為 SIGABRT造成的 crash

接著可以用 bt full 印出完整的資訊

目前只能知道,在 libc.so.6 這個 library的 function,writev() 出了問題,下面指出
No symbol table info available
我們就去找 symbol folder,試試看用 systemd-journald 的 binary跑gdb 試試看


gdb systemd-journald core
會看到多了一些資訊,gdb似乎有載入一些資訊


此時,在重新執行剛剛的指令,可以看到更完整的資訊
=>
gdb exe core
  








2025年6月20日 星期五

指令,把read-only 的filesystem,remount 成 read/write

使用mount指令,先看一下,目前 / 掛載為 read-only,ext4 的 filesystem
root@:# mount
/dev/mmcblk0p16 on / type ext4 (ro,relatime,norecovery)


把 root folder 重新掛載成可 read/write
 mount -o remount,rw /

再用mount看一次
root@:~# mount
/dev/mmcblk0p16 on / type ext4 (rw,relatime,norecovery)

2025年3月7日 星期五

馬桶水箱的水一 直滿出來,解決方法

 家裡馬桶水箱的水,一直太滿,從水箱中的一根管子溢出
 因為馬桶水箱,是靠浮球浮起來,來止水灌進水箱的

這裡提供兩個簡易的解決方法,可以先試試看能不能解決

1. 檢查浮球是否進水,導致浮不起來,
=> 有的浮球是可以轉開來的,可以看看裡面是否有進水
     把水甩掉,或是弄掉,再試試

2. 把連接浮球的鐵桿,弄彎一點,看看能不能止水

2025年1月7日 星期二

Linux Tool, taskset 可以用來限制程式,只去使用特定 CPU

 Linux 當中有個Tool,叫做 taskset,可以限制某個Daemon只跑在規定的CPU編號之下,這邊會先簡單介紹 taskset使用方式,不免俗的,最後會附上一個實際操作

首先簡單寫一個 while迴圈,打印test的字樣,但不顯示在螢幕上,這支來當我們的Daemon,並且使用以下command,讓他在背景執行
=> sh loop_test.sh &
======= loop_test.sh 小程式 =========
#!/bin/sh
while [ 1 ]
do
   echo "test" > /dev/null
done



======= 使用方式 =======

首先我們可以用以下的指令,來得知目前設備的 CPU核心數目
=> cat /proc/cpuinfo

查詢目前的 Daemon,所配置的 CPU編號,這有兩種查詢方式
1. 直接列出,此Daemon使用的CPU編號,這邊Daemon的 PID=5622 (ps -aux | grep loop_test.sh)
=>
root:~# taskset -cp 5622
pid 5622's current affinity list: 0,1

2. 以mask方式列出,此Daemon使用的CPU編號,這邊Daemon的 PID=5622
=>
root:~# taskset -p 5622
pid 5622's current affinity mask: 3

這邊的3,為Hex,需要把他換成二進制來解讀,所以為 0x11,表示CPU0,CPU1目前會讓此Daemon使用(如果CPU為8 core,得到的數值為FF(hex),則表示 CPU0~7都會分配)


======= 使用方式 & 實驗 =======
設置目前的 Daemon,只分配CPU1 來做

=>
root:~# taskset -cp 1 5622
pid 5622's current affinity list: 0,1
pid 5622's new affinity list: 1

"top -d 1" 觀察一下cpu 與 process 狀態

=> 可以看到 CPU1 的 idle為0%,loop_test.sh 把整個CPU1用盡了,而CPU0是完全閒置的











這時候,我們再使用指令把 loop_test.sh 平均分配給 CPU0 & CPU1
=>
root@auto2735evb-ivt-vp2:~# taskset -cp 0,1 5622
pid 5622's current affinity list: 1
pid 5622's new affinity list: 0,1

"top -d 1" 觀察一下cpu 與 process 狀態
=> 可以看到 CPU0與CPU1,都有分配給 loop_test.sh使用



2024年12月6日 星期五

在adb shell 執行一個背景程式,如何讓 adb shell中斷後,此背景程式不會被中斷

 今天遇到有客人問一個問題
 他想要用 tcpdump 抓封包,指令如下:
tcpdump -i any -C 100 -W 10 -U -w /tmp/tcpdump.cap &

但因為,我們的device,在拔除usb之後,device可以進入 suspend
他想要在 wakeup的時候,抓到是甚麼樣的封包,

另外他想要透過 adb shell 去執行這個指令,所以當下完上面指令,adb shell 斷線之後
tcpdump 也終止了

查詢與嘗試了一下,可以使用以下指令解決
nohup tcpdump -i any -C 100 -W 10 -U -w /tmp/tcpdump.cap > /tmp/tcpdump.log 2>&1 &

只要確保 /tmp 目錄是可寫的,這樣 tcpdump 的輸出和錯誤信息將被寫入到 /tmp/tcpdump.log 文件中