嵌入式系統 - 開機相關






雙rootfs開機轉換

mtd 切法

[ 1.148946] spi_qup 78b5000.spi: IN:block:16, fifo:64, OUT:block:16, fifo:64
[ 1.151660] m25p80 spi32766.0: found mx25u3235f, expected n25q128a11
[ 1.157521] m25p80 spi32766.0: mx25u3235f (4096 Kbytes)
[ 1.163868] 12 ofpart partitions found on MTD device spi32766.0
[ 1.168739] Creating 12 MTD partitions on "spi32766.0":
[ 1.174686] 0x000000000000-0x0000000a0000 : "0:SBL1"
[ 1.180552] 0x0000000a0000-0x0000000b0000 : "0:MIBIB"
[ 1.185677] 0x0000000b0000-0x0000000d0000 : "0:BOOTCONFIG"
[ 1.190605] 0x0000000d0000-0x0000000f0000 : "0:BOOTCONFIG1"
[ 1.196009] 0x0000000f0000-0x000000260000 : "0:QSEE"
[ 1.201457] 0x000000260000-0x000000270000 : "0:DEVCFG"
[ 1.206682] 0x000000270000-0x000000290000 : "0:RPM"
[ 1.211626] 0x000000290000-0x0000002a0000 : "0:CDT"
[ 1.216413] 0x0000002a0000-0x0000002b0000 : "0:APPSBLENV"
[ 1.221247] 0x0000002b0000-0x000000350000 : "0:APPSBL"
[ 1.226820] 0x000000350000-0x000000390000 : "0:ART"
[ 1.231835] 0x000000390000-0x000000400000 : "flash"
[ 1.237725] nand: device found, Manufacturer ID: 0xc2, Chip ID: 0xa1
[ 1.240877] nand: ONFI 10-Compliant Macronix MX30UF1G18AC
[ 1.247491] nand: 128 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
[ 1.252795] 2 ofpart partitions found on MTD device qcom_nand.0
[ 1.260244] Creating 2 MTD partitions on "qcom_nand.0":
[ 1.266060] 0x000000000000-0x000004000000 : "rootfs_1"
[ 1.318593] 0x000004000000-0x000008000000 : "rootfs"
[ 1.365634] mtd: device 13 (rootfs) set to be root filesystem
[ 1.365888] mtdsplit: no squashfs found in "rootfs"


轉換開機語法

echo 1 > /proc/boot_info/rootfs/primaryboot
cat /proc/boot_info/getbinary_bootconfig > /tmp/bootconfig.bin
cat /proc/boot_info/getbinary_bootconfig1 > /tmp/bootconfig1.bin
dd if=/tmp/bootconfig.bin of=/dev/mtdblock2
dd if=/tmp/bootconfig.bin of=/dev/mtdblock3













嵌入式系統 - Openwrt 相關





Openwrt 下載方法 (不能使用 root 帳號進行)


git clone https://git.openwrt.org/openwrt/openwrt.git
./scripts/feeds update -a
./scripts/feeds install -a
make menuconfig // 這一步要選擇cpu,以及需要的功能...
cd openwrt
make V=s

再來就是改過不了的部份了,除非使用的編譯環境跟原本的相同,不然會有很多錯誤產生。問題在 google 上搜尋,大部份都可以得到解答。祝好運~


在 u-boot 更新 XXXX-single.img 的下法


setenv ipaddr 192.168.1.1 // 自己的ip
setenv serverip 192.168.1.2 // tftp server 的 ip
setenv machid 8030002 // 非必要
set bootargs console=ttyMSM0,115200n8 // 非必要
tftpboot XXXX-single.img
imgaddr=$fileaddr && source $imgaddr:script
reset




Android - 改變PCM數據音量大小

 



int db = 6; // 範圍:+30(最大聲) ~ 0(原始音量) ~ -96(最小聲)Step2
private double factor = Math.pow(10, (double)db/20); // 分貝公式 y = 20 * log10(x)

// 取得 16bit 採樣率的完整數據
private short getShort(byte[] data, int start) {
return (short)((data[start] & 0xFF) | ((data[start+1] << 8) & 0xFF00));
}

/* 調整 PCM 數據音量
* pData:原始音頻數據
* nLen:原始音頻數據長度
* data2:轉換後新音頻數據
* nBitsPerSample:採樣率
* multiple:表示增益值 (需代入公式計算結果,在這裡即是 factor)
*/
public int amplifyPCMData(byte[] pData, int nLen, byte[] data2, int nBitsPerSample, float multiple)
{
int nCur = 0;
float pcmval;
if (nBitsPerSample == 16) {
short volum;
while (nCur < nLen) {
volum = getShort(pData, nCur);
// volum <<= 1;
// volum = (short)(volum * multiple);
pcmval = (volum * multiple);
if(volum < -32768)
volum = -32768;
else if(volum > 32767)
volum = 32767;
else
volum = (short)pcmval;
data2[nCur] = (byte)( volum & 0xFF);
data2[nCur+1] = (byte)((volum >> 8) & 0xFF);
nCur += 2;
}
} else if(nBitsPerSample == 8) {
byte volum;
while (nCur < nLen) {
volum = pData[nCur] & 0xFF;
pcmval = (volum * multiple);
if(volum < -127)
volum = -127;
else if(volum > 128)
volum = 128;
else
volum = (byte)(pcmval);
data2[nCur] = (byte)(volum & 0xFF);
nCur++;
}
}
return 0;
}




參考:


嵌入式系統 - gpio 相關




LED 燈號控制 (假定 LED 的 GPIO 為十進制的 34)


echo 34 > /sys/class/gpio/export // 指定控制 gpio 34
echo out > /sys/class/gpio/gpio34/direction // 指定方向 (in, out)
echo 1 > /sys/class/gpio/gpio34/value // 亮
echo 0 > /sys/class/gpio/gpio34/value // 不亮



factory reset 按鍵 (假定 GPIO 為 9)


echo 9 > /sys/class/gpio/export // 指定控制 gpio 9 (預設方向為 in,所以不用再指定方向)
cat /sys/class/gpio/gpio9/value // 0: 未按壓, 1: 已按壓



列出所有 gpio 的內容


cat /sys/kernel/debug/gpio



使用 /dev/gpio 控制範例


static int doit = 0;
#define RALINK_GPIO_ENABLE_INTP 0x08
#define RALINK_GPIO_DISABLE_INTP 0x09
#define RALINK_GPIO_REG_IRQ 0x0A
typedef struct {
unsigned int irq; //request irq pin number
pid_t pid; //process id to notify
} ralink_gpio_reg_info;
static void nvramIrqHandler(int signum)
{
if (!doit && signum == SIGUSR2) {
doit = 1;
// todo ...
}
}
int main(int argc, char **argv)
{
int fd;
ralink_gpio_reg_info info;

signal(SIGUSR1, nvramIrqHandler);
signal(SIGUSR2, nvramIrqHandler);

fd = open("/dev/gpio", O_RDONLY);
if (fd < 0) {
perror("/dev/gpio");
return -1;
}

//enable gpio interrupt
if (ioctl(fd, RALINK_GPIO_ENABLE_INTP) < 0)
goto ioctl_err;

info.pid = getpid();
info.irq = 18;

//register gpio
if (ioctl(fd, RALINK_GPIO_REG_IRQ, &info) < 0)
goto ioctl_err;

close(fd);

while(1) {
sleep(60);
}
return 0;

ioctl_err:
perror("ioctl");
close(fd);
return -1;
}



FILE *fp;
if ((fptr = fopen("/proc/gpio","r"))) { // 0:not push, 1:push
char buf[20];
fgets(buf, sizeof(buf), fptr);
sscanf(buf,"%d", &push_button);
fclose(fptr);
}



使用 /dev/mem 控制範例


int _8a110_read_bt( void)
{
int fd;
void *smc_addr,*psmc_addr;
u32 u32tmp;
u8 u8tmp;

if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
printf("open /dev/mem Error\n");

psmc_addr = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,\
fd,SMC_MAP_ADDRESS & ~MAP_MASK);

if(psmc_addr == (void *) -1)
printf("Memory mapped at address %p. Error\n", psmc_addr);

smc_addr = psmc_addr + (SMC_MAP_ADDRESS & MAP_MASK);

u32tmp = (*(volatile u32 *)(smc_addr));

*(volatile u8 *)(smc_addr + GPIO_SW_ADDRESS) = 0x01; // set Multi PIN = GPIO
write( fd, smc_addr + GPIO_SW_ADDRESS, 1);

u8tmp = (*(volatile u8 *)(smc_addr + GPIO_SW_READ));

if( munmap( psmc_addr, MAP_SIZE) == -1) {
perror( " Error un-mmapping the file");
}
close(fd);

if( u8tmp == 0x28) return 1;
else return 0;

}



int _8a110_control_led(int hl)
{
int fd;
void *smc_addr,*psmc_addr;
u32 u32tmp;

if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
printf("open /dev/mem Error\n");

psmc_addr = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,\
fd,SMC_MAP_ADDRESS & ~MAP_MASK);

if(psmc_addr == (void *) -1)
printf("Memory mapped at address %p. Error\n", psmc_addr);

smc_addr = psmc_addr + (SMC_MAP_ADDRESS & MAP_MASK);

u32tmp = (*(volatile u32 *)(smc_addr));

*(volatile u8 *)(smc_addr + PROGRAM_ADDRESS) = 0x01; // set Multi PIN = GPIO
write( fd, smc_addr + PROGRAM_ADDRESS, 1);

if (hl)
*(volatile u8 *)(smc_addr + GPIO_LED_OFFSET) = 0x40; // LED OFF
else
*(volatile u8 *)(smc_addr + GPIO_LED_OFFSET) = 0x00; // LED ON
write( fd, smc_addr + GPIO_LED_OFFSET, 1);

if( munmap( psmc_addr, MAP_SIZE) == -1) {
perror( " Error un-mmapping the file");
}
close(fd);

return 0;
}


嵌入式系統 - uboot 相關



help 命令


IPQ6018# help
? - alias for 'help'
aq_load_fw- LOAD aq-fw-binary
aq_phy_restart- Restart Aquantia phy
base - print or set address offset
bdinfo - print Board Info structure
bootelf - Boot from an ELF image in memory
bootipq - bootipq from flash device
bootm - boot application image from memory
bootp - boot image via network using BOOTP/TFTP protocol
bootvx - Boot vxWorks from an ELF image
bootz - boot Linux zImage image from memory
canary - test stack canary
chpart - change active partition
cmp - memory compare
coninfo - print console devices and information
cp - memory copy
crc32 - checksum calculation
dhcp - boot image via network using DHCP/TFTP protocol
dm - Driver model low level access
echo - echo args to console
editenv - edit environment variable
env - environment handling commands
erase - erase FLASH memory
exectzt - execute TZT

exit - exit script
false - do nothing, unsuccessfully
fdt - flattened device tree utility commands
flash - flash part_name
flash part_name load_addr file_size

flasherase- flerase part_name

flinfo - print FLASH memory information
fuseipq - fuse QFPROM registers from memory

go - start application at address 'addr'
help - print command description/usage
i2c - I2C sub-system
imxtract- extract a part of a multi-image
ipq_mdio- IPQ mdio utility commands
is_sec_boot_enabled- check secure boot fuse is enabled or not

itest - return true/false on integer compare
loop - infinite loop on address range
md - memory display
mii - MII utility commands
mm - memory modify (auto-incrementing address)
mmc - MMC sub system
mmcinfo - display MMC info
mtdparts- define flash/nand partitions
mtest - simple RAM read/write test
mw - memory write (fill)
nand - NAND sub-system
nboot - boot from NAND device
nm - memory modify (constant address)
part - disk partition related commands
pci - list and access PCI Configuration Space
ping - send ICMP ECHO_REQUEST to network host
printenv- print environment variables
protect - enable or disable FLASH write protection
reset - Perform RESET of the CPU
run - run commands in an environment variable
runmulticore- Enable and schedule secondary cores
saveenv - save environment variables to persistent storage
secure_authenticate- authenticate the signed image

setenv - set environment variables
setexpr - set environment variable as the result of eval expression
sf - SPI flash sub-system
showvar - print local hushshell variables
sleep - delay execution for some time
smeminfo- print SMEM FLASH information
source - run script from memory
test - minimal test like /bin/sh
tftpboot- boot image via network using TFTP protocol
tftpput - TFTP put command, for uploading files to a server
tftpsrv - act as a TFTP server and boot the first received file
true - do nothing, successfully
tzt - load and run tzt

uart - UART sub-system
ubi - ubi commands
usb - USB sub-system
usbboot - boot from USB device
version - print monitor, compiler and linker version



常用指令


printenv // 列印環境變數
setenv ipaddr X.X.X.X // 設定環境變數 - 自己的 ip
serenv serverip X.X.X.X // 設定環變數 - tftp server ip
saveenv // 儲存環境變數

tftpboot file.img // 從指定的 tftp server 下載 file.img
flasherase rootfs // 清空 mtd 分區名稱為 rootfs 的分區
flash rootfs // file.img 寫入 mtd 分區名稱為 rootfs 的分區 (此命令已包含清空)

nand erase [0x4000000(目的位址)] [0x3f00000(長度)] // 清空位址內容
nand write [0x44000000(來源位址)] [0x4000000(目的位址)] [0x3f00000(長度)] // 寫入位址內容
nand read [目的位址] [來源位址] [長度] // 讀取位址內容
tftpput [來源位址] [長度] [tftpServer的檔名] // 上傳位址內容 (需在server端先建立好檔名,並給寫入權限)

bootm 0x44000000 // 直接跳到 0x44000000 的位址進行開機
bootm // 從預設位址開機 (通常是 0x44000000)
reset // 重開機

mw [位址] [] [長度] // 設定記憶體中的值
md [位址] [長度] // 讀取記憶體中的值


讀取"裝備樹" & 顯示文字 (轉成 dts 格式)

tftpboot ipq6018-cp01-c3.dtb
fdt addr 0x44000000
fdt header
fdt printer


從 u-boot 備份 mtd 分區

kernel 的 mtd 分區訊息

[ 1.533431] 0x000000000000-0x000000180000 : "0:SBL1"
[ 1.540837] 0x000000180000-0x000000280000 : "0:MIBIB"
...
[ 1.601482] 0x000000d00000-0x000007700000 : "rootfs"


命令
setenv ipaddr X.X.X.X // 設定自己的 ip
serenv serverip X.X.X.X // 設定 tftp server 的 ip

nand read 0x44000000 0 0x180000
tftpput 0x44000000 0x180000 mtd.p1

nand read 0x44000000 0x180000 0x100000
tftpput 0x44000000 0x100000 mtd.p2

// rttofs 太大了,要分兩次
nand read 0x44000000 0xd00000 0x3000000
tftpput 0x44000000 0x3000000 mtd.p14-1
nand read 0x44000000 0x3d00000 0x3A00000
tftpput 0x44000000 0x3A00000 mtd.p14-2



在 u-boot 指定 mtd 分區範例


setenv bootargs ubi.mtd=rootfs root=mtd:ubi_rootfs rootfstype=squashfs rootwait mtdparts="spi32766.0:640k(0:SBL1)ro,64k(0:MIBIB)ro,128k(0:BOOTCONFIG)ro,128k(0:BOOTCONFIG1)ro,1472k(0:QSEE)ro,64k(0:DEVCFG)ro,128k(0:RPM)ro,64k(0:CDT)ro,64k(0:APPSBLENV),640k(0:APPSBL)ro,256k(0:ART)ro,448k(flash)ro;qcom_nand.0:64M(rootfs_1),64M(rootfs)"
saveenv


在 kernel 指定 mtd 分區範例


在 kernel/drivers/of/fdt.c Func:early_init_dt_scan_chosen 裡的 bootargs-append & strlcat 之後,加入以下代碼:

if(!strstr((char *)data, "mtdparts")) {
    //char *my_bootargs = "ubi.mtd=rootfs root=mtd:ubi_rootfs rootfstype=squashfs rootwait mtdparts=\"spi32766.0:640k(0:SBL1)ro,64k(0:MIBIB)ro,128k(0:BOOTCONFIG),128k(0:BOOTCONFIG1),1472k(0:QSEE)ro,64k(0:DEVCFG)ro,128k(0:RPM)ro,64k(0:CDT)ro,64k(0:APPSBLENV),640k(0:APPSBL)ro,256k(0:ART)ro,448k(flash)ro;qcom_nand.0:64M(rootfs_1),64M(rootfs)\" swiotlb=1 coherent_pool=2M ";
    char *my_bootargs = "console=ttyMSM0,115200n8 cnss2.bdf_pci0=0xa0 ubi.mtd=rootfs root=mtd:ubi_rootfs rootfstype=squashfs rootwait mtdparts=\"qcom_nand.0:1536k(0:SBL1)ro,1024k(0:MIBIB)ro,512k(0:BOOTCONFIG)ro,512k(0:BOOTCONFIG1)ro,3584k(0:QSEE)ro,512k(0:DEVCFG)ro,512k(0:RPM)ro,512k(0:CDT)ro,512k(0:APPSBLENV)ro,1536k(0:APPSBL)ro,512k(0:ART)ro,1024k(hwconfig)ro,1024k(swconfig)ro,106M(rootfs),512k(0:ETHPHYFW)ro,64M(image)\" swiotlb=1 coherent_pool=2M ";
    strlcpy(data, my_bootargs, min((int)strlen(my_bootargs), COMMAND_LINE_SIZE));
}

分區大小內容要自行修改
(或者修改 kernel 的 .config 參數,也可達到效果。
在 [Boot options -> Default kernel command string] (CONFIG_CMDLINE))


在 u-boot 更新 openwrt XXXX-single.img 的下法


setenv ipaddr 192.168.1.1 // 自己的ip
setenv serverip 192.168.1.2 // tftp server 的 ip
setenv machid 8030002 // 非必要
set bootargs console=ttyMSM0,115200n8 // 非必要
tftpboot XXXX-single.img
imgaddr=$fileaddr && source $imgaddr:script
reset



走過的坑

原本以為mtd分區像下面這樣的,u-boot是可以燒失敗的。失敗之後在最前面的boot(SBL1)可以救得起來。

[ 1.527278] Creating 16 MTD partitions on "qcom_nand.0":
[ 1.533431] 0x000000000000-0x000000180000 : "0:SBL1"
[ 1.540837] 0x000000180000-0x000000280000 : "0:MIBIB"
[ 1.545288] 0x000000280000-0x000000300000 : "0:BOOTCONFIG"
[ 1.549853] 0x000000300000-0x000000380000 : "0:BOOTCONFIG1"
[ 1.555234] 0x000000380000-0x000000700000 : "0:QSEE"
[ 1.563234] 0x000000700000-0x000000780000 : "0:DEVCFG"
[ 1.565949] 0x000000780000-0x000000800000 : "0:RPM"
[ 1.570904] 0x000000800000-0x000000880000 : "0:CDT"
[ 1.575552] 0x000000880000-0x000000900000 : "0:APPSBLENV"
[ 1.580434] 0x000000900000-0x000000a80000 : "0:APPSBL" <<<<< 這裡是 u-boot
[ 1.586834] 0x000000a80000-0x000000b00000 : "0:ART"

但我把 openwrt 的 XXX-single.img 燒進 APPSBL 之後,就停在

Format: Log Type - Time(microsec) - Message - Optional Info
Log Type: B - Since Boot(Power On Reset), D - Delta, S - Statistic
S - QC_IMAGE_VERSION_STRING=BOOT.XF.0.3-00100-IPQ60xxLZB-1
S - IMAGE_VARIANT_STRING=IPQ6018LA
S - OEM_IMAGE_VERSION_STRING=crm-ubuntu124
S - Boot Interface: NAND
S - Secure Boot: Off
S - Boot Config @ 0x000a602c = 0x000002e5
S - JTAG ID @ 0x000a607c = 0x0013a0e1
S - OEM ID @ 0x000a6080 = 0x00000000
S - Serial Number @ 0x000a4128 = 0x51f6e1ae
S - OEM Config Row 0 @ 0x000a4188 = 0x0000000000000000
S - OEM Config Row 1 @ 0x000a4190 = 0x0000000000000000
S - Feature Config Row 0 @ 0x000a4130 = 0x0000000008000001
S - Feature Config Row 1 @ 0x000a4138 = 0x02c3e83383000009
S - PBL Patch Ver: 1
S - I-cache: On
S - D-cache: On
B - 3413 - PBL, Start
B - 592 - bootable_media_detect_entry, Start
B - 4339 - bootable_media_detect_success, Start
B - 5147 - elf_loader_entry, Start
B - 5319 - auth_hash_seg_entry, Start
B - 7786 - auth_hash_seg_exit, Start
B - 8283 - elf_segs_hash_verify_entry, Start
B - 103647 - elf_segs_hash_verify_exit, Start
B - 107839 - auth_xbl_sec_hash_seg_entry, Start
B - 107985 - auth_xbl_sec_hash_seg_exit, Start
B - 114537 - xbl_sec_segs_hash_verify_entry, Start
B - 114538 - xbl_sec_segs_hash_verify_exit, Start
B - 115468 - PBL, End
B - 97386 - SBL1, Start
B - 240279 - GCC [RstStat:0x0, RstDbg:0x600000] WDog Stat : 0x4
B - 242719 - clock_init, Start
D - 3751 - clock_init, Delta
B - 252296 - boot_flash_init, Start
D - 30378 - boot_flash_init, Delta
B - 284961 - sbl1_ddr_set_default_params, Start
D - 274 - sbl1_ddr_set_default_params, Delta
B - 291580 - boot_config_data_table_init, Start
D - 4941 - boot_config_data_table_init, Delta - (575 Bytes)
B - 301675 - CDT Version:2,Platform ID:8,Major ID:3,Minor ID:0,Subtype:2
B - 306250 - Image Load, Start
D - 6588 - OEM_MISC Image Loaded, Delta - (0 Bytes)
B - 315583 - Image Load, Start
D - 5063 - PMIC Image Loaded, Delta - (0 Bytes)
B - 323452 - sbl1_ddr_set_params, Start
B - 328454 - CPR configuration: 0x366
B - 331657 - Pre_DDR_clock_init, Start
D - 213 - Pre_DDR_clock_init, Delta
D - 0 - sbl1_ddr_set_params, Delta
B - 366732 - Image Load, Start
D - 518 - APDP Image Loaded, Delta - (0 Bytes)
B - 385245 - Image Load, Start
D - 519 - QTI_MISC Image Loaded, Delta - (0 Bytes)
B - 387777 - Image Load, Start
D - 885 - Auth Metadata
D - 671 - Segments hash check
D - 23668 - QSEE Dev Config Image Loaded, Delta - (37154 Bytes)
B - 413336 - Image Load, Start
D - 6619 - Auth Metadata
D - 10279 - Segments hash check
D - 362798 - QSEE Image Loaded, Delta - (1439116 Bytes)
B - 776652 - Image Load, Start
D - 702 - Auth Metadata
D - 1007 - Segments hash check
D - 36844 - RPM Image Loaded, Delta - (102800 Bytes)
B - 814868 - Image Load, Start
D - 30 - Auth

然後就沒有後續了...
我的變磚戰蹟又加一了......

所以 SBL1 並無法拯救壞掉的 u-boot,跟以前一樣不能用壞 u-boot ....



嵌入式系統 - ubi 相關



ubi 命令

   
ubinfo // (a tool to print UBI information.) 查資訊
ubidetach // (tool to remove UBI devices (detach MTD devices from UBI)) 卸載
ubiattach // (a tool to attach MTD device to UBI.) 加載
ubimkvol // (a tool to create UBI volumes.) 建立卷
ubirmvol // (a tool to remove UBI volumes.) 刪除卷
ubirsvol // (a tool to resize UBI volumes.) 變更卷的大小
ubiformat // (a tool to format MTD devices and flash UBI images) 重建整個ubi
ubiblock // (a tool to create/remove block device interface from UBI volumes.)
ubiupdatevol // (a tool to write data to UBI volumes.) 更新卷
ubinize // (a tool to generate UBI images.) 製作 ubi 分區檔案
ubicrc32 //
ubirename // 變更卷的名稱

 掛載 ubifs


mount -t ubifs ubi0_0 /mnt/ubi // ubi0_0, 第一個0是第幾個加載的ubi流水號, 第二個0是建立ubi檔案時的vol_id
mount -t ubifs ubi0:rootfs /mnt/ubi // ubi0:rootfs, 0是第幾個加載的ubi流水號, rootfs是建立ubi檔案時的vol_name



mtd 在 kernel 的訊息範例


[ 2.893251] nand: device found, Manufacturer ID: 0xc2, Chip ID: 0xaa
[ 2.896277] nand: ONFI 10-Compliant Macronix MX30UF2G18AC
[ 2.902682] nand: 256 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64
[ 2.915469] 16 cmdlinepart partitions found on MTD device qcom_nand.0
[ 2.918829] Creating 16 MTD partitions on "qcom_nand.0":
[ 2.925254] 0x000000000000-0x000000180000 : "0:SBL1"
[ 2.932702] 0x000000180000-0x000000280000 : "0:MIBIB"
[ 2.937205] 0x000000280000-0x000000300000 : "0:BOOTCONFIG"
[ 2.941754] 0x000000300000-0x000000380000 : "0:BOOTCONFIG1"
[ 2.947094] 0x000000380000-0x000000700000 : "0:QSEE"
[ 2.954870] 0x000000700000-0x000000780000 : "0:DEVCFG"
[ 2.957800] 0x000000780000-0x000000800000 : "0:RPM"
[ 2.962746] 0x000000800000-0x000000880000 : "0:CDT"
[ 2.967500] 0x000000880000-0x000000900000 : "0:APPSBLENV"
[ 2.972404] 0x000000900000-0x000000a80000 : "0:APPSBL"
[ 2.978693] 0x000000a80000-0x000000b00000 : "0:ART"
[ 2.982961] 0x000000b00000-0x000000c00000 : "hwconfig"
[ 2.988119] 0x000000c00000-0x000000d00000 : "swconfig"
[ 2.993344] 0x000000d00000-0x000007700000 : "rootfs"
[ 3.077346] mtd: device 13 (rootfs) set to be root filesystem
[ 3.077635] mtdsplit: no squashfs found in "rootfs"
[ 3.082091] 0x000007700000-0x000007780000 : "0:ETHPHYFW"
[ 3.087948] 0x000007780000-0x00000b780000 : "image"



使用的 Image.cfg


[kernel]
# Volume mode (other option is static)
mode=ubi
# Source image
image=arch/arm64/boot/Image.itb
vol_size=10MiB
# Volume ID in UBI image
vol_id=0
# Allow for dynamic resize
vol_type=dynamic
# Volume name
vol_name=kernel

[rootfs]
# Volume mode (other option is static)
mode=ubi
# Source image
image=rootfs.squashfs
# Volume ID in UBI image
vol_id=1
# Allow for dynamic resize
vol_type=dynamic
# Volume name
vol_name=ubi_rootfs

[config_data]
mode=ubi
# this is arbitrary, since autoresize below will use up the remaining
# free space on the mtd volume
vol_size=1KiB
vol_id=2
vol_type=dynamic
vol_name=config_data
vol_flags=autoresize



 /proc/mtd 的內容


# cat /proc/mtd
dev: size erasesize name
mtd0: 00180000 00020000 "0:SBL1"
mtd1: 00100000 00020000 "0:MIBIB"
mtd2: 00080000 00020000 "0:BOOTCONFIG"
mtd3: 00080000 00020000 "0:BOOTCONFIG1"
mtd4: 00380000 00020000 "0:QSEE"
mtd5: 00080000 00020000 "0:DEVCFG"
mtd6: 00080000 00020000 "0:RPM"
mtd7: 00080000 00020000 "0:CDT"
mtd8: 00080000 00020000 "0:APPSBLENV"
mtd9: 00180000 00020000 "0:APPSBL"
mtd10: 00080000 00020000 "0:ART"
mtd11: 00100000 00020000 "hwconfig"
mtd12: 00100000 00020000 "swconfig"
mtd13: 06a00000 00020000 "rootfs"
mtd14: 00080000 00020000 "0:ETHPHYFW"
mtd15: 04000000 00020000 "image"
mtd16: 00a0d000 0001f000 "kernel"
mtd17: 03013000 0001f000 "ubi_rootfs"
mtd18: 0273c000 0001f000 "config_data"
mtd19: 0386e000 0001f000 "rootfs_data"



手動重建ubi範例


ubidetach -f -p /dev/mtd15 // 卸載ubi
ubiformat /dev/mtd15 -y // 格式化ubi
ubiattach -p /dev/mtd15 // 加載ubi
ubimkvol /dev/ubi1 -m -N rootfs_data // 建立ubi卷
mount -t ubifs ubi1:rootfs_data /mnt/data // mount ubifs


更新ubi卷 (需要先 umount)


ubiupdatevol /dev/ubi1_0 /tmp/image.data // /tmp/image.data 寫入到第2個加載的ubivoi_id0的卷
ubiupdatevol /dev/ubi1_0 -t // 清除卷


更新整個ubi


ubiformat /dev/mtd15 -y -f /tmp/image.ubi // /tmp/image.ubi 寫入到 mtd15



ubinfo 範例


# ubinfo -d 0
ubi0
Volumes count: 3
Logical eraseblock size: 126976 bytes, 124.0 KiB
Total amount of logical eraseblocks: 848 (107675648 bytes, 102.7 MiB)
Amount of available logical eraseblocks: 0 (0 bytes)
Maximum count of volumes 128
Count of bad physical eraseblocks: 0
Count of reserved physical eraseblocks: 38
Current maximum erase counter value: 2
Minimum input/output unit size: 2048 bytes
Character device major/minor: 242:0
Present volumes: 0, 1, 2

# ubinfo -d 0 -n 0
Volume ID: 0 (on ubi0)
Type: dynamic
Alignment: 1
Size: 83 LEBs (10539008 bytes, 10.1 MiB)
State: OK
Name: kernel
Character device major/minor: 242:1

# ubinfo -d 0 -n 1
Volume ID: 1 (on ubi0)
Type: dynamic
Alignment: 1
Size: 397 LEBs (50409472 bytes, 48.1 MiB)
State: OK
Name: ubi_rootfs
Character device major/minor: 242:2

# ubinfo -d 0 -n 2
Volume ID: 2 (on ubi0)
Type: dynamic
Alignment: 1
Size: 324 LEBs (41140224 bytes, 39.2 MiB)
State: OK
Name: config_data
Character device major/minor: 242:3



※ 如果 u-boot 有自己mtd的切法,不要試著在 kernel 裡改變它。
     否則當你使用 ubiupdatevol 後,會無法開機。



附件一: Image.itb 的製作方法


// ipq6018-cp01-c3.its 檔案內容

/dts-v1/;

/ {
description = "ARM64 OpenWrt FIT (Flattened Image Tree)";
#address-cells = <1>;

images {
kernel@1 {
description = "ARM64 OpenWrt Linux-4.4.60";
data = /incbin/("Image.gz");
type = "kernel";
arch = "arm64";
os = "linux";
compression = "gzip";
load = <0x41080000>;
entry = <0x41080000>;
hash@1 {
algo = "crc32";
};
hash@2 {
algo = "sha1";
};
};

fdt@1 {
description = "ARM64 OpenWrt qcom-ipq6018-cp01-c3 device tree blob";
data = /incbin/("dts/qcom/qcom-ipq6018-cp01-c3.dtb");
type = "flat_dt";
arch = "arm64";
compression = "none";
hash@1 {
algo = "crc32";
};
hash@2 {
algo = "sha1";
};
};
};

configurations {
default = "config@cp01-c3";
config@cp01-c3 {
description = "OpenWrt";
kernel = "kernel@1";
fdt = "fdt@1";
};
};
};


mkimage -f ipq6018-cp01-c3.its Image.itb

(要先有正確的dtb、kernel 編譯出 Image.gz)
64位元的位址是:0x41080000
32位元的位址是:0x41008000


// dts & dtb 互轉
dtc -I dts -O dtb -o output.dtb ipq6018-cp01-c3.dts // dts -> dtb
dtc -I dtb -O dts -o output.dts ipq6018-cp01-c3.dtb // dtb -> dts



dumpimage -l Image.itb // 列出列表
dumpimage Image.itb -T flat_dt -p 0 -o output.1 // 從 .itb 匯出列表第一個檔案 (通常是 kernel)
dumpimage Image.itb -T flat_dt -p 1 -o output.2 // 從 .itb 匯出列表第二個檔案 (通常是 dtb)


附件二: rootfs.squashfs 的製作方法


mksquashfs4 src_dir dst_file -nopad -noappend -root-owned -comp xz -Xpreset 9 -Xe -Xlc 0 -Xlp 2 -Xpb 2 -b 256k -p '/dev d 755 0 0' -p '/dev/console c 600 0 0 5 1' -processors 1
padjffs2 dst_file 4 8 16 64 128 256
dd if=dst_file of=root.squashfs bs=2k conv=sync

讀取 src_dir 目錄,建立 root.squashfs (暫存檔案為 dst_file)

附件三:image.ubi 的製作方法


ubinize -m 2048 -p 128KiB -o Image.ubi Image.cfg


附件四:image.data 的製作方法


mkfs.ubifs -x lzo -m 2048 -e 126976 -c 466 -r ./src_dir -o dst_file

-e 的值可查詢 ubinfo -d 0 的 "Logical eraseblock size"
-c 的值可查詢 ubinfo -d 0 -n 0 的 "Size"
註:增加 -F 參數,可解決 ECC ERROR 的問題 (kernel 需要 3.0 以上)。


C - inet ntoa aton (網路轉換相關)




宣告及定義


#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int inet_aton(const char *cp, struct in_addr *inp); // 網路字串(char *cp)轉網路數值. 成功回傳1, 失敗回傳0
in_addr_t inet_addr(const char *cp); // 功能與 inet_aton 相同,但是失敗回傳的-1255.255.255.255衝突。所以改用 inet_aton
in_addr_t inet_network(const char *cp); // 功能與 inet_addr 相同,測試起來會數值會反轉

char *inet_ntoa(struct in_addr in); // 網路數值轉網路字串
struct in_addr inet_makeaddr(in_addr_t net, in_addr_t host); // net host 合併
in_addr_t inet_lnaof(struct in_addr in); // 回傳網路數值的低位元部份 (依網路位元組序)
in_addr_t inet_netof(struct in_addr in); // 回傳網路數值的高位元部份 (依網路位元組序)

// 數值定義
typedef uint32_t in_addr_t;
// 結構定義
struct in_addr {
in_addr_t s_addr;
};



範例


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char **argv) {
struct in_addr inp;
int ret;
ret = inet_aton("192.168.111.222", & inp);
printf("inet_aton => %x, %d\n", inp.s_addr, ret);
printf("inet_addr => %x\n", inet_addr("192.168.111.222"));
printf("inet_network => %x\n", inet_network("192.168.111.222"));
printf("\n");
printf("inet_ntoa => %s\n", inet_ntoa(inp));
printf("inet_lnaof => %x\n", inet_lnaof(inp));
printf("inet_netof => %x\n", inet_netof(inp));
printf("\n");
ret = inet_aton("172.16.111.222", & inp);
printf("inet_aton => %x, %d\n", inp.s_addr, ret);
printf("inet_lnaof => %x\n", inet_lnaof(inp));
printf("inet_netof => %x\n", inet_netof(inp));
printf("inet_makeaddr => %x\n", inet_makeaddr(0x1122, 0x3344).s_addr);
return 0;
}

===== 執行結果 ======================
inet_aton => de6fa8c0, 1
inet_addr => de6fa8c0
inet_network => c0a86fde

inet_ntoa => 192.168.111.222
inet_lnaof => de
inet_netof => c0a86f

inet_aton => de6f10ac, 1
inet_lnaof => 6fde
inet_netof => ac10
inet_makeaddr => 44332211



其他常用


#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong); // 用於本機序轉換到網路序
uint16_t htons(uint16_t hostshort); // 用於本機序轉換到網路序
uint32_t ntohl(uint32_t netlong); // 用於網路序轉換到本機序
uint16_t ntohs(uint16_t netshort); // 用於網路序轉換到本機序

在x86用起來就是反轉順序,如:htonl(0xaa11bb22) 執行結果為 0x22bb11aa

註:在 little-endian 上呼叫,結果會跟輸入值相同


其他範例


char *my_ipv4_broadcast(char *ip, char *netmask)
{
static char buffer[32];
in_addr_t _ip = inet_addr(ip);
in_addr_t _netmask = inet_addr(netmask);
struct in_addr _broadcast;

_broadcast.s_addr = _ip | ~_netmask;
sprintf(buffer, "%s", inet_ntoa(_broadcast));

return buffer;
}
char *my_ipv4_netid(char *ip, char *netmask)
{
static char buffer[32];
in_addr_t _ip = inet_addr(ip);
in_addr_t _netmask = inet_addr(netmask);
struct in_addr _netid;

_netid.s_addr = _ip & _netmask;
sprintf(buffer, "%s", inet_ntoa(_netid));

return buffer;
}