본문 바로가기
프로...Linux

[FS/mtd] mtd 관련 작업

by 크크다스 2019. 1. 10.
반응형

[FS/mtd] mtd 관련 작업


MTD FAQ


embedded system에서 많이 사용하는 NAND등의 flash를 사용할때 많이 쓰는 

mtd 영역에 대해서 작업시 활용할 수 있는 Tip을 살펴본다.


- mtd 정보확인

root@Embedded:/# cat /proc/mtd

dev:    size   erasesize  name

mtd0: 00040000 00010000 "u-boot"

mtd1: 00010000 00010000 "u-boot-env"

mtd2: 00630000 00010000 "rootfs"

mtd3: 00070000 00010000 "rootfs_data"

mtd4: 00150000 00010000 "kernel"

mtd5: 00010000 00010000 "otp"

mtd6: 00010000 00010000 "nvram"

mtd7: 00010000 00010000 "art"

mtd8: 00780000 00010000 "firmware"

root@Embedded:/#


참고> mtdX vs. mtdblockX

root@Embedded:/proc# cat /proc/devices

Character devices:

  1 mem

  4 ttyS

  5 /dev/tty

  5 /dev/console

  5 /dev/ptmx

 10 misc

 90 mtd

108 ppp

128 ptm

136 pts

180 usb

189 usb_device

254 ttyATH


Block devices:

259 blkext

 31 mtdblock


root@Embedded:/dev# ls -l mtd7 mtdblock7

crw-r--r--    1 root     root       90,  14 Jan  1  1970 mtd7

brw-r--r--    1 root     root       31,   7 Jan  1  1970 mtdblock7



mtdX : Charactor Device

flash 관련 tool 들을 사용

mtdblockX : Block Device

일반 파일 관련 툴들을 사용

(MTD Write시 사용하지 말라는 언급이 있음. 

http://www.at91.com/viewtopic.php?t=21193

DO NOT use dd with NAND partitions !

Please use this instead

CODE: SELECT ALL

flash_eraseall /dev/mtd1
flashcp /myimages/uImage /dev/mtd1


- Read / Write 

일반 파일들 처럼 cp cat 등 등 활용하면 됨. ( 쓰기는 잘 안되는 경우들이 많은데, 케이스 별로 원인을 찾아서 대응해야 함.)

root@Embedded:/# hexdump -C /dev/mtdblock7 -n 6 -s 4098 | head -1

00001002  04 f0 21 11 11 12   


root@Embedded:/# tftp -p -l /dev/mtdblock7 -r firstpw/mtdblock7 192.168.88.203


root@Embedded:/# tftp -g -r firstpw/mtdblock7.xxd.rev -l /dev/mtdblock7 192.168.88.203



- mtd 영역 Hex 변환

위의 Read의 hexdump 외에도 xxd 등을 활용하여 hexdump , 변경(bin -> txt(dump), txt(dump) -> bin)을 수행 할 수 있다.

to hexdump>

xxd mtdblock7 > mtdblock7.xxd

--- change dump file

to bin>
xxd -r mtdblock7.xxd > mtdblock7.xxd.rev


- openWrt 에 mtd-util 추가하기

mtd-utils : 

http://processors.wiki.ti.com/index.php/MTD_Utilities


tmp/.config-target.in

select DEFAULT_mtd

위 처럼 되어 있는 곳마다 아래 라인 추가

select DEFAULT_mtd-utils


busybox's flash tools

base system > busybox > miscellaneous Utilities

x x [*] flashcp

x x [*] flash_lock  

x x [*] flash_unlock  

x x [*] flash_eraseall  


- mtd : Permission Error

Read only 인지 확인해보라

대부분 해당 Flag는 Bootloader에서 Command param으로 kernel로 전송한다 (ro)

변경 방법 1> 

Bootloader의 CFG에서 boot argment 를 변경


변경 방법 2> 방법 1을 사용할 수 없는 상황

Kernel  소스에서 Flag 강제 세팅 : 아래 처럼 코드 Blocking

drivers/mtd/cmdlinepart.c


static struct mtd_partition * newpart(char *s,

char **retptr,

int *num_parts,

int this_part,

unsigned char **extra_mem_ptr,

int extra_mem_size)

{

........


/* test for options */

if (strncmp(s, "ro", 2) == 0)

{

// mask_flags |= MTD_WRITEABLE;

s += 2;

}


# Boot Param으로 넘어오지 않는 경우에는 Kernel에서 직접 Driver 설정 화일 변경

아래 위치에서 static struct mtd_partition 설정 부분을 확인해보길 .... ( grep으로 ".mask_flags"를 찾는 것도 한 방법)

drivers/mtd/ ....

arch/mips/.....


mtd info program source

root@16M:/etc/firstpw# ./mtds

[/dev/mtd0]  MTD_NORFLASH WR BitWR ERASE UnLOCK  Sz(040000|  262144) ErSz(65536) WrSz(1) OobSz(0) Pad(4197963)

[/dev/mtd1]  MTD_NORFLASH WR BitWR ERASE UnLOCK  Sz(010000|   65536) ErSz(65536) WrSz(1) OobSz(0) Pad(4197963)

[/dev/mtd2]  MTD_NORFLASH WR BitWR ERASE UnLOCK  Sz(630000| 6488064) ErSz(65536) WrSz(1) OobSz(0) Pad(4197963)

[/dev/mtd3]  MTD_NORFLASH WR BitWR ERASE UnLOCK  Sz(070000|  458752) ErSz(65536) WrSz(1) OobSz(0) Pad(4197963)

[/dev/mtd4]  MTD_NORFLASH WR BitWR ERASE UnLOCK  Sz(150000| 1376256) ErSz(65536) WrSz(1) OobSz(0) Pad(4197963)

[/dev/mtd5]  MTD_NORFLASH WR BitWR ERASE UnLOCK  Sz(010000|   65536) ErSz(65536) WrSz(1) OobSz(0) Pad(4197963)

[/dev/mtd6]  MTD_NORFLASH WR BitWR ERASE UnLOCK  Sz(010000|   65536) ErSz(65536) WrSz(1) OobSz(0) Pad(4197963)

[/dev/mtd7]  MTD_NORFLASH WR BitWR ERASE UnLOCK  Sz(010000|   65536) ErSz(65536) WrSz(1) OobSz(0) Pad(4197963)

[/dev/mtd8]  MTD_NORFLASH WR BitWR ERASE UnLOCK  Sz(780000| 7864320) ErSz(65536) WrSz(1) OobSz(0) Pad(4197963)

root@16M:/etc/firstpw#


#include <stdio.h>

#include <fcntl.h>

#include <sys/ioctl.h>

#include <mtd/mtd-user.h>


#include <errno.h>

#include <string.h>

#include <unistd.h>



#define TARGET_MTD "/dev/mtd7"


int exit_w_err(char* pTitle, int ret)

{

printf("[%s] Ret[%d]\n", pTitle, ret);

printf(" MTD Error: %d[%s]\n", errno, strerror(errno));


_exit(0);

}


#define CASE_STR(_tag) \

case _tag: return #_tag;


char* str_type(__u8 type)

{

switch(type) {

CASE_STR(MTD_ABSENT)

CASE_STR(MTD_RAM)

CASE_STR(MTD_ROM)

CASE_STR(MTD_NORFLASH)

CASE_STR(MTD_NANDFLASH)

CASE_STR(MTD_DATAFLASH)

CASE_STR(MTD_UBIVOLUME)

CASE_STR(MTD_MLCNANDFLASH)

default: break;

}

return "Unknown type";

}


int print_mtd_info(char* pTitle, mtd_info_t* pInfo)

{

char sbuff[1024];

int len = 0;


len += snprintf(sbuff + len, sizeof(sbuff) - len, "[%s] %13s", pTitle, str_type(pInfo->type));

if(pInfo->flags & MTD_WRITEABLE) {

len += snprintf(sbuff + len, sizeof(sbuff) - len, " WR");

} else {

len += snprintf(sbuff + len, sizeof(sbuff) - len, " RO");

}

if(pInfo->flags & MTD_BIT_WRITEABLE) {

len += snprintf(sbuff + len, sizeof(sbuff) - len, " BitWR");

} else {

len += snprintf(sbuff + len, sizeof(sbuff) - len, "      ");

}

if(pInfo->flags & MTD_NO_ERASE) {

len += snprintf(sbuff + len, sizeof(sbuff) - len, " NoERA");

} else {

len += snprintf(sbuff + len, sizeof(sbuff) - len, " ERASE");

}

if(pInfo->flags & MTD_POWERUP_LOCK) {

len += snprintf(sbuff + len, sizeof(sbuff) - len, " PwrLOCK");

} else {

len += snprintf(sbuff + len, sizeof(sbuff) - len, " UnLOCK ");

}

len += snprintf(sbuff + len, sizeof(sbuff) - len, " Sz(%06x|%8u)", pInfo->size, pInfo->size);

len += snprintf(sbuff + len, sizeof(sbuff) - len, " ErSz(%5u)", pInfo->erasesize);

len += snprintf(sbuff + len, sizeof(sbuff) - len, " WrSz(%1u)", pInfo->writesize);

len += snprintf(sbuff + len, sizeof(sbuff) - len, " OobSz(%1u)", pInfo->oobsize);

len += snprintf(sbuff + len, sizeof(sbuff) - len, " Pad(%lu)", pInfo->padding);


len += snprintf(sbuff + len, sizeof(sbuff) - len, "\n");


printf(sbuff);

return 1;

}



#if 1 /* firstpw.2019.0110 */

#else /* firstpw.2019.0110 */

struct mtd_info_user {

 __u8 type;

 __u32 flags;

 __u32 size;

 __u32 erasesize;

 __u32 writesize;

 __u32 oobsize;

 __u64 padding;

};

#endif /* firstpw.2019.0110 */


int main(int argc, char *argv[])

{

mtd_info_t mtd_info;           // the MTD structure

erase_info_t ei;               // the erase block structure

int fd;

int i;

int ret;

char sbuff[256];


unsigned char data[20] = { 0xDE, 0xAD, 0xBE, 0xEF,  // our data to write

0xDE, 0xAD, 0xBE, 0xEF,

0xDE, 0xAD, 0xBE, 0xEF,

0xDE, 0xAD, 0xBE, 0xEF,

0xDE, 0xAD, 0xBE, 0xEF};

unsigned char read_buf[20] = {0x00};                // empty array for reading


for( i = 0; i < 9; i++) {

sprintf(sbuff, "/dev/mtd%d", i);


fd = open(sbuff, O_RDONLY);

if(fd < 0) {

printf("O_RDONLY> MTD Error: %d[%s]\n", errno, strerror(errno));

continue;

}


ret = ioctl(fd, MEMGETINFO, &mtd_info); 

if(ret < 0) {

printf("ioctl> MTD Error: %d[%s]\n", errno, strerror(errno));

continue;

}

print_mtd_info(sbuff, &mtd_info);


close(fd);

}

_exit(0);


for( i = 0; i < 9; i++) {

sprintf(sbuff, "/dev/mtd%d", i);


fd = open(sbuff, O_RDONLY);

printf("O_RDONLY>  [%s] Ret[%d]\n", sbuff, fd);

if(fd < 0) {

printf("O_RDONLY> MTD Error: %d[%s]\n", errno, strerror(errno));

} else {

close(fd);

}


fd = open(sbuff, O_WRONLY);

printf("O_WRONLY>  [%s] Ret[%d]\n", sbuff, fd);

if(fd < 0) {

printf("O_WRONLY> MTD Error: %d[%s]\n", errno, strerror(errno));

} else {

close(fd);

}


fd = open(sbuff, O_RDWR);

printf("O_RDWR>  [%s] Ret[%d]\n", sbuff, fd);

if(fd < 0) {

printf("O_RDWR> MTD Error: %d[%s]\n", errno, strerror(errno));

} else {

close(fd);

}

}

_exit(0);


fd = open(TARGET_MTD, O_RDWR); // open the mtd device for reading and 

// writing. Note you want mtd0 not mtdblock0

// also you probably need to open permissions

// to the dev (sudo chmod 777 /dev/mtd0)


if(fd < 0) {

exit_w_err("Open " TARGET_MTD, fd);

}


ret = lseek(fd, 0x1000, SEEK_SET);               // go to the first block

if(ret < 0) {

exit_w_err("lseek[0x1000] " TARGET_MTD, ret);

}

ret = read(fd, read_buf, sizeof(read_buf)); // read 20 bytes

if(ret < 0) {

exit_w_err("read[0x1000] " TARGET_MTD, ret);

}


// sanity check, should be all 0xFF if erase worked

for(i = 0; i<20; i++)

printf("Before buf[%d] = 0x%02x\n", i, (unsigned int)read_buf[i]);


ret = ioctl(fd, MEMGETINFO, &mtd_info);   // get the device info

if(ret < 0) {

exit_w_err("ioctl[MEMGETINFO] " TARGET_MTD, ret);

}

// dump it for a sanity check, should match what's in /proc/mtd

printf("MTD Type: %x\nMTD total size: %x bytes\nMTD erase size: %x bytes\n",

mtd_info.type, mtd_info.size, mtd_info.erasesize);


ei.length = mtd_info.erasesize;   //set the erase block size

for(ei.start = 0; ei.start < mtd_info.size; ei.start += ei.length)

{

ret = ioctl(fd, MEMUNLOCK, &ei);

if(ret < 0) {

exit_w_err("ioctl[MEMUNLOCK] " TARGET_MTD, ret);

}

printf("Eraseing Block %#x\n", ei.start); // show the blocks erasing

// warning, this prints a lot!

ret = ioctl(fd, MEMERASE, &ei);

if(ret < 0) {

exit_w_err("ioctl[MEMERASE] " TARGET_MTD, ret);

}

}    


ret = lseek(fd, 0, SEEK_SET);               // go to the first block

if(ret < 0) {

exit_w_err("lseek[0x1000] " TARGET_MTD, ret);

}

ret = read(fd, read_buf, sizeof(read_buf)); // read 20 bytes

if(ret < 0) {

exit_w_err("read[0x1000] " TARGET_MTD, ret);

}


// sanity check, should be all 0xFF if erase worked

for(i = 0; i<20; i++)

printf("buf[%d] = 0x%02x\n", i, (unsigned int)read_buf[i]);


ret = lseek(fd, 0, SEEK_SET);        // go back to first block's start

if(ret < 0) {

exit_w_err("lseek[0x1000] " TARGET_MTD, ret);

}

ret = write(fd, data, sizeof(data)); // write our message

if(ret < 0) {

exit_w_err("write[0x1000] " TARGET_MTD, ret);

}


ret = lseek(fd, 0, SEEK_SET);              // go back to first block's start

if(ret < 0) {

exit_w_err("lseek[0x1000] " TARGET_MTD, ret);

}

ret = read(fd, read_buf, sizeof(read_buf));// read the data

if(ret < 0) {

exit_w_err("read[0x1000] " TARGET_MTD, ret);

}


// sanity check, now you see the message we wrote!    

for(i = 0; i<20; i++)

printf("buf[%d] = 0x%02x\n", i, (unsigned int)read_buf[i]);


close(fd);

return 0;

}



반응형

'프로...Linux' 카테고리의 다른 글

[Util] sysdig - 사용자 감시  (0) 2019.01.15
[TS/Make] "aclocal-1.11: command not found"  (0) 2019.01.14
[Info] Check HW information  (0) 2018.12.21
[SCRIPT] partitioning  (0) 2018.12.14
[util] partition/mount - fdisk/lsblk(blkid)/df/mount  (0) 2018.12.14