在Linux運行期間升級Linux系統(Uboot+kernel+Rootfs)
版本:v1.2
Crifan Li
摘要
本文主要介紹了如何在嵌入式Linux系統運行的時候,進行升級整個Linux系統,包括uboot,kernel和rootfs。以及簡介Linux中的已有的通用的Nor Flash驅動m25p80,和簡介mtd util以及相關工具mtdinfo,flash_erase,flash_eraseall,nanddump,nandwrite等的基本用法。
![[提示]](http://www.crifan.com/files/res/docbook/images/tip.png)
HTML版本的在線地址為:
有任何意見,建議,提交bug等,都歡迎去討論組發帖討論:
http://www.crifan.com/bbs/categories/runtime_upgrade_linux/
2012-11-17
- 介紹了如何實現在線升級linux系統,即uboot,kernel,rootfs, 以及相關的前提知識和準備工作
- 通過Docbook發布
- 添加了各章節的id
- 建議掛載文件到ramdisk中
版權 © 2012 Crifan, http://crifan.com
本文章遵從:署名-非商業性使用 2.5 中國大陸(CC BY-NC 2.5)
目錄
插圖清單
- 1.1. Linux系統中的Nand MTD分區
表格清單
- 1.1. MTD工具簡介
- 1.2. 要升級的Linux系統的文件
正文之前
目錄
1. 此文目的
目前嵌入式Linux系統的升級,即升級uboot,kernel,rootfs等,的傳統的方式,都是用燒寫工具去燒寫,相對來說,顯得很繁瑣和效率比較低,而利用mtd工具的方式去升級系統,相對比較方便。
此文主要就是介紹,在嵌入式Linux系統下,已經實現了nand和(或)nor flash驅動后,如何利用mtd工具,進行實時(runtime)/在線(online)的情況下,升級Linux系統。
2. 一點說明
-
本文所寫內容,主要是之前的一些相關的工作總結,如果內容有誤,請及時告知:admin (at) crifan.com
其他技術問題的探討,任何的問題,意見,建議等,都歡迎郵件交流。
-
另外,如果需要的mtd-utils-1.3.1的源碼的話,也可以發郵件索取。
-
有此文相關的有兩個附件:
- 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文件。
- compiled_mtd-utils_arm.7z
第 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-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的官網,資料很豐富,感興趣的自己去看:
![[注意]](http://www.crifan.com/files/res/docbook/images/note.png)
不過,對于之前的版本的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系統的文件
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工具升級系統,其實說白了,就是:
- 用flasherase擦除數據
先用flasherase擦除對應mtd分區中的內容
- 用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分區

下面就來介紹,如何一步步升級uboot,kernel和rootfs。
1.3.1. 升級Uboot
- 擦除uboot所在分區的所有數據
./util/flash_eraseall /dev/mtd0
- 擦除舊的uboot的環境變量
./util/flash_erase /dev/mtd1 0x700000 2
- 0x800000~0x900000
即/dev/mtd1中的0x700000~0x800000, 用于存放uboot中的環境變量。
重新升級uboot的同時,先把舊的環境變量擦除掉。
- 0x800000~0x900000
- 寫入uboot數據
./util/nandwrite -p -s 0x80000 /dev/mtd0 u-boot_addHeader.bin
- -p參數
表示如果要寫入的數據不是頁大小的整數倍,會自己加填充數據即,如需要,自動padding。
- 0x80000
是當前4K的pagesize的nand flash的一個塊的大小。
- -p參數
1.3.2. 升級Kernel
- 擦除舊的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。
- 寫入kernel數據
./util/nandwrite -p /dev/mtd1 uImage
1.3.3. 升級rootfs
- 擦除rootfs所在分區數據
./util/flash_eraseall /dev/mtd2
- 寫入新的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而可能導致任何的系統崩潰了。
![[注意]](http://www.crifan.com/files/res/docbook/images/note.png)
所謂的ramdisk,我個人也不是非常熟悉。
只是對更不熟悉的人解釋一下,可以簡單理解為把你的內存劃分出來,當做一塊分區使用
所以這個小分區,說白了就是內存。所以,讀寫速度很快,也和nand 或nor flash無關,不會影響到Nand或Nor的升級。
一般來說,多數都是將ramdisk掛載到/tmp下面的,所以,如果你啥都不熟悉,直接把相關文件拷貝到/tmp,即可。
更多的,關于ramdisk或tmpfs,自己google吧。