AM335X的SD卡更新系統學習記錄

通常利用一張SD卡就能進行系統的更新,之前一直不知是什麼原理,最近了解了下,對了解到的內容作個記錄。使用的是AM335X平臺,系統是Linux,文件系統是EXT3:編程

一、首先須要一張分好分區的SD卡(分區方法這裏不作詳細介紹,通常可以使用TI官方提供的create-sdcard.sh腳本能夠進行分區)。其中分區1(FAT32)存放MLO、u-boot.img、uImage三個文件;分區2(EXT3)存放須要從SD卡啓動的Linux文件系統。網絡

二、AM335X上電後,根據Boot Sequence啓動配置(LCD0-LCD15引腳,具體可參考TI官方的335X參考手冊),從相應的存儲設備啓動,這裏配置的是從SD卡啓動。app

三、AM335X上電後首先執行固化在芯片內部ROM中的代碼,咱們稱之爲BLO,BLO的功能很強大,能讀取SD卡中的第一個分區(必須是FAT格式)的MLO文件,複製到AM335X內部的RAM中吞下,複製的起始地址爲0x402f0400,因此編譯MLO時,鏈接地址必須設置爲0x402F0400。less

四、通常的,MLO的做用是:禁用中斷、關看門狗、設置棧、初始化時鐘、初始化DDR三、初始化串口、最後複製S卡中boot(FAT32)分區的u-boot.img到DDR3的0x80000000(內存)處運行。MLO的最大致積能夠達到109K,對於簡單的邏輯程序綽綽有餘了。工具

五、u-boot的功能主要是啓動內核:u-boot從SD卡的boot(FAT32)分區複製uImage到內存運行。post

六、啓動Linux後掛載SD卡的rootfs分區(EXT3)的文件系統ui

七、文件系統是利用Busybox工具集建立的,首先內核會啓動BusyBox裏的Init進程。init進程首先主要對/etc/inittab文件進行解析,而後按照它的指示建立各類子進程。this

八、inittab文件的內容主要如下幾部分。其中系統運行後最早執行的是/etc/rc.d/rcS進程,而且它只執行一次,其它進程只有等它執行完畢後才能運行,u-boot、內核、文件系統的燒寫在這裏執行。spa

1 ::sysinit:/etc/rc.d/rcS
2 ::respawn:/sbin/getty 9600 tty1
3 ::ctrlaltdel:/sbin/reboot
4 ::shutdown:/etc/rc.d/rcS stop
5 ::restart:/sbin/init

九、接着繼續看到/etc/rc.d/rcS文件,這是一個腳本文件,下面一一分析它作的工做rest

#!/bin/sh

# minimal startup script, will work with msh (this is best available in
# MMUless format).

mode=${1:-start}                           #若第一個參數存在,則mode的值爲第一個參數;不然mode等於start

# load the configuration information
if [ -x /etc/rc.d/rc.conf ]
then
    . /etc/rc.d/rc.conf                    #無論/etc/rc.d/rc.conf是否可執行,都去執行它,等價於sh /etc/rc.d/rc.conf
fi

if [ $mode = "start" ]                     #若mode的值爲start,
then
    services=$cfg_services                 #那麼services等於$cfg_services(這個值在/etc/rc.d/rc.conf中定義:"crond mount-proc-sys hostname depmod modules udev filesystems inetd"else
    services=$cfg_services_r               #不然services等於$cfg_services_r (這個值在/etc/rc.d/rc.conf中定義:"inetd filesystems udev modules depmod hostname mount-proc-sys crond")
fi
cfg_services=${2:-$services}               #若第二個參數存在,則cfg_services的值爲第二個參數;不然cfg_services等於services

# run the configured sequence              #按配置的順序,啓動各個進程
for i in $cfg_services
do
    if [ -x /etc/rc.d/init.d/$i ]             #若是進程是可執行的,那麼
    then
        echo "/etc/rc.d/init.d/"$i $mode      #打印進程信息
        /etc/rc.d/init.d/$i $mode             #挨個執行
    fi
done

if [ $# -ge 2 ]                              #若是參數個數大於等於2
then
    exit 0                                   #退出
fi
if [ $mode = "start" ]                       #若mode的值爲start,
then
    # show all kernel log messages
    if [ -x /proc/sys/kernel/printk ]        #若/proc/sys/kernel/printk可執行
    then
        #echo 8 >  /proc/sys/kernel/printk
        echo 0 >  /proc/sys/kernel/printk    #清空/proc/sys/kernel/printk
    fi

    # echo set kernel halt time
    echo -e "\033[9;0]" > /dev/tty0

    #echo Bringing lo up
    /sbin/ifconfig lo 127.0.0.1 up 2>/dev/null
    /sbin/route add -net 127.0.0.0 netmask 255.0.0.0 gw 127.0.0.1 dev lo 2>/dev/null

    #echo eth0 setting                              #網卡0設置
    if [ -x /etc/eth0-setting ]
    then
        echo "Found /etc/eth0-setting..."
        /etc/rc.d/ifconfig-eth0 /etc/eth0-setting   #在/etc/eth0-setting文件中配置IP、MASK、GATEWAY信息
    fi

    #echo eth1 setting                              #網卡1設置
    if [ -x /etc/eth1-setting ]
    then
        echo "Found /etc/eth1-setting..."
        /etc/rc.d/ifconfig-eth1 /etc/eth1-setting   #在/etc/eth1-setting文件中配置IP、MASK、GATEWAY信息
    fi

    #echo wlan0 setting                              #wlan0設置
    if [ -x /etc/wlan0-setting ]
    then
        echo "Found /etc/wlan0-setting..."
        wpa_supplicant -B -D wext -c /etc/wpa.conf -i wlan0
        wpa_cli add_network
        wpa_cli enable_network 0
        /etc/rc.d/ifconfig-wlan0 /etc/wlan0-setting
    fi

fi

# run rc.local if present and executable
if [ -x /etc/rc.d/rc.local ]                       #若是/etc/rc.d/rc.local可執行
then

    echo "Found /etc/rc.d/rc.local..." 
    /etc/rc.d/rc.local $mode                       #那麼,直接執行它。整個啓動腳本的重點在這裏,後面分析它
fi

# run startx if present and executable
if [ -x /usr/bin/startx ]
then
    if [ $mode = "start" ]
then
        rm /tmp/.X0-lock
        startx
    fi
fi

/etc/rc.d/rcS腳本能夠總結爲以下的功能:
a、配置腳本運行的環境變量,文件爲/etc/rc.d/rc.conf
b、運行系統服務進程:crond mount-proc-sys hostname depmod modules udev filesystems inetd
c、設置網絡IP/etc/rc.d/ifconfig-eth0 /etc/eth0-setting、/etc/rc.d/ifconfig-eth1 /etc/eth1-setting
d、運行/etc/rc.d/rc.local腳本程序

 

十、分析/etc/rc.d/rc.local start腳本程序

#!/bin/sh
mode=${1:-start}                              #mode等於傳入的參數1爲start
if [ $mode = "start" ]                        #若是mode的值等於start,那麼運行如下程序
then

#set sgtl5000 volume 0~127
amixer cset numid=5 65                        #猜想是設置蜂鳴器音量,還不肯定

echo "start format board mmc..."
echo 1 > /sys/class/leds/user_buzzer/brightness   #打開蜂鳴器,說明開始運行此腳本更新系統

/etc/rc.d/spi.sh                                  #運行/etc/rc.d/spi.sh腳本,把/boot/u-boot.spi.512拷貝到Flash中,之後程序今後處取出u-boot運行
    如下爲/etc/rc.d/spi.sh腳本內容:
        #!/bin/sh

        echo "****************************************************"
        echo "****************************************************"
        echo ""
        echo " Hua Ming spi Flashing Script - 01/01/2015"
        echo ""

        echo "erase spi flash..."
        flash_erase /dev/mtd0 0 8

        echo "write boot/u-boot.spi.512 ..."
        flashcp /boot/u-boot.spi.512 /dev/mtd0
        echo "done"    

/etc/rc.d/mmc.sh /dev/mmcblk1               #運行/etc/rc.d/mmc.sh腳本對mmc以ext3文件系統格式進行分區,分爲4個區分別爲sys、opt、user、Reserved。

mount /dev/mmcblk1p1 /mnt                   #掛接sys分區,將rfs_335x.tar.gz的文件進行解壓縮,裏面存放了最小根文件系統
cd /mnt
tar -xzvf ../rfs_335x.tar.gz

mount /dev/mmcblk1p2 /mnt/opt               #掛接opt分區,將HmReader.tar.gz解壓縮,裏面存放了應用程序
tar -xzvf ../../HmReader.tar.gz

cd boot
ln -s boot.scr.mmc1 boot.scr

sync

echo 0 > /sys/class/leds/user_buzzer/brightness    #蜂鳴器關閉
echo "format finished ..."                         #格式化結束,更新完成

fi

/etc/rc.d/rc.local start腳本程序功能總結以下:
一、將/boot/u-boot.spi.512拷貝到Flash中,在從spi啓動時啓動u-boot。
二、對MMC1進行分區,分爲四個區分別爲sys、opt、user、Reserved
三、將最小根文件系統解壓縮到sys分區
四、將應用程序解壓縮到opt分區

 

十一、對/etc/rc.d/mmc.sh腳本的分析:

#!/bin/sh

echo "****************************************************"
echo "****************************************************"
echo ""
echo " Hua Ming Example Flashing Script - 01/01/2015"
echo ""

if [[ -z $1 ]]                #若是傳入腳本的參數1不存在的話
then
        echo "mmc.sh Usage:"
        echo "  mmc.sh <Dev>"
        echo "  Example: mmc.sh /dev/mmcblk0"
        exit                    #退出腳本
fi

STARTTIME=$(date +%s)            #得到當前時間

##---------Start of variables---------------------##

## Declare eMMC device name here
#DRIVE="/dev/mmcblk0"
DRIVE=$1                    #DRIVE=/dev/mmcblk1

##----------End of variables-----------------------##

## Kill any partition info that might be there
dd if=/dev/zero of=$DRIVE bs=4k count=1    #猜想是清除設備原有的分區
sync
sync                                       #立刻寫入設備

## Figure out how big the eMMC is in bytes
SIZE=`fdisk -l $DRIVE | grep Disk | awk '{print $5}'`    #算出塊設備的大小(以字節爲單位)

## Translate size into segments, which traditional tools call Cylinders. eMMC is not a spinning disk.
## We are basically ignoring what FDISK and SFDISK are reporting because it is not really accurate.
## we are translating this info to something that makes more sense for eMMC.
CYLINDERS=`echo $SIZE/255/63/512 | bc`    #做數學運算算出一個柱面的大小

## Check to see if the eMMC partitions have automatically loaded from the old MBR.
## This might have occured during the boot process if the kernel detected a filesystem
## before we killed the MBR. We will need to unmount and kill them by writing 4k zeros to the
## partitions that were found.
#檢查是否已經被掛載,而且已經分區。如有,則清除

check_mounted(){
  is_mounted=$(grep ${DRIVE}p /proc/mounts | awk '{print $2}')

  if grep -q ${DRIVE}p /proc/mounts; then
      echo "Found mounted partition(s) on " ${DRIVE}": " $is_mounted
      umount $is_mounted
      counter=1
      for i in $is_mounted; do \
          echo "4k erase on ${DRIVE}p${counter}"; 
          dd if=/dev/zero of=${DRIVE}p${counter} bs=4k count=1;
          counter=$((counter+1));
      done
  else
      echo "No partition found. Continuing."
  fi
}

check_mounted;

## Partitioning the eMMC using information gathered.
## Here is where you can add/remove partitions.
## We are building 2 partitions:
##  1. FAT, size = 9 cylinders * 255 heads * 63 sectors * 512 bytes/sec = ~70MB
##  2. EXT3, size = 223 ($CYLINDERS-[9 for fat]) cylinders * 255 heads * 63 sectors * 512 bytes/sec = ~1l.7GB
##
## You will need to change the lines ",9,0c0C,*", "10,,,-" to suit your needs.  Adding is similar,
## but you will need to be aware of partition sizes and boundaries.  Use the man page for sfdisk.
echo "Partitioning the eMMC..."
sfdisk -D -H 255 -S 63 -C $CYLINDERS $DRIVE << EOF
,65,0x0c,*
65,65,,-
130,130,,-
260,,,-
EOF

## This sleep is necessary as there is a service which attempts
## to automount any filesystems that it finds as soon as sfdisk
## finishes partitioning.  We sleep to let it run.  May need to
## be lengthened if you have more partitions.
sleep 2

## Check here if there has been a partition that automounted.
##  This will eliminate the old partition that gets
##  automatically found after the sfdisk command.  It ONLY
##  gets found if there was a previous file system on the same
##  partition boundary.  Happens when running this script more than once.
##  To fix, we just unmount and write some zeros to it.
check_mounted;

## Clean up the dos (FAT) partition as recommended by SFDISK
#dd if=/dev/zero of=${DRIVE}p1 bs=512 count=1

## Make sure posted writes are cleaned up
sync
sync

## Format the eMMC into 2 partitions
echo "Formatting the eMMC into 4 partitions..."

mkfs.ext3 -L "sys" ${DRIVE}p1
mkfs.ext3 -L "opt" ${DRIVE}p2
mkfs.ext3 -L "user" ${DRIVE}p3
mkfs.ext3 -L "Reserved" ${DRIVE}p4

## Make sure posted writes are cleaned up
sync
sync
echo "Formatting done."            #格式化完成

## The block below is only necessary if using 'dd'. 
## Force check the filesystem for consistency and fix errors if any.
## Resize partition to the length specified by the MBR.
## /sbin/e2fsck -fy ${DRIVE}p2
## /sbin/resize2fs ${DRIVE}p2

ENDTIME=$(date +%s)
echo "It took $(($ENDTIME - $STARTTIME)) seconds to complete this task..."    #計算格式化EMMC花了多長時間
## Reboot
echo ""
echo "********************************************"
echo " Hua Ming  Example Flash Script is complete."
echo ""

總結爲以ext3文件系統格式對MMC進行分區,分爲4個區分別爲sys、opt、user、Reserved。其中sys存放最小根文件系統,opt存放應用程序,後續能夠對它單獨進行更新。

 

十二、到這裏全部系統更新完成,拔掉SD卡,從新上電後根據Boot Sequence啓動配置(LCD0-LCD15引腳,具體可參考TI官方的335X編程手冊),從相應的存儲設備啓動,這裏配置的是SPI接口的Flash啓動。說啓動可能不許確,實際上是內部的ROM從SPI的flash中拷貝鏡像到RAM中運行。而後啓動u-boot,u-boot啓動後會從MMC的/sys分區的/boot目錄下取出uImage鏡像再到RAM中運行,接着Linux系統掛接到/sys系統。而後整個系統正常運行。

相關文章
相關標籤/搜索