2021/01/15

U-boot entry point

使用 Qualcomm 的 ipq 平台開發產品, 一個不小心遇到了 uboot 完全不會動的狀況, 連一開始顯示版本資訊的訊息都沒出現, 這下糟糕了, 根本就不能用 printf 去看他停在哪裡!

只好從uboot的進入點開始看了. 由於平台使用的是 armv7 的架構, 所以從 (uboot)/arch/arm/cpu/armv7/start.S 開始看. 雖然是組合語言, 幸好只是要看 b, bl, blx, bx 這一系列的分支指令, 而且很幸運的是整個 start.S 只用到 bl 這個.

ARM branch operation

那就一個一個的來找看看 c 的實作:

save_boot_params

void save_boot_params_default(u32 r0, u32 r1, u32 r2, u32 r3) { } void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3) __attribute__((weak, alias("save_boot_params_default")));

空空的.


cpu_init_cp15

cpu_init_crit

這兩個都在 start.S 後面用組合實作


board_init_f

實作在 uboot/arch/arm/lib/board.c

init_fnc_t *init_sequence[] = {
	arch_cpu_init,		/* basic arch cpu dependent setup */

#if defined(CONFIG_BOARD_EARLY_INIT_F)
	board_early_init_f,
#endif
#ifdef CONFIG_OF_CONTROL
	fdtdec_check_fdt,
#endif
	timer_init,		/* initialize timer */
#ifdef CONFIG_FSL_ESDHC
	get_clocks,
#endif
	env_init,		/* initialize environment */
	init_baudrate,		/* initialze baudrate settings */
	serial_init,		/* serial communications setup */
	console_init_f,		/* stage 1 init of console */
	display_banner,		/* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
	print_cpuinfo,		/* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
	checkboard,		/* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
	init_func_i2c,
#endif
	dram_init,		/* configure available RAM banks */
	NULL,
};

void board_init_f(ulong bootflag)
{
        ... ...
	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
		if ((*init_fnc_ptr)() != 0) {
			hang ();
		}
	}
	... ...
}

這裡會逐一呼叫 *init_sequence[] 裡面定義的 function, 如果有哪個 function 傳回不是 0, 就吊起.

追了這些 function, 終於發現是新增 machid, 還沒把相關的 board_parameter 補齊導致的, 趕緊把內容補上, 就可以結案了.


2020/12/30

用 shell 指令觸發 linux kernel panic

linux kernel sysrq

echo 1 >  /proc/sys/kernel/sysrq

echo c > /proc/sysrq-trigger

例如要測試 external watchdog, 就要 not allow reboot/power off (128), 然後再觸發 kernel panic (c) 停止 WDT toggle.

echo 382 > /proc/sys/kernel/sysrq

echo c > /proc/sysrq-trigger 

  

2020/11/26

Use a specific version of ocaml in debian/ubuntu

I used the latest Debian distribution. When I compiling coccinelle, I encountered the error message unbound module Parmap. The reason is that ocaml version that is too new. It is incompatible and must be returned to version 4.02.3. So I use opam to manage the ocaml version used.


1. Inteall opam (root).

sudo apt-get install opam


2.  Initial opam (none root).

opam init --compiler 4.02.3


3. Add ocaml path to environment $PATH.

eval $(opam config env)


4. Check the version you got.

ocamlc -v


5. Install modules.

opam install parmap

opam install camlp4

  

6. When need to switch installed versions.

opam switch 4.05.0

eval $(opam config env)


7. When need to compile and switch other versions.

opam switch create 4.03.0

eval $(opam config env)



2020/11/20

讓 uboot envtools 禁止變更重要的變數

uboot envtools 提供很方便的途徑來存取 uboot 環境變數,但是方便的工具卻也帶來很大的風險,如果被惡意使用,變更了重要的 uboot 環境變數,例如 bootcmd,可能會導致無法預期的後果,所以真的有必要禁止使用 uboot envtools 改變這些重要的變數內容。

以下內容是以 uboot 2014.10 為基礎, 更新的版本應該也不會有太大的差異.

檔案 uboot/tools/env/fw_env.c

最主要的寫入 function 是:
    int fw_env_write(char *name, char *value)

要做的事情很單純:
  1. 增加一個檢查要寫入的環境變數名稱的 function, 可以被更改的傳回 0, 不能被更改的傳回非0.
  2. 在 fw_env_wrire 裡面呼叫 1. 加入的 function 進行檢查.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
int fw_env_check_unmodifiable_name(char *name) {
	int i, cnt;
	char *unmodi[] = {
		"bootcmd",
		"baudrate",
		"ethaddr",
		"country",
		"regdomain",
		};
        cnt = sizeof(unmodi)/sizeof(unmodi[0]);
	for (i=0; i<cnt; i++) {
		if (0 == strcmp(unmodi[i], name)) {
			fprintf(stderr, "## Warning: "
						"environment \"%s\" can't be modified.\n", name);
			errno = EINVAL;
			return -EINVAL;
		}
	}
	return 0;
}

/*
 * Set/Clear a single variable in the environment.
 * This is called in sequence to update the environment
 * in RAM without updating the copy in flash after each set
 */
int fw_env_write(char *name, char *value)
{
	int len;
	char *env, *nxt;
	char *oldval = NULL;
	int deleting, creating, overwriting;

	if (fw_env_check_unmodifiable_name(name)) {
		return 0;
	}


2020/11/04

使用 OpenWRT 建構捕捉無線網路封包的設備

OpenWRT wifi basic

OpenWRT 有提供無線網路介面的monitor模式(我猜還是要驅動程式有支援才有用)。

首先修改 /etc/config/wireless 建立一個做為 monitor 的 interface

config wifi-iface wifi_mon0

option device 'wifi0'

option mode 'monitor'


 重新啟用 WiFi 之後,就可以看到這個 interface. 我沒有開啟其他 interface 所以介面名稱被分配為 ath0.


monitor 介面建立完成後, 就可以使用 tcpdump 來捕捉封包, 並寫成 pcap 檔案.

tcpdump -i ath0 -w /tmp/ath0.pcap


用 tcpdump 捕捉特定 MAC 的 802.11 radio 封包

tcpdump -ne -y ieee802_11_radio -i ath0 ether host 00:11:22:33:44:55


最後再設法提取到 wireshark 解讀.