在Linux運行期間升級Linux系統(Uboot+kernel+Rootfs)

版本:v1.2html

 

Crifan Li

摘要linux

本文主要介紹瞭如何在嵌入式Linux系統運行的時候,進行升級整個Linux系統,包括uboot,kernel和rootfs。以及簡介Linux中的已有的通用的Nor Flash驅動m25p80,和簡介mtd util以及相關工具mtdinfo,flash_erase,flash_eraseall,nanddump,nandwrite等的基本用法。git

[提示] 本文提供多種格式供:
在線閱讀 HTML HTMLs PDF CHM TXT RTF WEBHELP
下載(7zip壓縮包) HTML HTMLs PDF CHM TXT RTF WEBHELP

HTML版本的在線地址爲:web

http://www.crifan.com/files/doc/docbook/runtime_upgrade_linux/release/html/runtime_upgrade_linux.html框架

有任何意見,建議,提交bug等,都歡迎去討論組發帖討論:electron

http://www.crifan.com/bbs/categories/runtime_upgrade_linux/編輯器

2012-11-17函數

修訂歷史
修訂 1.0 2011-05-03 crl
  1. 介紹瞭如何實如今線升級linux系統,即uboot,kernel,rootfs, 以及相關的前提知識和準備工做
修訂 1.2 2012-11-17 crl
  1. 經過Docbook發佈
  2. 添加了各章節的id
  3. 建議掛載文件到ramdisk中

插圖清單

1.1.  Linux系統中的Nand MTD分區

正文以前

1. 此文目的

目前嵌入式Linux系統的升級,即升級uboot,kernel,rootfs等,的傳統的方式,都是用燒寫工具去燒寫,相對來講,顯得很繁瑣和效率比較低,而利用mtd工具的方式去升級系統,相對比較方便。

此文主要就是介紹,在嵌入式Linux系統下,已經實現了nand和(或)nor flash驅動後,如何利用mtd工具,進行實時(runtime)/在線(online)的狀況下,升級Linux系統。

2. 一點說明

  1. 本文所寫內容,主要是以前的一些相關的工做總結,若是內容有誤,請及時告知:admin (at) crifan.com

    其餘技術問題的探討,任何的問題,意見,建議等,都歡迎郵件交流。

  2. 另外,若是須要的mtd-utils-1.3.1的源碼的話,也能夠發郵件索取。

  3. 有此文相關的有兩個附件:

    • compiled_mtd-utils_arm.7z

      已經編譯好了的arm平臺的,包含了u32和u64版本的,本文所用到的那4個mtd 的工具,即flash_erase,flash_eraseall,nanddump,nandwrite。

    • mtd-utils-1.3.1_support_u32u64.7z

      我以前所用的mtd util的源碼。你若是是其餘平臺的,那麼用此源碼,能夠本身編譯出對應的mtd的一系列的工具。關於如何編譯,請參考Readme文件。

第 1 章 嵌入式系統中,如何在Linux運行的時候去升級Linux系統

摘要

1.1. 前提

簡單點說,在利用mtd工具升級系統以前,須要你的嵌入式linux自己具有必定條件。下面依次介紹這些前提條件。

1.1.1. Linux中已經實現Nor Flash驅動

常見的嵌入式系統,都是從nor flash啓動,而後對應的uboot是放在nor flash裏面的。

通常nor flash,容量相對較小,只有512KB等,有的大的一點的是1MB,2MB之類的。

通常的狀況是,uboot大約有200多KB,而linux的kernel鏡像文件,好比我遇到過的,大約在1M左右。

因此,對於這些稍微大一些的Nor Flash,每每除了放了uboot的代碼以外,還能夠放linux的kernel。

若是是小的Nor Flash,那麼每每是把kernel放在Nand Flash的某個分區。

而此處用mtd工具升級linux的前提之一,是你linux系統中,已經實現了對應的nand flash的驅動。而對於nor flash驅動的話,若是尚未實現對應驅動,那麼就先去實現對應的nor flash驅動。

下面這裏只是對於如何實現普通的nor flash驅動,就我接觸到的相關內容,給出一些提示。

對於常見的spi接口的nor flash來講,若是你的nor flash型號是常見的型號,那麼極可能你不用另外單獨再本身徹底從頭寫一個完整的nor flash驅動了。

關於不一樣的接口的Nor Flash之間的區別,不瞭解的能夠參考:CFI Flash, JEDEC Flash ,Parellel Flash, SPI Flash, Nand Flash,Nor Flash的區別和聯繫CFI(Common Flash Interface)詳解

由於,每每你的linux中已經實現了spi驅動的,因此此時,你只須要作下面兩件事情,一個是在板子相關部分,添加對應nor flash對應的初始化代碼,二是利用linux默認自帶的,對於常見nor flash都已經默認支持的nor flash驅動:m25p80.c

下面分別詳細解釋。

1.1.1.1. 在開發板相關部分添加對應nor flash初始化相關代碼

此處,只是簡單介紹一下,我以前所遇到的一個nor flash驅動,是如何作的。

關於添加nor flash初始化的代碼,其實很簡單,就是在開發板的最核心的那個文件(此處以arm系統爲例):

linux-2.6.28.4\arch\arm\mach-XXX\core.c

中,添加相似於這樣的代碼:

static const struct spi_board_info const XXX_spi_devices[] = {
	{			/* SSP NOR Flash chip */
	 .modalias = "ssp_nor",
	 .chip_select = XXX_SPI_NOR_CS,
	 .max_speed_hz = 20 * 1000 * 1000,
	 .bus_num = 1,
	 },
......
};
            

而後在本身開發板設備初始化的部分,添加對應spi nor設備的註冊函數:

spi_register_board_info(XXX_spi_devices,	 ARRAY_SIZE(XXX_spi_devices));

以實現對應的spi接口的nor flash設備的註冊和添加。

具體內部邏輯是如何實現的,就要本身去看代碼了。

此處只是給個框架,告訴你大概是怎麼去實現的,具體的實現,確定要你本身去看代碼搞懂。

1.1.1.2. Linux通用nor flash驅動m25p80.c簡介

在spi接口的nor flash設備註冊部分搞定後,再來看Linux中的,默認已經幫咱們實現好了的一個通用的nor flash的驅動。

具體的文件是:

linux-2.6.28.4\drivers\mtd\devices\m25p80.c

其中,對於支持的設備,能夠去看源碼中的設備列表部分的代碼:

/* NOTE: double check command sets and memory organization when you add
 * more flash chips.  This current list focusses on newer chips, which
 * have been converging on command sets which including JEDEC ID.
 */
static struct flash_info __devinitdata m25p_data [] = {

	/* Atmel -- some are (confusingly) marketed as "DataFlash" */
	{ "at25fs010",  0x1f6601, 0, 32 * 1024, 4, SECT_4K, },
	{ "at25fs040",  0x1f6604, 0, 64 * 1024, 8, SECT_4K, },

	{ "at25df041a", 0x1f4401, 0, 64 * 1024, 8, SECT_4K, },
	{ "at25df641",  0x1f4800, 0, 64 * 1024, 128, SECT_4K, },

	{ "at26f004",   0x1f0400, 0, 64 * 1024, 8, SECT_4K, },
	{ "at26df081a", 0x1f4501, 0, 64 * 1024, 16, SECT_4K, },
	{ "at26df161a", 0x1f4601, 0, 64 * 1024, 32, SECT_4K, },
	{ "at26df321",  0x1f4701, 0, 64 * 1024, 64, SECT_4K, },

	/* Spansion -- single (large) sector size only, at least
	 * for the chips listed here (without boot sectors).
	 */
	{ "s25sl004a", 0x010212, 0, 64 * 1024, 8, },
	{ "s25sl008a", 0x010213, 0, 64 * 1024, 16, },
	{ "s25sl016a", 0x010214, 0, 64 * 1024, 32, },
	{ "s25sl032a", 0x010215, 0, 64 * 1024, 64, },
	{ "s25sl064a", 0x010216, 0, 64 * 1024, 128, },
        { "s25sl12800", 0x012018, 0x0300, 256 * 1024, 64, },
	{ "s25sl12801", 0x012018, 0x0301, 64 * 1024, 256, },

	/* SST -- large erase sizes are "overlays", "sectors" are 4K */
	{ "sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K, },
	{ "sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K, },
	{ "sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K, },
	{ "sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K, },

	/* ST Microelectronics -- newer production may have feature updates */
	{ "m25p05",  0x202010,  0, 32 * 1024, 2, },
	{ "m25p10",  0x202011,  0, 32 * 1024, 4, },
	{ "m25p20",  0x202012,  0, 64 * 1024, 4, },
	{ "m25p40",  0x202013,  0, 64 * 1024, 8, },
	{ "m25p80",         0,  0, 64 * 1024, 16, },
	{ "m25p16",  0x202015,  0, 64 * 1024, 32, },
	{ "m25p32",  0x202016,  0, 64 * 1024, 64, },
	{ "m25p64",  0x202017,  0, 64 * 1024, 128, },
	{ "m25p128", 0x202018, 0, 256 * 1024, 64, },

	{ "m45pe80", 0x204014,  0, 64 * 1024, 16, },
	{ "m45pe16", 0x204015,  0, 64 * 1024, 32, },

	{ "m25pe80", 0x208014,  0, 64 * 1024, 16, },
	{ "m25pe16", 0x208015,  0, 64 * 1024, 32, SECT_4K, },

	/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
	{ "w25x10", 0xef3011, 0, 64 * 1024, 2, SECT_4K, },
	{ "w25x20", 0xef3012, 0, 64 * 1024, 4, SECT_4K, },
	{ "w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K, },
	{ "w25x80", 0xef3014, 0, 64 * 1024, 16, SECT_4K, },
	{ "w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K, },
	{ "w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K, },
	{ "w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K, },
};
            

若是要添加此驅動,以實現支持咱們的通用的nor flash,則在make menuconfig的時候,添加對應設備的支持便可。

對應選項的kconfig的配置內容在:

linux-2.6.28.4\drivers\mtd\devices\kconfig

中:

config MTD_M25P80
	tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)"
	depends on SPI_MASTER && EXPERIMENTAL
	help
	  This enables access to most modern SPI flash chips, used for
	  program and data storage.   Series supported include Atmel AT26DF, Spansion S25SL, SST 25VF, ST M25P, and Winbond W25X.  Other chips
	  are supported as well.  See the driver source for the current list,
	  or to add other chips.

	  Note that the original DataFlash chips (AT45 series, not AT26DF),
	  need an entirely different driver.

	  Set up your spi devices with the right board-specific platform data,
	  if you want to specify device partitioning or to use a device which
	  doesn't support the JEDEC ID instruction.
            

如上所述,若是這些步驟都作完了,最後新編譯生成的linux內核,運行後,就應該能夠能夠經過:

cat /proc/mtd

查看到對應的mtd設備了。若是沒有,那麼說明你的驅動仍是沒有添加正常。

1.1.2. Linux中已實現了U盤掛載,以方便拷貝要升級的文件

簡單來講就是,你的linux系統中已經有了USB驅動,而且已經實現了USB的gadget或者USB File storage,即實現了U盤的掛載。

有了U盤掛載,每次升級系統文件,包括uboot,kernel的uImage,rootfs等文件的話,就很方便了。

具體如何實現,不是本文所能說得清楚的,因此再也不多贅述。

對於新的Linux內核,在已經實現了USB device驅動的前提下,如何實現U盤的功能,能夠參考這個:在Linux USB Gadget下使用U盤

1.1.3. Linux中Nor Flash和Nand Flash已能正常工做

要用mtd工具升級系統以前,確定是對應的nand flash以及nor flash都是已經正常工做了。即,除了系統正常運行外,經過:

cat /proc/mtd

能夠看到對應的nor和nand的flash所對應的分區信息了。

1.1.4. 已經準備好了mtd工具

此處所說的準備好了mtd的工具,即編譯好了某個版本的mtd-utils,好比mtd-utils-1.3.1,而後獲得對應的可執行的一系列的工具,其中這幾個是用獲得的:

表 1.1. MTD工具簡介

MTD工具名稱 功能簡介
flash_erase 擦除(nand或nor)flash的某個部分
flash_eraseall 擦除整個mtd的分區(某個nor或nand分區)
nanddump 用於查看當前某個mtd分區的數據(nand的話,也支持顯示oob數據)
nandwrite 用於將某個文件/數據,寫入到某個mtd分區(的某個位置)

其中,對於如何獲得mtd-util的這些工具,有兩種辦法:

  • 一種是你自己用的buildroot編譯的整個rootfs,這時候,能夠在配置裏面選擇上mtd-util的工具,這樣生成的出來的rootfs,就有了對應的mtd-util的一系列工具。
  • 另外一種是,本身去mtd官網下載對應的mtd-util的源碼,而後本身編譯生成對應的mtd-util的工具。

兩種方法,都很簡單,只是提醒一下,編譯的話,確定是用交叉編譯器,而不是X86的PC上的編輯器去編譯,呵呵。

1.1.4.1. mtd-util簡介

mtd-util,即mtd的utilities,是mtd相關的不少工具的總稱,包括經常使用的mtdinfo,flash_erase, flash_eraseall, nanddump, nandwrite等,每個工具,基本上都對應着一個同文件名的C文件。

mtd-util,由mtd官方維護更新,開發這一套工具,目的是爲了Linux的MTD層提供一系列工具,方便管理維護mtd分區。

mtd工具對應的源碼,叫作mtd-utils,隨着時間更新,發佈了不少版本。

我以前用到的版本是mtd-utils-1.3.1,截止2011-05-01,最新版本到了v1.4.1。

mtd-util源碼的下載地址,請去MTD源碼的官網

另外多說一句,MTD的官網,資料很豐富,感興趣的本身去看:

[注意] linux的mtd要和mtd-util中的一致

不過,對於以前的版本的Linux的kernel來講,使用mtd-util的話,必定要配套,主要是後來新的linux的版本,開始支持mtd的大小,即nand的大小,大於4GB,對應的linux內核中的mtd層的有些變量,就必須從u32升級成u64,才能夠支持。

對應的mtd的util中一些變量,也是要和你當前linux版本的mtd匹配。

簡單說就是,不管你用哪一個版本的Linux內核,若是要去用mtd-util的話,那麼二者的版本要一直,即查看linux內核中的mtd的一些頭文件,主要是include\mtd\mtd-abi.h和你的mtd-util中的include\mtd\mtd-abi.h,兩個要一致。

不然,就會出現我以前遇到的問題,固然linux內核是u64版本的,支持nand flash大於4GB的,而用的mtd-util中的變量的定義,卻仍是u32,因此確定會出錯的。

爲了同一套mtd-util工具即支持u32又支持u64,我定義了一個宏來切換,下面貼出來,供須要的人蔘考:

加了宏以支持u32和u64的mtd-abi.h文件

mtd-util中的include\mtd\mtd-abi.h:

/*
 * Portions of MTD ABI definition which are shared by kernel and user space
 */

#ifndef __MTD_ABI_H__
#define __MTD_ABI_H__

#include <linux/types.h>

/* from u32 to u64 to support >4GB */
#define U64_VERSION   		  1

struct erase_info_user {
#if U64_VERSION
	__u64 start;
	__u64 length;
#else
	__u32 start;
	__u32 length;
#endif
};

struct mtd_oob_buf {
#if U64_VERSION
	__u64 start;
#else
	__u32 start;
#endif
	__u32 length;
	unsigned char __user *ptr;
};

#define MTD_ABSENT		0
#define MTD_RAM			1
#define MTD_ROM			2
#define MTD_NORFLASH		3
#define MTD_NANDFLASH		4
#define MTD_DATAFLASH		6
#define MTD_UBIVOLUME		7

#define MTD_WRITEABLE		0x400	/* Device is writeable */
#define MTD_BIT_WRITEABLE	0x800	/* Single bits can be flipped */
#define MTD_NO_ERASE		0x1000	/* No erase necessary */
#define MTD_STUPID_LOCK		0x2000	/* Always locked after reset */

// Some common devices / combinations of capabilities
#define MTD_CAP_ROM		0
#define MTD_CAP_RAM		(MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)
#define MTD_CAP_NORFLASH	(MTD_WRITEABLE | MTD_BIT_WRITEABLE)
#define MTD_CAP_NANDFLASH	(MTD_WRITEABLE)

/* ECC byte placement */
#define MTD_NANDECC_OFF		0	// Switch off ECC (Not recommended)
#define MTD_NANDECC_PLACE	1	// Use the given placement in the structure (YAFFS1 legacy mode)
#define MTD_NANDECC_AUTOPLACE	2	// Use the default placement scheme
#define MTD_NANDECC_PLACEONLY	3	// Use the given placement in the structure (Do not store ecc result on read)
#define MTD_NANDECC_AUTOPL_USR 	4	// Use the given autoplacement scheme rather than using the default

#define MTD_MAX_OOBFREE_ENTRIES	8

/* This constant declares the max. oobsize / page, which
 * is supported now. If you add a chip with bigger oobsize/page
 * adjust this accordingly.
 */
#define MTD_NAND_MAX_PAGESIZE	8192
/*
 * for special chip, page/oob is 4K/218,
 * so here alloc more than 256+256 for 8192 pagesize for future special chip like that
 */
#define MTD_NAND_MAX_OOBSIZE		(256 + 256)

/* OTP mode selection */
#define MTD_OTP_OFF		0
#define MTD_OTP_FACTORY	1
#define MTD_OTP_USER		2

struct mtd_info_user {
	__u8 type;
	__u32 flags;
#if U64_VERSION
	__u64 size;	 // Total size of the MTD
#else
	__u32 size;	 // Total size of the MTD
#endif
	__u32 erasesize;
	__u32 writesize;
	__u32 oobsize;   // Amount of OOB data per block (e.g. 16)
	/* The below two fields are obsolete and broken, do not use them
	 * (TODO: remove at some point) */
	__u32 ecctype;
	__u32 eccsize;
};

struct region_info_user {
#if U64_VERSION
	__u64 offset;		/* At which this region starts,
					 * from the beginning of the MTD */
#else
	__u32 offset;		/* At which this region starts,
					 * from the beginning of the MTD */
#endif
	__u32 erasesize;		/* For this region */
	__u32 numblocks;		/* Number of blocks in this region */
	__u32 regionindex;
};

struct otp_info {
	__u32 start;
	__u32 length;
	__u32 locked;
};

#define MEMGETINFO		_IOR('M', 1, struct mtd_info_user)
#define MEMERASE		_IOW('M', 2, struct erase_info_user)
#define MEMWRITEOOB		_IOWR('M', 3, struct mtd_oob_buf)
#define MEMREADOOB		_IOWR('M', 4, struct mtd_oob_buf)
#define MEMLOCK			_IOW('M', 5, struct erase_info_user)
#define MEMUNLOCK		_IOW('M', 6, struct erase_info_user)
#define MEMGETREGIONCOUNT	_IOR('M', 7, int)
#define MEMGETREGIONINFO	_IOWR('M', 8, struct region_info_user)
#define MEMSETOOBSEL		_IOW('M', 9, struct nand_oobinfo)
#define MEMGETOOBSEL		_IOR('M', 10, struct nand_oobinfo)
#define MEMGETBADBLOCK		_IOW('M', 11, __kernel_loff_t)
#define MEMSETBADBLOCK		_IOW('M', 12, __kernel_loff_t)
#define OTPSELECT		_IOR('M', 13, int)
#define OTPGETREGIONCOUNT	_IOW('M', 14, int)
#define OTPGETREGIONINFO	_IOW('M', 15, struct otp_info)
#define OTPLOCK			_IOR('M', 16, struct otp_info)
#define ECCGETLAYOUT		_IOR('M', 17, struct nand_ecclayout)
#define ECCGETSTATS		_IOR('M', 18, struct mtd_ecc_stats)
#define MTDFILEMODE		_IO('M', 19)
/*
 * set/clear prepare oob support
 * usage:
 * 1. set prep_oob_support
 * 2. call write_oob will only prepare, not actually write
 * 3. clear prep_oob_support 
 * 4. write_page will use the previously prepared oob buffer, then clear it automatically
 */
#define SETPREPAREOOB		_IOWR('M', 20, int)
#define CLEARPREPAREOOB	_IOWR('M', 21, int)

/*
 * Obsolete legacy interface. Keep it in order not to break userspace
 * interfaces
 */
struct nand_oobinfo {
	__u32 useecc;
	__u32 eccbytes;
	__u32 oobfree[MTD_MAX_OOBFREE_ENTRIES][2];
	__u32 eccpos[MTD_NAND_MAX_OOBSIZE];
};

struct nand_oobfree {
	__u32 offset;
	__u32 length;
};

/*
 * ECC layout control structure. Exported to userspace for
 * diagnosis and to allow creation of raw images
 */
struct nand_ecclayout {
	__u32 eccbytes;
	__u32 eccpos[MTD_NAND_MAX_OOBSIZE];
	__u32 oobavail;
	struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
};

/**
 * struct mtd_ecc_stats - error correction stats
 *
 * @corrected:	number of corrected bits
 * @failed:	number of uncorrectable errors
 * @badblocks:	number of bad blocks in this partition
 * @bbtblocks:	number of blocks reserved for bad block tables
 */
struct mtd_ecc_stats {
	__u32 corrected;
	__u32 failed;
	__u32 badblocks;
	__u32 bbtblocks;
};

/*
 * Read/write file modes for access to MTD
 */
enum mtd_file_modes {
	MTD_MODE_NORMAL = MTD_OTP_OFF,
	MTD_MODE_OTP_FACTORY = MTD_OTP_FACTORY,
	MTD_MODE_OTP_USER = MTD_OTP_USER,
	MTD_MODE_RAW,
};

#endif /* __MTD_ABI_H__ */
                

1.1.4.2. mtd中的/dev/mtdN與/dev/mtdblockN的區別

簡單說就是:

  • /dev/mtdN

    某個字符設備,對應的mtd的util,就是對其操做,實現對對應的mtd分區進行管理的。

  • /dev/mtdblockN

    某個塊設備,能夠直接像操做其餘塊設備同樣來操做此塊設備,好比直接cat數據進去等等常見的操做。

更加詳細的解釋,請去看這個帖子:

Linux系統中/dev/mtd與/dev/mtdblock的區別,即MTD字符設備和塊設備的區別

1.2. 準備工做

1.2.1. 準備好要升級的文件

將你新編譯和製做出來的,要升級的文件準備好,此處爲:

表 1.2. 要升級的Linux系統的文件

文件 文件名 說明
uboot文件 u-boot.bin 只是一個普通的二進制文件
linux的kernel文件 uImage 也是一個普通的二進制文件
rootfs文件 rootfs.4k.arm.yaffs2 是用mkyafffs2工具製做而成,內部數據格式是page數據+oob數據+page數據+oob數據+......,用於燒寫到Nand Flash中

1.2.2. 拷貝文件並掛載分區

此處,個人系統的U盤,是掛載在/dev/mtdblock4中。

因此,先要經過掛載/dev/mtdblock4,即Data分區,做爲U盤到PC上,

拷貝要升級的文件和util文件夾及其下面的工具:

nandwrite,flash_erase,flash_eraseall,nanddump

到U盤上,而後彈出U盤,以後將/dev/mtdblock4掛載到/mnt/dos下

此時,/mnt/dos下就該有

  • u-boot.bin
  • uImage
  • rootfs.4k.arm.yaffs2
  • util/

1.3. 利用mtd工具升級Linux系統

利用mtd工具升級系統,其實說白了,就是:

  1. 用flasherase擦除數據

    先用flasherase擦除對應mtd分區中的內容

  2. 用nandwrite寫入數據

    而後將對應的數據(uboot或uImage或rootfs)用nandwrite寫入到對應的mtd中對應的位置便可。

前面介紹過了,對於常見的是把uboot(和kernel)放到nor flash中,而把kernel和rootfs放在nand flash中的。

而我此處的舉的例子,是另一種,即所有內容都放在nand flash上的。

可是,不管是是nor flash,仍是nand flash,都在Linux的MTD框架下,管理起來,都是同樣的。都是能夠用對應的mtd的工具去操做的。因此,若是你自己是要升級對應的uboot(和kernel)到nor flash,對於整個過程,也是同樣的,本身照葫蘆畫瓢便可。

關於我此處舉例所用的MTD的分區是如何的,此處先給出相關部分的代碼:

#define UBOOT_SIZE 	(SZ_1M)
#define KERNEL_SIZE 	(SZ_8M)
#define ROOTFS_SIZE (SZ_1M*200)
#define TEMP_SIZE 	(SZ_1M*64)

#define BEFORE_DATA_PARTION_SIZE 					\
		(ROOTFS_SIZE + KERNEL_SIZE + UBOOT_SIZE + TEMP_SIZE)
。。。
static struct mtd_partition XXX_default_nand_part[] = {
	[0] = {
		.name	= "U-Boot",
		.offset	= 0,
		.size		= UBOOT_SIZE,
	},
	[1] = {
		.name	= "Kernel",
		.offset 	= UBOOT_SIZE,
		.size		= KERNEL_SIZE
	},
	[2] = {
		.name	= "Root filesystem",
		.offset 	= UBOOT_SIZE + KERNEL_SIZE,
		.size		= ROOTFS_SIZE,
	},
	[3] = {
		.name	= "Temp",
		.offset 	= UBOOT_SIZE + KERNEL_SIZE + ROOTFS_SIZE,
		.size		= TEMP_SIZE,
	},
	[4] = {
		.name	= "Data",
		.offset	= BEFORE_DATA_PARTION_SIZE,
		.size		= 0, /* set in XXX_init_nand_partion() */
	},
};
    

對應的用圖表來講明,以下:

圖 1.1. Linux系統中的Nand MTD分區

Linux系統中的Nand MTD分區

下面就來介紹,如何一步步升級uboot,kernel和rootfs。

1.3.1. 升級Uboot

  1. 擦除uboot所在分區的全部數據
    ./util/flash_eraseall /dev/mtd0
  2. 擦除舊的uboot的環境變量
    ./util/flash_erase /dev/mtd1 0x700000 2
    • 0x800000~0x900000

      即/dev/mtd1中的0x700000~0x800000, 用於存放uboot中的環境變量。

      從新升級uboot的同時,先把舊的環境變量擦除掉。

  3. 寫入uboot數據
    ./util/nandwrite -p -s 0x80000 /dev/mtd0 u-boot_addHeader.bin
    • -p參數

      表示若是要寫入的數據不是頁大小的整數倍,會本身加填充數據即,如須要,自動padding。

    • 0x80000

      是當前4K的pagesize的nand flash的一個塊的大小。

1.3.2. 升級Kernel

  1. 擦除舊的kernel數據
    ./util/flash_erase /dev/mtd1 0 10
    • 其中的參數0,表示從/dev/mtd1起始位置開始擦除
    • 參數10是表示要擦除的block數目

      /dev/mtd1的物理起始地址是0x100000,而0x100000~0x600000之間,是用於保存uImage的數據,因此:

      要擦除的block的數目

      = 要擦除的大小/塊大小

      = 0x500000/塊大小

      = 5M/512KB

      = 10

      其中,當前用的是這個4K pagesize的nand的塊大小是512KB。

  2. 寫入kernel數據
    ./util/nandwrite -p /dev/mtd1 uImage

1.3.3. 升級rootfs

  1. 擦除rootfs所在分區數據
    ./util/flash_eraseall /dev/mtd2
  2. 寫入新的rootfs
    ./util/nandwrite -o /dev/mtd2 rootfs.4k.arm.yaffs2
    • 由於此處的rootfs鏡像文件是yaffs2文件系統,包含了oob數據。因此此處加上參數-o,意思是寫入頁數據同時也寫入oob數據,並且,加了-o 參數同時就不能再像以前的uboot和uImage同樣,加-p參數了,由於包含了oob數據的rootfs,自己就是頁大小的整數倍,不須要padding。
    • 不論實際使用的是4K+128 仍是對於4K+218(內部處理爲4K+192)的nand,此處都是使用4K+128的rootfs鏡像。

1.4. 總結整個升級過程

整個runtime的升級linux的過程,其實很簡單。

若是說有難度的話,那麼算是,在升級數據以前,你本身自己要清楚你原先的數據,即uboot,kernel,rootfs,都是放在哪一個分區的哪一個位置的,而後分別擦除數據,寫入新數據便可。

另外有個要注意的是,升級rootfs的話,儘可能把其餘非內核必須的進程都關閉掉,防止在升級過程當中,還有進程或和程序去讀取nand flash上的rootfs。

此外,在燒寫某個文件以後,若是但願查看當前寫入的數據,是不是咱們所指望的,那麼能夠用nanddump工具,將對應部分的數據「打印」出來,好比:

查看uboot的第一page的數據:

./nanddump -l 0x1000 -s 0x80000 -p /dev/mtd0

其餘mtd-util的工具的用法,請本身參考mtd-util中源碼的具體實現,經過看源碼,能夠了解其具體是如何實現,以及參數的完整的含義。

1.4.1. 一些提示

1.4.1.1. 把東西放到ramdisk中以免影響

以前遇到不少人問這個問題了。那就是,若是在升級的時候,因爲也會升級rootfs,可是自己升級過程當中,所利用到的文件,若是是放在rootfs中,豈不是會致使系統崩潰了?

答案是,不會。由於我以前介紹的方法中,是把升級所需的mtd工具,放到U盤的。而U盤是單獨mount系統中的。

不過,更加好的作法是,把此處升級所相關的,全部的文件,包括mtd工具,要升級的各個文件,甚至其餘可能用到的reboot等工具,設置是這些工具可能依賴的到庫文件等等,都所有拷貝到ramdisk中。這樣,經過運行ramdisk中的全部工具,訪問ramdisk中的要升級的文件,去升級系統,就不會對升級rootfs而有啥負面影響,也不會因爲升級rootfs而可能致使任何的系統崩潰了。

[注意] 關於ramdisk

所謂的ramdisk,我我的也不是很是熟悉。

只是對更不熟悉的人解釋一下,能夠簡單理解爲把你的內存劃分出來,當作一塊分區使用

因此這個小分區,說白了就是內存。因此,讀寫速度很快,也和nand 或nor flash無關,不會影響到Nand或Nor的升級。

通常來講,多數都是將ramdisk掛載到/tmp下面的,因此,若是你啥都不熟悉,直接把相關文件拷貝到/tmp,便可。

更多的,關於ramdisk或tmpfs,本身google吧。

相關文章
相關標籤/搜索