Memory Technology Device - MTD Katmanı
MTD katmanı, donanım spesifik raw flash aygıt sürücüleri ile bunları kullanacak üst seviyeli katmanlar arasında bir soyutlama yapılabilmesini sağlar.
raw flash tabanlı ortamlarda kullanılır.
MTD katmanı tarafından algılanan aygıtlar, /proc/mtd
dosyasından görüntülenebilir:
$ cat /proc/mtd
dev: size erasesize name
mtd0: 00020000 00020000 "u-boot env"
mtd1: 00020000 00020000 "UBL"
mtd2: 00080000 00020000 "u-boot"
mtd3: 00400000 00020000 "kernel"
mtd4: 08000000 00020000 "filesystem1"
mtd5: 07a00000 00020000 "filesystem2"
MTD Karakter Aygıtı Desteği
mtdchar sürücüsü sistemde algılanan her bir MTD bölümüne (partition) karşılık, karakter tabanlı erişimi simüle edecek bir karakter aygıtı oluşturur.
Major numarası 90 (5A) şeklindedir. İsimlendirmesi /dev/mtdXX
şeklinde yapılır.
Read-Only erişimler için tek sayılı minor numaraları, read-write erişim için çift sayılı minor numaraları kullanılır.
raw flash üzerinde yapılacak işlemler ve silme operasyonları için ek ioctl çağrıları içerir.
Genellikle mtd-utils paketinden çıkan uygulamalar tarafından kullanılır.
MTD Blok Aygıtı Desteği
mtdblock sürücüsü sistemde algılanan her bir MTD bölümüne (partition) karşılık, blok tabanlı erişimi simüle edecek bir blok aygıtı oluşturur.
Major numarası 31 (1F) şeklindedir. İsimlendirmesi /dev/mtdblockXX
şeklinde yapılır.
Minor numarası, MTD bölümünün numarasını gösterir.
Blok tabanlı okuma-yazma operasyonlarını destekler. Ancak bozuk blok yönetimi, yazma operasyonlarının farklı bloklara dağıtılması (wear-levelling) gibi destekleri bulunmamaktadır.
MTD Partitioning (Bölümlendirme)
MTD aygıtları, bir gereklilik olmamakla birlikte, çoğu durumda bölümlendirme yapılarak kullanılırlar.
Bu şekilde MTD aygıtının farklı alanlarını, farklı özelliklerde (read-write, read-only vb.) ve amaçlarda kullanmak kolaylaşır.
Blok tabanlı aygıtlarda mevcut olan bölümlendirme tablosu (partition table) yapısı, MTD aygıtlarında yer almaz.
Bu nedenle bölümlendirme tablosunun nasıl olduğunun harici bir yerde saklanması gerekir. Bu harici yer, kernel kodunun içerisinde hard-coded biçiminde veya kernel açılış parametreleri sayesinde her açılışta parametrelerin okunması suretiyle gerçeklenir.
Redboot gibi bazı boot yükleyici uygulamaları, sabit disk gibi aygıtlara benzer şekilde bölümlendirme tablosunu MTD aygıtının belirli bir yerinde tutma alternatif yöntemiyle de çalışabilmektedirler. Bu senaryoda kernel tarafından ilgili bölümlendirme kurallarının okunup anlaşılabilmesi için, kernel derleme sürecinde Redboot Partition Table Parsing seçeneğinin aktifleştirilmesi gereklidir.
MTD Partitioning
Hardcode Yöntemi
Doğrudan ilgili MTD sürücüsü içerisinde yapılır. Örnek olara arch/arm/mach-omap2/board-omap3beagle.c
içerisine bakalım:
static struct mtd_partition omap3beagle_nand_partitions[] = {
/* All the partition sizes are listed in terms of NAND block size */
{
.name = "X-Loader",
.offset = 0,
.size = 4 * NAND_BLOCK_SIZE,
.mask_flags = MTD_WRITEABLE, /* force read-only */
},
{
.name = "U-Boot",
.offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */
.size = 15 * NAND_BLOCK_SIZE,
.mask_flags = MTD_WRITEABLE, /* force read-only */
},
{
.name = "U-Boot Env",
.offset = MTDPART_OFS_APPEND, /* Offset = 0x260000 */
.size = 1 * NAND_BLOCK_SIZE,
},
{
.name = "Kernel",
.offset = MTDPART_OFS_APPEND, /* Offset = 0x280000 */
.size = 32 * NAND_BLOCK_SIZE,
},
{
.name = "File System",
.offset = MTDPART_OFS_APPEND, /* Offset = 0x680000 */
.size = MTDPART_SIZ_FULL,
},
};
Bu modelde çalışan çekirdek yeniden derlenmeden, bölümlendirme tablosunu değiştirmek mümkün olmaz. Kulağa hoş gelmiyor olsa da pek çok sistem bu şekilde çalışmaktadır. Gömülü sistemlerin dizaynı yapıldıktan sonra sahadaki kullanımında sonradan bölümlendirme tablosunun yeniden yapılandırılması ihtiyacı genellikle oluşmaz. Böyle bir ihtiyacın oluşması durumu, muhtemel bir tasarım süreci problemine işaret eder.
Kernel Parametresiyle Bölümlendirme
Kernel açılış parametresi olarak aşağıdaki formatta değer girilmek suretiyle bölümlendirme tablosunu tanımlamak mümkündür:
mtdparts=davinci_nand:4m(kernel)ro,32m(rootfs)ro,100m(data),-(archive)
Bu örnekte;
- 4 MB Kernel için read-only,
- 32 MB kök dosya sistemi için
rootfs
adında read-only, - 100 MB
data
adında genel bir yazılabilir bölüm - Ve flash'ın geri kalan kısmının tamamından oluşan
archive
adında bir bölüm daha oluşturulmuştur.
Kernel'ın ilgili flash çipini hangi anahtar kelime üzerinden tanıdığını önceden öğrenmek veya açılış loglarından takip etmek gerekir. Bu örnekte anahtar kelime davinci_nand
şeklindedir. Sistemde birden fazla NAND flash çipi de bulunabilir. Bu şekilde hangi sürücü üzerinden hangi çipe erişmek istediğimizi de belirtmiş oluyoruz. Aynı sürücüde birden fazla çip olduğunda, instance numarası da kullanılır.
MTD Bölümünün Silinmesi
Bir MTD bölümünün tamamının veya belirli sayıdaki blokunun silinmesi için mtd-utils paketinden çıkan flash_erase
uygulaması kullanılır:
flash_erase <mtd_device> <offset> <block_count>
Offset değeri olarak 0
ve block count değeri olarak 0
girilmesi durumunda, tüm bölüm silinir.
Bloklar daha önceden kilitlenmiş durumda ise, -u
parametresi ile veya flash_unlock
uygulaması ile kilit kaldırılır.
Örnek kullanım:
flash_erase -u /dev/mtd3 0 0
MTD Bölümüne Yazma
Bir MTD bölümüne yazma (dosyasistemi imajını) işlemi için mtd-utils paketinden çıkan flashcp
ve nandwrite
uygulamaları kullanılır.
nandwrite -p <mtd_device> <file_name>
flashcp <file_name> <mtd_device>
nandwrite uygulaması NAND flash tipinde, flashcp uygulaması NOR flash tipinde kullanılır.
nandwrite uygulaması biraz daha yetenekli oluğ, padding vb. gibi daha fazla seçenek sunmaktadır.
Örnek kullanım:
nandwrite -p /dev/mtd3 /tmp/jffs.image
flashcp /tmp/jffs.image /dev/mtd3
MTD Aygıt Simülasyonu
Geliştirme ortamınızdaki bilgisayarda NAND flash bulunmayacağı için sürekli bir cihaz üzerinde çalışmanın mümkün olmadığı senaryolarda, nandsim
modülü üzerinden NAND flash ortamını simüle etmeniz mümkündür.
NAND simulator (nandsim) NAND flash aygıtını RAM veya bir dosya üzerinde simüle eder. nandsim
modülünü yüklerken simülasyonun durumunu etkileyecek pek çok modül parametresi bulunmaktadır. Başlıca modül parametreleri aşağıdaki gibidir:
first_id_byte
: NAND flash üzerinden okunacak ilk byte'ın ne olacağını gösterir (read ID
komutuna dönen cevap,manufacturer ID
değeri olarak yorumlanacaktır). Kernel kaynak kodu içerisindekiinclude/linux/mtd/nand.h
dosyasında NAND üretici kodları tanımlıdır.second_id_byte
: NAND flash üzerinden okunacak ikinci byte'ın ne olacağını gösterir (read ID
komutuna dönen cevap,chip ID
değeri olarak yorumlanacaktır).drivers/mtd/nand/nand_ids.c
dosyasında chip ID değerleri yer almaktadır. Örnek olarak0x78
chip ID değeri, 128MiB 1,8V 8-bit NAND iken,0xC5
2GiB 3,3V 16-bit NAND çipini gösterir.
Bunların haricinde nandsim
modülünün 20 kadar daha parametresi bulunmaktadır. Parametrelerin listesini modinfo
komutuyla alabilirsiniz:
$ sudo modinfo nandsim
parm: first_id_byte:The first byte returned by NAND Flash 'read ID' command (manufacturer ID) (uint)
parm: second_id_byte:The second byte returned by NAND Flash 'read ID' command (chip ID) (uint)
parm: third_id_byte:The third byte returned by NAND Flash 'read ID' command (uint)
parm: fourth_id_byte:The fourth byte returned by NAND Flash 'read ID' command (uint)
parm: access_delay:Initial page access delay (microseconds) (uint)
parm: programm_delay:Page programm delay (microseconds (uint)
parm: erase_delay:Sector erase delay (milliseconds) (uint)
parm: output_cycle:Word output (from flash) time (nanoseconds) (uint)
parm: input_cycle:Word input (to flash) time (nanoseconds) (uint)
parm: bus_width:Chip's bus width (8- or 16-bit) (uint)
parm: do_delays:Simulate NAND delays using busy-waits if not zero (uint)
parm: log:Perform logging if not zero (uint)
parm: dbg:Output debug information if not zero (uint)
parm: parts:Partition sizes (in erase blocks) separated by commas (array of ulong)
parm: badblocks:Erase blocks that are initially marked bad, separated by commas (charp)
parm: weakblocks:Weak erase blocks [: remaining erase cycles (defaults to 3)] separated by commas e.g. 113:2 means eb 113 can be erased only twice before failing (charp)
parm: weakpages:Weak pages [: maximum writes (defaults to 3)] separated by commas e.g. 1401:2 means page 1401 can be written only twice before failing (charp)
parm: bitflips:Maximum number of random bit flips per page (zero by default) (uint)
parm: gravepages:Pages that lose data [: maximum reads (defaults to 3)] separated by commas e.g. 1401:2 means page 1401 can be read only twice before failing (charp)
parm: overridesize:Specifies the NAND Flash size overriding the ID bytes. The size is specified in erase blocks and as the exponent of a power of two e.g. 5 means a size of 32 erase blocks (uint)
parm: cache_file:File to use to cache nand pages instead of memory (charp)
parm: bbt:0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in data area (uint)
parm: bch:Enable BCH ecc and set how many bits should be correctable in 512-byte blocks (uint)
Şimdi Fujitsu üreticisi için (0x04), 128 MiB'lık NAND flash (0x78) çipini simüle edelim:
$ sudo modprobe nandsim first_id_byte=0x04 second_id_byte=0x78
Sonrasında dmesg
komutuyla kernel buffer alanının son kısmına bakalım:
$ dmesg
[14399.796192] nand: device found, Manufacturer ID: 0x04, Chip ID: 0x78
[14399.796192] nand: Fujitsu NAND 128MiB 1,8V 8-bit
[14399.796193] nand: 128MiB, SLC, page size: 512, OOB size: 16
[14399.796203] flash size: 128 MiB
[14399.796203] page size: 512 bytes
[14399.796204] OOB area size: 16 bytes
[14399.796205] sector size: 16 KiB
[14399.796205] pages number: 262144
[14399.796206] pages per sector: 32
[14399.796206] bus width: 8
[14399.796207] bits in sector size: 14
[14399.796207] bits in page size: 9
[14399.796208] bits in OOB size: 4
[14399.796209] flash size with OOB: 135168 KiB
[14399.796209] page address bytes: 4
[14399.796210] sector address bytes: 3
[14399.796210] options: 0x42
[14399.796646] Scanning device for bad blocks
[14399.803631] Creating 1 MTD partitions on "NAND 128MiB 1,8V 8-bit":
[14399.803635] 0x000000000000-0x000008000000 : "NAND simulator partition 0"
$ cat /proc/mtd
dev: size erasesize name
mtd0: 08000000 00004000 "NAND simulator partition 0"
Artık kernel açısından normal bir MTD aygıtımız oluşmuş oldu. MTD aygıtları üzerindeki tüm işlemleri burada yapabiliriz (Jffs2, Ubi, Ubifs çalışmaları, flash_erase
, nandwrite
vb.)