版本:v1.1
2012-08-09
修訂歷史 | ||
---|---|---|
修訂 1.0 | 2011-05-03 | crl |
| ||
修訂 1.1 | 2012-08-09 | crl |
|
版權(quán) ? 2012 Crifan, http://crifan.com
目錄
正文之前1. 此文目的2. 一點(diǎn)說明1. 嵌入式系統(tǒng)中,如何在Linux運(yùn)行的時(shí)候去升級(jí)Linux系統(tǒng)1.1. 前提1.1.1. Linux中已經(jīng)實(shí)現(xiàn)Nor Flash驅(qū)動(dòng)1.1.1.1. 在開發(fā)板相關(guān)部分添加對(duì)應(yīng)nor flash初始化相關(guān)代碼1.1.1.2. Linux通用nor flash驅(qū)動(dòng)m25p80.c簡(jiǎn)介1.1.2. Linux中已實(shí)現(xiàn)了U盤掛載,以方便拷貝要升級(jí)的文件1.1.3. Linux中Nor Flash和Nand Flash已能正常工作1.1.4. 已經(jīng)準(zhǔn)備好了mtd工具1.1.4.1. mtd-util簡(jiǎn)介1.1.4.2. mtd中的/dev/mtdN與/dev/mtdblockN的區(qū)別1.2. 準(zhǔn)備工作1.2.1. 準(zhǔn)備好要升級(jí)的文件1.2.2. 拷貝文件并掛載分區(qū)1.3. 利用mtd工具升級(jí)Linux系統(tǒng)1.3.1. 升級(jí)Uboot1.3.2. 升級(jí)Kernel1.3.3. 升級(jí)rootfs1.3.4. 總結(jié)插圖清單
1.1. Linux系統(tǒng)中的Nand MTD分區(qū)目前嵌入式Linux系統(tǒng)的升級(jí),即升級(jí)uboot,kernel,rootfs等,的傳統(tǒng)的方式,都是用燒寫工具去燒寫,相對(duì)來說,顯得很繁瑣和效率比較低,而利用mtd工具的方式去升級(jí)系統(tǒng),相對(duì)比較方便。
此文主要就是介紹,在嵌入式Linux系統(tǒng)下,已經(jīng)實(shí)現(xiàn)了nand和(或)nor flash驅(qū)動(dòng)后,如何利用mtd工具,進(jìn)行實(shí)時(shí)(runtime)/在線(online)的情況下,升級(jí)Linux系統(tǒng)。
本文所寫內(nèi)容,主要是之前的一些相關(guān)的工作總結(jié),如果內(nèi)容有誤,請(qǐng)及時(shí)告知:admin (at) crifan.com
其他技術(shù)問題的探討,任何的問題,意見,建議等,都?xì)g迎郵件交流。
另外,如果需要的mtd-utils-1.3.1的源碼的話,也可以發(fā)郵件索取。
有此文相關(guān)的有兩個(gè)附件:
已經(jīng)編譯好了的arm平臺(tái)的,包含了u32和u64版本的,本文所用到的那4個(gè)mtd 的工具,即flash_erase,flash_eraseall,nanddump,nandwrite。
我之前所用的mtd util的源碼。你如果是其他平臺(tái)的,那么用此源碼,可以自己編譯出對(duì)應(yīng)的mtd的一系列的工具。關(guān)于如何編譯,請(qǐng)參考Readme文件。
目錄
1.1. 前提1.1.1. Linux中已經(jīng)實(shí)現(xiàn)Nor Flash驅(qū)動(dòng)1.1.1.1. 在開發(fā)板相關(guān)部分添加對(duì)應(yīng)nor flash初始化相關(guān)代碼1.1.1.2. Linux通用nor flash驅(qū)動(dòng)m25p80.c簡(jiǎn)介1.1.2. Linux中已實(shí)現(xiàn)了U盤掛載,以方便拷貝要升級(jí)的文件1.1.3. Linux中Nor Flash和Nand Flash已能正常工作1.1.4. 已經(jīng)準(zhǔn)備好了mtd工具1.1.4.1. mtd-util簡(jiǎn)介1.1.4.2. mtd中的/dev/mtdN與/dev/mtdblockN的區(qū)別1.2. 準(zhǔn)備工作1.2.1. 準(zhǔn)備好要升級(jí)的文件1.2.2. 拷貝文件并掛載分區(qū)1.3. 利用mtd工具升級(jí)Linux系統(tǒng)1.3.1. 升級(jí)Uboot1.3.2. 升級(jí)Kernel1.3.3. 升級(jí)rootfs1.3.4. 總結(jié)簡(jiǎn)單點(diǎn)說,在利用mtd工具升級(jí)系統(tǒng)之前,需要你的嵌入式linux本身具備一定條件。下面依次介紹這些前提條件。
常見的嵌入式系統(tǒng),都是從nor flash啟動(dòng),然后對(duì)應(yīng)的uboot是放在nor flash里面的。
一般nor flash,容量相對(duì)較小,只有512KB等,有的大的一點(diǎn)的是1MB,2MB之類的。
一般的情況是,uboot大約有200多KB,而linux的kernel鏡像文件,比如我遇到過的,大約在1M左右。
所以,對(duì)于這些稍微大一些的Nor Flash,往往除了放了uboot的代碼之外,還可以放linux的kernel。
如果是小的Nor Flash,那么往往是把kernel放在Nand Flash的某個(gè)分區(qū)。
而此處用mtd工具升級(jí)linux的前提之一,是你linux系統(tǒng)中,已經(jīng)實(shí)現(xiàn)了對(duì)應(yīng)的nand flash的驅(qū)動(dòng)。而對(duì)于nor flash驅(qū)動(dòng)的話,如果還沒有實(shí)現(xiàn)對(duì)應(yīng)驅(qū)動(dòng),那么就先去實(shí)現(xiàn)對(duì)應(yīng)的nor flash驅(qū)動(dòng)。
下面這里只是對(duì)于如何實(shí)現(xiàn)普通的nor flash驅(qū)動(dòng),就我接觸到的相關(guān)內(nèi)容,給出一些提示。
對(duì)于常見的spi接口的nor flash來說,如果你的nor flash型號(hào)是常見的型號(hào),那么很可能你不用另外單獨(dú)再自己完全從頭寫一個(gè)完整的nor flash驅(qū)動(dòng)了。
關(guān)于不同的接口的Nor Flash之間的區(qū)別,不了解的可以參考:CFI Flash, JEDEC Flash ,Parellel Flash, SPI Flash, Nand Flash,Nor Flash的區(qū)別和聯(lián)系和CFI(Common Flash Interface)詳解
因?yàn)?,往往你的linux中已經(jīng)實(shí)現(xiàn)了spi驅(qū)動(dòng)的,所以此時(shí),你只需要做下面兩件事情,一個(gè)是在板子相關(guān)部分,添加對(duì)應(yīng)nor flash對(duì)應(yīng)的初始化代碼,二是利用linux默認(rèn)自帶的,對(duì)于常見nor flash都已經(jīng)默認(rèn)支持的nor flash驅(qū)動(dòng):m25p80.c
下面分別詳細(xì)解釋。
此處,只是簡(jiǎn)單介紹一下,我之前所遇到的一個(gè)nor flash驅(qū)動(dòng),是如何做的。
關(guān)于添加nor flash初始化的代碼,其實(shí)很簡(jiǎn)單,就是在開發(fā)板的最核心的那個(gè)文件(此處以arm系統(tǒng)為例):
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, },......};然后在自己開發(fā)板設(shè)備初始化的部分,添加對(duì)應(yīng)spi nor設(shè)備的注冊(cè)函數(shù):
spi_register_board_info(XXX_spi_devices, ARRAY_SIZE(XXX_spi_devices));以實(shí)現(xiàn)對(duì)應(yīng)的spi接口的nor flash設(shè)備的注冊(cè)和添加。
具體內(nèi)部邏輯是如何實(shí)現(xiàn)的,就要自己去看代碼了。
此處只是給個(gè)框架,告訴你大概是怎么去實(shí)現(xiàn)的,具體的實(shí)現(xiàn),肯定要你自己去看代碼搞懂。
在spi接口的nor flash設(shè)備注冊(cè)部分搞定后,再來看Linux中的,默認(rèn)已經(jīng)幫我們實(shí)現(xiàn)好了的一個(gè)通用的nor flash的驅(qū)動(dòng)。
具體的文件是:
linux-2.6.28.4\drivers\mtd\devices\m25p80.c
其中,對(duì)于支持的設(shè)備,可以去看源碼中的設(shè)備列表部分的代碼:
/* 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, },};如果要添加此驅(qū)動(dòng),以實(shí)現(xiàn)支持我們的通用的nor flash,則在make menuconfig的時(shí)候,添加對(duì)應(yīng)設(shè)備的支持即可。
對(duì)應(yīng)選項(xiàng)的kconfig的配置內(nèi)容在:
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內(nèi)核,運(yùn)行后,就應(yīng)該可以可以通過:
cat /proc/mtd查看到對(duì)應(yīng)的mtd設(shè)備了。如果沒有,那么說明你的驅(qū)動(dòng)還是沒有添加正常。
簡(jiǎn)單來說就是,你的linux系統(tǒng)中已經(jīng)有了USB驅(qū)動(dòng),并且已經(jīng)實(shí)現(xiàn)了USB的gadget或者USB File storage,即實(shí)現(xiàn)了U盤的掛載。
有了U盤掛載,每次升級(jí)系統(tǒng)文件,包括uboot,kernel的uImage,rootfs等文件的話,就很方便了。
具體如何實(shí)現(xiàn),不是本文所能說得清楚的,所以不再多贅述。
對(duì)于新的Linux內(nèi)核,在已經(jīng)實(shí)現(xiàn)了USB device驅(qū)動(dòng)的前提下,如何實(shí)現(xiàn)U盤的功能,可以參考這個(gè):在Linux USB Gadget下使用U盤
要用mtd工具升級(jí)系統(tǒng)之前,肯定是對(duì)應(yīng)的nand flash以及nor flash都是已經(jīng)正常工作了。即,除了系統(tǒng)正常運(yùn)行外,通過:
cat /proc/mtd可以看到對(duì)應(yīng)的nor和nand的flash所對(duì)應(yīng)的分區(qū)信息了。
此處所說的準(zhǔn)備好了mtd的工具,即編譯好了某個(gè)版本的mtd-utils,比如mtd-utils-1.3.1,然后得到對(duì)應(yīng)的可執(zhí)行的一系列的工具,其中這幾個(gè)是用得到的:
表 1.1. MTD工具簡(jiǎn)介
MTD工具名稱 | 功能簡(jiǎn)介 |
---|---|
flash_erase | 擦除(nand或nor)flash的某個(gè)部分 |
flash_eraseall | 擦除整個(gè)mtd的分區(qū)(某個(gè)nor或nand分區(qū)) |
nanddump | 用于查看當(dāng)前某個(gè)mtd分區(qū)的數(shù)據(jù)(nand的話,也支持顯示oob數(shù)據(jù)) |
nandwrite | 用于將某個(gè)文件/數(shù)據(jù),寫入到某個(gè)mtd分區(qū)(的某個(gè)位置) |
其中,對(duì)于如何得到mtd-util的這些工具,有兩種辦法:
兩種方法,都很簡(jiǎn)單,只是提醒一下,編譯的話,肯定是用交叉編譯器,而不是X86的PC上的編輯器去編譯,呵呵。
mtd-util,即mtd的utilities,是mtd相關(guān)的很多工具的總稱,包括常用的mtdinfo,flash_erase, flash_eraseall, nanddump, nandwrite等,每一個(gè)工具,基本上都對(duì)應(yīng)著一個(gè)同文件名的C文件。
mtd-util,由mtd官方維護(hù)更新,開發(fā)這一套工具,目的是為了Linux的MTD層提供一系列工具,方便管理維護(hù)mtd分區(qū)。
mtd工具對(duì)應(yīng)的源碼,叫做mtd-utils,隨著時(shí)間更新,發(fā)布了很多版本。
我之前用到的版本是mtd-utils-1.3.1,截止2011-05-01,最新版本到了v1.4.1。
mtd-util源碼的下載地址,請(qǐng)去MTD源碼的官網(wǎng)
另外多說一句,MTD的官網(wǎng),資料很豐富,感興趣的自己去看:
![]() | linux的mtd要和mtd-util中的一致 |
---|---|
不過,對(duì)于之前的版本的Linux的kernel來說,使用mtd-util的話,一定要配套,主要是后來新的linux的版本,開始支持mtd的大小,即nand的大小,大于4GB,對(duì)應(yīng)的linux內(nèi)核中的mtd層的有些變量,就必須從u32升級(jí)成u64,才可以支持。 對(duì)應(yīng)的mtd的util中一些變量,也是要和你當(dāng)前l(fā)inux版本的mtd匹配。 簡(jiǎn)單說就是,無論你用哪個(gè)版本的Linux內(nèi)核,如果要去用mtd-util的話,那么兩者的版本要一直,即查看linux內(nèi)核中的mtd的一些頭文件,主要是include\mtd\mtd-abi.h和你的mtd-util中的include\mtd\mtd-abi.h,兩個(gè)要一致。 否則,就會(huì)出現(xiàn)我之前遇到的問題,當(dāng)然linux內(nèi)核是u64版本的,支持nand flash大于4GB的,而用的mtd-util中的變量的定義,卻還是u32,所以肯定會(huì)出錯(cuò)的。 為了同一套mtd-util工具即支持u32又支持u64,我定義了一個(gè)宏來切換,下面貼出來,供需要的人參考: 加了宏以支持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 1struct 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 2struct 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__ */ |
簡(jiǎn)單說就是:
某個(gè)字符設(shè)備,對(duì)應(yīng)的mtd的util,就是對(duì)其操作,實(shí)現(xiàn)對(duì)對(duì)應(yīng)的mtd分區(qū)進(jìn)行管理的。
某個(gè)塊設(shè)備,可以直接像操作其他塊設(shè)備一樣來操作此塊設(shè)備,比如直接cat數(shù)據(jù)進(jìn)去等等常見的操作。
更加詳細(xì)的解釋,請(qǐng)去看這個(gè)帖子:
Linux系統(tǒng)中/dev/mtd與/dev/mtdblock的區(qū)別,即MTD字符設(shè)備和塊設(shè)備的區(qū)別
將你新編譯和制作出來的,要升級(jí)的文件準(zhǔn)備好,此處為:
表 1.2. 要升級(jí)的Linux系統(tǒng)的文件
文件 | 文件名 | 說明 |
---|---|---|
uboot文件 | u-boot.bin | 只是一個(gè)普通的二進(jìn)制文件 |
linux的kernel文件 | uImage | 也是一個(gè)普通的二進(jìn)制文件 |
rootfs文件 | rootfs.4k.arm.yaffs2 | 是用mkyafffs2工具制作而成,內(nèi)部數(shù)據(jù)格式是page數(shù)據(jù)+oob數(shù)據(jù)+page數(shù)據(jù)+oob數(shù)據(jù)+......,用于燒寫到Nand Flash中 |
利用mtd工具升級(jí)系統(tǒng),其實(shí)說白了,就是:
先用flasherase擦除對(duì)應(yīng)mtd分區(qū)中的內(nèi)容
然后將對(duì)應(yīng)的數(shù)據(jù)(uboot或uImage或rootfs)用nandwrite寫入到對(duì)應(yīng)的mtd中對(duì)應(yīng)的位置即可。
前面介紹過了,對(duì)于常見的是把uboot(和kernel)放到nor flash中,而把kernel和rootfs放在nand flash中的。
而我此處的舉的例子,是另外一種,即全部?jī)?nèi)容都放在nand flash上的。
但是,不論是是nor flash,還是nand flash,都在Linux的MTD框架下,管理起來,都是一樣的。都是可以用對(duì)應(yīng)的mtd的工具去操作的。所以,如果你本身是要升級(jí)對(duì)應(yīng)的uboot(和kernel)到nor flash,對(duì)于整個(gè)過程,也是一樣的,自己照葫蘆畫瓢即可。
關(guān)于我此處舉例所用的MTD的分區(qū)是如何的,此處先給出相關(guān)部分的代碼:
#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() */ },};對(duì)應(yīng)的用圖表來說明,如下:
下面就來介紹,如何一步步升級(jí)uboot,kernel和rootfs。
即/dev/mtd1中的0x700000~0x800000, 用于存放uboot中的環(huán)境變量。
重新升級(jí)uboot的同時(shí),先把舊的環(huán)境變量擦除掉。
表示如果要寫入的數(shù)據(jù)不是頁大小的整數(shù)倍,會(huì)自己加填充數(shù)據(jù)即,如需要,自動(dòng)padding。
是當(dāng)前4K的pagesize的nand flash的一個(gè)塊的大小。
/dev/mtd1的物理起始地址是0x100000,而0x100000~0x600000之間,是用于保存uImage的數(shù)據(jù),所以:
要擦除的block的數(shù)目
= 要擦除的大小/塊大小
= 0x500000/塊大小
= 5M/512KB
= 10
其中,當(dāng)前用的是這個(gè)4K pagesize的nand的塊大小是512KB。
整個(gè)runtime的升級(jí)linux的過程,其實(shí)很簡(jiǎn)單。
如果說有難度的話,那么算是,在升級(jí)數(shù)據(jù)之前,你自己本身要清楚你原先的數(shù)據(jù),即uboot,kernel,rootfs,都是放在哪個(gè)分區(qū)的哪個(gè)位置的,然后分別擦除數(shù)據(jù),寫入新數(shù)據(jù)即可。
另外有個(gè)要注意的是,升級(jí)rootfs的話,盡量把其他非內(nèi)核必須的進(jìn)程都關(guān)閉掉,防止在升級(jí)過程中,還有進(jìn)程或和程序去讀取nand flash上的rootfs。
此外,在燒寫某個(gè)文件之后,如果希望查看當(dāng)前寫入的數(shù)據(jù),是否是我們所期望的,那么可以用nanddump工具,將對(duì)應(yīng)部分的數(shù)據(jù)“打印”出來,比如:
查看uboot的第一page的數(shù)據(jù):
./nanddump -l 0x1000 -s 0x80000 -p /dev/mtd0其他mtd-util的工具的用法,請(qǐng)自己參考mtd-util中源碼的具體實(shí)現(xiàn),通過看源碼,可以了解其具體是如何實(shí)現(xiàn),以及參數(shù)的完整的含義。
聯(lián)系客服