Using eMMC/SDHCI

Using eMMC/SDHCI#

emmc-drv is an L4Re block driver for eMMC and SDHC devices. It works also in QEMU, which we show here how to setup.

The function of the driver is to provide access to a eMMC/SDHC device per granularity of GPT partitions. In other words, the driver provides one Virtio-Block device per GPT partition on the storage device.

Setting up the setup#

The following ned script shows the necessary steps to launch the driver and provide Virtio-block device to potential clients, such as a virtual machine or an L4Re application.

emmc-qemu.ned#
 1-- vi:ft=lua
 2local L4 = require("L4");
 3local ld = L4.default_loader;
 4
 5local emmc_driver_params = "" ..
 6  "-v " ..
 7  "--client disk1 --device 0FC63DAF-8483-4772-8E79-3D69D8477DE4"
 8
 9local hw_desc_file = "";
10if L4.Info.arch() == "arm64" or L4.Info.arch() == "arm" then
11  hw_desc_file = "rom/hw_devices.io";
12end
13
14local vbus_sdhci = ld:new_channel();
15ld:start({ caps = {
16                    sigma0   = L4.Env.sigma0;
17                    icu      = L4.Env.icu;
18                    iommu    = L4.Env.iommu,
19                    sdhci    = vbus_sdhci:svr();
20                  },
21         },
22         "rom/io -vvvv " .. hw_desc_file .. " rom/vbus.io");
23
24local emmc_part1 = ld:new_channel()
25ld:start({ caps = {
26                    vbus   = vbus_sdhci,
27                    disk1  = emmc_part1:svr(),
28         },
29         log = { "emmc", "cyan" },
30         }, "rom/emmc-drv " .. emmc_driver_params);
31
32-- 'emmc_part1' is now a valid virtio-block capability

The config file for IO looks like this. As QEMU provides the controller as a PCIe device, no further setup is required.

vbus.io#
Io.add_vbus("sdhci", Io.Vi.System_bus
{
  pci_08 = wrap(Io.system_bus():match("PCI/CC_0805")), -- SDHCI
})

A module.list entry looks like this:

modules.list#
entry emmc-qemu
roottask moe rom/emmc-qemu.ned
kernel fiasco -serial_esc
module l4re
module ned
module io
module emmc-drv
module emmc-qemu.ned
module[arch=arm64] io/plat-arm_virt/hw_devices.io
module[arch=arm] io/plat-arm_virt/hw_devices.io
module vbus.io

Put all the files in a directory picked up by L4Re’s image generation.

Run it with QEMU#

First, we need to create a disk image to be presented to QEMU and used as a storage for the eMMC/SDHCI:

dd if=/dev/zero of=/tmp/emmc.img bs=1M count=16

Then we need to create GPT partitions in the file. For simplicity we just create a single partition. We also query the partition GUID as we need it to put in the ned script.

$ gdisk /tmp/emmc.img 
GPT fdisk (gdisk) version 1.0.10
  
Partition table scan:
  MBR: not present
  BSD: not present
  APM: not present
  GPT: not present
  
Creating new GPT entries in memory.
 
Command (? for help): n
Partition number (1-128, default 1): 
First sector (34-32734, default = 2048) or {+-}size{KMGTP}: 
Last sector (2048-32734, default = 30719) or {+-}size{KMGTP}: 
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): 
Changed type of partition to 'Linux filesystem'

Command (? for help): i
Using 1
Partition GUID code: 0FC63DAF-8483-4772-8E79-3D69D8477DE4 (Linux filesystem)
Partition unique GUID: 8B5424CF-C8D3-4B21-BE37-66D7FC61B1BC
First sector: 2048 (at 1024.0 KiB)
Last sector: 30719 (at 15.0 MiB)
Partition size: 28672 sectors (14.0 MiB)
Attribute flags: 0000000000000000
Partition name: 'Linux filesystem'

Command (? for help): w
  
Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!
  
Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to emmc.img.
Warning: The kernel is still using the old partition table.
The new table will be used at the next reboot or after you
run partprobe(8) or kpartx(8)
The operation has completed successfully.
$

The use-case can be run like this in one command for arm64. Of course, variables can also be put into your Makeconf.boot file, shortening the below command to just make qemu E=emmc-qemu. It also works on x86-64 accordingly.

make qemu E=emmc-qemu \
     MODULES_LIST=$PWD/modules.list \
     MODULE_SEARCH_PATH=$PWD/fiasco/build \
     QEMU_OPTIONS="-M virt -cpu cortex-a57 -serial stdio -vnc none -m 1g -drive id=sd_disk,file=/tmp/emmc.img,if=none,format=raw -device sdhci-pci,id=sdhci -device sd-card,drive=sd_disk,spec_version=3"