Linux
boot flow
sudo dd if=/dev/sda bs=512 count=1 2>/dev/null | strings | grep -Eoi ‘grub|lilo|acronis|reboot’
- Linux system須具備:
1. Bootloader
2. Linux Kernel
3. Root Filesystem: busybox, user用的程式, ex: bash, ls… - bootstrap flow:
BIOS -> MBR -> boot loader -> kernel -> init process -> login - Different type kernel:
Linux 核心設計: 作業系統術語及概念
Basic command
sudo VBoxClient --clipboard
10.2.2 變數的取用與設定:echo, 變數設定規則, unset
讀:
echo ${myname}
set:
myname=VBird
unset:
unset myname
dmesg: display開機訊息
變更為/usr/include目錄
cd /usr/include
// Compile or assemble the source files, but do not link, 產出.o
gcc -c test.c
ex: project, 執行檔由a,b,c 3個檔案組成// 個別編譯
gcc -c a.c
gcc -c b.c
gcc -c c.c//產出output executable/object/assemble file
//沒指定output name, default a.out
gcc -o test.c // 指定output name: test, 產出 test.a
gcc -o test test.c執行
./test//印出warning msg: -Wall
ex: var沒有initialize
gcc -Wall -o test test.c //只編譯不連結//連結 產生output: app
gcc -o app a.o b.o c.o
note: 只改b檔案, b重新編譯 -> 再連結即可//最佳化 -O
數字越高: 最佳化程度越高, 通常用-O2
gcc -O2 -o test test.c
The Linux Kernel Module Programming Guide
module指令:
.ko: kernel object
// module information
modinfo hello-1.ko// 載入多少 有hello字串的module
sudo lsmod | grep hello//install module
sudo insmod hello-1.ko// 傳入command line paramater:mystring="bebop" myintarray=-1
sudo insmod hello-5.ko mystring="bebop" myintarray=-1// remove module
sudo rmmod hello_1// 看install/remove module的資訊
sudo dmesg -t | tail -7
Makefile
ex: The Linux Kernel module programing
obj-m += hello-1.o
PWD := $(CURDIR)
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean//will build hello-1.o from hello-1.c, after linking get hello-1.ko
obj-m += hello-1.o
obj-m += test.o // test.o 不會編進kernel, 編成test.koobj-y += test.o // test.o 會編進kernel
ref:
https://mropengate.blogspot.com/2018/01/makefile.html
4.7 Building modules for a precompiled kernel 不懂
- syscall tracer
strace ./hello
5. Device Drivers
分為 block/character device:
- block device:
1. have a buffer for requests, can choose best order
2. can only accept input and return output in blocks (傳輸用block) - character device:
allowed to use as many or as few bytes as they like (傳輸用任意bytes)
第一個字b: block device
第一個字c: character device
ls -l
6.3 Registering A Device
- 要知道major number
dynamic allocate major number
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);
2. initialize the data structure cdev
void cdev_init(struct cdev *cdev, const struct file_operations *fops);
3. add the char device to the system
int cdev_add(struct cdev *p, dev_t dev, unsigned count);
6.4 Unregistering A Device
module沒人用(count=0), 才可以remove
increase, decrease and display this counter
try_module_get(THIS_MODULE)
: Increment the reference count of current module.module_put(THIS_MODULE)
: Decrement the reference count of current module.module_refcount(THIS_MODULE)
: Return the value of reference count of current module.
7 The /proc File System
the /proc file system allow easy access to information about processes
可以從user space read/write kernel space
8 sysfs: Interacting with your module
sysfs allows you to interact with the running kernel from userspace by reading or setting variables inside of modules.
- read:
cat /sys/kernel/mymodule/myvariable
- set:
echo "32" > /sys/kernel/mymodule/myvariable
9 Talking To Device Files
Device files are supposed to represent physical devices.
ioctl用來 read/write device
10 System Calls
system call 用來跟kernel溝通
system call帶number -> look at sys_call_table, call kernel function
system call stealing的例子,
11 Blocking Processes and threads
11.1 Sleep 例子做不出來
題目
delay vs sleep
delay: busy wait
sleep: non-busy wait
- Atomic context: 不能被打斷, 用delay
- non-atomic context: 依delay時間決定
https://blog.csdn.net/cherylchenyajun/article/details/110088333
spin_lock, spin_lock_irq, spin_lock_irqsave
- spin_lock:
preempt_disable();
interrupt搶占會出問題
ex:
// in normal run level
extern spinlock_t lock;
// …
spin_lock(&lock);
// do something
// interrupted by IRQ …// in IRQ
extern spinlock_t lock;
spin_lock(&lock); // dead lock
- spin_lock_irq:
local_irq_disable();
preempt_disable(); - spin_unlock_irq: enable IRQ
要確認獲得鎖之前IRQ是enable
- spin_lock_irqsave: disable preempt/interrupt, save irq flag
local_irq_save(flags);
preempt_disable(); - spin_unlock_irqrestore: restore IRQ status
每次關閉中斷前紀錄當前中斷的狀態,然後恢復它而不是直接把中斷開啟。
Top half: interrupt發生馬上要處理的事, 寫在ISR
Bottom half:
1.可以晚點做的事 -> schedule
2. interrupt enable
3種schdule:SoftIRQ, Tasklet, Workqueue
SoftIRQ vs Tasklet vs Workqueue
- softIRQ:
1. only static allocate
2. can not sleep
3. reentrant: same/different type can run concurrently on several CPUs
4. run interrupt context
5. can be interrupt by HW interrupt - Tasklet:
1. static + dynamic allocate
2. non-reentrant:
2.1 same type cannot run concurrently on several CPUs
2.2 different types can run concurrently on several CPUs
3. can not sleep
4. run interrupt context
- Workqueue:
1. can schedule
2. can sleep
3. run process context - Threaded IRQs:
目的: reduce the time spent with interrupts disabled
會create thread
https://ithelp.ithome.com.tw/articles/10252646
查看process memory
cat /proc/[pid]/status
check process CPU/memory usage:
ps -aux // find the pid of process
ps -p <pid> -o %cpu,%mem,cmd
perf分析CPU usage
用tick中斷採樣 -> 找出哪段程式最花時間
# perf record -a -e cycles -o cycle.perf -g sleep 10 // sampling
# perf report -i cycle.perf | more // report
Debug segmentation fault
用GDB + backtrace
Debug kernel panic
kernel panic: low-level error, OS can not fix it
設定kdump -> crash發生產生crash.log -> dump crash.log(vmlinux
)
user space communication with kernel space
- proc file
install proc file module -> create file in /proc/proc_name
讀:
cat /proc/proc_name
寫:
echo “hello123” > /proc/proc_name
- system call
ex: fork(), read(), write()… - ioctl:
install character driver -> user process use ioctl_fun
input/output/redirection
3種資料流:
- 標準輸入(standard input,代碼為
0
):程式執行所需要的輸入資料
cat 鍵盤輸入< 從檔案讀取資料
cat < input.txt
- 標準輸出(standard output,代碼為
1
):程式正常執行所產生的輸出資料。運算子: >, >>
ls > output.txt 存到output.txt, 原本內容清空
ls >> output.txt 存到output.txt, 原本內容保留, 加在原本內容之後
- 標準錯誤輸出(standard error output,代碼為
2
):程式出錯時通知使用者用的訊息,或是呈現程式狀態用的訊息。
使用 > 運算子,把標準錯誤輸出(2)導至指定的檔案:
ls non_exist > output.txt 2> error.txt
正常的輸出導入 output.txt
標準錯誤輸出導入 error.txtls non_exist > output.txt 2>&1
2>&1 就是把標準錯誤輸出(2)導入標準輸出(1),再靠著 > 把所有的資料全部導入 output.txt
- Redirection:
把兩個程式的輸入與輸出串接起來,就可以使用管線pipe, 運算子: |
ls | nl 每個檔案名加上行號
ls | grep keyword | nl | head -n 5
ls 的輸出中,以 grep 篩選出有 keyword 的檔名,交給 nl 加上行號,最後交給 head 輸出前 5 行資料。
ref:
程式開發教學
基本指令/linux寫code/安裝VSCode, NodeJS, Python
- file: 檢查檔案
GDB教學
sudo apt install gdb // install GDB
- 指令
增加 break point: b or break
刪除 break point: d or delete
list all break point: i b
跑程式: run
印出: p
繼續跑: c
step: 只跑一行程式 // 不用一直加break point - back trace: bt
frame + 數字: 跳到第幾號frame
up: 回到上個frame
down: 到下個frame
gcc simple.c -g // 加-g, 才可以用GDB
gcc -g gdb_example.c -o gdb_example //
gdb ./a.out
l // 1次show 10行code
b simple.c:7 // add break in line 7 of simple.c
b simple.c:9
i b // list all break point
run // execute -> stop at line 7
p x // print x
c // continue -> stop at line 9
p x // print x
bt // back trace
RTOS
- Linux embedded system vs RTOS
HAL(hardware abstraction layer)
讓APP 不用知道HW細節就可以access, 提高code的移植性
https://kezeodsnx.pixnet.net/blog/post/24676754
- BSP (Board Support Package):
主要功能:
1. 硬體的初始化,主要是針對CPU做初始化,為上層軟體提供硬體支援。
2. 為作業系統提供設備驅動程式與系統中斷服務程式。
3. 定製作業系統功能,提供軟體一個多工的操作環境。
4. 初始化作業系統,讓作業系統能夠正常運行。
開發流程: