https://en.wikipedia.org/wiki/MultiMediaCard#eMMC
위키피디아 번역
현재 구현된 임베디드 MMC(eMMC 또는 e.MMC) 아키텍처는 플래시 메모리, 버퍼 및 컨트롤러와 같은 MMC 구성 요소를 소형 ball grid array(BGA) IC 패키지에 넣어 회로 기판에 내장된 비휘발성 메모리 시스템으로 사용할 수 있도록 합니다. 이는 사용자가 탈착할 수 있는 카드가 아니라 printed circuit board(PCB)에 영구적으로 부착된다는 점에서 다른 버전의 MMC와 다릅니다.
따라서 메모리 또는 컨트롤러에 문제가 발생하면 eMMC를 교체하거나 수리해야 합니다. eMMC에서는 호스트 시스템이 논리 블록 주소(logical block addresses)에 데이터를 읽고 쓰기만 하면 됩니다. eMMC 컨트롤러 하드웨어와 펌웨어는 오류 수정 및 데이터 관리를 수행하여 호스트 시스템의 부담을 덜어줍니다. eMMC는 100, 153, 169 ball packages로 제공되며 8비트 병렬 인터페이스를 기반으로 합니다.
Universal Flash Storage(UFS)가 시장을 장악하기 시작한 2016년까지 거의 모든 휴대폰과 태블릿에서 이 형태의 플래시를 메인 스토리지로 사용했습니다. 하지만 2023년 현재에도 저가형 스마트폰을 비롯한 많은 소비자 애플리케이션에서 eMMC가 사용되고 있으며, Kioxia는 2024년 양산 예정인 최신 3D NAND 플래시 기반의 새로운 64GB 및 128GB eMMC 5.1 모듈을 출시했습니다.
eMMC는 SPI-bus protocol을 지원하지 않으며 NAND 플래시를 사용합니다.
https://www.jedec.org/standards-documents/technology-focus-areas/flash-memory-ssds-ufs-emmc/e-mmc
In January 2019, JEDEC published the latest version of its popular e.MMC standard: JESD84-B51A: Embedded MultiMediaCard (e.MMC), Electrical Standard (5.1A).
JESD84-B51A e.MMC v5.1A replaces all past versions of the e.MMC standard.
eMMC 와 SD/SDIO의 차이점
eMMC (embedded MultiMediaCard)
eMMC는 스마트폰, 태블릿, 스마트 TV, IoT 기기 등 다양한 전자 기기에 내장된 비휘발성 메모리 기술입니다. NAND 플래시 메모리와 메모리 컨트롤러를 단일 칩에 결합한 형태입니다. 주로 저장 장치로서 데이터를 읽고 쓰는 용도로 사용됩니다. 스마트폰이나 태블릿의 내부 저장소로 많이 사용되며, 주로 기기 내부에 고정된 형태로 제공됩니다.
작은 크기, 비교적 빠른 속도, 통합된 컨트롤러로 인해 기기 설계가 단순해지며, 가격 대비 성능이 우수합니다.
SD 카드처럼 탈착식이 아닌 기기 내부에 고정된 형태입니다.
SD/SDIO 카드
SD 카드는 탈착식 메모리 카드로, 외장형 저장 장치로 사용됩니다. SDIO 카드는 데이터 저장뿐 아니라 다른 기능(예: Wi-Fi 모듈)을 제공할 수 있습니다. 주로 외부 저장 용도로 사용되며, 다양한 장치에서 데이터 전송 및 외부 장치의 기능 확장을 지원합니다. 다양한 장치 간에 손쉽게 이동하며 데이터를 공유할 수 있습니다. 또한 추가 기능이 필요한 경우 SDIO 카드를 통해 기능 확장이 가능합니다.
리눅스 드라이버
리눅스에서 eMMC의 드라이버는 커널의 MMC (MultiMediaCard) 서브시스템 내에 포함되어 있습니다. eMMC는 기본적으로 SD 카드와 유사한 MMC 표준을 따르기 때문에, 리눅스 커널의 MMC 서브시스템을 통해 eMMC를 제어하고 관리합니다.
위치: drivers/mmc/
이 경로 아래에 있는 드라이버들이 MMC, SD, eMMC와 같은 장치들을 관리합니다. 이 서브시스템에는 호스트 컨트롤러 드라이버와 카드 드라이버가 포함됩니다.
주요 파일 및 디렉토리 설명
drivers/mmc/core/
: MMC의 핵심 기능을 담당하는 파일들이 위치합니다. 여기에는 MMC 카드 초기화, 데이터 전송, 카드 식별 등의 기능이 포함됩니다.
core.c
: MMC 카드의 기본적인 기능을 처리하는 코어 드라이버.mmc.c
: MMC 카드의 초기화 및 데이터 전송 관리.
drivers/mmc/host/
: 특정 하드웨어 호스트 컨트롤러에 대한 드라이버가 위치합니다. 여기에는 다양한 하드웨어에 대한 지원을 제공하는 드라이버들이 포함됩니다. 예를 들어, Qualcomm, Samsung, MediaTek 등의 eMMC 컨트롤러에 대한 드라이버가 여기에 존재할 수 있습니다.
- 일반적으로 sdhci-xxx.c 형태의 파일명으로 된 SD Host Controller Interface (SDHCI) 기반 드라이버들이 있습니다. 많은 eMMC 컨트롤러들이 SDHCI 표준을 따르기 때문입니다.
디바이스 확인
eMMC 장치는 /dev/mmcblkX
형식으로 인식됩니다.
$ ls -la /dev/mmcblk*
brw-rw---- 1 root disk 179, 0 2024-10-24 04:39 /dev/mmcblk0
brw-rw---- 1 root disk 179, 32 2024-10-24 04:39 /dev/mmcblk0boot0
brw-rw---- 1 root disk 179, 64 2024-10-24 04:39 /dev/mmcblk0boot1
crw------- 1 root root 242, 0 2024-10-24 04:39 /dev/mmcblk0rpmb
$ dmesg | grep mmcblk
mmcblk0: mmc0:0001 4FTE4R 3.64 GiB
mmcblk0boot0: mmc0:0001 4FTE4R partition 1 4.00 MiB
mmcblk0boot1: mmc0:0001 4FTE4R partition 2 4.00 MiB
mmcblk0rpmb: mmc0:0001 4FTE4R partition 3 512 KiB, chardev (242:0)
[mmcblk0p01] bootloader offset 0x000000000000, size 0x000000400000
[mmcblk0p06] recovery offset 0x000027800000, size 0x000002000000
[mmcblk0p10] boot offset 0x00002d800000, size 0x000004000000
[mmcblk0p12] tee offset 0x000033800000, size 0x000002000000
[mmcblk0p14] vendor offset 0x000037000000, size 0x000002000000
[mmcblk0p17] system offset 0x000042a00000, size 0x00004b000000
[mmcblk0p19] data offset 0x000096a00000, size 0x000052600000
EXT4-fs (mmcblk0p17): mounted filesystem with ordered data mode. Opts: (null)
EXT4-fs (mmcblk0p19): mounted filesystem with ordered data mode. Opts: (null)
EXT4-fs (mmcblk0p14): mounted filesystem with ordered data mode. Opts: (null)
EXT4-fs (mmcblk0p12): mounted filesystem with ordered data mode. Opts:
"/dev/mmcblk0rpmb" 는 뭘까?
Replay Protected Memory Block
https://en.wikipedia.org/wiki/Replay_Protected_Memory_Block
번역
Replay Protected Memory Block(RPMB)은 시스템이 특정 메모리 영역에 인증되고 재생 보호된 방식으로 데이터를 저장하는 수단으로 제공되며, 성공적으로 인증된 읽기 및 쓰기 액세스를 통해서만 읽고 쓸 수 있습니다. 호스트가 데이터를 덮어쓸 수는 있지만 절대 지울 수는 없습니다.
RPMB는 변조 방지(tamper-resistant) 기능이 있으므로 임베디드 시스템에서 데이터가 중요한 다양한 목적을 위한 저장 매체로 사용할 수 있습니다.
- 프로그래밍 가능한 ROM(programmable ROM) 스토리지가 없거나 데이터가 너무 큰 경우 시스템에 "영구" 또는 "사전 프로그래밍된" 데이터를 쓰기 위한 장소.
- 암호화 및 하드웨어 퓨즈(hardware fuses)와 함께 신뢰할 수 있는 실행 환경을 위한 신뢰 스토리지 솔루션 구축
- 버전화된 데이터(키, 암호화된 파일, 소프트웨어 등)를 위한 롤백 방지에도 사용할 수 있습니다.
- 신뢰할 수 있는 애플리케이션을 위한 스토리지
Linux와 같은 일부 운영 체제에서는 eMMC에 연결된 RPMB 장치에 액세스하기 위한 일반 드라이버를 제공할 수 있지만 다른 경우에는 독점 드라이버를 통해 RPMB 액세스가 제어되므로 데이터에 액세스하려면 일반 애플리케이션 대신 신뢰할 수 있는 애플리케이션을 사용해야 할 수 있습니다.
RPMB, a secret place inside the eMMC
아래 블로그의 일부
https://sergioprado.blog/rpmb-a-secret-place-inside-the-emmc/
What is the RPMB partition?
RPMB (Replay Protected Memory Block) is a dedicated partition available on some flash-based storage devices (eMMC, UFS, NVMe, etc) that makes it possible to store and retrieve data with integrity and authenticity support.
The RPMB interface is defined by the JEDEC organization and can be accessed with a specific and standardized security protocol that has its own commands and data structures.
It uses symmetric key authentication, where an authentication key is used by both the host (e.g. Linux OS) and the device (e.g. eMMC) to exchange authenticated data.
What is a replay attack?
A replay (or playback) attack occurs when a program copies data from a legitimate interaction involving two entities and then re-transmits the same data in a later stage.
In RPMB, a read-only counter is used at every write operation. This counter is incremented after every write operation and it is included in the calculation of the next MAC to be sent. So even if someone is able to intercept the write operation, replaying the same message would not work because it would require the re-calculation of the MAC with the new counter, and that can only be done by the one that has also the authentication key!
https://en.wikipedia.org/wiki/Replay_Protected_Memory_Block#Memory_layout
An RPMB device supplies the following memory sections:
This is the minimum defined by the specification, the actual block size depends on the flash vendor's implementation.
Linux driver
block.c
/**
* struct mmc_rpmb_data - special RPMB device type for these areas
* @dev: the device for the RPMB area
* @chrdev: character device for the RPMB area
* @id: unique device ID number
* @part_index: partition index (0 on first)
* @md: parent MMC block device
* @node: list item, so we can put this device on a list
*/
struct mmc_rpmb_data {
struct device dev;
struct cdev chrdev;
int id;
unsigned int part_index;
struct mmc_blk_data *md;
struct list_head node;
};
struct mmc_blk_ioc_data {
struct mmc_ioc_cmd ic;
unsigned char *buf;
u64 buf_bytes;
unsigned int flags;
#define MMC_BLK_IOC_DROP BIT(0) /* drop this mrq */
#define MMC_BLK_IOC_SBC BIT(1) /* use mrq.sbc */
struct mmc_rpmb_data *rpmb;
};
static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
{
int idx, ret;
if (!mmc_card_mmc(card))
return 0;
for (idx = 0; idx < card->nr_parts; idx++) {
if (card->part[idx].area_type & MMC_BLK_DATA_AREA_RPMB) {
/*
* RPMB partitions does not provide block access, they
* are only accessed using ioctl():s. Thus create
* special RPMB block devices that do not have a
* backing block queue for these.
*/
ret = mmc_blk_alloc_rpmb_part(card, md,
card->part[idx].part_cfg,
card->part[idx].size >> 9,
card->part[idx].name);
if (ret)
return ret;
} else if (card->part[idx].size) {
ret = mmc_blk_alloc_part(card, md,
card->part[idx].part_cfg,
card->part[idx].size >> 9,
card->part[idx].force_ro,
card->part[idx].name,
card->part[idx].area_type);
if (ret)
return ret;
}
}
return 0;
}
static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
struct mmc_blk_ioc_data **idatas, int i)
{
// ...
/*
* The RPMB accesses comes in from the character device, so we
* need to target these explicitly. Else we just target the
* partition type for the block device the ioctl() was issued
* on.
*/
if (idata->rpmb) {
/* Support multiple RPMB partitions */
target_part = idata->rpmb->part_index;
target_part |= EXT_CSD_PART_CONFIG_ACC_RPMB;
} else {
target_part = md->part_type;
}
// ...
if (idata->rpmb || prev_idata) {
sbc.opcode = MMC_SET_BLOCK_COUNT;
/*
* We don't do any blockcount validation because the max size
* may be increased by a future standard. We just copy the
* 'Reliable Write' bit here.
*/
sbc.arg = data.blocks | (idata->ic.write_flag & BIT(31));
if (prev_idata)
sbc.arg = prev_idata->ic.arg;
sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
mrq.sbc = &sbc;
}
}
/**
* mmc_rpmb_ioctl() - ioctl handler for the RPMB chardev
* @filp: the character device file
* @cmd: the ioctl() command
* @arg: the argument from userspace
*
* This will essentially just redirect the ioctl()s coming in over to
* the main block device spawning the RPMB character device.
*/
static long mmc_rpmb_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
struct mmc_rpmb_data *rpmb = filp->private_data;
int ret;
switch (cmd) {
case MMC_IOC_CMD:
ret = mmc_blk_ioctl_cmd(rpmb->md,
(struct mmc_ioc_cmd __user *)arg,
rpmb);
break;
case MMC_IOC_MULTI_CMD:
ret = mmc_blk_ioctl_multi_cmd(rpmb->md,
(struct mmc_ioc_multi_cmd __user *)arg,
rpmb);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
"/dev/mmcblk0boot0" 는 뭘까?
Boot partition
Pengutronix - eMMC Hardware Partitioning
The two boot hardware partitions are special and play an important role when the bootloader is started. The CPU can access their content in a simplified manner, which accelerates loading and running a bootloader. Some eMMC devices allow to configure their size as well.
eMMC flash | Embedded Artists Developer Site
When the eMMC component is delivered from the manufacturer it is normally divided into four areas as shown in the figure below.