├── docs ├── _static │ └── .gitkeep ├── requirements.txt ├── index.rst ├── Makefile ├── README.rst ├── conf.py └── HOWTO.rst ├── .gitignore ├── man ├── Makefile └── mmc.1 ├── .readthedocs.yaml ├── Android.mk ├── README ├── Makefile ├── mmc_cmds.h ├── 3rdparty └── hmac_sha │ ├── sha2.h │ ├── hmac_sha2.h │ ├── hmac_sha2.c │ └── sha2.c ├── mmc.h ├── mmc.1 ├── mmc.c └── lsmmc.c /docs/_static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx==4.3.2 2 | jinja2>=2.11 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .*.o.d 2 | *.o 3 | docs/_build 4 | /mmc 5 | -------------------------------------------------------------------------------- /man/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | clean: 3 | install: 4 | 5 | .PHONY: all clean install 6 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | # .readthedocs.yaml 3 | version: 2 4 | 5 | sphinx: 6 | configuration: docs/conf.py 7 | 8 | formats: all 9 | 10 | python: 11 | install: 12 | - requirements: docs/requirements.txt 13 | 14 | build: 15 | os: "ubuntu-22.04" # Specify the OS (if this option becomes available) 16 | tools: 17 | python: "3.8" 18 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. SPDX-License-Identifier: GPL-2.0-only 2 | .. mmc-utils documentation master file, created by 3 | sphinx-quickstart on Sat Jun 22 16:14:46 2024. 4 | You can adapt this file completely to your liking, but it should at least 5 | contain the root `toctree` directive. 6 | 7 | Welcome to mmc-utils's documentation! 8 | ===================================== 9 | 10 | .. toctree:: 11 | :maxdepth: 2 12 | :caption: Contents 13 | 14 | ../README.rst 15 | ../HOWTO.rst 16 | 17 | 18 | -------------------------------------------------------------------------------- /Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH:= $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | LOCAL_MODULE_TAGS := optional 5 | LOCAL_SRC_FILES:= mmc.c mmc_cmds.c 6 | LOCAL_SRC_FILES += 3rdparty/hmac_sha/sha2.c 3rdparty/hmac_sha/hmac_sha2.c 7 | LOCAL_MODULE := mmc_utils 8 | LOCAL_SHARED_LIBRARIES := libcutils libc 9 | LOCAL_C_INCLUDES+= $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include 10 | LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr 11 | LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/mmc-utils 12 | include $(BUILD_EXECUTABLE) 13 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | MMC tools (mmc-utils) 2 | ===================== 3 | 4 | mmc-utils is a tool for configuring MMC storage devices from userspace. 5 | 6 | Contribution guidelines 7 | ----------------------- 8 | 9 | The project works using a mailing list patch submission process, similar to the 10 | process used for the Linux kernel itself. 11 | 12 | One can document themselves by reading how to submit a patch in the official 13 | Linux kernel documentation: 14 | https://www.kernel.org/doc/html/latest/process/submitting-patches.html 15 | Not all sections apply but it should be a good way to get started. 16 | 17 | A patch should be sent as a mail (not as an attachement, see documentation 18 | above) to the linux-mmc@vger.kernel.org mailing list with maintainers as 19 | Cc recipients. 20 | 21 | Documentation 22 | ------------- 23 | https://mmc-utils.readthedocs.io/en/latest/ 24 | 25 | 26 | Maintainers 27 | ----------- 28 | 29 | Avri Altman 30 | Ulf Hansson 31 | 32 | License 33 | ------- 34 | 35 | This project is licensed under GPL-2.0-only. 36 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC ?= gcc 2 | GIT_VERSION := "$(shell git describe --abbrev=6 --always --tags)" 3 | AM_CFLAGS = -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 \ 4 | -DVERSION=\"$(GIT_VERSION)\" 5 | CFLAGS ?= -g -O2 6 | objects = \ 7 | mmc.o \ 8 | mmc_cmds.o \ 9 | lsmmc.o \ 10 | 3rdparty/hmac_sha/hmac_sha2.o \ 11 | 3rdparty/hmac_sha/sha2.o 12 | 13 | CHECKFLAGS = -Wall -Werror -Wuninitialized -Wundef 14 | 15 | DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@ 16 | 17 | override CFLAGS := $(CHECKFLAGS) $(AM_CFLAGS) $(CFLAGS) 18 | 19 | INSTALL = install 20 | prefix ?= /usr/local 21 | bindir = $(prefix)/bin 22 | LIBS= 23 | RESTORE_LIBS= 24 | mandir = /usr/share/man 25 | 26 | progs = mmc 27 | 28 | # make C=1 to enable sparse - default 29 | C ?= 1 30 | ifeq "$(C)" "1" 31 | check = sparse $(CHECKFLAGS) $(AM_CFLAGS) 32 | endif 33 | 34 | all: $(progs) 35 | 36 | .c.o: 37 | ifeq "$(C)" "1" 38 | $(check) $< 39 | endif 40 | $(CC) $(CPPFLAGS) $(CFLAGS) $(DEPFLAGS) -c $< -o $@ 41 | 42 | mmc: $(objects) 43 | $(CC) $(CFLAGS) -o $@ $(objects) $(LDFLAGS) $(LIBS) 44 | 45 | manpages: 46 | $(MAKE) -C man 47 | 48 | clean: 49 | rm -f $(progs) $(objects) 50 | $(MAKE) -C man clean 51 | $(MAKE) -C docs clean 52 | 53 | install: $(progs) 54 | $(INSTALL) -m755 -d $(DESTDIR)$(bindir) 55 | $(INSTALL) $(progs) $(DESTDIR)$(bindir) 56 | $(INSTALL) -m755 -d $(DESTDIR)$(mandir)/man1 57 | $(INSTALL) -m 644 mmc.1 $(DESTDIR)$(mandir)/man1 58 | 59 | -include $(foreach obj,$(objects), $(dir $(obj))/.$(notdir $(obj)).d) 60 | 61 | .PHONY: all clean install manpages install-man 62 | 63 | # Add this new target for building HTML documentation using docs/Makefile 64 | html-docs: 65 | $(MAKE) -C docs html 66 | -------------------------------------------------------------------------------- /docs/README.rst: -------------------------------------------------------------------------------- 1 | .. SPDX-License-Identifier: GPL-2.0-only 2 | 3 | README Intro 4 | -------------------- 5 | 6 | mmc-utils is a tool for configuring MMC storage devices from userspace. 7 | 8 | 9 | Source 10 | ------ 11 | 12 | mmc-utils resides in a git repo, the canonical place is: 13 | 14 | https://git.kernel.org/pub/scm/utils/mmc/mmc-utils.git 15 | 16 | 17 | Mailing list 18 | ------------ 19 | 20 | The project uses the kernel's mmc mailing list. There you should submit your 21 | patches, ask for help, or discuss mmc-utils related issues. A patch should be 22 | sent as a mail to the linux-mmc@vger.kernel.org mailing list with maintainers 23 | as Cc recipients. Archives can be found here: 24 | 25 | https://www.spinics.net/lists/linux-mmc/ 26 | 27 | or here: 28 | 29 | https://lore.kernel.org/linux-mmc/ 30 | 31 | 32 | Author 33 | ------ 34 | 35 | mmc-utils was written by Chris Ball and . 36 | 37 | 38 | Maintainers 39 | ----------- 40 | 41 | Avri Altman 42 | Ulf Hansson 43 | 44 | 45 | Building 46 | -------- 47 | 48 | Just type:: 49 | 50 | $ make 51 | $ make install 52 | 53 | Note that GNU make is required. Make install also builds the man page 54 | 55 | To cross-compile mmc-utils you can use environment variables. e.g. to build 56 | statically linked for ARM64:: 57 | 58 | $ make clean 59 | $ CC=aarch64-linux-gnu-gcc CFLAGS=' -g -O2 -static' make 60 | 61 | 62 | Documentation 63 | ------------- 64 | 65 | mmc-utils uses Sphinx_ to generate documentation from the reStructuredText_ files. 66 | To build HTML formatted documentation run ``make html-docs`` and direct your 67 | browser to :file:`./docs/_build/html/index.html`. 68 | 69 | .. _reStructuredText: https://www.sphinx-doc.org/rest.html 70 | .. _Sphinx: https://www.sphinx-doc.org 71 | 72 | 73 | License 74 | ------- 75 | 76 | This project is licensed under GPL-2.0-only. 77 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | # Configuration file for the Sphinx documentation builder. 3 | # 4 | # This file only contains a selection of the most common options. For a full 5 | # list see the documentation: 6 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 7 | 8 | # -- Path setup -------------------------------------------------------------- 9 | 10 | # If extensions (or modules to document with autodoc) are in another directory, 11 | # add these directories to sys.path here. If the directory is relative to the 12 | # documentation root, use os.path.abspath to make it absolute, like shown here. 13 | # 14 | # import os 15 | # import sys 16 | # sys.path.insert(0, os.path.abspath('.')) 17 | 18 | 19 | # -- Project information ----------------------------------------------------- 20 | 21 | project = 'mmc-utils' 22 | copyright = '2024, Chris Ball' 23 | author = 'Chris Ball' 24 | 25 | 26 | # -- General configuration --------------------------------------------------- 27 | 28 | # Add any Sphinx extension module names here, as strings. They can be 29 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 30 | # ones. 31 | extensions = [ 32 | ] 33 | 34 | # Add any paths that contain templates here, relative to this directory. 35 | templates_path = ['_templates'] 36 | 37 | # List of patterns, relative to source directory, that match files and 38 | # directories to ignore when looking for source files. 39 | # This pattern also affects html_static_path and html_extra_path. 40 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 41 | 42 | # The master toctree document. 43 | master_doc = 'index' 44 | 45 | # -- Options for HTML output ------------------------------------------------- 46 | 47 | # The theme to use for HTML and HTML Help pages. See the documentation for 48 | # a list of builtin themes. 49 | # 50 | html_theme = 'alabaster' 51 | 52 | # Add any paths that contain custom static files (such as style sheets) here, 53 | # relative to this directory. They are copied after the builtin static files, 54 | # so a file named "default.css" will overwrite the builtin "default.css". 55 | html_static_path = ['_static'] 56 | -------------------------------------------------------------------------------- /mmc_cmds.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU General Public 4 | * License v2 as published by the Free Software Foundation. 5 | * 6 | * This program is distributed in the hope that it will be useful, 7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | * General Public License for more details. 10 | * 11 | * You should have received a copy of the GNU General Public 12 | * License along with this program; if not, write to the 13 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 14 | * Boston, MA 021110-1307, USA. 15 | * 16 | * Modified to add field firmware update support, 17 | * those modifications are Copyright (c) 2016 SanDisk Corp. 18 | */ 19 | 20 | /* mmc_cmds.c */ 21 | int do_read_extcsd(int nargs, char **argv); 22 | int do_write_extcsd(int nargs, char **argv); 23 | int do_writeprotect_boot_get(int nargs, char **argv); 24 | int do_writeprotect_boot_set(int nargs, char **argv); 25 | int do_writeprotect_user_get(int nargs, char **argv); 26 | int do_writeprotect_user_set(int nargs, char **argv); 27 | int do_disable_512B_emulation(int nargs, char **argv); 28 | int do_write_boot_en(int nargs, char **argv); 29 | int do_boot_bus_conditions_set(int nargs, char **argv); 30 | int do_write_bkops_en(int nargs, char **argv); 31 | int do_hwreset_en(int nargs, char **argv); 32 | int do_hwreset_dis(int nargs, char **argv); 33 | int do_sanitize(int nargs, char **argv); 34 | int do_status_get(int nargs, char **argv); 35 | int do_create_gp_partition(int nargs, char **argv); 36 | int do_enh_area_set(int nargs, char **argv); 37 | int do_write_reliability_set(int nargs, char **argv); 38 | int do_rpmb_write_key(int nargs, char **argv); 39 | int do_rpmb_read_counter(int nargs, char **argv); 40 | int do_rpmb_read_block(int nargs, char **argv); 41 | int do_rpmb_write_block(int nargs, char **argv); 42 | int do_cache_en(int nargs, char **argv); 43 | int do_cache_dis(int nargs, char **argv); 44 | int do_ffu(int nargs, char **argv); 45 | int do_opt_ffu1(int nargs, char **argv); 46 | int do_opt_ffu2(int nargs, char **argv); 47 | int do_opt_ffu3(int nargs, char **argv); 48 | int do_opt_ffu4(int nargs, char **argv); 49 | int do_read_scr(int argc, char **argv); 50 | int do_read_cid(int argc, char **argv); 51 | int do_read_csd(int argc, char **argv); 52 | int do_erase(int nargs, char **argv); 53 | int do_general_cmd_read(int nargs, char **argv); 54 | int do_softreset(int nargs, char **argv); 55 | int do_preidle(int nargs, char **argv); 56 | int do_alt_boot_op(int nargs, char **argv); 57 | -------------------------------------------------------------------------------- /3rdparty/hmac_sha/sha2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * FIPS 180-2 SHA-224/256/384/512 implementation 3 | * Last update: 02/02/2007 4 | * Issue date: 04/30/2005 5 | * 6 | * Since this code has been incorporated into a GPLv2 project, it is 7 | * distributed under GPLv2 inside mmc-utils. The original BSD license 8 | * that the code was released under is included below for clarity. 9 | * 10 | * Copyright (C) 2005, 2007 Olivier Gay 11 | * All rights reserved. 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions 15 | * are met: 16 | * 1. Redistributions of source code must retain the above copyright 17 | * notice, this list of conditions and the following disclaimer. 18 | * 2. Redistributions in binary form must reproduce the above copyright 19 | * notice, this list of conditions and the following disclaimer in the 20 | * documentation and/or other materials provided with the distribution. 21 | * 3. Neither the name of the project nor the names of its contributors 22 | * may be used to endorse or promote products derived from this software 23 | * without specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 29 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 | * SUCH DAMAGE. 36 | */ 37 | 38 | #ifndef SHA2_H 39 | #define SHA2_H 40 | 41 | #define SHA224_DIGEST_SIZE ( 224 / 8) 42 | #define SHA256_DIGEST_SIZE ( 256 / 8) 43 | #define SHA384_DIGEST_SIZE ( 384 / 8) 44 | #define SHA512_DIGEST_SIZE ( 512 / 8) 45 | 46 | #define SHA256_BLOCK_SIZE ( 512 / 8) 47 | #define SHA512_BLOCK_SIZE (1024 / 8) 48 | #define SHA384_BLOCK_SIZE SHA512_BLOCK_SIZE 49 | #define SHA224_BLOCK_SIZE SHA256_BLOCK_SIZE 50 | 51 | #ifndef SHA2_TYPES 52 | #define SHA2_TYPES 53 | typedef unsigned char uint8; 54 | typedef unsigned int uint32; 55 | typedef unsigned long long uint64; 56 | #endif 57 | 58 | #ifdef __cplusplus 59 | extern "C" { 60 | #endif 61 | 62 | typedef struct { 63 | unsigned int tot_len; 64 | unsigned int len; 65 | unsigned char block[2 * SHA256_BLOCK_SIZE]; 66 | uint32 h[8]; 67 | } sha256_ctx; 68 | 69 | typedef struct { 70 | unsigned int tot_len; 71 | unsigned int len; 72 | unsigned char block[2 * SHA512_BLOCK_SIZE]; 73 | uint64 h[8]; 74 | } sha512_ctx; 75 | 76 | typedef sha512_ctx sha384_ctx; 77 | typedef sha256_ctx sha224_ctx; 78 | 79 | void sha224_init(sha224_ctx *ctx); 80 | void sha224_update(sha224_ctx *ctx, const unsigned char *message, 81 | unsigned int len); 82 | void sha224_final(sha224_ctx *ctx, unsigned char *digest); 83 | void sha224(const unsigned char *message, unsigned int len, 84 | unsigned char *digest); 85 | 86 | void sha256_init(sha256_ctx * ctx); 87 | void sha256_update(sha256_ctx *ctx, const unsigned char *message, 88 | unsigned int len); 89 | void sha256_final(sha256_ctx *ctx, unsigned char *digest); 90 | void sha256(const unsigned char *message, unsigned int len, 91 | unsigned char *digest); 92 | 93 | void sha384_init(sha384_ctx *ctx); 94 | void sha384_update(sha384_ctx *ctx, const unsigned char *message, 95 | unsigned int len); 96 | void sha384_final(sha384_ctx *ctx, unsigned char *digest); 97 | void sha384(const unsigned char *message, unsigned int len, 98 | unsigned char *digest); 99 | 100 | void sha512_init(sha512_ctx *ctx); 101 | void sha512_update(sha512_ctx *ctx, const unsigned char *message, 102 | unsigned int len); 103 | void sha512_final(sha512_ctx *ctx, unsigned char *digest); 104 | void sha512(const unsigned char *message, unsigned int len, 105 | unsigned char *digest); 106 | 107 | #ifdef __cplusplus 108 | } 109 | #endif 110 | 111 | #endif /* !SHA2_H */ 112 | 113 | -------------------------------------------------------------------------------- /man/mmc.1: -------------------------------------------------------------------------------- 1 | .TH MMC 1 "2015-11-16" "0.1" "mmc-utils" 2 | .SH 3 | NAME 4 | mmc-utils \- Configure MMC storage devices from userspace. 5 | .SH 6 | SYNOPSIS 7 | mmc [ []] [--help] 8 | .PP 9 | mmc [] --help 10 | .SH 11 | DESCRIPTION 12 | mmc-utils is a tool for configuring MMC storage devices from userspace. 13 | .SH 14 | COMMANDS AND OPTIONS 15 | .TP 16 | .BR "help | \-\-help | -h | " "(no arguments)" 17 | Shows the abbreviated help menu in the terminal. 18 | .TP 19 | .BR "extcsd read " 20 | Print extcsd data from . 21 | .TP 22 | .BR "writeprotect get " 23 | Determine the eMMC writeprotect status of . 24 | .TP 25 | .BR "writeprotect set " 26 | Set the eMMC writeprotect status of . 27 | This sets the eMMC to be write-protected until next boot. 28 | .TP 29 | .BR "disable 512B emulation " 30 | Set the eMMC data sector size to 4KB by disabling emulation on 31 | . 32 | .TP 33 | .BR "gp create <-y|-n|-c> " 34 | create general purpose partition for the . 35 | Dry-run only unless -y or -c is passed. 36 | Use -c if more partitioning settings are still to come. 37 | To set enhanced attribute to general partition being created set to 1 else set it to 0. 38 | To set extended attribute to general partition set to 1,2 else set it to 0. 39 | NOTE! This is a one-time programmable (unreversible) change. 40 | .TP 41 | .BR "enh_area set <-y|-n|-c> " 42 | Enable the enhanced user area for the . 43 | Dry-run only unless -y or -c is passed. 44 | Use -c if more partitioning settings are still to come. 45 | NOTE! This is a one-time programmable (unreversible) change. 46 | .TP 47 | .BR "write_reliability set <-y|-n|-c> " 48 | Enable write reliability per partition for the . 49 | Dry-run only unless -y or -c is passed. 50 | Use -c if more partitioning settings are still to come. 51 | NOTE! This is a one-time programmable (unreversible) change. 52 | .TP 53 | .BR "status get " 54 | Print the response to STATUS_SEND (CMD13). 55 | .TP 56 | .BR "bootpart enable " 57 | Enable the boot partition for the . 58 | Disable the boot partition for the with set to 0. 59 | To receive acknowledgment of boot from the card set 60 | to 1, else set it to 0. 61 | .TP 62 | .BR "bootbus set " 63 | Set Boot Bus Conditions. 64 | must be "single_backward|single_hs|dual" 65 | must be "x1|retain" 66 | must be "x1|x4|x8" 67 | .TP 68 | .BR "bkops enable " 69 | Enable the eMMC BKOPS feature on . 70 | NOTE! This is a one-time programmable (unreversible) change. 71 | .TP 72 | .BR "hwreset enable " 73 | Permanently enable the eMMC H/W Reset feature on . 74 | NOTE! This is a one-time programmable (unreversible) change. 75 | .TP 76 | .BR "hwreset disable " 77 | Permanently disable the eMMC H/W Reset feature on . 78 | NOTE! This is a one-time programmable (unreversible) change. 79 | .TP 80 | .BR "sanitize " 81 | Send Sanitize command to the . 82 | This will delete the unmapped memory region of the device. 83 | .TP 84 | .BR "rpmb write-key " 85 | Program authentication key which is 32 bytes length and stored 86 | in the specified file. Also you can specify '-' instead of 87 | key file path to read the key from stdin. 88 | NOTE! This is a one-time programmable (unreversible) change. 89 | .TP 90 | .BR "rpmb read-counter " 91 | Counter value for the will be read to stdout. 92 | .TP 93 | .BR "rpmb read-block
[key file]" 94 | Blocks of 256 bytes will be read from to output 95 | file or stdout if '-' is specified. If key is specified - read 96 | data will be verified. Instead of regular path you can specify 97 | '-' to read key from stdin. 98 | .TP 99 | .BR "rpmb write-block
<256 byte data file> " 100 | Block of 256 bytes will be written from data file to 101 | . Also you can specify '-' instead of key 102 | file path or data file to read the data from stdin. 103 | .TP 104 | .BR "cache enable " 105 | Enable the eMMC cache feature on . 106 | NOTE! The cache is an optional feature on devices >= eMMC4.5. 107 | .TP 108 | .BR "cache disable " 109 | Disable the eMMC cache feature on . 110 | NOTE! The cache is an optional feature on devices >= eMMC4.5. 111 | .TP 112 | .BR " --help" 113 | Show detailed help for a command or subset of commands. 114 | 115 | .SH 116 | EXAMPLES 117 | .TP 118 | Program authentication key from stdin: 119 | echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH | mmc rpmb write-key /dev/mmcblk0rpmb - 120 | .TP 121 | Write a block of 256 bytes of data to an rpmb device: 122 | $ (awk 'BEGIN {while (c++<256) printf "a"}' | echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH) | mmc rpmb write-block /dev/mmcblk0rpmb 0x02 - - 123 | .TP 124 | Read a block of 256 bytes of data from an rpmb device to stdout: 125 | $ echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH | mmc rpmb read-block /dev/mmcblk0rpmb 0x02 2 /tmp/block - 126 | .TP 127 | Read 2 blocks of 256 bytes from rpmb device to /tmp/block without verification: 128 | $ mmc rpmb read-block /dev/mmcblk0rpmb 0x02 2 /tmp/block 129 | -------------------------------------------------------------------------------- /docs/HOWTO.rst: -------------------------------------------------------------------------------- 1 | .. SPDX-License-Identifier: GPL-2.0-only 2 | 3 | Running mmc-utils 4 | ----------------- 5 | **Name** 6 | mmc - a tool for configuring MMC storage devices 7 | **Synopsis** 8 | ``mmc [options] [mmc-block-device]...`` 9 | **Description** 10 | *mmc-utils* is a single-threaded tool that will perform a specified type of mmc action as specified by the user. 11 | The typical use of mmc-utils is to access the mmc device either for configuring or reading its configuration registers. 12 | **Options** 13 | ``help | --help | -h | (no arguments)`` 14 | Shows the abbreviated help menu in the terminal. 15 | 16 | **Commands** 17 | ``extcsd read `` 18 | Print extcsd data from . 19 | 20 | ``extcsd write `` 21 | Write at offset to 's extcsd. 22 | 23 | ``writeprotect boot get `` 24 | Print the boot partitions write protect status for . 25 | 26 | ``writeprotect boot set [-p] []`` 27 | Set the boot partition write protect status for . 28 | If is passed (0 or 1), only protect that particular eMMC boot partition, otherwise protect both. It will be write-protected until the next boot. 29 | -p Protect partition permanently instead. NOTE! -p is a one-time programmable (unreversible) change. 30 | 31 | ``writeprotect user get `` 32 | Print the user areas write protect configuration for . 33 | 34 | ``writeprotect user set `` 35 | Set user area write protection. 36 | 37 | ``csd read [-h] [-v] [-b bus_type] [-r register] `` 38 | Print CSD data from . The device path should specify the csd sysfs file directory. 39 | if [bus_type] is passed (mmc or sd) the [register] content must be passed as well, and no need for device path. 40 | it is useful for cases we are getting the register value without having the actual platform. 41 | 42 | ``cid read `` 43 | Print CID data from . The device path should specify the cid sysfs file directory. 44 | if [bus_type] is passed (mmc or sd) the [register] content must be passed as well, and no need for device path. 45 | it is useful for cases we are getting the register value without having the actual platform. 46 | 47 | ``scr read `` 48 | Print SCR data from . The device path should specify the scr sysfs file directory. 49 | if [bus_type] is passed (mmc or sd) the [register] content must be passed as well, and no need for device path. 50 | it is useful for cases we are getting the register value without having the actual platform. 51 | 52 | ``ffu [chunk-bytes]`` 53 | Default mode. Run Field Firmware Update with `` on ``. `[chunk-bytes]` is optional and defaults to its max - 512k. Should be in decimal bytes and sector aligned. 54 | 55 | ``opt_ffu1 [chunk-bytes]`` 56 | Optional FFU mode 1, it's the same as 'ffu', but uses CMD23+CMD25 for repeated downloads and remains in FFU mode until completion. 57 | 58 | ``opt_ffu2 [chunk-bytes]`` 59 | Optional FFU mode 2, uses CMD25+CMD12 Open-ended Multiple-block write to download and remains in FFU mode until completion. 60 | 61 | ``opt_ffu3 [chunk-bytes]`` 62 | Optional FFU mode 3, uses CMD24 Single-block write for downloading, exiting FFU mode after each block written. 63 | 64 | ``opt_ffu4 [chunk-bytes]`` 65 | Optional FFU mode 4, uses CMD24 Single-block write for repeated downloads, remaining in FFU mode until completion. 66 | 67 | 68 | ``erase `` 69 | Send Erase CMD38 with specific argument to the . NOTE!: This will delete all user data in the specified region of the device. must be one of: legacy, discard, secure-erase, secure-trim1, secure-trim2, or trim. 70 | 71 | ``gen_cmd read [arg]`` 72 | Send GEN_CMD (CMD56) to read vendor-specific format/meaning data from . NOTE!: [arg] is optional and defaults to 0x1. If [arg] is specified, then [arg] must be a 32-bit hexadecimal number, prefixed with 0x/0X. And bit0 in [arg] must be 1. 73 | 74 | ``lock [password] [new_password]`` 75 | Usage: mmc lock [password] [new_password]. can be up to 16 character plaintext or hex string starting with 0x. s=set password, c=clear password, l=lock, sl=set password and lock, u=unlock, e=force erase. 76 | 77 | ``softreset `` 78 | Issues a CMD0 softreset, e.g., for testing if hardware reset for UHS works. 79 | 80 | ``preidle `` 81 | Issues a CMD0 GO_PRE_IDLE. 82 | 83 | ``boot_operation `` 84 | Does the alternative boot operation and writes the specified starting blocks of boot data into the requested file. Note some limitations: The boot operation must be configured, e.g., for legacy speed. The MMC must currently be running at the bus mode that is configured for the boot operation (HS200 and HS400 not supported at all). Only up to 512K bytes of boot data will be transferred. The MMC will perform a soft reset, if your system cannot handle that do not use the boot operation from mmc-utils. 85 | 86 | 87 | 88 | ``mmc rpmb write-block
<256 byte data file> `` 89 | Writes a block of data to the RPMB partition. 90 | 91 | ``mmc rpmb read-counter `` 92 | Reads the write counter from the RPMB partition. 93 | 94 | ``mmc rpmb read-block
[key file]`` 95 | Reads blocks of data from the RPMB partition. 96 | -------------------------------------------------------------------------------- /3rdparty/hmac_sha/hmac_sha2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HMAC-SHA-224/256/384/512 implementation 3 | * Last update: 06/15/2005 4 | * Issue date: 06/15/2005 5 | * 6 | * Since this code has been incorporated into a GPLv2 project, it is 7 | * distributed under GPLv2 inside mmc-utils. The original BSD license 8 | * that the code was released under is included below for clarity. 9 | * 10 | * Copyright (C) 2005 Olivier Gay 11 | * All rights reserved. 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions 15 | * are met: 16 | * 1. Redistributions of source code must retain the above copyright 17 | * notice, this list of conditions and the following disclaimer. 18 | * 2. Redistributions in binary form must reproduce the above copyright 19 | * notice, this list of conditions and the following disclaimer in the 20 | * documentation and/or other materials provided with the distribution. 21 | * 3. Neither the name of the project nor the names of its contributors 22 | * may be used to endorse or promote products derived from this software 23 | * without specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 29 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 | * SUCH DAMAGE. 36 | */ 37 | 38 | #ifndef HMAC_SHA2_H 39 | #define HMAC_SHA2_H 40 | 41 | #include "sha2.h" 42 | 43 | #ifdef __cplusplus 44 | extern "C" { 45 | #endif 46 | 47 | typedef struct { 48 | sha224_ctx ctx_inside; 49 | sha224_ctx ctx_outside; 50 | 51 | /* for hmac_reinit */ 52 | sha224_ctx ctx_inside_reinit; 53 | sha224_ctx ctx_outside_reinit; 54 | 55 | unsigned char block_ipad[SHA224_BLOCK_SIZE]; 56 | unsigned char block_opad[SHA224_BLOCK_SIZE]; 57 | } hmac_sha224_ctx; 58 | 59 | typedef struct { 60 | sha256_ctx ctx_inside; 61 | sha256_ctx ctx_outside; 62 | 63 | /* for hmac_reinit */ 64 | sha256_ctx ctx_inside_reinit; 65 | sha256_ctx ctx_outside_reinit; 66 | 67 | unsigned char block_ipad[SHA256_BLOCK_SIZE]; 68 | unsigned char block_opad[SHA256_BLOCK_SIZE]; 69 | } hmac_sha256_ctx; 70 | 71 | typedef struct { 72 | sha384_ctx ctx_inside; 73 | sha384_ctx ctx_outside; 74 | 75 | /* for hmac_reinit */ 76 | sha384_ctx ctx_inside_reinit; 77 | sha384_ctx ctx_outside_reinit; 78 | 79 | unsigned char block_ipad[SHA384_BLOCK_SIZE]; 80 | unsigned char block_opad[SHA384_BLOCK_SIZE]; 81 | } hmac_sha384_ctx; 82 | 83 | typedef struct { 84 | sha512_ctx ctx_inside; 85 | sha512_ctx ctx_outside; 86 | 87 | /* for hmac_reinit */ 88 | sha512_ctx ctx_inside_reinit; 89 | sha512_ctx ctx_outside_reinit; 90 | 91 | unsigned char block_ipad[SHA512_BLOCK_SIZE]; 92 | unsigned char block_opad[SHA512_BLOCK_SIZE]; 93 | } hmac_sha512_ctx; 94 | 95 | void hmac_sha224_init(hmac_sha224_ctx *ctx, const unsigned char *key, 96 | unsigned int key_size); 97 | void hmac_sha224_reinit(hmac_sha224_ctx *ctx); 98 | void hmac_sha224_update(hmac_sha224_ctx *ctx, const unsigned char *message, 99 | unsigned int message_len); 100 | void hmac_sha224_final(hmac_sha224_ctx *ctx, unsigned char *mac, 101 | unsigned int mac_size); 102 | void hmac_sha224(const unsigned char *key, unsigned int key_size, 103 | const unsigned char *message, unsigned int message_len, 104 | unsigned char *mac, unsigned mac_size); 105 | 106 | void hmac_sha256_init(hmac_sha256_ctx *ctx, const unsigned char *key, 107 | unsigned int key_size); 108 | void hmac_sha256_reinit(hmac_sha256_ctx *ctx); 109 | void hmac_sha256_update(hmac_sha256_ctx *ctx, const unsigned char *message, 110 | unsigned int message_len); 111 | void hmac_sha256_final(hmac_sha256_ctx *ctx, unsigned char *mac, 112 | unsigned int mac_size); 113 | void hmac_sha256(const unsigned char *key, unsigned int key_size, 114 | const unsigned char *message, unsigned int message_len, 115 | unsigned char *mac, unsigned mac_size); 116 | 117 | void hmac_sha384_init(hmac_sha384_ctx *ctx, const unsigned char *key, 118 | unsigned int key_size); 119 | void hmac_sha384_reinit(hmac_sha384_ctx *ctx); 120 | void hmac_sha384_update(hmac_sha384_ctx *ctx, const unsigned char *message, 121 | unsigned int message_len); 122 | void hmac_sha384_final(hmac_sha384_ctx *ctx, unsigned char *mac, 123 | unsigned int mac_size); 124 | void hmac_sha384(const unsigned char *key, unsigned int key_size, 125 | const unsigned char *message, unsigned int message_len, 126 | unsigned char *mac, unsigned mac_size); 127 | 128 | void hmac_sha512_init(hmac_sha512_ctx *ctx, const unsigned char *key, 129 | unsigned int key_size); 130 | void hmac_sha512_reinit(hmac_sha512_ctx *ctx); 131 | void hmac_sha512_update(hmac_sha512_ctx *ctx, const unsigned char *message, 132 | unsigned int message_len); 133 | void hmac_sha512_final(hmac_sha512_ctx *ctx, unsigned char *mac, 134 | unsigned int mac_size); 135 | void hmac_sha512(const unsigned char *key, unsigned int key_size, 136 | const unsigned char *message, unsigned int message_len, 137 | unsigned char *mac, unsigned mac_size); 138 | 139 | #ifdef __cplusplus 140 | } 141 | #endif 142 | 143 | #endif /* !HMAC_SHA2_H */ 144 | 145 | -------------------------------------------------------------------------------- /mmc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU General Public 4 | * License v2 as published by the Free Software Foundation. 5 | * 6 | * This program is distributed in the hope that it will be useful, 7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | * General Public License for more details. 10 | * 11 | * You should have received a copy of the GNU General Public 12 | * License along with this program; if not, write to the 13 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 14 | * Boston, MA 021110-1307, USA. 15 | * 16 | * Modified to add field firmware update support, 17 | * those modifications are Copyright (c) 2016 SanDisk Corp. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | /* From kernel linux/mmc/mmc.h */ 24 | #define MMC_GO_IDLE_STATE 0 /* bc */ 25 | #define MMC_GO_IDLE_STATE_ARG 0x0 26 | #define MMC_GO_PRE_IDLE_STATE_ARG 0xF0F0F0F0 27 | #define MMC_BOOT_INITIATION_ARG 0xFFFFFFFA 28 | #define MMC_SWITCH 6 /* ac [31:0] See below R1b */ 29 | #define MMC_SEND_EXT_CSD 8 /* adtc R1 */ 30 | #define MMC_STOP_TRANSMISSION 12 /* ac R1b */ 31 | #define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ 32 | #define R1_SWITCH_ERROR (1 << 7) /* sx, c */ 33 | #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ 34 | #define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ 35 | #define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */ 36 | #define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ 37 | #define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */ 38 | #define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */ 39 | #define MMC_CLEAR_WRITE_PROT 29 /* ac [31:0] data addr R1b */ 40 | #define MMC_SEND_WRITE_PROT_TYPE 31 /* ac [31:0] data addr R1 */ 41 | #define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */ 42 | #define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */ 43 | #define MMC_ERASE 38 /* ac [31] Secure request 44 | [30:16] set to 0 45 | [15] Force Garbage Collect request 46 | [14:2] set to 0 47 | [1] Discard Enable 48 | [0] Identify Write Blocks for 49 | Erase (or TRIM Enable) R1b */ 50 | #define MMC_GEN_CMD 56 /* adtc [31:1] stuff bits. 51 | [0]: RD/WR1 R1 */ 52 | 53 | #define R1_OUT_OF_RANGE (1 << 31) /* er, c */ 54 | #define R1_ADDRESS_ERROR (1 << 30) /* erx, c */ 55 | #define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */ 56 | #define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */ 57 | #define R1_ERASE_PARAM (1 << 27) /* ex, c */ 58 | #define R1_WP_VIOLATION (1 << 26) /* erx, c */ 59 | #define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */ 60 | #define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */ 61 | #define R1_COM_CRC_ERROR (1 << 23) /* er, b */ 62 | #define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */ 63 | #define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */ 64 | #define R1_CC_ERROR (1 << 20) /* erx, c */ 65 | #define R1_ERROR (1 << 19) /* erx, c */ 66 | #define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */ 67 | #define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */ 68 | #define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */ 69 | #define R1_ERASE_RESET (1 << 13) /* sr, c */ 70 | #define R1_READY_FOR_DATA (1 << 8) /* sx, a */ 71 | #define R1_EXCEPTION_EVENT (1 << 6) /* sr, a */ 72 | #define R1_APP_CMD (1 << 5) /* sr, c */ 73 | 74 | /* 75 | * EXT_CSD fields 76 | */ 77 | #define EXT_CSD_S_CMD_SET 504 78 | #define EXT_CSD_HPI_FEATURE 503 79 | #define EXT_CSD_BKOPS_SUPPORT 502 /* RO */ 80 | #define EXT_CSD_SUPPORTED_MODES 493 /* RO */ 81 | #define EXT_CSD_FFU_FEATURES 492 /* RO */ 82 | #define EXT_CSD_FFU_ARG_3 490 /* RO */ 83 | #define EXT_CSD_FFU_ARG_2 489 /* RO */ 84 | #define EXT_CSD_FFU_ARG_1 488 /* RO */ 85 | #define EXT_CSD_FFU_ARG_0 487 /* RO */ 86 | #define EXT_CSD_CMDQ_DEPTH 307 /* RO */ 87 | #define EXT_CSD_CMDQ_SUPPORT 308 /* RO */ 88 | #define EXT_CSD_NUM_OF_FW_SEC_PROG_3 305 /* RO */ 89 | #define EXT_CSD_NUM_OF_FW_SEC_PROG_2 304 /* RO */ 90 | #define EXT_CSD_NUM_OF_FW_SEC_PROG_1 303 /* RO */ 91 | #define EXT_CSD_NUM_OF_FW_SEC_PROG_0 302 /* RO */ 92 | #define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B 269 /* RO */ 93 | #define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A 268 /* RO */ 94 | #define EXT_CSD_PRE_EOL_INFO 267 /* RO */ 95 | #define EXT_CSD_FIRMWARE_VERSION 254 /* RO */ 96 | #define EXT_CSD_CACHE_SIZE_3 252 97 | #define EXT_CSD_CACHE_SIZE_2 251 98 | #define EXT_CSD_CACHE_SIZE_1 250 99 | #define EXT_CSD_CACHE_SIZE_0 249 100 | #define EXT_CSD_SEC_FEATURE_SUPPORT 231 101 | #define EXT_CSD_BOOT_INFO 228 /* R/W */ 102 | #define EXT_CSD_BOOT_MULT 226 /* RO */ 103 | #define EXT_CSD_HC_ERASE_GRP_SIZE 224 104 | #define EXT_CSD_HC_WP_GRP_SIZE 221 105 | #define EXT_CSD_SEC_COUNT_3 215 106 | #define EXT_CSD_SEC_COUNT_2 214 107 | #define EXT_CSD_SEC_COUNT_1 213 108 | #define EXT_CSD_SEC_COUNT_0 212 109 | #define EXT_CSD_PART_SWITCH_TIME 199 110 | #define EXT_CSD_REV 192 111 | #define EXT_CSD_BOOT_CFG 179 112 | #define EXT_CSD_PART_CONFIG 179 113 | #define EXT_CSD_BOOT_BUS_CONDITIONS 177 114 | #define EXT_CSD_ERASE_GROUP_DEF 175 115 | #define EXT_CSD_BOOT_WP_STATUS 174 116 | #define EXT_CSD_BOOT_WP 173 117 | #define EXT_CSD_USER_WP 171 118 | #define EXT_CSD_FW_CONFIG 169 /* R/W */ 119 | #define EXT_CSD_WR_REL_SET 167 120 | #define EXT_CSD_WR_REL_PARAM 166 121 | #define EXT_CSD_SANITIZE_START 165 122 | #define EXT_CSD_BKOPS_EN 163 /* R/W */ 123 | #define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ 124 | #define EXT_CSD_PARTITIONING_SUPPORT 160 /* RO */ 125 | #define EXT_CSD_MAX_ENH_SIZE_MULT_2 159 126 | #define EXT_CSD_MAX_ENH_SIZE_MULT_1 158 127 | #define EXT_CSD_MAX_ENH_SIZE_MULT_0 157 128 | #define EXT_CSD_PARTITIONS_ATTRIBUTE 156 /* R/W */ 129 | #define EXT_CSD_PARTITION_SETTING_COMPLETED 155 /* R/W */ 130 | #define EXT_CSD_GP_SIZE_MULT_4_2 154 131 | #define EXT_CSD_GP_SIZE_MULT_4_1 153 132 | #define EXT_CSD_GP_SIZE_MULT_4_0 152 133 | #define EXT_CSD_GP_SIZE_MULT_3_2 151 134 | #define EXT_CSD_GP_SIZE_MULT_3_1 150 135 | #define EXT_CSD_GP_SIZE_MULT_3_0 149 136 | #define EXT_CSD_GP_SIZE_MULT_2_2 148 137 | #define EXT_CSD_GP_SIZE_MULT_2_1 147 138 | #define EXT_CSD_GP_SIZE_MULT_2_0 146 139 | #define EXT_CSD_GP_SIZE_MULT_1_2 145 140 | #define EXT_CSD_GP_SIZE_MULT_1_1 144 141 | #define EXT_CSD_GP_SIZE_MULT_1_0 143 142 | #define EXT_CSD_ENH_SIZE_MULT_2 142 143 | #define EXT_CSD_ENH_SIZE_MULT_1 141 144 | #define EXT_CSD_ENH_SIZE_MULT_0 140 145 | #define EXT_CSD_ENH_START_ADDR_3 139 146 | #define EXT_CSD_ENH_START_ADDR_2 138 147 | #define EXT_CSD_ENH_START_ADDR_1 137 148 | #define EXT_CSD_ENH_START_ADDR_0 136 149 | #define EXT_CSD_NATIVE_SECTOR_SIZE 63 /* R */ 150 | #define EXT_CSD_USE_NATIVE_SECTOR 62 /* R/W */ 151 | #define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */ 152 | #define EXT_CSD_EXT_PARTITIONS_ATTRIBUTE_1 53 153 | #define EXT_CSD_EXT_PARTITIONS_ATTRIBUTE_0 52 154 | #define EXT_CSD_CACHE_CTRL 33 155 | #define EXT_CSD_MODE_CONFIG 30 156 | #define EXT_CSD_MODE_OPERATION_CODES 29 /* W */ 157 | #define EXT_CSD_FFU_STATUS 26 /* R */ 158 | #define EXT_CSD_SECURE_REMOVAL_TYPE 16 /* R/W */ 159 | #define EXT_CSD_CMDQ_MODE_EN 15 /* R/W */ 160 | 161 | /* 162 | * WR_REL_PARAM field definitions 163 | */ 164 | #define HS_CTRL_REL (1<<0) 165 | #define EN_REL_WR (1<<2) 166 | 167 | /* 168 | * BKOPS_EN field definitions 169 | */ 170 | #define BKOPS_MAN_ENABLE (1<<0) 171 | #define BKOPS_AUTO_ENABLE (1<<1) 172 | 173 | /* 174 | * EXT_CSD field definitions 175 | */ 176 | #define EXT_CSD_CONFIG_SECRM_TYPE (0x30) 177 | #define EXT_CSD_SUPPORTED_SECRM_TYPE (0x0f) 178 | #define EXT_CSD_FFU_INSTALL (0x01) 179 | #define EXT_CSD_FFU_MODE (0x01) 180 | #define EXT_CSD_NORMAL_MODE (0x00) 181 | #define EXT_CSD_FFU (1<<0) 182 | #define EXT_CSD_UPDATE_DISABLE (1<<0) 183 | #define EXT_CSD_HPI_SUPP (1<<0) 184 | #define EXT_CSD_HPI_IMPL (1<<1) 185 | #define EXT_CSD_CMD_SET_NORMAL (1<<0) 186 | /* NOTE: The eMMC spec calls the partitions "Area 1" and "Area 2", but Linux 187 | * calls them mmcblk0boot0 and mmcblk0boot1. To avoid confustion between the two 188 | * numbering schemes, this tool uses 0 and 1 throughout. */ 189 | #define EXT_CSD_BOOT_WP_S_AREA_1_PERM (0x08) 190 | #define EXT_CSD_BOOT_WP_S_AREA_1_PWR (0x04) 191 | #define EXT_CSD_BOOT_WP_S_AREA_0_PERM (0x02) 192 | #define EXT_CSD_BOOT_WP_S_AREA_0_PWR (0x01) 193 | #define EXT_CSD_BOOT_WP_B_SEC_WP_SEL (0x80) 194 | #define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40) 195 | #define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10) 196 | #define EXT_CSD_BOOT_WP_B_PERM_WP_SEC_SEL (0x08) 197 | #define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04) 198 | #define EXT_CSD_BOOT_WP_B_PWR_WP_SEC_SEL (0x02) 199 | #define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01) 200 | #define EXT_CSD_BOOT_INFO_HS_MODE (1<<2) 201 | #define EXT_CSD_BOOT_INFO_DDR_DDR (1<<1) 202 | #define EXT_CSD_BOOT_INFO_ALT (1<<0) 203 | #define EXT_CSD_BOOT_CFG_ACK (1<<6) 204 | #define EXT_CSD_BOOT_CFG_EN (0x38) 205 | #define EXT_CSD_BOOT_CFG_ACC (0x07) 206 | #define EXT_CSD_RST_N_EN_MASK (0x03) 207 | #define EXT_CSD_HW_RESET_EN (0x01) 208 | #define EXT_CSD_HW_RESET_DIS (0x02) 209 | #define EXT_CSD_PART_CONFIG_ACC_MASK (0x7) 210 | #define EXT_CSD_PART_CONFIG_ACC_NONE (0x0) 211 | #define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1) 212 | #define EXT_CSD_PART_CONFIG_ACC_BOOT1 (0x2) 213 | #define EXT_CSD_PART_CONFIG_ACC_USER_AREA (0x7) 214 | #define EXT_CSD_PART_CONFIG_ACC_ACK (0x40) 215 | #define EXT_CSD_PARTITIONING_EN (1<<0) 216 | #define EXT_CSD_ENH_ATTRIBUTE_EN (1<<1) 217 | #define EXT_CSD_ENH_4 (1<<4) 218 | #define EXT_CSD_ENH_3 (1<<3) 219 | #define EXT_CSD_ENH_2 (1<<2) 220 | #define EXT_CSD_ENH_1 (1<<1) 221 | #define EXT_CSD_ENH_USR (1<<0) 222 | #define EXT_CSD_REV_V5_1 8 223 | #define EXT_CSD_REV_V5_0 7 224 | #define EXT_CSD_REV_V4_5 6 225 | #define EXT_CSD_REV_V4_4_1 5 226 | #define EXT_CSD_REV_V4_3 3 227 | #define EXT_CSD_REV_V4_2 2 228 | #define EXT_CSD_REV_V4_1 1 229 | #define EXT_CSD_REV_V4_0 0 230 | #define EXT_CSD_SEC_GB_CL_EN (1<<4) 231 | #define EXT_CSD_SEC_ER_EN (1<<0) 232 | 233 | 234 | /* From kernel linux/mmc/core.h */ 235 | #define MMC_RSP_NONE 0 /* no response */ 236 | #define MMC_RSP_PRESENT (1 << 0) 237 | #define MMC_RSP_136 (1 << 1) /* 136 bit response */ 238 | #define MMC_RSP_CRC (1 << 2) /* expect valid crc */ 239 | #define MMC_RSP_BUSY (1 << 3) /* card may send busy */ 240 | #define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */ 241 | 242 | #define MMC_CMD_AC (0 << 5) 243 | #define MMC_CMD_ADTC (1 << 5) 244 | #define MMC_CMD_BC (2 << 5) 245 | 246 | #define MMC_RSP_SPI_S1 (1 << 7) /* one status byte */ 247 | #define MMC_RSP_SPI_BUSY (1 << 10) /* card may send busy */ 248 | 249 | #define MMC_RSP_SPI_R1 (MMC_RSP_SPI_S1) 250 | #define MMC_RSP_SPI_R1B (MMC_RSP_SPI_S1|MMC_RSP_SPI_BUSY) 251 | 252 | #define MMC_RSP_R1 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) 253 | #define MMC_RSP_R1B (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY) 254 | -------------------------------------------------------------------------------- /mmc.1: -------------------------------------------------------------------------------- 1 | .TH mmc\-utils 1 "April 2024" "User Manual" 2 | .SH NAME 3 | mmc \- a tool for configuring MMC storage devices 4 | .SH SYNOPSIS 5 | .B mmc 6 | [\fIoptions\fR] [\ mmc\-block\-device\fR]... 7 | .SH DESCRIPTION 8 | .B mmc-utils 9 | is a single-threaded tool that will perform a specified type of mmc action as specified by the user. 10 | .br 11 | The typical use of mmc-utils is to access the mmc device either for configuring or reading its configuration registers. 12 | .SH OPTIONS 13 | .TP 14 | .BI extcsd " " read " " \fIdevice\fR 15 | Read and prints the extended csd register 16 | .TP 17 | .BI extcsd " " write " " \fIoffset\fR " " \fIvalue\fR " " \fIdevice\fR 18 | Write \fIvalue\fR at \fIoffset\fR to the device's extcsd 19 | .TP 20 | .BI writeprotect " " boot " " get " " \fIdevice\fR 21 | Print the boot partitions write protect status 22 | .TP 23 | .BI writeprotect " " boot " " set " " \fIdevice\fR " " [\fInumber\fR] 24 | Set the boot partition write protect status for the device. 25 | .br 26 | If \fInumber\fR is passed (0 or 1), only protect that specified eMMC boot partition, otherwise protect both. 27 | .br 28 | It will be write-protected until the next boot. 29 | .TP 30 | .BI writeprotect " " user " " get " " \fIdevice\fR 31 | Print the user areas write protect configuration for . 32 | .TP 33 | .BI writeprotect " " user " " set " " \fItype\fR " " \fIstart\-block\fR " " \fIblocks\fR " " \fIdevice\fR 34 | Set the write protect configuration for the specified region of the user area for the device. 35 | .br 36 | \fIstart\-block\fR specifies the first block of the protected area. 37 | .br 38 | \fIblocks\fR specifies the size of the protected area in blocks. 39 | .br 40 | NOTE! The area must start and end on Write Protect Group boundaries, Use the "writeprotect user get" command to get the Write Protect Group size. 41 | \fItype\fR is one of the following: 42 | .RS 43 | .RS 44 | .TP 45 | .B none 46 | Clear temporary write protection. 47 | .TP 48 | .B temp 49 | Set temporary write protection. 50 | .TP 51 | .B pwron 52 | Set write protection until the next power on. 53 | .RE 54 | .RE 55 | .TP 56 | .BI writeprotect " " user " " get " " \fIdevice\fR 57 | Print the user area's write protect configuration for the device. 58 | .TP 59 | .BI disable " " 512B " " emulation " " \fIdevice\fR 60 | Set the eMMC data sector size to 4KB by disabling emulation on the device. 61 | .TP 62 | .BI gp " " create " " \fIdry\-run\fR " " \fIlength\-KiB\fR " " \fIpartition\fR " " \fIenh\-attr\fR " " \fIext\-attr\fR " " \fIdevice\fR 63 | Create general purpose partition for the device. 64 | .br 65 | NOTE! This is a one-time programmable (irreversible) change. 66 | .br 67 | To set enhanced attribute to general partition being created set \fIenh\-attr\fR to 1 else set it to 0. 68 | .br 69 | To set extended attribute to general partition set \fIenh\-attr\fR to 1,2 else set it to 0. 70 | .br 71 | \fIdry\-run\fR is one of the following: 72 | .RS 73 | .RS 74 | .TP 75 | .B \-y 76 | PARTITION_SETTING_COMPLETED in the extcsd will get set and the partitioning operation will take effect and be finalized. 77 | .TP 78 | .B \-c 79 | more partitioning settings are still to come - partitioning operation will not take effect. 80 | .TP 81 | .B otherwise 82 | These changes will not take effect neither now nor after a power cycle. 83 | .RE 84 | .RE 85 | .TP 86 | .BI enh_area " " set " " \fIdry\-run\fR " " \fIstart\-KiB\fR " " \fIlength\-KiB\fR " " \fIdevice\fR 87 | Enable the enhanced user area for the device. 88 | .br 89 | NOTE! This is a one-time programmable (irreversible) change. 90 | \fIdry\-run\fR is as above. 91 | .TP 92 | .BI write_reliability " " set " " " \fIdry\-run\fR " " \fIpartition\fR " " \fIdevice\fR 93 | Enable write reliability per partition for the device. 94 | .br 95 | NOTE! This is a one-time programmable (irreversible) change. 96 | \fIdry\-run\fR is as above. 97 | .TP 98 | .BI status " " get " " \fIdevice\fR 99 | Print the response to STATUS_SEND (CMD13). 100 | .TP 101 | .BI bootpart " " enable " " \fIboot\-partition\fR " " \fIsend\-ackn\fR " " \fIdevice\fR 102 | Enable the boot partition for the device. 103 | Disable the boot partition for the device if is \fIboot\-partition\fR set to 0. 104 | .br 105 | To receive acknowledgment of boot from the card set \fIsend\-ackn\fR to 1, else set it to 0. 106 | .TP 107 | .BI bootbus " " set " " \fIboot\-mode\fR " " \fIreset\-boot\-bus\-conditions\fR " " \fIboot\-bus\-width\fR " " \fIdevice\fR 108 | Set Boot Bus Conditions. 109 | .br 110 | \fIboot\-mode\fR is one of the following: single_backward, single_hs, or dual. 111 | .br 112 | \fIreset\-boot\-bus\-conditions\fR is one of the following: x1 or retain. 113 | .br 114 | \fIboot\-bus\-width\fR is one of the following: x1, x4, or x8. 115 | .TP 116 | .BI bkops_en " " \fImode\fR " " \fIdevice\fR 117 | Enable the eMMC BKOPS feature on the device. 118 | The auto (AUTO_EN) setting is only supported on eMMC 5.0 or newer. 119 | .br 120 | NOTE! Setting manual (MANUAL_EN) is one-time programmable (irreversible) change. 121 | .br 122 | \fImode\fR is one of the following: 123 | .RS 124 | .RS 125 | .TP 126 | .B auto 127 | Auto bkops is set 128 | .TP 129 | .B manual 130 | Manual bkops is set 131 | .RE 132 | .RE 133 | .TP 134 | .BI hwreset " " enable " " \fIdevice\fR 135 | Permanently enable the eMMC H/W Reset feature on the device. 136 | .br 137 | NOTE! This is a one-time programmable (irreversible) change. 138 | .TP 139 | .BI hwreset " " disable " " \fIdevice\fR 140 | Permanently disable the eMMC H/W Reset feature on the device. 141 | .br 142 | NOTE! This is a one-time programmable (irreversible) change. 143 | .TP 144 | .BI sanitize " " \fIdevice\fR " " \fI[timeout_ms]\fR 145 | Send Sanitize command to the device. 146 | This will delete the unmapped memory region of the device. 147 | .TP 148 | .BI rpmb " " write\-key " " \fIrpmb\-device\fR " " \fIkey\-file\fR 149 | Program authentication key which is 32 bytes length and stored in the specified file. 150 | .br 151 | Also you can specify '-' instead of key file path to read the key from stdin. 152 | .br 153 | NOTE! This is a one-time programmable (irreversible) change. 154 | .TP 155 | .BI rpmb " " read\-counter " " \fIrpmb\-device\fR 156 | Counter value for the \fIrpmb\-device\fR will be read to stdout. 157 | .TP 158 | .BI rpmb " " read\-block " " \fIrpmb\-device\fR " " \fIaddress\fR " " \fIblocks-\count\fR " " \fIoutput-\file\fR " " [\fIkey\-file\fR] 159 | Blocks of 256 bytes will be read from \fIrpmb\-device\fR to output 160 | file or stdout if '-' is specified. If key is specified - read 161 | data will be verified. 162 | .TP 163 | .BI rpmb " " write\-block " " \fIrpmb\-device\fR " " \fIaddress\fR " " \fI256\-byte\-data\-file\fR " " \fIkey\-file\fR 164 | Block of 256 bytes will be written from data file to 165 | \fIrpmb\-device\fR. 166 | .br 167 | Also you can specify '-' instead of key file path or data file to read the data from stdin. 168 | .TP 169 | .BI cache " " enable " " \fIdevice\fR 170 | Enable the eMMC cache feature on the device. 171 | .br 172 | NOTE! The cache is an optional feature on devices >= eMMC4.5. 173 | .TP 174 | .BI cache " " disable " " \fIdevice\fR 175 | Disable the eMMC cache feature on the device. 176 | .br 177 | NOTE! The cache is an optional feature on devices >= eMMC4.5. 178 | .TP 179 | .BI csd " " read " " \fR[-h] \fR[-v] " " \fR[-b " " \fIbus_type\fR] " " \fR[-r " " \fIregister\fR] " " \fI\fR 180 | Print CSD data from \fIdevice\-path\fR. 181 | The device path should specify the csd sysfs file directory. 182 | .br 183 | If \fIbus_type\fR is passed (mmc or sd), the \fIregister\fR content must be passed as well, and no need for device path. 184 | .br 185 | It is useful for cases where we are getting the register value without having the actual platform. 186 | .TP 187 | .BI cid " " read " " \fR[-h] \fR[-v] " " \fR[-b " " \fIbus_type\fR] " " \fR[-r " " \fIregister\fR] " " \fI\fR 188 | Print CID data from \fIdevice\-path\fR. 189 | The device path should specify the cid sysfs file directory. 190 | .br 191 | If \fIbus_type\fR is passed (mmc or sd), the \fIregister\fR content must be passed as well, and no need for device path. 192 | .br 193 | It is useful for cases where we are getting the register value without having the actual platform. 194 | .TP 195 | .BI scr " " read " " \fR[-h] \fR[-v] " " \fR[-b " " \fIbus_type\fR] " " \fR[-r " " \fIregister\fR] " " \fI\fR 196 | Print SCR data from \fIdevice\-path\fR. 197 | The device path should specify the scr sysfs file directory. 198 | .br 199 | If \fIbus_type\fR is passed (mmc or sd), the \fIregister\fR content must be passed as well, and no need for device path. 200 | .br 201 | It is useful for cases where we are getting the register value without having the actual platform. 202 | .TP 203 | .BI ffu " " \fIimage\-file\-name\fR " " \fIdevice\fR " " [\fIchunk\-bytes\fR] 204 | Run Field Firmware Update with \fIimage\-file\-name\fR on the device. 205 | .br 206 | [\fIchunk\-bytes\fR] is optional and defaults to its max - 512k. should be in decimal bytes and sector aligned. 207 | .br 208 | if [\fIchunk\-bytes\fR] is omitted, mmc-utils will try to run ffu using the largest possible chunks: max(image-file, 512k). 209 | .TP 210 | .BI opt_ffu1 " \fIimage\-file\-name\fR " " \fIdevice\fR " " [\fIchunk\-bytes\fR] 211 | Optional FFU mode 1, it's the same as 'ffu', but uses CMD23+CMD25 for repeated downloads and remains in FFU mode until completion. 212 | .TP 213 | .BI opt_ffu2 " \fIimage\-file\-name\fR " " \fIdevice\fR " " [\fIchunk\-bytes\fR] 214 | Optional FFU mode 2, uses CMD25+CMD12 Open-ended Multiple-block write to download and remains in FFU mode until completion. 215 | .TP 216 | .BI opt_ffu3 " \fIimage\-file\-name\fR " " \fIdevice\fR " " [\fIchunk\-bytes\fR] 217 | Optional FFU mode 3, uses CMD24 Single-block write for downloading, exiting FFU mode after each block is written. 218 | .TP 219 | .BI opt_ffu4 " \fIimage\-file\-name\fR " " \fIdevice\fR " " [\fIchunk\-bytes\fR] 220 | Optional FFU mode 4, uses CMD24 Single-block write for repeated downloads, remaining in FFU mode until completion. 221 | .TP 222 | .BI erase " " \fItype\fR " " \fIstart-address\fR " " \fIend\-address\fR " " \fIdevice\fR 223 | Send Erase CMD38 with specific argument to the device. 224 | .br 225 | NOTE!: This will delete all user data in the specified region of the device. 226 | .br 227 | \fItype\fR is one of the following: legacy, discard, secure-erase, secure-trim1, secure-trim2, or trim. 228 | .TP 229 | .BI gen_cmd " " read " \fidevice\fR [\fIarg\fR] 230 | Send GEN_CMD (CMD56) to read vendor-specific format/meaning data from the device. 231 | .br 232 | NOTE!: [\fIarg\fR] is optional and defaults to 0x1. If [\fIarg\fR] is specified, then [\fIarg\fR] 233 | must be a 32-bit hexadecimal number, prefixed with 0x/0X. And bit0 in [\fIarg\fR] must be 1. 234 | Normally this command is aimed to extract a device-health info from the device. 235 | .TP 236 | .BI softreset " " \fIdevice\fR 237 | Issues a CMD0 softreset, e.g. for testing if hardware reset for UHS works 238 | .TP 239 | .BI boot_operation " " \fIboot\-data\-file\fR " " \fIdevice\fR 240 | Does the alternative boot operation and writes the specified starting blocks of boot data into the requested file. 241 | Note some limitations: 242 | .RS 243 | .RS 244 | .TP 245 | .B 1) 246 | The boot operation must be configured first, e.g. via bootbus and/or bootpart commands 247 | .TP 248 | .B 2) 249 | The MMC must currently be running at the bus mode that is configured for the boot operation (HS200 and HS400 not supported at all). 250 | .TP 251 | .B 3) 252 | Only up to 512K bytes of boot data will be transferred. 253 | .TP 254 | .B 4) 255 | The MMC will perform a soft reset, if your system cannot handle that do not use the boot operation from mmc-utils. 256 | .RE 257 | .RE 258 | .TP 259 | .BI \-\-help " " | " " help " " | " " \-h 260 | Show the help 261 | .TP 262 | .BI \fIcmd\fR " " \-\-help 263 | Show detailed help for that specific \fIcmd\fR or subset of commands. 264 | .SH "RPMB COMMANDS" 265 | The RPMB partition on the eMMC devices is a special area used for storing cryptographically safe information signed by a 266 | special secret key. 267 | .br 268 | To write and read records from this special area, authentication is needed. 269 | .br 270 | The RPMB area is *only* and *exclusively* accessed using ioctl()s from user-space. 271 | .br 272 | RPMB commands are send using the mmc multi-ioctl, thus ensures that the atomic nature of the rpmb access operation. 273 | .br 274 | The rpmb device given as a parameter to the rpmb commands is not a block device but a char device. 275 | .br 276 | This was done to help the mmc driver to account for some of the rpmb peculiarities. 277 | .SH "EXAMPLES" 278 | .RE 279 | .P 280 | .B RPMB examples 281 | .RS 282 | Program rpmb key using the stdin option: 283 | .RS 284 | .P 285 | $ echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH | mmc rpmb write-key /dev/mmcblk0rpmb - 286 | .RE 287 | .P 288 | Read 2 blocks starting address 2 and output the received content to stdout. Verify the received frames using the key (not mandatory): 289 | .RS 290 | .P 291 | $ echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH | mmc rpmb read-block /dev/mmcblk0rpmb 0x02 2 - 292 | .RE 293 | .P 294 | Read 2 blocks without verification starting address 2 and output the received content to /tmp/block: 295 | .RS 296 | .P 297 | $mmc rpmb read-block /dev/mmcblk0rpmb 0x02 2 /tmp/block 298 | .RE 299 | .P 300 | Write a string of 'a's to address 2. both the input and key uses stdin interface: 301 | .RS 302 | .P 303 | $ (awk 'BEGIN {while (c++<256) printf "a"}' | echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH) | mmc rpmb write-block /dev/mmcblk0rpmb 0x02 - - 304 | .RE 305 | .P 306 | .RE 307 | .P 308 | .B Field Firmware Update (ffu) examples 309 | .RS 310 | Do ffu using max-possible chunk size: If the fluf size < 512k, it will be flushed in a single write sequence. 311 | .RS 312 | .P 313 | $ mmc ffu IO4e0aC2056001801M1100042AE1.fluf /dev/mmcblk0 314 | .RE 315 | .P 316 | Same as above, this time use a 4k chunks: 317 | .RS 318 | .P 319 | $ mmc ffu IO4e0aC2056001801M1100042AE1.fluf /dev/mmcblk0 4096 320 | .RE 321 | .P 322 | .RE 323 | .SH AUTHORS 324 | .B mmc-utils 325 | was written by Chris Ball and . 326 | .br 327 | It is currently maintained by Ulf Hansson . 328 | .SH "REPORTING BUGS" 329 | Report bugs to the \fBmmc\fR mailing list . 330 | .SH "SEE ALSO" 331 | For further documentation see \fBREADME\fR. 332 | .br 333 | A short intro - https://docs.kernel.org/driver-api/mmc/mmc-tools.html 334 | .br 335 | official git tree - https://git.kernel.org/pub/scm/utils/mmc/mmc-utils.git 336 | -------------------------------------------------------------------------------- /3rdparty/hmac_sha/hmac_sha2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * HMAC-SHA-224/256/384/512 implementation 3 | * Last update: 06/15/2005 4 | * Issue date: 06/15/2005 5 | * 6 | * Since this code has been incorporated into a GPLv2 project, it is 7 | * distributed under GPLv2 inside mmc-utils. The original BSD license 8 | * that the code was released under is included below for clarity. 9 | * 10 | * Copyright (C) 2005 Olivier Gay 11 | * All rights reserved. 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions 15 | * are met: 16 | * 1. Redistributions of source code must retain the above copyright 17 | * notice, this list of conditions and the following disclaimer. 18 | * 2. Redistributions in binary form must reproduce the above copyright 19 | * notice, this list of conditions and the following disclaimer in the 20 | * documentation and/or other materials provided with the distribution. 21 | * 3. Neither the name of the project nor the names of its contributors 22 | * may be used to endorse or promote products derived from this software 23 | * without specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 29 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 | * SUCH DAMAGE. 36 | */ 37 | 38 | #include 39 | 40 | #include "hmac_sha2.h" 41 | 42 | /* HMAC-SHA-224 functions */ 43 | 44 | void hmac_sha224_init(hmac_sha224_ctx *ctx, const unsigned char *key, 45 | unsigned int key_size) 46 | { 47 | unsigned int fill; 48 | unsigned int num; 49 | 50 | const unsigned char *key_used; 51 | unsigned char key_temp[SHA224_DIGEST_SIZE]; 52 | int i; 53 | 54 | if (key_size == SHA224_BLOCK_SIZE) { 55 | key_used = key; 56 | num = SHA224_BLOCK_SIZE; 57 | } else { 58 | if (key_size > SHA224_BLOCK_SIZE){ 59 | num = SHA224_DIGEST_SIZE; 60 | sha224(key, key_size, key_temp); 61 | key_used = key_temp; 62 | } else { /* key_size > SHA224_BLOCK_SIZE */ 63 | key_used = key; 64 | num = key_size; 65 | } 66 | fill = SHA224_BLOCK_SIZE - num; 67 | 68 | memset(ctx->block_ipad + num, 0x36, fill); 69 | memset(ctx->block_opad + num, 0x5c, fill); 70 | } 71 | 72 | for (i = 0; i < (int) num; i++) { 73 | ctx->block_ipad[i] = key_used[i] ^ 0x36; 74 | ctx->block_opad[i] = key_used[i] ^ 0x5c; 75 | } 76 | 77 | sha224_init(&ctx->ctx_inside); 78 | sha224_update(&ctx->ctx_inside, ctx->block_ipad, SHA224_BLOCK_SIZE); 79 | 80 | sha224_init(&ctx->ctx_outside); 81 | sha224_update(&ctx->ctx_outside, ctx->block_opad, 82 | SHA224_BLOCK_SIZE); 83 | 84 | /* for hmac_reinit */ 85 | memcpy(&ctx->ctx_inside_reinit, &ctx->ctx_inside, 86 | sizeof(sha224_ctx)); 87 | memcpy(&ctx->ctx_outside_reinit, &ctx->ctx_outside, 88 | sizeof(sha224_ctx)); 89 | } 90 | 91 | void hmac_sha224_reinit(hmac_sha224_ctx *ctx) 92 | { 93 | memcpy(&ctx->ctx_inside, &ctx->ctx_inside_reinit, 94 | sizeof(sha224_ctx)); 95 | memcpy(&ctx->ctx_outside, &ctx->ctx_outside_reinit, 96 | sizeof(sha224_ctx)); 97 | } 98 | 99 | void hmac_sha224_update(hmac_sha224_ctx *ctx, const unsigned char *message, 100 | unsigned int message_len) 101 | { 102 | sha224_update(&ctx->ctx_inside, message, message_len); 103 | } 104 | 105 | void hmac_sha224_final(hmac_sha224_ctx *ctx, unsigned char *mac, 106 | unsigned int mac_size) 107 | { 108 | unsigned char digest_inside[SHA224_DIGEST_SIZE]; 109 | unsigned char mac_temp[SHA224_DIGEST_SIZE]; 110 | 111 | sha224_final(&ctx->ctx_inside, digest_inside); 112 | sha224_update(&ctx->ctx_outside, digest_inside, SHA224_DIGEST_SIZE); 113 | sha224_final(&ctx->ctx_outside, mac_temp); 114 | memcpy(mac, mac_temp, mac_size); 115 | } 116 | 117 | void hmac_sha224(const unsigned char *key, unsigned int key_size, 118 | const unsigned char *message, unsigned int message_len, 119 | unsigned char *mac, unsigned mac_size) 120 | { 121 | hmac_sha224_ctx ctx; 122 | 123 | hmac_sha224_init(&ctx, key, key_size); 124 | hmac_sha224_update(&ctx, message, message_len); 125 | hmac_sha224_final(&ctx, mac, mac_size); 126 | } 127 | 128 | /* HMAC-SHA-256 functions */ 129 | 130 | void hmac_sha256_init(hmac_sha256_ctx *ctx, const unsigned char *key, 131 | unsigned int key_size) 132 | { 133 | unsigned int fill; 134 | unsigned int num; 135 | 136 | const unsigned char *key_used; 137 | unsigned char key_temp[SHA256_DIGEST_SIZE]; 138 | int i; 139 | 140 | if (key_size == SHA256_BLOCK_SIZE) { 141 | key_used = key; 142 | num = SHA256_BLOCK_SIZE; 143 | } else { 144 | if (key_size > SHA256_BLOCK_SIZE){ 145 | num = SHA256_DIGEST_SIZE; 146 | sha256(key, key_size, key_temp); 147 | key_used = key_temp; 148 | } else { /* key_size > SHA256_BLOCK_SIZE */ 149 | key_used = key; 150 | num = key_size; 151 | } 152 | fill = SHA256_BLOCK_SIZE - num; 153 | 154 | memset(ctx->block_ipad + num, 0x36, fill); 155 | memset(ctx->block_opad + num, 0x5c, fill); 156 | } 157 | 158 | for (i = 0; i < (int) num; i++) { 159 | ctx->block_ipad[i] = key_used[i] ^ 0x36; 160 | ctx->block_opad[i] = key_used[i] ^ 0x5c; 161 | } 162 | 163 | sha256_init(&ctx->ctx_inside); 164 | sha256_update(&ctx->ctx_inside, ctx->block_ipad, SHA256_BLOCK_SIZE); 165 | 166 | sha256_init(&ctx->ctx_outside); 167 | sha256_update(&ctx->ctx_outside, ctx->block_opad, 168 | SHA256_BLOCK_SIZE); 169 | 170 | /* for hmac_reinit */ 171 | memcpy(&ctx->ctx_inside_reinit, &ctx->ctx_inside, 172 | sizeof(sha256_ctx)); 173 | memcpy(&ctx->ctx_outside_reinit, &ctx->ctx_outside, 174 | sizeof(sha256_ctx)); 175 | } 176 | 177 | void hmac_sha256_reinit(hmac_sha256_ctx *ctx) 178 | { 179 | memcpy(&ctx->ctx_inside, &ctx->ctx_inside_reinit, 180 | sizeof(sha256_ctx)); 181 | memcpy(&ctx->ctx_outside, &ctx->ctx_outside_reinit, 182 | sizeof(sha256_ctx)); 183 | } 184 | 185 | void hmac_sha256_update(hmac_sha256_ctx *ctx, const unsigned char *message, 186 | unsigned int message_len) 187 | { 188 | sha256_update(&ctx->ctx_inside, message, message_len); 189 | } 190 | 191 | void hmac_sha256_final(hmac_sha256_ctx *ctx, unsigned char *mac, 192 | unsigned int mac_size) 193 | { 194 | unsigned char digest_inside[SHA256_DIGEST_SIZE]; 195 | unsigned char mac_temp[SHA256_DIGEST_SIZE]; 196 | 197 | sha256_final(&ctx->ctx_inside, digest_inside); 198 | sha256_update(&ctx->ctx_outside, digest_inside, SHA256_DIGEST_SIZE); 199 | sha256_final(&ctx->ctx_outside, mac_temp); 200 | memcpy(mac, mac_temp, mac_size); 201 | } 202 | 203 | void hmac_sha256(const unsigned char *key, unsigned int key_size, 204 | const unsigned char *message, unsigned int message_len, 205 | unsigned char *mac, unsigned mac_size) 206 | { 207 | hmac_sha256_ctx ctx; 208 | 209 | hmac_sha256_init(&ctx, key, key_size); 210 | hmac_sha256_update(&ctx, message, message_len); 211 | hmac_sha256_final(&ctx, mac, mac_size); 212 | } 213 | 214 | /* HMAC-SHA-384 functions */ 215 | 216 | void hmac_sha384_init(hmac_sha384_ctx *ctx, const unsigned char *key, 217 | unsigned int key_size) 218 | { 219 | unsigned int fill; 220 | unsigned int num; 221 | 222 | const unsigned char *key_used; 223 | unsigned char key_temp[SHA384_DIGEST_SIZE]; 224 | int i; 225 | 226 | if (key_size == SHA384_BLOCK_SIZE) { 227 | key_used = key; 228 | num = SHA384_BLOCK_SIZE; 229 | } else { 230 | if (key_size > SHA384_BLOCK_SIZE){ 231 | num = SHA384_DIGEST_SIZE; 232 | sha384(key, key_size, key_temp); 233 | key_used = key_temp; 234 | } else { /* key_size > SHA384_BLOCK_SIZE */ 235 | key_used = key; 236 | num = key_size; 237 | } 238 | fill = SHA384_BLOCK_SIZE - num; 239 | 240 | memset(ctx->block_ipad + num, 0x36, fill); 241 | memset(ctx->block_opad + num, 0x5c, fill); 242 | } 243 | 244 | for (i = 0; i < (int) num; i++) { 245 | ctx->block_ipad[i] = key_used[i] ^ 0x36; 246 | ctx->block_opad[i] = key_used[i] ^ 0x5c; 247 | } 248 | 249 | sha384_init(&ctx->ctx_inside); 250 | sha384_update(&ctx->ctx_inside, ctx->block_ipad, SHA384_BLOCK_SIZE); 251 | 252 | sha384_init(&ctx->ctx_outside); 253 | sha384_update(&ctx->ctx_outside, ctx->block_opad, 254 | SHA384_BLOCK_SIZE); 255 | 256 | /* for hmac_reinit */ 257 | memcpy(&ctx->ctx_inside_reinit, &ctx->ctx_inside, 258 | sizeof(sha384_ctx)); 259 | memcpy(&ctx->ctx_outside_reinit, &ctx->ctx_outside, 260 | sizeof(sha384_ctx)); 261 | } 262 | 263 | void hmac_sha384_reinit(hmac_sha384_ctx *ctx) 264 | { 265 | memcpy(&ctx->ctx_inside, &ctx->ctx_inside_reinit, 266 | sizeof(sha384_ctx)); 267 | memcpy(&ctx->ctx_outside, &ctx->ctx_outside_reinit, 268 | sizeof(sha384_ctx)); 269 | } 270 | 271 | void hmac_sha384_update(hmac_sha384_ctx *ctx, const unsigned char *message, 272 | unsigned int message_len) 273 | { 274 | sha384_update(&ctx->ctx_inside, message, message_len); 275 | } 276 | 277 | void hmac_sha384_final(hmac_sha384_ctx *ctx, unsigned char *mac, 278 | unsigned int mac_size) 279 | { 280 | unsigned char digest_inside[SHA384_DIGEST_SIZE]; 281 | unsigned char mac_temp[SHA384_DIGEST_SIZE]; 282 | 283 | sha384_final(&ctx->ctx_inside, digest_inside); 284 | sha384_update(&ctx->ctx_outside, digest_inside, SHA384_DIGEST_SIZE); 285 | sha384_final(&ctx->ctx_outside, mac_temp); 286 | memcpy(mac, mac_temp, mac_size); 287 | } 288 | 289 | void hmac_sha384(const unsigned char *key, unsigned int key_size, 290 | const unsigned char *message, unsigned int message_len, 291 | unsigned char *mac, unsigned mac_size) 292 | { 293 | hmac_sha384_ctx ctx; 294 | 295 | hmac_sha384_init(&ctx, key, key_size); 296 | hmac_sha384_update(&ctx, message, message_len); 297 | hmac_sha384_final(&ctx, mac, mac_size); 298 | } 299 | 300 | /* HMAC-SHA-512 functions */ 301 | 302 | void hmac_sha512_init(hmac_sha512_ctx *ctx, const unsigned char *key, 303 | unsigned int key_size) 304 | { 305 | unsigned int fill; 306 | unsigned int num; 307 | 308 | const unsigned char *key_used; 309 | unsigned char key_temp[SHA512_DIGEST_SIZE]; 310 | int i; 311 | 312 | if (key_size == SHA512_BLOCK_SIZE) { 313 | key_used = key; 314 | num = SHA512_BLOCK_SIZE; 315 | } else { 316 | if (key_size > SHA512_BLOCK_SIZE){ 317 | num = SHA512_DIGEST_SIZE; 318 | sha512(key, key_size, key_temp); 319 | key_used = key_temp; 320 | } else { /* key_size > SHA512_BLOCK_SIZE */ 321 | key_used = key; 322 | num = key_size; 323 | } 324 | fill = SHA512_BLOCK_SIZE - num; 325 | 326 | memset(ctx->block_ipad + num, 0x36, fill); 327 | memset(ctx->block_opad + num, 0x5c, fill); 328 | } 329 | 330 | for (i = 0; i < (int) num; i++) { 331 | ctx->block_ipad[i] = key_used[i] ^ 0x36; 332 | ctx->block_opad[i] = key_used[i] ^ 0x5c; 333 | } 334 | 335 | sha512_init(&ctx->ctx_inside); 336 | sha512_update(&ctx->ctx_inside, ctx->block_ipad, SHA512_BLOCK_SIZE); 337 | 338 | sha512_init(&ctx->ctx_outside); 339 | sha512_update(&ctx->ctx_outside, ctx->block_opad, 340 | SHA512_BLOCK_SIZE); 341 | 342 | /* for hmac_reinit */ 343 | memcpy(&ctx->ctx_inside_reinit, &ctx->ctx_inside, 344 | sizeof(sha512_ctx)); 345 | memcpy(&ctx->ctx_outside_reinit, &ctx->ctx_outside, 346 | sizeof(sha512_ctx)); 347 | } 348 | 349 | void hmac_sha512_reinit(hmac_sha512_ctx *ctx) 350 | { 351 | memcpy(&ctx->ctx_inside, &ctx->ctx_inside_reinit, 352 | sizeof(sha512_ctx)); 353 | memcpy(&ctx->ctx_outside, &ctx->ctx_outside_reinit, 354 | sizeof(sha512_ctx)); 355 | } 356 | 357 | void hmac_sha512_update(hmac_sha512_ctx *ctx, const unsigned char *message, 358 | unsigned int message_len) 359 | { 360 | sha512_update(&ctx->ctx_inside, message, message_len); 361 | } 362 | 363 | void hmac_sha512_final(hmac_sha512_ctx *ctx, unsigned char *mac, 364 | unsigned int mac_size) 365 | { 366 | unsigned char digest_inside[SHA512_DIGEST_SIZE]; 367 | unsigned char mac_temp[SHA512_DIGEST_SIZE]; 368 | 369 | sha512_final(&ctx->ctx_inside, digest_inside); 370 | sha512_update(&ctx->ctx_outside, digest_inside, SHA512_DIGEST_SIZE); 371 | sha512_final(&ctx->ctx_outside, mac_temp); 372 | memcpy(mac, mac_temp, mac_size); 373 | } 374 | 375 | void hmac_sha512(const unsigned char *key, unsigned int key_size, 376 | const unsigned char *message, unsigned int message_len, 377 | unsigned char *mac, unsigned mac_size) 378 | { 379 | hmac_sha512_ctx ctx; 380 | 381 | hmac_sha512_init(&ctx, key, key_size); 382 | hmac_sha512_update(&ctx, message, message_len); 383 | hmac_sha512_final(&ctx, mac, mac_size); 384 | } 385 | 386 | #ifdef TEST_VECTORS 387 | 388 | /* IETF Validation tests */ 389 | 390 | #include 391 | #include 392 | 393 | void test(const char *vector, unsigned char *digest, 394 | unsigned int digest_size) 395 | { 396 | char output[2 * SHA512_DIGEST_SIZE + 1]; 397 | int i; 398 | 399 | output[2 * digest_size] = '\0'; 400 | 401 | for (i = 0; i < (int) digest_size ; i++) { 402 | sprintf(output + 2*i, "%02x", digest[i]); 403 | } 404 | 405 | printf("H: %s\n", output); 406 | if (strcmp(vector, output)) { 407 | fprintf(stderr, "Test failed.\n"); 408 | exit(1); 409 | } 410 | } 411 | 412 | int main(void) 413 | { 414 | static const char *vectors[] = 415 | { 416 | /* HMAC-SHA-224 */ 417 | "896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22", 418 | "a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44", 419 | "7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea", 420 | "6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a", 421 | "0e2aea68a90c8d37c988bcdb9fca6fa8", 422 | "95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e", 423 | "3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1", 424 | /* HMAC-SHA-256 */ 425 | "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7", 426 | "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843", 427 | "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe", 428 | "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b", 429 | "a3b6167473100ee06e0c796c2955552b", 430 | "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54", 431 | "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2", 432 | /* HMAC-SHA-384 */ 433 | "afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59c" 434 | "faea9ea9076ede7f4af152e8b2fa9cb6", 435 | "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e" 436 | "8e2240ca5e69e2c78b3239ecfab21649", 437 | "88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b" 438 | "2a5ab39dc13814b94e3ab6e101a34f27", 439 | "3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e" 440 | "6801dd23c4a7d679ccf8a386c674cffb", 441 | "3abf34c3503b2a23a46efc619baef897", 442 | "4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c6" 443 | "0c2ef6ab4030fe8296248df163f44952", 444 | "6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5" 445 | "a678cc31e799176d3860e6110c46523e", 446 | /* HMAC-SHA-512 */ 447 | "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cde" 448 | "daa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854", 449 | "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea250554" 450 | "9758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737", 451 | "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39" 452 | "bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb", 453 | "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3db" 454 | "a91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd", 455 | "415fad6271580a531d4179bc891d87a6", 456 | "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f352" 457 | "6b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598", 458 | "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944" 459 | "b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58" 460 | }; 461 | 462 | static char *messages[] = 463 | { 464 | "Hi There", 465 | "what do ya want for nothing?", 466 | NULL, 467 | NULL, 468 | "Test With Truncation", 469 | "Test Using Larger Than Block-Size Key - Hash Key First", 470 | "This is a test using a larger than block-size key " 471 | "and a larger than block-size data. The key needs" 472 | " to be hashed before being used by the HMAC algorithm." 473 | }; 474 | 475 | unsigned char mac[SHA512_DIGEST_SIZE]; 476 | unsigned char *keys[7]; 477 | unsigned int keys_len[7] = {20, 4, 20, 25, 20, 131, 131}; 478 | unsigned int messages2and3_len = 50; 479 | unsigned int mac_224_size, mac_256_size, mac_384_size, mac_512_size; 480 | int i; 481 | 482 | for (i = 0; i < 7; i++) { 483 | keys[i] = malloc(keys_len[i]); 484 | if (keys[i] == NULL) { 485 | fprintf(stderr, "Can't allocate memory\n"); 486 | return 1; 487 | } 488 | } 489 | 490 | memset(keys[0], 0x0b, keys_len[0]); 491 | strcpy((char *) keys[1], "Jefe"); 492 | memset(keys[2], 0xaa, keys_len[2]); 493 | for (i = 0; i < (int) keys_len[3]; i++) 494 | keys[3][i] = (unsigned char) i + 1; 495 | memset(keys[4], 0x0c, keys_len[4]); 496 | memset(keys[5], 0xaa, keys_len[5]); 497 | memset(keys[6], 0xaa, keys_len[6]); 498 | 499 | messages[2] = malloc(messages2and3_len + 1); 500 | messages[3] = malloc(messages2and3_len + 1); 501 | 502 | if (messages[2] == NULL || messages[3] == NULL) { 503 | fprintf(stderr, "Can't allocate memory\n"); 504 | return 1; 505 | } 506 | 507 | messages[2][messages2and3_len] = '\0'; 508 | messages[3][messages2and3_len] = '\0'; 509 | 510 | memset(messages[2], 0xdd, messages2and3_len); 511 | memset(messages[3], 0xcd, messages2and3_len); 512 | 513 | printf("HMAC-SHA-2 IETF Validation tests\n\n"); 514 | 515 | for (i = 0; i < 7; i++) { 516 | if (i != 4) { 517 | mac_224_size = SHA224_DIGEST_SIZE; 518 | mac_256_size = SHA256_DIGEST_SIZE; 519 | mac_384_size = SHA384_DIGEST_SIZE; 520 | mac_512_size = SHA512_DIGEST_SIZE; 521 | } else { 522 | mac_224_size = 128 / 8; mac_256_size = 128 / 8; 523 | mac_384_size = 128 / 8; mac_512_size = 128 / 8; 524 | } 525 | 526 | printf("Test %d:\n", i + 1); 527 | 528 | hmac_sha224(keys[i], keys_len[i], (unsigned char *) messages[i], 529 | strlen(messages[i]), mac, mac_224_size); 530 | test(vectors[i], mac, mac_224_size); 531 | hmac_sha256(keys[i], keys_len[i], (unsigned char *) messages[i], 532 | strlen(messages[i]), mac, mac_256_size); 533 | test(vectors[7 + i], mac, mac_256_size); 534 | hmac_sha384(keys[i], keys_len[i], (unsigned char *) messages[i], 535 | strlen(messages[i]), mac, mac_384_size); 536 | test(vectors[14 + i], mac, mac_384_size); 537 | hmac_sha512(keys[i], keys_len[i], (unsigned char *) messages[i], 538 | strlen(messages[i]), mac, mac_512_size); 539 | test(vectors[21 + i], mac, mac_512_size); 540 | } 541 | 542 | printf("All tests passed.\n"); 543 | 544 | return 0; 545 | } 546 | 547 | #endif /* TEST_VECTORS */ 548 | 549 | -------------------------------------------------------------------------------- /mmc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU General Public 4 | * License v2 as published by the Free Software Foundation. 5 | * 6 | * This program is distributed in the hope that it will be useful, 7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 | * General Public License for more details. 10 | * 11 | * You should have received a copy of the GNU General Public 12 | * License along with this program; if not, write to the 13 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 14 | * Boston, MA 021110-1307, USA. 15 | * 16 | * Modified to add field firmware update support, 17 | * those modifications are Copyright (c) 2016 SanDisk Corp. 18 | * 19 | * (This code is based on btrfs-progs/btrfs.c.) 20 | */ 21 | 22 | #define _GNU_SOURCE 23 | #include 24 | #include 25 | #include 26 | 27 | #include "mmc_cmds.h" 28 | 29 | #define BASIC_HELP 0 30 | #define ADVANCED_HELP 1 31 | 32 | typedef int (*CommandFunction)(int argc, char **argv); 33 | 34 | struct Command { 35 | CommandFunction func; /* function which implements the command */ 36 | int nargs; /* if == 999, any number of arguments 37 | if >= 0, number of arguments, 38 | if < 0, _minimum_ number of arguments */ 39 | char *verb; /* verb */ 40 | char *help; /* help lines; from the 2nd line onward they 41 | are automatically indented */ 42 | char *adv_help; /* advanced help message; from the 2nd line 43 | onward they are automatically indented */ 44 | 45 | /* the following fields are run-time filled by the program */ 46 | char **cmds; /* array of subcommands */ 47 | int ncmds; /* number of subcommand */ 48 | }; 49 | 50 | static struct Command commands[] = { 51 | /* 52 | * avoid short commands different for the case only 53 | */ 54 | { do_read_extcsd, -1, 55 | "extcsd read", "\n" 56 | "Print extcsd data from .", 57 | NULL 58 | }, 59 | { do_write_extcsd, 3, 60 | "extcsd write", " \n" 61 | "Write at offset to 's extcsd.", 62 | NULL 63 | }, 64 | { do_writeprotect_boot_get, -1, 65 | "writeprotect boot get", "\n" 66 | "Print the boot partitions write protect status for .", 67 | NULL 68 | }, 69 | { do_writeprotect_boot_set, -1, 70 | "writeprotect boot set", 71 | #ifdef DANGEROUS_COMMANDS_ENABLED 72 | "[-p] " 73 | #endif /* DANGEROUS_COMMANDS_ENABLED */ 74 | " []\n" 75 | "Set the boot partition write protect status for .\n" 76 | "If is passed (0 or 1), only protect that particular\n" 77 | "eMMC boot partition, otherwise protect both. It will be\n" 78 | "write-protected until the next boot.\n" 79 | #ifdef DANGEROUS_COMMANDS_ENABLED 80 | " -p Protect partition permanently instead.\n" 81 | " NOTE! -p is a one-time programmable (unreversible) change.\n" 82 | #endif /* DANGEROUS_COMMANDS_ENABLED */ 83 | , NULL 84 | }, 85 | { do_writeprotect_user_set, -4, 86 | "writeprotect user set", "" "" "" "\n" 87 | #ifdef DANGEROUS_COMMANDS_ENABLED 88 | "Set the write protect configuration for the specified region\nof the user area for .\n must be \"none|temp|pwron|perm\".\n \"none\" - Clear temporary write protection.\n \"temp\" - Set temporary write protection.\n \"pwron\" - Set write protection until the next poweron.\n \"perm\" - Set permanent write protection.\n specifies the first block of the protected area.\n specifies the size of the protected area in blocks.\nNOTE! The area must start and end on Write Protect Group\nboundries, Use the \"writeprotect user get\" command to get the\nWrite Protect Group size.\nNOTE! \"perm\" is a one-time programmable (unreversible) change.", 89 | #else 90 | "Set the write protect configuration for the specified region\nof the user area for .\n must be \"none|temp|pwron\".\n \"none\" - Clear temporary write protection.\n \"temp\" - Set temporary write protection.\n \"pwron\" - Set write protection until the next poweron.\n specifies the first block of the protected area.\n specifies the size of the protected area in blocks.\nNOTE! The area must start and end on Write Protect Group\nboundries, Use the \"writeprotect user get\" command to get the\nWrite Protect Group size.", 91 | #endif /* DANGEROUS_COMMANDS_ENABLED */ 92 | NULL 93 | }, 94 | { do_writeprotect_user_get, -1, 95 | "writeprotect user get", "\n" 96 | "Print the user areas write protect configuration for .", 97 | NULL 98 | }, 99 | { do_disable_512B_emulation, -1, 100 | "disable 512B emulation", "\n" 101 | "Set the eMMC data sector size to 4KB by disabling emulation on\n.", 102 | NULL 103 | }, 104 | { do_create_gp_partition, -6, 105 | "gp create", "<-y|-n|-c> " " " " " " " " " "\n" 106 | "Create general purpose partition for the .\nDry-run only unless -y or -c is passed.\nUse -c if more partitioning settings are still to come.\nNOTE! This is a one-time programmable (unreversible) change.\nTo set enhanced attribute to general partition being created set\n to 1 else set it to 0.\nTo set extended attribute to general partition\n set to 1,2 else set it to 0", 107 | NULL 108 | }, 109 | { do_enh_area_set, -4, 110 | "enh_area set", "<-y|-n|-c> " " " " " "\n" 111 | "Enable the enhanced user area for the .\nDry-run only unless -y or -c is passed.\nUse -c if more partitioning settings are still to come.\nNOTE! This is a one-time programmable (unreversible) change.", 112 | NULL 113 | }, 114 | { do_write_reliability_set, -2, 115 | "write_reliability set", "<-y|-n|-c> " " " "\n" 116 | "Enable write reliability per partition for the .\nDry-run only unless -y or -c is passed.\nUse -c if more partitioning settings are still to come.\nNOTE! This is a one-time programmable (unreversible) change.", 117 | NULL 118 | }, 119 | { do_status_get, -1, 120 | "status get", "\n" 121 | "Print the response to STATUS_SEND (CMD13).", 122 | NULL 123 | }, 124 | { do_write_boot_en, -3, 125 | "bootpart enable", " " " " "\n" 126 | "Enable the boot partition for the .\nDisable the boot partition for the if is set to 0.\nTo receive acknowledgment of boot from the card set \nto 1, else set it to 0.", 127 | NULL 128 | }, 129 | { do_boot_bus_conditions_set, -4, 130 | "bootbus set", " " " " " " "\n" 131 | "Set Boot Bus Conditions.\n" 132 | " must be \"single_backward|single_hs|dual\"\n" 133 | " must be \"x1|retain\"\n" 134 | " must be \"x1|x4|x8\"", 135 | NULL 136 | }, 137 | { do_write_bkops_en, -2, 138 | "bkops_en", " \n" 139 | "Enable the eMMC BKOPS feature on .\n" 140 | "The auto (AUTO_EN) setting is only supported on eMMC 5.0 or newer.\n" 141 | "Setting auto won't have any effect if manual is set.\n" 142 | "NOTE! Setting manual (MANUAL_EN) is one-time programmable (unreversible) change.", 143 | NULL 144 | }, 145 | { do_hwreset_en, -1, 146 | "hwreset enable", "\n" 147 | "Permanently enable the eMMC H/W Reset feature on .\nNOTE! This is a one-time programmable (unreversible) change.", 148 | NULL 149 | }, 150 | { do_hwreset_dis, -1, 151 | "hwreset disable", "\n" 152 | "Permanently disable the eMMC H/W Reset feature on .\nNOTE! This is a one-time programmable (unreversible) change.", 153 | NULL 154 | }, 155 | { do_sanitize, -1, 156 | "sanitize", " [timeout_ms]\n" 157 | "Send Sanitize command to the .\nThis will delete the unmapped memory region of the device.", 158 | NULL 159 | }, 160 | { do_rpmb_write_key, -1, 161 | "rpmb write-key", " \n" 162 | "Program authentication key which is 32 bytes length and stored\n" 163 | "in the specified file. Also you can specify '-' instead of\n" 164 | "key file path to read the key from stdin.\n" 165 | "NOTE! This is a one-time programmable (unreversible) change.\n" 166 | "Example:\n" 167 | " $ echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH | \\\n" 168 | " mmc rpmb write-key /dev/mmcblk0rpmb -", 169 | NULL 170 | }, 171 | { do_rpmb_read_counter, -1, 172 | "rpmb read-counter", "\n" 173 | "Counter value for the will be read to stdout.", 174 | NULL 175 | }, 176 | { do_rpmb_read_block, -1, 177 | "rpmb read-block", "
[key file]\n" 178 | "Blocks of 256 bytes will be read from to output\n" 179 | "file or stdout if '-' is specified. If key is specified - read\n" 180 | "data will be verified. Instead of regular path you can specify\n" 181 | "'-' to read key from stdin.\n" 182 | "Example:\n" 183 | " $ echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH | \\\n" 184 | " mmc rpmb read-block /dev/mmcblk0rpmb 0x02 2 /tmp/block -\n" 185 | "or read two blocks without verification\n" 186 | " $ mmc rpmb read-block /dev/mmcblk0rpmb 0x02 2 /tmp/block", 187 | NULL 188 | }, 189 | { do_rpmb_write_block, -1, 190 | "rpmb write-block", "
<256 byte data file> \n" 191 | "Block of 256 bytes will be written from data file to\n" 192 | ". Also you can specify '-' instead of key\n" 193 | "file path or data file to read the data from stdin.\n" 194 | "Example:\n" 195 | " $ (awk 'BEGIN {while (c++<256) printf \"a\"}' | \\\n" 196 | " echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH) | \\\n" 197 | " mmc rpmb write-block /dev/mmcblk0rpmb 0x02 - -", 198 | NULL 199 | }, 200 | { do_cache_en, -1, 201 | "cache enable", "\n" 202 | "Enable the eMMC cache feature on .\n" 203 | "NOTE! The cache is an optional feature on devices >= eMMC4.5.", 204 | NULL 205 | }, 206 | { do_cache_dis, -1, 207 | "cache disable", "\n" 208 | "Disable the eMMC cache feature on .\n" 209 | "NOTE! The cache is an optional feature on devices >= eMMC4.5.", 210 | NULL 211 | }, 212 | { do_read_csd, -1, 213 | "csd read", "\n" 214 | "Print CSD data from .\n" 215 | "The device path should specify the csd file directory.", 216 | NULL 217 | }, 218 | { do_read_cid, -1, 219 | "cid read", "\n" 220 | "Print CID data from .\n" 221 | "The device path should specify the cid file directory.", 222 | NULL 223 | }, 224 | { do_read_scr, -1, 225 | "scr read", "\n" 226 | "Print SCR data from .\n" 227 | "The device path should specify the scr file directory.", 228 | NULL 229 | }, 230 | { do_ffu, -2, 231 | "ffu", " [chunk-bytes]\n" 232 | "Run Field Firmware Update with on .\n" 233 | "[chunk-bytes] is optional and defaults to its max - 512k. " 234 | "should be in decimal bytes and sector aligned.\n", 235 | NULL 236 | }, 237 | { do_opt_ffu1, -2, 238 | "opt_ffu1", " [chunk-bytes]\n" 239 | "Optional FFU mode 1, it's the same as 'ffu', but uses CMD23+CMD25 for repeated downloads and remains in FFU mode until completion.\n", 240 | NULL 241 | }, 242 | { do_opt_ffu2, -2, 243 | "opt_ffu2", " [chunk-bytes]\n" 244 | "Optional FFU mode 2, uses CMD25+CMD12 Open-ended Multiple-block write to download and remains in FFU mode until completion.\n", 245 | NULL 246 | }, 247 | { do_opt_ffu3, -2, 248 | "opt_ffu3", " [chunk-bytes]\n" 249 | "Optional FFU mode 3, uses CMD24 Single-block write for downloading, exiting FFU mode after each block written.\n", 250 | NULL 251 | }, 252 | { do_opt_ffu4, -2, 253 | "opt_ffu4", " [chunk-bytes]\n" 254 | "Optional FFU mode 4, uses CMD24 Single-block write for repeated downloads, remaining in FFU mode until completion.\n", 255 | NULL 256 | }, 257 | { do_erase, -4, 258 | "erase", " " " " " " "\n" 259 | "Send Erase CMD38 with specific argument to the \n\n" 260 | "NOTE!: This will delete all user data in the specified region of the device\n" 261 | " must be: legacy | discard | secure-erase | " 262 | "secure-trim1 | secure-trim2 | trim \n", 263 | NULL 264 | }, 265 | { do_general_cmd_read, -1, 266 | "gen_cmd read", " [arg]\n" 267 | "Send GEN_CMD (CMD56) to read vendor-specific format/meaning data from \n\n" 268 | "NOTE!: [arg] is optional and defaults to 0x1. If [arg] is specified, then [arg]\n" 269 | "must be a 32-bit hexadecimal number, prefixed with 0x/0X. And bit0 in [arg] must\n" 270 | "be 1.", 271 | NULL 272 | }, 273 | { do_softreset, -1, 274 | "softreset", "\n" 275 | "Issues a CMD0 softreset, e.g. for testing if hardware reset for UHS works", 276 | NULL 277 | }, 278 | { do_preidle, -1, 279 | "preidle", "\n" 280 | "Issues a CMD0 GO_PRE_IDLE", 281 | NULL 282 | }, 283 | { do_alt_boot_op, -1, 284 | "boot_operation", " \n" 285 | "Does the alternative boot operation and writes the specified starting blocks of boot data into the requested file.\n\n" 286 | "Note some limitations\n:" 287 | "1. The boot operation must be configured, e.g. for legacy speed:\n" 288 | "mmc-utils bootbus set single_backward retain x8 /dev/mmcblk2\n" 289 | "mmc-utils bootpart enable 1 0 /dev/mmcblk2\n" 290 | "2. The MMC must currently be running at the bus mode that is configured for the boot operation (HS200 and HS400 not supported at all).\n" 291 | "3. Only up to 512K bytes of boot data will be transferred.\n" 292 | "4. The MMC will perform a soft reset, if your system cannot handle that do not use the boot operation from mmc-utils.\n", 293 | NULL 294 | }, 295 | { NULL, 0, NULL, NULL } 296 | }; 297 | 298 | static char *get_prgname(char *programname) 299 | { 300 | char *np; 301 | np = strrchr(programname,'/'); 302 | if(!np) 303 | np = programname; 304 | else 305 | np++; 306 | 307 | return np; 308 | } 309 | 310 | static void print_help(char *programname, struct Command *cmd, int helptype) 311 | { 312 | char *pc; 313 | 314 | printf("\t%s %s ", programname, cmd->verb ); 315 | 316 | if (helptype == ADVANCED_HELP && cmd->adv_help) 317 | for(pc = cmd->adv_help; *pc; pc++){ 318 | putchar(*pc); 319 | if(*pc == '\n') 320 | printf("\t\t"); 321 | } 322 | else 323 | for(pc = cmd->help; *pc; pc++){ 324 | putchar(*pc); 325 | if(*pc == '\n') 326 | printf("\t\t"); 327 | } 328 | 329 | putchar('\n'); 330 | } 331 | 332 | static void help(char *np) 333 | { 334 | struct Command *cp; 335 | 336 | printf("Usage:\n"); 337 | for( cp = commands; cp->verb; cp++ ) 338 | print_help(np, cp, BASIC_HELP); 339 | 340 | printf("\n\t%s help|--help|-h\n\t\tShow the help.\n",np); 341 | printf("\n\t%s --help\n\t\tShow detailed help for a command or subset of commands.\n",np); 342 | printf("\n%s\n", VERSION); 343 | } 344 | 345 | static int split_command(char *cmd, char ***commands) 346 | { 347 | int c, l; 348 | char *p, *s; 349 | 350 | for (*commands = NULL, l = c = 0, p = s = cmd ; ; p++, l++) { 351 | if ( *p && *p != ' ' ) 352 | continue; 353 | 354 | /* c + 2 so that we have room for the null */ 355 | (*commands) = realloc( (*commands), sizeof(char *)*(c + 2)); 356 | (*commands)[c] = strndup(s, l); 357 | c++; 358 | l = 0; 359 | s = p+1; 360 | if( !*p ) break; 361 | } 362 | 363 | (*commands)[c] = NULL; 364 | return c; 365 | } 366 | 367 | /* 368 | This function checks if the passed command is ambiguous 369 | */ 370 | static int check_ambiguity(struct Command *cmd, char **argv){ 371 | int i; 372 | struct Command *cp; 373 | /* check for ambiguity */ 374 | for( i = 0 ; i < cmd->ncmds ; i++ ){ 375 | int match; 376 | for( match = 0, cp = commands; cp->verb; cp++ ){ 377 | int j, skip; 378 | char *s1, *s2; 379 | 380 | if( cp->ncmds < i ) 381 | continue; 382 | 383 | for( skip = 0, j = 0 ; j < i ; j++ ) 384 | if( strcmp(cmd->cmds[j], cp->cmds[j])){ 385 | skip=1; 386 | break; 387 | } 388 | if(skip) 389 | continue; 390 | 391 | if( !strcmp(cmd->cmds[i], cp->cmds[i])) 392 | continue; 393 | for(s2 = cp->cmds[i], s1 = argv[i+1]; 394 | *s1 == *s2 && *s1; s1++, s2++ ) ; 395 | if( !*s1 ) 396 | match++; 397 | } 398 | if(match){ 399 | int j; 400 | fprintf(stderr, "ERROR: in command '"); 401 | for( j = 0 ; j <= i ; j++ ) 402 | fprintf(stderr, "%s%s",j?" ":"", argv[j+1]); 403 | fprintf(stderr, "', '%s' is ambiguous\n",argv[j]); 404 | return -2; 405 | } 406 | } 407 | return 0; 408 | } 409 | 410 | /* 411 | * This function, compacts the program name and the command in the first 412 | * element of the '*av' array 413 | */ 414 | static int prepare_args(int *ac, char ***av, char *prgname, struct Command *cmd ){ 415 | 416 | char **ret; 417 | int i; 418 | char *newname; 419 | 420 | ret = (char **)malloc(sizeof(char*)*(*ac+1)); 421 | newname = (char*)malloc(strlen(prgname)+strlen(cmd->verb)+2); 422 | if( !ret || !newname ){ 423 | free(ret); 424 | free(newname); 425 | return -1; 426 | } 427 | 428 | ret[0] = newname; 429 | for(i=0; i < *ac ; i++ ) 430 | ret[i+1] = (*av)[i]; 431 | 432 | strcpy(newname, prgname); 433 | strcat(newname, " "); 434 | strcat(newname, cmd->verb); 435 | 436 | (*ac)++; 437 | *av = ret; 438 | 439 | return 0; 440 | 441 | } 442 | 443 | /* 444 | This function performs the following jobs: 445 | - show the help if '--help' or 'help' or '-h' are passed 446 | - verify that a command is not ambiguous, otherwise show which 447 | part of the command is ambiguous 448 | - if after a (even partial) command there is '--help' show detailed help 449 | for all the matching commands 450 | - if the command doesn't match show an error 451 | - finally, if a command matches, they return which command matched and 452 | the arguments 453 | 454 | The function return 0 in case of help is requested; <0 in case 455 | of uncorrect command; >0 in case of matching commands 456 | argc, argv are the arg-counter and arg-vector (input) 457 | *nargs_ is the number of the arguments after the command (output) 458 | **cmd_ is the invoked command (output) 459 | ***args_ are the arguments after the command 460 | 461 | */ 462 | static int parse_args(int argc, char **argv, 463 | CommandFunction *func_, 464 | int *nargs_, char **cmd_, char ***args_ ) 465 | { 466 | struct Command *cp; 467 | struct Command *matchcmd = NULL; 468 | char *prgname = get_prgname(argv[0]); 469 | int i=0, helprequested=0; 470 | 471 | if( argc < 2 || !strcmp(argv[1], "help") || 472 | !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){ 473 | help(prgname); 474 | return 0; 475 | } 476 | 477 | for( cp = commands; cp->verb; cp++ ) 478 | if( !cp->ncmds) 479 | cp->ncmds = split_command(cp->verb, &(cp->cmds)); 480 | 481 | for( cp = commands; cp->verb; cp++ ){ 482 | int match; 483 | 484 | if( argc-1 < cp->ncmds ) 485 | continue; 486 | for( match = 1, i = 0 ; i < cp->ncmds ; i++ ){ 487 | char *s1, *s2; 488 | s1 = cp->cmds[i]; 489 | s2 = argv[i+1]; 490 | 491 | for(s2 = cp->cmds[i], s1 = argv[i+1]; 492 | *s1 == *s2 && *s1; 493 | s1++, s2++ ) ; 494 | if( *s1 ){ 495 | match=0; 496 | break; 497 | } 498 | } 499 | 500 | /* If you understand why this code works ... 501 | you are a genious !! */ 502 | if(argc>i+1 && !strcmp(argv[i+1],"--help")){ 503 | if(!helprequested) 504 | printf("Usage:\n"); 505 | print_help(prgname, cp, ADVANCED_HELP); 506 | helprequested=1; 507 | continue; 508 | } 509 | 510 | if(!match) 511 | continue; 512 | 513 | matchcmd = cp; 514 | *nargs_ = argc-matchcmd->ncmds-1; 515 | *cmd_ = matchcmd->verb; 516 | *args_ = argv+matchcmd->ncmds+1; 517 | *func_ = cp->func; 518 | 519 | break; 520 | } 521 | 522 | if(helprequested){ 523 | printf("\n%s\n", VERSION); 524 | return 0; 525 | } 526 | 527 | if(!matchcmd){ 528 | fprintf( stderr, "ERROR: unknown command '%s'\n",argv[1]); 529 | help(prgname); 530 | return -1; 531 | } 532 | 533 | if(check_ambiguity(matchcmd, argv)) 534 | return -2; 535 | 536 | /* check the number of argument */ 537 | if (matchcmd->nargs < 0 && matchcmd->nargs < -*nargs_ ){ 538 | fprintf(stderr, "ERROR: '%s' requires minimum %d arg(s)\n", 539 | matchcmd->verb, -matchcmd->nargs); 540 | return -2; 541 | } 542 | if(matchcmd->nargs >= 0 && matchcmd->nargs != *nargs_ && matchcmd->nargs != 999){ 543 | fprintf(stderr, "ERROR: '%s' requires %d arg(s)\n", 544 | matchcmd->verb, matchcmd->nargs); 545 | return -2; 546 | } 547 | 548 | if (prepare_args( nargs_, args_, prgname, matchcmd )){ 549 | fprintf(stderr, "ERROR: not enough memory\\n"); 550 | return -20; 551 | } 552 | 553 | 554 | return 1; 555 | } 556 | int main(int ac, char **av ) 557 | { 558 | char *cmd = NULL, **args = NULL; 559 | int nargs = 0, r; 560 | CommandFunction func = NULL; 561 | 562 | r = parse_args(ac, av, &func, &nargs, &cmd, &args); 563 | if( r <= 0 ){ 564 | /* error or no command to parse*/ 565 | exit(-r); 566 | } 567 | 568 | exit(func(nargs, args)); 569 | } 570 | 571 | -------------------------------------------------------------------------------- /3rdparty/hmac_sha/sha2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FIPS 180-2 SHA-224/256/384/512 implementation 3 | * Last update: 02/02/2007 4 | * Issue date: 04/30/2005 5 | * 6 | * Since this code has been incorporated into a GPLv2 project, it is 7 | * distributed under GPLv2 inside mmc-utils. The original BSD license 8 | * that the code was released under is included below for clarity. 9 | * 10 | * Copyright (C) 2005, 2007 Olivier Gay 11 | * All rights reserved. 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions 15 | * are met: 16 | * 1. Redistributions of source code must retain the above copyright 17 | * notice, this list of conditions and the following disclaimer. 18 | * 2. Redistributions in binary form must reproduce the above copyright 19 | * notice, this list of conditions and the following disclaimer in the 20 | * documentation and/or other materials provided with the distribution. 21 | * 3. Neither the name of the project nor the names of its contributors 22 | * may be used to endorse or promote products derived from this software 23 | * without specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 29 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 | * SUCH DAMAGE. 36 | */ 37 | 38 | #if 0 39 | #define UNROLL_LOOPS /* Enable loops unrolling */ 40 | #endif 41 | 42 | #include 43 | 44 | #include "sha2.h" 45 | 46 | #define SHFR(x, n) (x >> n) 47 | #define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) 48 | #define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) 49 | #define CH(x, y, z) ((x & y) ^ (~x & z)) 50 | #define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) 51 | 52 | #define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) 53 | #define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) 54 | #define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3)) 55 | #define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10)) 56 | 57 | #define SHA512_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39)) 58 | #define SHA512_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41)) 59 | #define SHA512_F3(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHFR(x, 7)) 60 | #define SHA512_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x, 6)) 61 | 62 | #define UNPACK32(x, str) \ 63 | { \ 64 | *((str) + 3) = (uint8) ((x) ); \ 65 | *((str) + 2) = (uint8) ((x) >> 8); \ 66 | *((str) + 1) = (uint8) ((x) >> 16); \ 67 | *((str) + 0) = (uint8) ((x) >> 24); \ 68 | } 69 | 70 | #define PACK32(str, x) \ 71 | { \ 72 | *(x) = ((uint32) *((str) + 3) ) \ 73 | | ((uint32) *((str) + 2) << 8) \ 74 | | ((uint32) *((str) + 1) << 16) \ 75 | | ((uint32) *((str) + 0) << 24); \ 76 | } 77 | 78 | #define UNPACK64(x, str) \ 79 | { \ 80 | *((str) + 7) = (uint8) ((x) ); \ 81 | *((str) + 6) = (uint8) ((x) >> 8); \ 82 | *((str) + 5) = (uint8) ((x) >> 16); \ 83 | *((str) + 4) = (uint8) ((x) >> 24); \ 84 | *((str) + 3) = (uint8) ((x) >> 32); \ 85 | *((str) + 2) = (uint8) ((x) >> 40); \ 86 | *((str) + 1) = (uint8) ((x) >> 48); \ 87 | *((str) + 0) = (uint8) ((x) >> 56); \ 88 | } 89 | 90 | #define PACK64(str, x) \ 91 | { \ 92 | *(x) = ((uint64) *((str) + 7) ) \ 93 | | ((uint64) *((str) + 6) << 8) \ 94 | | ((uint64) *((str) + 5) << 16) \ 95 | | ((uint64) *((str) + 4) << 24) \ 96 | | ((uint64) *((str) + 3) << 32) \ 97 | | ((uint64) *((str) + 2) << 40) \ 98 | | ((uint64) *((str) + 1) << 48) \ 99 | | ((uint64) *((str) + 0) << 56); \ 100 | } 101 | 102 | /* Macros used for loops unrolling */ 103 | 104 | #define SHA256_SCR(i) \ 105 | { \ 106 | w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \ 107 | + SHA256_F3(w[i - 15]) + w[i - 16]; \ 108 | } 109 | 110 | #define SHA512_SCR(i) \ 111 | { \ 112 | w[i] = SHA512_F4(w[i - 2]) + w[i - 7] \ 113 | + SHA512_F3(w[i - 15]) + w[i - 16]; \ 114 | } 115 | 116 | #define SHA256_EXP(a, b, c, d, e, f, g, h, j) \ 117 | { \ 118 | t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \ 119 | + sha256_k[j] + w[j]; \ 120 | t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ 121 | wv[d] += t1; \ 122 | wv[h] = t1 + t2; \ 123 | } 124 | 125 | #define SHA512_EXP(a, b, c, d, e, f, g ,h, j) \ 126 | { \ 127 | t1 = wv[h] + SHA512_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \ 128 | + sha512_k[j] + w[j]; \ 129 | t2 = SHA512_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ 130 | wv[d] += t1; \ 131 | wv[h] = t1 + t2; \ 132 | } 133 | 134 | static uint32 sha224_h0[8] = 135 | {0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 136 | 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; 137 | 138 | static uint32 sha256_h0[8] = 139 | {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 140 | 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; 141 | 142 | static uint64 sha384_h0[8] = 143 | {0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 144 | 0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL, 145 | 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, 146 | 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL}; 147 | 148 | static uint64 sha512_h0[8] = 149 | {0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 150 | 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, 151 | 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 152 | 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL}; 153 | 154 | static uint32 sha256_k[64] = 155 | {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 156 | 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 157 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 158 | 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 159 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 160 | 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 161 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 162 | 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 163 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 164 | 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 165 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 166 | 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 167 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 168 | 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 169 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 170 | 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; 171 | 172 | static uint64 sha512_k[80] = 173 | {0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 174 | 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 175 | 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 176 | 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 177 | 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 178 | 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 179 | 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 180 | 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 181 | 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 182 | 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 183 | 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 184 | 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 185 | 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 186 | 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 187 | 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 188 | 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 189 | 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 190 | 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, 191 | 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 192 | 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 193 | 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 194 | 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 195 | 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 196 | 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 197 | 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 198 | 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 199 | 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 200 | 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 201 | 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 202 | 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 203 | 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 204 | 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 205 | 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 206 | 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 207 | 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 208 | 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 209 | 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 210 | 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 211 | 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 212 | 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL}; 213 | 214 | /* SHA-256 functions */ 215 | 216 | static void sha256_transf(sha256_ctx *ctx, const unsigned char *message, 217 | unsigned int block_nb) 218 | { 219 | uint32 w[64]; 220 | uint32 wv[8]; 221 | uint32 t1, t2; 222 | const unsigned char *sub_block; 223 | int i; 224 | 225 | #ifndef UNROLL_LOOPS 226 | int j; 227 | #endif 228 | 229 | for (i = 0; i < (int) block_nb; i++) { 230 | sub_block = message + (i << 6); 231 | 232 | #ifndef UNROLL_LOOPS 233 | for (j = 0; j < 16; j++) { 234 | PACK32(&sub_block[j << 2], &w[j]); 235 | } 236 | 237 | for (j = 16; j < 64; j++) { 238 | SHA256_SCR(j); 239 | } 240 | 241 | for (j = 0; j < 8; j++) { 242 | wv[j] = ctx->h[j]; 243 | } 244 | 245 | for (j = 0; j < 64; j++) { 246 | t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) 247 | + sha256_k[j] + w[j]; 248 | t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); 249 | wv[7] = wv[6]; 250 | wv[6] = wv[5]; 251 | wv[5] = wv[4]; 252 | wv[4] = wv[3] + t1; 253 | wv[3] = wv[2]; 254 | wv[2] = wv[1]; 255 | wv[1] = wv[0]; 256 | wv[0] = t1 + t2; 257 | } 258 | 259 | for (j = 0; j < 8; j++) { 260 | ctx->h[j] += wv[j]; 261 | } 262 | #else 263 | PACK32(&sub_block[ 0], &w[ 0]); PACK32(&sub_block[ 4], &w[ 1]); 264 | PACK32(&sub_block[ 8], &w[ 2]); PACK32(&sub_block[12], &w[ 3]); 265 | PACK32(&sub_block[16], &w[ 4]); PACK32(&sub_block[20], &w[ 5]); 266 | PACK32(&sub_block[24], &w[ 6]); PACK32(&sub_block[28], &w[ 7]); 267 | PACK32(&sub_block[32], &w[ 8]); PACK32(&sub_block[36], &w[ 9]); 268 | PACK32(&sub_block[40], &w[10]); PACK32(&sub_block[44], &w[11]); 269 | PACK32(&sub_block[48], &w[12]); PACK32(&sub_block[52], &w[13]); 270 | PACK32(&sub_block[56], &w[14]); PACK32(&sub_block[60], &w[15]); 271 | 272 | SHA256_SCR(16); SHA256_SCR(17); SHA256_SCR(18); SHA256_SCR(19); 273 | SHA256_SCR(20); SHA256_SCR(21); SHA256_SCR(22); SHA256_SCR(23); 274 | SHA256_SCR(24); SHA256_SCR(25); SHA256_SCR(26); SHA256_SCR(27); 275 | SHA256_SCR(28); SHA256_SCR(29); SHA256_SCR(30); SHA256_SCR(31); 276 | SHA256_SCR(32); SHA256_SCR(33); SHA256_SCR(34); SHA256_SCR(35); 277 | SHA256_SCR(36); SHA256_SCR(37); SHA256_SCR(38); SHA256_SCR(39); 278 | SHA256_SCR(40); SHA256_SCR(41); SHA256_SCR(42); SHA256_SCR(43); 279 | SHA256_SCR(44); SHA256_SCR(45); SHA256_SCR(46); SHA256_SCR(47); 280 | SHA256_SCR(48); SHA256_SCR(49); SHA256_SCR(50); SHA256_SCR(51); 281 | SHA256_SCR(52); SHA256_SCR(53); SHA256_SCR(54); SHA256_SCR(55); 282 | SHA256_SCR(56); SHA256_SCR(57); SHA256_SCR(58); SHA256_SCR(59); 283 | SHA256_SCR(60); SHA256_SCR(61); SHA256_SCR(62); SHA256_SCR(63); 284 | 285 | wv[0] = ctx->h[0]; wv[1] = ctx->h[1]; 286 | wv[2] = ctx->h[2]; wv[3] = ctx->h[3]; 287 | wv[4] = ctx->h[4]; wv[5] = ctx->h[5]; 288 | wv[6] = ctx->h[6]; wv[7] = ctx->h[7]; 289 | 290 | SHA256_EXP(0,1,2,3,4,5,6,7, 0); SHA256_EXP(7,0,1,2,3,4,5,6, 1); 291 | SHA256_EXP(6,7,0,1,2,3,4,5, 2); SHA256_EXP(5,6,7,0,1,2,3,4, 3); 292 | SHA256_EXP(4,5,6,7,0,1,2,3, 4); SHA256_EXP(3,4,5,6,7,0,1,2, 5); 293 | SHA256_EXP(2,3,4,5,6,7,0,1, 6); SHA256_EXP(1,2,3,4,5,6,7,0, 7); 294 | SHA256_EXP(0,1,2,3,4,5,6,7, 8); SHA256_EXP(7,0,1,2,3,4,5,6, 9); 295 | SHA256_EXP(6,7,0,1,2,3,4,5,10); SHA256_EXP(5,6,7,0,1,2,3,4,11); 296 | SHA256_EXP(4,5,6,7,0,1,2,3,12); SHA256_EXP(3,4,5,6,7,0,1,2,13); 297 | SHA256_EXP(2,3,4,5,6,7,0,1,14); SHA256_EXP(1,2,3,4,5,6,7,0,15); 298 | SHA256_EXP(0,1,2,3,4,5,6,7,16); SHA256_EXP(7,0,1,2,3,4,5,6,17); 299 | SHA256_EXP(6,7,0,1,2,3,4,5,18); SHA256_EXP(5,6,7,0,1,2,3,4,19); 300 | SHA256_EXP(4,5,6,7,0,1,2,3,20); SHA256_EXP(3,4,5,6,7,0,1,2,21); 301 | SHA256_EXP(2,3,4,5,6,7,0,1,22); SHA256_EXP(1,2,3,4,5,6,7,0,23); 302 | SHA256_EXP(0,1,2,3,4,5,6,7,24); SHA256_EXP(7,0,1,2,3,4,5,6,25); 303 | SHA256_EXP(6,7,0,1,2,3,4,5,26); SHA256_EXP(5,6,7,0,1,2,3,4,27); 304 | SHA256_EXP(4,5,6,7,0,1,2,3,28); SHA256_EXP(3,4,5,6,7,0,1,2,29); 305 | SHA256_EXP(2,3,4,5,6,7,0,1,30); SHA256_EXP(1,2,3,4,5,6,7,0,31); 306 | SHA256_EXP(0,1,2,3,4,5,6,7,32); SHA256_EXP(7,0,1,2,3,4,5,6,33); 307 | SHA256_EXP(6,7,0,1,2,3,4,5,34); SHA256_EXP(5,6,7,0,1,2,3,4,35); 308 | SHA256_EXP(4,5,6,7,0,1,2,3,36); SHA256_EXP(3,4,5,6,7,0,1,2,37); 309 | SHA256_EXP(2,3,4,5,6,7,0,1,38); SHA256_EXP(1,2,3,4,5,6,7,0,39); 310 | SHA256_EXP(0,1,2,3,4,5,6,7,40); SHA256_EXP(7,0,1,2,3,4,5,6,41); 311 | SHA256_EXP(6,7,0,1,2,3,4,5,42); SHA256_EXP(5,6,7,0,1,2,3,4,43); 312 | SHA256_EXP(4,5,6,7,0,1,2,3,44); SHA256_EXP(3,4,5,6,7,0,1,2,45); 313 | SHA256_EXP(2,3,4,5,6,7,0,1,46); SHA256_EXP(1,2,3,4,5,6,7,0,47); 314 | SHA256_EXP(0,1,2,3,4,5,6,7,48); SHA256_EXP(7,0,1,2,3,4,5,6,49); 315 | SHA256_EXP(6,7,0,1,2,3,4,5,50); SHA256_EXP(5,6,7,0,1,2,3,4,51); 316 | SHA256_EXP(4,5,6,7,0,1,2,3,52); SHA256_EXP(3,4,5,6,7,0,1,2,53); 317 | SHA256_EXP(2,3,4,5,6,7,0,1,54); SHA256_EXP(1,2,3,4,5,6,7,0,55); 318 | SHA256_EXP(0,1,2,3,4,5,6,7,56); SHA256_EXP(7,0,1,2,3,4,5,6,57); 319 | SHA256_EXP(6,7,0,1,2,3,4,5,58); SHA256_EXP(5,6,7,0,1,2,3,4,59); 320 | SHA256_EXP(4,5,6,7,0,1,2,3,60); SHA256_EXP(3,4,5,6,7,0,1,2,61); 321 | SHA256_EXP(2,3,4,5,6,7,0,1,62); SHA256_EXP(1,2,3,4,5,6,7,0,63); 322 | 323 | ctx->h[0] += wv[0]; ctx->h[1] += wv[1]; 324 | ctx->h[2] += wv[2]; ctx->h[3] += wv[3]; 325 | ctx->h[4] += wv[4]; ctx->h[5] += wv[5]; 326 | ctx->h[6] += wv[6]; ctx->h[7] += wv[7]; 327 | #endif /* !UNROLL_LOOPS */ 328 | } 329 | } 330 | 331 | void sha256(const unsigned char *message, unsigned int len, unsigned char *digest) 332 | { 333 | sha256_ctx ctx; 334 | 335 | sha256_init(&ctx); 336 | sha256_update(&ctx, message, len); 337 | sha256_final(&ctx, digest); 338 | } 339 | 340 | void sha256_init(sha256_ctx *ctx) 341 | { 342 | #ifndef UNROLL_LOOPS 343 | int i; 344 | for (i = 0; i < 8; i++) { 345 | ctx->h[i] = sha256_h0[i]; 346 | } 347 | #else 348 | ctx->h[0] = sha256_h0[0]; ctx->h[1] = sha256_h0[1]; 349 | ctx->h[2] = sha256_h0[2]; ctx->h[3] = sha256_h0[3]; 350 | ctx->h[4] = sha256_h0[4]; ctx->h[5] = sha256_h0[5]; 351 | ctx->h[6] = sha256_h0[6]; ctx->h[7] = sha256_h0[7]; 352 | #endif /* !UNROLL_LOOPS */ 353 | 354 | ctx->len = 0; 355 | ctx->tot_len = 0; 356 | } 357 | 358 | void sha256_update(sha256_ctx *ctx, const unsigned char *message, 359 | unsigned int len) 360 | { 361 | unsigned int block_nb; 362 | unsigned int new_len, rem_len, tmp_len; 363 | const unsigned char *shifted_message; 364 | 365 | tmp_len = SHA256_BLOCK_SIZE - ctx->len; 366 | rem_len = len < tmp_len ? len : tmp_len; 367 | 368 | memcpy(&ctx->block[ctx->len], message, rem_len); 369 | 370 | if (ctx->len + len < SHA256_BLOCK_SIZE) { 371 | ctx->len += len; 372 | return; 373 | } 374 | 375 | new_len = len - rem_len; 376 | block_nb = new_len / SHA256_BLOCK_SIZE; 377 | 378 | shifted_message = message + rem_len; 379 | 380 | sha256_transf(ctx, ctx->block, 1); 381 | sha256_transf(ctx, shifted_message, block_nb); 382 | 383 | rem_len = new_len % SHA256_BLOCK_SIZE; 384 | 385 | memcpy(ctx->block, &shifted_message[block_nb << 6], 386 | rem_len); 387 | 388 | ctx->len = rem_len; 389 | ctx->tot_len += (block_nb + 1) << 6; 390 | } 391 | 392 | void sha256_final(sha256_ctx *ctx, unsigned char *digest) 393 | { 394 | unsigned int block_nb; 395 | unsigned int pm_len; 396 | unsigned int len_b; 397 | 398 | #ifndef UNROLL_LOOPS 399 | int i; 400 | #endif 401 | 402 | block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) 403 | < (ctx->len % SHA256_BLOCK_SIZE))); 404 | 405 | len_b = (ctx->tot_len + ctx->len) << 3; 406 | pm_len = block_nb << 6; 407 | 408 | memset(ctx->block + ctx->len, 0, pm_len - ctx->len); 409 | ctx->block[ctx->len] = 0x80; 410 | UNPACK32(len_b, ctx->block + pm_len - 4); 411 | 412 | sha256_transf(ctx, ctx->block, block_nb); 413 | 414 | #ifndef UNROLL_LOOPS 415 | for (i = 0 ; i < 8; i++) { 416 | UNPACK32(ctx->h[i], &digest[i << 2]); 417 | } 418 | #else 419 | UNPACK32(ctx->h[0], &digest[ 0]); 420 | UNPACK32(ctx->h[1], &digest[ 4]); 421 | UNPACK32(ctx->h[2], &digest[ 8]); 422 | UNPACK32(ctx->h[3], &digest[12]); 423 | UNPACK32(ctx->h[4], &digest[16]); 424 | UNPACK32(ctx->h[5], &digest[20]); 425 | UNPACK32(ctx->h[6], &digest[24]); 426 | UNPACK32(ctx->h[7], &digest[28]); 427 | #endif /* !UNROLL_LOOPS */ 428 | } 429 | 430 | /* SHA-512 functions */ 431 | 432 | static void sha512_transf(sha512_ctx *ctx, const unsigned char *message, 433 | unsigned int block_nb) 434 | { 435 | uint64 w[80]; 436 | uint64 wv[8]; 437 | uint64 t1, t2; 438 | const unsigned char *sub_block; 439 | int i, j; 440 | 441 | for (i = 0; i < (int) block_nb; i++) { 442 | sub_block = message + (i << 7); 443 | 444 | #ifndef UNROLL_LOOPS 445 | for (j = 0; j < 16; j++) { 446 | PACK64(&sub_block[j << 3], &w[j]); 447 | } 448 | 449 | for (j = 16; j < 80; j++) { 450 | SHA512_SCR(j); 451 | } 452 | 453 | for (j = 0; j < 8; j++) { 454 | wv[j] = ctx->h[j]; 455 | } 456 | 457 | for (j = 0; j < 80; j++) { 458 | t1 = wv[7] + SHA512_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) 459 | + sha512_k[j] + w[j]; 460 | t2 = SHA512_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); 461 | wv[7] = wv[6]; 462 | wv[6] = wv[5]; 463 | wv[5] = wv[4]; 464 | wv[4] = wv[3] + t1; 465 | wv[3] = wv[2]; 466 | wv[2] = wv[1]; 467 | wv[1] = wv[0]; 468 | wv[0] = t1 + t2; 469 | } 470 | 471 | for (j = 0; j < 8; j++) { 472 | ctx->h[j] += wv[j]; 473 | } 474 | #else 475 | PACK64(&sub_block[ 0], &w[ 0]); PACK64(&sub_block[ 8], &w[ 1]); 476 | PACK64(&sub_block[ 16], &w[ 2]); PACK64(&sub_block[ 24], &w[ 3]); 477 | PACK64(&sub_block[ 32], &w[ 4]); PACK64(&sub_block[ 40], &w[ 5]); 478 | PACK64(&sub_block[ 48], &w[ 6]); PACK64(&sub_block[ 56], &w[ 7]); 479 | PACK64(&sub_block[ 64], &w[ 8]); PACK64(&sub_block[ 72], &w[ 9]); 480 | PACK64(&sub_block[ 80], &w[10]); PACK64(&sub_block[ 88], &w[11]); 481 | PACK64(&sub_block[ 96], &w[12]); PACK64(&sub_block[104], &w[13]); 482 | PACK64(&sub_block[112], &w[14]); PACK64(&sub_block[120], &w[15]); 483 | 484 | SHA512_SCR(16); SHA512_SCR(17); SHA512_SCR(18); SHA512_SCR(19); 485 | SHA512_SCR(20); SHA512_SCR(21); SHA512_SCR(22); SHA512_SCR(23); 486 | SHA512_SCR(24); SHA512_SCR(25); SHA512_SCR(26); SHA512_SCR(27); 487 | SHA512_SCR(28); SHA512_SCR(29); SHA512_SCR(30); SHA512_SCR(31); 488 | SHA512_SCR(32); SHA512_SCR(33); SHA512_SCR(34); SHA512_SCR(35); 489 | SHA512_SCR(36); SHA512_SCR(37); SHA512_SCR(38); SHA512_SCR(39); 490 | SHA512_SCR(40); SHA512_SCR(41); SHA512_SCR(42); SHA512_SCR(43); 491 | SHA512_SCR(44); SHA512_SCR(45); SHA512_SCR(46); SHA512_SCR(47); 492 | SHA512_SCR(48); SHA512_SCR(49); SHA512_SCR(50); SHA512_SCR(51); 493 | SHA512_SCR(52); SHA512_SCR(53); SHA512_SCR(54); SHA512_SCR(55); 494 | SHA512_SCR(56); SHA512_SCR(57); SHA512_SCR(58); SHA512_SCR(59); 495 | SHA512_SCR(60); SHA512_SCR(61); SHA512_SCR(62); SHA512_SCR(63); 496 | SHA512_SCR(64); SHA512_SCR(65); SHA512_SCR(66); SHA512_SCR(67); 497 | SHA512_SCR(68); SHA512_SCR(69); SHA512_SCR(70); SHA512_SCR(71); 498 | SHA512_SCR(72); SHA512_SCR(73); SHA512_SCR(74); SHA512_SCR(75); 499 | SHA512_SCR(76); SHA512_SCR(77); SHA512_SCR(78); SHA512_SCR(79); 500 | 501 | wv[0] = ctx->h[0]; wv[1] = ctx->h[1]; 502 | wv[2] = ctx->h[2]; wv[3] = ctx->h[3]; 503 | wv[4] = ctx->h[4]; wv[5] = ctx->h[5]; 504 | wv[6] = ctx->h[6]; wv[7] = ctx->h[7]; 505 | 506 | j = 0; 507 | 508 | do { 509 | SHA512_EXP(0,1,2,3,4,5,6,7,j); j++; 510 | SHA512_EXP(7,0,1,2,3,4,5,6,j); j++; 511 | SHA512_EXP(6,7,0,1,2,3,4,5,j); j++; 512 | SHA512_EXP(5,6,7,0,1,2,3,4,j); j++; 513 | SHA512_EXP(4,5,6,7,0,1,2,3,j); j++; 514 | SHA512_EXP(3,4,5,6,7,0,1,2,j); j++; 515 | SHA512_EXP(2,3,4,5,6,7,0,1,j); j++; 516 | SHA512_EXP(1,2,3,4,5,6,7,0,j); j++; 517 | } while (j < 80); 518 | 519 | ctx->h[0] += wv[0]; ctx->h[1] += wv[1]; 520 | ctx->h[2] += wv[2]; ctx->h[3] += wv[3]; 521 | ctx->h[4] += wv[4]; ctx->h[5] += wv[5]; 522 | ctx->h[6] += wv[6]; ctx->h[7] += wv[7]; 523 | #endif /* !UNROLL_LOOPS */ 524 | } 525 | } 526 | 527 | void sha512(const unsigned char *message, unsigned int len, 528 | unsigned char *digest) 529 | { 530 | sha512_ctx ctx; 531 | 532 | sha512_init(&ctx); 533 | sha512_update(&ctx, message, len); 534 | sha512_final(&ctx, digest); 535 | } 536 | 537 | void sha512_init(sha512_ctx *ctx) 538 | { 539 | #ifndef UNROLL_LOOPS 540 | int i; 541 | for (i = 0; i < 8; i++) { 542 | ctx->h[i] = sha512_h0[i]; 543 | } 544 | #else 545 | ctx->h[0] = sha512_h0[0]; ctx->h[1] = sha512_h0[1]; 546 | ctx->h[2] = sha512_h0[2]; ctx->h[3] = sha512_h0[3]; 547 | ctx->h[4] = sha512_h0[4]; ctx->h[5] = sha512_h0[5]; 548 | ctx->h[6] = sha512_h0[6]; ctx->h[7] = sha512_h0[7]; 549 | #endif /* !UNROLL_LOOPS */ 550 | 551 | ctx->len = 0; 552 | ctx->tot_len = 0; 553 | } 554 | 555 | void sha512_update(sha512_ctx *ctx, const unsigned char *message, 556 | unsigned int len) 557 | { 558 | unsigned int block_nb; 559 | unsigned int new_len, rem_len, tmp_len; 560 | const unsigned char *shifted_message; 561 | 562 | tmp_len = SHA512_BLOCK_SIZE - ctx->len; 563 | rem_len = len < tmp_len ? len : tmp_len; 564 | 565 | memcpy(&ctx->block[ctx->len], message, rem_len); 566 | 567 | if (ctx->len + len < SHA512_BLOCK_SIZE) { 568 | ctx->len += len; 569 | return; 570 | } 571 | 572 | new_len = len - rem_len; 573 | block_nb = new_len / SHA512_BLOCK_SIZE; 574 | 575 | shifted_message = message + rem_len; 576 | 577 | sha512_transf(ctx, ctx->block, 1); 578 | sha512_transf(ctx, shifted_message, block_nb); 579 | 580 | rem_len = new_len % SHA512_BLOCK_SIZE; 581 | 582 | memcpy(ctx->block, &shifted_message[block_nb << 7], 583 | rem_len); 584 | 585 | ctx->len = rem_len; 586 | ctx->tot_len += (block_nb + 1) << 7; 587 | } 588 | 589 | void sha512_final(sha512_ctx *ctx, unsigned char *digest) 590 | { 591 | unsigned int block_nb; 592 | unsigned int pm_len; 593 | unsigned int len_b; 594 | 595 | #ifndef UNROLL_LOOPS 596 | int i; 597 | #endif 598 | 599 | block_nb = 1 + ((SHA512_BLOCK_SIZE - 17) 600 | < (ctx->len % SHA512_BLOCK_SIZE)); 601 | 602 | len_b = (ctx->tot_len + ctx->len) << 3; 603 | pm_len = block_nb << 7; 604 | 605 | memset(ctx->block + ctx->len, 0, pm_len - ctx->len); 606 | ctx->block[ctx->len] = 0x80; 607 | UNPACK32(len_b, ctx->block + pm_len - 4); 608 | 609 | sha512_transf(ctx, ctx->block, block_nb); 610 | 611 | #ifndef UNROLL_LOOPS 612 | for (i = 0 ; i < 8; i++) { 613 | UNPACK64(ctx->h[i], &digest[i << 3]); 614 | } 615 | #else 616 | UNPACK64(ctx->h[0], &digest[ 0]); 617 | UNPACK64(ctx->h[1], &digest[ 8]); 618 | UNPACK64(ctx->h[2], &digest[16]); 619 | UNPACK64(ctx->h[3], &digest[24]); 620 | UNPACK64(ctx->h[4], &digest[32]); 621 | UNPACK64(ctx->h[5], &digest[40]); 622 | UNPACK64(ctx->h[6], &digest[48]); 623 | UNPACK64(ctx->h[7], &digest[56]); 624 | #endif /* !UNROLL_LOOPS */ 625 | } 626 | 627 | /* SHA-384 functions */ 628 | 629 | void sha384(const unsigned char *message, unsigned int len, 630 | unsigned char *digest) 631 | { 632 | sha384_ctx ctx; 633 | 634 | sha384_init(&ctx); 635 | sha384_update(&ctx, message, len); 636 | sha384_final(&ctx, digest); 637 | } 638 | 639 | void sha384_init(sha384_ctx *ctx) 640 | { 641 | #ifndef UNROLL_LOOPS 642 | int i; 643 | for (i = 0; i < 8; i++) { 644 | ctx->h[i] = sha384_h0[i]; 645 | } 646 | #else 647 | ctx->h[0] = sha384_h0[0]; ctx->h[1] = sha384_h0[1]; 648 | ctx->h[2] = sha384_h0[2]; ctx->h[3] = sha384_h0[3]; 649 | ctx->h[4] = sha384_h0[4]; ctx->h[5] = sha384_h0[5]; 650 | ctx->h[6] = sha384_h0[6]; ctx->h[7] = sha384_h0[7]; 651 | #endif /* !UNROLL_LOOPS */ 652 | 653 | ctx->len = 0; 654 | ctx->tot_len = 0; 655 | } 656 | 657 | void sha384_update(sha384_ctx *ctx, const unsigned char *message, 658 | unsigned int len) 659 | { 660 | unsigned int block_nb; 661 | unsigned int new_len, rem_len, tmp_len; 662 | const unsigned char *shifted_message; 663 | 664 | tmp_len = SHA384_BLOCK_SIZE - ctx->len; 665 | rem_len = len < tmp_len ? len : tmp_len; 666 | 667 | memcpy(&ctx->block[ctx->len], message, rem_len); 668 | 669 | if (ctx->len + len < SHA384_BLOCK_SIZE) { 670 | ctx->len += len; 671 | return; 672 | } 673 | 674 | new_len = len - rem_len; 675 | block_nb = new_len / SHA384_BLOCK_SIZE; 676 | 677 | shifted_message = message + rem_len; 678 | 679 | sha512_transf(ctx, ctx->block, 1); 680 | sha512_transf(ctx, shifted_message, block_nb); 681 | 682 | rem_len = new_len % SHA384_BLOCK_SIZE; 683 | 684 | memcpy(ctx->block, &shifted_message[block_nb << 7], 685 | rem_len); 686 | 687 | ctx->len = rem_len; 688 | ctx->tot_len += (block_nb + 1) << 7; 689 | } 690 | 691 | void sha384_final(sha384_ctx *ctx, unsigned char *digest) 692 | { 693 | unsigned int block_nb; 694 | unsigned int pm_len; 695 | unsigned int len_b; 696 | 697 | #ifndef UNROLL_LOOPS 698 | int i; 699 | #endif 700 | 701 | block_nb = (1 + ((SHA384_BLOCK_SIZE - 17) 702 | < (ctx->len % SHA384_BLOCK_SIZE))); 703 | 704 | len_b = (ctx->tot_len + ctx->len) << 3; 705 | pm_len = block_nb << 7; 706 | 707 | memset(ctx->block + ctx->len, 0, pm_len - ctx->len); 708 | ctx->block[ctx->len] = 0x80; 709 | UNPACK32(len_b, ctx->block + pm_len - 4); 710 | 711 | sha512_transf(ctx, ctx->block, block_nb); 712 | 713 | #ifndef UNROLL_LOOPS 714 | for (i = 0 ; i < 6; i++) { 715 | UNPACK64(ctx->h[i], &digest[i << 3]); 716 | } 717 | #else 718 | UNPACK64(ctx->h[0], &digest[ 0]); 719 | UNPACK64(ctx->h[1], &digest[ 8]); 720 | UNPACK64(ctx->h[2], &digest[16]); 721 | UNPACK64(ctx->h[3], &digest[24]); 722 | UNPACK64(ctx->h[4], &digest[32]); 723 | UNPACK64(ctx->h[5], &digest[40]); 724 | #endif /* !UNROLL_LOOPS */ 725 | } 726 | 727 | /* SHA-224 functions */ 728 | 729 | void sha224(const unsigned char *message, unsigned int len, 730 | unsigned char *digest) 731 | { 732 | sha224_ctx ctx; 733 | 734 | sha224_init(&ctx); 735 | sha224_update(&ctx, message, len); 736 | sha224_final(&ctx, digest); 737 | } 738 | 739 | void sha224_init(sha224_ctx *ctx) 740 | { 741 | #ifndef UNROLL_LOOPS 742 | int i; 743 | for (i = 0; i < 8; i++) { 744 | ctx->h[i] = sha224_h0[i]; 745 | } 746 | #else 747 | ctx->h[0] = sha224_h0[0]; ctx->h[1] = sha224_h0[1]; 748 | ctx->h[2] = sha224_h0[2]; ctx->h[3] = sha224_h0[3]; 749 | ctx->h[4] = sha224_h0[4]; ctx->h[5] = sha224_h0[5]; 750 | ctx->h[6] = sha224_h0[6]; ctx->h[7] = sha224_h0[7]; 751 | #endif /* !UNROLL_LOOPS */ 752 | 753 | ctx->len = 0; 754 | ctx->tot_len = 0; 755 | } 756 | 757 | void sha224_update(sha224_ctx *ctx, const unsigned char *message, 758 | unsigned int len) 759 | { 760 | unsigned int block_nb; 761 | unsigned int new_len, rem_len, tmp_len; 762 | const unsigned char *shifted_message; 763 | 764 | tmp_len = SHA224_BLOCK_SIZE - ctx->len; 765 | rem_len = len < tmp_len ? len : tmp_len; 766 | 767 | memcpy(&ctx->block[ctx->len], message, rem_len); 768 | 769 | if (ctx->len + len < SHA224_BLOCK_SIZE) { 770 | ctx->len += len; 771 | return; 772 | } 773 | 774 | new_len = len - rem_len; 775 | block_nb = new_len / SHA224_BLOCK_SIZE; 776 | 777 | shifted_message = message + rem_len; 778 | 779 | sha256_transf(ctx, ctx->block, 1); 780 | sha256_transf(ctx, shifted_message, block_nb); 781 | 782 | rem_len = new_len % SHA224_BLOCK_SIZE; 783 | 784 | memcpy(ctx->block, &shifted_message[block_nb << 6], 785 | rem_len); 786 | 787 | ctx->len = rem_len; 788 | ctx->tot_len += (block_nb + 1) << 6; 789 | } 790 | 791 | void sha224_final(sha224_ctx *ctx, unsigned char *digest) 792 | { 793 | unsigned int block_nb; 794 | unsigned int pm_len; 795 | unsigned int len_b; 796 | 797 | #ifndef UNROLL_LOOPS 798 | int i; 799 | #endif 800 | 801 | block_nb = (1 + ((SHA224_BLOCK_SIZE - 9) 802 | < (ctx->len % SHA224_BLOCK_SIZE))); 803 | 804 | len_b = (ctx->tot_len + ctx->len) << 3; 805 | pm_len = block_nb << 6; 806 | 807 | memset(ctx->block + ctx->len, 0, pm_len - ctx->len); 808 | ctx->block[ctx->len] = 0x80; 809 | UNPACK32(len_b, ctx->block + pm_len - 4); 810 | 811 | sha256_transf(ctx, ctx->block, block_nb); 812 | 813 | #ifndef UNROLL_LOOPS 814 | for (i = 0 ; i < 7; i++) { 815 | UNPACK32(ctx->h[i], &digest[i << 2]); 816 | } 817 | #else 818 | UNPACK32(ctx->h[0], &digest[ 0]); 819 | UNPACK32(ctx->h[1], &digest[ 4]); 820 | UNPACK32(ctx->h[2], &digest[ 8]); 821 | UNPACK32(ctx->h[3], &digest[12]); 822 | UNPACK32(ctx->h[4], &digest[16]); 823 | UNPACK32(ctx->h[5], &digest[20]); 824 | UNPACK32(ctx->h[6], &digest[24]); 825 | #endif /* !UNROLL_LOOPS */ 826 | } 827 | 828 | #ifdef TEST_VECTORS 829 | 830 | /* FIPS 180-2 Validation tests */ 831 | 832 | #include 833 | #include 834 | 835 | void test(const char *vector, unsigned char *digest, 836 | unsigned int digest_size) 837 | { 838 | char output[2 * SHA512_DIGEST_SIZE + 1]; 839 | int i; 840 | 841 | output[2 * digest_size] = '\0'; 842 | 843 | for (i = 0; i < (int) digest_size ; i++) { 844 | sprintf(output + 2 * i, "%02x", digest[i]); 845 | } 846 | 847 | printf("H: %s\n", output); 848 | if (strcmp(vector, output)) { 849 | fprintf(stderr, "Test failed.\n"); 850 | exit(EXIT_FAILURE); 851 | } 852 | } 853 | 854 | int main(void) 855 | { 856 | static const char *vectors[4][3] = 857 | { /* SHA-224 */ 858 | { 859 | "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", 860 | "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525", 861 | "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67", 862 | }, 863 | /* SHA-256 */ 864 | { 865 | "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", 866 | "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", 867 | "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0", 868 | }, 869 | /* SHA-384 */ 870 | { 871 | "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed" 872 | "8086072ba1e7cc2358baeca134c825a7", 873 | "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712" 874 | "fcc7c71a557e2db966c3e9fa91746039", 875 | "9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b" 876 | "07b8b3dc38ecc4ebae97ddd87f3d8985", 877 | }, 878 | /* SHA-512 */ 879 | { 880 | "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" 881 | "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", 882 | "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018" 883 | "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909", 884 | "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb" 885 | "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b" 886 | } 887 | }; 888 | 889 | static const char message1[] = "abc"; 890 | static const char message2a[] = "abcdbcdecdefdefgefghfghighijhi" 891 | "jkijkljklmklmnlmnomnopnopq"; 892 | static const char message2b[] = "abcdefghbcdefghicdefghijdefghijkefghij" 893 | "klfghijklmghijklmnhijklmnoijklmnopjklm" 894 | "nopqklmnopqrlmnopqrsmnopqrstnopqrstu"; 895 | unsigned char *message3; 896 | unsigned int message3_len = 1000000; 897 | unsigned char digest[SHA512_DIGEST_SIZE]; 898 | 899 | message3 = malloc(message3_len); 900 | if (message3 == NULL) { 901 | fprintf(stderr, "Can't allocate memory\n"); 902 | return -1; 903 | } 904 | memset(message3, 'a', message3_len); 905 | 906 | printf("SHA-2 FIPS 180-2 Validation tests\n\n"); 907 | printf("SHA-224 Test vectors\n"); 908 | 909 | sha224((const unsigned char *) message1, strlen(message1), digest); 910 | test(vectors[0][0], digest, SHA224_DIGEST_SIZE); 911 | sha224((const unsigned char *) message2a, strlen(message2a), digest); 912 | test(vectors[0][1], digest, SHA224_DIGEST_SIZE); 913 | sha224(message3, message3_len, digest); 914 | test(vectors[0][2], digest, SHA224_DIGEST_SIZE); 915 | printf("\n"); 916 | 917 | printf("SHA-256 Test vectors\n"); 918 | 919 | sha256((const unsigned char *) message1, strlen(message1), digest); 920 | test(vectors[1][0], digest, SHA256_DIGEST_SIZE); 921 | sha256((const unsigned char *) message2a, strlen(message2a), digest); 922 | test(vectors[1][1], digest, SHA256_DIGEST_SIZE); 923 | sha256(message3, message3_len, digest); 924 | test(vectors[1][2], digest, SHA256_DIGEST_SIZE); 925 | printf("\n"); 926 | 927 | printf("SHA-384 Test vectors\n"); 928 | 929 | sha384((const unsigned char *) message1, strlen(message1), digest); 930 | test(vectors[2][0], digest, SHA384_DIGEST_SIZE); 931 | sha384((const unsigned char *)message2b, strlen(message2b), digest); 932 | test(vectors[2][1], digest, SHA384_DIGEST_SIZE); 933 | sha384(message3, message3_len, digest); 934 | test(vectors[2][2], digest, SHA384_DIGEST_SIZE); 935 | printf("\n"); 936 | 937 | printf("SHA-512 Test vectors\n"); 938 | 939 | sha512((const unsigned char *) message1, strlen(message1), digest); 940 | test(vectors[3][0], digest, SHA512_DIGEST_SIZE); 941 | sha512((const unsigned char *) message2b, strlen(message2b), digest); 942 | test(vectors[3][1], digest, SHA512_DIGEST_SIZE); 943 | sha512(message3, message3_len, digest); 944 | test(vectors[3][2], digest, SHA512_DIGEST_SIZE); 945 | printf("\n"); 946 | 947 | printf("All tests passed.\n"); 948 | 949 | return 0; 950 | } 951 | 952 | #endif /* TEST_VECTORS */ 953 | 954 | -------------------------------------------------------------------------------- /lsmmc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) ST-Ericsson SA 2010-2011 3 | * Author: Sebastian Rasmussen 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following 15 | * disclaimer in the documentation and/or other materials 16 | * provided with the distribution. 17 | * 3. Neither the name of the ST-Ericsson SA nor the names of its 18 | * contributors may be used to endorse or promote products 19 | * derived from this software without specific prior written 20 | * permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 33 | * OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #include "mmc.h" 50 | #include "mmc_cmds.h" 51 | 52 | #define MASKTOBIT0(high) \ 53 | ((high >= 0) ? ((1ull << ((high) + 1ull)) - 1ull) : 0ull) 54 | #define MASK(high, low) (MASKTOBIT0(high) & ~MASKTOBIT0(low - 1)) 55 | #define BITS(value, high, low) (((value) & MASK((high), (low))) >> (low)) 56 | #define IDS_MAX 256 57 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 58 | 59 | enum bus_type { 60 | MMC = 1, 61 | SD, 62 | }; 63 | 64 | struct config { 65 | char *dir; 66 | bool verbose; 67 | 68 | enum bus_type bus; 69 | char *reg; 70 | }; 71 | 72 | enum REG_TYPE { 73 | CID = 0, 74 | CSD, 75 | SCR, 76 | }; 77 | 78 | struct ids_database { 79 | int id; 80 | char *manufacturer; 81 | }; 82 | 83 | static struct ids_database sd_database[] = { 84 | { 85 | .id = 0x01, 86 | .manufacturer = "Panasonic", 87 | }, 88 | { 89 | .id = 0x02, 90 | .manufacturer = "Toshiba/Kingston/Viking", 91 | }, 92 | { 93 | .id = 0x03, 94 | .manufacturer = "SanDisk", 95 | }, 96 | { 97 | .id = 0x08, 98 | .manufacturer = "Silicon Power", 99 | }, 100 | { 101 | .id = 0x18, 102 | .manufacturer = "Infineon", 103 | }, 104 | { 105 | .id = 0x1b, 106 | .manufacturer = "Transcend/Samsung", 107 | }, 108 | { 109 | .id = 0x1c, 110 | .manufacturer = "Transcend", 111 | }, 112 | { 113 | .id = 0x1d, 114 | .manufacturer = "Corsair/AData", 115 | }, 116 | { 117 | .id = 0x1e, 118 | .manufacturer = "Transcend", 119 | }, 120 | { 121 | .id = 0x1f, 122 | .manufacturer = "Kingston", 123 | }, 124 | { 125 | .id = 0x27, 126 | .manufacturer = "Delkin/Phison", 127 | }, 128 | { 129 | .id = 0x28, 130 | .manufacturer = "Lexar", 131 | }, 132 | { 133 | .id = 0x30, 134 | .manufacturer = "SanDisk", 135 | }, 136 | { 137 | .id = 0x31, 138 | .manufacturer = "Silicon Power", 139 | }, 140 | { 141 | .id = 0x33, 142 | .manufacturer = "STMicroelectronics", 143 | }, 144 | { 145 | .id = 0x41, 146 | .manufacturer = "Kingston", 147 | }, 148 | { 149 | .id = 0x6f, 150 | .manufacturer = "STMicroelectronics", 151 | }, 152 | { 153 | .id = 0x74, 154 | .manufacturer = "Transcend", 155 | }, 156 | { 157 | .id = 0x76, 158 | .manufacturer = "Patriot", 159 | }, 160 | { 161 | .id = 0x82, 162 | .manufacturer = "Gobe/Sony", 163 | }, 164 | { 165 | .id = 0x89, 166 | .manufacturer = "Unknown", 167 | }, 168 | }; 169 | 170 | static struct ids_database mmc_database[] = { 171 | { 172 | .id = 0x00, 173 | .manufacturer = "SanDisk", 174 | }, 175 | { 176 | .id = 0x02, 177 | .manufacturer = "Kingston/SanDisk", 178 | }, 179 | { 180 | .id = 0x03, 181 | .manufacturer = "Toshiba", 182 | }, 183 | { 184 | .id = 0x05, 185 | .manufacturer = "Unknown", 186 | }, 187 | { 188 | .id = 0x06, 189 | .manufacturer = "Unknown", 190 | }, 191 | { 192 | .id = 0x11, 193 | .manufacturer = "Toshiba", 194 | }, 195 | { 196 | .id = 0x13, 197 | .manufacturer = "Micron", 198 | }, 199 | { 200 | .id = 0x15, 201 | .manufacturer = "Samsung/SanDisk/LG", 202 | }, 203 | { 204 | .id = 0x37, 205 | .manufacturer = "KingMax", 206 | }, 207 | { 208 | .id = 0x44, 209 | .manufacturer = "ATP", 210 | }, 211 | { 212 | .id = 0x45, 213 | .manufacturer = "SanDisk Corporation", 214 | }, 215 | { 216 | .id = 0x2c, 217 | .manufacturer = "Kingston", 218 | }, 219 | { 220 | .id = 0x70, 221 | .manufacturer = "Kingston", 222 | }, 223 | { 224 | .id = 0xfe, 225 | .manufacturer = "Micron", 226 | }, 227 | }; 228 | 229 | /* Command line parsing functions */ 230 | static void usage(char *progname) 231 | { 232 | printf("Usage: %s [-h] [-v] [-b bus_type] [-r register] \n", progname); 233 | printf("\n"); 234 | printf("Options:\n"); 235 | printf("\t-b\t bus type. Either sd or mmc. if specified, register value must be given.\n"); 236 | printf("\t-r\t The register content. if specified no need for device path\n"); 237 | printf("\t-h\tShow this help.\n"); 238 | printf("\t-v\tEnable verbose mode.\n"); 239 | } 240 | 241 | static void to_lowercase(char *str) 242 | { 243 | for (; *str; ++str) 244 | *str = tolower((unsigned char)*str); 245 | } 246 | 247 | static int parse_opts(int argc, char **argv, struct config *config) 248 | { 249 | int c; 250 | bool bus_given = false; 251 | bool reg_given = false; 252 | 253 | while ((c = getopt(argc, argv, "hvb:r:")) != -1) { 254 | switch (c) { 255 | case 'h': 256 | usage(argv[0]); 257 | return -1; 258 | case 'v': 259 | config->verbose = true; 260 | break; 261 | case 'b': 262 | to_lowercase(optarg); 263 | if (strcmp(optarg, "mmc") == 0) { 264 | config->bus = MMC; 265 | } else if (strcmp(optarg, "sd") == 0) { 266 | config->bus = SD; 267 | } else { 268 | fprintf(stderr, "Unknown bus type '%s'.\n\n", optarg); 269 | usage(argv[0]); 270 | return -1; 271 | } 272 | bus_given = true; 273 | 274 | break; 275 | case 'r': 276 | config->reg = strdup(optarg); 277 | reg_given = true; 278 | 279 | break; 280 | case '?': 281 | fprintf(stderr, 282 | "Unknown option '%c' encountered.\n\n", c); 283 | usage(argv[0]); 284 | return -1; 285 | case ':': 286 | fprintf(stderr, 287 | "Argument for option '%c' missing.\n\n", c); 288 | usage(argv[0]); 289 | return -1; 290 | default: 291 | fprintf(stderr, 292 | "Unimplemented option '%c' encountered.\n", c); 293 | break; 294 | } 295 | } 296 | 297 | if (bus_given != reg_given) { 298 | fprintf(stderr, "Both bus type and register must be provided together.\n\n"); 299 | usage(argv[0]); 300 | return -1; 301 | } 302 | 303 | if (reg_given) { 304 | if (optind < argc) { 305 | fprintf(stderr, "Either register or directory, not both.\n\n"); 306 | usage(argv[0]); 307 | return -1; 308 | } 309 | } else { 310 | if (optind >= argc) { 311 | fprintf(stderr, "Expected mmc directory arguments.\n\n"); 312 | usage(argv[0]); 313 | return -1; 314 | } 315 | 316 | config->dir = strdup(argv[optind]); 317 | } 318 | 319 | return 0; 320 | } 321 | 322 | static char *get_manufacturer(struct config *config, unsigned int manid) 323 | { 324 | struct ids_database *db; 325 | unsigned int ids_cnt; 326 | int i; 327 | 328 | if (config->bus == MMC) { 329 | db = mmc_database; 330 | ids_cnt = ARRAY_SIZE(mmc_database); 331 | } else { 332 | db = sd_database; 333 | ids_cnt = ARRAY_SIZE(sd_database); 334 | } 335 | 336 | for (i = 0; i < ids_cnt; i++) { 337 | if (db[i].id == manid) 338 | return db[i].manufacturer; 339 | } 340 | 341 | return NULL; 342 | } 343 | 344 | /* MMC/SD file parsing functions */ 345 | static char *read_file(char *name) 346 | { 347 | char line[4096]; 348 | char *preparsed, *start = line; 349 | int len; 350 | FILE *f; 351 | 352 | f = fopen(name, "r"); 353 | if (!f) { 354 | fprintf(stderr, "Could not open MMC/SD file '%s'.\n", name); 355 | return NULL; 356 | } 357 | 358 | preparsed = fgets(line, sizeof(line), f); 359 | if (!preparsed) { 360 | if (ferror(f)) 361 | fprintf(stderr, "Could not read MMC/SD file '%s'.\n", 362 | name); 363 | else 364 | fprintf(stderr, 365 | "Could not read data from MMC/SD file '%s'.\n", 366 | name); 367 | 368 | if (fclose(f)) 369 | fprintf(stderr, "Could not close MMC/SD file '%s'.\n", 370 | name); 371 | return NULL; 372 | } 373 | 374 | if (fclose(f)) { 375 | fprintf(stderr, "Could not close MMC/SD file '%s'.\n", name); 376 | return NULL; 377 | } 378 | 379 | line[sizeof(line) - 1] = '\0'; 380 | len = strlen(line); 381 | 382 | while (len > 0 && isspace(line[len - 1])) 383 | len--; 384 | 385 | while (len > 0 && isspace(*start)) { 386 | start++; 387 | len--; 388 | } 389 | 390 | start[len] = '\0'; 391 | return strdup(start); 392 | } 393 | 394 | /* Hexadecimal string parsing functions */ 395 | static char *to_binstr(char *hexstr) 396 | { 397 | char *bindigits[] = { 398 | "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", 399 | "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111", 400 | }; 401 | char *binstr, *tail; 402 | 403 | binstr = calloc(strlen(hexstr) * 4 + 1, sizeof(char)); 404 | if (!binstr) 405 | return NULL; 406 | 407 | tail = binstr; 408 | 409 | while (hexstr && *hexstr != '\0') { 410 | if (!isxdigit(*hexstr)) { 411 | free(binstr); 412 | return NULL; 413 | } 414 | 415 | if (isdigit(*hexstr)) 416 | strcat(tail, bindigits[*hexstr - '0']); 417 | else if (islower(*hexstr)) 418 | strcat(tail, bindigits[*hexstr - 'a' + 10]); 419 | else 420 | strcat(tail, bindigits[*hexstr - 'A' + 10]); 421 | 422 | hexstr++; 423 | tail += 4; 424 | } 425 | 426 | return binstr; 427 | } 428 | 429 | static void bin_to_unsigned(unsigned int *u, char *binstr, int width) 430 | { 431 | *u = 0; 432 | assert(width <= 32); 433 | 434 | while (binstr && *binstr != '\0' && width > 0) { 435 | *u <<= 1; 436 | *u |= *binstr == '0' ? 0 : 1; 437 | 438 | binstr++; 439 | width--; 440 | } 441 | } 442 | 443 | static void bin_to_ascii(char *a, char *binstr, int width) 444 | { 445 | assert(width % 8 == 0); 446 | *a = '\0'; 447 | 448 | while (binstr && *binstr != '\0' && width > 0) { 449 | unsigned int u; 450 | char c[2] = { '\0', '\0' }; 451 | char *s = &c[0]; 452 | 453 | bin_to_unsigned(&u, binstr, 8); 454 | c[0] = u; 455 | 456 | strcat(a, s); 457 | binstr += 8; 458 | width -= 8; 459 | } 460 | } 461 | 462 | static void parse_bin(char *hexstr, char *fmt, ...) 463 | { 464 | va_list args; 465 | char *origstr; 466 | char *binstr; 467 | unsigned long width = 0; 468 | 469 | binstr = to_binstr(hexstr); 470 | origstr = binstr; 471 | 472 | va_start(args, fmt); 473 | 474 | while (binstr && fmt && *fmt != '\0') { 475 | if (isdigit(*fmt)) { 476 | char *rest; 477 | 478 | errno = 0; 479 | width = strtoul(fmt, &rest, 10); 480 | if (width == ULONG_MAX && errno != 0) 481 | fprintf(stderr, "strtoul()"); 482 | fmt = rest; 483 | } else if (*fmt == 'u') { 484 | unsigned int *u = va_arg(args, unsigned int *); 485 | 486 | if (u) 487 | bin_to_unsigned(u, binstr, width); 488 | binstr += width; 489 | width = 0; 490 | fmt++; 491 | } else if (*fmt == 'r') { 492 | binstr += width; 493 | width = 0; 494 | fmt++; 495 | } else if (*fmt == 'a') { 496 | char *c = va_arg(args, char *); 497 | 498 | if (c) 499 | bin_to_ascii(c, binstr, width); 500 | binstr += width; 501 | width = 0; 502 | fmt++; 503 | } else { 504 | fmt++; 505 | } 506 | } 507 | 508 | va_end(args); 509 | free(origstr); 510 | } 511 | 512 | /* MMC/SD information parsing functions */ 513 | static void print_sd_cid(struct config *config, char *cid) 514 | { 515 | static const char *months[] = { 516 | "jan", "feb", "mar", "apr", "may", "jun", 517 | "jul", "aug", "sep", "oct", "nov", "dec", 518 | "invalid0", "invalid1", "invalid2", "invalid3", 519 | }; 520 | unsigned int mid; 521 | char oid[3]; 522 | char pnm[6]; 523 | unsigned int prv_major; 524 | unsigned int prv_minor; 525 | unsigned int psn; 526 | unsigned int mdt_month; 527 | unsigned int mdt_year; 528 | unsigned int crc; 529 | char *manufacturer = NULL; 530 | 531 | parse_bin(cid, "8u16a40a4u4u32u4r8u4u7u1r", 532 | &mid, &oid[0], &pnm[0], &prv_major, &prv_minor, &psn, 533 | &mdt_year, &mdt_month, &crc); 534 | 535 | oid[2] = '\0'; 536 | pnm[5] = '\0'; 537 | 538 | manufacturer = get_manufacturer(config, mid); 539 | 540 | if (config->verbose) { 541 | printf("======SD/CID======\n"); 542 | 543 | printf("\tMID: 0x%02x (", mid); 544 | if (manufacturer) 545 | printf("%s)\n", manufacturer); 546 | else 547 | printf("Unlisted)\n"); 548 | 549 | printf("\tOID: %s\n", oid); 550 | printf("\tPNM: %s\n", pnm); 551 | printf("\tPRV: 0x%01x%01x ", prv_major, prv_minor); 552 | printf("(%u.%u)\n", prv_major, prv_minor); 553 | printf("\tPSN: 0x%08x\n", psn); 554 | printf("\tMDT: 0x%02x%01x %u %s\n", mdt_year, mdt_month, 555 | 2000 + mdt_year, months[mdt_month]); 556 | printf("\tCRC: 0x%02x\n", crc); 557 | } else { 558 | if (manufacturer) 559 | printf("manufacturer: '%s' '%s'\n", 560 | manufacturer, oid); 561 | else 562 | printf("manufacturer: 'Unlisted' '%s'\n", oid); 563 | 564 | printf("product: '%s' %u.%u\n", pnm, prv_major, prv_minor); 565 | printf("serial: 0x%08x\n", psn); 566 | printf("manufacturing date: %u %s\n", 2000 + mdt_year, 567 | months[mdt_month]); 568 | } 569 | } 570 | 571 | static void print_mmc_cid(struct config *config, char *cid) 572 | { 573 | static const char *months[] = { 574 | "jan", "feb", "mar", "apr", "may", "jun", 575 | "jul", "aug", "sep", "oct", "nov", "dec", 576 | "invalid0", "invalid1", "invalid2", "invalid3", 577 | }; 578 | unsigned int mid; 579 | unsigned int cbx; 580 | unsigned int oid; 581 | char pnm[7]; 582 | unsigned int prv_major; 583 | unsigned int prv_minor; 584 | unsigned int psn; 585 | unsigned int mdt_month; 586 | unsigned int mdt_year; 587 | unsigned int crc; 588 | char *manufacturer = NULL; 589 | 590 | parse_bin(cid, "8u6r2u8u48a4u4u32u4u4u7u1r", 591 | &mid, &cbx, &oid, &pnm[0], &prv_major, &prv_minor, &psn, 592 | &mdt_year, &mdt_month, &crc); 593 | 594 | pnm[6] = '\0'; 595 | 596 | manufacturer = get_manufacturer(config, mid); 597 | 598 | if (config->verbose) { 599 | printf("======MMC/CID======\n"); 600 | 601 | printf("\tMID: 0x%02x (", mid); 602 | if (manufacturer) 603 | printf("%s)\n", manufacturer); 604 | else 605 | printf("Unlisted)\n"); 606 | 607 | printf("\tCBX: 0x%01x (", cbx); 608 | switch (cbx) { 609 | case 0: 610 | printf("card)\n"); 611 | break; 612 | case 1: 613 | printf("BGA)\n"); 614 | break; 615 | case 2: 616 | printf("PoP)\n"); 617 | break; 618 | case 3: 619 | printf("reserved)\n"); 620 | break; 621 | } 622 | 623 | printf("\tOID: 0x%01x\n", oid); 624 | printf("\tPNM: %s\n", pnm); 625 | printf("\tPRV: 0x%01x%01x ", prv_major, prv_minor); 626 | printf("(%u.%u)\n", prv_major, prv_minor); 627 | printf("\tPSN: 0x%08x\n", psn); 628 | printf("\tMDT: 0x%01x%01x %u %s\n", mdt_month, mdt_year, 629 | 1997 + mdt_year, months[mdt_month]); 630 | printf("\tCRC: 0x%02x\n", crc); 631 | } else { 632 | if (manufacturer) 633 | printf("manufacturer: 0x%02x (%s) oid: 0x%01x\n", 634 | mid, manufacturer, oid); 635 | else 636 | printf("manufacturer: 0x%02x (Unlisted) oid: 0x%01x\n", mid, oid); 637 | 638 | printf("product: '%s' %u.%u\n", pnm, prv_major, prv_minor); 639 | printf("serial: 0x%08x\n", psn); 640 | printf("manufacturing date: %u %s\n", 1997 + mdt_year, 641 | months[mdt_month]); 642 | } 643 | } 644 | 645 | static void print_sd_csd(struct config *config, char *csd) 646 | { 647 | unsigned int csd_structure; 648 | unsigned int taac_timevalue; 649 | unsigned int taac_timeunit; 650 | unsigned int nsac; 651 | unsigned int tran_speed_timevalue; 652 | unsigned int tran_speed_transferrateunit; 653 | unsigned int ccc; 654 | unsigned int read_bl_len; 655 | unsigned int read_bl_partial; 656 | unsigned int write_blk_misalign; 657 | unsigned int read_blk_misalign; 658 | unsigned int dsr_imp; 659 | unsigned int c_size; 660 | unsigned int vdd_r_curr_min; 661 | unsigned int vdd_r_curr_max; 662 | unsigned int vdd_w_curr_min; 663 | unsigned int vdd_w_curr_max; 664 | unsigned int c_size_mult; 665 | unsigned int erase_blk_en; 666 | unsigned int sector_size; 667 | unsigned int wp_grp_size; 668 | unsigned int wp_grp_enable; 669 | unsigned int r2w_factor; 670 | unsigned int write_bl_len; 671 | unsigned int write_bl_partial; 672 | unsigned int file_format_grp; 673 | unsigned int copy; 674 | unsigned int perm_write_protect; 675 | unsigned int tmp_write_protect; 676 | unsigned int file_format; 677 | unsigned int crc; 678 | unsigned int taac; 679 | unsigned int tran_speed; 680 | 681 | parse_bin(csd, "2u", &csd_structure); 682 | 683 | if (csd_structure == 0) { 684 | parse_bin(csd, "2u6r1r4u3u8u1r4u3u12u4u1u1u1u1u2r12u3u3u3u3u3u" 685 | "1u7u7u1u2r3u4u1u5r1u1u1u1u2u2r7u1r", 686 | NULL, &taac_timevalue, &taac_timeunit, &nsac, 687 | &tran_speed_timevalue, 688 | &tran_speed_transferrateunit, &ccc, 689 | &read_bl_len, &read_bl_partial, 690 | &write_blk_misalign, &read_blk_misalign, 691 | &dsr_imp, &c_size, &vdd_r_curr_min, 692 | &vdd_r_curr_max, &vdd_w_curr_min, 693 | &vdd_w_curr_max, &c_size_mult, &erase_blk_en, 694 | §or_size, &wp_grp_size, &wp_grp_enable, 695 | &r2w_factor, &write_bl_len, &write_bl_partial, 696 | &file_format_grp, ©, &perm_write_protect, 697 | &tmp_write_protect, &file_format, &crc); 698 | } else if (csd_structure == 1) { 699 | parse_bin(csd, "2u6r1r4u3u8u1r4u3u12u4u1u1u1u1u6r22u1r1u7u7u1u" 700 | "2r3u4u1u5r1u1u1u1u2u2r7u1r", 701 | NULL, &taac_timevalue, &taac_timeunit, &nsac, 702 | &tran_speed_timevalue, 703 | &tran_speed_transferrateunit, &ccc, 704 | &read_bl_len, &read_bl_partial, 705 | &write_blk_misalign, &read_blk_misalign, 706 | &dsr_imp, &c_size, &erase_blk_en, §or_size, 707 | &wp_grp_size, &wp_grp_enable, &r2w_factor, 708 | &write_bl_len, &write_bl_partial, 709 | &file_format_grp, ©, &perm_write_protect, 710 | &tmp_write_protect, &file_format, &crc); 711 | 712 | vdd_r_curr_min = 0; 713 | c_size_mult = 0; 714 | } else { 715 | printf("Unknown CSD structure: 0x%1x\n", csd_structure); 716 | return; 717 | } 718 | 719 | taac = taac_timevalue << 3 | taac_timeunit; 720 | tran_speed = tran_speed_timevalue << 3 | tran_speed_transferrateunit; 721 | 722 | if (config->verbose) { 723 | float value; 724 | unsigned long long blocks = 0; 725 | int block_size = 0; 726 | unsigned long long memory_capacity; 727 | 728 | printf("======SD/CSD======\n"); 729 | 730 | printf("\tCSD_STRUCTURE: %u\n", csd_structure); 731 | printf("\tTAAC: 0x%02x (", taac); 732 | 733 | switch (taac_timevalue) { 734 | case 0x0: 735 | value = 0.0f; 736 | break; 737 | case 0x1: 738 | value = 1.0f; 739 | break; 740 | case 0x2: 741 | value = 1.2f; 742 | break; 743 | case 0x3: 744 | value = 1.3f; 745 | break; 746 | case 0x4: 747 | value = 1.5f; 748 | break; 749 | case 0x5: 750 | value = 2.0f; 751 | break; 752 | case 0x6: 753 | value = 2.5f; 754 | break; 755 | case 0x7: 756 | value = 3.0f; 757 | break; 758 | case 0x8: 759 | value = 3.5f; 760 | break; 761 | case 0x9: 762 | value = 4.0f; 763 | break; 764 | case 0xa: 765 | value = 4.5f; 766 | break; 767 | case 0xb: 768 | value = 5.0f; 769 | break; 770 | case 0xc: 771 | value = 5.5f; 772 | break; 773 | case 0xd: 774 | value = 6.0f; 775 | break; 776 | case 0xe: 777 | value = 7.0f; 778 | break; 779 | case 0xf: 780 | value = 8.0f; 781 | break; 782 | default: 783 | value = 0.0f; 784 | break; 785 | } 786 | 787 | switch (taac_timeunit) { 788 | case 0x0: 789 | printf("%.2fns)\n", value * 1.0f); 790 | break; 791 | case 0x1: 792 | printf("%.2fns)\n", value * 10.0f); 793 | break; 794 | case 0x2: 795 | printf("%.2fns)\n", value * 100.0f); 796 | break; 797 | case 0x3: 798 | printf("%.2fus)\n", value * 1.0f); 799 | break; 800 | case 0x4: 801 | printf("%.2fus)\n", value * 10.0f); 802 | break; 803 | case 0x5: 804 | printf("%.2fus)\n", value * 100.0f); 805 | break; 806 | case 0x6: 807 | printf("%.2fms)\n", value * 1.0f); 808 | break; 809 | case 0x7: 810 | printf("%.2fms)\n", value * 10.0f); 811 | break; 812 | } 813 | 814 | if (csd_structure == 1 && taac != 0x0e) 815 | printf("Warn: Invalid TAAC (should be 0x0e)\n"); 816 | 817 | printf("\tNSAC: %u clocks\n", nsac); 818 | if (csd_structure == 1 && nsac != 0x00) 819 | printf("Warn: Invalid NSAC (should be 0x00)\n"); 820 | 821 | printf("\tTRAN_SPEED: 0x%02x (", tran_speed); 822 | switch (tran_speed_timevalue) { 823 | case 0x0: 824 | value = 0.0f; 825 | break; 826 | case 0x1: 827 | value = 1.0f; 828 | break; 829 | case 0x2: 830 | value = 1.2f; 831 | break; 832 | case 0x3: 833 | value = 1.3f; 834 | break; 835 | case 0x4: 836 | value = 1.5f; 837 | break; 838 | case 0x5: 839 | value = 2.0f; 840 | break; 841 | case 0x6: 842 | value = 2.5f; 843 | break; 844 | case 0x7: 845 | value = 3.0f; 846 | break; 847 | case 0x8: 848 | value = 3.5f; 849 | break; 850 | case 0x9: 851 | value = 4.0f; 852 | break; 853 | case 0xa: 854 | value = 4.5f; 855 | break; 856 | case 0xb: 857 | value = 5.0f; 858 | break; 859 | case 0xc: 860 | value = 5.5f; 861 | break; 862 | case 0xd: 863 | value = 6.0f; 864 | break; 865 | case 0xe: 866 | value = 7.0f; 867 | break; 868 | case 0xf: 869 | value = 8.0f; 870 | break; 871 | default: 872 | value = 0.0f; 873 | break; 874 | } 875 | 876 | switch (tran_speed_transferrateunit) { 877 | case 0x0: 878 | printf("%.2fkbit/s)\n", value * 100.0f); 879 | break; 880 | case 0x1: 881 | printf("%.2fMbit/s)\n", value * 1.0f); 882 | break; 883 | case 0x2: 884 | printf("%.2fMbit/s)\n", value * 10.0f); 885 | break; 886 | case 0x3: 887 | printf("%.2fMbit/s)\n", value * 100.0f); 888 | break; 889 | default: 890 | printf("reserved)\n"); 891 | break; 892 | } 893 | if (csd_structure == 0 && 894 | (tran_speed != 0x32 && tran_speed != 0x5a)) 895 | printf("Warn: Invalid TRAN_SPEED " 896 | "(should be 0x32 or 0x5a)\n"); 897 | if (csd_structure == 1 && tran_speed != 0x32 && 898 | tran_speed != 0x5a && tran_speed != 0x0b && 899 | tran_speed != 0x2b) 900 | printf("Warn: Invalid TRAN_SPEED " 901 | "(should be 0x32, 0x5a, 0x0b or 0x2b\n"); 902 | 903 | printf("\tCCC: 0x%03x (class: ", ccc); 904 | if (ccc & 0x800) 905 | printf("11, "); 906 | if (ccc & 0x400) 907 | printf("10, "); 908 | if (ccc & 0x200) 909 | printf("9, "); 910 | if (ccc & 0x100) 911 | printf("8, "); 912 | if (ccc & 0x080) 913 | printf("7, "); 914 | if (ccc & 0x040) 915 | printf("6, "); 916 | if (ccc & 0x020) 917 | printf("5, "); 918 | if (ccc & 0x010) 919 | printf("4, "); 920 | if (ccc & 0x008) 921 | printf("3, "); 922 | if (ccc & 0x004) 923 | printf("2, "); 924 | if (ccc & 0x002) 925 | printf("1, "); 926 | if (ccc & 0x001) 927 | printf("0, "); 928 | printf(" )\n"); 929 | 930 | if (csd_structure == 0 && 931 | (ccc != 0x5b5 && ccc != 0x7b5 && ccc != 0x5f5)) 932 | printf("Warn: Invalid CCC (should be 0x5b5, " 933 | "0x7b5 or 0x5f5)\n"); 934 | else if (csd_structure == 1 && ccc != 0x5b5 && ccc != 0x7b5) 935 | printf("Warn: Invalid CCC (should be 0x5b5 or 0x7b5)\n"); 936 | 937 | printf("\tREAD_BL_LEN: 0x%01x (", read_bl_len); 938 | switch (read_bl_len) { 939 | case 0x9: 940 | printf("512 bytes)\n"); 941 | break; 942 | case 0xa: 943 | printf("1024 bytes)\n"); 944 | break; 945 | case 0xb: 946 | printf("2048 bytes)\n"); 947 | break; 948 | default: 949 | printf("reserved bytes)\n"); 950 | break; 951 | } 952 | 953 | if (csd_structure == 1 && read_bl_len != 0x9) 954 | printf("Warn: Invalid READ_BL_LEN (should be 0x9)\n"); 955 | 956 | printf("\tREAD_BL_PARTIAL: 0x%01x\n", read_bl_partial); 957 | if (csd_structure == 0 && read_bl_partial != 0x01) 958 | printf("Warn: Invalid READ_BL_PARTIAL (should be 0x01)\n"); 959 | else if (csd_structure == 1 && read_bl_partial != 0x00) 960 | printf("Warn: Invalid READ_BL_PARTIAL (should be 0x00)\n"); 961 | 962 | printf("\tWRITE_BLK_MISALIGN: 0x%01x\n", write_blk_misalign); 963 | if (csd_structure == 1 && write_blk_misalign != 0x00) 964 | printf("Warn: Invalid WRITE_BLK_MISALIGN (should be 0x00)\n"); 965 | 966 | printf("\tREAD_BLK_MISALIGN: 0x%01x\n", read_blk_misalign); 967 | if (csd_structure == 1 && read_blk_misalign != 0x00) 968 | printf("Warn: Invalid READ_BLK_MISALIGN (should be 0x00)\n"); 969 | 970 | printf("\tDSR_IMP: 0x%01x\n", dsr_imp); 971 | 972 | if (csd_structure == 0) { 973 | int mult; 974 | int blocknr; 975 | int block_len; 976 | 977 | printf("\tC_SIZE: 0x%03x\n", c_size); 978 | printf("\tVDD_R_CURR_MIN: 0x%01x (", vdd_r_curr_min); 979 | switch (vdd_r_curr_min) { 980 | case 0x0: 981 | printf("0.5mA)\n"); 982 | break; 983 | case 0x1: 984 | printf("1mA)\n"); 985 | break; 986 | case 0x2: 987 | printf("5mA)\n"); 988 | break; 989 | case 0x3: 990 | printf("10mA)\n"); 991 | break; 992 | case 0x4: 993 | printf("25mA)\n"); 994 | break; 995 | case 0x5: 996 | printf("35mA)\n"); 997 | break; 998 | case 0x6: 999 | printf("60mA)\n"); 1000 | break; 1001 | case 0x7: 1002 | printf("100mA)\n"); 1003 | break; 1004 | } 1005 | 1006 | printf("\tVDD_R_CURR_MAX: 0x%01x (", vdd_r_curr_max); 1007 | switch (vdd_r_curr_max) { 1008 | case 0x0: 1009 | printf("1mA)\n"); 1010 | break; 1011 | case 0x1: 1012 | printf("5mA)\n"); 1013 | break; 1014 | case 0x2: 1015 | printf("10mA)\n"); 1016 | break; 1017 | case 0x3: 1018 | printf("25mA)\n"); 1019 | break; 1020 | case 0x4: 1021 | printf("35mA)\n"); 1022 | break; 1023 | case 0x5: 1024 | printf("45mA)\n"); 1025 | break; 1026 | case 0x6: 1027 | printf("80mA)\n"); 1028 | break; 1029 | case 0x7: 1030 | printf("200mA)\n"); 1031 | break; 1032 | } 1033 | 1034 | printf("\tVDD_W_CURR_MIN: 0x%01x (", vdd_w_curr_min); 1035 | switch (vdd_w_curr_min) { 1036 | case 0x0: 1037 | printf("0.5mA)\n"); 1038 | break; 1039 | case 0x1: 1040 | printf("1mA)\n"); 1041 | break; 1042 | case 0x2: 1043 | printf("5mA)\n"); 1044 | break; 1045 | case 0x3: 1046 | printf("10mA)\n"); 1047 | break; 1048 | case 0x4: 1049 | printf("25mA)\n"); 1050 | break; 1051 | case 0x5: 1052 | printf("35mA)\n"); 1053 | break; 1054 | case 0x6: 1055 | printf("60mA)\n"); 1056 | break; 1057 | case 0x7: 1058 | printf("100mA)\n"); 1059 | break; 1060 | } 1061 | 1062 | printf("\tVDD_W_CURR_MAX: 0x%01x (", vdd_w_curr_max); 1063 | switch (vdd_w_curr_max) { 1064 | case 0x0: 1065 | printf("1mA)\n"); 1066 | break; 1067 | case 0x1: 1068 | printf("5mA)\n"); 1069 | break; 1070 | case 0x2: 1071 | printf("10mA)\n"); 1072 | break; 1073 | case 0x3: 1074 | printf("25mA)\n"); 1075 | break; 1076 | case 0x4: 1077 | printf("35mA)\n"); 1078 | break; 1079 | case 0x5: 1080 | printf("45mA)\n"); 1081 | break; 1082 | case 0x6: 1083 | printf("80mA)\n"); 1084 | break; 1085 | case 0x7: 1086 | printf("200mA)\n"); 1087 | break; 1088 | } 1089 | 1090 | printf("\tC_SIZE_MULT: 0x%01x\n", c_size_mult); 1091 | 1092 | mult = 1 << (c_size_mult + 2); 1093 | blocknr = (c_size + 1) * mult; 1094 | block_len = 1 << read_bl_len; 1095 | blocks = blocknr; 1096 | block_size = block_len; 1097 | } else if (csd_structure == 1) { 1098 | printf("\tC_SIZE: 0x%06x\n", c_size); 1099 | 1100 | printf("\tERASE_BLK_EN: 0x%01x\n", erase_blk_en); 1101 | if (erase_blk_en != 0x01) 1102 | printf("Warn: Invalid ERASE_BLK_EN (should be 0x01)\n"); 1103 | 1104 | printf("\tSECTOR_SIZE: 0x%02x (Erasable sector: %u blocks)\n", 1105 | sector_size, sector_size + 1); 1106 | if (sector_size != 0x7f) 1107 | printf("Warn: Invalid SECTOR_SIZE (should be 0x7f)\n"); 1108 | 1109 | printf("\tWP_GRP_SIZE: 0x%02x (Write protect group: %u blocks)\n", 1110 | wp_grp_size, wp_grp_size + 1); 1111 | if (wp_grp_size != 0x00) 1112 | printf("Warn: Invalid WP_GRP_SIZE (should be 0x00)\n"); 1113 | 1114 | printf("\tWP_GRP_ENABLE: 0x%01x\n", wp_grp_enable); 1115 | if (wp_grp_enable != 0x00) 1116 | printf("Warn: Invalid WP_GRP_ENABLE (should be 0x00)\n"); 1117 | 1118 | printf("\tR2W_FACTOR: 0x%01x (Write %u times read)\n", 1119 | r2w_factor, r2w_factor); 1120 | if (r2w_factor != 0x02) 1121 | printf("Warn: Invalid R2W_FACTOR (should be 0x02)\n"); 1122 | 1123 | printf("\tWRITE_BL_LEN: 0x%01x (", write_bl_len); 1124 | switch (write_bl_len) { 1125 | case 9: 1126 | printf("512 bytes)\n"); 1127 | break; 1128 | case 10: 1129 | printf("1024 bytes)\n"); 1130 | break; 1131 | case 11: 1132 | printf("2048 bytes)\n"); 1133 | break; 1134 | default: 1135 | printf("reserved)\n"); 1136 | break; 1137 | } 1138 | 1139 | if (write_bl_len != 0x09) 1140 | printf("Warn: Invalid WRITE_BL_LEN (should be 0x09)\n"); 1141 | 1142 | printf("\tWRITE_BL_PARTIAL: 0x%01x\n", write_bl_partial); 1143 | if (write_bl_partial != 0x00) 1144 | printf("Warn: Invalid WRITE_BL_PARTIAL (should be 0x00)\n"); 1145 | 1146 | printf("\tFILE_FORMAT_GRP: 0x%01x\n", file_format_grp); 1147 | if (file_format_grp != 0x00) 1148 | printf("Warn: Invalid FILE_FORMAT_GRP (should be 0x00)\n"); 1149 | 1150 | printf("\tCOPY: 0x%01x\n", copy); 1151 | printf("\tPERM_WRITE_PROTECT: 0x%01x\n", 1152 | perm_write_protect); 1153 | printf("\tTMP_WRITE_PROTECT: 0x%01x\n", 1154 | tmp_write_protect); 1155 | printf("\tFILE_FORMAT: 0x%01x (", 1156 | file_format); 1157 | 1158 | if (file_format_grp == 1) { 1159 | printf("reserved)\n"); 1160 | } else { 1161 | switch (file_format) { 1162 | case 0: 1163 | printf("partition table)\n"); 1164 | break; 1165 | case 1: 1166 | printf("no partition table)\n"); 1167 | break; 1168 | case 2: 1169 | printf("Universal File Format)\n"); 1170 | break; 1171 | case 3: 1172 | printf("Others/unknown)\n"); 1173 | break; 1174 | } 1175 | } 1176 | 1177 | if (file_format != 0x00) 1178 | printf("Warn: Invalid FILE_FORMAT (should be 0x00)\n"); 1179 | 1180 | printf("\tCRC: 0x%01x\n", crc); 1181 | 1182 | memory_capacity = (c_size + 1) * 512ull * 1024ull; 1183 | block_size = 512; 1184 | blocks = memory_capacity / block_size; 1185 | } 1186 | 1187 | memory_capacity = blocks * block_size; 1188 | 1189 | printf("\tCAPACITY: "); 1190 | if (memory_capacity / (1024ull * 1024ull * 1024ull) > 0) 1191 | printf("%.2fGbyte", 1192 | memory_capacity / (1024.0 * 1024.0 * 1024.0)); 1193 | else if (memory_capacity / (1024ull * 1024ull) > 0) 1194 | printf("%.2fMbyte", memory_capacity / (1024.0 * 1024.0)); 1195 | else if (memory_capacity / (1024ull) > 0) 1196 | printf("%.2fKbyte", memory_capacity / (1024.0)); 1197 | else 1198 | printf("%.2fbyte", memory_capacity * 1.0); 1199 | 1200 | printf(" (%llu bytes, %llu sectors, %d bytes each)\n", 1201 | memory_capacity, blocks, block_size); 1202 | } else { 1203 | unsigned long long blocks = 0; 1204 | int block_size = 0; 1205 | unsigned long long memory_capacity; 1206 | 1207 | printf("card classes: "); 1208 | if (ccc & 0x800) 1209 | printf("11 extension, "); 1210 | if (ccc & 0x400) 1211 | printf("10 switch, "); 1212 | if (ccc & 0x200) 1213 | printf("9 I/O mode, "); 1214 | if (ccc & 0x100) 1215 | printf("8 application specific, "); 1216 | if (ccc & 0x080) 1217 | printf("7 lock card, "); 1218 | if (ccc & 0x040) 1219 | printf("6 write protection, "); 1220 | if (ccc & 0x020) 1221 | printf("5 erase, "); 1222 | if (ccc & 0x010) 1223 | printf("4 block write, "); 1224 | if (ccc & 0x008) 1225 | printf("3 reserved, "); 1226 | if (ccc & 0x004) 1227 | printf("2 block read, "); 1228 | if (ccc & 0x002) 1229 | printf("1 reserved, "); 1230 | if (ccc & 0x001) 1231 | printf("0 basic, "); 1232 | printf("\b\b\n"); 1233 | 1234 | if (csd_structure == 0) { 1235 | int mult; 1236 | int blocknr; 1237 | int block_len; 1238 | 1239 | mult = 1 << (c_size_mult + 2); 1240 | blocknr = (c_size + 1) * mult; 1241 | block_len = 1 << read_bl_len; 1242 | blocks = blocknr; 1243 | block_size = block_len; 1244 | } else if (csd_structure == 1) { 1245 | memory_capacity = (c_size + 1) * 512ull * 1024ull; 1246 | block_size = 512; 1247 | blocks = memory_capacity / block_size; 1248 | } 1249 | 1250 | memory_capacity = blocks * block_size; 1251 | 1252 | printf("capacity: "); 1253 | if (memory_capacity / (1024ull * 1024ull * 1024ull) > 0) 1254 | printf("%.2fGbyte", 1255 | memory_capacity / (1024.0 * 1024.0 * 1024.0)); 1256 | else if (memory_capacity / (1024ull * 1024ull) > 0) 1257 | printf("%.2fMbyte", memory_capacity / (1024.0 * 1024.0)); 1258 | else if (memory_capacity / (1024ull) > 0) 1259 | printf("%.2fKbyte", memory_capacity / (1024.0)); 1260 | else 1261 | printf("%.2fbyte", memory_capacity * 1.0); 1262 | 1263 | printf(" (%llu bytes, %llu sectors, %d bytes each)\n", 1264 | memory_capacity, blocks, block_size); 1265 | } 1266 | } 1267 | 1268 | static void print_mmc_csd_structure(unsigned int csd_structure) 1269 | { 1270 | printf("\tCSD_STRUCTURE: 0x%01x (", csd_structure); 1271 | switch (csd_structure) { 1272 | case 0x0: 1273 | printf("v1.0)\n"); 1274 | break; 1275 | case 0x1: 1276 | printf("v1.1)\n"); 1277 | break; 1278 | case 0x2: 1279 | printf("v1.2)\n"); 1280 | break; 1281 | case 0x3: 1282 | printf("version in ext_csd)\n"); 1283 | break; 1284 | } 1285 | } 1286 | 1287 | static void print_mmc_csd_spec_ver(unsigned int spec_vers) 1288 | { 1289 | printf("\tSPEC_VERS: 0x%01x (", spec_vers); 1290 | switch (spec_vers) { 1291 | case 0x0: 1292 | printf("v1.0-v1.2)\n"); 1293 | break; 1294 | case 0x1: 1295 | printf("v1.4)\n"); 1296 | break; 1297 | case 0x2: 1298 | printf("v2.0-v2.2)\n"); 1299 | break; 1300 | case 0x3: 1301 | printf("v3.1-v3.31)\n"); 1302 | break; 1303 | case 0x4: 1304 | printf("v4.0-v4.3)\n"); 1305 | break; 1306 | default: 1307 | printf("reserved)\n"); 1308 | break; 1309 | } 1310 | } 1311 | 1312 | static void 1313 | print_mmc_csd_taac(unsigned int taac_timevalue, unsigned int taac_timeunit) 1314 | { 1315 | float value; 1316 | unsigned int taac = taac_timevalue << 3 | taac_timeunit; 1317 | 1318 | printf("\tTAAC: 0x%02x (", taac); 1319 | switch (taac_timevalue) { 1320 | case 0x0: 1321 | value = 0.0f; 1322 | break; 1323 | case 0x1: 1324 | value = 1.0f; 1325 | break; 1326 | case 0x2: 1327 | value = 1.2f; 1328 | break; 1329 | case 0x3: 1330 | value = 1.3f; 1331 | break; 1332 | case 0x4: 1333 | value = 1.5f; 1334 | break; 1335 | case 0x5: 1336 | value = 2.0f; 1337 | break; 1338 | case 0x6: 1339 | value = 2.5f; 1340 | break; 1341 | case 0x7: 1342 | value = 3.0f; 1343 | break; 1344 | case 0x8: 1345 | value = 3.5f; 1346 | break; 1347 | case 0x9: 1348 | value = 4.0f; 1349 | break; 1350 | case 0xa: 1351 | value = 4.5f; 1352 | break; 1353 | case 0xb: 1354 | value = 5.0f; 1355 | break; 1356 | case 0xc: 1357 | value = 5.5f; 1358 | break; 1359 | case 0xd: 1360 | value = 6.0f; 1361 | break; 1362 | case 0xe: 1363 | value = 7.0f; 1364 | break; 1365 | case 0xf: 1366 | value = 8.0f; 1367 | break; 1368 | default: 1369 | value = 0.0f; 1370 | break; 1371 | } 1372 | 1373 | switch (taac_timeunit) { 1374 | case 0x0: 1375 | printf("%.2fns)\n", value * 1.0f); 1376 | break; 1377 | case 0x1: 1378 | printf("%.2fns)\n", value * 10.0f); 1379 | break; 1380 | case 0x2: 1381 | printf("%.2fns)\n", value * 100.0f); 1382 | break; 1383 | case 0x3: 1384 | printf("%.2fus)\n", value * 1.0f); 1385 | break; 1386 | case 0x4: 1387 | printf("%.2fus)\n", value * 10.0f); 1388 | break; 1389 | case 0x5: 1390 | printf("%.2fus)\n", value * 100.0f); 1391 | break; 1392 | case 0x6: 1393 | printf("%.2fms)\n", value * 1.0f); 1394 | break; 1395 | case 0x7: 1396 | printf("%.2fms)\n", value * 10.0f); 1397 | break; 1398 | } 1399 | } 1400 | 1401 | static void print_mmc_csd_nsac(unsigned int nsac, unsigned int tran_speed_timevalue, 1402 | unsigned int tran_speed_transferrateunit) 1403 | { 1404 | float value; 1405 | unsigned int tran_speed = tran_speed_timevalue << 3 | tran_speed_transferrateunit; 1406 | 1407 | printf("\tNSAC: %u clocks\n", nsac); 1408 | printf("\tTRAN_SPEED: 0x%02x (", tran_speed); 1409 | switch (tran_speed_timevalue) { 1410 | case 0x0: 1411 | value = 0.0f; 1412 | break; 1413 | case 0x1: 1414 | value = 1.0f; 1415 | break; 1416 | case 0x2: 1417 | value = 1.2f; 1418 | break; 1419 | case 0x3: 1420 | value = 1.3f; 1421 | break; 1422 | case 0x4: 1423 | value = 1.5f; 1424 | break; 1425 | case 0x5: 1426 | value = 2.0f; 1427 | break; 1428 | case 0x6: 1429 | value = 2.6f; 1430 | break; 1431 | case 0x7: 1432 | value = 3.0f; 1433 | break; 1434 | case 0x8: 1435 | value = 3.5f; 1436 | break; 1437 | case 0x9: 1438 | value = 4.0f; 1439 | break; 1440 | case 0xa: 1441 | value = 4.5f; 1442 | break; 1443 | case 0xb: 1444 | value = 5.2f; 1445 | break; 1446 | case 0xc: 1447 | value = 5.5f; 1448 | break; 1449 | case 0xd: 1450 | value = 6.0f; 1451 | break; 1452 | case 0xe: 1453 | value = 7.0f; 1454 | break; 1455 | case 0xf: 1456 | value = 8.0f; 1457 | break; 1458 | default: 1459 | value = 0.0f; 1460 | break; 1461 | } 1462 | 1463 | switch (tran_speed_transferrateunit) { 1464 | case 0x0: 1465 | printf("%.2fKHz/s)\n", value * 100.0f); 1466 | break; 1467 | case 0x1: 1468 | printf("%.2fMHz/s)\n", value * 1.0f); 1469 | break; 1470 | case 0x2: 1471 | printf("%.2fMHz/s)\n", value * 10.0f); 1472 | break; 1473 | case 0x3: 1474 | printf("%.2fMHz/s)\n", value * 100.0f); 1475 | break; 1476 | default: 1477 | printf("reserved)\n"); 1478 | break; 1479 | } 1480 | } 1481 | 1482 | static void print_mmc_csd_ccc(unsigned int ccc) 1483 | { 1484 | printf("\tCCC: 0x%03x (class: ", ccc); 1485 | if (ccc & 0x800) 1486 | printf("11, "); 1487 | if (ccc & 0x400) 1488 | printf("10, "); 1489 | if (ccc & 0x200) 1490 | printf("9, "); 1491 | if (ccc & 0x100) 1492 | printf("8, "); 1493 | if (ccc & 0x080) 1494 | printf("7, "); 1495 | if (ccc & 0x040) 1496 | printf("6, "); 1497 | if (ccc & 0x020) 1498 | printf("5, "); 1499 | if (ccc & 0x010) 1500 | printf("4, "); 1501 | if (ccc & 0x008) 1502 | printf("3, "); 1503 | if (ccc & 0x004) 1504 | printf("2, "); 1505 | if (ccc & 0x002) 1506 | printf("1, "); 1507 | if (ccc & 0x001) 1508 | printf("0, "); 1509 | printf(" )\n"); 1510 | } 1511 | 1512 | static void print_mmc_csd_read_bl_len(unsigned int read_bl_len) 1513 | { 1514 | printf("\tREAD_BL_LEN: 0x%01x (", read_bl_len); 1515 | switch (read_bl_len) { 1516 | case 0x0: 1517 | printf("1 byte)\n"); 1518 | break; 1519 | case 0x1: 1520 | printf("2 byte)\n"); 1521 | break; 1522 | case 0x2: 1523 | printf("4 byte)\n"); 1524 | break; 1525 | case 0x3: 1526 | printf("8 byte)\n"); 1527 | break; 1528 | case 0x4: 1529 | printf("16 byte)\n"); 1530 | break; 1531 | case 0x5: 1532 | printf("32 byte)\n"); 1533 | break; 1534 | case 0x6: 1535 | printf("64 byte)\n"); 1536 | break; 1537 | case 0x7: 1538 | printf("128 byte)\n"); 1539 | break; 1540 | case 0x8: 1541 | printf("256 byte)\n"); 1542 | break; 1543 | case 0x9: 1544 | printf("512 bytes)\n"); 1545 | break; 1546 | case 0xa: 1547 | printf("1024 bytes)\n"); 1548 | break; 1549 | case 0xb: 1550 | printf("2048 bytes)\n"); 1551 | break; 1552 | case 0xc: 1553 | printf("4096 bytes)\n"); 1554 | break; 1555 | case 0xd: 1556 | printf("8192 bytes)\n"); 1557 | break; 1558 | case 0xe: 1559 | printf("16K bytes)\n"); 1560 | break; 1561 | default: 1562 | printf("reserved bytes)\n"); 1563 | break; 1564 | } 1565 | } 1566 | 1567 | static void print_mmc_csd_read_bl_partial(unsigned int read_bl_partial) 1568 | { 1569 | printf("\tREAD_BL_PARTIAL: 0x%01x (", read_bl_partial); 1570 | switch (read_bl_partial) { 1571 | case 0x0: 1572 | printf("only 512 byte and READ_BL_LEN block size)\n"); 1573 | break; 1574 | case 0x1: 1575 | printf("less than READ_BL_LEN block size can be used)\n"); 1576 | break; 1577 | } 1578 | } 1579 | 1580 | static void print_mmc_csd_write_blk_misalign(unsigned int write_blk_misalign) 1581 | { 1582 | printf("\tWRITE_BLK_MISALIGN: 0x%01x (", write_blk_misalign); 1583 | switch (write_blk_misalign) { 1584 | case 0x0: 1585 | printf("writes across block boundaries are invalid)\n"); 1586 | break; 1587 | case 0x1: 1588 | printf("writes across block boundaries are allowed)\n"); 1589 | break; 1590 | } 1591 | } 1592 | 1593 | static void print_mmc_csd_read_blk_misalign(unsigned int read_blk_misalign) 1594 | { 1595 | printf("\tREAD_BLK_MISALIGN: 0x%01x (", read_blk_misalign); 1596 | switch (read_blk_misalign) { 1597 | case 0x0: 1598 | printf("reads across block boundaries are invalid)\n"); 1599 | break; 1600 | case 0x1: 1601 | printf("reads across block boundaries are allowed)\n"); 1602 | break; 1603 | } 1604 | } 1605 | 1606 | static void print_mmc_csd_dsr_imp(unsigned int dsr_imp) 1607 | { 1608 | printf("\tDSR_IMP: 0x%01x (", dsr_imp); 1609 | switch (dsr_imp) { 1610 | case 0x0: 1611 | printf("configurable driver stage not available)\n"); 1612 | break; 1613 | case 0x1: 1614 | printf("configurable driver state available)\n"); 1615 | break; 1616 | } 1617 | } 1618 | 1619 | static void print_mmc_csd_vdd(unsigned int vdd_r_curr_min, unsigned int vdd_r_curr_max, 1620 | unsigned int vdd_w_curr_min, unsigned int vdd_w_curr_max) 1621 | { 1622 | printf("\tVDD_R_CURR_MIN: 0x%01x (", vdd_r_curr_min); 1623 | switch (vdd_r_curr_min) { 1624 | case 0x0: 1625 | printf("0.5mA)\n"); 1626 | break; 1627 | case 0x1: 1628 | printf("1mA)\n"); 1629 | break; 1630 | case 0x2: 1631 | printf("5mA)\n"); 1632 | break; 1633 | case 0x3: 1634 | printf("10mA)\n"); 1635 | break; 1636 | case 0x4: 1637 | printf("25mA)\n"); 1638 | break; 1639 | case 0x5: 1640 | printf("35mA)\n"); 1641 | break; 1642 | case 0x6: 1643 | printf("60mA)\n"); 1644 | break; 1645 | case 0x7: 1646 | printf("100mA)\n"); 1647 | break; 1648 | } 1649 | 1650 | printf("\tVDD_R_CURR_MAX: 0x%01x (", vdd_r_curr_max); 1651 | switch (vdd_r_curr_max) { 1652 | case 0x0: 1653 | printf("1mA)\n"); 1654 | break; 1655 | case 0x1: 1656 | printf("5mA)\n"); 1657 | break; 1658 | case 0x2: 1659 | printf("10mA)\n"); 1660 | break; 1661 | case 0x3: 1662 | printf("25mA)\n"); 1663 | break; 1664 | case 0x4: 1665 | printf("35mA)\n"); 1666 | break; 1667 | case 0x5: 1668 | printf("45mA)\n"); 1669 | break; 1670 | case 0x6: 1671 | printf("80mA)\n"); 1672 | break; 1673 | case 0x7: 1674 | printf("200mA)\n"); 1675 | break; 1676 | } 1677 | 1678 | printf("\tVDD_W_CURR_MIN: 0x%01x (", vdd_w_curr_min); 1679 | switch (vdd_w_curr_min) { 1680 | case 0x0: 1681 | printf("0.5mA)\n"); 1682 | break; 1683 | case 0x1: 1684 | printf("1mA)\n"); 1685 | break; 1686 | case 0x2: 1687 | printf("5mA)\n"); 1688 | break; 1689 | case 0x3: 1690 | printf("10mA)\n"); 1691 | break; 1692 | case 0x4: 1693 | printf("25mA)\n"); 1694 | break; 1695 | case 0x5: 1696 | printf("35mA)\n"); 1697 | break; 1698 | case 0x6: 1699 | printf("60mA)\n"); 1700 | break; 1701 | case 0x7: 1702 | printf("100mA)\n"); 1703 | break; 1704 | } 1705 | 1706 | printf("\tVDD_W_CURR_MAX: 0x%01x (", vdd_w_curr_max); 1707 | switch (vdd_w_curr_max) { 1708 | case 0x0: 1709 | printf("1mA)\n"); 1710 | break; 1711 | case 0x1: 1712 | printf("5mA)\n"); 1713 | break; 1714 | case 0x2: 1715 | printf("10mA)\n"); 1716 | break; 1717 | case 0x3: 1718 | printf("25mA)\n"); 1719 | break; 1720 | case 0x4: 1721 | printf("35mA)\n"); 1722 | break; 1723 | case 0x5: 1724 | printf("45mA)\n"); 1725 | break; 1726 | case 0x6: 1727 | printf("80mA)\n"); 1728 | break; 1729 | case 0x7: 1730 | printf("200mA)\n"); 1731 | break; 1732 | } 1733 | } 1734 | 1735 | static void print_mmc_csd_default_ecc(unsigned int default_ecc) 1736 | { 1737 | printf("\tDEFAULT_ECC: 0x%01x (", default_ecc); 1738 | switch (default_ecc) { 1739 | case 0: 1740 | printf("none)\n"); 1741 | break; 1742 | case 1: 1743 | printf("BCH)\n"); 1744 | break; 1745 | default: 1746 | printf("reserved)\n"); 1747 | break; 1748 | } 1749 | } 1750 | 1751 | static void print_mmc_csd_write_bl_len(unsigned int write_bl_len) 1752 | { 1753 | printf("\tWRITE_BL_LEN: 0x%01x (", write_bl_len); 1754 | switch (write_bl_len) { 1755 | case 0x0: 1756 | printf("1 byte)\n"); 1757 | break; 1758 | case 0x1: 1759 | printf("2 byte)\n"); 1760 | break; 1761 | case 0x2: 1762 | printf("4 byte)\n"); 1763 | break; 1764 | case 0x3: 1765 | printf("8 byte)\n"); 1766 | break; 1767 | case 0x4: 1768 | printf("16 byte)\n"); 1769 | break; 1770 | case 0x5: 1771 | printf("32 byte)\n"); 1772 | break; 1773 | case 0x6: 1774 | printf("64 byte)\n"); 1775 | break; 1776 | case 0x7: 1777 | printf("128 byte)\n"); 1778 | break; 1779 | case 0x8: 1780 | printf("256 byte)\n"); 1781 | break; 1782 | case 0x9: 1783 | printf("512 bytes)\n"); 1784 | break; 1785 | case 0xa: 1786 | printf("1024 bytes)\n"); 1787 | break; 1788 | case 0xb: 1789 | printf("2048 bytes)\n"); 1790 | break; 1791 | case 0xc: 1792 | printf("4096 bytes)\n"); 1793 | break; 1794 | case 0xd: 1795 | printf("8192 bytes)\n"); 1796 | break; 1797 | case 0xe: 1798 | printf("16K bytes)\n"); 1799 | break; 1800 | default: 1801 | printf("reserved bytes)\n"); 1802 | break; 1803 | } 1804 | } 1805 | 1806 | static void print_mmc_csd_write_bl_partial(unsigned int write_bl_partial) 1807 | { 1808 | printf("\tWRITE_BL_PARTIAL: 0x%01x (", write_bl_partial); 1809 | switch (write_bl_partial) { 1810 | case 0x0: 1811 | printf("only 512 byte and WRITE_BL_LEN block size)\n"); 1812 | break; 1813 | case 0x1: 1814 | printf("less than WRITE_BL_LEN block size can be used)\n"); 1815 | break; 1816 | } 1817 | } 1818 | 1819 | static void print_mmc_csd_file_format(unsigned int file_format, unsigned int file_format_grp) 1820 | { 1821 | printf("\tFILE_FORMAT: 0x%01x (", file_format); 1822 | if (file_format != 0) 1823 | printf("Warn: Invalid FILE_FORMAT\n"); 1824 | 1825 | if (file_format_grp == 1) { 1826 | printf("reserved)\n"); 1827 | } else { 1828 | switch (file_format) { 1829 | case 0: 1830 | printf("partition table)\n"); 1831 | break; 1832 | case 1: 1833 | printf("no partition table)\n"); 1834 | break; 1835 | case 2: 1836 | printf("Universal File Format)\n"); 1837 | break; 1838 | case 3: 1839 | printf("Others/unknown)\n"); 1840 | break; 1841 | } 1842 | } 1843 | } 1844 | 1845 | static void print_mmc_csd_ecc(unsigned int ecc) 1846 | { 1847 | printf("\tECC: 0x%01x (", ecc); 1848 | switch (ecc) { 1849 | case 0: 1850 | printf("none)\n"); 1851 | break; 1852 | case 1: 1853 | printf("BCH(542,512))\n"); 1854 | break; 1855 | default: 1856 | printf("reserved)\n"); 1857 | break; 1858 | } 1859 | } 1860 | 1861 | static void print_mmc_csd_capacity(unsigned int c_size, unsigned int c_size_mult, 1862 | unsigned int read_bl_len) 1863 | { 1864 | int mult = 1 << (c_size_mult + 2); 1865 | unsigned long long blocknr = (c_size + 1) * mult; 1866 | int block_len = 1 << read_bl_len; 1867 | unsigned long long memory_capacity; 1868 | 1869 | if (c_size == 0xfff) 1870 | return; 1871 | 1872 | printf("\tC_SIZE: 0x%03x\n", c_size); 1873 | printf("\tC_SIZE_MULT: 0x%01x\n", c_size_mult); 1874 | 1875 | memory_capacity = blocknr * block_len; 1876 | 1877 | printf("\tCAPACITY: "); 1878 | if (memory_capacity / (1024ull * 1024ull * 1024ull) > 0) 1879 | printf("%.2fGbyte", memory_capacity / (1024.0 * 1024.0 * 1024.0)); 1880 | else if (memory_capacity / (1024ull * 1024ull) > 0) 1881 | printf("%.2fMbyte", memory_capacity / (1024.0 * 1024.0)); 1882 | else if (memory_capacity / (1024ull) > 0) 1883 | printf("%.2fKbyte", memory_capacity / (1024.0)); 1884 | else 1885 | printf("%.2fbyte", memory_capacity * 1.0); 1886 | 1887 | printf(" (%llu bytes, %llu sectors, %d bytes each)\n", memory_capacity, blocknr, block_len); 1888 | } 1889 | 1890 | static void print_mmc_csd(struct config *config, char *csd) 1891 | { 1892 | unsigned int csd_structure, spec_vers, taac_timevalue, taac_timeunit, nsac; 1893 | unsigned int tran_speed_timevalue, tran_speed_transferrateunit, ccc, read_bl_len; 1894 | unsigned int read_bl_partial, write_blk_misalign, read_blk_misalign, dsr_imp; 1895 | unsigned int c_size, vdd_r_curr_min, vdd_r_curr_max, vdd_w_curr_min, vdd_w_curr_max; 1896 | unsigned int c_size_mult, erase_grp_size, erase_grp_mult, wp_grp_size, wp_grp_enable; 1897 | unsigned int default_ecc, r2w_factor, write_bl_len, write_bl_partial, content_prot_app; 1898 | unsigned int file_format_grp, copy, perm_write_protect, tmp_write_protect, file_format; 1899 | unsigned int ecc, crc; 1900 | 1901 | parse_bin(csd, "2u4u2r1r4u3u8u1r4u3u12u4u1u1u1u1u2r12u3u3u3u3u3u" 1902 | "5u5u5u1u2u3u4u1u4r1u1u1u1u1u2u2u7u1r", 1903 | &csd_structure, &spec_vers, &taac_timevalue, 1904 | &taac_timeunit, &nsac, &tran_speed_timevalue, 1905 | &tran_speed_transferrateunit, &ccc, &read_bl_len, 1906 | &read_bl_partial, &write_blk_misalign, 1907 | &read_blk_misalign, &dsr_imp, &c_size, 1908 | &vdd_r_curr_min, &vdd_r_curr_max, 1909 | &vdd_w_curr_min, &vdd_w_curr_max, &c_size_mult, 1910 | &erase_grp_size, &erase_grp_mult, &wp_grp_size, 1911 | &wp_grp_enable, &default_ecc, &r2w_factor, 1912 | &write_bl_len, &write_bl_partial, &content_prot_app, 1913 | &file_format_grp, ©, &perm_write_protect, 1914 | &tmp_write_protect, &file_format, &ecc, &crc); 1915 | 1916 | if (config->verbose) { 1917 | 1918 | printf("======MMC/CSD======\n"); 1919 | 1920 | print_mmc_csd_structure(csd_structure); 1921 | 1922 | print_mmc_csd_spec_ver(spec_vers); 1923 | 1924 | print_mmc_csd_taac(taac_timevalue, taac_timeunit); 1925 | 1926 | print_mmc_csd_nsac(nsac, tran_speed_timevalue, tran_speed_transferrateunit); 1927 | 1928 | print_mmc_csd_ccc(ccc); 1929 | 1930 | print_mmc_csd_read_bl_len(read_bl_len); 1931 | 1932 | print_mmc_csd_read_bl_partial(read_bl_partial); 1933 | 1934 | print_mmc_csd_write_blk_misalign(write_blk_misalign); 1935 | 1936 | print_mmc_csd_read_blk_misalign(read_blk_misalign); 1937 | 1938 | print_mmc_csd_dsr_imp(dsr_imp); 1939 | 1940 | print_mmc_csd_vdd(vdd_r_curr_min, vdd_r_curr_max, vdd_w_curr_min, vdd_w_curr_max); 1941 | 1942 | printf("\tERASE_GRP_SIZE: 0x%02x\n", erase_grp_size); 1943 | printf("\tERASE_GRP_MULT: 0x%02x (%u write blocks/erase group)\n", 1944 | erase_grp_mult, (erase_grp_size + 1) * 1945 | (erase_grp_mult + 1)); 1946 | printf("\tWP_GRP_SIZE: 0x%02x (%u blocks/write protect group)\n", 1947 | wp_grp_size, wp_grp_size + 1); 1948 | printf("\tWP_GRP_ENABLE: 0x%01x\n", wp_grp_enable); 1949 | 1950 | print_mmc_csd_default_ecc(default_ecc); 1951 | 1952 | printf("\tR2W_FACTOR: 0x%01x (Write %u times read)\n", 1953 | r2w_factor, r2w_factor); 1954 | 1955 | print_mmc_csd_write_bl_len(write_bl_len); 1956 | 1957 | print_mmc_csd_write_bl_partial(write_bl_partial); 1958 | 1959 | printf("\tCONTENT_PROT_APP: 0x%01x\n", content_prot_app); 1960 | printf("\tFILE_FORMAT_GRP: 0x%01x\n", file_format_grp); 1961 | if (file_format_grp != 0) 1962 | printf("Warn: Invalid FILE_FORMAT_GRP\n"); 1963 | 1964 | printf("\tCOPY: 0x%01x\n", copy); 1965 | printf("\tPERM_WRITE_PROTECT: 0x%01x\n", perm_write_protect); 1966 | printf("\tTMP_WRITE_PROTECT: 0x%01x\n", tmp_write_protect); 1967 | 1968 | print_mmc_csd_file_format(file_format, file_format_grp); 1969 | 1970 | print_mmc_csd_ecc(ecc); 1971 | 1972 | printf("\tCRC: 0x%01x\n", crc); 1973 | 1974 | print_mmc_csd_capacity(c_size, c_size_mult, read_bl_len); 1975 | } else { 1976 | print_mmc_csd_spec_ver(spec_vers); 1977 | 1978 | print_mmc_csd_ccc(ccc); 1979 | 1980 | print_mmc_csd_capacity(c_size, c_size_mult, read_bl_len); 1981 | } 1982 | } 1983 | 1984 | static void print_sd_scr(struct config *config, char *scr) 1985 | { 1986 | unsigned int scr_structure; 1987 | unsigned int sd_spec; 1988 | unsigned int data_stat_after_erase; 1989 | unsigned int sd_security; 1990 | unsigned int sd_bus_widths; 1991 | unsigned int sd_spec3; 1992 | unsigned int ex_security; 1993 | unsigned int cmd_support; 1994 | 1995 | parse_bin(scr, "4u4u1u3u4u1u4u9r2u32r", 1996 | &scr_structure, &sd_spec, &data_stat_after_erase, 1997 | &sd_security, &sd_bus_widths, &sd_spec3, 1998 | &ex_security, &cmd_support); 1999 | 2000 | if (config->verbose) { 2001 | printf("======SD/SCR======\n"); 2002 | 2003 | printf("\tSCR_STRUCTURE: 0x%01x (", scr_structure); 2004 | switch (scr_structure) { 2005 | case 0: 2006 | printf("SCR v1.0)\n"); 2007 | break; 2008 | default: 2009 | printf("reserved)\n"); 2010 | break; 2011 | } 2012 | 2013 | printf("\tSD_SPEC: 0x%01x (", sd_spec); 2014 | switch (sd_spec) { 2015 | case 0: 2016 | printf("SD v1.0/1.01)\n"); 2017 | break; 2018 | case 1: 2019 | printf("SD v1.10)\n"); 2020 | break; 2021 | case 2: 2022 | printf("SD v2.00/v3.0x)\n"); 2023 | break; 2024 | case 3: 2025 | printf("SD v4.00)\n"); 2026 | break; 2027 | default: 2028 | printf("reserved)\n"); 2029 | break; 2030 | } 2031 | 2032 | printf("\tDATA_STAT_AFTER_ERASE: 0x%01x\n", 2033 | data_stat_after_erase); 2034 | 2035 | printf("\tSD_SECURITY: 0x%01x (", sd_security); 2036 | switch (sd_security) { 2037 | case 0: 2038 | printf("no security)\n"); 2039 | break; 2040 | case 1: 2041 | printf("not used)\n"); 2042 | break; 2043 | case 2: 2044 | printf("SDSC card/security v1.01)\n"); 2045 | break; 2046 | case 3: 2047 | printf("SDHC card/security v2.00)\n"); 2048 | break; 2049 | case 4: 2050 | printf("SDXC card/security v3.xx)\n"); 2051 | break; 2052 | default: 2053 | printf("reserved)\n"); 2054 | break; 2055 | } 2056 | 2057 | printf("\tSD_BUS_WIDTHS: 0x%01x (", sd_bus_widths); 2058 | if (BITS(sd_bus_widths, 2, 2)) 2059 | printf("4bit, "); 2060 | if (BITS(sd_bus_widths, 0, 0)) 2061 | printf("1bit, "); 2062 | printf(" bus)\n"); 2063 | 2064 | printf("\tSD_SPEC3: 0x%01x (", sd_spec3); 2065 | if (sd_spec >= 2) { 2066 | switch (sd_spec3) { 2067 | case 0: 2068 | printf("SD v2.00)\n"); 2069 | break; 2070 | case 1: 2071 | printf("SD v3.0x)\n"); 2072 | break; 2073 | } 2074 | } else { 2075 | printf("SD 1.xx)\n"); 2076 | } 2077 | 2078 | printf("\tEX_SECURITY: 0x%01x\n", ex_security); 2079 | 2080 | printf("\tCMD_SUPPORT: 0x%01x (", cmd_support); 2081 | if (BITS(cmd_support, 1, 1)) 2082 | printf("CMD23 "); 2083 | if (BITS(cmd_support, 0, 0)) 2084 | printf("CMD20 "); 2085 | printf(" )\n"); 2086 | } else { 2087 | printf("version: "); 2088 | switch (sd_spec) { 2089 | case 0: 2090 | printf("SD 1.0/1.01\n"); 2091 | break; 2092 | case 1: 2093 | printf("SD 1.10\n"); 2094 | break; 2095 | case 2: 2096 | switch (sd_spec3) { 2097 | case 0: 2098 | printf("SD 2.00\n"); 2099 | break; 2100 | case 1: 2101 | printf("SD 3.0x\n"); 2102 | break; 2103 | default: 2104 | printf("unknown\n"); 2105 | break; 2106 | } 2107 | break; 2108 | case 3: 2109 | printf("SD 4.00\n"); 2110 | break; 2111 | default: 2112 | printf("unknown\n"); 2113 | break; 2114 | } 2115 | 2116 | printf("bus widths: "); 2117 | if (BITS(sd_bus_widths, 2, 2)) 2118 | printf("4bit, "); 2119 | if (BITS(sd_bus_widths, 0, 0)) 2120 | printf("1bit, "); 2121 | printf("\b\b\n"); 2122 | } 2123 | } 2124 | 2125 | static int process_reg(struct config *config, char *reg_content, enum REG_TYPE reg) 2126 | { 2127 | int ret = 0; 2128 | 2129 | switch (reg) { 2130 | case CID: 2131 | if (!reg_content) { 2132 | fprintf(stderr, 2133 | "Could not read card identity in directory '%s'.\n", 2134 | config->dir); 2135 | ret = -1; 2136 | goto err; 2137 | } 2138 | 2139 | if (config->bus == SD) 2140 | print_sd_cid(config, reg_content); 2141 | else 2142 | print_mmc_cid(config, reg_content); 2143 | 2144 | break; 2145 | case CSD: 2146 | if (!reg_content) { 2147 | fprintf(stderr, 2148 | "Could not read card specific data in " 2149 | "directory '%s'.\n", config->dir); 2150 | ret = -1; 2151 | goto err; 2152 | } 2153 | 2154 | if (config->bus == SD) 2155 | print_sd_csd(config, reg_content); 2156 | else 2157 | print_mmc_csd(config, reg_content); 2158 | 2159 | break; 2160 | case SCR: 2161 | if (config->bus != SD) 2162 | break; 2163 | 2164 | if (!reg_content) { 2165 | fprintf(stderr, "Could not read SD card " 2166 | "configuration in directory '%s'.\n", 2167 | config->dir); 2168 | ret = -1; 2169 | goto err; 2170 | } 2171 | 2172 | print_sd_scr(config, reg_content); 2173 | 2174 | break; 2175 | default: 2176 | goto err; 2177 | } 2178 | 2179 | err: 2180 | 2181 | return ret; 2182 | } 2183 | 2184 | static int process_reg_from_file(struct config *config, enum REG_TYPE reg) 2185 | { 2186 | char *reg_content = NULL; 2187 | int ret = 0; 2188 | 2189 | switch (reg) { 2190 | case CID: 2191 | reg_content = read_file("cid"); 2192 | ret = process_reg(config, reg_content, CID); 2193 | 2194 | break; 2195 | case CSD: 2196 | reg_content = read_file("csd"); 2197 | ret = process_reg(config, reg_content, CSD); 2198 | 2199 | break; 2200 | case SCR: 2201 | if (config->bus != SD) 2202 | break; 2203 | 2204 | reg_content = read_file("scr"); 2205 | ret = process_reg(config, reg_content, SCR); 2206 | 2207 | break; 2208 | default: 2209 | goto err; 2210 | } 2211 | 2212 | err: 2213 | free(reg_content); 2214 | 2215 | return ret; 2216 | } 2217 | 2218 | static int process_dir(struct config *config, enum REG_TYPE reg) 2219 | { 2220 | char *type = NULL; 2221 | int ret = 0; 2222 | 2223 | if (chdir(config->dir) < 0) { 2224 | fprintf(stderr, 2225 | "MMC/SD information directory '%s' does not exist.\n", 2226 | config->dir); 2227 | return -1; 2228 | } 2229 | 2230 | type = read_file("type"); 2231 | if (!type) { 2232 | fprintf(stderr, 2233 | "Could not read card interface type in directory '%s'.\n", 2234 | config->dir); 2235 | return -1; 2236 | } 2237 | 2238 | if (strcmp(type, "MMC") && strcmp(type, "SD")) { 2239 | fprintf(stderr, "Unknown type: '%s'\n", type); 2240 | ret = -1; 2241 | goto err; 2242 | } 2243 | 2244 | config->bus = strcmp(type, "MMC") ? SD : MMC; 2245 | 2246 | ret = process_reg_from_file(config, reg); 2247 | 2248 | err: 2249 | free(type); 2250 | 2251 | return ret; 2252 | } 2253 | 2254 | static int do_read_reg(int argc, char **argv, enum REG_TYPE reg) 2255 | { 2256 | struct config cfg = {}; 2257 | int ret; 2258 | 2259 | ret = parse_opts(argc, argv, &cfg); 2260 | if (ret) 2261 | return ret; 2262 | 2263 | if (cfg.dir) { 2264 | ret = process_dir(&cfg, reg); 2265 | free(cfg.dir); 2266 | } else if (cfg.reg) { 2267 | ret = process_reg(&cfg, cfg.reg, reg); 2268 | } 2269 | 2270 | return ret; 2271 | } 2272 | 2273 | int do_read_csd(int argc, char **argv) 2274 | { 2275 | return do_read_reg(argc, argv, CSD); 2276 | } 2277 | 2278 | int do_read_cid(int argc, char **argv) 2279 | { 2280 | return do_read_reg(argc, argv, CID); 2281 | } 2282 | 2283 | int do_read_scr(int argc, char **argv) 2284 | { 2285 | return do_read_reg(argc, argv, SCR); 2286 | } 2287 | --------------------------------------------------------------------------------