code style

2019年8月2日 星期五

u-boot arm64 from QEMU

#!/bin/bash
PREFIX="aarch64-linux-gnu-"
arch="arm64"
TOP=`pwd`

UBOOT_SRC_URL="https://ftp.denx.de/pub/u-boot/u-boot-2018.11.tar.bz2"
TOOLCHAIN_SRC_URL="http://releases.linaro.org/components/toolchain/binaries/6.5-2018.12/aarch64-linux-gnu/gcc-linaro-6.5.0-2018.12-x86_64_aarch64-linux-gnu.tar.xz"
BUSYBOX_SRC_URL="http://busybox.net/downloads/busybox-1.23.2.tar.bz2"
KERNEL_SRC_URL="https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.4.8.tar.xz"

UBOOT_DIR="uboot_src"
TOOLCHAIN_DIR="toolchain_src"
BUSYBOX_DIR="busybox_src"
KERNEL_DIR="linux_src"

TOOLCHAIN_PATH="$TOP/$TOOLCHAIN_DIR/bin"

BUSYBOX_PALTFORM="busybox-$arch"
LINUX_PALTFORM="linux-$arch-basic"



download_src(){
if [ -d "$1" ]; then
echo "The $1 has been downloaded"
else
mkdir "$1"
wget -P /tmp/ "$2" && tar $3 "/tmp/`basename $2`" -C "$1" --strip-components=1
fi
}

toolchain() {
download_src $TOOLCHAIN_DIR $TOOLCHAIN_SRC_URL xJf
export PATH=${PATH}:${TOOLCHAIN_PATH}
export ARCH=$arch
export CROSS_COMPILE=$PREFIX
}


uboot() {
download_src $UBOOT_DIR $UBOOT_SRC_URL jxvf
toolchain;
cd "$UBOOT_DIR"
make qemu_arm64_defconfig
make -j4
}


busybox() {
download_src $BUSYBOX_DIR $BUSYBOX_SRC_URL xjf
toolchain;
mkdir -pv $TOP/initramfs
mkdir -pv $TOP/obj/$BUSYBOX_PALTFORM

cd "$BUSYBOX_DIR"
    make mrproper
    make O=$TOP/obj/$BUSYBOX_PALTFORM defconfig
sed -i 's/.*CONFIG_STATIC.*/CONFIG_STATIC=y/' $TOP/obj/$BUSYBOX_PALTFORM/.config
sed -i 's/.*CONFIG_INSTALL_NO_USR.*/CONFIG_INSTALL_NO_USR=y/' $TOP/obj/$BUSYBOX_PALTFORM/.config
sed -i 's/.*CONFIG_FEATURE_PREFER_APPLETS.*/CONFIG_FEATURE_PREFER_APPLETS=y/' $TOP/obj/$BUSYBOX_PALTFORM/.config
sed -i 's/.*CONFIG_FEATURE_SH_STANDALONE.*/CONFIG_FEATURE_SH_STANDALONE=y/' $TOP/obj/$BUSYBOX_PALTFORM/.config
    make clean
    make O=$TOP/obj/$BUSYBOX_PALTFORM -j12 2>&1 | tee  ../busybox_build.log
    make O=$TOP/obj/$BUSYBOX_PALTFORM install

# initramfs
cd $TOP/initramfs
mkdir -pv {bin,sbin,etc/init.d,proc,sys,dev,lib,usr/{bin,sbin}}
cp -av $TOP/obj/$BUSYBOX_PALTFORM/_install/* .

cd dev
sudo mknod -m 660 null c 1 3
sudo mknod -m 622 console c 5 1
sudo mknod -m 622 tty0 c 4 0
ln -sf null tty2
ln -sf null tty3
ln -sf null tty4
cd ..
    #cp -a $TOP/toolchain_src/arm-linux-gnueabihf/libc/* lib

#don't have any space or tab when use EOF to output file
cat << EOF > etc/init.d/rcS
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
echo -e "\nBoot took $(cut -d" " -f1 /proc/uptime) seconds\n"
EOF

    chmod 755 etc/init.d/rcS
    find . -print0 \
        | cpio --null -ov --format=newc \
        | gzip -9 > $TOP/obj/$BUSYBOX_PALTFORM/initramfs-"$BUSYBOX_PALTFORM".cpio.gz
}

initramfs() {
    TOP=`pwd`
    cd $TOP/initramfs/"$BUSYBOX_PALTFORM"

    #find ./ | cpio -o -H newc | gzip > $TOP/obj/initramfs-$BUSYBOX_PALTFORM.cpio.gz

    find . -print0 \
    | cpio --null -ov --format=newc \
    | gzip -9 > $TOP/obj/BUSYBOX_PALTFORM/initramfs-"$BUSYBOX_PALTFORM".cpio.gz
}

kernel() {
download_src $KERNEL_DIR $KERNEL_SRC_URL xJf
toolchain;
# build kernel
cd $TOP
    mkdir -pv obj/"$LINUX_PALTFORM"
    make -C $KERNEL_DIR O=../obj/$LINUX_PALTFORM mrproper
    make  -C $KERNEL_DIR O=../obj/$LINUX_PALTFORM  defconfig
    sed -i 's/.*CONFIG_EXPERIMENTAL.*/CONFIG_EXPERIMENTAL=y/' ../obj/$LINUX_PALTFORM/.config
sed -i 's/.*CONFIG_DEBUG_INFO.*/CONFIG_DEBUG_INFO=y/' ../obj/$LINUX_PALTFORM/.config
sed -i 's/.*CONFIG_KGDB.*/CONFIG_KGDB=y/' ../obj/$LINUX_PALTFORM/.config
sed -i 's/.*CONFIG_KGDB_LOW_LEVEL_TRAP.*/CONFIG_KGDB_LOW_LEVEL_TRAP=y/' ../obj/$LINUX_PALTFORM/.config
sed -i 's/.*CONFIG_FRAME_POINTER.*/CONFIG_FRAME_POINTER=y/' ../obj/$LINUX_PALTFORM/.config
sed -i 's/.*CONFIG_MAGIC_SYSRQ.*/CONFIG_MAGIC_SYSRQ=y/' ../obj/$LINUX_PALTFORM/.config
sed -i 's/.*CONFIG_8139CP.*/CONFIG_8139CP=y/' ../obj/$LINUX_PALTFORM/.config
sed -i 's/.*CONFIG_DEBUG_SET_MODULE_RONX.*/CONFIG_DEBUG_SET_MODULE_RONX=n/' obj/$LINUX_PALTFORM/.config
sed -i 's/.*CONFIG_DEBUG_RODATA.*/CONFIG_DEBUG_RODATA=n/' ../obj/$LINUX_PALTFORM/.config
sed -i 's/.*CONFIG_MODULE_FORCE_LOAD.*/CONFIG_MODULE_FORCE_LOAD=y/' ../obj/$LINUX_PALTFORM/.config
sed -i 's/.*CONFIG_MODULE_UNLOAD.*/CONFIG_MODULE_UNLOAD=y/' ../obj/$LINUX_PALTFORM/.config
sed -i 's/.*CONFIG_MODULE_FORCE_UNLOAD.*/CONFIG_MODULE_FORCE_UNLOAD=y/' ../obj/$LINUX_PALTFORM/.config

cat << EOF >> ../obj/"$LINUX_PALTFORM"/.config
CONFIG_KPROBES_ON_FTRACE=y
CONFIG_UPROBES=y
CONFIG_TRACE_IRQFLAGS=y
CONFIG_TRACER_MAX_TRACE=y
CONFIG_RING_BUFFER_ALLOW_SWAP=y
CONFIG_FTRACE=y
CONFIG_FUNCTION_TRACER=y
CONFIG_FUNCTION_GRAPH_TRACER=y
CONFIG_IRQSOFF_TRACER=y
CONFIG_SCHED_TRACER=y
CONFIG_FTRACE_SYSCALLS=y
CONFIG_TRACER_SNAPSHOT=y
CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y
CONFIG_STACK_TRACER=y
CONFIG_UPROBE_EVENT=y
CONFIG_DYNAMIC_FTRACE=y
CONFIG_DYNAMIC_FTRACE_WITH_REGS=y
CONFIG_FUNCTION_PROFILER=y
CONFIG_FTRACE_MCOUNT_RECORD=y
CONFIG_FTRACE_SELFTEST=y
CONFIG_FTRACE_STARTUP_TEST=y
CONFIG_EVENT_TRACE_TEST_SYSCALLS=y
CONFIG_MMIOTRACE=y
CONFIG_PERCPU_RWSEM=y
EOF

yes '' | make -C $KERNEL_DIR O=../obj/$LINUX_PALTFORM oldconfig
make -C $KERNEL_DIR O=../obj/$LINUX_PALTFORM clean
time make -C $KERNEL_DIR O=../obj/$LINUX_PALTFORM -j12 2>&1 | tee kernel_build.log
}


qemu() {
    qemu-system-aarch64 -machine virt -cpu cortex-a53 -nographic -m 2048 \
    -kernel obj/"$LINUX_PALTFORM"/arch/arm64/boot/Image \
    -initrd obj/$BUSYBOX_PALTFORM/initramfs-"$BUSYBOX_PALTFORM".cpio.gz \
    -append "root=/dev/ram rdinit=/sbin/init console=ttyAMA0,115200"
}



initramfs() {
    cd $TOP/initramfs/"$BUSYBOX_PALTFORM"

    #find ./ | cpio -o -H newc | gzip > $TOP/obj/initramfs-$BUSYBOX_PALTFORM.cpio.gz

    find . -print0 \
    | cpio --null -ov --format=newc \
    | gzip -9 > $TOP/obj/$BUSYBOX_PALTFORM/initramfs-"$BUSYBOX_PALTFORM".cpio.gz
}

while true; do
    case "$1" in
-t|--toolchain) toolchain; exit 0;;
-u|--uboot) uboot; exit 0;;
-b|--busybox) busybox; exit 0;;
-i|--initramfs) initramfs; exit 0;;
-k|--kernel) kernel; exit 0;;
        -r|--run) qemu; exit 0;;
        --) shift; break;;
    esac
    shift
done


2019年7月28日 星期日

espressobin boot from UART

ESPRESSObin v7 boot from UART



如果版子上沒有bootloader(u-boot), 可使用UART mode 來recovery.
a. build UART images, they are located in build/a3700/debug/uart-images/ directory:
$ ls build/a3700/debug/uart-images
TIM_ATF.bin  atf-ntim.txt  boot-image_h.bin  wtmi_h.bin

b. 調jump to UART mode, 參考boot modes table


Boot modes - ESPRESSObin v7
ESPRESSObin boot modeJ11J3J10
Serial NOR flash download mode2-32-31-2
eMMC download mode2-31-22-3
eMMC alternate download mode2-31-22-3
SATA download mode2-31-22-3
Serial NAND flash download mode2-31-22-3
UART mode2-31-22-3
MicroSD card2-31-22-3
 c.  open comport from windows and we should  should see the > prompt presented on the HyperTerminal screen. In this terminal, type wtp to switch the BootROM to WTP download mode.
 d.  download the WTPTP tools from extranet
 e. run this command from cmd.exe(-C 38 is your COM number)
>> WtpDownload.exe -P UART -C 38 -R 115200 -B path\to\TIM_ATF.bin -I path\to\wtmi_h.bin -I path\to\boot-image_h.bin -E

f. when you see the "Mavell>>" , use tftp to update bootloader
 set ip address

Marvell>> setenv serverip 192.168.x.x
Marvell>> setenv ipaddr 192.168.x.x
check
Marvell>> ping $serverip
update u-boot

Marvell>> bubt espressobin-bootloader-cpu-1000-ddr3-2cs-1g-atf-ga3306ab-uboot-gaee49fc-20180129-REL.bin
Burning U-BOOT image "espressobin-bootloader-cpu-1000-ddr3-2cs-1g-atf-ga3306ab-uboot-gaee49fc-20180129-REL.bin" from "tftp" to "spi"
Using neta@30000 device
TFTP from server 192.168.10.134; our IP address is 192.168.10.145
Filename 'espressobin-bootloader-cpu-1000-ddr3-2cs-1g-atf-ga3306ab-uboot-gaee49fc-20180129-REL.bin'.
Load address: 0x2000000
Loading: #################################################################
 #################################################################
 #################################################################
 #################################################################
 ##########################
 2.3 MiB/s
done
Bytes transferred = 4194304 (400000 hex)
Image checksum...OK!
SF: Detected w25q32dw with page size 256 Bytes, erase size 4 KiB, total 4 MiB
Erasing 4198400 bytes (1025 blocks) at offset 0 ...Done!
Writing 4194304 bytes from 0x2000000 to offset 0 ...Done!
g. chang jump to "Serial NOR flash download mode"

2019年7月15日 星期一

Bootloader

embedded linux system上, software可分4個層次:
1. 引導加載程序:
是系統上電後運行的第一段code。包括在firmware中的boot code(option)和bootloader兩部分
2.kernel:
包括訂製kernel和啟動參數
3.rootfs:
位於flash上的rootfs.通常用ramdisk來作為rootfs.
4.application:
實際上板子上開發應用的程式

x86主機:
引導加載程序由BIOS(位於flash rom)和位於硬碟的MBR中的OS BootLooader組成(GRUB,LILO..)
系統上電後運行BIOS => 硬體檢測,資源分配 => 將MBR中的 BootLooader由硬碟讀到ram=>
將控制權交給OS BootLoader

embedded linux system的boot loader:
而在嵌入式系統中,通常並沒有像BIOS那樣的程式(注,有的嵌入式CPU也會內嵌一段短小的啟動程序),因此整個系統的加載啟動任務就完全由BootLoader來完成.

比如在一個基於ARM7TDMI core的嵌入式系統中,系統在上電或複位時通常都從地址0x00000000處開始執行,而在這個地址處安排的通常就是系統的BootLoader程序.

簡單地說,BootLoader就是在kernel運行之前運行的一段小程序.通過這段小程序,我們可以初始化硬體設備、建立內存空間的映射圖,從而將系統的軟硬體環境帶到一個合適的狀態,以便為最終調用kernel准備好正確的環境.

啟動過程:
可分為Single Stage和Multi-Stage, 一般flash上使用的是Multi-Stage. 大多是stage1和stage2.
stage1:
硬體設備initial
RAM空間 inital
copy BootLoader 的stage2 到RAM空間中
設置好stack point(sp)
跳轉到stage2的 c entry point

stage2:
硬體設備initial
檢測memory map
將kernel和rootfs從flash中讀到RAM
為kernel設置啟動參數
調用kernel


2017年7月17日 星期一

Device Tree(4)Device Node Requirements

一個device tree最少要由一個root node,cpus node, memory node組成。

Root Node
Root node表示符號為"/",下表是它的屬性

Aliases Node
這個屬性在root的位置,node name為aliases。必須要為小寫字元開頭,長度為1~31字元,主要是用來減少冗長的路徑名稱。
可用字元如下圖:






例:
aliases {
  serial0 = "/simple-bus@fe000000/serial@llc500";
  ethernet0 = "/simple-bus@fe000000/ethernet@31c000";
}

就可用serial0來代表/simple-bus@fe000000/serial@llc500

Memory Node
表示實際系統上的memory layout,屬性見下圖:














例:
一個 64-bit Power system 的 physical memory layout:
RAM: starting address 0x0, length 0x80000000 (2GB)
RAM: starting address 0x100000000, length 0x100000000 (4GB)

在root node定義address and size,這裡表示reg 屬性需要2個32-bit cells
#address-cells = <2>;
#size-cells = <2>;

可用下面兩種方式表示這兩段記憶體

(1)
memory@0 {
   device_type = "memory";
   reg = <0x000000000 0x00000000 0x00000000 0x80000000
              0x000000001 0x00000000  0x00000001 0x00000000>;
};

(2)
memory@0 {
device_type = "memory";
reg = <0x000000000 0x00000000 0x00000000 0x80000000>;
};

memory@100000000 {
device_type = "memory";
reg = <0x000000001 0x00000000 0x00000001 0x00000000>;
};

Chosen Node
用來描述由系統firmware指定的runtime parameter。會放在root node底下。原本通過tag list傳遞的一些 kernel的運行時參數可以通過Device Tree傳遞。例如command line可以通過bootargs這個property這個屬性傳遞,node屬性如下圖:















例:
chosen {
   bootargs = “root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200”;
};

CPUS Node
表示實際系統上的CPU,因為可能不只一個CPU又或是多核心,cpus node包含cpu node,等下會說到。cpus node屬性如下圖:



CPU Node
表示實際系統上的CPU,屬性如下圖:














































Device Tree(3)Interrupts and Interrupt Mapping

Properties for Interrupt Generating Devices
interrupt-parent 
在device tree中interrupt controller有一個interrupt-parent 屬性,這個用來表示interrupt之間的路由關係,它用一個phandle value表示其parent。各個interrupt controller的定義是不一樣的,有的用3個u32,有的用4個。

interrupt tree 有可能和device tree是不一樣的。
這個node本身如果沒有這interrupt-parent 的話,就是用parent node的interrupt-parent。

interrupts
一個能產生中斷的設備,必須要定義interrups這屬性。這裡指的就是設備產生的interrupt,描述interrupt source的又叫interrupt specifier。使用<u32>來表示。

例:
interrupts = <0xA 8>;
表示interrupt number:0xA, level/sense:8

Properties for Interrupt Controllers
interrupt-controller
Value type:<empty>
用來表示interrupt-controller

interrupt-cells
Value type:<u32>
用來表示interrupt-controller需要幾個單位做interrupt specifier

 Interrupt Nexus Properties
一個interrupt nexus node應該要有一個#interrupt-cells 屬性
interrupt nexus
用來轉譯的,nexus的意思就是"連結",連結上下兩個domains的那個node。
例:
PCI controller device node定義了一個nexus node,用來轉譯PCI interrupt namespace(INTA,INTB,etc.)到interrupt controller的IRQ。

interrupt關係圖示例


上圖中沒有interrupt-parent的open-pic為root,有3個doamin,2個nexus nodes。可轉換為下圖:


2017年7月14日 星期五

Device Tree(2)Properties

Property Names:
由1~31個字元組成,內容為下述:
Character Description 0-9
digit a-z lowercase letter
,(comma ). (period) _ (underscore) +( plus sign) - (dash) ? (question mark) #(hash)

需要一個唯一的prefix,來辨別property的名稱或組織,例如:
fsl,channel-fifo-len
ibm,ppc-interrupt-server#s
linux,network-index

Property Values:
有下面幾種類型,記憶體排方式應該是看CPU 架構為主,little-endian或big-endian:
empty => 如果是true-false的話,可以為空。
u32 => 32bit 整數
u64 => 64bit 整數
string=> 字串
prop-encoded-array=>描述property用
phandle => 一個u32 value,可以用來給別的node拿來參考用,類似指標,指向另一個node。
stringlist => 連續的字串

Standard Properties:
device tree是使用 Device Tree Source(DTS)格式來描述nodes和properties。下面列出一些標準的properties。


Property:compatible
Value type:<stringlist>
用來描述driver model,OS會照stringlist順序去找尋driver model,建議格式為 "manufacturer,model"。
例:
compatible = “fsl,mpc8641-uart”, “ns16550";

在這例子中有兩個string,OS會先去找“fsl,mpc8641-uart”, 如果找不到就會改去找 general ns16650 device type。

Property:model
Value type:<string>
driver名稱及model number。
例:
model = “fsl,MPC8349EMITX”;

Property:phandle
Value type:<u32>
一個在device tree中的唯一值,給其他的node參考用。
例:
pic@10000000 {
    phandle = <1>;
    interrupt-controller; 20
};
定義pandle=1,其他的node可用1這個值來使用pic@10000000。
例:
interrupt-parent = <1>;

Property:status
Value type:<string>
顯示driver的操作,有4種。
okay=>表示可操作
disabled=>表示目前為關閉,不可操作
fail=>表示目前為錯誤,需要修復,不可操作
fail-sss=>表示目前為錯誤,需要修復,不可操作。sss用來指示錯誤原因。

Property:#address-cells and #size-cells
Value type:<u32>
表示在child node's 的reg裡的address and size。如果沒有寫,default為2 and 1。
#size-cells是可以為0的,那reg裡面的size就會被省略。
例:
裡面表示soc的child serial node裡的reg有一個address (0x4600)和一個size(0x100)。

Property:reg
Value type:<prop-encoded-array>, 表示方式為(address, length)
register,主要是指memory-mapped IO register的offsets and lengths。
例:
#address-cells為1 and #size-cells為1
reg = <0x3000 0x20 0xFE00 0x100>;
代表在0x3000有一個32byte的block和0xFE00有一個256 byte block

Property:ranges
Value type:<empty> or <prop-encoded-array>, 表示方式為(child-bus-address, parent-bus-address, length)
表示 register定址的範圍
例:
定址範圍有0x00100000, 1024KB,child 定址在0x0, mapping 到parent 0xe0000000。
在此例中,serial的offset 為04600,而mapping後的位置為0xe0004600

Property:device_type
Value type:<string>
原本在IEEE1275中用來描述FCode,因為ePAPR沒有FCode,為了相容性,只用在cpu and memory上。
例:
 memory {
   device_type = "memory";
   reg = <0x00000000 0x100000000>; /* 4 GB */
 };








Device Tree(1)觀念和介紹

概念:
Linux  Kernel從3.x開始引入設備樹的概念。樹狀結構來描述硬體,每一個node有property/value來描述屬性,除了root node之外,都會有一個parent。原則上是非動態偵測的device,就要加入device tree,例如PCI。

下圖表示一個最簡單可以開機的OS的device tree,包含了平台、CPU、memory等資訊。 



Node Names:
名稱組成方式為 => node-name@unit-address

node-name為長度1~31的大小寫英文數字以及 ,(comma) .(period) _(underscore) +(plus sign) -(dash)組成。開頭必頭為英文字母。

unit-address要符合reg property。unit-address可以省略,只要名稱不要和其他兄弟節點一樣即可。

root node的名稱是slash(/)。

例如ethernet@fe001000和ethernet@fe002000這兩個node就是以unit-address來分別。

建議的node-name:
• atm
• cache-controller
• compact-flash 9
• can
• cpu
• crypto
• disk
• display
• dma-controller
• ethernet
• ethernet-phy
• fdc
• flash
• gpio
• i2c
• ide
• interrupt-controller
• isa
• keyboard
• mdio
• memory
• memory-controller
• mouse
• nvram
• parallel
• pc-card
• pci
• pcie
• rtc
• sata
• scsi
• serial
• sound
• spi
• timer
• usb
• vme
• watchdog