heap_init 函數(shù)在SDRAM中指定了一塊1M大小的內(nèi)存作為heap(起始地址HEAP_BASE = 0x33e00000),并在heap的開(kāi)頭定義了一個(gè)數(shù)據(jù)結(jié)構(gòu)blockhead。事實(shí)上,heap就是使用一系列的blockhead數(shù)據(jù)結(jié)構(gòu)來(lái)描述和操作的。每個(gè)blockhead數(shù)據(jù)結(jié)構(gòu)對(duì)應(yīng)著一塊heap內(nèi)存,假設(shè)一個(gè)blockhead數(shù)據(jù)結(jié)構(gòu)的存放位置為A,則它對(duì)應(yīng)的可分配內(nèi)存地址為“A + sizeof(blockhead)”到“A + sizeof(blockhead) + size - 1”。blockhead數(shù)據(jù)結(jié)構(gòu)在lib/heap.c中定義:
1 typedef struct blockhead_t {
2 int32 signature; //固定為BLOCKHEAD_SIGNATURE
3 bool allocated; //此區(qū)域是否已經(jīng)分配出去:0-N,1-Y
4 unsigned long size; //此區(qū)域大小
5 struct blockhead_t *next; //鏈表指針
6 struct blockhead_t *prev; //鏈表指針
7 } blockhead;
現(xiàn)在來(lái)看看heap是如何運(yùn)作的(如果您不關(guān)心heap實(shí)現(xiàn)的細(xì)節(jié),這段可以跳過(guò))。vivi對(duì)heap的操作比較簡(jiǎn)單,vivi中有一個(gè)全局變量 static blockhead *gHeapBase,它是heap的鏈表頭指針,通過(guò)它可以遍歷所有blockhead數(shù)據(jù)結(jié)構(gòu)。假設(shè)需要?jiǎng)討B(tài)申請(qǐng)一塊sizeA大小的內(nèi)存,則 mmalloc函數(shù)從gHeapBase開(kāi)始搜索blockhead數(shù)據(jù)結(jié)構(gòu),如果發(fā)現(xiàn)某個(gè)blockhead滿足:
(1) allocated = 0 //表示未分配
(2) size > sizeA,則找到了合適的blockhead,
滿足上述條件后,進(jìn)行如下操作:
a.allocated設(shè)為1
b.如果size – sizeA > sizeof(blockhead),則將剩下的內(nèi)存組織成一個(gè)新的blockhead,放入鏈表中
c.返回分配的內(nèi)存的首地址釋放內(nèi)存的操作更簡(jiǎn)單,直接將要釋放的內(nèi)存對(duì)應(yīng)的blockhead數(shù)據(jù)結(jié)構(gòu)的allocated設(shè)為0即可。
heap_init函數(shù)直接調(diào)用mmalloc_init函數(shù)進(jìn)行初始化,此函數(shù)代碼在lib/heap.c中,比較簡(jiǎn)單,初始化gHeapBase即可:
[main(int argc, char *argv[]) > heap_init(void) > mmalloc_init(unsigned char *heap, unsigned long size)]
1 static inline int mmalloc_init(unsigned char *heap, unsigned long size)
2 {
3 if (gHeapBase != NULL) return -1;
4 DPRINTK("malloc_init(): initialize heap area at 0x%08lx, size = 0x%08lx\n", heap, size);
5 gHeapBase = (blockhead *)(heap);
6 gHeapBase->allocated=FALSE;
7 gHeapBase->signature=BLOCKHEAD_SIGNATURE;
8 gHeapBase->next=NULL;
9 gHeapBase->prev=NULL;
10 gHeapBase->size = size - sizeof(blockhead);
11 return 0;
12 }
static blockhead *gHeapBase = NULL; 這個(gè)就是上面稱(chēng)贊的全局變量了,定義在lib/heap.c中。上面就是個(gè)鏈表操作,數(shù)據(jù)結(jié)構(gòu),看來(lái)搞這個(gè)也得好好學(xué)數(shù)據(jù)結(jié)構(gòu)啊,不然內(nèi)存搞的溢出、浪費(fèi)可就哭都來(lái)不及了。
5、Step 5:mtd_dev_init()
所謂MTD(Memory Technology Device)相關(guān)的技術(shù)。在linux系統(tǒng)中,我們通常會(huì)用到不同的存儲(chǔ)設(shè)備,特別是FLASH設(shè)備。為了在使用新的存儲(chǔ)設(shè)備時(shí),我們能更簡(jiǎn)便地提供它的驅(qū)動(dòng)程序,在上層應(yīng)用和硬件驅(qū)動(dòng)的中間,抽象出MTD設(shè)備層。驅(qū)動(dòng)層不必關(guān)心存儲(chǔ)的數(shù)據(jù)格式如何,比如是FAT32、ETX2還是FFS2或其它。它僅僅提供一些簡(jiǎn)單的接口,比如讀寫(xiě)、擦除及查詢。如何組織數(shù)據(jù),則是上層應(yīng)用的事情。MTD層將驅(qū)動(dòng)層提供的函數(shù)封裝起來(lái),向上層提供統(tǒng)一的接口。這樣,上層即可專(zhuān)注于文件系統(tǒng)的實(shí)現(xiàn),而不必關(guān)心存儲(chǔ)設(shè)備的具體操作。這段亂七八糟的話也許比較讓人暈,也可以這樣理解在設(shè)備驅(qū)動(dòng)(此處指存儲(chǔ)設(shè)備)和上層應(yīng)用之間還存在著一層,共三層,這個(gè)中間層就是MTD技術(shù)的產(chǎn)物。通常可以將它視為驅(qū)動(dòng)的一部分,叫做上層驅(qū)動(dòng),而那些實(shí)現(xiàn)設(shè)備的讀、寫(xiě)操作的驅(qū)動(dòng)稱(chēng)為下層驅(qū)動(dòng),上層驅(qū)動(dòng)將下層驅(qū)動(dòng)封裝,并且留給其上層應(yīng)用一些更加容易簡(jiǎn)單的接口。
在我們即將看到的代碼中,使用mtd_info數(shù)據(jù)結(jié)構(gòu)表示一個(gè)MTD 設(shè)備,使用nand_chip數(shù)據(jù)結(jié)構(gòu)表示一個(gè)nand flash芯片。在mtd_info結(jié)構(gòu)中,對(duì)nand_flash結(jié)構(gòu)作了封裝,向上層提供統(tǒng)一的接口。比如,它根據(jù)nand_flash提供的 read_data(讀一個(gè)字節(jié))、read_addr(發(fā)送要讀的扇區(qū)的地址)等函數(shù),構(gòu)造了一個(gè)通用的讀函數(shù)read,將此函數(shù)的指針作為自己的一個(gè)成員。而上層要讀寫(xiě)flash時(shí),執(zhí)行mtd_info中的read、write函數(shù)即可。
mtd_dev_init()用來(lái)掃描所使用的 NAND Flash的型號(hào),構(gòu)造MTD設(shè)備,即構(gòu)造一個(gè)mtd_info的數(shù)據(jù)結(jié)構(gòu)。對(duì)于S3C2410來(lái)說(shuō),它直接調(diào)用mtd_init(),mtd_init 又調(diào)用smc_init(),此函數(shù)在drivers/mtd/maps/s3c2410_flash.c中:
[main(int argc,char *argv[])>mtd_dev_init()>mtd_init()]
1 int mtd_init(void)
2 {
3 int ret;
4 #ifdef CONFIG_MTD_CFI /*is not set*/
5 ret = cfi_init();
6 #endif
7 #ifdef CONFIG_MTD_SMC9 /* =y */
8 ret = smc_init();
9 #endif
10 #ifdef CONFIG_S3C2410_AMD_BOOT /*is not set*/
11 ret = amd_init();
12 #endif
13 if (ret) {
14 mymtd = NULL;
15 return ret;
16 }
17 return 0;
18 }
顯而易見(jiàn),該函數(shù)應(yīng)取第二項(xiàng),這項(xiàng)在autoconf.h中定義了。
[main(int argc, char *argv[]) > mtd_dev_init() > mtd_init() > smc_init()]
1 static int
2 smc_init(void)
3 {
/*struct mtd_info *mymtd,數(shù)據(jù)類(lèi)型在include/mtd/mtd.h*/
/*strcut nand_chip在include/mtd/nand.h中定義*/
4 struct nand_chip *this;
5 u_int16_t nfconf;
/* Allocate memory for MTD device structure and private data */
6 mymtd = mmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip));
7 if (!mymtd) {
8 printk("Unable to allocate S3C2410 NAND MTD device structure.\n");
9 return -ENOMEM;
10 }
/* Get pointer to private data */
11 this = (struct nand_chip *)(&mymtd[1]);
/* Initialize structures */
12 memset((char *)mymtd, 0, sizeof(struct mtd_info));
13 memset((char *)this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
14 mymtd->priv = this;
/* set NAND Flash controller */
15 nfconf = NFCONF;
/* NAND Flash controller enable */
16 nfconf |= NFCONF_FCTRL_EN;
/* Set flash memory timing */
17 nfconf &= ~NFCONF_TWRPH1; /* 0x0 */
18 nfconf |= NFCONF_TWRPH0_3; /* 0x3 */
19 nfconf &= ~NFCONF_TACLS; /* 0x0 */
20 NFCONF = nfconf;
/* Set address of NAND IO lines */
21 this->hwcontrol = smc_hwcontrol;
22 this->write_cmd = write_cmd;
23 this->write_addr = write_addr;
24 this->read_data = read_data;
25 this->write_data = write_data;
26 this->wait_for_ready = wait_for_ready;
/* Chip Enable -> RESET -> Wait for Ready -> Chip Disable */
27 this->hwcontrol(NAND_CTL_SETNCE);
28 this->write_cmd(NAND_CMD_RESET);
29 this->wait_for_ready();
30 this->hwcontrol(NAND_CTL_CLRNCE);
31 smc_insert(this);
32 return 0;
33 }
6 -14行構(gòu)造了一個(gè)mtd_info結(jié)構(gòu)和nand_flash結(jié)構(gòu),前者對(duì)應(yīng)MTD設(shè)備,后者對(duì)應(yīng)nand flash芯片(如果您用的是其他類(lèi)型的存儲(chǔ)器件,比如nor flash,這里的nand_flash結(jié)構(gòu)應(yīng)該換為其他類(lèi)型的數(shù)據(jù)結(jié)構(gòu))。MTD設(shè)備是具體存儲(chǔ)器件的抽象,那么在這些代碼中這種關(guān)系如何體現(xiàn)呢——第 14行的代碼把兩者連結(jié)在一起了。事實(shí)上,mtd_info結(jié)構(gòu)中各成員的實(shí)現(xiàn)(比如read、write函數(shù)),正是由priv變量所指向的 nand_flash的各類(lèi)操作函數(shù)(比如read_addr、read_data等)來(lái)實(shí)現(xiàn)的。
15-20行是初始化S3C2410上的 NAND FLASH控制器。前面分配的nand_flash結(jié)構(gòu)還是空的,現(xiàn)在當(dāng)然就是填滿它的各類(lèi)成員了,這正是21-26行做的事情。27-30行對(duì)這塊 nand flash作了一下復(fù)位操作。最后,也是最復(fù)雜的部分,根據(jù)剛才填充的nand_flash結(jié)構(gòu),構(gòu)造mtd_info結(jié)構(gòu),這由31行的 smc_insert函數(shù)調(diào)用smc_scan完成。
這才是VIVI啟動(dòng)的第5步,還有三步就完成了啟動(dòng)了,同時(shí)我的這篇閱讀筆記也就OVER了。
評(píng)論
查看更多