Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:15.5:Update
mmc-utils
mmc-utils-0.1+git.20220208.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File mmc-utils-0.1+git.20220208.obscpio of Package mmc-utils
07070100000000000081A40000000000000000000000016202891700000010000000000000000000000000000000000000002600000000mmc-utils-0.1+git.20220208/.gitignore.*.o.d *.o /mmc 07070100000001000041ED0000000000000000000000036202891700000000000000000000000000000000000000000000002400000000mmc-utils-0.1+git.20220208/3rdparty07070100000002000041ED0000000000000000000000026202891700000000000000000000000000000000000000000000002D00000000mmc-utils-0.1+git.20220208/3rdparty/hmac_sha07070100000003000081A400000000000000000000000162028917000048A3000000000000000000000000000000000000003900000000mmc-utils-0.1+git.20220208/3rdparty/hmac_sha/hmac_sha2.c/* * HMAC-SHA-224/256/384/512 implementation * Last update: 06/15/2005 * Issue date: 06/15/2005 * * Since this code has been incorporated into a GPLv2 project, it is * distributed under GPLv2 inside mmc-utils. The original BSD license * that the code was released under is included below for clarity. * * Copyright (C) 2005 Olivier Gay <olivier.gay@a3.epfl.ch> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include <string.h> #include "hmac_sha2.h" /* HMAC-SHA-224 functions */ void hmac_sha224_init(hmac_sha224_ctx *ctx, const unsigned char *key, unsigned int key_size) { unsigned int fill; unsigned int num; const unsigned char *key_used; unsigned char key_temp[SHA224_DIGEST_SIZE]; int i; if (key_size == SHA224_BLOCK_SIZE) { key_used = key; num = SHA224_BLOCK_SIZE; } else { if (key_size > SHA224_BLOCK_SIZE){ num = SHA224_DIGEST_SIZE; sha224(key, key_size, key_temp); key_used = key_temp; } else { /* key_size > SHA224_BLOCK_SIZE */ key_used = key; num = key_size; } fill = SHA224_BLOCK_SIZE - num; memset(ctx->block_ipad + num, 0x36, fill); memset(ctx->block_opad + num, 0x5c, fill); } for (i = 0; i < (int) num; i++) { ctx->block_ipad[i] = key_used[i] ^ 0x36; ctx->block_opad[i] = key_used[i] ^ 0x5c; } sha224_init(&ctx->ctx_inside); sha224_update(&ctx->ctx_inside, ctx->block_ipad, SHA224_BLOCK_SIZE); sha224_init(&ctx->ctx_outside); sha224_update(&ctx->ctx_outside, ctx->block_opad, SHA224_BLOCK_SIZE); /* for hmac_reinit */ memcpy(&ctx->ctx_inside_reinit, &ctx->ctx_inside, sizeof(sha224_ctx)); memcpy(&ctx->ctx_outside_reinit, &ctx->ctx_outside, sizeof(sha224_ctx)); } void hmac_sha224_reinit(hmac_sha224_ctx *ctx) { memcpy(&ctx->ctx_inside, &ctx->ctx_inside_reinit, sizeof(sha224_ctx)); memcpy(&ctx->ctx_outside, &ctx->ctx_outside_reinit, sizeof(sha224_ctx)); } void hmac_sha224_update(hmac_sha224_ctx *ctx, const unsigned char *message, unsigned int message_len) { sha224_update(&ctx->ctx_inside, message, message_len); } void hmac_sha224_final(hmac_sha224_ctx *ctx, unsigned char *mac, unsigned int mac_size) { unsigned char digest_inside[SHA224_DIGEST_SIZE]; unsigned char mac_temp[SHA224_DIGEST_SIZE]; sha224_final(&ctx->ctx_inside, digest_inside); sha224_update(&ctx->ctx_outside, digest_inside, SHA224_DIGEST_SIZE); sha224_final(&ctx->ctx_outside, mac_temp); memcpy(mac, mac_temp, mac_size); } void hmac_sha224(const unsigned char *key, unsigned int key_size, const unsigned char *message, unsigned int message_len, unsigned char *mac, unsigned mac_size) { hmac_sha224_ctx ctx; hmac_sha224_init(&ctx, key, key_size); hmac_sha224_update(&ctx, message, message_len); hmac_sha224_final(&ctx, mac, mac_size); } /* HMAC-SHA-256 functions */ void hmac_sha256_init(hmac_sha256_ctx *ctx, const unsigned char *key, unsigned int key_size) { unsigned int fill; unsigned int num; const unsigned char *key_used; unsigned char key_temp[SHA256_DIGEST_SIZE]; int i; if (key_size == SHA256_BLOCK_SIZE) { key_used = key; num = SHA256_BLOCK_SIZE; } else { if (key_size > SHA256_BLOCK_SIZE){ num = SHA256_DIGEST_SIZE; sha256(key, key_size, key_temp); key_used = key_temp; } else { /* key_size > SHA256_BLOCK_SIZE */ key_used = key; num = key_size; } fill = SHA256_BLOCK_SIZE - num; memset(ctx->block_ipad + num, 0x36, fill); memset(ctx->block_opad + num, 0x5c, fill); } for (i = 0; i < (int) num; i++) { ctx->block_ipad[i] = key_used[i] ^ 0x36; ctx->block_opad[i] = key_used[i] ^ 0x5c; } sha256_init(&ctx->ctx_inside); sha256_update(&ctx->ctx_inside, ctx->block_ipad, SHA256_BLOCK_SIZE); sha256_init(&ctx->ctx_outside); sha256_update(&ctx->ctx_outside, ctx->block_opad, SHA256_BLOCK_SIZE); /* for hmac_reinit */ memcpy(&ctx->ctx_inside_reinit, &ctx->ctx_inside, sizeof(sha256_ctx)); memcpy(&ctx->ctx_outside_reinit, &ctx->ctx_outside, sizeof(sha256_ctx)); } void hmac_sha256_reinit(hmac_sha256_ctx *ctx) { memcpy(&ctx->ctx_inside, &ctx->ctx_inside_reinit, sizeof(sha256_ctx)); memcpy(&ctx->ctx_outside, &ctx->ctx_outside_reinit, sizeof(sha256_ctx)); } void hmac_sha256_update(hmac_sha256_ctx *ctx, const unsigned char *message, unsigned int message_len) { sha256_update(&ctx->ctx_inside, message, message_len); } void hmac_sha256_final(hmac_sha256_ctx *ctx, unsigned char *mac, unsigned int mac_size) { unsigned char digest_inside[SHA256_DIGEST_SIZE]; unsigned char mac_temp[SHA256_DIGEST_SIZE]; sha256_final(&ctx->ctx_inside, digest_inside); sha256_update(&ctx->ctx_outside, digest_inside, SHA256_DIGEST_SIZE); sha256_final(&ctx->ctx_outside, mac_temp); memcpy(mac, mac_temp, mac_size); } void hmac_sha256(const unsigned char *key, unsigned int key_size, const unsigned char *message, unsigned int message_len, unsigned char *mac, unsigned mac_size) { hmac_sha256_ctx ctx; hmac_sha256_init(&ctx, key, key_size); hmac_sha256_update(&ctx, message, message_len); hmac_sha256_final(&ctx, mac, mac_size); } /* HMAC-SHA-384 functions */ void hmac_sha384_init(hmac_sha384_ctx *ctx, const unsigned char *key, unsigned int key_size) { unsigned int fill; unsigned int num; const unsigned char *key_used; unsigned char key_temp[SHA384_DIGEST_SIZE]; int i; if (key_size == SHA384_BLOCK_SIZE) { key_used = key; num = SHA384_BLOCK_SIZE; } else { if (key_size > SHA384_BLOCK_SIZE){ num = SHA384_DIGEST_SIZE; sha384(key, key_size, key_temp); key_used = key_temp; } else { /* key_size > SHA384_BLOCK_SIZE */ key_used = key; num = key_size; } fill = SHA384_BLOCK_SIZE - num; memset(ctx->block_ipad + num, 0x36, fill); memset(ctx->block_opad + num, 0x5c, fill); } for (i = 0; i < (int) num; i++) { ctx->block_ipad[i] = key_used[i] ^ 0x36; ctx->block_opad[i] = key_used[i] ^ 0x5c; } sha384_init(&ctx->ctx_inside); sha384_update(&ctx->ctx_inside, ctx->block_ipad, SHA384_BLOCK_SIZE); sha384_init(&ctx->ctx_outside); sha384_update(&ctx->ctx_outside, ctx->block_opad, SHA384_BLOCK_SIZE); /* for hmac_reinit */ memcpy(&ctx->ctx_inside_reinit, &ctx->ctx_inside, sizeof(sha384_ctx)); memcpy(&ctx->ctx_outside_reinit, &ctx->ctx_outside, sizeof(sha384_ctx)); } void hmac_sha384_reinit(hmac_sha384_ctx *ctx) { memcpy(&ctx->ctx_inside, &ctx->ctx_inside_reinit, sizeof(sha384_ctx)); memcpy(&ctx->ctx_outside, &ctx->ctx_outside_reinit, sizeof(sha384_ctx)); } void hmac_sha384_update(hmac_sha384_ctx *ctx, const unsigned char *message, unsigned int message_len) { sha384_update(&ctx->ctx_inside, message, message_len); } void hmac_sha384_final(hmac_sha384_ctx *ctx, unsigned char *mac, unsigned int mac_size) { unsigned char digest_inside[SHA384_DIGEST_SIZE]; unsigned char mac_temp[SHA384_DIGEST_SIZE]; sha384_final(&ctx->ctx_inside, digest_inside); sha384_update(&ctx->ctx_outside, digest_inside, SHA384_DIGEST_SIZE); sha384_final(&ctx->ctx_outside, mac_temp); memcpy(mac, mac_temp, mac_size); } void hmac_sha384(const unsigned char *key, unsigned int key_size, const unsigned char *message, unsigned int message_len, unsigned char *mac, unsigned mac_size) { hmac_sha384_ctx ctx; hmac_sha384_init(&ctx, key, key_size); hmac_sha384_update(&ctx, message, message_len); hmac_sha384_final(&ctx, mac, mac_size); } /* HMAC-SHA-512 functions */ void hmac_sha512_init(hmac_sha512_ctx *ctx, const unsigned char *key, unsigned int key_size) { unsigned int fill; unsigned int num; const unsigned char *key_used; unsigned char key_temp[SHA512_DIGEST_SIZE]; int i; if (key_size == SHA512_BLOCK_SIZE) { key_used = key; num = SHA512_BLOCK_SIZE; } else { if (key_size > SHA512_BLOCK_SIZE){ num = SHA512_DIGEST_SIZE; sha512(key, key_size, key_temp); key_used = key_temp; } else { /* key_size > SHA512_BLOCK_SIZE */ key_used = key; num = key_size; } fill = SHA512_BLOCK_SIZE - num; memset(ctx->block_ipad + num, 0x36, fill); memset(ctx->block_opad + num, 0x5c, fill); } for (i = 0; i < (int) num; i++) { ctx->block_ipad[i] = key_used[i] ^ 0x36; ctx->block_opad[i] = key_used[i] ^ 0x5c; } sha512_init(&ctx->ctx_inside); sha512_update(&ctx->ctx_inside, ctx->block_ipad, SHA512_BLOCK_SIZE); sha512_init(&ctx->ctx_outside); sha512_update(&ctx->ctx_outside, ctx->block_opad, SHA512_BLOCK_SIZE); /* for hmac_reinit */ memcpy(&ctx->ctx_inside_reinit, &ctx->ctx_inside, sizeof(sha512_ctx)); memcpy(&ctx->ctx_outside_reinit, &ctx->ctx_outside, sizeof(sha512_ctx)); } void hmac_sha512_reinit(hmac_sha512_ctx *ctx) { memcpy(&ctx->ctx_inside, &ctx->ctx_inside_reinit, sizeof(sha512_ctx)); memcpy(&ctx->ctx_outside, &ctx->ctx_outside_reinit, sizeof(sha512_ctx)); } void hmac_sha512_update(hmac_sha512_ctx *ctx, const unsigned char *message, unsigned int message_len) { sha512_update(&ctx->ctx_inside, message, message_len); } void hmac_sha512_final(hmac_sha512_ctx *ctx, unsigned char *mac, unsigned int mac_size) { unsigned char digest_inside[SHA512_DIGEST_SIZE]; unsigned char mac_temp[SHA512_DIGEST_SIZE]; sha512_final(&ctx->ctx_inside, digest_inside); sha512_update(&ctx->ctx_outside, digest_inside, SHA512_DIGEST_SIZE); sha512_final(&ctx->ctx_outside, mac_temp); memcpy(mac, mac_temp, mac_size); } void hmac_sha512(const unsigned char *key, unsigned int key_size, const unsigned char *message, unsigned int message_len, unsigned char *mac, unsigned mac_size) { hmac_sha512_ctx ctx; hmac_sha512_init(&ctx, key, key_size); hmac_sha512_update(&ctx, message, message_len); hmac_sha512_final(&ctx, mac, mac_size); } #ifdef TEST_VECTORS /* IETF Validation tests */ #include <stdio.h> #include <stdlib.h> void test(const char *vector, unsigned char *digest, unsigned int digest_size) { char output[2 * SHA512_DIGEST_SIZE + 1]; int i; output[2 * digest_size] = '\0'; for (i = 0; i < (int) digest_size ; i++) { sprintf(output + 2*i, "%02x", digest[i]); } printf("H: %s\n", output); if (strcmp(vector, output)) { fprintf(stderr, "Test failed.\n"); exit(1); } } int main(void) { static const char *vectors[] = { /* HMAC-SHA-224 */ "896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22", "a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44", "7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea", "6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a", "0e2aea68a90c8d37c988bcdb9fca6fa8", "95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e", "3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1", /* HMAC-SHA-256 */ "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7", "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843", "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe", "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b", "a3b6167473100ee06e0c796c2955552b", "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54", "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2", /* HMAC-SHA-384 */ "afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59c" "faea9ea9076ede7f4af152e8b2fa9cb6", "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e" "8e2240ca5e69e2c78b3239ecfab21649", "88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b" "2a5ab39dc13814b94e3ab6e101a34f27", "3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e" "6801dd23c4a7d679ccf8a386c674cffb", "3abf34c3503b2a23a46efc619baef897", "4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c6" "0c2ef6ab4030fe8296248df163f44952", "6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5" "a678cc31e799176d3860e6110c46523e", /* HMAC-SHA-512 */ "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cde" "daa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854", "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea250554" "9758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737", "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39" "bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb", "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3db" "a91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd", "415fad6271580a531d4179bc891d87a6", "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f352" "6b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598", "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944" "b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58" }; static char *messages[] = { "Hi There", "what do ya want for nothing?", NULL, NULL, "Test With Truncation", "Test Using Larger Than Block-Size Key - Hash Key First", "This is a test using a larger than block-size key " "and a larger than block-size data. The key needs" " to be hashed before being used by the HMAC algorithm." }; unsigned char mac[SHA512_DIGEST_SIZE]; unsigned char *keys[7]; unsigned int keys_len[7] = {20, 4, 20, 25, 20, 131, 131}; unsigned int messages2and3_len = 50; unsigned int mac_224_size, mac_256_size, mac_384_size, mac_512_size; int i; for (i = 0; i < 7; i++) { keys[i] = malloc(keys_len[i]); if (keys[i] == NULL) { fprintf(stderr, "Can't allocate memory\n"); return 1; } } memset(keys[0], 0x0b, keys_len[0]); strcpy((char *) keys[1], "Jefe"); memset(keys[2], 0xaa, keys_len[2]); for (i = 0; i < (int) keys_len[3]; i++) keys[3][i] = (unsigned char) i + 1; memset(keys[4], 0x0c, keys_len[4]); memset(keys[5], 0xaa, keys_len[5]); memset(keys[6], 0xaa, keys_len[6]); messages[2] = malloc(messages2and3_len + 1); messages[3] = malloc(messages2and3_len + 1); if (messages[2] == NULL || messages[3] == NULL) { fprintf(stderr, "Can't allocate memory\n"); return 1; } messages[2][messages2and3_len] = '\0'; messages[3][messages2and3_len] = '\0'; memset(messages[2], 0xdd, messages2and3_len); memset(messages[3], 0xcd, messages2and3_len); printf("HMAC-SHA-2 IETF Validation tests\n\n"); for (i = 0; i < 7; i++) { if (i != 4) { mac_224_size = SHA224_DIGEST_SIZE; mac_256_size = SHA256_DIGEST_SIZE; mac_384_size = SHA384_DIGEST_SIZE; mac_512_size = SHA512_DIGEST_SIZE; } else { mac_224_size = 128 / 8; mac_256_size = 128 / 8; mac_384_size = 128 / 8; mac_512_size = 128 / 8; } printf("Test %d:\n", i + 1); hmac_sha224(keys[i], keys_len[i], (unsigned char *) messages[i], strlen(messages[i]), mac, mac_224_size); test(vectors[i], mac, mac_224_size); hmac_sha256(keys[i], keys_len[i], (unsigned char *) messages[i], strlen(messages[i]), mac, mac_256_size); test(vectors[7 + i], mac, mac_256_size); hmac_sha384(keys[i], keys_len[i], (unsigned char *) messages[i], strlen(messages[i]), mac, mac_384_size); test(vectors[14 + i], mac, mac_384_size); hmac_sha512(keys[i], keys_len[i], (unsigned char *) messages[i], strlen(messages[i]), mac, mac_512_size); test(vectors[21 + i], mac, mac_512_size); } printf("All tests passed.\n"); return 0; } #endif /* TEST_VECTORS */ 07070100000004000081A400000000000000000000000162028917000015D3000000000000000000000000000000000000003900000000mmc-utils-0.1+git.20220208/3rdparty/hmac_sha/hmac_sha2.h/* * HMAC-SHA-224/256/384/512 implementation * Last update: 06/15/2005 * Issue date: 06/15/2005 * * Since this code has been incorporated into a GPLv2 project, it is * distributed under GPLv2 inside mmc-utils. The original BSD license * that the code was released under is included below for clarity. * * Copyright (C) 2005 Olivier Gay <olivier.gay@a3.epfl.ch> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef HMAC_SHA2_H #define HMAC_SHA2_H #include "sha2.h" #ifdef __cplusplus extern "C" { #endif typedef struct { sha224_ctx ctx_inside; sha224_ctx ctx_outside; /* for hmac_reinit */ sha224_ctx ctx_inside_reinit; sha224_ctx ctx_outside_reinit; unsigned char block_ipad[SHA224_BLOCK_SIZE]; unsigned char block_opad[SHA224_BLOCK_SIZE]; } hmac_sha224_ctx; typedef struct { sha256_ctx ctx_inside; sha256_ctx ctx_outside; /* for hmac_reinit */ sha256_ctx ctx_inside_reinit; sha256_ctx ctx_outside_reinit; unsigned char block_ipad[SHA256_BLOCK_SIZE]; unsigned char block_opad[SHA256_BLOCK_SIZE]; } hmac_sha256_ctx; typedef struct { sha384_ctx ctx_inside; sha384_ctx ctx_outside; /* for hmac_reinit */ sha384_ctx ctx_inside_reinit; sha384_ctx ctx_outside_reinit; unsigned char block_ipad[SHA384_BLOCK_SIZE]; unsigned char block_opad[SHA384_BLOCK_SIZE]; } hmac_sha384_ctx; typedef struct { sha512_ctx ctx_inside; sha512_ctx ctx_outside; /* for hmac_reinit */ sha512_ctx ctx_inside_reinit; sha512_ctx ctx_outside_reinit; unsigned char block_ipad[SHA512_BLOCK_SIZE]; unsigned char block_opad[SHA512_BLOCK_SIZE]; } hmac_sha512_ctx; void hmac_sha224_init(hmac_sha224_ctx *ctx, const unsigned char *key, unsigned int key_size); void hmac_sha224_reinit(hmac_sha224_ctx *ctx); void hmac_sha224_update(hmac_sha224_ctx *ctx, const unsigned char *message, unsigned int message_len); void hmac_sha224_final(hmac_sha224_ctx *ctx, unsigned char *mac, unsigned int mac_size); void hmac_sha224(const unsigned char *key, unsigned int key_size, const unsigned char *message, unsigned int message_len, unsigned char *mac, unsigned mac_size); void hmac_sha256_init(hmac_sha256_ctx *ctx, const unsigned char *key, unsigned int key_size); void hmac_sha256_reinit(hmac_sha256_ctx *ctx); void hmac_sha256_update(hmac_sha256_ctx *ctx, const unsigned char *message, unsigned int message_len); void hmac_sha256_final(hmac_sha256_ctx *ctx, unsigned char *mac, unsigned int mac_size); void hmac_sha256(const unsigned char *key, unsigned int key_size, const unsigned char *message, unsigned int message_len, unsigned char *mac, unsigned mac_size); void hmac_sha384_init(hmac_sha384_ctx *ctx, const unsigned char *key, unsigned int key_size); void hmac_sha384_reinit(hmac_sha384_ctx *ctx); void hmac_sha384_update(hmac_sha384_ctx *ctx, const unsigned char *message, unsigned int message_len); void hmac_sha384_final(hmac_sha384_ctx *ctx, unsigned char *mac, unsigned int mac_size); void hmac_sha384(const unsigned char *key, unsigned int key_size, const unsigned char *message, unsigned int message_len, unsigned char *mac, unsigned mac_size); void hmac_sha512_init(hmac_sha512_ctx *ctx, const unsigned char *key, unsigned int key_size); void hmac_sha512_reinit(hmac_sha512_ctx *ctx); void hmac_sha512_update(hmac_sha512_ctx *ctx, const unsigned char *message, unsigned int message_len); void hmac_sha512_final(hmac_sha512_ctx *ctx, unsigned char *mac, unsigned int mac_size); void hmac_sha512(const unsigned char *key, unsigned int key_size, const unsigned char *message, unsigned int message_len, unsigned char *mac, unsigned mac_size); #ifdef __cplusplus } #endif #endif /* !HMAC_SHA2_H */ 07070100000005000081A40000000000000000000000016202891700008189000000000000000000000000000000000000003400000000mmc-utils-0.1+git.20220208/3rdparty/hmac_sha/sha2.c/* * FIPS 180-2 SHA-224/256/384/512 implementation * Last update: 02/02/2007 * Issue date: 04/30/2005 * * Since this code has been incorporated into a GPLv2 project, it is * distributed under GPLv2 inside mmc-utils. The original BSD license * that the code was released under is included below for clarity. * * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #define UNROLL_LOOPS /* Enable loops unrolling */ #endif #include <string.h> #include "sha2.h" #define SHFR(x, n) (x >> n) #define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) #define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) #define CH(x, y, z) ((x & y) ^ (~x & z)) #define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) #define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) #define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) #define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3)) #define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10)) #define SHA512_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39)) #define SHA512_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41)) #define SHA512_F3(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHFR(x, 7)) #define SHA512_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x, 6)) #define UNPACK32(x, str) \ { \ *((str) + 3) = (uint8) ((x) ); \ *((str) + 2) = (uint8) ((x) >> 8); \ *((str) + 1) = (uint8) ((x) >> 16); \ *((str) + 0) = (uint8) ((x) >> 24); \ } #define PACK32(str, x) \ { \ *(x) = ((uint32) *((str) + 3) ) \ | ((uint32) *((str) + 2) << 8) \ | ((uint32) *((str) + 1) << 16) \ | ((uint32) *((str) + 0) << 24); \ } #define UNPACK64(x, str) \ { \ *((str) + 7) = (uint8) ((x) ); \ *((str) + 6) = (uint8) ((x) >> 8); \ *((str) + 5) = (uint8) ((x) >> 16); \ *((str) + 4) = (uint8) ((x) >> 24); \ *((str) + 3) = (uint8) ((x) >> 32); \ *((str) + 2) = (uint8) ((x) >> 40); \ *((str) + 1) = (uint8) ((x) >> 48); \ *((str) + 0) = (uint8) ((x) >> 56); \ } #define PACK64(str, x) \ { \ *(x) = ((uint64) *((str) + 7) ) \ | ((uint64) *((str) + 6) << 8) \ | ((uint64) *((str) + 5) << 16) \ | ((uint64) *((str) + 4) << 24) \ | ((uint64) *((str) + 3) << 32) \ | ((uint64) *((str) + 2) << 40) \ | ((uint64) *((str) + 1) << 48) \ | ((uint64) *((str) + 0) << 56); \ } /* Macros used for loops unrolling */ #define SHA256_SCR(i) \ { \ w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \ + SHA256_F3(w[i - 15]) + w[i - 16]; \ } #define SHA512_SCR(i) \ { \ w[i] = SHA512_F4(w[i - 2]) + w[i - 7] \ + SHA512_F3(w[i - 15]) + w[i - 16]; \ } #define SHA256_EXP(a, b, c, d, e, f, g, h, j) \ { \ t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \ + sha256_k[j] + w[j]; \ t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ wv[d] += t1; \ wv[h] = t1 + t2; \ } #define SHA512_EXP(a, b, c, d, e, f, g ,h, j) \ { \ t1 = wv[h] + SHA512_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \ + sha512_k[j] + w[j]; \ t2 = SHA512_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ wv[d] += t1; \ wv[h] = t1 + t2; \ } uint32 sha224_h0[8] = {0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; uint32 sha256_h0[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; uint64 sha384_h0[8] = {0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL}; uint64 sha512_h0[8] = {0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL}; uint32 sha256_k[64] = {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; uint64 sha512_k[80] = {0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL}; /* SHA-256 functions */ void sha256_transf(sha256_ctx *ctx, const unsigned char *message, unsigned int block_nb) { uint32 w[64]; uint32 wv[8]; uint32 t1, t2; const unsigned char *sub_block; int i; #ifndef UNROLL_LOOPS int j; #endif for (i = 0; i < (int) block_nb; i++) { sub_block = message + (i << 6); #ifndef UNROLL_LOOPS for (j = 0; j < 16; j++) { PACK32(&sub_block[j << 2], &w[j]); } for (j = 16; j < 64; j++) { SHA256_SCR(j); } for (j = 0; j < 8; j++) { wv[j] = ctx->h[j]; } for (j = 0; j < 64; j++) { t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j]; t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); wv[7] = wv[6]; wv[6] = wv[5]; wv[5] = wv[4]; wv[4] = wv[3] + t1; wv[3] = wv[2]; wv[2] = wv[1]; wv[1] = wv[0]; wv[0] = t1 + t2; } for (j = 0; j < 8; j++) { ctx->h[j] += wv[j]; } #else PACK32(&sub_block[ 0], &w[ 0]); PACK32(&sub_block[ 4], &w[ 1]); PACK32(&sub_block[ 8], &w[ 2]); PACK32(&sub_block[12], &w[ 3]); PACK32(&sub_block[16], &w[ 4]); PACK32(&sub_block[20], &w[ 5]); PACK32(&sub_block[24], &w[ 6]); PACK32(&sub_block[28], &w[ 7]); PACK32(&sub_block[32], &w[ 8]); PACK32(&sub_block[36], &w[ 9]); PACK32(&sub_block[40], &w[10]); PACK32(&sub_block[44], &w[11]); PACK32(&sub_block[48], &w[12]); PACK32(&sub_block[52], &w[13]); PACK32(&sub_block[56], &w[14]); PACK32(&sub_block[60], &w[15]); SHA256_SCR(16); SHA256_SCR(17); SHA256_SCR(18); SHA256_SCR(19); SHA256_SCR(20); SHA256_SCR(21); SHA256_SCR(22); SHA256_SCR(23); SHA256_SCR(24); SHA256_SCR(25); SHA256_SCR(26); SHA256_SCR(27); SHA256_SCR(28); SHA256_SCR(29); SHA256_SCR(30); SHA256_SCR(31); SHA256_SCR(32); SHA256_SCR(33); SHA256_SCR(34); SHA256_SCR(35); SHA256_SCR(36); SHA256_SCR(37); SHA256_SCR(38); SHA256_SCR(39); SHA256_SCR(40); SHA256_SCR(41); SHA256_SCR(42); SHA256_SCR(43); SHA256_SCR(44); SHA256_SCR(45); SHA256_SCR(46); SHA256_SCR(47); SHA256_SCR(48); SHA256_SCR(49); SHA256_SCR(50); SHA256_SCR(51); SHA256_SCR(52); SHA256_SCR(53); SHA256_SCR(54); SHA256_SCR(55); SHA256_SCR(56); SHA256_SCR(57); SHA256_SCR(58); SHA256_SCR(59); SHA256_SCR(60); SHA256_SCR(61); SHA256_SCR(62); SHA256_SCR(63); wv[0] = ctx->h[0]; wv[1] = ctx->h[1]; wv[2] = ctx->h[2]; wv[3] = ctx->h[3]; wv[4] = ctx->h[4]; wv[5] = ctx->h[5]; wv[6] = ctx->h[6]; wv[7] = ctx->h[7]; SHA256_EXP(0,1,2,3,4,5,6,7, 0); SHA256_EXP(7,0,1,2,3,4,5,6, 1); SHA256_EXP(6,7,0,1,2,3,4,5, 2); SHA256_EXP(5,6,7,0,1,2,3,4, 3); SHA256_EXP(4,5,6,7,0,1,2,3, 4); SHA256_EXP(3,4,5,6,7,0,1,2, 5); SHA256_EXP(2,3,4,5,6,7,0,1, 6); SHA256_EXP(1,2,3,4,5,6,7,0, 7); SHA256_EXP(0,1,2,3,4,5,6,7, 8); SHA256_EXP(7,0,1,2,3,4,5,6, 9); SHA256_EXP(6,7,0,1,2,3,4,5,10); SHA256_EXP(5,6,7,0,1,2,3,4,11); SHA256_EXP(4,5,6,7,0,1,2,3,12); SHA256_EXP(3,4,5,6,7,0,1,2,13); SHA256_EXP(2,3,4,5,6,7,0,1,14); SHA256_EXP(1,2,3,4,5,6,7,0,15); SHA256_EXP(0,1,2,3,4,5,6,7,16); SHA256_EXP(7,0,1,2,3,4,5,6,17); SHA256_EXP(6,7,0,1,2,3,4,5,18); SHA256_EXP(5,6,7,0,1,2,3,4,19); SHA256_EXP(4,5,6,7,0,1,2,3,20); SHA256_EXP(3,4,5,6,7,0,1,2,21); SHA256_EXP(2,3,4,5,6,7,0,1,22); SHA256_EXP(1,2,3,4,5,6,7,0,23); SHA256_EXP(0,1,2,3,4,5,6,7,24); SHA256_EXP(7,0,1,2,3,4,5,6,25); SHA256_EXP(6,7,0,1,2,3,4,5,26); SHA256_EXP(5,6,7,0,1,2,3,4,27); SHA256_EXP(4,5,6,7,0,1,2,3,28); SHA256_EXP(3,4,5,6,7,0,1,2,29); SHA256_EXP(2,3,4,5,6,7,0,1,30); SHA256_EXP(1,2,3,4,5,6,7,0,31); SHA256_EXP(0,1,2,3,4,5,6,7,32); SHA256_EXP(7,0,1,2,3,4,5,6,33); SHA256_EXP(6,7,0,1,2,3,4,5,34); SHA256_EXP(5,6,7,0,1,2,3,4,35); SHA256_EXP(4,5,6,7,0,1,2,3,36); SHA256_EXP(3,4,5,6,7,0,1,2,37); SHA256_EXP(2,3,4,5,6,7,0,1,38); SHA256_EXP(1,2,3,4,5,6,7,0,39); SHA256_EXP(0,1,2,3,4,5,6,7,40); SHA256_EXP(7,0,1,2,3,4,5,6,41); SHA256_EXP(6,7,0,1,2,3,4,5,42); SHA256_EXP(5,6,7,0,1,2,3,4,43); SHA256_EXP(4,5,6,7,0,1,2,3,44); SHA256_EXP(3,4,5,6,7,0,1,2,45); SHA256_EXP(2,3,4,5,6,7,0,1,46); SHA256_EXP(1,2,3,4,5,6,7,0,47); SHA256_EXP(0,1,2,3,4,5,6,7,48); SHA256_EXP(7,0,1,2,3,4,5,6,49); SHA256_EXP(6,7,0,1,2,3,4,5,50); SHA256_EXP(5,6,7,0,1,2,3,4,51); SHA256_EXP(4,5,6,7,0,1,2,3,52); SHA256_EXP(3,4,5,6,7,0,1,2,53); SHA256_EXP(2,3,4,5,6,7,0,1,54); SHA256_EXP(1,2,3,4,5,6,7,0,55); SHA256_EXP(0,1,2,3,4,5,6,7,56); SHA256_EXP(7,0,1,2,3,4,5,6,57); SHA256_EXP(6,7,0,1,2,3,4,5,58); SHA256_EXP(5,6,7,0,1,2,3,4,59); SHA256_EXP(4,5,6,7,0,1,2,3,60); SHA256_EXP(3,4,5,6,7,0,1,2,61); SHA256_EXP(2,3,4,5,6,7,0,1,62); SHA256_EXP(1,2,3,4,5,6,7,0,63); ctx->h[0] += wv[0]; ctx->h[1] += wv[1]; ctx->h[2] += wv[2]; ctx->h[3] += wv[3]; ctx->h[4] += wv[4]; ctx->h[5] += wv[5]; ctx->h[6] += wv[6]; ctx->h[7] += wv[7]; #endif /* !UNROLL_LOOPS */ } } void sha256(const unsigned char *message, unsigned int len, unsigned char *digest) { sha256_ctx ctx; sha256_init(&ctx); sha256_update(&ctx, message, len); sha256_final(&ctx, digest); } void sha256_init(sha256_ctx *ctx) { #ifndef UNROLL_LOOPS int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha256_h0[i]; } #else ctx->h[0] = sha256_h0[0]; ctx->h[1] = sha256_h0[1]; ctx->h[2] = sha256_h0[2]; ctx->h[3] = sha256_h0[3]; ctx->h[4] = sha256_h0[4]; ctx->h[5] = sha256_h0[5]; ctx->h[6] = sha256_h0[6]; ctx->h[7] = sha256_h0[7]; #endif /* !UNROLL_LOOPS */ ctx->len = 0; ctx->tot_len = 0; } void sha256_update(sha256_ctx *ctx, const unsigned char *message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; const unsigned char *shifted_message; tmp_len = SHA256_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA256_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA256_BLOCK_SIZE; shifted_message = message + rem_len; sha256_transf(ctx, ctx->block, 1); sha256_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA256_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 6], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 6; } void sha256_final(sha256_ctx *ctx, unsigned char *digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; #ifndef UNROLL_LOOPS int i; #endif block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) < (ctx->len % SHA256_BLOCK_SIZE))); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 6; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); sha256_transf(ctx, ctx->block, block_nb); #ifndef UNROLL_LOOPS for (i = 0 ; i < 8; i++) { UNPACK32(ctx->h[i], &digest[i << 2]); } #else UNPACK32(ctx->h[0], &digest[ 0]); UNPACK32(ctx->h[1], &digest[ 4]); UNPACK32(ctx->h[2], &digest[ 8]); UNPACK32(ctx->h[3], &digest[12]); UNPACK32(ctx->h[4], &digest[16]); UNPACK32(ctx->h[5], &digest[20]); UNPACK32(ctx->h[6], &digest[24]); UNPACK32(ctx->h[7], &digest[28]); #endif /* !UNROLL_LOOPS */ } /* SHA-512 functions */ void sha512_transf(sha512_ctx *ctx, const unsigned char *message, unsigned int block_nb) { uint64 w[80]; uint64 wv[8]; uint64 t1, t2; const unsigned char *sub_block; int i, j; for (i = 0; i < (int) block_nb; i++) { sub_block = message + (i << 7); #ifndef UNROLL_LOOPS for (j = 0; j < 16; j++) { PACK64(&sub_block[j << 3], &w[j]); } for (j = 16; j < 80; j++) { SHA512_SCR(j); } for (j = 0; j < 8; j++) { wv[j] = ctx->h[j]; } for (j = 0; j < 80; j++) { t1 = wv[7] + SHA512_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha512_k[j] + w[j]; t2 = SHA512_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); wv[7] = wv[6]; wv[6] = wv[5]; wv[5] = wv[4]; wv[4] = wv[3] + t1; wv[3] = wv[2]; wv[2] = wv[1]; wv[1] = wv[0]; wv[0] = t1 + t2; } for (j = 0; j < 8; j++) { ctx->h[j] += wv[j]; } #else PACK64(&sub_block[ 0], &w[ 0]); PACK64(&sub_block[ 8], &w[ 1]); PACK64(&sub_block[ 16], &w[ 2]); PACK64(&sub_block[ 24], &w[ 3]); PACK64(&sub_block[ 32], &w[ 4]); PACK64(&sub_block[ 40], &w[ 5]); PACK64(&sub_block[ 48], &w[ 6]); PACK64(&sub_block[ 56], &w[ 7]); PACK64(&sub_block[ 64], &w[ 8]); PACK64(&sub_block[ 72], &w[ 9]); PACK64(&sub_block[ 80], &w[10]); PACK64(&sub_block[ 88], &w[11]); PACK64(&sub_block[ 96], &w[12]); PACK64(&sub_block[104], &w[13]); PACK64(&sub_block[112], &w[14]); PACK64(&sub_block[120], &w[15]); SHA512_SCR(16); SHA512_SCR(17); SHA512_SCR(18); SHA512_SCR(19); SHA512_SCR(20); SHA512_SCR(21); SHA512_SCR(22); SHA512_SCR(23); SHA512_SCR(24); SHA512_SCR(25); SHA512_SCR(26); SHA512_SCR(27); SHA512_SCR(28); SHA512_SCR(29); SHA512_SCR(30); SHA512_SCR(31); SHA512_SCR(32); SHA512_SCR(33); SHA512_SCR(34); SHA512_SCR(35); SHA512_SCR(36); SHA512_SCR(37); SHA512_SCR(38); SHA512_SCR(39); SHA512_SCR(40); SHA512_SCR(41); SHA512_SCR(42); SHA512_SCR(43); SHA512_SCR(44); SHA512_SCR(45); SHA512_SCR(46); SHA512_SCR(47); SHA512_SCR(48); SHA512_SCR(49); SHA512_SCR(50); SHA512_SCR(51); SHA512_SCR(52); SHA512_SCR(53); SHA512_SCR(54); SHA512_SCR(55); SHA512_SCR(56); SHA512_SCR(57); SHA512_SCR(58); SHA512_SCR(59); SHA512_SCR(60); SHA512_SCR(61); SHA512_SCR(62); SHA512_SCR(63); SHA512_SCR(64); SHA512_SCR(65); SHA512_SCR(66); SHA512_SCR(67); SHA512_SCR(68); SHA512_SCR(69); SHA512_SCR(70); SHA512_SCR(71); SHA512_SCR(72); SHA512_SCR(73); SHA512_SCR(74); SHA512_SCR(75); SHA512_SCR(76); SHA512_SCR(77); SHA512_SCR(78); SHA512_SCR(79); wv[0] = ctx->h[0]; wv[1] = ctx->h[1]; wv[2] = ctx->h[2]; wv[3] = ctx->h[3]; wv[4] = ctx->h[4]; wv[5] = ctx->h[5]; wv[6] = ctx->h[6]; wv[7] = ctx->h[7]; j = 0; do { SHA512_EXP(0,1,2,3,4,5,6,7,j); j++; SHA512_EXP(7,0,1,2,3,4,5,6,j); j++; SHA512_EXP(6,7,0,1,2,3,4,5,j); j++; SHA512_EXP(5,6,7,0,1,2,3,4,j); j++; SHA512_EXP(4,5,6,7,0,1,2,3,j); j++; SHA512_EXP(3,4,5,6,7,0,1,2,j); j++; SHA512_EXP(2,3,4,5,6,7,0,1,j); j++; SHA512_EXP(1,2,3,4,5,6,7,0,j); j++; } while (j < 80); ctx->h[0] += wv[0]; ctx->h[1] += wv[1]; ctx->h[2] += wv[2]; ctx->h[3] += wv[3]; ctx->h[4] += wv[4]; ctx->h[5] += wv[5]; ctx->h[6] += wv[6]; ctx->h[7] += wv[7]; #endif /* !UNROLL_LOOPS */ } } void sha512(const unsigned char *message, unsigned int len, unsigned char *digest) { sha512_ctx ctx; sha512_init(&ctx); sha512_update(&ctx, message, len); sha512_final(&ctx, digest); } void sha512_init(sha512_ctx *ctx) { #ifndef UNROLL_LOOPS int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha512_h0[i]; } #else ctx->h[0] = sha512_h0[0]; ctx->h[1] = sha512_h0[1]; ctx->h[2] = sha512_h0[2]; ctx->h[3] = sha512_h0[3]; ctx->h[4] = sha512_h0[4]; ctx->h[5] = sha512_h0[5]; ctx->h[6] = sha512_h0[6]; ctx->h[7] = sha512_h0[7]; #endif /* !UNROLL_LOOPS */ ctx->len = 0; ctx->tot_len = 0; } void sha512_update(sha512_ctx *ctx, const unsigned char *message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; const unsigned char *shifted_message; tmp_len = SHA512_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA512_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA512_BLOCK_SIZE; shifted_message = message + rem_len; sha512_transf(ctx, ctx->block, 1); sha512_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA512_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 7], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 7; } void sha512_final(sha512_ctx *ctx, unsigned char *digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; #ifndef UNROLL_LOOPS int i; #endif block_nb = 1 + ((SHA512_BLOCK_SIZE - 17) < (ctx->len % SHA512_BLOCK_SIZE)); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 7; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); sha512_transf(ctx, ctx->block, block_nb); #ifndef UNROLL_LOOPS for (i = 0 ; i < 8; i++) { UNPACK64(ctx->h[i], &digest[i << 3]); } #else UNPACK64(ctx->h[0], &digest[ 0]); UNPACK64(ctx->h[1], &digest[ 8]); UNPACK64(ctx->h[2], &digest[16]); UNPACK64(ctx->h[3], &digest[24]); UNPACK64(ctx->h[4], &digest[32]); UNPACK64(ctx->h[5], &digest[40]); UNPACK64(ctx->h[6], &digest[48]); UNPACK64(ctx->h[7], &digest[56]); #endif /* !UNROLL_LOOPS */ } /* SHA-384 functions */ void sha384(const unsigned char *message, unsigned int len, unsigned char *digest) { sha384_ctx ctx; sha384_init(&ctx); sha384_update(&ctx, message, len); sha384_final(&ctx, digest); } void sha384_init(sha384_ctx *ctx) { #ifndef UNROLL_LOOPS int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha384_h0[i]; } #else ctx->h[0] = sha384_h0[0]; ctx->h[1] = sha384_h0[1]; ctx->h[2] = sha384_h0[2]; ctx->h[3] = sha384_h0[3]; ctx->h[4] = sha384_h0[4]; ctx->h[5] = sha384_h0[5]; ctx->h[6] = sha384_h0[6]; ctx->h[7] = sha384_h0[7]; #endif /* !UNROLL_LOOPS */ ctx->len = 0; ctx->tot_len = 0; } void sha384_update(sha384_ctx *ctx, const unsigned char *message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; const unsigned char *shifted_message; tmp_len = SHA384_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA384_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA384_BLOCK_SIZE; shifted_message = message + rem_len; sha512_transf(ctx, ctx->block, 1); sha512_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA384_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 7], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 7; } void sha384_final(sha384_ctx *ctx, unsigned char *digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; #ifndef UNROLL_LOOPS int i; #endif block_nb = (1 + ((SHA384_BLOCK_SIZE - 17) < (ctx->len % SHA384_BLOCK_SIZE))); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 7; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); sha512_transf(ctx, ctx->block, block_nb); #ifndef UNROLL_LOOPS for (i = 0 ; i < 6; i++) { UNPACK64(ctx->h[i], &digest[i << 3]); } #else UNPACK64(ctx->h[0], &digest[ 0]); UNPACK64(ctx->h[1], &digest[ 8]); UNPACK64(ctx->h[2], &digest[16]); UNPACK64(ctx->h[3], &digest[24]); UNPACK64(ctx->h[4], &digest[32]); UNPACK64(ctx->h[5], &digest[40]); #endif /* !UNROLL_LOOPS */ } /* SHA-224 functions */ void sha224(const unsigned char *message, unsigned int len, unsigned char *digest) { sha224_ctx ctx; sha224_init(&ctx); sha224_update(&ctx, message, len); sha224_final(&ctx, digest); } void sha224_init(sha224_ctx *ctx) { #ifndef UNROLL_LOOPS int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha224_h0[i]; } #else ctx->h[0] = sha224_h0[0]; ctx->h[1] = sha224_h0[1]; ctx->h[2] = sha224_h0[2]; ctx->h[3] = sha224_h0[3]; ctx->h[4] = sha224_h0[4]; ctx->h[5] = sha224_h0[5]; ctx->h[6] = sha224_h0[6]; ctx->h[7] = sha224_h0[7]; #endif /* !UNROLL_LOOPS */ ctx->len = 0; ctx->tot_len = 0; } void sha224_update(sha224_ctx *ctx, const unsigned char *message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; const unsigned char *shifted_message; tmp_len = SHA224_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA224_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA224_BLOCK_SIZE; shifted_message = message + rem_len; sha256_transf(ctx, ctx->block, 1); sha256_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA224_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 6], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 6; } void sha224_final(sha224_ctx *ctx, unsigned char *digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; #ifndef UNROLL_LOOPS int i; #endif block_nb = (1 + ((SHA224_BLOCK_SIZE - 9) < (ctx->len % SHA224_BLOCK_SIZE))); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 6; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); sha256_transf(ctx, ctx->block, block_nb); #ifndef UNROLL_LOOPS for (i = 0 ; i < 7; i++) { UNPACK32(ctx->h[i], &digest[i << 2]); } #else UNPACK32(ctx->h[0], &digest[ 0]); UNPACK32(ctx->h[1], &digest[ 4]); UNPACK32(ctx->h[2], &digest[ 8]); UNPACK32(ctx->h[3], &digest[12]); UNPACK32(ctx->h[4], &digest[16]); UNPACK32(ctx->h[5], &digest[20]); UNPACK32(ctx->h[6], &digest[24]); #endif /* !UNROLL_LOOPS */ } #ifdef TEST_VECTORS /* FIPS 180-2 Validation tests */ #include <stdio.h> #include <stdlib.h> void test(const char *vector, unsigned char *digest, unsigned int digest_size) { char output[2 * SHA512_DIGEST_SIZE + 1]; int i; output[2 * digest_size] = '\0'; for (i = 0; i < (int) digest_size ; i++) { sprintf(output + 2 * i, "%02x", digest[i]); } printf("H: %s\n", output); if (strcmp(vector, output)) { fprintf(stderr, "Test failed.\n"); exit(EXIT_FAILURE); } } int main(void) { static const char *vectors[4][3] = { /* SHA-224 */ { "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525", "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67", }, /* SHA-256 */ { "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0", }, /* SHA-384 */ { "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed" "8086072ba1e7cc2358baeca134c825a7", "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712" "fcc7c71a557e2db966c3e9fa91746039", "9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b" "07b8b3dc38ecc4ebae97ddd87f3d8985", }, /* SHA-512 */ { "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018" "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909", "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb" "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b" } }; static const char message1[] = "abc"; static const char message2a[] = "abcdbcdecdefdefgefghfghighijhi" "jkijkljklmklmnlmnomnopnopq"; static const char message2b[] = "abcdefghbcdefghicdefghijdefghijkefghij" "klfghijklmghijklmnhijklmnoijklmnopjklm" "nopqklmnopqrlmnopqrsmnopqrstnopqrstu"; unsigned char *message3; unsigned int message3_len = 1000000; unsigned char digest[SHA512_DIGEST_SIZE]; message3 = malloc(message3_len); if (message3 == NULL) { fprintf(stderr, "Can't allocate memory\n"); return -1; } memset(message3, 'a', message3_len); printf("SHA-2 FIPS 180-2 Validation tests\n\n"); printf("SHA-224 Test vectors\n"); sha224((const unsigned char *) message1, strlen(message1), digest); test(vectors[0][0], digest, SHA224_DIGEST_SIZE); sha224((const unsigned char *) message2a, strlen(message2a), digest); test(vectors[0][1], digest, SHA224_DIGEST_SIZE); sha224(message3, message3_len, digest); test(vectors[0][2], digest, SHA224_DIGEST_SIZE); printf("\n"); printf("SHA-256 Test vectors\n"); sha256((const unsigned char *) message1, strlen(message1), digest); test(vectors[1][0], digest, SHA256_DIGEST_SIZE); sha256((const unsigned char *) message2a, strlen(message2a), digest); test(vectors[1][1], digest, SHA256_DIGEST_SIZE); sha256(message3, message3_len, digest); test(vectors[1][2], digest, SHA256_DIGEST_SIZE); printf("\n"); printf("SHA-384 Test vectors\n"); sha384((const unsigned char *) message1, strlen(message1), digest); test(vectors[2][0], digest, SHA384_DIGEST_SIZE); sha384((const unsigned char *)message2b, strlen(message2b), digest); test(vectors[2][1], digest, SHA384_DIGEST_SIZE); sha384(message3, message3_len, digest); test(vectors[2][2], digest, SHA384_DIGEST_SIZE); printf("\n"); printf("SHA-512 Test vectors\n"); sha512((const unsigned char *) message1, strlen(message1), digest); test(vectors[3][0], digest, SHA512_DIGEST_SIZE); sha512((const unsigned char *) message2b, strlen(message2b), digest); test(vectors[3][1], digest, SHA512_DIGEST_SIZE); sha512(message3, message3_len, digest); test(vectors[3][2], digest, SHA512_DIGEST_SIZE); printf("\n"); printf("All tests passed.\n"); return 0; } #endif /* TEST_VECTORS */ 07070100000006000081A40000000000000000000000016202891700000FAF000000000000000000000000000000000000003400000000mmc-utils-0.1+git.20220208/3rdparty/hmac_sha/sha2.h/* * FIPS 180-2 SHA-224/256/384/512 implementation * Last update: 02/02/2007 * Issue date: 04/30/2005 * * Since this code has been incorporated into a GPLv2 project, it is * distributed under GPLv2 inside mmc-utils. The original BSD license * that the code was released under is included below for clarity. * * Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef SHA2_H #define SHA2_H #define SHA224_DIGEST_SIZE ( 224 / 8) #define SHA256_DIGEST_SIZE ( 256 / 8) #define SHA384_DIGEST_SIZE ( 384 / 8) #define SHA512_DIGEST_SIZE ( 512 / 8) #define SHA256_BLOCK_SIZE ( 512 / 8) #define SHA512_BLOCK_SIZE (1024 / 8) #define SHA384_BLOCK_SIZE SHA512_BLOCK_SIZE #define SHA224_BLOCK_SIZE SHA256_BLOCK_SIZE #ifndef SHA2_TYPES #define SHA2_TYPES typedef unsigned char uint8; typedef unsigned int uint32; typedef unsigned long long uint64; #endif #ifdef __cplusplus extern "C" { #endif typedef struct { unsigned int tot_len; unsigned int len; unsigned char block[2 * SHA256_BLOCK_SIZE]; uint32 h[8]; } sha256_ctx; typedef struct { unsigned int tot_len; unsigned int len; unsigned char block[2 * SHA512_BLOCK_SIZE]; uint64 h[8]; } sha512_ctx; typedef sha512_ctx sha384_ctx; typedef sha256_ctx sha224_ctx; void sha224_init(sha224_ctx *ctx); void sha224_update(sha224_ctx *ctx, const unsigned char *message, unsigned int len); void sha224_final(sha224_ctx *ctx, unsigned char *digest); void sha224(const unsigned char *message, unsigned int len, unsigned char *digest); void sha256_init(sha256_ctx * ctx); void sha256_update(sha256_ctx *ctx, const unsigned char *message, unsigned int len); void sha256_final(sha256_ctx *ctx, unsigned char *digest); void sha256(const unsigned char *message, unsigned int len, unsigned char *digest); void sha384_init(sha384_ctx *ctx); void sha384_update(sha384_ctx *ctx, const unsigned char *message, unsigned int len); void sha384_final(sha384_ctx *ctx, unsigned char *digest); void sha384(const unsigned char *message, unsigned int len, unsigned char *digest); void sha512_init(sha512_ctx *ctx); void sha512_update(sha512_ctx *ctx, const unsigned char *message, unsigned int len); void sha512_final(sha512_ctx *ctx, unsigned char *digest); void sha512(const unsigned char *message, unsigned int len, unsigned char *digest); #ifdef __cplusplus } #endif #endif /* !SHA2_H */ 07070100000007000081A400000000000000000000000162028917000001E1000000000000000000000000000000000000002600000000mmc-utils-0.1+git.20220208/Android.mkLOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES:= mmc.c mmc_cmds.c LOCAL_SRC_FILES += 3rdparty/hmac_sha/sha2.c 3rdparty/hmac_sha/hmac_sha2.c LOCAL_MODULE := mmc_utils LOCAL_SHARED_LIBRARIES := libcutils libc LOCAL_C_INCLUDES+= $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/mmc-utils include $(BUILD_EXECUTABLE) 07070100000008000081A40000000000000000000000016202891700000413000000000000000000000000000000000000002400000000mmc-utils-0.1+git.20220208/MakefileCC ?= gcc AM_CFLAGS = -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 CFLAGS ?= -g -O2 objects = \ mmc.o \ mmc_cmds.o \ lsmmc.o \ 3rdparty/hmac_sha/hmac_sha2.o \ 3rdparty/hmac_sha/sha2.o CHECKFLAGS = -Wall -Werror -Wuninitialized -Wundef DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@ override CFLAGS := $(CHECKFLAGS) $(AM_CFLAGS) $(CFLAGS) INSTALL = install prefix ?= /usr/local bindir = $(prefix)/bin LIBS= RESTORE_LIBS= progs = mmc # make C=1 to enable sparse ifdef C check = sparse $(CHECKFLAGS) endif all: $(progs) manpages .c.o: ifdef C $(check) $< endif $(CC) $(CPPFLAGS) $(CFLAGS) $(DEPFLAGS) -c $< -o $@ mmc: $(objects) $(CC) $(CFLAGS) -o $@ $(objects) $(LDFLAGS) $(LIBS) manpages: $(MAKE) -C man install-man: $(MAKE) -C man install clean: rm -f $(progs) $(objects) $(MAKE) -C man clean install: $(progs) install-man $(INSTALL) -m755 -d $(DESTDIR)$(bindir) $(INSTALL) $(progs) $(DESTDIR)$(bindir) -include $(foreach obj,$(objects), $(dir $(obj))/.$(notdir $(obj)).d) .PHONY: all clean install manpages install-man 07070100000009000081A4000000000000000000000001620289170000035A000000000000000000000000000000000000002200000000mmc-utils-0.1+git.20220208/READMEMMC tools (mmc-utils) ===================== mmc-utils is a tool for configuring MMC storage devices from userspace. Contribution guidelines ----------------------- The project works using a mailing list patch submission process, similar to the process used for the Linux kernel itself. One can document themselves by reading how to submit a patch in the official Linux kernel documentation: https://www.kernel.org/doc/html/latest/process/submitting-patches.html Not all sections apply but it should be a good way to get started. A patch should be sent as a mail (not as an attachement, see documentation above) to the linux-mmc@vger.kernel.org mailing list with maintainers as Cc recipients. Maintainers ----------- Avri Altman <avri.altman@wdc.com> Ulf Hansson <ulf.hansson@linaro.org> License ------- This project is licensed under GPL-2.0-only. 0707010000000A000081A4000000000000000000000001620289170000C8DD000000000000000000000000000000000000002300000000mmc-utils-0.1+git.20220208/lsmmc.c/* * Copyright (C) ST-Ericsson SA 2010-2011 * Author: Sebastian Rasmussen <sebastian.rasmussen@stericsson.com> * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * 3. Neither the name of the ST-Ericsson SA nor the names of its * contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <assert.h> #include <ctype.h> #include <dirent.h> #include <errno.h> #include <limits.h> #include <stdarg.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "mmc.h" #define MASKTOBIT0(high) \ ((high >= 0) ? ((1ull << ((high) + 1ull)) - 1ull) : 0ull) #define MASK(high, low) (MASKTOBIT0(high) & ~MASKTOBIT0(low - 1)) #define BITS(value, high, low) (((value) & MASK((high), (low))) >> (low)) #define IDS_MAX 256 struct config { char *idsfile; char *dir; bool verbose; int interfaces; char **interface; char **mmc_ids; char **sd_ids; char *type; char *cid; char *csd; char *scr; char *ext_csd; }; enum REG_TYPE { CID = 0, CSD, SCR, EXT_CSD, }; struct ids_database { char *type; int id; char *manufacturer; }; struct ids_database database[] = { { .type = "sd", .id = 0x01, .manufacturer = "Panasonic", }, { .type = "sd", .id = 0x02, .manufacturer = "Toshiba/Kingston/Viking", }, { .type = "sd", .id = 0x03, .manufacturer = "SanDisk", }, { .type = "sd", .id = 0x08, .manufacturer = "Silicon Power", }, { .type = "sd", .id = 0x18, .manufacturer = "Infineon", }, { .type = "sd", .id = 0x1b, .manufacturer = "Transcend/Samsung", }, { .type = "sd", .id = 0x1c, .manufacturer = "Transcend", }, { .type = "sd", .id = 0x1d, .manufacturer = "Corsair/AData", }, { .type = "sd", .id = 0x1e, .manufacturer = "Transcend", }, { .type = "sd", .id = 0x1f, .manufacturer = "Kingston", }, { .type = "sd", .id = 0x27, .manufacturer = "Delkin/Phison", }, { .type = "sd", .id = 0x28, .manufacturer = "Lexar", }, { .type = "sd", .id = 0x30, .manufacturer = "SanDisk", }, { .type = "sd", .id = 0x31, .manufacturer = "Silicon Power", }, { .type = "sd", .id = 0x33, .manufacturer = "STMicroelectronics", }, { .type = "sd", .id = 0x41, .manufacturer = "Kingston", }, { .type = "sd", .id = 0x6f, .manufacturer = "STMicroelectronics", }, { .type = "sd", .id = 0x74, .manufacturer = "Transcend", }, { .type = "sd", .id = 0x76, .manufacturer = "Patriot", }, { .type = "sd", .id = 0x82, .manufacturer = "Gobe/Sony", }, { .type = "sd", .id = 0x89, .manufacturer = "Unknown", }, { .type = "mmc", .id = 0x00, .manufacturer = "SanDisk", }, { .type = "mmc", .id = 0x02, .manufacturer = "Kingston/SanDisk", }, { .type = "mmc", .id = 0x03, .manufacturer = "Toshiba", }, { .type = "mmc", .id = 0x05, .manufacturer = "Unknown", }, { .type = "mmc", .id = 0x06, .manufacturer = "Unknown", }, { .type = "mmc", .id = 0x11, .manufacturer = "Toshiba", }, { .type = "mmc", .id = 0x13, .manufacturer = "Micron", }, { .type = "mmc", .id = 0x15, .manufacturer = "Samsung/SanDisk/LG", }, { .type = "mmc", .id = 0x37, .manufacturer = "KingMax", }, { .type = "mmc", .id = 0x44, .manufacturer = "SanDisk", }, { .type = "mmc", .id = 0x2c, .manufacturer = "Kingston", }, { .type = "mmc", .id = 0x70, .manufacturer = "Kingston", }, { .type = "mmc", .id = 0xfe, .manufacturer = "Micron", }, }; /* Command line parsing functions */ void usage(void) { printf("Usage: print mmc [-h] [-v] <device path ...>\n"); printf("\n"); printf("Options:\n"); printf("\t-h\tShow this help.\n"); printf("\t-v\tEnable verbose mode.\n"); } int parse_opts(int argc, char **argv, struct config *config) { int c; while ((c = getopt(argc, argv, "hv")) != -1) { switch (c) { case 'h': usage(); return -1; case 'v': config->verbose = true; break; case '?': fprintf(stderr, "Unknown option '%c' encountered.\n\n", c); usage(); return -1; case ':': fprintf(stderr, "Argument for option '%c' missing.\n\n", c); usage(); return -1; default: fprintf(stderr, "Unimplemented option '%c' encountered.\n", c); break; } } if (optind >= argc) { fprintf(stderr, "Expected mmc directory arguments.\n\n"); usage(); return -1; } config->dir = strdup(argv[optind]); return 0; } int parse_ids(struct config *config) { unsigned int ids_cnt = sizeof(database) / sizeof(struct ids_database); unsigned int value; char **ids; char *type; int i; for (i = 0; i < ids_cnt; i++) { type = database[i].type; if (!strcmp(type, "mmc")) { ids = config->mmc_ids; } else if (!strcmp(type, "sd")) { ids = config->sd_ids; } else { fprintf(stderr, "MMC/SD id parse error, unknown type: '%s'.\n", type); return -1; } value = database[i].id; if (value >= IDS_MAX) { fprintf(stderr, "MMC/SD id parse error, id out of range.\n"); return -1; } if (ids[value]) { fprintf(stderr, "Duplicate entries: type='%s', id='0x%1x'.\n", type, value); return -1; } ids[value] = database[i].manufacturer; } return 0; } /* MMC/SD file parsing functions */ char *read_file(char *name) { char line[4096]; char *preparsed, *start = line; int len; FILE *f; f = fopen(name, "r"); if (!f) { fprintf(stderr, "Could not open MMC/SD file '%s'.\n", name); return NULL; } preparsed = fgets(line, sizeof(line), f); if (!preparsed) { if (ferror(f)) fprintf(stderr, "Could not read MMC/SD file '%s'.\n", name); else fprintf(stderr, "Could not read data from MMC/SD file '%s'.\n", name); if (fclose(f)) fprintf(stderr, "Could not close MMC/SD file '%s'.\n", name); return NULL; } if (fclose(f)) { fprintf(stderr, "Could not close MMC/SD file '%s'.\n", name); return NULL; } line[sizeof(line) - 1] = '\0'; len = strlen(line); while (len > 0 && isspace(line[len - 1])) len--; while (len > 0 && isspace(*start)) { start++; len--; } start[len] = '\0'; return strdup(start); } /* Hexadecimal string parsing functions */ char *to_binstr(char *hexstr) { char *bindigits[] = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111", }; char *binstr, *tail; binstr = calloc(strlen(hexstr) * 4 + 1, sizeof(char)); if (!binstr) return NULL; tail = binstr; while (hexstr && *hexstr != '\0') { if (!isxdigit(*hexstr)) { free(binstr); return NULL; } if (isdigit(*hexstr)) strcat(tail, bindigits[*hexstr - '0']); else if (islower(*hexstr)) strcat(tail, bindigits[*hexstr - 'a' + 10]); else strcat(tail, bindigits[*hexstr - 'A' + 10]); hexstr++; tail += 4; } return binstr; } void bin_to_unsigned(unsigned int *u, char *binstr, int width) { *u = 0; assert(width <= 32); while (binstr && *binstr != '\0' && width > 0) { *u <<= 1; *u |= *binstr == '0' ? 0 : 1; binstr++; width--; } } void bin_to_ascii(char *a, char *binstr, int width) { assert(width % 8 == 0); *a = '\0'; while (binstr && *binstr != '\0' && width > 0) { unsigned int u; char c[2] = { '\0', '\0' }; char *s = &c[0]; bin_to_unsigned(&u, binstr, 8); c[0] = u; strcat(a, s); binstr += 8; width -= 8; } } void parse_bin(char *hexstr, char *fmt, ...) { va_list args; char *origstr; char *binstr; unsigned long width = 0; binstr = to_binstr(hexstr); origstr = binstr; va_start(args, fmt); while (binstr && fmt && *fmt != '\0') { if (isdigit(*fmt)) { char *rest; errno = 0; width = strtoul(fmt, &rest, 10); if (width == ULONG_MAX && errno != 0) fprintf(stderr, "strtoul()"); fmt = rest; } else if (*fmt == 'u') { unsigned int *u = va_arg(args, unsigned int *); if (u) bin_to_unsigned(u, binstr, width); binstr += width; width = 0; fmt++; } else if (*fmt == 'r') { binstr += width; width = 0; fmt++; } else if (*fmt == 'a') { char *c = va_arg(args, char *); if (c) bin_to_ascii(c, binstr, width); binstr += width; width = 0; fmt++; } else { fmt++; } } va_end(args); free(origstr); } /* MMC/SD information parsing functions */ void print_sd_cid(struct config *config, char *cid) { static const char *months[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec", "invalid0", "invalid1", "invalid2", "invalid3", }; unsigned int mid; char oid[3]; char pnm[6]; unsigned int prv_major; unsigned int prv_minor; unsigned int psn; unsigned int mdt_month; unsigned int mdt_year; unsigned int crc; parse_bin(cid, "8u16a40a4u4u32u4r8u4u7u1r", &mid, &oid[0], &pnm[0], &prv_major, &prv_minor, &psn, &mdt_year, &mdt_month, &crc); oid[2] = '\0'; pnm[5] = '\0'; if (config->verbose) { printf("======SD/CID======\n"); printf("\tMID: 0x%02x (", mid); if (config->sd_ids[mid]) printf("%s)\n", config->sd_ids[mid]); else printf("Unlisted)\n"); printf("\tOID: %s\n", oid); printf("\tPNM: %s\n", pnm); printf("\tPRV: 0x%01x%01x ", prv_major, prv_minor); printf("(%u.%u)\n", prv_major, prv_minor); printf("\tPSN: 0x%08x\n", psn); printf("\tMDT: 0x%02x%01x %u %s\n", mdt_year, mdt_month, 2000 + mdt_year, months[mdt_month]); printf("\tCRC: 0x%02x\n", crc); } else { if (config->sd_ids[mid]) printf("manufacturer: '%s' '%s'\n", config->sd_ids[mid], oid); else printf("manufacturer: 'Unlisted' '%s'\n", oid); printf("product: '%s' %u.%u\n", pnm, prv_major, prv_minor); printf("serial: 0x%08x\n", psn); printf("manufacturing date: %u %s\n", 2000 + mdt_year, months[mdt_month]); } } void print_mmc_cid(struct config *config, char *cid) { static const char *months[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec", "invalid0", "invalid1", "invalid2", "invalid3", }; unsigned int mid; unsigned int cbx; unsigned int oid; char pnm[7]; unsigned int prv_major; unsigned int prv_minor; unsigned int psn; unsigned int mdt_month; unsigned int mdt_year; unsigned int crc; parse_bin(cid, "8u6r2u8u48a4u4u32u4u4u7u1r", &mid, &cbx, &oid, &pnm[0], &prv_major, &prv_minor, &psn, &mdt_year, &mdt_month, &crc); pnm[6] = '\0'; if (config->verbose) { printf("======MMC/CID======\n"); printf("\tMID: 0x%02x (", mid); if (config->mmc_ids[mid]) printf("%s)\n", config->mmc_ids[mid]); else printf("Unlisted)\n"); printf("\tCBX: 0x%01x (", cbx); switch (cbx) { case 0: printf("card)\n"); break; case 1: printf("BGA)\n"); break; case 2: printf("PoP)\n"); break; case 3: printf("reserved)\n"); break; } printf("\tOID: 0x%01x\n", oid); printf("\tPNM: %s\n", pnm); printf("\tPRV: 0x%01x%01x ", prv_major, prv_minor); printf("(%u.%u)\n", prv_major, prv_minor); printf("\tPSN: 0x%08x\n", psn); printf("\tMDT: 0x%01x%01x %u %s\n", mdt_month, mdt_year, 1997 + mdt_year, months[mdt_month]); printf("\tCRC: 0x%02x\n", crc); } else { if (config->mmc_ids[mid]) printf("manufacturer: '%s' '%c'\n", config->mmc_ids[mid], oid); else printf("manufacturer: 'Unlisted' '%c'\n", oid); printf("product: '%s' %u.%u\n", pnm, prv_major, prv_minor); printf("serial: 0x%08x\n", psn); printf("manufacturing date: %u %s\n", 1997 + mdt_year, months[mdt_month]); } } void print_sd_csd(struct config *config, char *csd) { unsigned int csd_structure; unsigned int taac_timevalue; unsigned int taac_timeunit; unsigned int nsac; unsigned int tran_speed_timevalue; unsigned int tran_speed_transferrateunit; unsigned int ccc; unsigned int read_bl_len; unsigned int read_bl_partial; unsigned int write_blk_misalign; unsigned int read_blk_misalign; unsigned int dsr_imp; unsigned int c_size; unsigned int vdd_r_curr_min; unsigned int vdd_r_curr_max; unsigned int vdd_w_curr_min; unsigned int vdd_w_curr_max; unsigned int c_size_mult; unsigned int erase_blk_en; unsigned int sector_size; unsigned int wp_grp_size; unsigned int wp_grp_enable; unsigned int r2w_factor; unsigned int write_bl_len; unsigned int write_bl_partial; unsigned int file_format_grp; unsigned int copy; unsigned int perm_write_protect; unsigned int tmp_write_protect; unsigned int file_format; unsigned int crc; unsigned int taac; unsigned int tran_speed; parse_bin(csd, "2u", &csd_structure); if (csd_structure == 0) { parse_bin(csd, "2u6r1r4u3u8u1r4u3u12u4u1u1u1u1u2r12u3u3u3u3u3u" "1u7u7u1u2r3u4u1u5r1u1u1u1u2u2r7u1r", NULL, &taac_timevalue, &taac_timeunit, &nsac, &tran_speed_timevalue, &tran_speed_transferrateunit, &ccc, &read_bl_len, &read_bl_partial, &write_blk_misalign, &read_blk_misalign, &dsr_imp, &c_size, &vdd_r_curr_min, &vdd_r_curr_max, &vdd_w_curr_min, &vdd_w_curr_max, &c_size_mult, &erase_blk_en, §or_size, &wp_grp_size, &wp_grp_enable, &r2w_factor, &write_bl_len, &write_bl_partial, &file_format_grp, ©, &perm_write_protect, &tmp_write_protect, &file_format, &crc); } else if (csd_structure == 1) { parse_bin(csd, "2u6r1r4u3u8u1r4u3u12u4u1u1u1u1u6r22u1r1u7u7u1u" "2r3u4u1u5r1u1u1u1u2u2r7u1r", NULL, &taac_timevalue, &taac_timeunit, &nsac, &tran_speed_timevalue, &tran_speed_transferrateunit, &ccc, &read_bl_len, &read_bl_partial, &write_blk_misalign, &read_blk_misalign, &dsr_imp, &c_size, &erase_blk_en, §or_size, &wp_grp_size, &wp_grp_enable, &r2w_factor, &write_bl_len, &write_bl_partial, &file_format_grp, ©, &perm_write_protect, &tmp_write_protect, &file_format, &crc); vdd_r_curr_min = 0; c_size_mult = 0; } else { printf("Unknown CSD structure: 0x%1x\n", csd_structure); return; } taac = taac_timevalue << 3 | taac_timeunit; tran_speed = tran_speed_timevalue << 3 | tran_speed_transferrateunit; if (config->verbose) { float value; unsigned long long blocks = 0; int block_size = 0; unsigned long long memory_capacity; printf("======SD/CSD======\n"); printf("\tCSD_STRUCTURE: %u\n", csd_structure); printf("\tTAAC: 0x%02x (", taac); switch (taac_timevalue) { case 0x0: value = 0.0f; break; case 0x1: value = 1.0f; break; case 0x2: value = 1.2f; break; case 0x3: value = 1.3f; break; case 0x4: value = 1.5f; break; case 0x5: value = 2.0f; break; case 0x6: value = 2.5f; break; case 0x7: value = 3.0f; break; case 0x8: value = 3.5f; break; case 0x9: value = 4.0f; break; case 0xa: value = 4.5f; break; case 0xb: value = 5.0f; break; case 0xc: value = 5.5f; break; case 0xd: value = 6.0f; break; case 0xe: value = 7.0f; break; case 0xf: value = 8.0f; break; default: value = 0.0f; break; } switch (taac_timeunit) { case 0x0: printf("%.2fns)\n", value * 1.0f); break; case 0x1: printf("%.2fns)\n", value * 10.0f); break; case 0x2: printf("%.2fns)\n", value * 100.0f); break; case 0x3: printf("%.2fus)\n", value * 1.0f); break; case 0x4: printf("%.2fus)\n", value * 10.0f); break; case 0x5: printf("%.2fus)\n", value * 100.0f); break; case 0x6: printf("%.2fms)\n", value * 1.0f); break; case 0x7: printf("%.2fms)\n", value * 10.0f); break; } if (csd_structure == 1 && taac != 0x0e) printf("Warn: Invalid TAAC (should be 0x0e)\n"); printf("\tNSAC: %u clocks\n", nsac); if (csd_structure == 1 && nsac != 0x00) printf("Warn: Invalid NSAC (should be 0x00)\n"); printf("\tTRAN_SPEED: 0x%02x (", tran_speed); switch (tran_speed_timevalue) { case 0x0: value = 0.0f; break; case 0x1: value = 1.0f; break; case 0x2: value = 1.2f; break; case 0x3: value = 1.3f; break; case 0x4: value = 1.5f; break; case 0x5: value = 2.0f; break; case 0x6: value = 2.5f; break; case 0x7: value = 3.0f; break; case 0x8: value = 3.5f; break; case 0x9: value = 4.0f; break; case 0xa: value = 4.5f; break; case 0xb: value = 5.0f; break; case 0xc: value = 5.5f; break; case 0xd: value = 6.0f; break; case 0xe: value = 7.0f; break; case 0xf: value = 8.0f; break; default: value = 0.0f; break; } switch (tran_speed_transferrateunit) { case 0x0: printf("%.2fkbit/s)\n", value * 100.0f); break; case 0x1: printf("%.2fMbit/s)\n", value * 1.0f); break; case 0x2: printf("%.2fMbit/s)\n", value * 10.0f); break; case 0x3: printf("%.2fMbit/s)\n", value * 100.0f); break; default: printf("reserved)\n"); break; } if (csd_structure == 0 && (tran_speed != 0x32 && tran_speed != 0x5a)) printf("Warn: Invalid TRAN_SPEED " "(should be 0x32 or 0x5a)\n"); if (csd_structure == 1 && tran_speed != 0x32 && tran_speed != 0x5a && tran_speed != 0x0b && tran_speed != 0x2b) printf("Warn: Invalid TRAN_SPEED " "(should be 0x32, 0x5a, 0x0b or 0x2b\n"); printf("\tCCC: 0x%03x (class: ", ccc); if (ccc & 0x800) printf("11, "); if (ccc & 0x400) printf("10, "); if (ccc & 0x200) printf("9, "); if (ccc & 0x100) printf("8, "); if (ccc & 0x080) printf("7, "); if (ccc & 0x040) printf("6, "); if (ccc & 0x020) printf("5, "); if (ccc & 0x010) printf("4, "); if (ccc & 0x008) printf("3, "); if (ccc & 0x004) printf("2, "); if (ccc & 0x002) printf("1, "); if (ccc & 0x001) printf("0, "); printf(" )\n"); if (csd_structure == 0 && (ccc != 0x5b5 && ccc != 0x7b5 && ccc != 0x5f5)) printf("Warn: Invalid CCC (should be 0x5b5, " "0x7b5 or 0x5f5)\n"); else if (csd_structure == 1 && ccc != 0x5b5 && ccc != 0x7b5) printf("Warn: Invalid CCC (should be 0x5b5 or 0x7b5)\n"); printf("\tREAD_BL_LEN: 0x%01x (", read_bl_len); switch (read_bl_len) { case 0x9: printf("512 bytes)\n"); break; case 0xa: printf("1024 bytes)\n"); break; case 0xb: printf("2048 bytes)\n"); break; default: printf("reserved bytes)\n"); break; } if (csd_structure == 1 && read_bl_len != 0x9) printf("Warn: Invalid READ_BL_LEN (should be 0x9)\n"); printf("\tREAD_BL_PARTIAL: 0x%01x\n", read_bl_partial); if (csd_structure == 0 && read_bl_partial != 0x01) printf("Warn: Invalid READ_BL_PARTIAL (should be 0x01)\n"); else if (csd_structure == 1 && read_bl_partial != 0x00) printf("Warn: Invalid READ_BL_PARTIAL (should be 0x00)\n"); printf("\tWRITE_BLK_MISALIGN: 0x%01x\n", write_blk_misalign); if (csd_structure == 1 && write_blk_misalign != 0x00) printf("Warn: Invalid WRITE_BLK_MISALIGN (should be 0x00)\n"); printf("\tREAD_BLK_MISALIGN: 0x%01x\n", read_blk_misalign); if (csd_structure == 1 && read_blk_misalign != 0x00) printf("Warn: Invalid READ_BLK_MISALIGN (should be 0x00)\n"); printf("\tDSR_IMP: 0x%01x\n", dsr_imp); if (csd_structure == 0) { int mult; int blocknr; int block_len; printf("\tC_SIZE: 0x%03x\n", c_size); printf("\tVDD_R_CURR_MIN: 0x%01x (", vdd_r_curr_min); switch (vdd_r_curr_min) { case 0x0: printf("0.5mA)\n"); break; case 0x1: printf("1mA)\n"); break; case 0x2: printf("5mA)\n"); break; case 0x3: printf("10mA)\n"); break; case 0x4: printf("25mA)\n"); break; case 0x5: printf("35mA)\n"); break; case 0x6: printf("60mA)\n"); break; case 0x7: printf("100mA)\n"); break; } printf("\tVDD_R_CURR_MAX: 0x%01x (", vdd_r_curr_max); switch (vdd_r_curr_max) { case 0x0: printf("1mA)\n"); break; case 0x1: printf("5mA)\n"); break; case 0x2: printf("10mA)\n"); break; case 0x3: printf("25mA)\n"); break; case 0x4: printf("35mA)\n"); break; case 0x5: printf("45mA)\n"); break; case 0x6: printf("80mA)\n"); break; case 0x7: printf("200mA)\n"); break; } printf("\tVDD_W_CURR_MIN: 0x%01x (", vdd_w_curr_min); switch (vdd_w_curr_min) { case 0x0: printf("0.5mA)\n"); break; case 0x1: printf("1mA)\n"); break; case 0x2: printf("5mA)\n"); break; case 0x3: printf("10mA)\n"); break; case 0x4: printf("25mA)\n"); break; case 0x5: printf("35mA)\n"); break; case 0x6: printf("60mA)\n"); break; case 0x7: printf("100mA)\n"); break; } printf("\tVDD_W_CURR_MAX: 0x%01x (", vdd_w_curr_max); switch (vdd_w_curr_max) { case 0x0: printf("1mA)\n"); break; case 0x1: printf("5mA)\n"); break; case 0x2: printf("10mA)\n"); break; case 0x3: printf("25mA)\n"); break; case 0x4: printf("35mA)\n"); break; case 0x5: printf("45mA)\n"); break; case 0x6: printf("80mA)\n"); break; case 0x7: printf("200mA)\n"); break; } printf("\tC_SIZE_MULT: 0x%01x\n", c_size_mult); mult = 1 << (c_size_mult + 2); blocknr = (c_size + 1) * mult; block_len = 1 << read_bl_len; blocks = blocknr; block_size = block_len; } else if (csd_structure == 1) { printf("\tC_SIZE: 0x%06x\n", c_size); printf("\tERASE_BLK_EN: 0x%01x\n", erase_blk_en); if (erase_blk_en != 0x01) printf("Warn: Invalid ERASE_BLK_EN (should be 0x01)\n"); printf("\tSECTOR_SIZE: 0x%02x (Erasable sector: %u blocks)\n", sector_size, sector_size + 1); if (sector_size != 0x7f) printf("Warn: Invalid SECTOR_SIZE (should be 0x7f)\n"); printf("\tWP_GRP_SIZE: 0x%02x (Write protect group: %u blocks)\n", wp_grp_size, wp_grp_size + 1); if (wp_grp_size != 0x00) printf("Warn: Invalid WP_GRP_SIZE (should be 0x00)\n"); printf("\tWP_GRP_ENABLE: 0x%01x\n", wp_grp_enable); if (wp_grp_enable != 0x00) printf("Warn: Invalid WP_GRP_ENABLE (should be 0x00)\n"); printf("\tR2W_FACTOR: 0x%01x (Write %u times read)\n", r2w_factor, r2w_factor); if (r2w_factor != 0x02) printf("Warn: Invalid R2W_FACTOR (should be 0x02)\n"); printf("\tWRITE_BL_LEN: 0x%01x (", write_bl_len); switch (write_bl_len) { case 9: printf("512 bytes)\n"); break; case 10: printf("1024 bytes)\n"); break; case 11: printf("2048 bytes)\n"); break; default: printf("reserved)\n"); break; } if (write_bl_len != 0x09) printf("Warn: Invalid WRITE_BL_LEN (should be 0x09)\n"); printf("\tWRITE_BL_PARTIAL: 0x%01x\n", write_bl_partial); if (write_bl_partial != 0x00) printf("Warn: Invalid WRITE_BL_PARTIAL (should be 0x00)\n"); printf("\tFILE_FORMAT_GRP: 0x%01x\n", file_format_grp); if (file_format_grp != 0x00) printf("Warn: Invalid FILE_FORMAT_GRP (should be 0x00)\n"); printf("\tCOPY: 0x%01x\n", copy); printf("\tPERM_WRITE_PROTECT: 0x%01x\n", perm_write_protect); printf("\tTMP_WRITE_PROTECT: 0x%01x\n", tmp_write_protect); printf("\tFILE_FORMAT: 0x%01x (", file_format); if (file_format_grp == 1) { printf("reserved)\n"); } else { switch (file_format) { case 0: printf("partition table)\n"); break; case 1: printf("no partition table)\n"); break; case 2: printf("Universal File Format)\n"); break; case 3: printf("Others/unknown)\n"); break; } } if (file_format != 0x00) printf("Warn: Invalid FILE_FORMAT (should be 0x00)\n"); printf("\tCRC: 0x%01x\n", crc); memory_capacity = (c_size + 1) * 512ull * 1024ull; block_size = 512; blocks = memory_capacity / block_size; } memory_capacity = blocks * block_size; printf("\tCAPACITY: "); if (memory_capacity / (1024ull * 1024ull * 1024ull) > 0) printf("%.2fGbyte", memory_capacity / (1024.0 * 1024.0 * 1024.0)); else if (memory_capacity / (1024ull * 1024ull) > 0) printf("%.2fMbyte", memory_capacity / (1024.0 * 1024.0)); else if (memory_capacity / (1024ull) > 0) printf("%.2fKbyte", memory_capacity / (1024.0)); else printf("%.2fbyte", memory_capacity * 1.0); printf(" (%llu bytes, %llu sectors, %d bytes each)\n", memory_capacity, blocks, block_size); } else { unsigned long long blocks = 0; int block_size = 0; unsigned long long memory_capacity; printf("card classes: "); if (ccc & 0x800) printf("11 extension, "); if (ccc & 0x400) printf("10 switch, "); if (ccc & 0x200) printf("9 I/O mode, "); if (ccc & 0x100) printf("8 application specific, "); if (ccc & 0x080) printf("7 lock card, "); if (ccc & 0x040) printf("6 write protection, "); if (ccc & 0x020) printf("5 erase, "); if (ccc & 0x010) printf("4 block write, "); if (ccc & 0x008) printf("3 reserved, "); if (ccc & 0x004) printf("2 block read, "); if (ccc & 0x002) printf("1 reserved, "); if (ccc & 0x001) printf("0 basic, "); printf("\b\b\n"); if (csd_structure == 0) { int mult; int blocknr; int block_len; mult = 1 << (c_size_mult + 2); blocknr = (c_size + 1) * mult; block_len = 1 << read_bl_len; blocks = blocknr; block_size = block_len; } else if (csd_structure == 1) { memory_capacity = (c_size + 1) * 512ull * 1024ull; block_size = 512; blocks = memory_capacity / block_size; } memory_capacity = blocks * block_size; printf("capacity: "); if (memory_capacity / (1024ull * 1024ull * 1024ull) > 0) printf("%.2fGbyte", memory_capacity / (1024.0 * 1024.0 * 1024.0)); else if (memory_capacity / (1024ull * 1024ull) > 0) printf("%.2fMbyte", memory_capacity / (1024.0 * 1024.0)); else if (memory_capacity / (1024ull) > 0) printf("%.2fKbyte", memory_capacity / (1024.0)); else printf("%.2fbyte", memory_capacity * 1.0); printf(" (%llu bytes, %llu sectors, %d bytes each)\n", memory_capacity, blocks, block_size); } } void print_mmc_csd(struct config *config, char *csd) { unsigned int csd_structure; unsigned int spec_vers; unsigned int taac_timevalue; unsigned int taac_timeunit; unsigned int nsac; unsigned int tran_speed_timevalue; unsigned int tran_speed_transferrateunit; unsigned int ccc; unsigned int read_bl_len; unsigned int read_bl_partial; unsigned int write_blk_misalign; unsigned int read_blk_misalign; unsigned int dsr_imp; unsigned int c_size; unsigned int vdd_r_curr_min; unsigned int vdd_r_curr_max; unsigned int vdd_w_curr_min; unsigned int vdd_w_curr_max; unsigned int c_size_mult; unsigned int erase_grp_size; unsigned int erase_grp_mult; unsigned int wp_grp_size; unsigned int wp_grp_enable; unsigned int default_ecc; unsigned int r2w_factor; unsigned int write_bl_len; unsigned int write_bl_partial; unsigned int content_prot_app; unsigned int file_format_grp; unsigned int copy; unsigned int perm_write_protect; unsigned int tmp_write_protect; unsigned int file_format; unsigned int ecc; unsigned int crc; unsigned int taac; unsigned int tran_speed; parse_bin(csd, "2u4u2r1r4u3u8u1r4u3u12u4u1u1u1u1u2r12u3u3u3u3u3u" "5u5u5u1u2u3u4u1u4r1u1u1u1u1u2u2u7u1r", &csd_structure, &spec_vers, &taac_timevalue, &taac_timeunit, &nsac, &tran_speed_timevalue, &tran_speed_transferrateunit, &ccc, &read_bl_len, &read_bl_partial, &write_blk_misalign, &read_blk_misalign, &dsr_imp, &c_size, &vdd_r_curr_min, &vdd_r_curr_max, &vdd_w_curr_min, &vdd_w_curr_max, &c_size_mult, &erase_grp_size, &erase_grp_mult, &wp_grp_size, &wp_grp_enable, &default_ecc, &r2w_factor, &write_bl_len, &write_bl_partial, &content_prot_app, &file_format_grp, ©, &perm_write_protect, &tmp_write_protect, &file_format, &ecc, &crc); taac = taac_timevalue << 3 | taac_timeunit; tran_speed = tran_speed_timevalue << 3 | tran_speed_transferrateunit; if (config->verbose) { float value; int mult; int blocknr; int block_len; unsigned long long blocks = 0; int block_size = 0; unsigned long long memory_capacity; printf("======MMC/CSD======\n"); printf("\tCSD_STRUCTURE: 0x%01x (", csd_structure); switch (csd_structure) { case 0x0: printf("v1.0)\n"); break; case 0x1: printf("v1.1)\n"); break; case 0x2: printf("v1.2)\n"); break; case 0x3: printf("version in ext_csd)\n"); break; } printf("\tSPEC_VERS: 0x%01x (", spec_vers); switch (spec_vers) { case 0x0: printf("v1.0-v1.2)\n"); break; case 0x1: printf("v1.4)\n"); break; case 0x2: printf("v2.0-v2.2)\n"); break; case 0x3: printf("v3.1-v3.31)\n"); break; case 0x4: printf("v4.0-v4.3)\n"); break; default: printf("reserved)\n"); break; } printf("\tTAAC: 0x%02x (", taac); switch (taac_timevalue) { case 0x0: value = 0.0f; break; case 0x1: value = 1.0f; break; case 0x2: value = 1.2f; break; case 0x3: value = 1.3f; break; case 0x4: value = 1.5f; break; case 0x5: value = 2.0f; break; case 0x6: value = 2.5f; break; case 0x7: value = 3.0f; break; case 0x8: value = 3.5f; break; case 0x9: value = 4.0f; break; case 0xa: value = 4.5f; break; case 0xb: value = 5.0f; break; case 0xc: value = 5.5f; break; case 0xd: value = 6.0f; break; case 0xe: value = 7.0f; break; case 0xf: value = 8.0f; break; default: value = 0.0f; break; } switch (taac_timeunit) { case 0x0: printf("%.2fns)\n", value * 1.0f); break; case 0x1: printf("%.2fns)\n", value * 10.0f); break; case 0x2: printf("%.2fns)\n", value * 100.0f); break; case 0x3: printf("%.2fus)\n", value * 1.0f); break; case 0x4: printf("%.2fus)\n", value * 10.0f); break; case 0x5: printf("%.2fus)\n", value * 100.0f); break; case 0x6: printf("%.2fms)\n", value * 1.0f); break; case 0x7: printf("%.2fms)\n", value * 10.0f); break; } printf("\tNSAC: %u clocks\n", nsac); printf("\tTRAN_SPEED: 0x%02x (", tran_speed); switch (tran_speed_timevalue) { case 0x0: value = 0.0f; break; case 0x1: value = 1.0f; break; case 0x2: value = 1.2f; break; case 0x3: value = 1.3f; break; case 0x4: value = 1.5f; break; case 0x5: value = 2.0f; break; case 0x6: value = 2.6f; break; case 0x7: value = 3.0f; break; case 0x8: value = 3.5f; break; case 0x9: value = 4.0f; break; case 0xa: value = 4.5f; break; case 0xb: value = 5.2f; break; case 0xc: value = 5.5f; break; case 0xd: value = 6.0f; break; case 0xe: value = 7.0f; break; case 0xf: value = 8.0f; break; default: value = 0.0f; break; } switch (tran_speed_transferrateunit) { case 0x0: printf("%.2fKHz/s)\n", value * 100.0f); break; case 0x1: printf("%.2fMHz/s)\n", value * 1.0f); break; case 0x2: printf("%.2fMHz/s)\n", value * 10.0f); break; case 0x3: printf("%.2fMHz/s)\n", value * 100.0f); break; default: printf("reserved)\n"); break; } printf("\tCCC: 0x%03x (class: ", ccc); if (ccc & 0x800) printf("11, "); if (ccc & 0x400) printf("10, "); if (ccc & 0x200) printf("9, "); if (ccc & 0x100) printf("8, "); if (ccc & 0x080) printf("7, "); if (ccc & 0x040) printf("6, "); if (ccc & 0x020) printf("5, "); if (ccc & 0x010) printf("4, "); if (ccc & 0x008) printf("3, "); if (ccc & 0x004) printf("2, "); if (ccc & 0x002) printf("1, "); if (ccc & 0x001) printf("0, "); printf(" )\n"); printf("\tREAD_BL_LEN: 0x%01x (", read_bl_len); switch (read_bl_len) { case 0x0: printf("1 byte)\n"); break; case 0x1: printf("2 byte)\n"); break; case 0x2: printf("4 byte)\n"); break; case 0x3: printf("8 byte)\n"); break; case 0x4: printf("16 byte)\n"); break; case 0x5: printf("32 byte)\n"); break; case 0x6: printf("64 byte)\n"); break; case 0x7: printf("128 byte)\n"); break; case 0x8: printf("256 byte)\n"); break; case 0x9: printf("512 bytes)\n"); break; case 0xa: printf("1024 bytes)\n"); break; case 0xb: printf("2048 bytes)\n"); break; case 0xc: printf("4096 bytes)\n"); break; case 0xd: printf("8192 bytes)\n"); break; case 0xe: printf("16K bytes)\n"); break; default: printf("reserved bytes)\n"); break; } printf("\tREAD_BL_PARTIAL: 0x%01x (", read_bl_partial); switch (read_bl_partial) { case 0x0: printf("only 512 byte and READ_BL_LEN block size)\n"); break; case 0x1: printf("less than READ_BL_LEN block size can be used)\n"); break; } printf("\tWRITE_BLK_MISALIGN: 0x%01x (", write_blk_misalign); switch (write_blk_misalign) { case 0x0: printf("writes across block boundaries are invalid)\n"); break; case 0x1: printf("writes across block boundaries are allowed)\n"); break; } printf("\tREAD_BLK_MISALIGN: 0x%01x (", read_blk_misalign); switch (read_blk_misalign) { case 0x0: printf("reads across block boundaries are invalid)\n"); break; case 0x1: printf("reads across block boundaries are allowed)\n"); break; } printf("\tDSR_IMP: 0x%01x (", dsr_imp); switch (dsr_imp) { case 0x0: printf("configurable driver stage not available)\n"); break; case 0x1: printf("configurable driver state available)\n"); break; } printf("\tC_SIZE: 0x%03x\n", c_size); printf("\tVDD_R_CURR_MIN: 0x%01x (", vdd_r_curr_min); switch (vdd_r_curr_min) { case 0x0: printf("0.5mA)\n"); break; case 0x1: printf("1mA)\n"); break; case 0x2: printf("5mA)\n"); break; case 0x3: printf("10mA)\n"); break; case 0x4: printf("25mA)\n"); break; case 0x5: printf("35mA)\n"); break; case 0x6: printf("60mA)\n"); break; case 0x7: printf("100mA)\n"); break; } printf("\tVDD_R_CURR_MAX: 0x%01x (", vdd_r_curr_max); switch (vdd_r_curr_max) { case 0x0: printf("1mA)\n"); break; case 0x1: printf("5mA)\n"); break; case 0x2: printf("10mA)\n"); break; case 0x3: printf("25mA)\n"); break; case 0x4: printf("35mA)\n"); break; case 0x5: printf("45mA)\n"); break; case 0x6: printf("80mA)\n"); break; case 0x7: printf("200mA)\n"); break; } printf("\tVDD_W_CURR_MIN: 0x%01x (", vdd_w_curr_min); switch (vdd_w_curr_min) { case 0x0: printf("0.5mA)\n"); break; case 0x1: printf("1mA)\n"); break; case 0x2: printf("5mA)\n"); break; case 0x3: printf("10mA)\n"); break; case 0x4: printf("25mA)\n"); break; case 0x5: printf("35mA)\n"); break; case 0x6: printf("60mA)\n"); break; case 0x7: printf("100mA)\n"); break; } printf("\tVDD_W_CURR_MAX: 0x%01x (", vdd_w_curr_max); switch (vdd_w_curr_max) { case 0x0: printf("1mA)\n"); break; case 0x1: printf("5mA)\n"); break; case 0x2: printf("10mA)\n"); break; case 0x3: printf("25mA)\n"); break; case 0x4: printf("35mA)\n"); break; case 0x5: printf("45mA)\n"); break; case 0x6: printf("80mA)\n"); break; case 0x7: printf("200mA)\n"); break; } printf("\tC_SIZE_MULT: 0x%01x\n", c_size_mult); printf("\tERASE_GRP_SIZE: 0x%02x\n", erase_grp_size); printf("\tERASE_GRP_MULT: 0x%02x (%u write blocks/erase group)\n", erase_grp_mult, (erase_grp_size + 1) * (erase_grp_mult + 1)); printf("\tWP_GRP_SIZE: 0x%02x (%u blocks/write protect group)\n", wp_grp_size, wp_grp_size + 1); printf("\tWP_GRP_ENABLE: 0x%01x\n", wp_grp_enable); printf("\tDEFAULT_ECC: 0x%01x (", default_ecc); switch (default_ecc) { case 0: printf("none)\n"); break; case 1: printf("BCH)\n"); break; default: printf("reserved)\n"); break; } printf("\tR2W_FACTOR: 0x%01x (Write %u times read)\n", r2w_factor, r2w_factor); printf("\tWRITE_BL_LEN: 0x%01x (", write_bl_len); switch (write_bl_len) { case 0x0: printf("1 byte)\n"); break; case 0x1: printf("2 byte)\n"); break; case 0x2: printf("4 byte)\n"); break; case 0x3: printf("8 byte)\n"); break; case 0x4: printf("16 byte)\n"); break; case 0x5: printf("32 byte)\n"); break; case 0x6: printf("64 byte)\n"); break; case 0x7: printf("128 byte)\n"); break; case 0x8: printf("256 byte)\n"); break; case 0x9: printf("512 bytes)\n"); break; case 0xa: printf("1024 bytes)\n"); break; case 0xb: printf("2048 bytes)\n"); break; case 0xc: printf("4096 bytes)\n"); break; case 0xd: printf("8192 bytes)\n"); break; case 0xe: printf("16K bytes)\n"); break; default: printf("reserved bytes)\n"); break; } printf("\tWRITE_BL_PARTIAL: 0x%01x (", write_bl_partial); switch (write_bl_partial) { case 0x0: printf("only 512 byte and WRITE_BL_LEN block size)\n"); break; case 0x1: printf("less than WRITE_BL_LEN block size can be used)\n"); break; } printf("\tCONTENT_PROT_APP: 0x%01x\n", content_prot_app); printf("\tFILE_FORMAT_GRP: 0x%01x\n", file_format_grp); if (file_format_grp != 0) printf("Warn: Invalid FILE_FORMAT_GRP\n"); printf("\tCOPY: 0x%01x\n", copy); printf("\tPERM_WRITE_PROTECT: 0x%01x\n", perm_write_protect); printf("\tTMP_WRITE_PROTECT: 0x%01x\n", tmp_write_protect); printf("\tFILE_FORMAT: 0x%01x (", file_format); if (file_format != 0) printf("Warn: Invalid FILE_FORMAT\n"); if (file_format_grp == 1) { printf("reserved)\n"); } else { switch (file_format) { case 0: printf("partition table)\n"); break; case 1: printf("no partition table)\n"); break; case 2: printf("Universal File Format)\n"); break; case 3: printf("Others/unknown)\n"); break; } } printf("\tECC: 0x%01x (", ecc); switch (ecc) { case 0: printf("none)\n"); break; case 1: printf("BCH(542,512))\n"); break; default: printf("reserved)\n"); break; } printf("\tCRC: 0x%01x\n", crc); mult = 1 << (c_size_mult + 2); blocknr = (c_size + 1) * mult; block_len = 1 << read_bl_len; blocks = blocknr; block_size = block_len; memory_capacity = blocks * block_size; printf("\tCAPACITY: "); if (memory_capacity / (1024ull * 1024ull * 1024ull) > 0) printf("%.2fGbyte", memory_capacity / (1024.0 * 1024.0 * 1024.0)); else if (memory_capacity / (1024ull * 1024ull) > 0) printf("%.2fMbyte", memory_capacity / (1024.0 * 1024.0)); else if (memory_capacity / (1024ull) > 0) printf("%.2fKbyte", memory_capacity / (1024.0)); else printf("%.2fbyte", memory_capacity * 1.0); printf(" (%llu bytes, %llu sectors, %d bytes each)\n", memory_capacity, blocks, block_size); } else { int mult; int blocknr; int block_len; unsigned long long blocks = 0; int block_size = 0; unsigned long long memory_capacity; printf("version: "); switch (spec_vers) { case 0x0: printf("MMC v1.0-v1.2\n"); break; case 0x1: printf("MMC v1.4\n"); break; case 0x2: printf("MMC v2.0-v2.2\n"); break; case 0x3: printf("MMC v3.1-v3.31\n"); break; case 0x4: printf("MMC v4.0-v4.3\n"); break; default: printf("reserved\n"); break; } printf("card classes: "); if (ccc & 0x800) printf("11, "); if (ccc & 0x400) printf("10, "); if (ccc & 0x200) printf("9, "); if (ccc & 0x100) printf("8, "); if (ccc & 0x080) printf("7, "); if (ccc & 0x040) printf("6, "); if (ccc & 0x020) printf("5, "); if (ccc & 0x010) printf("4, "); if (ccc & 0x008) printf("3, "); if (ccc & 0x004) printf("2, "); if (ccc & 0x002) printf("1, "); if (ccc & 0x001) printf("0, "); printf("\b\b\n"); mult = 1 << (c_size_mult + 2); blocknr = (c_size + 1) * mult; block_len = 1 << read_bl_len; blocks = blocknr; block_size = block_len; memory_capacity = blocks * block_size; printf("capacity: "); if (memory_capacity / (1024ull * 1024ull * 1024ull) > 0) printf("%.2fGbyte", memory_capacity / (1024.0 * 1024.0 * 1024.0)); else if (memory_capacity / (1024ull * 1024ull) > 0) printf("%.2fMbyte", memory_capacity / (1024.0 * 1024.0)); else if (memory_capacity / (1024ull) > 0) printf("%.2fKbyte", memory_capacity / (1024.0)); else printf("%.2fbyte", memory_capacity * 1.0); printf(" (%llu bytes, %llu sectors, %d bytes each)\n", memory_capacity, blocks, block_size); } } char *speed_class_speed(unsigned char id, bool ddr) { if (ddr) { switch (id) { case 0x00: return "<4.8MB/s"; case 0x08: return " 4.8MB/s"; case 0x0a: return " 6.0MB/s"; case 0x0f: return " 9.0MB/s"; case 0x14: return "12.0MB/s"; case 0x1e: return "18.0MB/s"; case 0x28: return "24.0MB/s"; case 0x32: return "30.0MB/s"; case 0x3c: return "36.0MB/s"; case 0x46: return "42.0MB/s"; case 0x50: return "48.0MB/s"; case 0x64: return "60.0MB/s"; case 0x78: return "72.0MB/s"; case 0x8c: return "84.0MB/s"; case 0xa0: return "96.0MB/s"; default: return "??.?MB/s"; } } else { switch (id) { case 0x00: return "<2.4MB/s"; case 0x08: return " 2.4MB/s"; case 0x0a: return " 3.0MB/s"; case 0x0f: return " 4.5MB/s"; case 0x14: return " 6.0MB/s"; case 0x1e: return " 9.0MB/s"; case 0x28: return "12.0MB/s"; case 0x32: return "15.0MB/s"; case 0x3c: return "18.0MB/s"; case 0x46: return "21.0MB/s"; case 0x50: return "24.0MB/s"; case 0x64: return "30.0MB/s"; case 0x78: return "36.0MB/s"; case 0x8c: return "42.0MB/s"; case 0xa0: return "48.0MB/s"; default: return "??.?MB/s"; } } } char speed_class_name(unsigned char id) { switch (id) { case 0x00: return '?'; case 0x08: return 'A'; case 0x0a: return 'B'; case 0x0f: return 'C'; case 0x14: return 'D'; case 0x1e: return 'E'; case 0x28: return 'F'; case 0x32: return 'G'; case 0x3c: return 'H'; case 0x46: return 'J'; case 0x50: return 'K'; case 0x64: return 'M'; case 0x78: return 'O'; case 0x8c: return 'R'; case 0xa0: return 'T'; default: return '?'; } } char *power_class_consumption(unsigned int id, bool volt360) { if (volt360) { switch (id) { case 0x0: return "100-200mA"; case 0x1: return "120-220mA"; case 0x2: return "150-250mA"; case 0x3: return "180-280mA"; case 0x4: return "200-300mA"; case 0x5: return "220-320mA"; case 0x6: return "250-350mA"; case 0x7: return "300-400mA"; case 0x8: return "350-450mA"; case 0x9: return "400-500mA"; case 0xa: return "450-550mA"; default: return "reserved"; } } else { switch (id) { case 0x0: return "65-130mA"; case 0x1: return "70-140mA"; case 0x2: return "80-160mA"; case 0x3: return "90-180mA"; case 0x4: return "100-200mA"; case 0x5: return "120-220mA"; case 0x6: return "140-240mA"; case 0x7: return "160-260mA"; case 0x8: return "180-280mA"; case 0x9: return "200-300mA"; case 0xa: return "250-350mA"; default: return "reserved"; } } } char *sleep_consumption(unsigned int id) { switch (id) { case 0x00: return "not defined"; case 0x01: return "2uA"; case 0x02: return "4uA"; case 0x03: return "8uA"; case 0x04: return "16uA"; case 0x05: return "32uA"; case 0x06: return "64uA"; case 0x07: return "128uA"; case 0x08: return "0.256mA"; case 0x09: return "0.512mA"; case 0x0a: return "1.024mA"; case 0x0b: return "2.048mA"; case 0x0c: return "4.096mA"; case 0x0d: return "8.192mA"; default: return "reserved"; } } void print_sd_scr(struct config *config, char *scr) { unsigned int scr_structure; unsigned int sd_spec; unsigned int data_stat_after_erase; unsigned int sd_security; unsigned int sd_bus_widths; unsigned int sd_spec3; unsigned int ex_security; unsigned int cmd_support; parse_bin(scr, "4u4u1u3u4u1u4u9r2u32r", &scr_structure, &sd_spec, &data_stat_after_erase, &sd_security, &sd_bus_widths, &sd_spec3, &ex_security, &cmd_support); if (config->verbose) { printf("======SD/SCR======\n"); printf("\tSCR_STRUCTURE: 0x%01x (", scr_structure); switch (scr_structure) { case 0: printf("SCR v1.0)\n"); break; default: printf("reserved)\n"); break; } printf("\tSD_SPEC: 0x%01x (", sd_spec); switch (sd_spec) { case 0: printf("SD v1.0/1.01)\n"); break; case 1: printf("SD v1.10)\n"); break; case 2: printf("SD v2.00/v3.0x)\n"); break; case 3: printf("SD v4.00)\n"); break; default: printf("reserved)\n"); break; } printf("\tDATA_STAT_AFTER_ERASE: 0x%01x\n", data_stat_after_erase); printf("\tSD_SECURITY: 0x%01x (", sd_security); switch (sd_security) { case 0: printf("no security)\n"); break; case 1: printf("not used)\n"); break; case 2: printf("SDSC card/security v1.01)\n"); break; case 3: printf("SDHC card/security v2.00)\n"); break; case 4: printf("SDXC card/security v3.xx)\n"); break; default: printf("reserved)\n"); break; } printf("\tSD_BUS_WIDTHS: 0x%01x (", sd_bus_widths); if (BITS(sd_bus_widths, 2, 2)) printf("4bit, "); if (BITS(sd_bus_widths, 0, 0)) printf("1bit, "); printf(" bus)\n"); printf("\tSD_SPEC3: 0x%01x (", sd_spec3); if (sd_spec >= 2) { switch (sd_spec3) { case 0: printf("SD v2.00)\n"); break; case 1: printf("SD v3.0x)\n"); break; } } else { printf("SD 1.xx)\n"); } printf("\tEX_SECURITY: 0x%01x\n", ex_security); printf("\tCMD_SUPPORT: 0x%01x (", cmd_support); if (BITS(cmd_support, 1, 1)) printf("CMD23 "); if (BITS(cmd_support, 0, 0)) printf("CMD20 "); printf(" )\n"); } else { printf("version: "); switch (sd_spec) { case 0: printf("SD 1.0/1.01\n"); break; case 1: printf("SD 1.10\n"); break; case 2: switch (sd_spec3) { case 0: printf("SD 2.00\n"); break; case 1: printf("SD 3.0x\n"); break; default: printf("unknown\n"); break; } break; case 3: printf("SD 4.00\n"); break; default: printf("unknown\n"); break; } printf("bus widths: "); if (BITS(sd_bus_widths, 2, 2)) printf("4bit, "); if (BITS(sd_bus_widths, 0, 0)) printf("1bit, "); printf("\b\b\n"); } } /* MMC/SD interface processing functions */ void print_info(struct config *config, char *type, char *cid, char *csd, char *scr, char *ext_csd) { printf("type: '%s'\n", type); if (!strcmp(type, "SD") && cid) print_sd_cid(config, cid); else if (!strcmp(type, "MMC") && cid) print_mmc_cid(config, cid); if (!strcmp(type, "SD") && scr) print_sd_scr(config, scr); if (!strcmp(type, "MMC") && csd) print_mmc_csd(config, csd); else if (!strcmp(type, "SD") && csd) print_sd_csd(config, csd); } int process_dir(struct config *config, enum REG_TYPE reg) { char *type = NULL, *cid = NULL, *csd = NULL, *scr = NULL, *ext_csd = NULL; int ret = 0; if (chdir(config->dir) < 0) { fprintf(stderr, "MMC/SD information directory '%s' does not exist.\n", config->dir); return -1; } type = read_file("type"); if (!type) { fprintf(stderr, "Could not read card interface type in directory '%s'.\n", config->dir); return -1; } if (strcmp(type, "MMC") && strcmp(type, "SD")) { fprintf(stderr, "Unknown type: '%s'\n", type); ret = -1; goto err; } switch (reg) { case CID: cid = read_file("cid"); if (!cid) { fprintf(stderr, "Could not read card identity in directory '%s'.\n", config->dir); ret = -1; goto err; } break; case CSD: csd = read_file("csd"); if (!csd) { fprintf(stderr, "Could not read card specific data in " "directory '%s'.\n", config->dir); ret = -1; goto err; } break; case SCR: if (!strcmp(type, "SD")) { scr = read_file("scr"); if (!scr) { fprintf(stderr, "Could not read SD card " "configuration in directory '%s'.\n", config->dir); ret = -1; goto err; } } break; case EXT_CSD: if (!strcmp(type, "MMC")) { ext_csd = read_file("ext_csd"); if (!ext_csd) { fprintf(stderr, "Could not read extra specific " "data in directory '%s'.\n", config->dir); ret = -1; goto err; } } break; default: goto err; } print_info(config, type, cid, csd, scr, ext_csd); err: free(ext_csd); free(scr); free(csd); free(cid); free(type); return ret; } int lsmmc_main(struct config *config, int argc, char **argv) { int ret; memset(config, 0, sizeof(*config)); config->mmc_ids = calloc(IDS_MAX, sizeof(char *)); config->sd_ids = calloc(IDS_MAX, sizeof(char *)); if (!config->mmc_ids || !config->sd_ids) { fprintf(stderr, "Could not allocate memory for lsmmc.\n"); return -1; } ret = parse_opts(argc, argv, config); if (ret) return ret; return parse_ids(config); } void lsmmc_free(struct config *config) { free(config->mmc_ids); free(config->sd_ids); free(config->dir); } int do_read_csd(int argc, char **argv) { struct config config; int ret; if (argc != 2 && argc != 3) { fprintf(stderr, "Usage: Print CSD data from <device path>.\n"); exit(1); } ret = lsmmc_main(&config, argc, argv); if (ret) goto out; if (config.dir) ret = process_dir(&config, CSD); out: lsmmc_free(&config); return ret; } int do_read_cid(int argc, char **argv) { struct config config; int ret; if (argc != 2 && argc != 3) { fprintf(stderr, "Usage: Print CID data from <device path>.\n"); exit(1); } ret = lsmmc_main(&config, argc, argv); if (ret) goto out; if (config.dir) ret = process_dir(&config, CID); out: lsmmc_free(&config); return ret; } int do_read_scr(int argc, char **argv) { struct config config; int ret; if (argc != 2 && argc != 3) { fprintf(stderr, "Usage: Print SCR data from <device path>.\n"); exit(1); } ret = lsmmc_main(&config, argc, argv); if (ret) goto out; if (config.dir) ret = process_dir(&config, SCR); out: lsmmc_free(&config); return ret; } 0707010000000B000041ED0000000000000000000000026202891700000000000000000000000000000000000000000000001F00000000mmc-utils-0.1+git.20220208/man0707010000000C000081A40000000000000000000000016202891700000032000000000000000000000000000000000000002800000000mmc-utils-0.1+git.20220208/man/Makefileall: clean: install: .PHONY: all clean install 0707010000000D000081A40000000000000000000000016202891700001347000000000000000000000000000000000000002500000000mmc-utils-0.1+git.20220208/man/mmc.1.TH MMC 1 "2015-11-16" "0.1" "mmc-utils" .SH NAME mmc-utils \- Configure MMC storage devices from userspace. .SH SYNOPSIS mmc [<command> [<args>]] [--help] .PP mmc [<command>] --help .SH DESCRIPTION mmc-utils is a tool for configuring MMC storage devices from userspace. .SH COMMANDS AND OPTIONS .TP .BR "help | \-\-help | -h | " "(no arguments)" Shows the abbreviated help menu in the terminal. .TP .BR "extcsd read <device>" Print extcsd data from <device>. .TP .BR "writeprotect get <device>" Determine the eMMC writeprotect status of <device>. .TP .BR "writeprotect set <device>" Set the eMMC writeprotect status of <device>. This sets the eMMC to be write-protected until next boot. .TP .BR "disable 512B emulation <device>" Set the eMMC data sector size to 4KB by disabling emulation on <device>. .TP .BR "gp create <-y|-n|-c> <length KiB> <partition> <enh_attr> <ext_attr> <device>" create general purpose partition for the <device>. Dry-run only unless -y or -c is passed. Use -c if more partitioning settings are still to come. To set enhanced attribute to general partition being created set <enh_attr> to 1 else set it to 0. To set extended attribute to general partition set <ext_attr> to 1,2 else set it to 0. NOTE! This is a one-time programmable (unreversible) change. .TP .BR "enh_area set <-y|-n|-c> <start KiB> <length KiB> <device>" Enable the enhanced user area for the <device>. Dry-run only unless -y or -c is passed. Use -c if more partitioning settings are still to come. NOTE! This is a one-time programmable (unreversible) change. .TP .BR "write_reliability set <-y|-n|-c> <partition> <device>" Enable write reliability per partition for the <device>. Dry-run only unless -y or -c is passed. Use -c if more partitioning settings are still to come. NOTE! This is a one-time programmable (unreversible) change. .TP .BR "status get <device>" Print the response to STATUS_SEND (CMD13). .TP .BR "bootpart enable <boot_partition> <send_ack> <device>" Enable the boot partition for the <device>. Disable the boot partition for the <device> with <boot_partition> set to 0. To receive acknowledgment of boot from the card set <send_ack> to 1, else set it to 0. .TP .BR "bootbus set <boot_mode> <reset_boot_bus_conditions> <boot_bus_width> <device>" Set Boot Bus Conditions. <boot_mode> must be "single_backward|single_hs|dual" <reset_boot_bus_conditions> must be "x1|retain" <boot_bus_width> must be "x1|x4|x8" .TP .BR "bkops enable <device>" Enable the eMMC BKOPS feature on <device>. NOTE! This is a one-time programmable (unreversible) change. .TP .BR "hwreset enable <device>" Permanently enable the eMMC H/W Reset feature on <device>. NOTE! This is a one-time programmable (unreversible) change. .TP .BR "hwreset disable <device>" Permanently disable the eMMC H/W Reset feature on <device>. NOTE! This is a one-time programmable (unreversible) change. .TP .BR "sanitize <device>" Send Sanitize command to the <device>. This will delete the unmapped memory region of the device. .TP .BR "rpmb write-key <rpmb device> <key file>" Program authentication key which is 32 bytes length and stored in the specified file. Also you can specify '-' instead of key file path to read the key from stdin. NOTE! This is a one-time programmable (unreversible) change. .TP .BR "rpmb read-counter <rpmb device>" Counter value for the <rpmb device> will be read to stdout. .TP .BR "rpmb read-block <rpmb device> <address> <blocks count> <output file> [key file]" Blocks of 256 bytes will be read from <rpmb device> to output file or stdout if '-' is specified. If key is specified - read data will be verified. Instead of regular path you can specify '-' to read key from stdin. .TP .BR "rpmb write-block <rpmb device> <address> <256 byte data file> <key file>" Block of 256 bytes will be written from data file to <rpmb device>. Also you can specify '-' instead of key file path or data file to read the data from stdin. .TP .BR "cache enable <device>" Enable the eMMC cache feature on <device>. NOTE! The cache is an optional feature on devices >= eMMC4.5. .TP .BR "cache disable <device>" Disable the eMMC cache feature on <device>. NOTE! The cache is an optional feature on devices >= eMMC4.5. .TP .BR "<cmd> --help" Show detailed help for a command or subset of commands. .SH EXAMPLES .TP Program authentication key from stdin: echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH | mmc rpmb write-key /dev/mmcblk0rpmb - .TP Write a block of 256 bytes of data to an rpmb device: $ (awk 'BEGIN {while (c++<256) printf "a"}' | echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH) | mmc rpmb write-block /dev/mmcblk0rpmb 0x02 - - .TP Read a block of 256 bytes of data from an rpmb device to stdout: $ echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH | mmc rpmb read-block /dev/mmcblk0rpmb 0x02 2 /tmp/block - .TP Read 2 blocks of 256 bytes from rpmb device to /tmp/block without verification: $ mmc rpmb read-block /dev/mmcblk0rpmb 0x02 2 /tmp/block 0707010000000E000081A40000000000000000000000016202891700004004000000000000000000000000000000000000002100000000mmc-utils-0.1+git.20220208/mmc.c/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. * * Modified to add field firmware update support, * those modifications are Copyright (c) 2016 SanDisk Corp. * * (This code is based on btrfs-progs/btrfs.c.) */ #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> #include "mmc_cmds.h" #define MMC_VERSION "0.1" #define BASIC_HELP 0 #define ADVANCED_HELP 1 typedef int (*CommandFunction)(int argc, char **argv); struct Command { CommandFunction func; /* function which implements the command */ int nargs; /* if == 999, any number of arguments if >= 0, number of arguments, if < 0, _minimum_ number of arguments */ char *verb; /* verb */ char *help; /* help lines; from the 2nd line onward they are automatically indented */ char *adv_help; /* advanced help message; from the 2nd line onward they are automatically indented */ /* the following fields are run-time filled by the program */ char **cmds; /* array of subcommands */ int ncmds; /* number of subcommand */ }; static struct Command commands[] = { /* * avoid short commands different for the case only */ { do_read_extcsd, -1, "extcsd read", "<device>\n" "Print extcsd data from <device>.", NULL }, { do_writeprotect_boot_get, -1, "writeprotect boot get", "<device>\n" "Print the boot partitions write protect status for <device>.", NULL }, { do_writeprotect_boot_set, -1, "writeprotect boot set", #ifdef DANGEROUS_COMMANDS_ENABLED "[-p] " #endif /* DANGEROUS_COMMANDS_ENABLED */ "<device> [<number>]\n" "Set the boot partition write protect status for <device>.\n" "If <number> is passed (0 or 1), only protect that particular\n" "eMMC boot partition, otherwise protect both. It will be\n" "write-protected until the next boot.\n" #ifdef DANGEROUS_COMMANDS_ENABLED " -p Protect partition permanently instead.\n" " NOTE! -p is a one-time programmable (unreversible) change.\n" #endif /* DANGEROUS_COMMANDS_ENABLED */ , NULL }, { do_writeprotect_user_set, -4, "writeprotect user set", "<type>" "<start block>" "<blocks>" "<device>\n" #ifdef DANGEROUS_COMMANDS_ENABLED "Set the write protect configuration for the specified region\nof the user area for <device>.\n<type> 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<start block> specifies the first block of the protected area.\n<blocks> 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.", #else "Set the write protect configuration for the specified region\nof the user area for <device>.\n<type> 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<start block> specifies the first block of the protected area.\n<blocks> 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.", #endif /* DANGEROUS_COMMANDS_ENABLED */ NULL }, { do_writeprotect_user_get, -1, "writeprotect user get", "<device>\n" "Print the user areas write protect configuration for <device>.", NULL }, { do_disable_512B_emulation, -1, "disable 512B emulation", "<device>\n" "Set the eMMC data sector size to 4KB by disabling emulation on\n<device>.", NULL }, { do_create_gp_partition, -6, "gp create", "<-y|-n|-c> " "<length KiB> " "<partition> " "<enh_attr> " "<ext_attr> " "<device>\n" "Create general purpose partition for the <device>.\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 <enh_attr> to 1 else set it to 0.\nTo set extended attribute to general partition\n set <ext_attr> to 1,2 else set it to 0", NULL }, { do_enh_area_set, -4, "enh_area set", "<-y|-n|-c> " "<start KiB> " "<length KiB> " "<device>\n" "Enable the enhanced user area for the <device>.\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.", NULL }, { do_write_reliability_set, -2, "write_reliability set", "<-y|-n|-c> " "<partition> " "<device>\n" "Enable write reliability per partition for the <device>.\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.", NULL }, { do_status_get, -1, "status get", "<device>\n" "Print the response to STATUS_SEND (CMD13).", NULL }, { do_write_boot_en, -3, "bootpart enable", "<boot_partition> " "<send_ack> " "<device>\n" "Enable the boot partition for the <device>.\nDisable the boot partition for the <device> if <boot_partition> is set to 0.\nTo receive acknowledgment of boot from the card set <send_ack>\nto 1, else set it to 0.", NULL }, { do_boot_bus_conditions_set, -4, "bootbus set", "<boot_mode> " "<reset_boot_bus_conditions> " "<boot_bus_width> " "<device>\n" "Set Boot Bus Conditions.\n" "<boot_mode> must be \"single_backward|single_hs|dual\"\n" "<reset_boot_bus_conditions> must be \"x1|retain\"\n" "<boot_bus_width> must be \"x1|x4|x8\"", NULL }, { do_write_bkops_en, -2, "bkops_en", "<auto|manual> <device>\n" "Enable the eMMC BKOPS feature on <device>.\n" "The auto (AUTO_EN) setting is only supported on eMMC 5.0 or newer.\n" "Setting auto won't have any effect if manual is set.\n" "NOTE! Setting manual (MANUAL_EN) is one-time programmable (unreversible) change.", NULL }, { do_hwreset_en, -1, "hwreset enable", "<device>\n" "Permanently enable the eMMC H/W Reset feature on <device>.\nNOTE! This is a one-time programmable (unreversible) change.", NULL }, { do_hwreset_dis, -1, "hwreset disable", "<device>\n" "Permanently disable the eMMC H/W Reset feature on <device>.\nNOTE! This is a one-time programmable (unreversible) change.", NULL }, { do_sanitize, -1, "sanitize", "<device>\n" "Send Sanitize command to the <device>.\nThis will delete the unmapped memory region of the device.", NULL }, { do_rpmb_write_key, -1, "rpmb write-key", "<rpmb device> <key file>\n" "Program authentication key which is 32 bytes length and stored\n" "in the specified file. Also you can specify '-' instead of\n" "key file path to read the key from stdin.\n" "NOTE! This is a one-time programmable (unreversible) change.\n" "Example:\n" " $ echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH | \\\n" " mmc rpmb write-key /dev/mmcblk0rpmb -", NULL }, { do_rpmb_read_counter, -1, "rpmb read-counter", "<rpmb device>\n" "Counter value for the <rpmb device> will be read to stdout.", NULL }, { do_rpmb_read_block, -1, "rpmb read-block", "<rpmb device> <address> <blocks count> <output file> [key file]\n" "Blocks of 256 bytes will be read from <rpmb device> to output\n" "file or stdout if '-' is specified. If key is specified - read\n" "data will be verified. Instead of regular path you can specify\n" "'-' to read key from stdin.\n" "Example:\n" " $ echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH | \\\n" " mmc rpmb read-block /dev/mmcblk0rpmb 0x02 2 /tmp/block -\n" "or read two blocks without verification\n" " $ mmc rpmb read-block /dev/mmcblk0rpmb 0x02 2 /tmp/block", NULL }, { do_rpmb_write_block, -1, "rpmb write-block", "<rpmb device> <address> <256 byte data file> <key file>\n" "Block of 256 bytes will be written from data file to\n" "<rpmb device>. Also you can specify '-' instead of key\n" "file path or data file to read the data from stdin.\n" "Example:\n" " $ (awk 'BEGIN {while (c++<256) printf \"a\"}' | \\\n" " echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH) | \\\n" " mmc rpmb write-block /dev/mmcblk0rpmb 0x02 - -", NULL }, { do_cache_en, -1, "cache enable", "<device>\n" "Enable the eMMC cache feature on <device>.\n" "NOTE! The cache is an optional feature on devices >= eMMC4.5.", NULL }, { do_cache_dis, -1, "cache disable", "<device>\n" "Disable the eMMC cache feature on <device>.\n" "NOTE! The cache is an optional feature on devices >= eMMC4.5.", NULL }, { do_read_csd, -1, "csd read", "<device path>\n" "Print CSD data from <device path>.\n" "The device path should specify the csd file directory.", NULL }, { do_read_cid, -1, "cid read", "<device path>\n" "Print CID data from <device path>.\n" "The device path should specify the cid file directory.", NULL }, { do_read_scr, -1, "scr read", "<device path>\n" "Print SCR data from <device path>.\n" "The device path should specify the scr file directory.", NULL }, { do_ffu, -2, "ffu", "<image name> <device>\n" "Run Field Firmware Update with <image name> on <device>.\n", NULL }, { do_erase, -4, "erase", "<type> " "<start address> " "<end address> " "<device>\n" "Send Erase CMD38 with specific argument to the <device>\n\n" "NOTE!: This will delete all user data in the specified region of the device\n" "<type> must be: legacy | discard | secure-erase | " "secure-trim1 | secure-trim2 | trim \n", NULL }, { 0, 0, 0, 0 } }; static char *get_prgname(char *programname) { char *np; np = strrchr(programname,'/'); if(!np) np = programname; else np++; return np; } static void print_help(char *programname, struct Command *cmd, int helptype) { char *pc; printf("\t%s %s ", programname, cmd->verb ); if (helptype == ADVANCED_HELP && cmd->adv_help) for(pc = cmd->adv_help; *pc; pc++){ putchar(*pc); if(*pc == '\n') printf("\t\t"); } else for(pc = cmd->help; *pc; pc++){ putchar(*pc); if(*pc == '\n') printf("\t\t"); } putchar('\n'); } static void help(char *np) { struct Command *cp; printf("Usage:\n"); for( cp = commands; cp->verb; cp++ ) print_help(np, cp, BASIC_HELP); printf("\n\t%s help|--help|-h\n\t\tShow the help.\n",np); printf("\n\t%s <cmd> --help\n\t\tShow detailed help for a command or subset of commands.\n",np); printf("\n%s\n", MMC_VERSION); } static int split_command(char *cmd, char ***commands) { int c, l; char *p, *s; for( *commands = 0, l = c = 0, p = s = cmd ; ; p++, l++ ){ if ( *p && *p != ' ' ) continue; /* c + 2 so that we have room for the null */ (*commands) = realloc( (*commands), sizeof(char *)*(c + 2)); (*commands)[c] = strndup(s, l); c++; l = 0; s = p+1; if( !*p ) break; } (*commands)[c] = 0; return c; } /* This function checks if the passed command is ambiguous */ static int check_ambiguity(struct Command *cmd, char **argv){ int i; struct Command *cp; /* check for ambiguity */ for( i = 0 ; i < cmd->ncmds ; i++ ){ int match; for( match = 0, cp = commands; cp->verb; cp++ ){ int j, skip; char *s1, *s2; if( cp->ncmds < i ) continue; for( skip = 0, j = 0 ; j < i ; j++ ) if( strcmp(cmd->cmds[j], cp->cmds[j])){ skip=1; break; } if(skip) continue; if( !strcmp(cmd->cmds[i], cp->cmds[i])) continue; for(s2 = cp->cmds[i], s1 = argv[i+1]; *s1 == *s2 && *s1; s1++, s2++ ) ; if( !*s1 ) match++; } if(match){ int j; fprintf(stderr, "ERROR: in command '"); for( j = 0 ; j <= i ; j++ ) fprintf(stderr, "%s%s",j?" ":"", argv[j+1]); fprintf(stderr, "', '%s' is ambiguous\n",argv[j]); return -2; } } return 0; } /* * This function, compacts the program name and the command in the first * element of the '*av' array */ static int prepare_args(int *ac, char ***av, char *prgname, struct Command *cmd ){ char **ret; int i; char *newname; ret = (char **)malloc(sizeof(char*)*(*ac+1)); newname = (char*)malloc(strlen(prgname)+strlen(cmd->verb)+2); if( !ret || !newname ){ free(ret); free(newname); return -1; } ret[0] = newname; for(i=0; i < *ac ; i++ ) ret[i+1] = (*av)[i]; strcpy(newname, prgname); strcat(newname, " "); strcat(newname, cmd->verb); (*ac)++; *av = ret; return 0; } /* This function performs the following jobs: - show the help if '--help' or 'help' or '-h' are passed - verify that a command is not ambiguous, otherwise show which part of the command is ambiguous - if after a (even partial) command there is '--help' show detailed help for all the matching commands - if the command doesn't match show an error - finally, if a command matches, they return which command matched and the arguments The function return 0 in case of help is requested; <0 in case of uncorrect command; >0 in case of matching commands argc, argv are the arg-counter and arg-vector (input) *nargs_ is the number of the arguments after the command (output) **cmd_ is the invoked command (output) ***args_ are the arguments after the command */ static int parse_args(int argc, char **argv, CommandFunction *func_, int *nargs_, char **cmd_, char ***args_ ) { struct Command *cp; struct Command *matchcmd=0; char *prgname = get_prgname(argv[0]); int i=0, helprequested=0; if( argc < 2 || !strcmp(argv[1], "help") || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){ help(prgname); return 0; } for( cp = commands; cp->verb; cp++ ) if( !cp->ncmds) cp->ncmds = split_command(cp->verb, &(cp->cmds)); for( cp = commands; cp->verb; cp++ ){ int match; if( argc-1 < cp->ncmds ) continue; for( match = 1, i = 0 ; i < cp->ncmds ; i++ ){ char *s1, *s2; s1 = cp->cmds[i]; s2 = argv[i+1]; for(s2 = cp->cmds[i], s1 = argv[i+1]; *s1 == *s2 && *s1; s1++, s2++ ) ; if( *s1 ){ match=0; break; } } /* If you understand why this code works ... you are a genious !! */ if(argc>i+1 && !strcmp(argv[i+1],"--help")){ if(!helprequested) printf("Usage:\n"); print_help(prgname, cp, ADVANCED_HELP); helprequested=1; continue; } if(!match) continue; matchcmd = cp; *nargs_ = argc-matchcmd->ncmds-1; *cmd_ = matchcmd->verb; *args_ = argv+matchcmd->ncmds+1; *func_ = cp->func; break; } if(helprequested){ printf("\n%s\n", MMC_VERSION); return 0; } if(!matchcmd){ fprintf( stderr, "ERROR: unknown command '%s'\n",argv[1]); help(prgname); return -1; } if(check_ambiguity(matchcmd, argv)) return -2; /* check the number of argument */ if (matchcmd->nargs < 0 && matchcmd->nargs < -*nargs_ ){ fprintf(stderr, "ERROR: '%s' requires minimum %d arg(s)\n", matchcmd->verb, -matchcmd->nargs); return -2; } if(matchcmd->nargs >= 0 && matchcmd->nargs != *nargs_ && matchcmd->nargs != 999){ fprintf(stderr, "ERROR: '%s' requires %d arg(s)\n", matchcmd->verb, matchcmd->nargs); return -2; } if (prepare_args( nargs_, args_, prgname, matchcmd )){ fprintf(stderr, "ERROR: not enough memory\\n"); return -20; } return 1; } int main(int ac, char **av ) { char *cmd=0, **args=0; int nargs=0, r; CommandFunction func=0; r = parse_args(ac, av, &func, &nargs, &cmd, &args); if( r <= 0 ){ /* error or no command to parse*/ exit(-r); } exit(func(nargs, args)); } 0707010000000F000081A400000000000000000000000162028917000020F8000000000000000000000000000000000000002100000000mmc-utils-0.1+git.20220208/mmc.h/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. * * Modified to add field firmware update support, * those modifications are Copyright (c) 2016 SanDisk Corp. */ #include <linux/mmc/ioctl.h> /* From kernel linux/mmc/mmc.h */ #define MMC_SWITCH 6 /* ac [31:0] See below R1b */ #define MMC_SEND_EXT_CSD 8 /* adtc R1 */ #define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ #define R1_SWITCH_ERROR (1 << 7) /* sx, c */ #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ #define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ #define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */ #define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ #define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */ #define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */ #define MMC_CLEAR_WRITE_PROT 29 /* ac [31:0] data addr R1b */ #define MMC_SEND_WRITE_PROT_TYPE 31 /* ac [31:0] data addr R1 */ #define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */ #define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */ #define MMC_ERASE 38 /* ac [31] Secure request [30:16] set to 0 [15] Force Garbage Collect request [14:2] set to 0 [1] Discard Enable [0] Identify Write Blocks for Erase (or TRIM Enable) R1b */ /* * EXT_CSD fields */ #define EXT_CSD_S_CMD_SET 504 #define EXT_CSD_HPI_FEATURE 503 #define EXT_CSD_BKOPS_SUPPORT 502 /* RO */ #define EXT_CSD_SUPPORTED_MODES 493 /* RO */ #define EXT_CSD_FFU_FEATURES 492 /* RO */ #define EXT_CSD_FFU_ARG_3 490 /* RO */ #define EXT_CSD_FFU_ARG_2 489 /* RO */ #define EXT_CSD_FFU_ARG_1 488 /* RO */ #define EXT_CSD_FFU_ARG_0 487 /* RO */ #define EXT_CSD_CMDQ_DEPTH 307 /* RO */ #define EXT_CSD_CMDQ_SUPPORT 308 /* RO */ #define EXT_CSD_NUM_OF_FW_SEC_PROG_3 305 /* RO */ #define EXT_CSD_NUM_OF_FW_SEC_PROG_2 304 /* RO */ #define EXT_CSD_NUM_OF_FW_SEC_PROG_1 303 /* RO */ #define EXT_CSD_NUM_OF_FW_SEC_PROG_0 302 /* RO */ #define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B 269 /* RO */ #define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A 268 /* RO */ #define EXT_CSD_PRE_EOL_INFO 267 /* RO */ #define EXT_CSD_FIRMWARE_VERSION 254 /* RO */ #define EXT_CSD_CACHE_SIZE_3 252 #define EXT_CSD_CACHE_SIZE_2 251 #define EXT_CSD_CACHE_SIZE_1 250 #define EXT_CSD_CACHE_SIZE_0 249 #define EXT_CSD_SEC_FEATURE_SUPPORT 231 #define EXT_CSD_BOOT_INFO 228 /* R/W */ #define EXT_CSD_HC_ERASE_GRP_SIZE 224 #define EXT_CSD_HC_WP_GRP_SIZE 221 #define EXT_CSD_SEC_COUNT_3 215 #define EXT_CSD_SEC_COUNT_2 214 #define EXT_CSD_SEC_COUNT_1 213 #define EXT_CSD_SEC_COUNT_0 212 #define EXT_CSD_PART_SWITCH_TIME 199 #define EXT_CSD_REV 192 #define EXT_CSD_BOOT_CFG 179 #define EXT_CSD_PART_CONFIG 179 #define EXT_CSD_BOOT_BUS_CONDITIONS 177 #define EXT_CSD_ERASE_GROUP_DEF 175 #define EXT_CSD_BOOT_WP_STATUS 174 #define EXT_CSD_BOOT_WP 173 #define EXT_CSD_USER_WP 171 #define EXT_CSD_FW_CONFIG 169 /* R/W */ #define EXT_CSD_WR_REL_SET 167 #define EXT_CSD_WR_REL_PARAM 166 #define EXT_CSD_SANITIZE_START 165 #define EXT_CSD_BKOPS_EN 163 /* R/W */ #define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ #define EXT_CSD_PARTITIONING_SUPPORT 160 /* RO */ #define EXT_CSD_MAX_ENH_SIZE_MULT_2 159 #define EXT_CSD_MAX_ENH_SIZE_MULT_1 158 #define EXT_CSD_MAX_ENH_SIZE_MULT_0 157 #define EXT_CSD_PARTITIONS_ATTRIBUTE 156 /* R/W */ #define EXT_CSD_PARTITION_SETTING_COMPLETED 155 /* R/W */ #define EXT_CSD_GP_SIZE_MULT_4_2 154 #define EXT_CSD_GP_SIZE_MULT_4_1 153 #define EXT_CSD_GP_SIZE_MULT_4_0 152 #define EXT_CSD_GP_SIZE_MULT_3_2 151 #define EXT_CSD_GP_SIZE_MULT_3_1 150 #define EXT_CSD_GP_SIZE_MULT_3_0 149 #define EXT_CSD_GP_SIZE_MULT_2_2 148 #define EXT_CSD_GP_SIZE_MULT_2_1 147 #define EXT_CSD_GP_SIZE_MULT_2_0 146 #define EXT_CSD_GP_SIZE_MULT_1_2 145 #define EXT_CSD_GP_SIZE_MULT_1_1 144 #define EXT_CSD_GP_SIZE_MULT_1_0 143 #define EXT_CSD_ENH_SIZE_MULT_2 142 #define EXT_CSD_ENH_SIZE_MULT_1 141 #define EXT_CSD_ENH_SIZE_MULT_0 140 #define EXT_CSD_ENH_START_ADDR_3 139 #define EXT_CSD_ENH_START_ADDR_2 138 #define EXT_CSD_ENH_START_ADDR_1 137 #define EXT_CSD_ENH_START_ADDR_0 136 #define EXT_CSD_NATIVE_SECTOR_SIZE 63 /* R */ #define EXT_CSD_USE_NATIVE_SECTOR 62 /* R/W */ #define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */ #define EXT_CSD_EXT_PARTITIONS_ATTRIBUTE_1 53 #define EXT_CSD_EXT_PARTITIONS_ATTRIBUTE_0 52 #define EXT_CSD_CACHE_CTRL 33 #define EXT_CSD_MODE_CONFIG 30 #define EXT_CSD_MODE_OPERATION_CODES 29 /* W */ #define EXT_CSD_FFU_STATUS 26 /* R */ #define EXT_CSD_SECURE_REMOVAL_TYPE 16 /* R/W */ #define EXT_CSD_CMDQ_MODE_EN 15 /* R/W */ /* * WR_REL_PARAM field definitions */ #define HS_CTRL_REL (1<<0) #define EN_REL_WR (1<<2) /* * BKOPS_EN field definitions */ #define BKOPS_MAN_ENABLE (1<<0) #define BKOPS_AUTO_ENABLE (1<<1) /* * EXT_CSD field definitions */ #define EXT_CSD_CONFIG_SECRM_TYPE (0x30) #define EXT_CSD_SUPPORTED_SECRM_TYPE (0x0f) #define EXT_CSD_FFU_INSTALL (0x01) #define EXT_CSD_FFU_MODE (0x01) #define EXT_CSD_NORMAL_MODE (0x00) #define EXT_CSD_FFU (1<<0) #define EXT_CSD_UPDATE_DISABLE (1<<0) #define EXT_CSD_HPI_SUPP (1<<0) #define EXT_CSD_HPI_IMPL (1<<1) #define EXT_CSD_CMD_SET_NORMAL (1<<0) /* NOTE: The eMMC spec calls the partitions "Area 1" and "Area 2", but Linux * calls them mmcblk0boot0 and mmcblk0boot1. To avoid confustion between the two * numbering schemes, this tool uses 0 and 1 throughout. */ #define EXT_CSD_BOOT_WP_S_AREA_1_PERM (0x08) #define EXT_CSD_BOOT_WP_S_AREA_1_PWR (0x04) #define EXT_CSD_BOOT_WP_S_AREA_0_PERM (0x02) #define EXT_CSD_BOOT_WP_S_AREA_0_PWR (0x01) #define EXT_CSD_BOOT_WP_B_SEC_WP_SEL (0x80) #define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40) #define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10) #define EXT_CSD_BOOT_WP_B_PERM_WP_SEC_SEL (0x08) #define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04) #define EXT_CSD_BOOT_WP_B_PWR_WP_SEC_SEL (0x02) #define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01) #define EXT_CSD_BOOT_INFO_HS_MODE (1<<2) #define EXT_CSD_BOOT_INFO_DDR_DDR (1<<1) #define EXT_CSD_BOOT_INFO_ALT (1<<0) #define EXT_CSD_BOOT_CFG_ACK (1<<6) #define EXT_CSD_BOOT_CFG_EN (0x38) #define EXT_CSD_BOOT_CFG_ACC (0x07) #define EXT_CSD_RST_N_EN_MASK (0x03) #define EXT_CSD_HW_RESET_EN (0x01) #define EXT_CSD_HW_RESET_DIS (0x02) #define EXT_CSD_PART_CONFIG_ACC_MASK (0x7) #define EXT_CSD_PART_CONFIG_ACC_NONE (0x0) #define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1) #define EXT_CSD_PART_CONFIG_ACC_BOOT1 (0x2) #define EXT_CSD_PART_CONFIG_ACC_USER_AREA (0x7) #define EXT_CSD_PART_CONFIG_ACC_ACK (0x40) #define EXT_CSD_PARTITIONING_EN (1<<0) #define EXT_CSD_ENH_ATTRIBUTE_EN (1<<1) #define EXT_CSD_ENH_4 (1<<4) #define EXT_CSD_ENH_3 (1<<3) #define EXT_CSD_ENH_2 (1<<2) #define EXT_CSD_ENH_1 (1<<1) #define EXT_CSD_ENH_USR (1<<0) #define EXT_CSD_REV_V5_1 8 #define EXT_CSD_REV_V5_0 7 #define EXT_CSD_REV_V4_5 6 #define EXT_CSD_REV_V4_4_1 5 #define EXT_CSD_REV_V4_3 3 #define EXT_CSD_REV_V4_2 2 #define EXT_CSD_REV_V4_1 1 #define EXT_CSD_REV_V4_0 0 #define EXT_CSD_SEC_GB_CL_EN (1<<4) #define EXT_CSD_SEC_ER_EN (1<<0) /* From kernel linux/mmc/core.h */ #define MMC_RSP_PRESENT (1 << 0) #define MMC_RSP_136 (1 << 1) /* 136 bit response */ #define MMC_RSP_CRC (1 << 2) /* expect valid crc */ #define MMC_RSP_BUSY (1 << 3) /* card may send busy */ #define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */ #define MMC_CMD_AC (0 << 5) #define MMC_CMD_ADTC (1 << 5) #define MMC_RSP_SPI_S1 (1 << 7) /* one status byte */ #define MMC_RSP_SPI_BUSY (1 << 10) /* card may send busy */ #define MMC_RSP_SPI_R1 (MMC_RSP_SPI_S1) #define MMC_RSP_SPI_R1B (MMC_RSP_SPI_S1|MMC_RSP_SPI_BUSY) #define MMC_RSP_R1 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) #define MMC_RSP_R1B (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY) 07070100000010000081A400000000000000000000000162028917000125D0000000000000000000000000000000000000002600000000mmc-utils-0.1+git.20220208/mmc_cmds.c/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. * * Modified to add field firmware update support, * those modifications are Copyright (c) 2016 SanDisk Corp. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <stdint.h> #include <assert.h> #include <linux/fs.h> /* for BLKGETSIZE */ #include "mmc.h" #include "mmc_cmds.h" #include "3rdparty/hmac_sha/hmac_sha2.h" #ifndef offsetof #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif #define WP_BLKS_PER_QUERY 32 #define USER_WP_PERM_PSWD_DIS 0x80 #define USER_WP_CD_PERM_WP_DIS 0x40 #define USER_WP_US_PERM_WP_DIS 0x10 #define USER_WP_US_PWR_WP_DIS 0x08 #define USER_WP_US_PERM_WP_EN 0x04 #define USER_WP_US_PWR_WP_EN 0x01 #define USER_WP_CLEAR (USER_WP_US_PERM_WP_DIS | USER_WP_US_PWR_WP_DIS \ | USER_WP_US_PERM_WP_EN | USER_WP_US_PWR_WP_EN) #define WPTYPE_NONE 0 #define WPTYPE_TEMP 1 #define WPTYPE_PWRON 2 #define WPTYPE_PERM 3 int read_extcsd(int fd, __u8 *ext_csd) { int ret = 0; struct mmc_ioc_cmd idata; memset(&idata, 0, sizeof(idata)); memset(ext_csd, 0, sizeof(__u8) * 512); idata.write_flag = 0; idata.opcode = MMC_SEND_EXT_CSD; idata.arg = 0; idata.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; idata.blksz = 512; idata.blocks = 1; mmc_ioc_cmd_set_data(idata, ext_csd); ret = ioctl(fd, MMC_IOC_CMD, &idata); if (ret) perror("ioctl"); return ret; } int write_extcsd_value(int fd, __u8 index, __u8 value) { int ret = 0; struct mmc_ioc_cmd idata; memset(&idata, 0, sizeof(idata)); idata.write_flag = 1; idata.opcode = MMC_SWITCH; idata.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (index << 16) | (value << 8) | EXT_CSD_CMD_SET_NORMAL; idata.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; ret = ioctl(fd, MMC_IOC_CMD, &idata); if (ret) perror("ioctl"); return ret; } int send_status(int fd, __u32 *response) { int ret = 0; struct mmc_ioc_cmd idata; memset(&idata, 0, sizeof(idata)); idata.opcode = MMC_SEND_STATUS; idata.arg = (1 << 16); idata.flags = MMC_RSP_R1 | MMC_CMD_AC; ret = ioctl(fd, MMC_IOC_CMD, &idata); if (ret) perror("ioctl"); *response = idata.response[0]; return ret; } static __u32 get_size_in_blks(int fd) { int res; int size; res = ioctl(fd, BLKGETSIZE, &size); if (res) { fprintf(stderr, "Error getting device size, errno: %d\n", errno); perror(""); return -1; } return size; } static int set_write_protect(int fd, __u32 blk_addr, int on_off) { int ret = 0; struct mmc_ioc_cmd idata; memset(&idata, 0, sizeof(idata)); idata.write_flag = 1; if (on_off) idata.opcode = MMC_SET_WRITE_PROT; else idata.opcode = MMC_CLEAR_WRITE_PROT; idata.arg = blk_addr; idata.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; ret = ioctl(fd, MMC_IOC_CMD, &idata); if (ret) perror("ioctl"); return ret; } static int send_write_protect_type(int fd, __u32 blk_addr, __u64 *group_bits) { int ret = 0; struct mmc_ioc_cmd idata; __u8 buf[8]; __u64 bits = 0; int x; memset(&idata, 0, sizeof(idata)); idata.write_flag = 0; idata.opcode = MMC_SEND_WRITE_PROT_TYPE; idata.blksz = 8, idata.blocks = 1, idata.arg = blk_addr; idata.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; mmc_ioc_cmd_set_data(idata, buf); ret = ioctl(fd, MMC_IOC_CMD, &idata); if (ret) perror("ioctl"); for (x = 0; x < sizeof(buf); x++) bits |= (__u64)(buf[7 - x]) << (x * 8); *group_bits = bits; return ret; } static void print_writeprotect_boot_status(__u8 *ext_csd) { __u8 reg; __u8 ext_csd_rev = ext_csd[EXT_CSD_REV]; /* A43: reserved [174:0] */ if (ext_csd_rev >= 5) { printf("Boot write protection status registers" " [BOOT_WP_STATUS]: 0x%02x\n", ext_csd[174]); reg = ext_csd[EXT_CSD_BOOT_WP]; printf("Boot Area Write protection [BOOT_WP]: 0x%02x\n", reg); printf(" Power ro locking: "); if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_DIS) printf("not possible\n"); else printf("possible\n"); printf(" Permanent ro locking: "); if (reg & EXT_CSD_BOOT_WP_B_PERM_WP_DIS) printf("not possible\n"); else printf("possible\n"); reg = ext_csd[EXT_CSD_BOOT_WP_STATUS]; printf(" partition 0 ro lock status: "); if (reg & EXT_CSD_BOOT_WP_S_AREA_0_PERM) printf("locked permanently\n"); else if (reg & EXT_CSD_BOOT_WP_S_AREA_0_PWR) printf("locked until next power on\n"); else printf("not locked\n"); printf(" partition 1 ro lock status: "); if (reg & EXT_CSD_BOOT_WP_S_AREA_1_PERM) printf("locked permanently\n"); else if (reg & EXT_CSD_BOOT_WP_S_AREA_1_PWR) printf("locked until next power on\n"); else printf("not locked\n"); } } static int get_wp_group_size_in_blks(__u8 *ext_csd, __u32 *size) { __u8 ext_csd_rev = ext_csd[EXT_CSD_REV]; if ((ext_csd_rev < 5) || (ext_csd[EXT_CSD_ERASE_GROUP_DEF] == 0)) return 1; *size = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * ext_csd[EXT_CSD_HC_WP_GRP_SIZE] * 1024; return 0; } int do_writeprotect_boot_get(int nargs, char **argv) { __u8 ext_csd[512]; int fd, ret; char *device; if (nargs != 2) { fprintf(stderr, "Usage: mmc writeprotect boot get </path/to/mmcblkX>\n"); exit(1); } device = argv[1]; fd = open(device, O_RDWR); if (fd < 0) { perror("open"); exit(1); } ret = read_extcsd(fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); exit(1); } print_writeprotect_boot_status(ext_csd); close(fd); return ret; } int do_writeprotect_boot_set(int nargs, char **argv) { __u8 ext_csd[512], value; int fd, ret; char *device; char *end; int argi = 1; int permanent = 0; int partition = -1; #ifdef DANGEROUS_COMMANDS_ENABLED if (!strcmp(argv[argi], "-p")){ permanent = 1; argi++; } #endif if (nargs < 1 + argi || nargs > 2 + argi) { fprintf(stderr, "Usage: mmc writeprotect boot set " #ifdef DANGEROUS_COMMANDS_ENABLED "[-p] " #endif "</path/to/mmcblkX> [0|1]\n"); exit(1); } device = argv[argi++]; fd = open(device, O_RDWR); if (fd < 0) { perror("open"); exit(1); } if (nargs == 1 + argi) { partition = strtoul(argv[argi], &end, 0); if (*end != '\0' || !(partition == 0 || partition == 1)) { fprintf(stderr, "Invalid partition number (must be 0 or 1): %s\n", argv[argi]); exit(1); } } ret = read_extcsd(fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); exit(1); } value = ext_csd[EXT_CSD_BOOT_WP]; /* * If permanent protection is already on for one partition and we're * trying to enable power-reset protection for the other we need to make * sure the selection bit for permanent protection still points to the * former or we'll accidentally permanently protect the latter. */ if ((value & EXT_CSD_BOOT_WP_B_PERM_WP_EN) && !permanent) { if (ext_csd[EXT_CSD_BOOT_WP_STATUS] & EXT_CSD_BOOT_WP_S_AREA_1_PERM) { value |= EXT_CSD_BOOT_WP_B_PERM_WP_SEC_SEL; if (partition != 1) partition = 0; } else { /* PERM_WP_SEC_SEL cleared -> pointing to partition 0 */ if (partition != 0) partition = 1; } } if (partition != -1) { value |= EXT_CSD_BOOT_WP_B_SEC_WP_SEL; if (partition == 1) value |= permanent ? EXT_CSD_BOOT_WP_B_PERM_WP_SEC_SEL : EXT_CSD_BOOT_WP_B_PWR_WP_SEC_SEL; } value |= permanent ? EXT_CSD_BOOT_WP_B_PERM_WP_EN : EXT_CSD_BOOT_WP_B_PWR_WP_EN; ret = write_extcsd_value(fd, EXT_CSD_BOOT_WP, value); if (ret) { fprintf(stderr, "Could not write 0x%02x to " "EXT_CSD[%d] in %s\n", value, EXT_CSD_BOOT_WP, device); exit(1); } close(fd); return ret; } static char *prot_desc[] = { "No", "Temporary", "Power-on", "Permanent" }; static void print_wp_status(__u32 wp_sizeblks, __u32 start_group, __u32 end_group, int rptype) { printf("Write Protect Groups %d-%d (Blocks %d-%d), ", start_group, end_group, start_group * wp_sizeblks, ((end_group + 1) * wp_sizeblks) - 1); printf("%s Write Protection\n", prot_desc[rptype]); } int do_writeprotect_user_get(int nargs, char **argv) { __u8 ext_csd[512]; int fd, ret; char *device; int x; int y = 0; __u32 wp_sizeblks; __u32 dev_sizeblks; __u32 cnt; __u64 bits; __u32 wpblk; __u32 last_wpblk = 0; __u32 prot; __u32 last_prot = -1; int remain; if (nargs != 2) { fprintf(stderr, "Usage: mmc writeprotect user get </path/to/mmcblkX>\n"); exit(1); } device = argv[1]; fd = open(device, O_RDWR); if (fd < 0) { perror("open"); exit(1); } ret = read_extcsd(fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); exit(1); } ret = get_wp_group_size_in_blks(ext_csd, &wp_sizeblks); if (ret) exit(1); printf("Write Protect Group size in blocks/bytes: %d/%d\n", wp_sizeblks, wp_sizeblks * 512); dev_sizeblks = get_size_in_blks(fd); cnt = dev_sizeblks / wp_sizeblks; for (x = 0; x < cnt; x += WP_BLKS_PER_QUERY) { ret = send_write_protect_type(fd, x * wp_sizeblks, &bits); if (ret) break; remain = cnt - x; if (remain > WP_BLKS_PER_QUERY) remain = WP_BLKS_PER_QUERY; for (y = 0; y < remain; y++) { prot = (bits >> (y * 2)) & 0x3; if (prot != last_prot) { /* not first time */ if (last_prot != -1) { wpblk = x + y; print_wp_status(wp_sizeblks, last_wpblk, wpblk - 1, last_prot); last_wpblk = wpblk; } last_prot = prot; } } } if (last_wpblk != (x + y - 1)) print_wp_status(wp_sizeblks, last_wpblk, cnt - 1, last_prot); close(fd); return ret; } int do_writeprotect_user_set(int nargs, char **argv) { __u8 ext_csd[512]; int fd, ret; char *device; int blk_start; int blk_cnt; __u32 wp_blks; __u8 user_wp; int x; int wptype; if (nargs != 5) goto usage; device = argv[4]; fd = open(device, O_RDWR); if (fd < 0) { perror("open"); exit(1); } if (!strcmp(argv[1], "none")) { wptype = WPTYPE_NONE; } else if (!strcmp(argv[1], "temp")) { wptype = WPTYPE_TEMP; } else if (!strcmp(argv[1], "pwron")) { wptype = WPTYPE_PWRON; #ifdef DANGEROUS_COMMANDS_ENABLED } else if (!strcmp(argv[1], "perm")) { wptype = WPTYPE_PERM; #endif /* DANGEROUS_COMMANDS_ENABLED */ } else { fprintf(stderr, "Error, invalid \"type\"\n"); goto usage; } ret = read_extcsd(fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); exit(1); } ret = get_wp_group_size_in_blks(ext_csd, &wp_blks); if (ret) { fprintf(stderr, "Operation not supported for this device\n"); exit(1); } blk_start = strtol(argv[2], NULL, 0); blk_cnt = strtol(argv[3], NULL, 0); if ((blk_start % wp_blks) || (blk_cnt % wp_blks)) { fprintf(stderr, "<start block> and <blocks> must be a "); fprintf(stderr, "multiple of the Write Protect Group (%d)\n", wp_blks); exit(1); } if (wptype != WPTYPE_NONE) { user_wp = ext_csd[EXT_CSD_USER_WP]; user_wp &= ~USER_WP_CLEAR; switch (wptype) { case WPTYPE_TEMP: break; case WPTYPE_PWRON: user_wp |= USER_WP_US_PWR_WP_EN; break; case WPTYPE_PERM: user_wp |= USER_WP_US_PERM_WP_EN; break; } if (user_wp != ext_csd[EXT_CSD_USER_WP]) { ret = write_extcsd_value(fd, EXT_CSD_USER_WP, user_wp); if (ret) { fprintf(stderr, "Error setting EXT_CSD\n"); exit(1); } } } for (x = 0; x < blk_cnt; x += wp_blks) { ret = set_write_protect(fd, blk_start + x, wptype != WPTYPE_NONE); if (ret) { fprintf(stderr, "Could not set write protect for %s\n", device); exit(1); } } if (wptype != WPTYPE_NONE) { ret = write_extcsd_value(fd, EXT_CSD_USER_WP, ext_csd[EXT_CSD_USER_WP]); if (ret) { fprintf(stderr, "Error restoring EXT_CSD\n"); exit(1); } } return ret; usage: fprintf(stderr, "Usage: mmc writeprotect user set <type><start block><blocks><device>\n"); exit(1); } int do_disable_512B_emulation(int nargs, char **argv) { __u8 ext_csd[512], native_sector_size, data_sector_size, wr_rel_param; int fd, ret; char *device; if (nargs != 2) { fprintf(stderr, "Usage: mmc disable 512B emulation </path/to/mmcblkX>\n"); exit(1); } device = argv[1]; fd = open(device, O_RDWR); if (fd < 0) { perror("open"); exit(1); } ret = read_extcsd(fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); exit(1); } wr_rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; native_sector_size = ext_csd[EXT_CSD_NATIVE_SECTOR_SIZE]; data_sector_size = ext_csd[EXT_CSD_DATA_SECTOR_SIZE]; if (native_sector_size && !data_sector_size && (wr_rel_param & EN_REL_WR)) { ret = write_extcsd_value(fd, EXT_CSD_USE_NATIVE_SECTOR, 1); if (ret) { fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n", 1, EXT_CSD_NATIVE_SECTOR_SIZE, device); exit(1); } printf("MMC disable 512B emulation successful. Now reset the device to switch to 4KB native sector mode.\n"); } else if (native_sector_size && data_sector_size) { printf("MMC 512B emulation mode is already disabled; doing nothing.\n"); } else { printf("MMC does not support disabling 512B emulation mode.\n"); } close(fd); return ret; } int do_write_boot_en(int nargs, char **argv) { __u8 ext_csd[512]; __u8 value = 0; int fd, ret; char *device; int boot_area, send_ack; if (nargs != 4) { fprintf(stderr, "Usage: mmc bootpart enable <partition_number> <send_ack> </path/to/mmcblkX>\n"); exit(1); } /* * If <send_ack> is 1, the device will send acknowledgment * pattern "010" to the host when boot operation begins. * If <send_ack> is 0, it won't. */ boot_area = strtol(argv[1], NULL, 10); send_ack = strtol(argv[2], NULL, 10); device = argv[3]; fd = open(device, O_RDWR); if (fd < 0) { perror("open"); exit(1); } ret = read_extcsd(fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); exit(1); } value = ext_csd[EXT_CSD_PART_CONFIG]; switch (boot_area) { case EXT_CSD_PART_CONFIG_ACC_NONE: value &= ~(7 << 3); break; case EXT_CSD_PART_CONFIG_ACC_BOOT0: value |= (1 << 3); value &= ~(3 << 4); break; case EXT_CSD_PART_CONFIG_ACC_BOOT1: value |= (1 << 4); value &= ~(1 << 3); value &= ~(1 << 5); break; case EXT_CSD_PART_CONFIG_ACC_USER_AREA: value |= (boot_area << 3); break; default: fprintf(stderr, "Cannot enable the boot area\n"); exit(1); } if (send_ack) value |= EXT_CSD_PART_CONFIG_ACC_ACK; else value &= ~EXT_CSD_PART_CONFIG_ACC_ACK; ret = write_extcsd_value(fd, EXT_CSD_PART_CONFIG, value); if (ret) { fprintf(stderr, "Could not write 0x%02x to " "EXT_CSD[%d] in %s\n", value, EXT_CSD_PART_CONFIG, device); exit(1); } close(fd); return ret; } int do_boot_bus_conditions_set(int nargs, char **argv) { __u8 ext_csd[512]; __u8 value = 0; int fd, ret; char *device; if (nargs != 5) { fprintf(stderr, "Usage: mmc: bootbus set <boot_mode> <reset_boot_bus_conditions> <boot_bus_width> <device>\n"); exit(1); } if (strcmp(argv[1], "single_backward") == 0) value |= 0; else if (strcmp(argv[1], "single_hs") == 0) value |= 0x8; else if (strcmp(argv[1], "dual") == 0) value |= 0x10; else { fprintf(stderr, "illegal <boot_mode> specified\n"); exit(1); } if (strcmp(argv[2], "x1") == 0) value |= 0; else if (strcmp(argv[2], "retain") == 0) value |= 0x4; else { fprintf(stderr, "illegal <reset_boot_bus_conditions> specified\n"); exit(1); } if (strcmp(argv[3], "x1") == 0) value |= 0; else if (strcmp(argv[3], "x4") == 0) value |= 0x1; else if (strcmp(argv[3], "x8") == 0) value |= 0x2; else { fprintf(stderr, "illegal <boot_bus_width> specified\n"); exit(1); } device = argv[4]; fd = open(device, O_RDWR); if (fd < 0) { perror("open"); exit(1); } ret = read_extcsd(fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); exit(1); } printf("Changing ext_csd[BOOT_BUS_CONDITIONS] from 0x%02x to 0x%02x\n", ext_csd[EXT_CSD_BOOT_BUS_CONDITIONS], value); ret = write_extcsd_value(fd, EXT_CSD_BOOT_BUS_CONDITIONS, value); if (ret) { fprintf(stderr, "Could not write 0x%02x to " "EXT_CSD[%d] in %s\n", value, EXT_CSD_BOOT_BUS_CONDITIONS, device); exit(1); } close(fd); return ret; } int do_hwreset(int value, int nargs, char **argv) { __u8 ext_csd[512]; int fd, ret; char *device; if (nargs != 2) { fprintf(stderr, "Usage: mmc hwreset enable </path/to/mmcblkX>\n"); exit(1); } device = argv[1]; fd = open(device, O_RDWR); if (fd < 0) { perror("open"); exit(1); } ret = read_extcsd(fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); exit(1); } if ((ext_csd[EXT_CSD_RST_N_FUNCTION] & EXT_CSD_RST_N_EN_MASK) == EXT_CSD_HW_RESET_EN) { fprintf(stderr, "H/W Reset is already permanently enabled on %s\n", device); exit(1); } if ((ext_csd[EXT_CSD_RST_N_FUNCTION] & EXT_CSD_RST_N_EN_MASK) == EXT_CSD_HW_RESET_DIS) { fprintf(stderr, "H/W Reset is already permanently disabled on %s\n", device); exit(1); } ret = write_extcsd_value(fd, EXT_CSD_RST_N_FUNCTION, value); if (ret) { fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n", value, EXT_CSD_RST_N_FUNCTION, device); exit(1); } close(fd); return ret; } int do_hwreset_en(int nargs, char **argv) { return do_hwreset(EXT_CSD_HW_RESET_EN, nargs, argv); } int do_hwreset_dis(int nargs, char **argv) { return do_hwreset(EXT_CSD_HW_RESET_DIS, nargs, argv); } int do_write_bkops_en(int nargs, char **argv) { __u8 ext_csd[512], value = 0; int fd, ret; char *device; char *en_type; if (nargs != 3) { fprintf(stderr, "Usage: mmc bkops_en <auto|manual> </path/to/mmcblkX>\n"); exit(1); } en_type = argv[1]; device = argv[2]; fd = open(device, O_RDWR); if (fd < 0) { perror("open"); exit(1); } ret = read_extcsd(fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); exit(1); } if (strcmp(en_type, "auto") == 0) { if (ext_csd[EXT_CSD_REV] < EXT_CSD_REV_V5_0) { fprintf(stderr, "%s doesn't support AUTO_EN in the BKOPS_EN register\n", device); exit(1); } ret = write_extcsd_value(fd, EXT_CSD_BKOPS_EN, BKOPS_AUTO_ENABLE); } else if (strcmp(en_type, "manual") == 0) { ret = write_extcsd_value(fd, EXT_CSD_BKOPS_EN, BKOPS_MAN_ENABLE); } else { fprintf(stderr, "%s invalid mode for BKOPS_EN requested: %s. Valid options: auto or manual\n", en_type, device); exit(1); } if (ret) { fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n", value, EXT_CSD_BKOPS_EN, device); exit(1); } close(fd); return ret; } int do_status_get(int nargs, char **argv) { __u32 response; int fd, ret; char *device; if (nargs != 2) { fprintf(stderr, "Usage: mmc status get </path/to/mmcblkX>\n"); exit(1); } device = argv[1]; fd = open(device, O_RDWR); if (fd < 0) { perror("open"); exit(1); } ret = send_status(fd, &response); if (ret) { fprintf(stderr, "Could not read response to SEND_STATUS from %s\n", device); exit(1); } printf("SEND_STATUS response: 0x%08x\n", response); close(fd); return ret; } unsigned int get_sector_count(__u8 *ext_csd) { return (ext_csd[EXT_CSD_SEC_COUNT_3] << 24) | (ext_csd[EXT_CSD_SEC_COUNT_2] << 16) | (ext_csd[EXT_CSD_SEC_COUNT_1] << 8) | ext_csd[EXT_CSD_SEC_COUNT_0]; } int is_blockaddresed(__u8 *ext_csd) { unsigned int sectors = get_sector_count(ext_csd); /* over 2GiB devices are block-addressed */ return (sectors > (2u * 1024 * 1024 * 1024) / 512); } unsigned int get_hc_wp_grp_size(__u8 *ext_csd) { return ext_csd[221]; } unsigned int get_hc_erase_grp_size(__u8 *ext_csd) { return ext_csd[224]; } int set_partitioning_setting_completed(int dry_run, const char * const device, int fd) { int ret; if (dry_run == 1) { fprintf(stderr, "NOT setting PARTITION_SETTING_COMPLETED\n"); fprintf(stderr, "These changes will not take effect neither " "now nor after a power cycle\n"); return 1; } else if (dry_run == 2) { printf("-c given, expecting more partition settings before " "writing PARTITION_SETTING_COMPLETED\n"); return 0; } fprintf(stderr, "setting OTP PARTITION_SETTING_COMPLETED!\n"); ret = write_extcsd_value(fd, EXT_CSD_PARTITION_SETTING_COMPLETED, 0x1); if (ret) { fprintf(stderr, "Could not write 0x1 to " "EXT_CSD[%d] in %s\n", EXT_CSD_PARTITION_SETTING_COMPLETED, device); return 1; } __u32 response; ret = send_status(fd, &response); if (ret) { fprintf(stderr, "Could not get response to SEND_STATUS " "from %s\n", device); return 1; } if (response & R1_SWITCH_ERROR) { fprintf(stderr, "Setting OTP PARTITION_SETTING_COMPLETED " "failed on %s\n", device); return 1; } fprintf(stderr, "Setting OTP PARTITION_SETTING_COMPLETED on " "%s SUCCESS\n", device); fprintf(stderr, "Device power cycle needed for settings to " "take effect.\n" "Confirm that PARTITION_SETTING_COMPLETED bit is set " "using 'extcsd read' after power cycle\n"); return 0; } int check_enhanced_area_total_limit(const char * const device, int fd) { __u8 ext_csd[512]; __u32 regl; unsigned long max_enh_area_sz, user_area_sz, enh_area_sz = 0; unsigned long gp4_part_sz, gp3_part_sz, gp2_part_sz, gp1_part_sz; unsigned long total_sz, total_gp_user_sz; unsigned int wp_sz, erase_sz; int ret; ret = read_extcsd(fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); exit(1); } wp_sz = get_hc_wp_grp_size(ext_csd); erase_sz = get_hc_erase_grp_size(ext_csd); regl = (ext_csd[EXT_CSD_GP_SIZE_MULT_4_2] << 16) | (ext_csd[EXT_CSD_GP_SIZE_MULT_4_1] << 8) | ext_csd[EXT_CSD_GP_SIZE_MULT_4_0]; gp4_part_sz = 512l * regl * erase_sz * wp_sz; if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_4) { enh_area_sz += gp4_part_sz; printf("Enhanced GP4 Partition Size [GP_SIZE_MULT_4]: 0x%06x\n", regl); printf(" i.e. %lu KiB\n", gp4_part_sz); } regl = (ext_csd[EXT_CSD_GP_SIZE_MULT_3_2] << 16) | (ext_csd[EXT_CSD_GP_SIZE_MULT_3_1] << 8) | ext_csd[EXT_CSD_GP_SIZE_MULT_3_0]; gp3_part_sz = 512l * regl * erase_sz * wp_sz; if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_3) { enh_area_sz += gp3_part_sz; printf("Enhanced GP3 Partition Size [GP_SIZE_MULT_3]: 0x%06x\n", regl); printf(" i.e. %lu KiB\n", gp3_part_sz); } regl = (ext_csd[EXT_CSD_GP_SIZE_MULT_2_2] << 16) | (ext_csd[EXT_CSD_GP_SIZE_MULT_2_1] << 8) | ext_csd[EXT_CSD_GP_SIZE_MULT_2_0]; gp2_part_sz = 512l * regl * erase_sz * wp_sz; if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_2) { enh_area_sz += gp2_part_sz; printf("Enhanced GP2 Partition Size [GP_SIZE_MULT_2]: 0x%06x\n", regl); printf(" i.e. %lu KiB\n", gp2_part_sz); } regl = (ext_csd[EXT_CSD_GP_SIZE_MULT_1_2] << 16) | (ext_csd[EXT_CSD_GP_SIZE_MULT_1_1] << 8) | ext_csd[EXT_CSD_GP_SIZE_MULT_1_0]; gp1_part_sz = 512l * regl * erase_sz * wp_sz; if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_1) { enh_area_sz += gp1_part_sz; printf("Enhanced GP1 Partition Size [GP_SIZE_MULT_1]: 0x%06x\n", regl); printf(" i.e. %lu KiB\n", gp1_part_sz); } regl = (ext_csd[EXT_CSD_ENH_SIZE_MULT_2] << 16) | (ext_csd[EXT_CSD_ENH_SIZE_MULT_1] << 8) | ext_csd[EXT_CSD_ENH_SIZE_MULT_0]; user_area_sz = 512l * regl * erase_sz * wp_sz; if (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_USR) { enh_area_sz += user_area_sz; printf("Enhanced User Data Area Size [ENH_SIZE_MULT]: 0x%06x\n", regl); printf(" i.e. %lu KiB\n", user_area_sz); } regl = (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_2] << 16) | (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_1] << 8) | ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_0]; max_enh_area_sz = 512l * regl * erase_sz * wp_sz; printf("Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x%06x\n", regl); printf(" i.e. %lu KiB\n", max_enh_area_sz); if (enh_area_sz > max_enh_area_sz) { fprintf(stderr, "Programmed total enhanced size %lu KiB cannot exceed max enhanced area %lu KiB %s\n", enh_area_sz, max_enh_area_sz, device); return 1; } total_sz = get_sector_count(ext_csd) / 2; total_gp_user_sz = gp4_part_sz + gp3_part_sz + gp2_part_sz + gp1_part_sz + user_area_sz; if (total_gp_user_sz > total_sz) { fprintf(stderr, "requested total partition size %lu KiB cannot exceed card capacity %lu KiB %s\n", total_gp_user_sz, total_sz, device); return 1; } return 0; } int do_create_gp_partition(int nargs, char **argv) { __u8 value; __u8 ext_csd[512]; __u8 address; int fd, ret; char *device; int dry_run = 1; int partition, enh_attr, ext_attr; unsigned int length_kib, gp_size_mult; unsigned long align; if (nargs != 7) { fprintf(stderr, "Usage: mmc gp create <-y|-n|-c> <length KiB> <partition> <enh_attr> <ext_attr> </path/to/mmcblkX>\n"); exit(1); } if (!strcmp("-y", argv[1])) { dry_run = 0; } else if (!strcmp("-c", argv[1])) { dry_run = 2; } length_kib = strtol(argv[2], NULL, 10); partition = strtol(argv[3], NULL, 10); enh_attr = strtol(argv[4], NULL, 10); ext_attr = strtol(argv[5], NULL, 10); device = argv[6]; if (partition < 1 || partition > 4) { printf("Invalid gp partition number; valid range [1-4].\n"); exit(1); } if (enh_attr && ext_attr) { printf("Not allowed to set both enhanced attribute and extended attribute\n"); exit(1); } fd = open(device, O_RDWR); if (fd < 0) { perror("open"); exit(1); } ret = read_extcsd(fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); exit(1); } /* assert not PARTITION_SETTING_COMPLETED */ if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED]) { printf(" Device is already partitioned\n"); exit(1); } align = 512l * get_hc_wp_grp_size(ext_csd) * get_hc_erase_grp_size(ext_csd); gp_size_mult = (length_kib + align/2l) / align; /* set EXT_CSD_ERASE_GROUP_DEF bit 0 */ ret = write_extcsd_value(fd, EXT_CSD_ERASE_GROUP_DEF, 0x1); if (ret) { fprintf(stderr, "Could not write 0x1 to EXT_CSD[%d] in %s\n", EXT_CSD_ERASE_GROUP_DEF, device); exit(1); } value = (gp_size_mult >> 16) & 0xff; address = EXT_CSD_GP_SIZE_MULT_1_2 + (partition - 1) * 3; ret = write_extcsd_value(fd, address, value); if (ret) { fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n", value, address, device); exit(1); } value = (gp_size_mult >> 8) & 0xff; address = EXT_CSD_GP_SIZE_MULT_1_1 + (partition - 1) * 3; ret = write_extcsd_value(fd, address, value); if (ret) { fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n", value, address, device); exit(1); } value = gp_size_mult & 0xff; address = EXT_CSD_GP_SIZE_MULT_1_0 + (partition - 1) * 3; ret = write_extcsd_value(fd, address, value); if (ret) { fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n", value, address, device); exit(1); } value = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; if (enh_attr) value |= (1 << partition); else value &= ~(1 << partition); ret = write_extcsd_value(fd, EXT_CSD_PARTITIONS_ATTRIBUTE, value); if (ret) { fprintf(stderr, "Could not write EXT_CSD_ENH_%x to EXT_CSD[%d] in %s\n", partition, EXT_CSD_PARTITIONS_ATTRIBUTE, device); exit(1); } address = EXT_CSD_EXT_PARTITIONS_ATTRIBUTE_0 + (partition - 1) / 2; value = ext_csd[address]; if (ext_attr) value |= (ext_attr << (4 * ((partition - 1) % 2))); else value &= (0xF << (4 * ((partition % 2)))); ret = write_extcsd_value(fd, address, value); if (ret) { fprintf(stderr, "Could not write 0x%x to EXT_CSD[%d] in %s\n", value, address, device); exit(1); } ret = check_enhanced_area_total_limit(device, fd); if (ret) exit(1); if (set_partitioning_setting_completed(dry_run, device, fd)) exit(1); return 0; } int do_enh_area_set(int nargs, char **argv) { __u8 value; __u8 ext_csd[512]; int fd, ret; char *device; int dry_run = 1; unsigned int start_kib, length_kib, enh_start_addr, enh_size_mult; unsigned long align; if (nargs != 5) { fprintf(stderr, "Usage: mmc enh_area set <-y|-n|-c> <start KiB> <length KiB> </path/to/mmcblkX>\n"); exit(1); } if (!strcmp("-y", argv[1])) { dry_run = 0; } else if (!strcmp("-c", argv[1])) { dry_run = 2; } start_kib = strtol(argv[2], NULL, 10); length_kib = strtol(argv[3], NULL, 10); device = argv[4]; fd = open(device, O_RDWR); if (fd < 0) { perror("open"); exit(1); } ret = read_extcsd(fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); exit(1); } /* assert ENH_ATTRIBUTE_EN */ if (!(ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & EXT_CSD_ENH_ATTRIBUTE_EN)) { printf(" Device cannot have enhanced tech.\n"); exit(1); } /* assert not PARTITION_SETTING_COMPLETED */ if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED]) { printf(" Device is already partitioned\n"); exit(1); } align = 512l * get_hc_wp_grp_size(ext_csd) * get_hc_erase_grp_size(ext_csd); enh_size_mult = (length_kib + align/2l) / align; enh_start_addr = start_kib * (1024 / (is_blockaddresed(ext_csd) ? 512 : 1)); enh_start_addr /= align; enh_start_addr *= align; /* set EXT_CSD_ERASE_GROUP_DEF bit 0 */ ret = write_extcsd_value(fd, EXT_CSD_ERASE_GROUP_DEF, 0x1); if (ret) { fprintf(stderr, "Could not write 0x1 to " "EXT_CSD[%d] in %s\n", EXT_CSD_ERASE_GROUP_DEF, device); exit(1); } /* write to ENH_START_ADDR and ENH_SIZE_MULT and PARTITIONS_ATTRIBUTE's ENH_USR bit */ value = (enh_start_addr >> 24) & 0xff; ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_3, value); if (ret) { fprintf(stderr, "Could not write 0x%02x to " "EXT_CSD[%d] in %s\n", value, EXT_CSD_ENH_START_ADDR_3, device); exit(1); } value = (enh_start_addr >> 16) & 0xff; ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_2, value); if (ret) { fprintf(stderr, "Could not write 0x%02x to " "EXT_CSD[%d] in %s\n", value, EXT_CSD_ENH_START_ADDR_2, device); exit(1); } value = (enh_start_addr >> 8) & 0xff; ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_1, value); if (ret) { fprintf(stderr, "Could not write 0x%02x to " "EXT_CSD[%d] in %s\n", value, EXT_CSD_ENH_START_ADDR_1, device); exit(1); } value = enh_start_addr & 0xff; ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_0, value); if (ret) { fprintf(stderr, "Could not write 0x%02x to " "EXT_CSD[%d] in %s\n", value, EXT_CSD_ENH_START_ADDR_0, device); exit(1); } value = (enh_size_mult >> 16) & 0xff; ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_2, value); if (ret) { fprintf(stderr, "Could not write 0x%02x to " "EXT_CSD[%d] in %s\n", value, EXT_CSD_ENH_SIZE_MULT_2, device); exit(1); } value = (enh_size_mult >> 8) & 0xff; ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_1, value); if (ret) { fprintf(stderr, "Could not write 0x%02x to " "EXT_CSD[%d] in %s\n", value, EXT_CSD_ENH_SIZE_MULT_1, device); exit(1); } value = enh_size_mult & 0xff; ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_0, value); if (ret) { fprintf(stderr, "Could not write 0x%02x to " "EXT_CSD[%d] in %s\n", value, EXT_CSD_ENH_SIZE_MULT_0, device); exit(1); } value = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] | EXT_CSD_ENH_USR; ret = write_extcsd_value(fd, EXT_CSD_PARTITIONS_ATTRIBUTE, value); if (ret) { fprintf(stderr, "Could not write EXT_CSD_ENH_USR to " "EXT_CSD[%d] in %s\n", EXT_CSD_PARTITIONS_ATTRIBUTE, device); exit(1); } ret = check_enhanced_area_total_limit(device, fd); if (ret) exit(1); printf("Done setting ENH_USR area on %s\n", device); if (set_partitioning_setting_completed(dry_run, device, fd)) exit(1); return 0; } int do_write_reliability_set(int nargs, char **argv) { __u8 value; __u8 ext_csd[512]; int fd, ret; int dry_run = 1; int partition; char *device; if (nargs != 4) { fprintf(stderr,"Usage: mmc write_reliability set <-y|-n|-c> <partition> </path/to/mmcblkX>\n"); exit(1); } if (!strcmp("-y", argv[1])) { dry_run = 0; } else if (!strcmp("-c", argv[1])) { dry_run = 2; } partition = strtol(argv[2], NULL, 10); device = argv[3]; fd = open(device, O_RDWR); if (fd < 0) { perror("open"); exit(1); } ret = read_extcsd(fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); exit(1); } /* assert not PARTITION_SETTING_COMPLETED */ if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED]) { printf(" Device is already partitioned\n"); exit(1); } /* assert HS_CTRL_REL */ if (!(ext_csd[EXT_CSD_WR_REL_PARAM] & HS_CTRL_REL)) { printf("Cannot set write reliability parameters, WR_REL_SET is " "read-only\n"); exit(1); } value = ext_csd[EXT_CSD_WR_REL_SET] | (1<<partition); ret = write_extcsd_value(fd, EXT_CSD_WR_REL_SET, value); if (ret) { fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n", value, EXT_CSD_WR_REL_SET, device); exit(1); } printf("Done setting EXT_CSD_WR_REL_SET to 0x%02x on %s\n", value, device); if (set_partitioning_setting_completed(dry_run, device, fd)) exit(1); return 0; } int do_read_extcsd(int nargs, char **argv) { __u8 ext_csd[512], ext_csd_rev, reg; __u32 regl; int fd, ret; char *device; const char *str; if (nargs != 2) { fprintf(stderr, "Usage: mmc extcsd read </path/to/mmcblkX>\n"); exit(1); } device = argv[1]; fd = open(device, O_RDWR); if (fd < 0) { perror("open"); exit(1); } ret = read_extcsd(fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); exit(1); } ext_csd_rev = ext_csd[EXT_CSD_REV]; switch (ext_csd_rev) { case 8: str = "5.1"; break; case 7: str = "5.0"; break; case 6: str = "4.5"; break; case 5: str = "4.41"; break; case 3: str = "4.3"; break; case 2: str = "4.2"; break; case 1: str = "4.1"; break; case 0: str = "4.0"; break; default: goto out_free; } printf("=============================================\n"); printf(" Extended CSD rev 1.%d (MMC %s)\n", ext_csd_rev, str); printf("=============================================\n\n"); if (ext_csd_rev < 3) goto out_free; /* No ext_csd */ /* Parse the Extended CSD registers. * Reserved bit should be read as "0" in case of spec older * than A441. */ reg = ext_csd[EXT_CSD_S_CMD_SET]; printf("Card Supported Command sets [S_CMD_SET: 0x%02x]\n", reg); if (!reg) printf(" - Standard MMC command sets\n"); reg = ext_csd[EXT_CSD_HPI_FEATURE]; printf("HPI Features [HPI_FEATURE: 0x%02x]: ", reg); if (reg & EXT_CSD_HPI_SUPP) { if (reg & EXT_CSD_HPI_IMPL) printf("implementation based on CMD12\n"); else printf("implementation based on CMD13\n"); } printf("Background operations support [BKOPS_SUPPORT: 0x%02x]\n", ext_csd[502]); if (ext_csd_rev >= 6) { printf("Max Packet Read Cmd [MAX_PACKED_READS: 0x%02x]\n", ext_csd[501]); printf("Max Packet Write Cmd [MAX_PACKED_WRITES: 0x%02x]\n", ext_csd[500]); printf("Data TAG support [DATA_TAG_SUPPORT: 0x%02x]\n", ext_csd[499]); printf("Data TAG Unit Size [TAG_UNIT_SIZE: 0x%02x]\n", ext_csd[498]); printf("Tag Resources Size [TAG_RES_SIZE: 0x%02x]\n", ext_csd[497]); printf("Context Management Capabilities" " [CONTEXT_CAPABILITIES: 0x%02x]\n", ext_csd[496]); printf("Large Unit Size [LARGE_UNIT_SIZE_M1: 0x%02x]\n", ext_csd[495]); printf("Extended partition attribute support" " [EXT_SUPPORT: 0x%02x]\n", ext_csd[494]); printf("Generic CMD6 Timer [GENERIC_CMD6_TIME: 0x%02x]\n", ext_csd[248]); printf("Power off notification [POWER_OFF_LONG_TIME: 0x%02x]\n", ext_csd[247]); printf("Cache Size [CACHE_SIZE] is %d KiB\n", (ext_csd[249] << 0 | (ext_csd[250] << 8) | (ext_csd[251] << 16) | (ext_csd[252] << 24)) / 8); } /* A441: Reserved [501:247] A43: reserved [246:229] */ if (ext_csd_rev >= 5) { printf("Background operations status" " [BKOPS_STATUS: 0x%02x]\n", ext_csd[246]); /* CORRECTLY_PRG_SECTORS_NUM [245:242] TODO */ printf("1st Initialisation Time after programmed sector" " [INI_TIMEOUT_AP: 0x%02x]\n", ext_csd[241]); /* A441: reserved [240] */ printf("Power class for 52MHz, DDR at 3.6V" " [PWR_CL_DDR_52_360: 0x%02x]\n", ext_csd[239]); printf("Power class for 52MHz, DDR at 1.95V" " [PWR_CL_DDR_52_195: 0x%02x]\n", ext_csd[238]); /* A441: reserved [237-236] */ if (ext_csd_rev >= 6) { printf("Power class for 200MHz at 3.6V" " [PWR_CL_200_360: 0x%02x]\n", ext_csd[237]); printf("Power class for 200MHz, at 1.95V" " [PWR_CL_200_195: 0x%02x]\n", ext_csd[236]); } printf("Minimum Performance for 8bit at 52MHz in DDR mode:\n"); printf(" [MIN_PERF_DDR_W_8_52: 0x%02x]\n", ext_csd[235]); printf(" [MIN_PERF_DDR_R_8_52: 0x%02x]\n", ext_csd[234]); /* A441: reserved [233] */ printf("TRIM Multiplier [TRIM_MULT: 0x%02x]\n", ext_csd[232]); printf("Secure Feature support [SEC_FEATURE_SUPPORT: 0x%02x]\n", ext_csd[231]); } if (ext_csd_rev == 5) { /* Obsolete in 4.5 */ printf("Secure Erase Multiplier [SEC_ERASE_MULT: 0x%02x]\n", ext_csd[230]); printf("Secure TRIM Multiplier [SEC_TRIM_MULT: 0x%02x]\n", ext_csd[229]); } reg = ext_csd[EXT_CSD_BOOT_INFO]; printf("Boot Information [BOOT_INFO: 0x%02x]\n", reg); if (reg & EXT_CSD_BOOT_INFO_ALT) printf(" Device supports alternative boot method\n"); if (reg & EXT_CSD_BOOT_INFO_DDR_DDR) printf(" Device supports dual data rate during boot\n"); if (reg & EXT_CSD_BOOT_INFO_HS_MODE) printf(" Device supports high speed timing during boot\n"); /* A441/A43: reserved [227] */ printf("Boot partition size [BOOT_SIZE_MULTI: 0x%02x]\n", ext_csd[226]); printf("Access size [ACC_SIZE: 0x%02x]\n", ext_csd[225]); reg = get_hc_erase_grp_size(ext_csd); printf("High-capacity erase unit size [HC_ERASE_GRP_SIZE: 0x%02x]\n", reg); printf(" i.e. %u KiB\n", 512 * reg); printf("High-capacity erase timeout [ERASE_TIMEOUT_MULT: 0x%02x]\n", ext_csd[223]); printf("Reliable write sector count [REL_WR_SEC_C: 0x%02x]\n", ext_csd[222]); reg = get_hc_wp_grp_size(ext_csd); printf("High-capacity W protect group size [HC_WP_GRP_SIZE: 0x%02x]\n", reg); printf(" i.e. %lu KiB\n", 512l * get_hc_erase_grp_size(ext_csd) * reg); printf("Sleep current (VCC) [S_C_VCC: 0x%02x]\n", ext_csd[220]); printf("Sleep current (VCCQ) [S_C_VCCQ: 0x%02x]\n", ext_csd[219]); /* A441/A43: reserved [218] */ printf("Sleep/awake timeout [S_A_TIMEOUT: 0x%02x]\n", ext_csd[217]); /* A441/A43: reserved [216] */ unsigned int sectors = get_sector_count(ext_csd); printf("Sector Count [SEC_COUNT: 0x%08x]\n", sectors); if (is_blockaddresed(ext_csd)) printf(" Device is block-addressed\n"); else printf(" Device is NOT block-addressed\n"); /* A441/A43: reserved [211] */ printf("Minimum Write Performance for 8bit:\n"); printf(" [MIN_PERF_W_8_52: 0x%02x]\n", ext_csd[210]); printf(" [MIN_PERF_R_8_52: 0x%02x]\n", ext_csd[209]); printf(" [MIN_PERF_W_8_26_4_52: 0x%02x]\n", ext_csd[208]); printf(" [MIN_PERF_R_8_26_4_52: 0x%02x]\n", ext_csd[207]); printf("Minimum Write Performance for 4bit:\n"); printf(" [MIN_PERF_W_4_26: 0x%02x]\n", ext_csd[206]); printf(" [MIN_PERF_R_4_26: 0x%02x]\n", ext_csd[205]); /* A441/A43: reserved [204] */ printf("Power classes registers:\n"); printf(" [PWR_CL_26_360: 0x%02x]\n", ext_csd[203]); printf(" [PWR_CL_52_360: 0x%02x]\n", ext_csd[202]); printf(" [PWR_CL_26_195: 0x%02x]\n", ext_csd[201]); printf(" [PWR_CL_52_195: 0x%02x]\n", ext_csd[200]); /* A43: reserved [199:198] */ if (ext_csd_rev >= 5) { printf("Partition switching timing " "[PARTITION_SWITCH_TIME: 0x%02x]\n", ext_csd[199]); printf("Out-of-interrupt busy timing" " [OUT_OF_INTERRUPT_TIME: 0x%02x]\n", ext_csd[198]); } /* A441/A43: reserved [197] [195] [193] [190] [188] * [186] [184] [182] [180] [176] */ if (ext_csd_rev >= 6) printf("I/O Driver Strength [DRIVER_STRENGTH: 0x%02x]\n", ext_csd[197]); /* DEVICE_TYPE in A45, CARD_TYPE in A441 */ reg = ext_csd[196]; printf("Card Type [CARD_TYPE: 0x%02x]\n", reg); if (reg & 0x80) printf(" HS400 Dual Data Rate eMMC @200MHz 1.2VI/O\n"); if (reg & 0x40) printf(" HS400 Dual Data Rate eMMC @200MHz 1.8VI/O\n"); if (reg & 0x20) printf(" HS200 Single Data Rate eMMC @200MHz 1.2VI/O\n"); if (reg & 0x10) printf(" HS200 Single Data Rate eMMC @200MHz 1.8VI/O\n"); if (reg & 0x08) printf(" HS Dual Data Rate eMMC @52MHz 1.2VI/O\n"); if (reg & 0x04) printf(" HS Dual Data Rate eMMC @52MHz 1.8V or 3VI/O\n"); if (reg & 0x02) printf(" HS eMMC @52MHz - at rated device voltage(s)\n"); if (reg & 0x01) printf(" HS eMMC @26MHz - at rated device voltage(s)\n"); printf("CSD structure version [CSD_STRUCTURE: 0x%02x]\n", ext_csd[194]); /* ext_csd_rev = ext_csd[EXT_CSD_REV] (already done!!!) */ printf("Command set [CMD_SET: 0x%02x]\n", ext_csd[191]); printf("Command set revision [CMD_SET_REV: 0x%02x]\n", ext_csd[189]); printf("Power class [POWER_CLASS: 0x%02x]\n", ext_csd[187]); printf("High-speed interface timing [HS_TIMING: 0x%02x]\n", ext_csd[185]); if (ext_csd_rev >= 8) printf("Enhanced Strobe mode [STROBE_SUPPORT: 0x%02x]\n", ext_csd[184]); /* bus_width: ext_csd[183] not readable */ printf("Erased memory content [ERASED_MEM_CONT: 0x%02x]\n", ext_csd[181]); reg = ext_csd[EXT_CSD_BOOT_CFG]; printf("Boot configuration bytes [PARTITION_CONFIG: 0x%02x]\n", reg); switch ((reg & EXT_CSD_BOOT_CFG_EN)>>3) { case 0x0: printf(" Not boot enable\n"); break; case 0x1: printf(" Boot Partition 1 enabled\n"); break; case 0x2: printf(" Boot Partition 2 enabled\n"); break; case 0x7: printf(" User Area Enabled for boot\n"); break; } switch (reg & EXT_CSD_BOOT_CFG_ACC) { case 0x0: printf(" No access to boot partition\n"); break; case 0x1: printf(" R/W Boot Partition 1\n"); break; case 0x2: printf(" R/W Boot Partition 2\n"); break; case 0x3: printf(" R/W Replay Protected Memory Block (RPMB)\n"); break; default: printf(" Access to General Purpose partition %d\n", (reg & EXT_CSD_BOOT_CFG_ACC) - 3); break; } printf("Boot config protection [BOOT_CONFIG_PROT: 0x%02x]\n", ext_csd[178]); printf("Boot bus Conditions [BOOT_BUS_CONDITIONS: 0x%02x]\n", ext_csd[177]); printf("High-density erase group definition" " [ERASE_GROUP_DEF: 0x%02x]\n", ext_csd[EXT_CSD_ERASE_GROUP_DEF]); print_writeprotect_boot_status(ext_csd); if (ext_csd_rev >= 5) { /* A441]: reserved [172] */ printf("User area write protection register" " [USER_WP]: 0x%02x\n", ext_csd[171]); /* A441]: reserved [170] */ printf("FW configuration [FW_CONFIG]: 0x%02x\n", ext_csd[169]); printf("RPMB Size [RPMB_SIZE_MULT]: 0x%02x\n", ext_csd[168]); reg = ext_csd[EXT_CSD_WR_REL_SET]; const char * const fast = "existing data is at risk if a power " "failure occurs during a write operation"; const char * const reliable = "the device protects existing " "data if a power failure occurs during a write " "operation"; printf("Write reliability setting register" " [WR_REL_SET]: 0x%02x\n", reg); printf(" user area: %s\n", (reg & (1<<0)) ? reliable : fast); int i; for (i = 1; i <= 4; i++) { printf(" partition %d: %s\n", i, (reg & (1<<i)) ? reliable : fast); } reg = ext_csd[EXT_CSD_WR_REL_PARAM]; printf("Write reliability parameter register" " [WR_REL_PARAM]: 0x%02x\n", reg); if (reg & 0x01) printf(" Device supports writing EXT_CSD_WR_REL_SET\n"); if (reg & 0x04) printf(" Device supports the enhanced def. of reliable " "write\n"); /* sanitize_start ext_csd[165]]: not readable * bkops_start ext_csd[164]]: only writable */ printf("Enable background operations handshake" " [BKOPS_EN]: 0x%02x\n", ext_csd[163]); printf("H/W reset function" " [RST_N_FUNCTION]: 0x%02x\n", ext_csd[162]); printf("HPI management [HPI_MGMT]: 0x%02x\n", ext_csd[161]); reg = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; printf("Partitioning Support [PARTITIONING_SUPPORT]: 0x%02x\n", reg); if (reg & EXT_CSD_PARTITIONING_EN) printf(" Device support partitioning feature\n"); else printf(" Device NOT support partitioning feature\n"); if (reg & EXT_CSD_ENH_ATTRIBUTE_EN) printf(" Device can have enhanced tech.\n"); else printf(" Device cannot have enhanced tech.\n"); regl = (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_2] << 16) | (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_1] << 8) | ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_0]; printf("Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x%06x\n", regl); unsigned int wp_sz = get_hc_wp_grp_size(ext_csd); unsigned int erase_sz = get_hc_erase_grp_size(ext_csd); printf(" i.e. %lu KiB\n", 512l * regl * wp_sz * erase_sz); printf("Partitions attribute [PARTITIONS_ATTRIBUTE]: 0x%02x\n", ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]); reg = ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED]; printf("Partitioning Setting" " [PARTITION_SETTING_COMPLETED]: 0x%02x\n", reg); if (reg) printf(" Device partition setting complete\n"); else printf(" Device partition setting NOT complete\n"); printf("General Purpose Partition Size\n" " [GP_SIZE_MULT_4]: 0x%06x\n", (ext_csd[154] << 16) | (ext_csd[153] << 8) | ext_csd[152]); printf(" [GP_SIZE_MULT_3]: 0x%06x\n", (ext_csd[151] << 16) | (ext_csd[150] << 8) | ext_csd[149]); printf(" [GP_SIZE_MULT_2]: 0x%06x\n", (ext_csd[148] << 16) | (ext_csd[147] << 8) | ext_csd[146]); printf(" [GP_SIZE_MULT_1]: 0x%06x\n", (ext_csd[145] << 16) | (ext_csd[144] << 8) | ext_csd[143]); regl = (ext_csd[EXT_CSD_ENH_SIZE_MULT_2] << 16) | (ext_csd[EXT_CSD_ENH_SIZE_MULT_1] << 8) | ext_csd[EXT_CSD_ENH_SIZE_MULT_0]; printf("Enhanced User Data Area Size" " [ENH_SIZE_MULT]: 0x%06x\n", regl); printf(" i.e. %lu KiB\n", 512l * regl * get_hc_erase_grp_size(ext_csd) * get_hc_wp_grp_size(ext_csd)); regl = (ext_csd[EXT_CSD_ENH_START_ADDR_3] << 24) | (ext_csd[EXT_CSD_ENH_START_ADDR_2] << 16) | (ext_csd[EXT_CSD_ENH_START_ADDR_1] << 8) | ext_csd[EXT_CSD_ENH_START_ADDR_0]; printf("Enhanced User Data Start Address" " [ENH_START_ADDR]: 0x%08x\n", regl); printf(" i.e. %llu bytes offset\n", (is_blockaddresed(ext_csd) ? 512ll : 1ll) * regl); /* A441]: reserved [135] */ printf("Bad Block Management mode" " [SEC_BAD_BLK_MGMNT]: 0x%02x\n", ext_csd[134]); /* A441: reserved [133:0] */ } /* B45 */ if (ext_csd_rev >= 6) { int j; /* tcase_support ext_csd[132] not readable */ printf("Periodic Wake-up [PERIODIC_WAKEUP]: 0x%02x\n", ext_csd[131]); printf("Program CID/CSD in DDR mode support" " [PROGRAM_CID_CSD_DDR_SUPPORT]: 0x%02x\n", ext_csd[130]); for (j = 127; j >= 64; j--) printf("Vendor Specific Fields" " [VENDOR_SPECIFIC_FIELD[%d]]: 0x%02x\n", j, ext_csd[j]); printf("Native sector size [NATIVE_SECTOR_SIZE]: 0x%02x\n", ext_csd[63]); printf("Sector size emulation [USE_NATIVE_SECTOR]: 0x%02x\n", ext_csd[62]); printf("Sector size [DATA_SECTOR_SIZE]: 0x%02x\n", ext_csd[61]); printf("1st initialization after disabling sector" " size emulation [INI_TIMEOUT_EMU]: 0x%02x\n", ext_csd[60]); printf("Class 6 commands control [CLASS_6_CTRL]: 0x%02x\n", ext_csd[59]); printf("Number of addressed group to be Released" "[DYNCAP_NEEDED]: 0x%02x\n", ext_csd[58]); printf("Exception events control" " [EXCEPTION_EVENTS_CTRL]: 0x%04x\n", (ext_csd[57] << 8) | ext_csd[56]); printf("Exception events status" "[EXCEPTION_EVENTS_STATUS]: 0x%04x\n", (ext_csd[55] << 8) | ext_csd[54]); printf("Extended Partitions Attribute" " [EXT_PARTITIONS_ATTRIBUTE]: 0x%04x\n", (ext_csd[53] << 8) | ext_csd[52]); for (j = 51; j >= 37; j--) printf("Context configuration" " [CONTEXT_CONF[%d]]: 0x%02x\n", j, ext_csd[j]); printf("Packed command status" " [PACKED_COMMAND_STATUS]: 0x%02x\n", ext_csd[36]); printf("Packed command failure index" " [PACKED_FAILURE_INDEX]: 0x%02x\n", ext_csd[35]); printf("Power Off Notification" " [POWER_OFF_NOTIFICATION]: 0x%02x\n", ext_csd[34]); printf("Control to turn the Cache ON/OFF" " [CACHE_CTRL]: 0x%02x\n", ext_csd[33]); /* flush_cache ext_csd[32] not readable */ printf("Control to turn the Cache Barrier ON/OFF" " [BARRIER_CTRL]: 0x%02x\n", ext_csd[31]); /*Reserved [30:0] */ } if (ext_csd_rev >= 7) { printf("eMMC Firmware Version: %.8s\n", (char*)&ext_csd[EXT_CSD_FIRMWARE_VERSION]); printf("eMMC Life Time Estimation A [EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A]: 0x%02x\n", ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A]); printf("eMMC Life Time Estimation B [EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]: 0x%02x\n", ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B]); printf("eMMC Pre EOL information [EXT_CSD_PRE_EOL_INFO]: 0x%02x\n", ext_csd[EXT_CSD_PRE_EOL_INFO]); reg = ext_csd[EXT_CSD_SECURE_REMOVAL_TYPE]; printf("Secure Removal Type [SECURE_REMOVAL_TYPE]: 0x%02x\n", reg); printf(" information is configured to be removed "); /* Bit [5:4]: Configure Secure Removal Type */ switch ((reg & EXT_CSD_CONFIG_SECRM_TYPE) >> 4) { case 0x0: printf("by an erase of the physical memory\n"); break; case 0x1: printf("by an overwriting the addressed locations" " with a character followed by an erase\n"); break; case 0x2: printf("by an overwriting the addressed locations" " with a character, its complement, then a random character\n"); break; case 0x3: printf("using a vendor defined\n"); break; } /* Bit [3:0]: Supported Secure Removal Type */ printf(" Supported Secure Removal Type:\n"); if (reg & 0x01) printf(" information removed by an erase of the physical memory\n"); if (reg & 0x02) printf(" information removed by an overwriting the addressed locations" " with a character followed by an erase\n"); if (reg & 0x04) printf(" information removed by an overwriting the addressed locations" " with a character, its complement, then a random character\n"); if (reg & 0x08) printf(" information removed using a vendor defined\n"); } if (ext_csd_rev >= 8) { printf("Command Queue Support [CMDQ_SUPPORT]: 0x%02x\n", ext_csd[EXT_CSD_CMDQ_SUPPORT]); printf("Command Queue Depth [CMDQ_DEPTH]: %u\n", (ext_csd[EXT_CSD_CMDQ_DEPTH] & 0x1f) + 1); printf("Command Enabled [CMDQ_MODE_EN]: 0x%02x\n", ext_csd[EXT_CSD_CMDQ_MODE_EN]); printf("Note: CMDQ_MODE_EN may not indicate the runtime CMDQ ON or OFF.\n" "Please check sysfs node '/sys/devices/.../mmc_host/mmcX/mmcX:XXXX/cmdq_en'\n"); } out_free: return ret; } int do_sanitize(int nargs, char **argv) { int fd, ret; char *device; if (nargs != 2) { fprintf(stderr, "Usage: mmc sanitize </path/to/mmcblkX>\n"); exit(1); } device = argv[1]; fd = open(device, O_RDWR); if (fd < 0) { perror("open"); exit(1); } ret = write_extcsd_value(fd, EXT_CSD_SANITIZE_START, 1); if (ret) { fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n", 1, EXT_CSD_SANITIZE_START, device); exit(1); } close(fd); return ret; } #define DO_IO(func, fd, buf, nbyte) \ ({ \ ssize_t ret = 0, r; \ do { \ r = func(fd, buf + ret, nbyte - ret); \ if (r < 0 && errno != EINTR) { \ ret = -1; \ break; \ } \ else if (r > 0) \ ret += r; \ } while (r != 0 && (size_t)ret != nbyte); \ \ ret; \ }) #define RPMB_MULTI_CMD_MAX_CMDS 3 enum rpmb_op_type { MMC_RPMB_WRITE_KEY = 0x01, MMC_RPMB_READ_CNT = 0x02, MMC_RPMB_WRITE = 0x03, MMC_RPMB_READ = 0x04, /* For internal usage only, do not use it directly */ MMC_RPMB_READ_RESP = 0x05 }; struct rpmb_frame { u_int8_t stuff[196]; u_int8_t key_mac[32]; u_int8_t data[256]; u_int8_t nonce[16]; u_int32_t write_counter; u_int16_t addr; u_int16_t block_count; u_int16_t result; u_int16_t req_resp; }; static inline void set_single_cmd(struct mmc_ioc_cmd *ioc, __u32 opcode, int write_flag, unsigned int blocks) { ioc->opcode = opcode; ioc->write_flag = write_flag; ioc->arg = 0x0; ioc->blksz = 512; ioc->blocks = blocks; ioc->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; } /* Performs RPMB operation. * * @fd: RPMB device on which we should perform ioctl command * @frame_in: input RPMB frame, should be properly inited * @frame_out: output (result) RPMB frame. Caller is responsible for checking * result and req_resp for output frame. * @out_cnt: count of outer frames. Used only for multiple blocks reading, * in the other cases -EINVAL will be returned. */ static int do_rpmb_op(int fd, const struct rpmb_frame *frame_in, struct rpmb_frame *frame_out, unsigned int out_cnt) { #ifndef MMC_IOC_MULTI_CMD fprintf(stderr, "mmc-utils has been compiled without MMC_IOC_MULTI_CMD" " support, needed by RPMB operation.\n"); exit(1); #else int err; u_int16_t rpmb_type; struct mmc_ioc_multi_cmd *mioc; struct mmc_ioc_cmd *ioc; struct rpmb_frame frame_status; memset(&frame_status, 0, sizeof(frame_status)); if (!frame_in || !frame_out || !out_cnt) return -EINVAL; /* prepare arguments for MMC_IOC_MULTI_CMD ioctl */ mioc = (struct mmc_ioc_multi_cmd *) calloc(1, sizeof (struct mmc_ioc_multi_cmd) + RPMB_MULTI_CMD_MAX_CMDS * sizeof (struct mmc_ioc_cmd)); if (!mioc) { return -ENOMEM; } rpmb_type = be16toh(frame_in->req_resp); switch(rpmb_type) { case MMC_RPMB_WRITE: case MMC_RPMB_WRITE_KEY: if (out_cnt != 1) { err = -EINVAL; goto out; } mioc->num_of_cmds = 3; /* Write request */ ioc = &mioc->cmds[0]; set_single_cmd(ioc, MMC_WRITE_MULTIPLE_BLOCK, (1 << 31) | 1, 1); mmc_ioc_cmd_set_data((*ioc), frame_in); /* Result request */ ioc = &mioc->cmds[1]; frame_status.req_resp = htobe16(MMC_RPMB_READ_RESP); set_single_cmd(ioc, MMC_WRITE_MULTIPLE_BLOCK, 1, 1); mmc_ioc_cmd_set_data((*ioc), &frame_status); /* Get response */ ioc = &mioc->cmds[2]; set_single_cmd(ioc, MMC_READ_MULTIPLE_BLOCK, 0, 1); mmc_ioc_cmd_set_data((*ioc), frame_out); break; case MMC_RPMB_READ_CNT: if (out_cnt != 1) { err = -EINVAL; goto out; } /* fall through */ case MMC_RPMB_READ: mioc->num_of_cmds = 2; /* Read request */ ioc = &mioc->cmds[0]; set_single_cmd(ioc, MMC_WRITE_MULTIPLE_BLOCK, 1, 1); mmc_ioc_cmd_set_data((*ioc), frame_in); /* Get response */ ioc = &mioc->cmds[1]; set_single_cmd(ioc, MMC_READ_MULTIPLE_BLOCK, 0, out_cnt); mmc_ioc_cmd_set_data((*ioc), frame_out); break; default: err = -EINVAL; goto out; } err = ioctl(fd, MMC_IOC_MULTI_CMD, mioc); out: free(mioc); return err; #endif /* !MMC_IOC_MULTI_CMD */ } int do_rpmb_write_key(int nargs, char **argv) { int ret, dev_fd, key_fd; struct rpmb_frame frame_in = { .req_resp = htobe16(MMC_RPMB_WRITE_KEY) }, frame_out; if (nargs != 3) { fprintf(stderr, "Usage: mmc rpmb write-key </path/to/mmcblkXrpmb> </path/to/key>\n"); exit(1); } dev_fd = open(argv[1], O_RDWR); if (dev_fd < 0) { perror("device open"); exit(1); } if (0 == strcmp(argv[2], "-")) key_fd = STDIN_FILENO; else { key_fd = open(argv[2], O_RDONLY); if (key_fd < 0) { perror("can't open key file"); exit(1); } } /* Read the auth key */ ret = DO_IO(read, key_fd, frame_in.key_mac, sizeof(frame_in.key_mac)); if (ret < 0) { perror("read the key"); exit(1); } else if (ret != sizeof(frame_in.key_mac)) { printf("Auth key must be %lu bytes length, but we read only %d, exit\n", (unsigned long)sizeof(frame_in.key_mac), ret); exit(1); } /* Execute RPMB op */ ret = do_rpmb_op(dev_fd, &frame_in, &frame_out, 1); if (ret != 0) { perror("RPMB ioctl failed"); exit(1); } /* Check RPMB response */ if (frame_out.result != 0) { printf("RPMB operation failed, retcode 0x%04x\n", be16toh(frame_out.result)); exit(1); } close(dev_fd); if (key_fd != STDIN_FILENO) close(key_fd); return ret; } int rpmb_read_counter(int dev_fd, unsigned int *cnt) { int ret; struct rpmb_frame frame_in = { .req_resp = htobe16(MMC_RPMB_READ_CNT) }, frame_out; /* Execute RPMB op */ ret = do_rpmb_op(dev_fd, &frame_in, &frame_out, 1); if (ret != 0) { perror("RPMB ioctl failed"); exit(1); } /* Check RPMB response */ if (frame_out.result != 0) return be16toh(frame_out.result); *cnt = be32toh(frame_out.write_counter); return 0; } int do_rpmb_read_counter(int nargs, char **argv) { int ret, dev_fd; unsigned int cnt; if (nargs != 2) { fprintf(stderr, "Usage: mmc rpmb read-counter </path/to/mmcblkXrpmb>\n"); exit(1); } dev_fd = open(argv[1], O_RDWR); if (dev_fd < 0) { perror("device open"); exit(1); } ret = rpmb_read_counter(dev_fd, &cnt); /* Check RPMB response */ if (ret != 0) { printf("RPMB operation failed, retcode 0x%04x\n", ret); exit(1); } close(dev_fd); printf("Counter value: 0x%08x\n", cnt); return ret; } int do_rpmb_read_block(int nargs, char **argv) { int i, ret, dev_fd, data_fd, key_fd = -1; uint16_t addr; /* * for reading RPMB, number of blocks is set by CMD23 only, the packet * frame field for that is set to 0. So, the type is not u16 but uint! */ unsigned int blocks_cnt; unsigned char key[32]; struct rpmb_frame frame_in = { .req_resp = htobe16(MMC_RPMB_READ), }, *frame_out_p; if (nargs != 5 && nargs != 6) { fprintf(stderr, "Usage: mmc rpmb read-block </path/to/mmcblkXrpmb> <address> <blocks count> </path/to/output_file> [/path/to/key]\n"); exit(1); } dev_fd = open(argv[1], O_RDWR); if (dev_fd < 0) { perror("device open"); exit(1); } /* Get block address */ errno = 0; addr = strtol(argv[2], NULL, 0); if (errno) { perror("incorrect address"); exit(1); } frame_in.addr = htobe16(addr); /* Get blocks count */ errno = 0; blocks_cnt = strtol(argv[3], NULL, 0); if (errno) { perror("incorrect blocks count"); exit(1); } if (!blocks_cnt) { printf("please, specify valid blocks count number\n"); exit(1); } frame_out_p = calloc(sizeof(*frame_out_p), blocks_cnt); if (!frame_out_p) { printf("can't allocate memory for RPMB outer frames\n"); exit(1); } /* Write 256b data */ if (0 == strcmp(argv[4], "-")) data_fd = STDOUT_FILENO; else { data_fd = open(argv[4], O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR); if (data_fd < 0) { perror("can't open output file"); exit(1); } } /* Key is specified */ if (nargs == 6) { if (0 == strcmp(argv[5], "-")) key_fd = STDIN_FILENO; else { key_fd = open(argv[5], O_RDONLY); if (key_fd < 0) { perror("can't open input key file"); exit(1); } } ret = DO_IO(read, key_fd, key, sizeof(key)); if (ret < 0) { perror("read the key data"); exit(1); } else if (ret != sizeof(key)) { printf("Data must be %lu bytes length, but we read only %d, exit\n", (unsigned long)sizeof(key), ret); exit(1); } } /* Execute RPMB op */ ret = do_rpmb_op(dev_fd, &frame_in, frame_out_p, blocks_cnt); if (ret != 0) { perror("RPMB ioctl failed"); exit(1); } /* Check RPMB response */ if (frame_out_p[blocks_cnt - 1].result != 0) { printf("RPMB operation failed, retcode 0x%04x\n", be16toh(frame_out_p[blocks_cnt - 1].result)); exit(1); } /* Do we have to verify data against key? */ if (nargs == 6) { unsigned char mac[32]; hmac_sha256_ctx ctx; struct rpmb_frame *frame_out = NULL; hmac_sha256_init(&ctx, key, sizeof(key)); for (i = 0; i < blocks_cnt; i++) { frame_out = &frame_out_p[i]; hmac_sha256_update(&ctx, frame_out->data, sizeof(*frame_out) - offsetof(struct rpmb_frame, data)); } hmac_sha256_final(&ctx, mac, sizeof(mac)); /* Impossible */ assert(frame_out); /* Compare calculated MAC and MAC from last frame */ if (memcmp(mac, frame_out->key_mac, sizeof(mac))) { printf("RPMB MAC missmatch\n"); exit(1); } } /* Write data */ for (i = 0; i < blocks_cnt; i++) { struct rpmb_frame *frame_out = &frame_out_p[i]; ret = DO_IO(write, data_fd, frame_out->data, sizeof(frame_out->data)); if (ret < 0) { perror("write the data"); exit(1); } else if (ret != sizeof(frame_out->data)) { printf("Data must be %lu bytes length, but we wrote only %d, exit\n", (unsigned long)sizeof(frame_out->data), ret); exit(1); } } free(frame_out_p); close(dev_fd); if (data_fd != STDOUT_FILENO) close(data_fd); if (key_fd != -1 && key_fd != STDIN_FILENO) close(key_fd); return ret; } int do_rpmb_write_block(int nargs, char **argv) { int ret, dev_fd, key_fd, data_fd; unsigned char key[32]; uint16_t addr; unsigned int cnt; struct rpmb_frame frame_in = { .req_resp = htobe16(MMC_RPMB_WRITE), .block_count = htobe16(1) }, frame_out; if (nargs != 5) { fprintf(stderr, "Usage: mmc rpmb write-block </path/to/mmcblkXrpmb> <address> </path/to/input_file> </path/to/key>\n"); exit(1); } dev_fd = open(argv[1], O_RDWR); if (dev_fd < 0) { perror("device open"); exit(1); } ret = rpmb_read_counter(dev_fd, &cnt); /* Check RPMB response */ if (ret != 0) { printf("RPMB read counter operation failed, retcode 0x%04x\n", ret); exit(1); } frame_in.write_counter = htobe32(cnt); /* Get block address */ errno = 0; addr = strtol(argv[2], NULL, 0); if (errno) { perror("incorrect address"); exit(1); } frame_in.addr = htobe16(addr); /* Read 256b data */ if (0 == strcmp(argv[3], "-")) data_fd = STDIN_FILENO; else { data_fd = open(argv[3], O_RDONLY); if (data_fd < 0) { perror("can't open input file"); exit(1); } } ret = DO_IO(read, data_fd, frame_in.data, sizeof(frame_in.data)); if (ret < 0) { perror("read the data"); exit(1); } else if (ret != sizeof(frame_in.data)) { printf("Data must be %lu bytes length, but we read only %d, exit\n", (unsigned long)sizeof(frame_in.data), ret); exit(1); } /* Read the auth key */ if (0 == strcmp(argv[4], "-")) key_fd = STDIN_FILENO; else { key_fd = open(argv[4], O_RDONLY); if (key_fd < 0) { perror("can't open key file"); exit(1); } } ret = DO_IO(read, key_fd, key, sizeof(key)); if (ret < 0) { perror("read the key"); exit(1); } else if (ret != sizeof(key)) { printf("Auth key must be %lu bytes length, but we read only %d, exit\n", (unsigned long)sizeof(key), ret); exit(1); } /* Calculate HMAC SHA256 */ hmac_sha256( key, sizeof(key), frame_in.data, sizeof(frame_in) - offsetof(struct rpmb_frame, data), frame_in.key_mac, sizeof(frame_in.key_mac)); /* Execute RPMB op */ ret = do_rpmb_op(dev_fd, &frame_in, &frame_out, 1); if (ret != 0) { perror("RPMB ioctl failed"); exit(1); } /* Check RPMB response */ if (frame_out.result != 0) { printf("RPMB operation failed, retcode 0x%04x\n", be16toh(frame_out.result)); exit(1); } close(dev_fd); if (data_fd != STDIN_FILENO) close(data_fd); if (key_fd != STDIN_FILENO) close(key_fd); return ret; } int do_cache_ctrl(int value, int nargs, char **argv) { __u8 ext_csd[512]; int fd, ret; char *device; if (nargs != 2) { fprintf(stderr, "Usage: mmc cache enable </path/to/mmcblkX>\n"); exit(1); } device = argv[1]; fd = open(device, O_RDWR); if (fd < 0) { perror("open"); exit(1); } ret = read_extcsd(fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); exit(1); } if (ext_csd[EXT_CSD_REV] < EXT_CSD_REV_V4_5) { fprintf(stderr, "The CACHE option is only availabe on devices >= " "MMC 4.5 %s\n", device); exit(1); } /* If the cache size is zero, this device does not have a cache */ if (!(ext_csd[EXT_CSD_CACHE_SIZE_3] || ext_csd[EXT_CSD_CACHE_SIZE_2] || ext_csd[EXT_CSD_CACHE_SIZE_1] || ext_csd[EXT_CSD_CACHE_SIZE_0])) { fprintf(stderr, "The CACHE option is not available on %s\n", device); exit(1); } ret = write_extcsd_value(fd, EXT_CSD_CACHE_CTRL, value); if (ret) { fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n", value, EXT_CSD_CACHE_CTRL, device); exit(1); } close(fd); return ret; } int do_cache_en(int nargs, char **argv) { return do_cache_ctrl(1, nargs, argv); } int do_cache_dis(int nargs, char **argv) { return do_cache_ctrl(0, nargs, argv); } static int erase(int dev_fd, __u32 argin, __u32 start, __u32 end) { int ret = 0; struct mmc_ioc_multi_cmd *multi_cmd; __u8 ext_csd[512]; ret = read_extcsd(dev_fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD\n"); exit(1); } if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { fprintf(stderr, "High Capacity Erase Unit Size=%d bytes\n" \ "High Capacity Erase Timeout=%d ms\n" \ "High Capacity Write Protect Group Size=%d bytes\n", ext_csd[224]*0x80000, ext_csd[223]*300, ext_csd[221]*ext_csd[224]*0x80000); } multi_cmd = calloc(1, sizeof(struct mmc_ioc_multi_cmd) + 3 * sizeof(struct mmc_ioc_cmd)); if (!multi_cmd) { perror("Failed to allocate memory"); return -ENOMEM; } multi_cmd->num_of_cmds = 3; /* Set erase start address */ multi_cmd->cmds[0].opcode = MMC_ERASE_GROUP_START; multi_cmd->cmds[0].arg = start; multi_cmd->cmds[0].flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; multi_cmd->cmds[0].write_flag = 1; /* Set erase end address */ multi_cmd->cmds[1].opcode = MMC_ERASE_GROUP_END; multi_cmd->cmds[1].arg = end; multi_cmd->cmds[1].flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; multi_cmd->cmds[1].write_flag = 1; /* Send Erase Command */ multi_cmd->cmds[2].opcode = MMC_ERASE; multi_cmd->cmds[2].arg = argin; multi_cmd->cmds[2].cmd_timeout_ms = 300*255*255; multi_cmd->cmds[2].flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; multi_cmd->cmds[2].write_flag = 1; /* send erase cmd with multi-cmd */ ret = ioctl(dev_fd, MMC_IOC_MULTI_CMD, multi_cmd); if (ret) perror("Erase multi-cmd ioctl"); free(multi_cmd); return ret; } int do_erase(int nargs, char **argv) { int dev_fd, ret; char *print_str; __u8 ext_csd[512], checkup_mask = 0; __u32 arg, start, end; if (nargs != 5) { fprintf(stderr, "Usage: erase <type> <start addr> <end addr> </path/to/mmcblkX>\n"); exit(1); } if (strstr(argv[2], "0x") || strstr(argv[2], "0X")) start = strtol(argv[2], NULL, 16); else start = strtol(argv[2], NULL, 10); if (strstr(argv[3], "0x") || strstr(argv[3], "0X")) end = strtol(argv[3], NULL, 16); else end = strtol(argv[3], NULL, 10); if (end < start) { fprintf(stderr, "erase start [0x%08x] > erase end [0x%08x]\n", start, end); exit(1); } if (strcmp(argv[1], "legacy") == 0) { arg = 0x00000000; print_str = "Legacy Erase"; } else if (strcmp(argv[1], "discard") == 0) { arg = 0x00000003; print_str = "Discard"; } else if (strcmp(argv[1], "secure-erase") == 0) { print_str = "Secure Erase"; checkup_mask = EXT_CSD_SEC_ER_EN; arg = 0x80000000; } else if (strcmp(argv[1], "secure-trim1") == 0) { print_str = "Secure Trim Step 1"; checkup_mask = EXT_CSD_SEC_ER_EN | EXT_CSD_SEC_GB_CL_EN; arg = 0x80000001; } else if (strcmp(argv[1], "secure-trim2") == 0) { print_str = "Secure Trim Step 2"; checkup_mask = EXT_CSD_SEC_ER_EN | EXT_CSD_SEC_GB_CL_EN; arg = 0x80008000; } else if (strcmp(argv[1], "trim") == 0) { print_str = "Trim"; checkup_mask = EXT_CSD_SEC_GB_CL_EN; arg = 0x00000001; } else { fprintf(stderr, "Unknown erase type: %s\n", argv[1]); exit(1); } dev_fd = open(argv[4], O_RDWR); if (dev_fd < 0) { perror(argv[4]); exit(1); } if (checkup_mask) { ret = read_extcsd(dev_fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", argv[4]); goto out; } if ((checkup_mask & ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) != checkup_mask) { fprintf(stderr, "%s is not supported in %s\n", print_str, argv[4]); ret = -ENOTSUP; goto out; } } printf("Executing %s from 0x%08x to 0x%08x\n", print_str, start, end); ret = erase(dev_fd, arg, start, end); out: printf(" %s %s!\n\n", print_str, ret ? "Failed" : "Succeed"); close(dev_fd); return ret; } int do_ffu(int nargs, char **argv) { #ifndef MMC_IOC_MULTI_CMD fprintf(stderr, "mmc-utils has been compiled without MMC_IOC_MULTI_CMD" " support, needed by FFU.\n"); exit(1); #else int dev_fd, img_fd; int sect_done = 0, retry = 3, ret = -EINVAL; unsigned int sect_size; __u8 ext_csd[512]; __u8 *buf = NULL; __u32 arg; off_t fw_size; ssize_t chunk_size; char *device; struct mmc_ioc_multi_cmd *multi_cmd = NULL; __u32 blocks = 1; if (nargs != 3) { fprintf(stderr, "Usage: ffu <image name> </path/to/mmcblkX> \n"); exit(1); } device = argv[2]; dev_fd = open(device, O_RDWR); if (dev_fd < 0) { perror("device open failed"); exit(1); } img_fd = open(argv[1], O_RDONLY); if (img_fd < 0) { perror("image open failed"); close(dev_fd); exit(1); } ret = read_extcsd(dev_fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); goto out; } if (ext_csd[EXT_CSD_REV] < EXT_CSD_REV_V5_0) { fprintf(stderr, "The FFU feature is only available on devices >= " "MMC 5.0, not supported in %s\n", device); goto out; } if (!(ext_csd[EXT_CSD_SUPPORTED_MODES] & EXT_CSD_FFU)) { fprintf(stderr, "FFU is not supported in %s\n", device); goto out; } if (ext_csd[EXT_CSD_FW_CONFIG] & EXT_CSD_UPDATE_DISABLE) { fprintf(stderr, "Firmware update was disabled in %s\n", device); goto out; } fw_size = lseek(img_fd, 0, SEEK_END); if (fw_size > MMC_IOC_MAX_BYTES || fw_size == 0) { fprintf(stderr, "Wrong firmware size"); goto out; } /* allocate maximum required */ buf = malloc(fw_size); multi_cmd = calloc(1, sizeof(struct mmc_ioc_multi_cmd) + 4 * sizeof(struct mmc_ioc_cmd)); if (!buf || !multi_cmd) { perror("failed to allocate memory"); goto out; } sect_size = (ext_csd[EXT_CSD_DATA_SECTOR_SIZE] == 0) ? 512 : 4096; if (fw_size % sect_size) { fprintf(stderr, "Firmware data size (%jd) is not aligned!\n", (intmax_t)fw_size); goto out; } /* calculate required fw blocks for CMD25 */ blocks = fw_size / sect_size; /* set CMD ARG */ arg = ext_csd[EXT_CSD_FFU_ARG_0] | ext_csd[EXT_CSD_FFU_ARG_1] << 8 | ext_csd[EXT_CSD_FFU_ARG_2] << 16 | ext_csd[EXT_CSD_FFU_ARG_3] << 24; /* prepare multi_cmd for FFU based on cmd to be used */ /* prepare multi_cmd to be sent */ multi_cmd->num_of_cmds = 4; /* put device into ffu mode */ multi_cmd->cmds[0].opcode = MMC_SWITCH; multi_cmd->cmds[0].arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (EXT_CSD_MODE_CONFIG << 16) | (EXT_CSD_FFU_MODE << 8) | EXT_CSD_CMD_SET_NORMAL; multi_cmd->cmds[0].flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; multi_cmd->cmds[0].write_flag = 1; /* send block count */ multi_cmd->cmds[1].opcode = MMC_SET_BLOCK_COUNT; multi_cmd->cmds[1].arg = blocks; multi_cmd->cmds[1].flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; /* send image chunk */ multi_cmd->cmds[2].opcode = MMC_WRITE_MULTIPLE_BLOCK; multi_cmd->cmds[2].blksz = sect_size; multi_cmd->cmds[2].blocks = blocks; multi_cmd->cmds[2].arg = arg; multi_cmd->cmds[2].flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; multi_cmd->cmds[2].write_flag = 1; mmc_ioc_cmd_set_data(multi_cmd->cmds[2], buf); /* return device into normal mode */ multi_cmd->cmds[3].opcode = MMC_SWITCH; multi_cmd->cmds[3].arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (EXT_CSD_MODE_CONFIG << 16) | (EXT_CSD_NORMAL_MODE << 8) | EXT_CSD_CMD_SET_NORMAL; multi_cmd->cmds[3].flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; multi_cmd->cmds[3].write_flag = 1; do_retry: /* read firmware chunk */ lseek(img_fd, 0, SEEK_SET); chunk_size = read(img_fd, buf, fw_size); if (chunk_size > 0) { /* send ioctl with multi-cmd */ ret = ioctl(dev_fd, MMC_IOC_MULTI_CMD, multi_cmd); if (ret) { perror("Multi-cmd ioctl"); /* In case multi-cmd ioctl failed before exiting from ffu mode */ ioctl(dev_fd, MMC_IOC_CMD, &multi_cmd->cmds[3]); goto out; } ret = read_extcsd(dev_fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); goto out; } /* Test if we need to restart the download */ sect_done = ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG_0] | ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG_1] << 8 | ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG_2] << 16 | ext_csd[EXT_CSD_NUM_OF_FW_SEC_PROG_3] << 24; /* By spec, host should re-start download from the first sector if sect_done is 0 */ if (sect_done == 0) { if (retry > 0) { retry--; fprintf(stderr, "Programming failed. Retrying... (%d)\n", retry); goto do_retry; } fprintf(stderr, "Programming failed! Aborting...\n"); goto out; } else { fprintf(stderr, "Programmed %d/%jd bytes\r", sect_done * sect_size, (intmax_t)fw_size); } } if ((sect_done * sect_size) == fw_size) { fprintf(stderr, "Programmed %jd/%jd bytes\n", (intmax_t)fw_size, (intmax_t)fw_size); fprintf(stderr, "Programming finished with status %d \n", ret); } else { fprintf(stderr, "FW size and number of sectors written mismatch. Status return %d\n", ret); goto out; } /* check mode operation for ffu install*/ if (!ext_csd[EXT_CSD_FFU_FEATURES]) { fprintf(stderr, "Please reboot to complete firmware installation on %s\n", device); } else { fprintf(stderr, "Installing firmware on %s...\n", device); /* Re-enter ffu mode and install the firmware */ multi_cmd->num_of_cmds = 2; /* set ext_csd to install mode */ multi_cmd->cmds[1].opcode = MMC_SWITCH; multi_cmd->cmds[1].blksz = 0; multi_cmd->cmds[1].blocks = 0; multi_cmd->cmds[1].arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (EXT_CSD_MODE_OPERATION_CODES << 16) | (EXT_CSD_FFU_INSTALL << 8) | EXT_CSD_CMD_SET_NORMAL; multi_cmd->cmds[1].flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; multi_cmd->cmds[1].write_flag = 1; /* send ioctl with multi-cmd */ ret = ioctl(dev_fd, MMC_IOC_MULTI_CMD, multi_cmd); if (ret) { perror("Multi-cmd ioctl failed setting install mode"); /* In case multi-cmd ioctl failed before exiting from ffu mode */ ioctl(dev_fd, MMC_IOC_CMD, &multi_cmd->cmds[3]); goto out; } ret = read_extcsd(dev_fd, ext_csd); if (ret) { fprintf(stderr, "Could not read EXT_CSD from %s\n", device); goto out; } /* return status */ ret = ext_csd[EXT_CSD_FFU_STATUS]; if (ret) { fprintf(stderr, "%s: error %d during FFU install:\n", device, ret); goto out; } else { fprintf(stderr, "FFU finished successfully\n"); } } out: free(buf); free(multi_cmd); close(img_fd); close(dev_fd); return ret; #endif } 07070100000011000081A40000000000000000000000016202891700000826000000000000000000000000000000000000002600000000mmc-utils-0.1+git.20220208/mmc_cmds.h/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. * * Modified to add field firmware update support, * those modifications are Copyright (c) 2016 SanDisk Corp. */ /* mmc_cmds.c */ int do_read_extcsd(int nargs, char **argv); int do_write_extcsd(int nargs, char **argv); int do_writeprotect_boot_get(int nargs, char **argv); int do_writeprotect_boot_set(int nargs, char **argv); int do_writeprotect_user_get(int nargs, char **argv); int do_writeprotect_user_set(int nargs, char **argv); int do_disable_512B_emulation(int nargs, char **argv); int do_write_boot_en(int nargs, char **argv); int do_boot_bus_conditions_set(int nargs, char **argv); int do_write_bkops_en(int nargs, char **argv); int do_hwreset_en(int nargs, char **argv); int do_hwreset_dis(int nargs, char **argv); int do_sanitize(int nargs, char **argv); int do_status_get(int nargs, char **argv); int do_create_gp_partition(int nargs, char **argv); int do_enh_area_set(int nargs, char **argv); int do_write_reliability_set(int nargs, char **argv); int do_rpmb_write_key(int nargs, char **argv); int do_rpmb_read_counter(int nargs, char **argv); int do_rpmb_read_block(int nargs, char **argv); int do_rpmb_write_block(int nargs, char **argv); int do_cache_en(int nargs, char **argv); int do_cache_dis(int nargs, char **argv); int do_ffu(int nargs, char **argv); int do_read_scr(int argc, char **argv); int do_read_cid(int argc, char **argv); int do_read_csd(int argc, char **argv); int do_erase(int nargs, char **argv); 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!440 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor