embedded
linux
overview
VFS
Author: CrazyMonkey
email: kccddb@gmail.com
Date: 20230915
Copyright: CC BY-NC-SA
因為有同學問了 system programming 與 embedded Linux system 的問題, 因此增加一些內容, 希望同學了解運作原理
A. Linux System Programming 優良書本:
因有同學需要 , 特地加上一本很好的巨著, 相信很有幫助!
(1). 對於想了解 Linux System Call 想更清楚的同學, 下面有上下冊兩本 (有範例, 有中文版)可以當程式設計者深入的參考閱讀
The Linux Programming Interface 國際中文版 (上冊, 下冊) 全書約 1500 頁
The Linux Programming Interface: A Linux and UNIX System Programming Handbook
作者: Michael Kerrisk
譯者: 廖明沂, 楊竹星
(2) 比較簡短(很好的書)
Linux System Programming, R, Love
對 IoT 有興趣可以考慮 ESP8266 (有 Wi-Fi, 可用Arduino Ide 開發 )
B. 增加 SPI 觀念與連結(也記得 OOP)
c 物件導向 可以嗎? 還是一定要用 C++ 或 JAVA?
c language: function pointer, callback and event-driven
這網站有很多軟體的 cross referece, linux kernel source, busybox, QEMU, …
向 全世界的軟體設計者學習如何寫軟體
https://elixir.bootlin.com/linux/latest/source
Futher Reading:
Udev (userspace /dev) is a Linux sub-system for dynamic device detection and management, since kernel 2.6.x.
Udev: Introduction to Device Management In Modern Linux System
[CC BY-SA 3.0], via Wikimedia Commons
Linux 與 C是未來業界非常重要的知識, C 更是科技業單晶片與 Embedded System 的程式語言, 希望有興趣科技的同學加油!
D. 因很多 GPIO 3.3V 因此 若要控制 5V or 12V 可能 需要 NPN or PNP Tranzistor 或 使用 solid state relay (SSR)
特別注意 Ic 電流大小 (看 datasheet) 複習 電子學(安排電阻值, 自己計算負載所需的電流) 電資學院應該要懂一些基本的
e.g., TIP122 NPN 可達 5A 可用, 就不須 SSR
以前我學弟在美國, 有次請他們研發人員設計一電路, 隔一星期, 對方說 沒給電路圖 無法 用 SPICE!
這課程很花時間, 可以練 吐納養氣腹式呼吸
必學!吐納養氣腹式呼吸,啟動身體自癒力!健康2.0 20161224
General Embedded Linux Systems
Start up
power on–>hardware (CPU+ROM code (or Flash), Memory, Flash, ..)
ROM code UP and RUN
ROM code –-Choose Available Boot Loader (e.g., U-Boot)
Boot Loader UP and RUN-->Check and Choose Linux kernel image (e.g., bzimage) and Root File System (rootfs)
Load image, maybe, from flash, serial port, network, ...
Linux kernel image UP (first part)--decompress Linux (main part) to memory
RUN Linux main part --->
START all initial codes
......
mount rootfs / <<<root
RUN init (in rootfs)
init RUN all apps and INSERT all pre-defined kernel modules
START shell, ...
$>
PC 使用的 GRUB (GRand Unified Bootloader):
Details of GRUB on the PC
Linux kernel 啟動部分:
以 Linux 2.4.0 為例:
https://lxr.linux.no/linux-old+v2.4.0/init/main.c
604 kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
dup, dup2, dup3 - duplicate a file descriptor
execve - execute program
How to Set Environment Variables in Linux
Futher Reading:
How to read environment variables of a process
In general, "init" is the leading process with pid (process id)=0
You can look the result of pstree:
laikc@laikc-VirtualBox:~/course$ pstree
init─┬─NetworkManager─┬─dhclient
│ ├─dnsmasq
│ └─2*[{NetworkManager}]
├─accounts-daemon───{accounts-daemon}
├─atd
├─bluetoothd
├─console-kit-dae───64*[{console-kit-dae}]
├─cron
├─cupsd
├─2*[dbus-daemon]
├─6*[getty]
├─gvfs-fuse-daemo───3*[{gvfs-fuse-daemo}]
├─gvfsd
├─lightdm─┬─Xorg
│ ├─lightdm─┬─lightdm-greeter───lightdm-gtk-gre───{lightdm-gtk-gre}
│ │ └─{lightdm}
│ ├─lightdm
│ └─2*[{lightdm}]
├─modem-manager
├─named───3*[{named}]
├─ntpd
├─polkitd───{polkitd}
├─rsyslogd───3*[{rsyslogd}]
├─samba───4*[samba]
├─smbd───smbd
├─sshd─┬─sshd───sshd───bash───bash───pstree
│ └─sshd───sshd───bash
├─udevd───2*[udevd]
├─upowerd───2*[{upowerd}]
├─upstart-socket-
└─upstart-udev-br
Linux VFS & System Call
PART II
PEX Boot ( SEE http://www.syslinux.org/wiki/index.php?title=PXELINUX )
Start up
power–>hardware (CPU+Network ROM code, Memory, Flash, ..)
ROM code UP and RUN
ROM code –-PXE Loader (in Netwok ROM,Flash)
Choose Available Boot Loader (e.g., PXELINUX ) (Need DHCP server)
Load pxe-loader via TFTP (from TFTP server)
Boot Loader UP and RUN-->Check and Choose Linux kernel image (e.g., bzimage) and Root File System (rootfs)
Linux kernel image UP (first part)–decompress Linux (main part) to memory
Linux main part –->RUN
START all initial codes
…
mount rootfs / <<<root
RUN "init" in rootfs
init RUN all apps and INSERT all pre-defined kernel modules
START shell
$>
This is the op principle of network thin client!
How to Mount an NFS Share in Linux
Linux 檔案系統掛載(mount)使用教學與範例, by G. T. Wang
Busybox中httpd、ftpd、telnetd、tftpd、ntpd的用法
Install tftp server:
sudo apt install tftpd-hpa
Now, check whether the tftpd-hpa service is running with the following command:
sudo systemctl status tftpd-hpa
Modify tftpd-hpa
nano /etc/default/tftpd-hpa
改自 /tftpboot
Restart:
sudo systemctl restart tftpd-hpa
kclai@ubuntu16:/tmp$ tftp localhost
tftp> get net.sh
Received 171 bytes in 0.1 seconds
tftp> quit
kclai@ubuntu16:/tmp$
Linux unix-like monolithic architecture+loadable modules
Anatomy of the Linux file system (dentry, inode)
devfs
procfs
Linux v2.4.31 net/socket.c
與 Linux VFS 溝通
socket(AF_INET, SOCK_STREAM, 0)
net/ipv4/af_inet.c
GPIO
因同學有來問, 因此增加說明
這對Embedded Linux 設計很重要的基礎
[Day 7]-【STM32系列】淺入淺出之 General Purpose Input/Output 介紹 (上)
GPIO: You can control GPIO from user space
e.g. control /sys/class/gpio/gpio49/value
/sys/class/gpio/gpio49#> ls
active_low direction edge power subsystem uevent value
#> echo out > direction
#> echo 1 > value
#> echo 0 > value
注意 優缺點! 有些應用不適宜! 此外 debounce 也須處理!!! Appendix A.
SPI
/dev/spidevxx.yy 其中 xx 可能 0, yy 可能 0,1,.. yy 代表 chip select (哪一個 SPI)
user space
fd=open("/dev/spidevxx.yy ", …
ioctl (fd, …chip mode…)
…
read/write /ioctl
close
對一般的應用 可更進一步參考:
http://www.raspberry-projects.com/pi/programming-in-c/spi/using-the-spi-interface
其中 int SpiWriteAndRead 是重要的做法,還有 memset(&spi[i], 0, sizeof (spi[i])); 也類似我於課程中提的問題! 小心! 很多人忘記這個動作!
用 ioctl 來取代 read/write 有內部設計的原因 , I2C, USB 都有類似的用法
想像
user app<<<==================>>> SPI device
SPI interface (CS, CLK, MISO, MOSI) bit frame <–-> device
client <<< Network programming >>> server
兩者觀念一樣!! 也是
螺絲<-----螺紋---->螺帽
的關係
特別提醒
如果使用 GPIO, SPI 等裝置要注意 TIMING 的問題, 若使用 USER SPACE 可能有精準度的問題!
Benchmarking Raspberry Pi GPIO Speed
有關SPI, I²C, NAND Flash, NOR Flash, …可參考
Essential Linux Device Drivers, by Sreekrishnan Venkateswaran
I2C Introduction – Part 1 (Basics)
I2C Protocol Introduction – Part 2 (Advanced Topics)
We will focus on socket layer in this course (network programming).
Remark.
For example, "printf" is not a system call. Try run "strace your_hello_program" , you find it's "write" not printf!
Moreover, fopen, fprintf, strcmp, strcpy, … are not system calls. They are functions in dynamic lib libc…so.
Try "ldd your_hello_program" ! You can print the shared objects (shared libraries) ! This is an important method to build your new root file system with .shared libraries. See example "man ldd".
// user name is laikc
vdso (virtual dynamic shared object, see man 7 vdso)
Why does the vDSO exist at all? There are some system calls the
kernel provides that user-space code ends up using frequently, to
the point that such calls can dominate overall performance. This
is due both to the frequency of the call as well as the context-
switch overhead that results from exiting user space and entering the kernel.
In x86 32-bit systems, you can
trigger a software interrupt (int $0x80) to tell the kernel you
wish to make a system call.
e.g., gettimeofday
laikc@laikc-VirtualBox:/tmp/demo/laikc/course$ ldd ./ex1_1
linux-vdso.so.1 => (0x00007fff31d0d000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff323de0000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff3241b5000)
laikc@laikc-VirtualBox:/tmp/demo/laikc/course$
Performance issue: "copy_to_ user" & "copy_from_ user"
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
e.g.,
User space <–> Kernel space
read(fd, buf, count)/recv <––––> read(fd, buf,…)/recv
<<<<–-copy_to_ user
write(fd, buf,count)/send <––––-> write(fd, buf, …)/send
copy from user–->>>>>
Virtual Device:
Then we can use the remote devices. For example, mouse, keyboard, sound, memory, disk, …display…
Network programming is an important skill!"
This is the operation principle of network thin client!
You can, also, boot Windows OS via PXE.
願意再學請看以下:
作者 Greg Kroah-Hartman 提供
Linux Kernel in a Nutshell
This is the web site for the book, Linux Kernel in a Nutshell, by Greg Kroah-Hartman, published by O'Reilly.
License
This book is available under the terms of the Creative Commons Attribution-ShareAlike 2.5 license. That means that you are free to download and redistribute it. The development of the book was made possible, however, by those who purchase a copy from O'Reilly or elsewhere.
請需要的讀者參考
第一步:
對於一般學生 可以進一步學習 x86 Linux
利用 載入 Linux kernel source code
重新 編譯 並可開重新多重開機, 網路有很多善心人士提供許多資料, 我就不寫了.
小心 kernel : 重新編譯 重要事項:
(1) make menuconfig 與你CPU 有關, 因此 Google 時 請加 VM VirtualBox 或你 VMware 的名稱
最好用 VM 來測試你的 kernel, 才不會麻煩
(2) 不要用太新的版本, 學習用舊的即可, 尤其x86 很雜, 安全性很麻煩, 因練習用就儘可不用, 日後正式 用途需要考慮!
如果用量不是很大, Embedded Linux Board也夠用! 省電安全!
樹莓派或 TI BeagleBoard 夠一般 web server, 一般控制, NAS, … 等 用了!
(但要 DIY, 請把本課程學好, 才做的好)
:::
後面給進階的使用者
Appendix: System Call
Kernel Part: Depend on kernel version and arch
User Part: Depend on gcc version
Basic file: Check unistd.h, syscall.h, …
For example,
#define __NR_exit 1
#define __NR_fork 2
#define __NR_read 3
#define __NR_write 4
#define __NR_open 5
#define __NR_close 6
#define __NR_waitpid 7
…
Important command strace:
strace: trace system calls and signals
In general, user space: read(…) –>[sys call](3, …) –>kernel [sys call] (__NR_read …) –…
"strace" command help u to see your running system calls and using files, e.g.,"#> strace ./ex1"
If your network program has "gethostname (or gethostname2)", try to see using files.
Be careful, "gethostname" is not thread-safe. If you need not this function, don't use it.
You can add your new system call to kernel source (depends on kernel version…)
Remarks.
I am sorry, I can not give u a unique answer.
If you need this future, please see your kernel source.
In practice, you need not this future. This is a good excise for understanding system calls.
Advanced Users
I2C Introduction – Part 1 (Basics)
Appendix: Build a new Linux kernel and Rootfs
x86:
please google!
other ARCH: (Linux architecture)
step 1. toolchain
step 2. linux kernel
step 3. root file system (you can use busybox)
step 4. create your init
mount:
如何mount 特殊 file system 請 google 查詢
dd:
有用的command, 必需小心的危險command, 用錯會哭哭!!
請看 https://en.wikipedia.org/wiki/Dd_(Unix)
例如
dd if=/dev/zero bs=1024 count=1000000 of=file_1GB
複製至 of=/tmp/zero_copy
dd if=file_1GB of=/tmp/zero_copy
dd if=/dev/zero of=/tmp/rootimg bs=1k count=2000 通常用來產生 2MB rootimg 但原因是…很多人不知道!
事實上很多人 rootfs 愈來愈大就是沒真正了解學過知識的重點! 其實就是~~全為0 的檔案, 再複製你真正的檔案, 這要 gzip 才壓縮更多!! 否則一堆檔案垃圾 當壓縮檔愈來愈大
Now making it look like a block device instead of just a regular file (See man 8 losetup)
$ losetup /dev/loop0 rootimg
Creating an ext2 file system with the loop device
$ mke2fs -c /dev/loop0
You can mount in /mnt/rootfs (mkdir /mnt/rootfs)
$ mount -t ext2 /dev/loop0 /mnt/rootfs
You can use /mnt/rootfs as your new root file system
$ umount /dev/loop0
$ losetup -d /dev/loop0
Using VM:
Lubuntu 12.04: Compile QEMU 2.0.0
Create USB linux (using syslinux):
還有 4M Linux
Use QEMU:
QEMU (ARM Arch) (含 toolchain, kernel, rootfs 產生) (若初級使用 請 google, 有很多!)
device files system
$:> ls -al /dev
major minor
total 724
…
lrwxrwxrwx 1 root root 9 Oct 14 22:51 cdrom -> /dev/scd1
lrwxrwxrwx 1 root root 9 Oct 14 22:52 cdrom1 -> /dev/scd0
crw–––- 1 root tty 5, 1 Jan 19 20:47 console
crw–w–– 1 root video 29, 1 Mar 15 2002 fb0autodetect
…
brw-rw–– 1 root disk 3, 64 Mar 15 2002 hdb
brw-rw–– 1 root disk 22, 0 Mar 15 2002 hdc
brw-rw–– 1 root disk 22, 64 Mar 15 2002 hdd
…
crw-r––- 1 root kmem 1, 1 Sep 28 18:06 mem
crw-rw-rw- 1 root root 1, 3 Sep 28 18:06 null
…
brw-rw–– 1 root disk 8, 0 Mar 15 2002 sda //major number=8, minor number=0
brw-rw–– 1 root disk 8, 1 Mar 15 2002 sda1
brw-rw–– 1 root disk 8, 2 Mar 15 2002 sda2
brw-rw–– 1 root disk 8, 3 Mar 15 2002 sda3
brw-rw–– 1 root disk 8, 4 Mar 15 2002 sda4
brw-rw–– 1 root disk 8, 16 Mar 15 2002 sdb
brw-rw–– 1 root disk 8, 17 Mar 15 2002 sdb1
brw-rw–– 1 root disk 8, 18 Mar 15 2002 sdb2
brw-rw–– 1 root disk 8, 19 Mar 15 2002 sdb3
brw-rw–– 1 root disk 8, 20 Mar 15 2002 sdb4
…
lrwxrwxrwx 1 root root 4 Sep 28 18:05 stderr -> fd/2
lrwxrwxrwx 1 root root 4 Sep 28 18:05 stdin -> fd/0
lrwxrwxrwx 1 root root 4 Sep 28 18:05 stdout -> fd/1
crw-rw-rw- 1 root tty 5, 0 Sep 28 18:06 tty
crw–––- 1 root root 4, 0 Sep 28 18:06 tty0
crw–––- 1 root root 4, 1 Jan 19 14:59 tty1
…
crw-rw–– 1 root dialout 4, 64 Mar 15 2002 ttyS0
crw-rw–– 1 root dialout 4, 65 Mar 15 2002 ttyS1
crw-rw–– 1 root dialout 4, 66 Mar 15 2002 ttyS2
crw-rw–– 1 root dialout 4, 67 Mar 15 2002 ttyS3
crw-rw–– 1 root dialout 188, 0 Mar 15 2002 ttyUSB0 //不一定在這裡
crw-rw–– 1 root dialout 188, 1 Mar 15 2002 ttyUSB1
cr–r–r– 1 root root 1, 9 Jan 19 20:46 urandom
drwxr-xr-x 2 root root 4096 Sep 28 18:05 usb
…
crw-rw-rw- 1 root root 1, 5 Sep 28 18:06 zero
//下面這個是 自己寫的 device (假設的)
crw-rw-rw- 1 root root 100, 0 Sep 28 18:06 mydev
crw-rw–– c 表示 char device
b???… b 表示 block device
//問題來了
(1) /dev/mydev 如何產生 ? major number=100, minor number=0 如何產生?
(2) user space 如何使用?
(1)
引 用寫的很好的 Writing a Linux Kernel Module — Part 2: A Character Device
的file_operations 資料:
基本想法: Object Model (簡化說明)
(a)
Write a kernel module mydev.c ->gcc (You Need Makefile, Kernel Source and strip)->mydev.ko
kernel module mydev.c (完整寫法…可參考http://derekmolloy.ie/writing-a-linux-kernel-module-part-2-a-character-device/ , 他的好例子複雜一點, register_chrdev(100,"mydev",&myfp); 可以取代register_chrdev(0, DEVICE_NAME, &fops);但必須確保 major 100 可用!)
一般而言, 作者 register_chrdev(0, DEVICE_NAME, &fops) 是比較好的方式~ 這裡 要讓讀者練習與了解 mknod
(a.1) write myfp ===>file_operations // 模擬檔案操作
(a.2) you must register a char device
register_chrdev(100,"mydev",&myfp);
#!> insmod mydev
/* become a virtual char device /
#!> mknod /dev/mydev c 100 0
/ make a device node for user space app*/
Then you can write your app hellodev.c
Appendix A.
虛擬程式: square wave
loop:
echo 1 > /sys/class/gpio/gpio49/value
sleep_msec 1
echo 0 > /sys/class/gpio/gpio49/value
sleep_msec 1
goto loop
會如何? 請思考可能的問題! 我上課會說! 事實上這虛擬程式有限制
mmap:
https://jasonblog.github.io/note/linux_driver/mmap_driver_implementation.html
Linux的二號功臣 Alan Cox
How to Write Linux Mouse Drivers, by Alan Cox
Kernel Korner - Sleeping in the Kernel