diff --git a/BoardConfig.mk b/BoardConfig.mk index 994b43a9b429db1a10739521a3f51c5f4b2228c9..591b0ff9f093a6152518749f669100429026637b 100644 --- a/BoardConfig.mk +++ b/BoardConfig.mk @@ -81,8 +81,5 @@ BOARD_AVB_SYSTEM_ADD_HASHTREE_FOOTER_ARGS := --hash_algorithm sha256 BOARD_AVB_PRODUCT_ADD_HASHTREE_FOOTER_ARGS := --hash_algorithm sha256 BOARD_AVB_VENDOR_ADD_HASHTREE_FOOTER_ARGS := --hash_algorithm sha256 -# Sepolicy -BOARD_VENDOR_SEPOLICY_DIRS += $(DEVICE_PATH)/sepolicy/vendor - # Inherit from the proprietary version include vendor/teracube/emerald/BoardConfigVendor.mk diff --git a/bootctrl/Android.bp b/bootctrl/Android.bp index 18224fb7165b9419c400e9e343727f63b4354119..a84200e10d1e17be65281cf1649d3e867513e7fe 100644 --- a/bootctrl/Android.bp +++ b/bootctrl/Android.bp @@ -15,8 +15,8 @@ // cc_library_shared { - name: "android.hardware.boot@1.1-mtkimpl", - stem: "android.hardware.boot@1.0-impl-1.1-mtkimpl", + name: "android.hardware.boot@1.2-mtkimpl", + stem: "android.hardware.boot@1.0-impl-1.2-mtkimpl", defaults: [ "hidl_defaults", "libboot_control_defaults", @@ -25,7 +25,8 @@ cc_library_shared { vendor: true, recovery_available: true, srcs: ["BootControl.cpp", "boot_region_control.cpp"], - + cppflags: ["-Wno-unused-variable"], + cflags: ["-Wno-unused-variable"], header_libs: ["device_kernel_headers"], shared_libs: [ @@ -35,6 +36,8 @@ cc_library_shared { "libutils", "android.hardware.boot@1.0", "android.hardware.boot@1.1", + "android.hardware.boot@1.2", + "libmtk_bsg" ], static_libs: [ "libboot_control", diff --git a/bootctrl/BootControl.cpp b/bootctrl/BootControl.cpp index 2bf19a7ad36f6b59d630a15650697e9e20325c84..34dc52a2d8fb377d2ac075a29d7e4b06e52b82af 100644 --- a/bootctrl/BootControl.cpp +++ b/bootctrl/BootControl.cpp @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#define LOG_TAG "android.hardware.boot@1.1-mtkimpl" +#define LOG_TAG "android.hardware.boot@1.2-mtkimpl" #include @@ -28,7 +28,7 @@ namespace android { namespace hardware { namespace boot { -namespace V1_1 { +namespace V1_2 { namespace implementation { using ::android::hardware::boot::V1_0::CommandResult; @@ -142,6 +142,10 @@ Return BootControl::getSnapshotMergeStatus() { return impl_.GetSnapshotMergeStatus(); } +Return BootControl::getActiveBootSlot() { + return impl_.GetActiveBootSlot(); +} + IBootControl* HIDL_FETCH_IBootControl(const char* /* hal */) { auto module = std::make_unique(); if (!module->Init()) { @@ -155,4 +159,4 @@ IBootControl* HIDL_FETCH_IBootControl(const char* /* hal */) { } // namespace V1_1 } // namespace boot } // namespace hardware -} // namespace android +} // namespace android \ No newline at end of file diff --git a/bootctrl/BootControl.h b/bootctrl/BootControl.h index d63b244208a405a5e189d3c9cde80ac48892d4cd..a215fcba2f1fbf61bb13eba1dcc21f8d8b1dfa5e 100644 --- a/bootctrl/BootControl.h +++ b/bootctrl/BootControl.h @@ -16,7 +16,7 @@ #pragma once -#include +#include #include #include #include @@ -25,13 +25,13 @@ namespace android { namespace hardware { namespace boot { -namespace V1_1 { +namespace V1_2 { namespace implementation { using ::android::hardware::Return; using ::android::hardware::Void; using ::android::hardware::boot::V1_0::BoolResult; -using ::android::hardware::boot::V1_1::IBootControl; +using ::android::hardware::boot::V1_2::IBootControl; using ::android::hardware::boot::V1_1::MergeStatus; class BootControl : public IBootControl { @@ -52,6 +52,9 @@ class BootControl : public IBootControl { Return setSnapshotMergeStatus(MergeStatus status) override; Return getSnapshotMergeStatus() override; + // Methods from ::android::hardware::boot::V1_2::IBootControl. + Return getActiveBootSlot() override; + private: android::bootable::BootControl impl_; android::bootable::BootControlExt implext_; @@ -64,4 +67,4 @@ extern "C" IBootControl* HIDL_FETCH_IBootControl(const char* name); } // namespace V1_1 } // namespace boot } // namespace hardware -} // namespace android +} // namespace android \ No newline at end of file diff --git a/bootctrl/boot_control_definition.h b/bootctrl/boot_control_definition.h index 5d36a987e16f8e4ce64727e0864e399d57ca51aa..887f8292a8ceac312428d1e703af543a46a5e1dd 100644 --- a/bootctrl/boot_control_definition.h +++ b/bootctrl/boot_control_definition.h @@ -115,4 +115,4 @@ namespace bootable { bool LoadBootloaderControl(const std::string& misc_device, bootloader_control* buffer); uint32_t BootloaderControlLECRC(const bootloader_control* boot_ctrl); } -} +} \ No newline at end of file diff --git a/bootctrl/boot_region_control.cpp b/bootctrl/boot_region_control.cpp index 1835d78e116472b67183c4496e4ae2d74d4e48db..9fecc756c728b6811a7d25e8004ea22fb33209ba 100644 --- a/bootctrl/boot_region_control.cpp +++ b/bootctrl/boot_region_control.cpp @@ -1,38 +1,3 @@ -/***************************************************************************** -* Copyright Statement: -* -------------------- -* This software is protected by Copyright and the information contained -* herein is confidential. The software may not be copied and the information -* contained herein may not be used or disclosed except with the written -* permission of MediaTek Inc. (C) 2020 -* -* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES -* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") -* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON -* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. -* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE -* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR -* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH -* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO -* NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S -* SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. -* -* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE -* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, -* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, -* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO -* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. -* -* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE -* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF -* LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND -* RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER -* THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC). -* -*****************************************************************************/ - #include #include #include @@ -41,10 +6,14 @@ #if !defined(ARCH_X86) #include "mmc-mtk-ioctl.h" +#include "ufs-mtk-ioctl.h" #include #endif #include "boot_region_control_private.h" +extern "C"{ + #include "mtk_ioctl.h" +} namespace android { namespace bootable { @@ -120,6 +89,35 @@ static bool emmc_set_active_boot_part(int bootpart) return ret; } +static bool ufs_set_active_boot_part(int boot) +{ + struct ufs_ioctl_query_data idata; + unsigned char buf[1]; + int fd, ret = true; + + fd = open("/dev/block/sdc", O_RDWR); + if (fd < 0) { + printf("%s: open device failed, err: %d\n", __func__, fd); + return false; + } + + buf[0] = boot; /* 1: BootLU A, 2: BootLU B */ + + idata.opcode = UPIU_QUERY_OPCODE_WRITE_ATTR; + idata.idn = QUERY_ATTR_IDN_BOOT_LUN_EN; + idata.idx = 0; + idata.buf_ptr = &buf[0]; + idata.buf_byte = 1; + + if (ioctl(fd, UFS_IOCTL_QUERY, &idata) < 0) { + LOG(ERROR) << "ufs_set boot_part old fail"; + ret = ioctrl_w_attr("/dev/ufs-bsg0", QUERY_ATTR_IDN_BOOT_LUN_EN, 0, 0, boot); + } + + close(fd); + return ret; +} + bool BootControlExt::SetBootRegionSlot(unsigned int slot) { int boot_part = 0; @@ -136,8 +134,9 @@ bool BootControlExt::SetBootRegionSlot(unsigned int slot) { else boot_part = 1; - if (!emmc_set_active_boot_part(boot_part)) - return false; + if (!ufs_set_active_boot_part(boot_part)) + if (!emmc_set_active_boot_part(boot_part)) + return false; return true; } @@ -147,4 +146,4 @@ bool BootControlExt::SetBootRegionSlot(unsigned int slot) { } #endif //#if !defined(ARCH_X86) } -} +} \ No newline at end of file diff --git a/bootctrl/boot_region_control_private.h b/bootctrl/boot_region_control_private.h index 9be848b52ca768d31c449f36effc3019d5ccc638..ecf7e30a821008236a39b685240b04f1712684b6 100644 --- a/bootctrl/boot_region_control_private.h +++ b/bootctrl/boot_region_control_private.h @@ -1,38 +1,3 @@ -/***************************************************************************** -* Copyright Statement: -* -------------------- -* This software is protected by Copyright and the information contained -* herein is confidential. The software may not be copied and the information -* contained herein may not be used or disclosed except with the written -* permission of MediaTek Inc. (C) 2020 -* -* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES -* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") -* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON -* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. -* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE -* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR -* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH -* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO -* NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S -* SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. -* -* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE -* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, -* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, -* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO -* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. -* -* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE -* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF -* LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND -* RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER -* THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC). -* -*****************************************************************************/ - #pragma once namespace android { diff --git a/bootctrl/mmc-mtk-ioctl.h b/bootctrl/mmc-mtk-ioctl.h index 962ccb15acdadf071ed7eecfacf58ca5734435d1..53eeac97d812e6fbe420f938fe9684db7d56e56b 100644 --- a/bootctrl/mmc-mtk-ioctl.h +++ b/bootctrl/mmc-mtk-ioctl.h @@ -1,106 +1,52 @@ -/* - * Copyright (C) 2018 MediaTek Inc. - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 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 http://www.gnu.org/licenses/gpl-2.0.html for more details. - */ - -#ifndef MMC_MTK_IOCTL_H__ -#define MMC_MTK_IOCTL_H__ - -#include - -#define MMC_BLOCK_MAJOR 179 - -struct mmc_ioc_cmd { - /* Implies direction of data. true = write, false = read */ - int write_flag; - - /* Application-specific command. true = precede with CMD55 */ - int is_acmd; - - __u32 opcode; - __u32 arg; - __u32 response[4]; /* CMD response */ - unsigned int flags; - unsigned int blksz; - unsigned int blocks; - - /* - * Sleep at least postsleep_min_us useconds, and at most - * postsleep_max_us useconds *after* issuing command. Needed for - * some read commands for which cards have no other way of indicating - * they're ready for the next command (i.e. there is no equivalent of - * a "busy" indicator for read operations). - */ - unsigned int postsleep_min_us; - unsigned int postsleep_max_us; - - /* - * Override driver-computed timeouts. Note the difference in units! - */ - unsigned int data_timeout_ns; - unsigned int cmd_timeout_ms; - /* - * For 64-bit machines, the next member, ``__u64 data_ptr``, wants to - * be 8-byte aligned. Make sure this struct is the same size when - * built for 32-bit. - */ - __u32 __pad; +#ifndef EMMC_MTK_IOCTL_H__ +#define EMMC_MTK_IOCTL_H__ - /* DAT buffer */ - __u64 data_ptr; -}; -#define mmc_ioc_cmd_set_data(ic, ptr) ic.data_ptr = (__u64)(unsigned long) ptr - -#define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd) - -/* Standard MMC commands (4.1) type argument response */ - /* class 1 */ -#define MMC_SWITCH 6 /* ac [31:0] See below R1b */ -#define MMC_SEND_EXT_CSD 8 /* adtc R1 */ +#include +#define MMC_BLOCK_MAJOR 179 +#define MMC_SWITCH 6 +#define MMC_SEND_EXT_CSD 8 /* - * EXT_CSD fields - */ -#define EXT_CSD_PART_CONFIG 179 /* R/W */ - +* EXT_CSD fields +*/ +#define EXT_CSD_PART_CONFIG 179 + +/**/ +typedef enum { + EMMC_PART_UNKNOWN=0 + ,EMMC_PART_BOOT1 + ,EMMC_PART_BOOT2 + ,EMMC_PART_RPMB + ,EMMC_PART_GP1 + ,EMMC_PART_GP2 + ,EMMC_PART_GP3 + ,EMMC_PART_GP4 + ,EMMC_PART_USER + ,EMMC_PART_END +} Region; + +/* Copied from kernel linux/mmc/core.h */ +#define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */ +#define MMC_RSP_BUSY (1 << 3) /* card may send busy */ +#define MMC_RSP_CRC (1 << 2) /* expect valid crc */ +#define MMC_RSP_136 (1 << 1) /* 136 bit response */ +#define MMC_RSP_PRESENT (1 << 0) + +#define MMC_CMD_ADTC (1 << 5) +#define MMC_CMD_AC (0 << 5) + +#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) + +/* Copied from kernel linux/mmc/mmc.h */ #define EXT_CSD_CMD_SET_NORMAL (1<<0) #define EXT_CSD_CMD_SET_SECURE (1<<1) #define EXT_CSD_CMD_SET_CPSECURE (1<<2) -/* - * MMC_SWITCH access modes - */ #define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ #define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */ #define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */ #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ -#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 */ - -/* - * These are the native response types, and correspond to valid bit - * patterns of the above flags. One additional valid pattern - * is all zeros, which means we don't expect a response. - */ -#define MMC_RSP_NONE (0) -#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) - -#define MMC_CMD_MASK (3 << 5) /* non-SPI command type */ -#define MMC_CMD_AC (0 << 5) -#define MMC_CMD_ADTC (1 << 5) -#define MMC_CMD_BC (2 << 5) -#define MMC_CMD_BCR (3 << 5) - -#endif /* MMC_MTK_IOCTL_H__ */ +#endif diff --git a/bootctrl/mtk_ioctl.h b/bootctrl/mtk_ioctl.h new file mode 100644 index 0000000000000000000000000000000000000000..786c141e5dab5f64319ee8b4a7da1c6d1b911709 --- /dev/null +++ b/bootctrl/mtk_ioctl.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MTK_IOCTL_H_ +#define MTK_IOCTL_H_ + + +int ioctrl_w_attr(const char path[], uint8_t idn, uint8_t index, uint8_t selector, uint32_t value); +// int ioctrl_r_attr(int fd, uint8_t idn, uint8_t index, uint8_t selector, uint32_t *value); + + +#endif diff --git a/bootctrl/ufs-mtk-ioctl-private.h b/bootctrl/ufs-mtk-ioctl-private.h new file mode 100644 index 0000000000000000000000000000000000000000..5228a60f30b7b371494383d7bc838dac9be14987 --- /dev/null +++ b/bootctrl/ufs-mtk-ioctl-private.h @@ -0,0 +1,49 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + *** To edit the content of this header, modify the corresponding + *** source file (e.g. under external/kernel-headers/original/) then + *** run bionic/libc/kernel/tools/update_all.py + *** + *** Any manual change here will be lost the next time this script will + *** be run. You've been warned! + *** + **************************************************************************** + ****************************************************************************/ +#ifndef UFS_MTK_IOCTL_PRIVATE_H_ +#define UFS_MTK_IOCTL_PRIVATE_H_ +enum query_opcode { + UPIU_QUERY_OPCODE_READ_DESC = 0x1, + UPIU_QUERY_OPCODE_READ_ATTR = 0x3, + UPIU_QUERY_OPCODE_WRITE_ATTR = 0x4, + UPIU_QUERY_OPCODE_READ_FLAG = 0x5, +}; +enum attr_idn { + QUERY_ATTR_IDN_BOOT_LUN_EN = 0x00, + QUERY_ATTR_IDN_DEVICE_FFU_STATUS = 0x14, +}; +enum flag_idn { + QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE = 0xB, +}; +enum desc_idn { + QUERY_DESC_IDN_DEVICE = 0x0, + QUERY_DESC_IDN_STRING = 0x5, +}; +enum ufs_desc_max_size { + QUERY_DESC_DEVICE_MAX_SIZE = 0x40, +}; +enum ufs_feature_support_list { + UFS_FEATURES_FFU = 0x1, +}; +enum device_desc_param { + DEVICE_DESC_PARAM_MANF_ID = 0x18, + DEVICE_DESC_UFS_FEATURES_SUPPORT = 0x1F, + DEVICE_DESC_PARAM_PRL = 0x2A, +}; +#endif diff --git a/bootctrl/ufs-mtk-ioctl.h b/bootctrl/ufs-mtk-ioctl.h new file mode 100644 index 0000000000000000000000000000000000000000..bb733a53dbc3d205ddd5f38de20c8c93cc24acd5 --- /dev/null +++ b/bootctrl/ufs-mtk-ioctl.h @@ -0,0 +1,51 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + *** To edit the content of this header, modify the corresponding + *** source file (e.g. under external/kernel-headers/original/) then + *** run bionic/libc/kernel/tools/update_all.py + *** + *** Any manual change here will be lost the next time this script will + *** be run. You've been warned! + *** + **************************************************************************** + ****************************************************************************/ +#ifndef UFS_MTK_IOCTL_H__ +#define UFS_MTK_IOCTL_H__ +#include "ufs-mtk-ioctl-private.h" +#define UFS_IOCTL_QUERY 0x5388 +#define UFS_IOCTL_FFU 0x5389 +#define UFS_IOCTL_GET_FW_VER 0x5390 +#define UFS_IOCTL_RPMB 0x5391 +#define HPB_QUERY_OPCODE 0x5500 +#define UFS_IOCTL_FFU_MAX_FW_SIZE_BYTES (512L * 1024) +#define UFS_IOCTL_FFU_MAX_FW_VER_BYTES (4) +#define UFS_IOCTL_FFU_MAX_FW_VER_STRING_DESCR_BYTES (10) +struct ufs_ioctl_query_data { + __u32 opcode; + __u8 idn; + __u8 idx; + __u16 buf_byte; + __u8 * buf_ptr; +}; +struct ufs_ioctl_query_data_hpb { + __u32 opcode; + __u8 idn; + __u16 buf_size; + __u8 buffer[0]; +}; +struct ufs_ioctl_ffu_data { + __u32 buf_byte; + __u8 * buf_ptr; +}; +struct ufs_ioctl_query_fw_ver_data { + __u16 buf_byte; + __u8 * buf_ptr; +}; +#endif diff --git a/device.mk b/device.mk index 274217c540e232436cdc3d96afb49c4b326d630e..dcc44a37a7caab6f977a6b7c92df7f60b8db656c 100644 --- a/device.mk +++ b/device.mk @@ -24,10 +24,10 @@ PRODUCT_PACKAGES += \ # Bootctrl PRODUCT_PACKAGES += \ - android.hardware.boot@1.1 \ - android.hardware.boot@1.1-service \ - android.hardware.boot@1.1-mtkimpl \ - android.hardware.boot@1.1-mtkimpl.recovery + android.hardware.boot@1.2 \ + android.hardware.boot@1.2-service \ + android.hardware.boot@1.2-mtkimpl \ + android.hardware.boot@1.2-mtkimpl.recovery PRODUCT_PROPERTY_OVERRIDES += \ ro.cp_system_other_odex=1 diff --git a/dtbo/dtbo.img b/dtbo/dtbo.img old mode 100644 new mode 100755 index 6261b930aac5b6bb420373924f0d154da2090fdf..4a12fa52147908d499e41a87b383ecfc72f7de92 Binary files a/dtbo/dtbo.img and b/dtbo/dtbo.img differ diff --git a/libmtk_bsg/Android.bp b/libmtk_bsg/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..bcbc4810d4cc7c63a0d82ea99d87a6e113ecea01 --- /dev/null +++ b/libmtk_bsg/Android.bp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2021, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +cc_library_shared { + name: "libmtk_bsg", + vendor: true, + recovery_available: true, + srcs: ["*.c"], + + header_libs: ["device_kernel_headers"], +} diff --git a/libmtk_bsg/Makefile.disable b/libmtk_bsg/Makefile.disable new file mode 100644 index 0000000000000000000000000000000000000000..89420540d35e33dc5bc422f7d8acdc3d9a04d394 --- /dev/null +++ b/libmtk_bsg/Makefile.disable @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +export CC := $(CROSS_COMPILE)gcc +AM_CFLAGS = -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 +CFLAGS ?= -g -O2 -static + +ifneq ($(CROSS_COMPILE),) + LDFLAGS += -static +endif + +#CXXFLAGS = -DDEBUG + +objects = \ + ufs.o \ + ufs_cmds.o \ + options.o \ + scsi_bsg_util.o \ + ufs_err_hist.o \ + unipro.o \ + ufs_ffu.o \ + ufs_vendor.o\ + hmac_sha2.o \ + sha2.o \ + ufs_rpmb.o \ + ufs_hmr.o + +CHECKFLAGS = -Wall -Wundef -Wno-missing-braces + +DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@ +override CFLAGS := $(CHECKFLAGS) $(AM_CFLAGS) $(CFLAGS) $(INC_DIR) $(CXXFLAGS) +progs = ufs-utils +ifdef C + check = sparse $(CHECKFLAGS) +endif + +.c.o: +ifdef C + $(check) $< +endif + $(CC) $(CPPFLAGS) $(CFLAGS) $(DEPFLAGS) -c $< -o $@ + +ufs-utils:$(objects) + $(CC) $(CFLAGS) -o $@ $(objects) $(LDFLAGS) $(LIBS) + +help: + @echo "\033[31m==============Build Instructions==============\033[0m" + @echo "\033[92mTo build ufs_utils follow the following steps\033[0m" + @echo "\033[92m1 Set CROSS_COMPILE variable\033[0m" + @echo "\033[92m2 Build the tool using \"make\"\033[0m" + @echo "\033[92m3 Clean the tool using \"make clean\"\033[0m" + +clean: + @rm -f $(progs) $(objects) .*.o.d +.PHONY: all clean diff --git a/libmtk_bsg/README.md b/libmtk_bsg/README.md new file mode 100644 index 0000000000000000000000000000000000000000..58eb6e11486a9bc89a73d5c0b667c4c48c647eeb --- /dev/null +++ b/libmtk_bsg/README.md @@ -0,0 +1,87 @@ +# UFS Tool ver 1.9 # + +## Description: ## +a) Read/Write device flags, attributes & descriptors by +using the BSG infrastructure in linux kernel (applied to 5.1 rc1) +Due to the issues in UFS BSG driver, the following patch have to be +applied: + https://lore.kernel.org/patchwork/patch/1076796/ + https://patchwork.kernel.org/patch/11011891/ +b) Get/Set UNIPRO attributes +c) HMR - Host Manual Refresh functionality +The following options may work with the SCSI BSG device +using sg v4 structure (e.g. /dev/0:0:0:0) +or via a SCSI Generic interface using sg v3 struct (e.g. /dev/block/sda) +d) Error History +e) FFU - Field Firmware Update +f) Send Vendor commands based on SCSI WRITE/READ Buffer commands +g) RPMB functionality + +The tool is aligned to the UFS 3.1 spec. + +## Build: ## +### Set CROSS\_COMPILE variable(e.g.): ### +export CROSS\_COMPILE=/XXX/aarch64-linux-gnu- + +### Build: ### +"make" + +### Clean: ### + "make clean" + +## Usage ## +Copy the tool into a directory on the device (e.g. +/data/local/tmp). +Run the tool without arguments or with -h/--help + options in order to list the supported features: +E.g. Run: +./ufs-utils --help +Output: + ufs-utils help|--help|-h Show the help. + + ufs-utils -v + Show the version. + + ufs-utils --help|-h + Show detailed help for a command + + Run the tool's help for the ufs configuration features in order to + get full information related to the feature, all options and the + examples. E.g.: getting help for ufs flags Run: ./ufs-utils fl --help + Output: Flags command usage: + + ufs-utils fl [-t] [-a|-r|-o|-e] [-p]   + + -t Flags type idn + Available flags and its access, based on UFS ver 3.0 : + 0 : Reserved + 1 : fDeviceInit | Read | SetOnly + 2 : fPermanentWPEn | Read | WriteOnce + 3 : fPowerOnWPEn | Read | ResetOnPower + 4 : fBackgroundOpsEn | Read | Volatile + 5 : fDeviceLifeSpanModeEn | Read | Volatile + 6 : fPurgeEnable | WriteOnly | Volatile + 7 : fRefreshEnable | WriteOnly | Volatile + 8 : fPhyResourceRemoval | Read | Persistent + 9 : fBusyRTC | ReadOnly + 10 : Reserved + 11 : fPermanentlyDisableFw | Read | WriteOnce + + -a read and print all readable flags for the device + + -r read operation (default), for readable flag(s) + + -e set flag operation + + -c clear/reset flag operation + + -o toggle flag operation + + -p path to ufs bsg device + + Example - Read the bkops operation flag + ufs-utils fl -t 4 -p /dev/ufs-bsg + +## Authors ## +signed-off-by:Arthur Simchaev (arthur.simchaev@wdc.com) +signed-off-by:Avri Altman (avri.altman@wdc.com) diff --git a/libmtk_bsg/hmac_sha2.c b/libmtk_bsg/hmac_sha2.c new file mode 100644 index 0000000000000000000000000000000000000000..1130ebf80d73be25d356d8ba3daf517ed1b603a4 --- /dev/null +++ b/libmtk_bsg/hmac_sha2.c @@ -0,0 +1,544 @@ +/* + * HMAC-SHA-224/256/384/512 implementation + * Last update: 06/15/2005 + * Issue date: 06/15/2005 + * + * Copyright (C) 2005 Olivier Gay + * 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 + +#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 +#include + +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 */ + diff --git a/libmtk_bsg/hmac_sha2.h b/libmtk_bsg/hmac_sha2.h new file mode 100644 index 0000000000000000000000000000000000000000..64b020267b57c592220429e9ae857c03e6b38879 --- /dev/null +++ b/libmtk_bsg/hmac_sha2.h @@ -0,0 +1,140 @@ +/* + * HMAC-SHA-224/256/384/512 implementation + * Last update: 06/15/2005 + * Issue date: 06/15/2005 + * + * Copyright (C) 2005 Olivier Gay + * 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 */ + diff --git a/libmtk_bsg/ioctl.h b/libmtk_bsg/ioctl.h new file mode 100644 index 0000000000000000000000000000000000000000..45f21978ababde3eeddd8bb943ff0ef4676454f3 --- /dev/null +++ b/libmtk_bsg/ioctl.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef UAPI_SCSI_IOCTL_H_ +#define UAPI_SCSI_IOCTL_H_ + +#ifndef SG_IO +/* synchronous SCSI command ioctl, (only in version 3 interface) */ +#define SG_IO 0x2285 /* similar effect as write() followed by read() */ +#endif + +#ifndef _UAPIBSG_H +#include + +#define DEF_TIMEOUT_MSEC (60000) +#define BSG_PROTOCOL_SCSI 0 + +#define BSG_SUB_PROTOCOL_SCSI_CMD 0 +#define BSG_SUB_PROTOCOL_SCSI_TMF 1 +#define BSG_SUB_PROTOCOL_SCSI_TRANSPORT 2 + +/* + * For flag constants below: + * sg.h sg_io_hdr also has bits defined for it's flags member. These + * two flag values (0x10 and 0x20) have the same meaning in sg.h . For + * bsg the BSG_FLAG_Q_AT_HEAD flag is ignored since it is the deafult. + */ +#define BSG_FLAG_Q_AT_TAIL 0x10 /* default is Q_AT_HEAD */ +#define BSG_FLAG_Q_AT_HEAD 0x20 + +struct sg_io_v4 { + __s32 guard; /* [i] 'Q' to differentiate from v3 */ + __u32 protocol; /* [i] 0 -> SCSI , .... */ + __u32 subprotocol; /* [i] 0 -> SCSI command, 1 -> SCSI task + management function, .... */ + + __u32 request_len; /* [i] in bytes */ + __u64 request; /* [i], [*i] {SCSI: cdb} */ + __u64 request_tag; /* [i] {SCSI: task tag (only if flagged)} */ + __u32 request_attr; /* [i] {SCSI: task attribute} */ + __u32 request_priority; /* [i] {SCSI: task priority} */ + __u32 request_extra; /* [i] {spare, for padding} */ + __u32 max_response_len; /* [i] in bytes */ + __u64 response; /* [i], [*o] {SCSI: (auto)sense data} */ + + /* "dout_": data out (to device); "din_": data in (from device) */ + __u32 dout_iovec_count; /* [i] 0 -> "flat" dout transfer else + dout_xfer points to array of iovec */ + __u32 dout_xfer_len; /* [i] bytes to be transferred to device */ + __u32 din_iovec_count; /* [i] 0 -> "flat" din transfer */ + __u32 din_xfer_len; /* [i] bytes to be transferred from device */ + __u64 dout_xferp; /* [i], [*i] */ + __u64 din_xferp; /* [i], [*o] */ + + __u32 timeout; /* [i] units: millisecond */ + __u32 flags; /* [i] bit mask */ + __u64 usr_ptr; /* [i->o] unused internally */ + __u32 spare_in; /* [i] */ + + __u32 driver_status; /* [o] 0 -> ok */ + __u32 transport_status; /* [o] 0 -> ok */ + __u32 device_status; /* [o] {SCSI: command completion status} */ + __u32 retry_delay; /* [o] {SCSI: status auxiliary information} */ + __u32 info; /* [o] additional information */ + __u32 duration; /* [o] time to complete, in milliseconds */ + __u32 response_len; /* [o] bytes of response actually written */ + __s32 din_resid; /* [o] din_xfer_len - actual_din_xfer_len */ + __s32 dout_resid; /* [o] dout_xfer_len - actual_dout_xfer_len */ + __u64 generated_tag; /* [o] {SCSI: transport generated task tag} */ + __u32 spare_out; /* [o] */ + + __u32 padding; +}; + +/* + * SCSI Generic v3 struct copied from include/scsi/sg.h + */ +typedef struct sg_io_hdr { + int interface_id; /* [i] 'S' for SCSI generic (required) */ + int dxfer_direction; /* [i] data transfer direction */ + unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ + unsigned char mx_sb_len; /* [i] max length to write to sbp */ + unsigned short int iovec_count; /* [i] 0 implies no scatter gather */ + unsigned int dxfer_len; /* [i] byte count of data transfer */ + void *dxferp; /* [i], [*io] points to data transfer memory + or scatter gather list */ + unsigned char *cmdp; /* [i], [*i] points to command to perform */ + unsigned char *sbp; /* [i], [*o] points to sense_buffer memory */ + unsigned int timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */ + unsigned int flags; /* [i] 0 -> default, see SG_FLAG... */ + int pack_id; /* [i->o] unused internally (normally) */ + void *usr_ptr; /* [i->o] unused internally */ + unsigned char status; /* [o] scsi status */ + unsigned char masked_status;/* [o] shifted, masked scsi status */ + unsigned char msg_status; /* [o] messaging level data (optional) */ + unsigned char sb_len_wr; /* [o] byte count actually written to sbp */ + unsigned short int host_status; /* [o] errors from host adapter */ + unsigned short int driver_status;/* [o] errors from software driver */ + int resid; /* [o] dxfer_len - actual_transferred */ + unsigned int duration; /* [o] time taken by cmd (unit: millisec) */ + unsigned int info; /* [o] auxiliary information */ +} sg_io_hdr_t; + +#endif /* _UAPIBSG_H */ +#endif /* UAPI_SCSI_IOCTL_H_ */ diff --git a/libmtk_bsg/mtk_ioctl.c b/libmtk_bsg/mtk_ioctl.c new file mode 100644 index 0000000000000000000000000000000000000000..dea729be6ea4e8ce28521c105a44973333daa94f --- /dev/null +++ b/libmtk_bsg/mtk_ioctl.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* Wrapping the ioctrl of linux kernel*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ufs_cmds.h" +#include "options.h" +#include "ufs.h" + + + +static void initialized_options(struct tool_options *options) +{ + memset(options, INVALID, sizeof(*options)); + options->path[0] = '\0'; + options->keypath[0] = '\0'; + options->data = NULL; + options->sg_type = SG4_TYPE; +} + + +/** + * @brief write attribute to bsg device + * + * @param path device path e.g /dev/block/sdc + * @param idn idn of attribute + * @param index index of attribute + * @param selector selector of attribute + * @param value the value to write to attribute. If the descriptor accepts only size less than DWORD, + * other bytes are ignored. + * @return int return OK on success write. + */ +int ioctrl_w_attr(const char path[], uint8_t idn, uint8_t index, uint8_t selector, uint32_t value){ + + struct tool_options options; + initialized_options(&options); + + options.config_type_inx = ATTR_TYPE; + options.opr = WRITE; // write + + // TODO: check reseult + // alloc buffer + options.data = (uint32_t *)calloc(1, sizeof(uint32_t)); + + // verify_write(&options); + + options.idn = idn; + options.index = index; + options.selector = selector; + strcpy(options.path, path);// TODO: check copy error + *((uint32_t *)options.data) = value; + + verify_arg_and_set_default(&options); + + if (do_attributes(&options)){ + print_error("attribute write failed"); + return ERROR; + } + + return OK; +} + + diff --git a/libmtk_bsg/options.c b/libmtk_bsg/options.c new file mode 100644 index 0000000000000000000000000000000000000000..a619cb38ad85c2ca76181d24403959a66dddd2ab --- /dev/null +++ b/libmtk_bsg/options.c @@ -0,0 +1,842 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +#include "options.h" +#include "ufs.h" +#include "unipro.h" +#include "ufs_ffu.h" +#include "ufs_rpmb.h" +#include "ufs_hmr.h" + +static int verify_and_set_idn(struct tool_options *options); +static int verify_read(struct tool_options *options); +static int verify_write(struct tool_options *options); +static int verify_and_set_flag_operation(int opr_type, + struct tool_options *options); +static int verify_and_set_device_path(struct tool_options *options); +static int verify_and_set_index(struct tool_options *options); +static int verify_and_set_selector(struct tool_options *options); +static int verify_target(struct tool_options *options, int target); +static int verify_and_set_ffu_chunk_size(struct tool_options *options); +static int verify_length(struct tool_options *options); +static int verify_offset(struct tool_options *options); +static int verify_and_set_start_addr(struct tool_options *options); +static int verify_and_set_num_block(struct tool_options *options); +static int verify_lun(struct tool_options *options); +static int verify_and_set_key_path(struct tool_options *options); +static int verify_region(struct tool_options *options); +static int verify_and_set_hmr_method(struct tool_options *options); +static int verify_and_set_hmr_unit(struct tool_options *options); +static int verify_sg_struct(struct tool_options *options); + +#define MAX_ADDRESS 0xFFFF + + +int init_options(int opt_cnt, char *opt_arr[], struct tool_options *options) +{ + int rc = -EINVAL; + int curr_opt = 0; + int opt = 0; + + static struct option long_opts[] = { + {"peer", no_argument, NULL, 'u'}, /* UFS device */ + {"local", no_argument, NULL, 'l'}, /* UFS host*/ + {NULL, 0, NULL, 0} + }; + static char *short_opts = "t:p:w:i:s:O:L:n:k:m:d:x:y:g:rocea"; + + while (-1 != + (curr_opt = getopt_long(opt_cnt, opt_arr, short_opts, + long_opts, &opt))) { + switch (curr_opt) { + case 'a': + rc = verify_read(options); + if (!rc) + options->opr = READ_ALL; + break; + case 't': + rc = verify_and_set_idn(options); + break; + case 'r': + rc = verify_read(options); + if (!rc) + options->opr = READ; + break; + case 'w': + rc = verify_write(options); + if (!rc) + options->opr = WRITE; + break; + case 'c': + rc = verify_and_set_flag_operation(CLEAR_FLAG, + options); + break; + case 'e': + rc = verify_and_set_flag_operation(SET_FLAG, options); + break; + case 'o': + rc = verify_and_set_flag_operation(TOGGLE_FLAG, + options); + break; + case 'p': + rc = verify_and_set_device_path(options); + break; + case 'i': + rc = verify_and_set_index(options); + break; + case 's': + if (options->config_type_inx == FFU_TYPE) + rc = verify_and_set_ffu_chunk_size(options); + else if (options->config_type_inx == RPMB_CMD_TYPE) + rc = verify_and_set_start_addr(options); + else + rc = verify_and_set_selector(options); + break; + case 'u': + rc = verify_target(options, DME_PEER); + break; + case 'l': + rc = verify_target(options, DME_LOCAL); + break; + case 'd': + rc = verify_lun(options); + break; + case 'L': + rc = verify_length(options); + break; + case 'O': + rc = verify_offset(options); + break; + case 'n': + rc = verify_and_set_num_block(options); + break; + case 'k': + rc = verify_and_set_key_path(options); + break; + case 'm': + rc = verify_region(options); + break; + case 'x': + rc = verify_and_set_hmr_method(options); + break; + case 'y': + rc = verify_and_set_hmr_unit(options); + break; + case 'g': + rc = verify_sg_struct(options); + break; + default: + rc = -EINVAL; + break; + } + if (rc) + break; + } + + if (!rc) + rc = verify_arg_and_set_default(options); + + return rc; +} + +static int verify_target(struct tool_options *options, int target) +{ + if (options->target != INVALID) { + print_error("duplicated operate target."); + goto out; + } + + options->target = target; + return OK; + +out: + return ERROR; +} + +static int verify_and_set_index(struct tool_options *options) +{ + int index = INVALID; + + if (options->index != INVALID) { + print_error("duplicated index"); + goto out; + } + + /* In case atoi returned 0 . Check that is real 0 and not error + * arguments . Also check that the value is in correct range + */ + if (strstr(optarg, "0x") || strstr(optarg, "0X")) + index = (int)strtol(optarg, NULL, 0); + else + index = atoi(optarg); + + if ((index == 0 && strcmp(optarg, "0")) || index < 0) { + print_error("Invalid argument for index"); + goto out; + } + + options->index = index; + return OK; + +out: + return ERROR; +} + +static int verify_and_set_ffu_chunk_size(struct tool_options *options) +{ + int chunk_size_kb = atoi(optarg); + + if (!chunk_size_kb) { + print_error("Invalid chunk_size %d ", chunk_size_kb); + goto out; + } + options->size = chunk_size_kb * 1024; + if ((options->size > MAX_IOCTL_BUF_SIZE) || + (options->size % ALIGNMENT_CHUNK_SIZE)) { + print_error("The chunk should be multiple value of 4k, between 4k and %dk", + MAX_IOCTL_BUF_SIZE / 1024); + goto out; + } + return OK; +out: + return ERROR; +} + +static int verify_and_set_selector(struct tool_options *options) +{ + int selector = INVALID; + + if (options->selector != INVALID) { + print_error("duplicated selector"); + goto out; + } + + /* In case atoi returned 0 . Check that is real 0 and not error + * arguments . Also check that the value is in correct range + */ + selector = atoi(optarg); + if ((selector == 0 && strcmp(optarg, "0")) || selector < 0) { + print_error("Invalid argument for selector"); + goto out; + } + + options->selector = selector; + return OK; + +out: + return ERROR; +} + +static int verify_and_set_idn(struct tool_options *options) +{ + int idn = INVALID; + + if (options->idn != INVALID) { + print_error("duplicated type option"); + goto out; + } + + /* In case atoi returned 0. Check that is real 0 and not error + * arguments. Also check that the value is in correct range + */ + idn = atoi(optarg); + if ((idn == 0 && strcmp(optarg, "0")) || idn < 0) { + print_error("Invalid argument for idn"); + goto out; + } + + switch (options->config_type_inx) { + case DESC_TYPE: + if (idn > QUERY_DESC_IDN_MAX) { + print_error("Invalid descriptor idn %d", idn); + goto out; + } + break; + case ATTR_TYPE: + if (idn >= QUERY_ATTR_IDN_MAX) { + print_error("Invalid attr idn %d", idn); + goto out; + } + break; + case FLAG_TYPE: + if (idn > QUERY_FLAG_IDN_MAX) { + print_error("Invalid flag idn %d", idn); + goto out; + } + break; + case UIC_TYPE: + if (idn >= MAX_UNIPRO_IDN) { + print_error("Invalid UIC idn %d", idn); + goto out; + } + break; + case FFU_TYPE: + if (idn >= UFS_FFU_MAX) { + print_error("Invalid ffu cmd %d", idn); + goto out; + } + break; + case RPMB_CMD_TYPE: + if (idn >= RPMB_CMD_MAX) { + print_error("Invalid rpmb cmd %d", idn); + goto out; + } + break; + default: + print_error("Invalid UFS configuration type %d", idn); + goto out; + } + + options->idn = idn; + return OK; + +out: + return ERROR; +} + +static int verify_length(struct tool_options *options) +{ + int len = INVALID; + + if (options->len != INVALID) { + print_error("duplicated length option"); + goto out; + } + + /* In case atoi returned 0. Check that is real 0 and not error + * arguments. Also check that the value is in correct range + */ + len = atoi(optarg); + if (len == 0 || len < 0 || len > BLOCK_SIZE) { + print_error("Invalid argument for length. The value should be between 1 to %dB", + BLOCK_SIZE); + goto out; + } + + options->len = len; + return OK; + +out: + return ERROR; +} + +static int verify_offset(struct tool_options *options) +{ + int offset = INVALID; + + if (options->offset != INVALID) { + print_error("duplicated offset option"); + goto out; + } + if (strstr(optarg, "0x") || strstr(optarg, "0X")) + offset = (int)strtol(optarg, NULL, 0); + else + offset = atoi(optarg); + if ((offset == 0 && strcmp(optarg, "0")) || offset < 0) { + print_error("Invalid argument for offset"); + goto out; + } + + options->offset = offset; + return OK; + +out: + return ERROR; +} + +static int verify_and_set_start_addr(struct tool_options *options) +{ + int start_block = 0; + + if (options->config_type_inx != RPMB_CMD_TYPE) { + print_error("start block address using only for rpmb cmd"); + goto out; + } + + start_block = atoi(optarg); + if ((start_block == 0 && strcmp(optarg, "0")) || + start_block < 0 || start_block > MAX_ADDRESS) { + print_error("Invalid start address"); + goto out; + } else + options->start_block = start_block; + return OK; + +out: + return ERROR; +} + +static int verify_and_set_num_block(struct tool_options *options) +{ + int num_block = 0; + + if (options->config_type_inx != RPMB_CMD_TYPE) { + print_error("num_block using only for rpmb cmd"); + goto out; + } + + num_block = atoi(optarg); + if ((num_block == 0 && strcmp(optarg, "0")) || num_block < 0) { + print_error("Invalid numbers of block"); + goto out; + } else + options->num_block = num_block; + return OK; + +out: + return ERROR; + +} + +static int verify_and_set_key_path(struct tool_options *options) +{ + if (options->config_type_inx != RPMB_CMD_TYPE) { + print_error("key path using only for rpmb cmd"); + goto out; + } + + if (options->keypath[0] != '\0') { + print_error("Duplicate Key path"); + goto out; + } + + if ((optarg == NULL) || (optarg[0] == 0)) { + print_error("Key path missed"); + goto out; + } + + if (strlen(optarg) >= PATH_MAX) { + print_error("Key path is too long"); + goto out; + } + + strcpy(options->keypath, optarg); + return OK; + +out: + return ERROR; +} + +static int verify_sg_struct(struct tool_options *options) +{ + int8_t sg_type; + + if ((0 == (sg_type = atoi(optarg)) && 0 != (strcmp(optarg, "0"))) || + ((sg_type != SG3_TYPE) && (sg_type != SG4_TYPE))) { + print_error("Invalid SG struct"); + return ERROR; + } else + options->sg_type = sg_type; + return OK; +} + +static int verify_lun(struct tool_options *options) +{ + int8_t lun = 0; + + lun = atoi(optarg); + if ((lun == 0 && strcmp(optarg, "0")) || lun < 0) { + print_error("Invalid lun"); + return ERROR; + } + options->lun = lun; + return OK; +} + +static int verify_region(struct tool_options *options) +{ + int8_t region = 0; + + region = atoi(optarg); + if ((region == 0 && strcmp(optarg, "0")) || region < 0 + || region > 3) { + print_error("Invalid RPMB region"); + return ERROR; + } + options->region = region; + return OK; +} + +static int verify_rpmb_arg(struct tool_options *options) +{ + int ret = OK; + + if (options->region == INVALID) + options->region = 0; + + switch (options->idn) { + case AUTHENTICATION_KEY: + if (options->keypath[0] == 0) { + print_error("Key path is missed"); + ret = ERROR; + } + break; + case READ_RPMB: + if (!options->data) { + print_error("Output data file missed"); + ret = ERROR; + } + break; + case READ_SEC_RPMB_CONF_BLOCK: + if (!options->data) { + print_error("Output data file missed"); + ret = ERROR; + } + if (options->lun == INVALID) { + print_error("LUN parameter is missed"); + ret = ERROR; + } + + if (options->region > 0) { + print_error("Config block exist only in region 0"); + ret = ERROR; + } + break; + case WRITE_RPMB: + if (!options->data) { + print_error("Input data file missed"); + ret = ERROR; + } + if (options->keypath[0] == 0) { + print_error("Key path is missed"); + ret = ERROR; + } + if (options->num_block == INVALID) + options->num_block = 1; + if (options->start_block == INVALID) + options->start_block = 0; + break; + case WRITE_SEC_RPMB_CONF_BLOCK: + if (!options->data) { + print_error("Input data file missed"); + ret = ERROR; + } + if (options->keypath[0] == 0) { + print_error("Key path is missed"); + ret = ERROR; + } + if (options->region > 0) { + print_error("Config block exist only in region 0"); + ret = ERROR; + } + break; + case READ_WRITE_COUNTER: + break; + default: + print_error("Unsupported RPMB cmd %d", + options->idn); + break; + } + return ret; +} + +static int verify_and_set_hmr_method(struct tool_options *options) +{ + int ret = ERROR; + long result; + + if (options->hmr_method != INVALID) { + print_error("Duplicated hmr method option"); + goto out; + } + + ret = str_to_long(optarg, 10, &result); + if (ret == ERROR) { + print_error("Invalid argument for hmr method: not convertable"); + goto out; + } + + if (result < HMR_METHOD_FORCE || result >= HMR_METHOD_MAX) { + print_error("Invalid argument for hmr method: out of range"); + ret = ERROR; + goto out; + } + + options->hmr_method = result; + +out: + return ret; +} + +static int verify_and_set_hmr_unit(struct tool_options *options) +{ + int ret = ERROR; + long result; + + if (options->hmr_unit != INVALID) { + print_error("Duplicated hmr unit option"); + goto out; + } + + ret = str_to_long(optarg, 10, &result); + if (ret == ERROR) { + print_error("Invalid argument for hmr unit: not convertable"); + goto out; + } + + if (result < HMR_UNIT_MIN || result >= HMR_UNIT_MAX) { + print_error("Invalid argument for hmr unit: out of range"); + ret = ERROR; + goto out; + } + + options->hmr_unit = result; + +out: + return ret; +} + + +// TODO: remove arg verification! +int verify_arg_and_set_default(struct tool_options *options) +{ + if (options->path[0] == '\0') { + print_error("Missing device path type"); + goto out; + } + + if (options->opr == INVALID) + options->opr = READ; + + if (options->opr == WRITE && !options->data) { + print_error("Data missed for the write operation"); + goto out; + } + if (options->config_type_inx != ERR_HIST_TYPE && + options->config_type_inx != VENDOR_BUFFER_TYPE && + options->config_type_inx != HMR_TYPE && + options->opr != READ_ALL && + options->idn == INVALID) { + print_error("The type idn is missed"); + goto out; + } + + if (options->config_type_inx == DESC_TYPE && + options->idn == QUERY_DESC_IDN_STRING && + options->index == INVALID) { + print_error("The index is missed"); + goto out; + } + + if (options->config_type_inx == UIC_TYPE) { + if (options->idn == INVALID) { + /* + * As for the Unipro attributes access, should always + * specify idn. + */ + print_error("idn of Unipro attributes is missed"); + goto out; + } + + if (options->opr == WRITE && options->target != DME_PEER && + options->target != DME_LOCAL) { + /* + * As for Unipro attributes write, should + * specify accessing target. + */ + print_error("accessing target is missed"); + goto out; + } + + if (options->index == INVALID && + (options->opr == READ || options->opr == WRITE)) { + print_error("ID of Unipro attributes is missed"); + goto out; + } + } + + if (options->index == INVALID) + options->index = 0; + + if (options->selector == INVALID) + options->selector = 0; + + if (options->config_type_inx == FFU_TYPE) { + if (options->size == INVALID) + options->size = MAX_IOCTL_BUF_SIZE; + if (options->idn == INVALID) + /*Default operation*/ + options->idn = UFS_FFU; + if ((options->idn != UFS_CHECK_FFU_STATUS) && + (options->data == NULL)) { + print_error("The FW file name is missing"); + goto out; + } + } + + if ((options->config_type_inx == VENDOR_BUFFER_TYPE) && + (options->len == INVALID)) + options->len = BLOCK_SIZE; + + if (options->config_type_inx == RPMB_CMD_TYPE) { + if (verify_rpmb_arg(options)) + goto out; + } + + if (options->config_type_inx == HMR_TYPE) { + if (options->hmr_method == INVALID) + options->hmr_method = HMR_METHOD_SELECTIVE; + + if (options->hmr_unit == INVALID) + options->hmr_unit = HMR_UNIT_MIN; + } + + return OK; + +out: + return ERROR; +} + +static int verify_and_set_device_path(struct tool_options *options) +{ + if (options->path[0] != '\0') { + print_error("Duplicate Device path %d", options->path[0]); + goto out; + } + + if (optarg[0] == 0) { + print_error("Device path missed"); + goto out; + } + + if (strlen(optarg) >= PATH_MAX) { + print_error("Device path is too long"); + goto out; + } + + // strcpy(options->path, optarg); + return OK; + +out: + return ERROR; +} + +static int verify_read(struct tool_options *options) +{ + if (options->opr != INVALID) { + print_error("duplicated operation option(read)"); + goto out; + } + + return OK; + +out: + return ERROR; +} + +static int verify_write(struct tool_options *options) +{ + errno = 0; + + if (options->opr != INVALID) { + print_error("duplicated operation option(write)"); + goto out; + } + + if (optarg[0] == 0) { + print_error("Data is missed"); + goto out; + } + + if (options->config_type_inx == DESC_TYPE) { + int arg_len = strlen(optarg); + int str_desc_max_len = QUERY_DESC_STRING_MAX_SIZE/2 - 2; + + if (options->idn != QUERY_DESC_IDN_CONFIGURAION && + options->idn != QUERY_DESC_IDN_STRING) { + print_error("write unavailable for descriptor = %d", + options->idn); + goto out; + } + + if (arg_len > str_desc_max_len) { + print_error("Input data is too big"); + goto out; + } + + options->data = (char *)malloc(QUERY_DESC_STRING_MAX_SIZE); + if (!options->data) { + print_error("Memory Allocation problem"); + goto out; + } + + strcpy(options->data, optarg); + } + + if (options->config_type_inx == FLAG_TYPE) { + print_error("Please use 'c', 'e', or 'o' for flag operations"); + goto out; + } + + if (options->config_type_inx == ATTR_TYPE || + options->config_type_inx == UIC_TYPE) { + options->data = (__u32 *)calloc(1, sizeof(__u32)); + if (!options->data) { + print_error("Memory Allocation problem"); + goto out; + } + + // *(__u32 *)options->data = strtol(optarg, &endptr, 16); + + if (errno != 0) { + print_error("Wrong data"); + goto out; + } + } + if (options->config_type_inx == FFU_TYPE || + options->config_type_inx == VENDOR_BUFFER_TYPE || + options->config_type_inx == RPMB_CMD_TYPE) { + int len = strlen(optarg) + 1; + + if (len >= PATH_MAX) { + print_error("Input file path is too long"); + goto out; + } + options->data = (char *)calloc(1, len); + if (options->data == NULL) { + print_error("Memory Allocation problem"); + goto out; + } else + strcpy(options->data, optarg); + } + + return OK; + +out: + return ERROR; +} + +static int +verify_and_set_flag_operation(int opr_type, struct tool_options *options) +{ + if (options->opr != INVALID) { + print_error("duplicated operation option"); + goto out; + } + + if (options->config_type_inx != FLAG_TYPE) { + print_error("-c | -o | -e operation only for the flag type"); + goto out; + } + + if (opr_type < CLEAR_FLAG || opr_type > TOGGLE_FLAG) { + print_error("Incorrect operation for the flag type"); + goto out; + } + + options->opr = opr_type; + return OK; + +out: + return ERROR; +} + diff --git a/libmtk_bsg/options.h b/libmtk_bsg/options.h new file mode 100644 index 0000000000000000000000000000000000000000..6b7c48b57571618134b12f178e62722f8fbee3f5 --- /dev/null +++ b/libmtk_bsg/options.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef OPTIONS_H_ +#define OPTIONS_H_ +#include + +#define OK 0 +#define ERROR -1 +#define INVALID -1 + +#ifndef _UAPI_LINUX_LIMITS_H +#define PATH_MAX 4096 +#endif + +#define READ 0 +#define WRITE 1 +#define CLEAR_FLAG 2 +#define SET_FLAG 3 +#define TOGGLE_FLAG 4 +#define READ_ALL 5 + + +#define ALIGNMENT_CHUNK_SIZE 4096 + +struct tool_options { + /* one of @ufs_cong_type */ + int config_type_inx; + /* opt: -t, type - one of @flag_idn / @attr_idn / @desc_idn + * or @unipro attribute idn + */ + int idn; + /* opt: -r/w/o/c/a, type of the operation read/write/toggle/clear */ + int opr; + int index; + int selector; + /* data for writing */ + void *data; + /* @DME_LOCAL or @DME_PEER */ + int target; + int size; + int offset; + int len; + /* HMR related */ + int hmr_method; + int hmr_unit; + /*start block address for rpmb cmd */ + int start_block; + int num_block; + int8_t lun; + /*RPMB region*/ + int8_t region; + int sg_type; + char keypath[PATH_MAX]; + char path[PATH_MAX]; + // int fd; +}; +int verify_arg_and_set_default(struct tool_options *options); +int init_options(int opt_cnt, char **opt_arr, struct tool_options *options); +#endif /* OPTIONS_H_ */ diff --git a/libmtk_bsg/scsi_bsg_util.c b/libmtk_bsg/scsi_bsg_util.c new file mode 100644 index 0000000000000000000000000000000000000000..4d6381befd9cd674a67e85f1f377dbc31f5d5375 --- /dev/null +++ b/libmtk_bsg/scsi_bsg_util.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#pragma GCC diagnostic ignored "-Wall" +#pragma GCC diagnostic ignored "-Wextra" +#pragma GCC diagnostic ignored "-Wsign-compare" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ioctl.h" +#include "ufs.h" +#include "scsi_bsg_util.h" +#include "ufs_rpmb.h" + +#define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\ + htobe32((byte3 << 24) | (byte2 << 16) |\ + (byte1 << 8) | (byte0)) +#define SEC_SPEC_OFFSET 2 +#define SEC_TRANS_LEN_OFFSET 6 +/* description of the sense key values */ +static const char *const snstext[] = { + "No Sense", /* 0: There is no sense information */ + "Recovered Error", /* 1: The last command completed successfully + but used error correction */ + "Not Ready", /* 2: The addressed target is not ready */ + "Medium Error", /* 3: Data error detected on the medium */ + "Hardware Error", /* 4: Controller or device failure */ + "Illegal Request", /* 5: Error in request */ + "Unit Attention", /* 6: Removable medium was changed, or + the target has been reset, or ... */ + "Data Protect", /* 7: Access to the data is blocked */ + "Blank Check", /* 8: Reached unexpected written or unwritten + region of the medium */ + "Vendor Specific", + "Copy Aborted", /* A: COPY or COMPARE was aborted */ + "Aborted Command", /* B: The target aborted the command */ + "Equal", /* C: A SEARCH DATA command found data equal */ + "Volume Overflow", /* D: Medium full with still data to be written */ + "Miscompare", /* E: Source data and data on the medium + do not agree */ +}; + +static int send_scsi_cmd(int fd, const __u8 *cdb, void *buf, + __u8 cmd_len, __u32 byte_cnt, int dir, __u8 sg_type); + +/* Get sense key string or NULL if not available */ +static const char *sense_key_string(__u8 key) +{ + if (key <= 0xE) + return snstext[key]; + + return NULL; +} + +static inline void put_unaligned_be24(__u32 val, void *p) +{ + ((__u8 *)p)[0] = (val >> 16) & 0xff; + ((__u8 *)p)[1] = (val >> 8) & 0xff; + ((__u8 *)p)[2] = val & 0xff; +} + +static int write_file_with_counter(const char *pattern, const void *buffer, + int length) +{ +#ifdef DEBUG + static int counter = 1; + char filename[1024] = {0}; + sprintf(filename, pattern, counter++); + return write_file(filename, buffer, length); +#else + return 0; +#endif +} + +int write_buffer(int fd, __u8 *buf, __u8 mode, __u8 buf_id, __u32 buf_offset, + int byte_count, __u8 sg_type) +{ + int ret; + unsigned char write_buf_cmd [WRITE_BUF_CMDLEN] = { + WRITE_BUFFER_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + if (fd < 0 || buf == NULL || byte_count <= 0) { + perror("scsi write cmd: wrong parameters"); + return -EINVAL; + } + + write_buf_cmd[1] = mode; + write_buf_cmd[2] = buf_id; + put_unaligned_be24((uint32_t)buf_offset, write_buf_cmd + 3); + put_unaligned_be24(byte_count, write_buf_cmd + 6); + WRITE_LOG("Start : %s mode %d , buf_id %d", __func__, mode, buf_id); + ret = send_scsi_cmd(fd, write_buf_cmd, buf, + WRITE_BUF_CMDLEN, byte_count, + SG_DXFER_TO_DEV, sg_type); + if (ret < 0) { + print_error("SG_IO WRITE BUFFER data error ret %d", ret); + } + return ret; +} + +int read_buffer(int fd, __u8 *buf, __u8 mode, __u8 buf_id, + __u32 buf_offset, int byte_count, __u8 sg_type) +{ + + int ret; + unsigned char read_buf_cmd[READ_BUF_CMDLEN] = {READ_BUFFER_CMD, + 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + if (fd < 0 || buf == NULL || byte_count <= 0) { + print_error("scsi read cmd: wrong parameters"); + return -EINVAL; + } + + read_buf_cmd[1] = mode; + read_buf_cmd[2] = buf_id; + put_unaligned_be24((__u32)buf_offset, read_buf_cmd + 3); + put_unaligned_be24((__u32)byte_count, read_buf_cmd + 6); + WRITE_LOG("Start : %s\n", __func__); + ret = send_scsi_cmd(fd, read_buf_cmd, buf, + READ_BUF_CMDLEN, byte_count, + SG_DXFER_FROM_DEV, sg_type); + + if (ret < 0) { + print_error("SG_IO READ BUFFER data error ret %d", ret); + } + + return ret; +} + +int scsi_security_in(int fd, struct rpmb_frame *frame, int cnt, __u8 region, + __u8 sg_type) +{ + int ret; + __u32 trans_len = cnt * sizeof(struct rpmb_frame); + __u16 sec_spec = (region << 8) | SEC_SPECIFIC_UFS_RPMB; + unsigned char sec_in_cmd[SEC_PROTOCOL_CMD_SIZE] = { + SECURITY_PROTOCOL_IN, SEC_PROTOCOL_UFS, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + WRITE_LOG("Start : %s\n", __func__); + if (fd < 0 || frame == NULL || cnt <= 0) { + print_error("scsi sec_in cmd: wrong parameters"); + return ERROR; + } + + *(__u16 *)(sec_in_cmd + SEC_SPEC_OFFSET) = htobe16(sec_spec); + *(__u32 *)(sec_in_cmd + SEC_TRANS_LEN_OFFSET) = htobe32(trans_len); + + ret = send_scsi_cmd(fd, sec_in_cmd, frame, SEC_PROTOCOL_CMD_SIZE, + trans_len, SG_DXFER_FROM_DEV, sg_type); + + return ret; +} + +int scsi_security_out(int fd, struct rpmb_frame *frame_in, + unsigned int cnt, __u8 region, __u8 sg_type) +{ + int ret; + __u32 trans_len = cnt * sizeof(struct rpmb_frame); + __u16 sec_spec = (region << 8) | SEC_SPECIFIC_UFS_RPMB; + unsigned char sec_out_cmd[SEC_PROTOCOL_CMD_SIZE] = { + SECURITY_PROTOCOL_OUT, SEC_PROTOCOL_UFS, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + if (fd < 0 || frame_in == NULL || cnt <= 0) { + print_error("scsi sec_out cmd: wrong parameters"); + return ERROR; + } + *(__u16 *)(sec_out_cmd + SEC_SPEC_OFFSET) = htobe16(sec_spec); + *(__u32 *)(sec_out_cmd + SEC_TRANS_LEN_OFFSET) = htobe32(trans_len); + ret = send_scsi_cmd(fd, sec_out_cmd, frame_in, + SEC_PROTOCOL_CMD_SIZE, trans_len, + SG_DXFER_TO_DEV, sg_type); + + return ret; +} + +void prepare_upiu(struct ufs_bsg_request *bsg_req, + __u8 query_req_func, __u16 data_len, + __u8 opcode, __u8 idn, __u8 index, __u8 sel) +{ + bsg_req->msgcode = UPIU_TRANSACTION_QUERY_REQ; + + /* Fill UPIU header */ + bsg_req->upiu_req.header.dword_0 = + UPIU_HEADER_DWORD(UPIU_TRANSACTION_QUERY_REQ, 0, 0, 0); + bsg_req->upiu_req.header.dword_1 = + UPIU_HEADER_DWORD(0, query_req_func, 0, 0); + bsg_req->upiu_req.header.dword_2 = + UPIU_HEADER_DWORD(0, 0, data_len >> 8, (__u8)data_len); + + /* Fill Transaction Specific Fields */ + bsg_req->upiu_req.qr.opcode = opcode; + bsg_req->upiu_req.qr.idn = idn; + bsg_req->upiu_req.qr.index = index; + bsg_req->upiu_req.qr.selector = sel; + bsg_req->upiu_req.qr.length = htobe16(data_len); +} + +/** + * send_scsi_cmd - Utility function for SCSI command sending + * @fd: bsg driver file descriptor + * @cdb: pointer to SCSI cmd cdb buffer + * @buf: pointer to the SCSI cmd data buffer + * @cmd_len: SCSI command length + * @byte_cnt: SCSI data length + * @dir: The cmd direction + * + **/ +static int send_scsi_cmd(int fd, const __u8 *cdb, void *buf, __u8 cmd_len, + __u32 byte_cnt, int dir, __u8 sg_type) +{ + int ret; + void *sg_struct; + struct sg_io_v4 io_hdr_v4 = { 0 }; + struct sg_io_hdr io_hdr_v3 = { 0 }; + __u8 sense_buffer[SENSE_BUFF_LEN] = { 0 }; + + if ((byte_cnt && buf == NULL) || cdb == NULL) { + print_error("send_scsi_cmd: wrong parameters"); + return -EINVAL; + } + + if (sg_type == SG4_TYPE) { + io_hdr_v4.guard = 'Q'; + io_hdr_v4.protocol = BSG_PROTOCOL_SCSI; + io_hdr_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; + io_hdr_v4.response = (__u64)sense_buffer; + io_hdr_v4.max_response_len = SENSE_BUFF_LEN; + io_hdr_v4.request_len = cmd_len; + if (dir == SG_DXFER_FROM_DEV) { + io_hdr_v4.din_xfer_len = (__u32)byte_cnt; + io_hdr_v4.din_xferp = (__u64)buf; + } else { + io_hdr_v4.dout_xfer_len = (__u32)byte_cnt; + io_hdr_v4.dout_xferp = (__u64)buf; + } + io_hdr_v4.request = (__u64)cdb; + sg_struct = &io_hdr_v4; + } + else { + io_hdr_v3.interface_id = 'S'; + io_hdr_v3.cmd_len = cmd_len; + io_hdr_v3.mx_sb_len = SENSE_BUFF_LEN; + io_hdr_v3.dxfer_direction = dir; + io_hdr_v3.dxfer_len = byte_cnt; + io_hdr_v3.dxferp = buf; + /* pointer to command buf (rbufCmdBlk) */ + io_hdr_v3.cmdp = (unsigned char *)cdb; + io_hdr_v3.sbp = sense_buffer; + io_hdr_v3.timeout = DEF_TIMEOUT_MSEC; + sg_struct = &io_hdr_v3; + } + WRITE_LOG("Start : %s cmd = %x len %d sg_type %d\n", __func__, cdb[0], + byte_cnt, sg_type); + + write_file_with_counter("scsi_cmd_cdb_%d.bin", + cdb, cmd_len); + + while (((ret = ioctl(fd, SG_IO, sg_struct)) < 0) && + ((errno == EINTR) || (errno == EAGAIN))); + if (sg_type == SG4_TYPE) { + if (io_hdr_v4.info != 0) { + print_error("Command fail with status %x , senseKey %s, asc 0x%02x, ascq 0x%02x", + io_hdr_v4.info, + sense_key_string(sense_buffer[2]), + sense_buffer[12], + sense_buffer[13]); + ret = -EINVAL; + } + } + else { + if (io_hdr_v3.status) { + print_error("Command fail with status %x , senseKey %s, asc 0x%02x, ascq 0x%02x", + io_hdr_v3.status, + sense_key_string(sense_buffer[2]), + sense_buffer[12], + sense_buffer[13]); + ret = -EINVAL; + } + + } + + return ret; +} + +/** + * send_bsg_scsi_trs - Utility function for SCSI transport cmd sending + * @fd: ufs bsg driver file descriptor + * @request_buff: pointer to the Query Request + * @reply_buff: pointer to the Query Response + * @req_buf_len: Query Request data length + * @reply_buf_len: Query Response data length + * @data_buf: pointer to the data buffer + * + * The function using ufs bsg infrastructure in linux kernel (/dev/ufs-bsg) + * in order to send Query request command + **/ +int send_bsg_scsi_trs(int fd, struct ufs_bsg_request *request_buff, + struct ufs_bsg_reply *reply_buff, __u32 req_buf_len, + __u32 reply_buf_len, __u8 *data_buf) +{ + int ret; + struct sg_io_v4 io_hdr_v4 = { 0 }; + + if (request_buff == NULL || reply_buff == NULL) { + print_error("%s: wrong parameters", __func__); + return -EINVAL; + } + + if (req_buf_len != 0 || reply_buf_len != 0) { + if (data_buf == NULL) { + print_error("%s: data_buf is NULL", __func__); + return -EINVAL; + } + } + + io_hdr_v4.guard = 'Q'; + io_hdr_v4.protocol = BSG_PROTOCOL_SCSI; + io_hdr_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_TRANSPORT; + io_hdr_v4.response = (__u64)reply_buff; + io_hdr_v4.max_response_len = BSG_REPLY_SZ; + io_hdr_v4.request_len = BSG_REQUEST_SZ; + io_hdr_v4.request = (__u64)request_buff; + + if (req_buf_len > 0) { + /* write descriptor */ + io_hdr_v4.dout_xferp = (__u64)(data_buf); + io_hdr_v4.dout_xfer_len = req_buf_len; + } else if (reply_buf_len > 0) { + /* read descriptor */ + io_hdr_v4.din_xferp = (__u64)(data_buf); + io_hdr_v4.din_xfer_len = reply_buf_len; + } + + WRITE_LOG("%s cmd = %x req_len %d , res_len %d\n", __func__, + request_buff->upiu_req.qr.idn, req_buf_len, + reply_buf_len); + + write_file_with_counter("bsg_reg_%d.bin", + &request_buff->upiu_req, + sizeof(struct utp_upiu_req)); + + + while (((ret = ioctl(fd, SG_IO, &io_hdr_v4)) < 0) && + ((errno == EINTR) || (errno == EAGAIN))) + ; + + if (io_hdr_v4.info != 0) { + print_error("Command fail with status %x ", + io_hdr_v4.info); + + ret = -EINVAL; + } + + write_file_with_counter("bsg_rsp_%d.bin", reply_buff, + BSG_REPLY_SZ); + + WRITE_LOG("%s res_len %d\n", __func__, + reply_buff->reply_payload_rcv_len); + return ret; +} diff --git a/libmtk_bsg/scsi_bsg_util.h b/libmtk_bsg/scsi_bsg_util.h new file mode 100644 index 0000000000000000000000000000000000000000..fb48a33db026c0802cf752f4aa82b3927be7a3de --- /dev/null +++ b/libmtk_bsg/scsi_bsg_util.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef BSG_UTIL_H_ +#define BSG_UTIL_H_ + +/* In case include/uapi/scsi/scsi_bsg_ufs.h is not included*/ +#ifndef SCSI_BSG_UFS_H +/* + * This file intended to be included by both kernel and user space + */ + +#define UFS_CDB_SIZE 16 + +#define BUFFER_VENDOR_MODE 0x01 +#define BUFFER_DATA_MODE 0x02 +#define BUFFER_FFU_MODE 0x0E +#define BUFFER_EHS_MODE 0x1C + +#define SG_DXFER_NONE -1 /* e.g. a SCSI Test Unit Ready command */ +#define SG_DXFER_TO_DEV -2 /* e.g. a SCSI WRITE command */ +#define SG_DXFER_FROM_DEV -3 /* e.g. a SCSI READ command */ + +#define SENSE_BUFF_LEN (18) +#define WRITE_BUF_CMDLEN 10 +#define READ_BUF_CMDLEN 10 +#define SEC_PROTOCOL_TIMEOUT_MSEC (1000) +#define SEC_PROTOCOL_CMD_SIZE (12) +#define SEC_PROTOCOL_UFS (0xEC) +#define SEC_SPECIFIC_UFS_RPMB (0x0001) +#define WRITE_BUFFER_CMD 0x3B +#define READ_BUFFER_CMD 0x3c +#define SECURITY_PROTOCOL_IN 0xa2 +#define SECURITY_PROTOCOL_OUT 0xb5 + +/** + * struct utp_upiu_header - UPIU header structure + * @dword_0: UPIU header DW-0 + * @dword_1: UPIU header DW-1 + * @dword_2: UPIU header DW-2 + */ +struct utp_upiu_header { + __be32 dword_0; + __be32 dword_1; + __be32 dword_2; +}; + +/** + * struct utp_upiu_query - upiu request buffer structure for + * query request. + * @opcode: command to perform B-0 + * @idn: a value that indicates the particular type of data B-1 + * @index: Index to further identify data B-2 + * @selector: Index to further identify data B-3 + * @reserved_osf: spec reserved field B-4,5 + * @length: number of descriptor bytes to read/write B-6,7 + * @value: Attribute value to be written DW-5 + * @reserved: spec reserved DW-6,7 + */ +struct utp_upiu_query { + __u8 opcode; + __u8 idn; + __u8 index; + __u8 selector; + __be16 reserved_osf; + __be16 length; + __be32 value; + __be32 reserved[2]; +}; + +/** + * struct utp_upiu_cmd - Command UPIU structure + * @data_transfer_len: Data Transfer Length DW-3 + * @cdb: Command Descriptor Block CDB DW-4 to DW-7 + */ +struct utp_upiu_cmd { + __be32 exp_data_transfer_len; + __u8 cdb[UFS_CDB_SIZE]; +}; + +/** + * struct utp_upiu_req - general upiu request structure + * @header:UPIU header structure DW-0 to DW-2 + * @sc: fields structure for scsi command DW-3 to DW-7 + * @qr: fields structure for query request DW-3 to DW-7 + */ +struct utp_upiu_req { + struct utp_upiu_header header; + union { + struct utp_upiu_cmd sc; + struct utp_upiu_query qr; + struct utp_upiu_query tr; + /* use utp_upiu_query to host the 4 dwords of uic command */ + struct utp_upiu_query uc; + }; +}; + +/* request (CDB) structure of the sg_io_v4 */ +struct ufs_bsg_request { + __u32 msgcode; + struct utp_upiu_req upiu_req; +}; + +/* response (request sense data) structure of the sg_io_v4 */ +struct ufs_bsg_reply { + /* + * The completion result. Result exists in two forms: + * if negative, it is an -Exxx system errno value. There will + * be no further reply information supplied. + * else, it's the 4-byte scsi error result, with driver, host, + * msg and status fields. The per-msgcode reply structure + * will contain valid data. + */ + __u32 result; + + /* If there was reply_payload, how much was received? */ + __u32 reply_payload_rcv_len; + + struct utp_upiu_req upiu_rsp; +}; +#endif /* SCSI_BSG_UFS_H.*/ + +struct rpmb_frame { + __u8 stuff[196]; + __u8 key_mac[32]; + __u8 data[256]; + __u8 nonce[16]; + __u32 write_counter; + __u16 addr; + __u16 block_count; + __u16 result; + __u16 req_resp; +}; + +#define BSG_REPLY_SZ (sizeof(struct ufs_bsg_reply)) +#define BSG_REQUEST_SZ (sizeof(struct ufs_bsg_request)) + +int send_bsg_scsi_trs(int fd, struct ufs_bsg_request *request_buff, + struct ufs_bsg_reply *reply_buff, __u32 request_len, + __u32 reply_len, __u8 *data_buf); +void prepare_upiu(struct ufs_bsg_request *bsg_req, __u8 query_req_func, + __u16 data_len, __u8 opcode, __u8 idn, __u8 index, __u8 sel); +int read_buffer(int fd, __u8 *buf, uint8_t mode, __u8 buf_id, + __u32 buf_offset, int byte_count, __u8 sg_type); +int write_buffer(int fd, __u8 *buf, __u8 mode, __u8 buf_id, __u32 buf_offset, + int byte_count, __u8 sg_type); +int scsi_security_out(int fd, struct rpmb_frame *frame_in, + unsigned int cnt, __u8 region, __u8 sg_type); +int scsi_security_in(int fd, struct rpmb_frame *frame, int cnt, + __u8 region, __u8 sg_type); +#endif /* BSG_UTIL_H_ */ + diff --git a/libmtk_bsg/sha2.c b/libmtk_bsg/sha2.c new file mode 100644 index 0000000000000000000000000000000000000000..0fe4c375c932d12afa972fc8141bda02aac1bb74 --- /dev/null +++ b/libmtk_bsg/sha2.c @@ -0,0 +1,949 @@ +/* + * FIPS 180-2 SHA-224/256/384/512 implementation + * Last update: 02/02/2007 + * Issue date: 04/30/2005 + * + * Copyright (C) 2005, 2007 Olivier Gay + * 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 + +#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 +#include + +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 */ + diff --git a/libmtk_bsg/sha2.h b/libmtk_bsg/sha2.h new file mode 100644 index 0000000000000000000000000000000000000000..4ac552446c343af5e1b14e33b8746ea219bac484 --- /dev/null +++ b/libmtk_bsg/sha2.h @@ -0,0 +1,108 @@ +/* + * HMAC-SHA-224/256/384/512 implementation + * Last update: 06/15/2005 + * Issue date: 06/15/2005 + * + * Copyright (C) 2005 Olivier Gay + * 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 */ + diff --git a/libmtk_bsg/ufs.c b/libmtk_bsg/ufs.c new file mode 100644 index 0000000000000000000000000000000000000000..6ed37e48a1812959c86edf6a6fb0bb0b226c5103 --- /dev/null +++ b/libmtk_bsg/ufs.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#pragma GCC diagnostic ignored "-Wall" +#pragma GCC diagnostic ignored "-Wextra" +#pragma GCC diagnostic ignored "-Wsign-compare" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ufs_cmds.h" +#include "options.h" +#include "ufs.h" +#include "ufs_err_hist.h" +#include "unipro.h" +#include "ufs_ffu.h" +#include "ufs_vendor.h" +#include "ufs_rpmb.h" +#include "ufs_hmr.h" + +#define UFS_BSG_UTIL_VERSION "1.9" +typedef int (*command_function)(struct tool_options *opt); + +struct tool_command { + command_function func; /* function which implements the command */ + char *conf_type; /* one of: descriptor/attributes/flags */ + int conf_type_ind; /* confiruration type index */ +}; + +static struct tool_command commands[] = { + /* + * avoid short commands different for the case only + */ + { do_desc, "desc", DESC_TYPE}, + { do_attributes, "attr", ATTR_TYPE}, + { do_flags, "fl", FLAG_TYPE}, + { do_err_hist, "err_hist", ERR_HIST_TYPE}, + { do_uic, "uic", UIC_TYPE}, + { do_ffu, "ffu", FFU_TYPE}, + { do_vendor, "vendor", VENDOR_BUFFER_TYPE}, + { do_rpmb, "rpmb", RPMB_CMD_TYPE}, + { do_hmr, "hmr", HMR_TYPE}, + { 0, 0, 0} +}; + +static char *get_prgname(char *programname) +{ + char *np; + + np = strrchr(programname, '/'); + if (!np) + np = programname; + else + np++; + + return np; +} + +static void help(char *np) +{ + char help_str[256] = {0}; + + strcat(help_str, ""); + printf("\n Usage:\n"); + printf("\n\t%s help|--help|-h\n\t\tShow the help.\n", np); + printf("\n\t%s -v\n\t\tShow the version.\n", np); + printf("\n\t%s %s%s", np, help_str, + " --help|-h\n\t\tShow detailed help for a command\n"); +} + +static void initialized_options(struct tool_options *options) +{ + memset(options, INVALID, sizeof(*options)); + options->path[0] = '\0'; + options->keypath[0] = '\0'; + options->data = NULL; + options->sg_type = SG4_TYPE; +} + +static int parse_args(int argc, char **argv, command_function *func, + struct tool_options *options) +{ + int rc = OK; + struct tool_command *cp; + char *prgname = get_prgname(argv[0]); + + if (argc == 2 && !strcmp(argv[1], "-v")) { + printf("\n\t %s ver: %s\n", prgname, UFS_BSG_UTIL_VERSION); + goto out; + } else if (argc <= 2) { + help(prgname); + goto out; + } + + for (cp = commands; cp->conf_type; cp++) { + if (!strcmp(argv[1], cp->conf_type)) { + options->config_type_inx = cp->conf_type_ind; + *func = cp->func; + break; + } + } + + if (options->config_type_inx == INVALID) { + print_error("Please enter the correct config type"); + help(prgname); + rc = -EINVAL; + goto out; + } + + if (argc == 3 && + (!strcmp(argv[2], "-h") || !strcmp(argv[2], "--help"))) { + print_command_help(prgname, options->config_type_inx); + *func = 0; + goto out; + } + + rc = init_options(argc, argv, options); + +out: + return rc; +} + +int write_file(const char *name, const void *buffer, int length) +{ + int fd; + int rc = 0; + size_t ret; + + WRITE_LOG("writing file %s length=%d\n", name, length); + fd = open(name, O_RDWR | O_CREAT | O_TRUNC | O_SYNC, 0600); + if (fd == -1) { + WRITE_LOG("%s: failed in open errno=%d", __func__, errno); + return -ENOENT; + } + + ret = write(fd, buffer, length); + if (length != ret) { + WRITE_LOG( "%s: failed in write errno=%d", __func__, errno); + rc = -EIO; + } + + close(fd); + return rc; +} + +void print_error(const char *msg, ...) +{ + va_list args; + + printf("\n Err: "); + va_start(args, msg); + vprintf(msg, args); + va_end(args); + printf("\n"); +} + +void print_warn(const char *msg, ...) +{ + va_list args; + + va_start(args, msg); + fprintf(stderr, "\nWARN: "); + vfprintf(stderr, msg, args); + va_end(args); + printf("\n"); +} + +void print_command_help(char *prgname, int config_type) +{ + switch (config_type) { + case DESC_TYPE: + desc_help(prgname); + break; + case ATTR_TYPE: + attribute_help(prgname); + break; + case FLAG_TYPE: + flag_help(prgname); + break; + case ERR_HIST_TYPE: + err_hist_help(prgname); + break; + case FFU_TYPE: + ffu_help(prgname); + break; + case UIC_TYPE: + unipro_help(prgname); + break; + case VENDOR_BUFFER_TYPE: + vendor_help(prgname); + break; + case RPMB_CMD_TYPE: + rpmb_help(prgname); + break; + case HMR_TYPE: + hmr_help(prgname); + break; + default: + print_error("Unsupported cmd type"); + break; + } +} + +/* + * Wrapper for strtol() function. + * + * strtol() has advantages over atoi(): + * - has error handling + * - handles not only decimal, but acts accordingly to the 'base' argument + * - accepts strings with "0x" prefix + * - stores address of the first invalid character + */ +long str_to_long(char *nptr, int base, long *result) +{ + char *endptr; + + if (!nptr || !result) + return ERROR; + + /* + * From man: + * Since strtol() can legitimately return 0, LONG_MAX, or LONG_MIN + * on both success and failure, the calling program should set errno to 0 + * before the call... + */ + errno = 0; + + *result = strtol(optarg, &endptr, base); + + if (endptr == nptr || /* no conversion performed */ + *endptr != '\0' || /* some chars not converted */ + *result == LONG_MIN || /* underflow occured */ + *result == LONG_MAX || /* overflow occured */ + errno != 0) /* any other error */ + return ERROR; + + return OK; +} + +int main(int ac, char **av) +{ + int rc; + command_function func = NULL; + struct tool_options options; + + initialized_options(&options); + + rc = parse_args(ac, av, &func, &options); + if (rc) + goto out; + + if (func) + rc = func(&options); + +out: + if (options.data) + free(options.data); + return rc ? EXIT_FAILURE : EXIT_SUCCESS; +} + diff --git a/libmtk_bsg/ufs.h b/libmtk_bsg/ufs.h new file mode 100644 index 0000000000000000000000000000000000000000..f382aa072222b03118ee85c450ac7b0522127393 --- /dev/null +++ b/libmtk_bsg/ufs.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#ifndef UFS_H_ +#define UFS_H_ +#include "ioctl.h" +#include "scsi_bsg_util.h" + +#define BLOCK_SIZE 512 + +/* + * Generally the max HW max chunk is 512KB, + * but in order to be in safe side tool using 256KB as max chunk size + * between user and kernel space +*/ +#define MAX_IOCTL_BUF_SIZE (256L * 1024) + +enum sg_struct_type { + SG4_TYPE = 0, + SG3_TYPE +}; + +/* Flag idn for Query Requests*/ +enum flag_idn { + QUERY_FLAG_IDN_RESERVED1 = 0x00, + QUERY_FLAG_IDN_FDEVICEINIT = 0x01, + QUERY_FLAG_IDN_PERMANENT_WPE = 0x02, + QUERY_FLAG_IDN_PWR_ON_WPE = 0x03, + QUERY_FLAG_IDN_BKOPS_EN = 0x04, + QUERY_FLAG_IDN_DEVICE_LIFE_SPAN_MODE_EN = 0x05, + QUERY_FLAG_IDN_PURGE_ENABLE = 0x06, + QUERY_FLAG_IDN_REFRESH_ENABLE = 0x07, + QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL = 0x08, + QUERY_FLAG_IDN_BUSY_RTC = 0x09, + QUERY_FLAG_IDN_RESERVED4 = 0x0A, + QUERY_FLAG_IDN_PERMANENTLYDISABLEFW = 0x0B, + QUERY_FLAG_IDN_WB_EN = 0x0E, + QUERY_FLAG_IDN_WB_BUF_FLUSH_EN = 0x0F, + QUERY_FLAG_IDN_WB_BUF_FLUSH_H8 = 0x10, + QUERY_FLAG_IDN_HPB_RESET = 0x11, + QUERY_FLAG_IDN_HPB_EN = 0x12, + QUERY_FLAG_IDN_MAX +}; + +/* Attribute idn for Query requests */ +enum attr_idn { + QUERY_ATTR_IDN_BOOT_LU_EN = 0x00, + QUERY_ATTR_IDN_RESERVED1 = 0x01, + QUERY_ATTR_IDN_POWER_MODE = 0x02, + QUERY_ATTR_IDN_ACTIVE_ICC_LVL = 0x03, + QUERY_ATTR_IDN_OOO_DATA_EN = 0x04, + QUERY_ATTR_IDN_BKOPS_STATUS = 0x05, + QUERY_ATTR_IDN_PURGE_STATUS = 0x06, + QUERY_ATTR_IDN_MAX_DATA_IN = 0x07, + QUERY_ATTR_IDN_MAX_DATA_OUT = 0x08, + QUERY_ATTR_IDN_DYN_CAP_NEEDED = 0x09, + QUERY_ATTR_IDN_REF_CLK_FREQ = 0x0A, + QUERY_ATTR_IDN_CONF_DESC_LOCK = 0x0B, + QUERY_ATTR_IDN_MAX_NUM_OF_RTT = 0x0C, + QUERY_ATTR_IDN_EE_CONTROL = 0x0D, + QUERY_ATTR_IDN_EE_STATUS = 0x0E, + QUERY_ATTR_IDN_SECONDS_PASSED = 0x0F, + QUERY_ATTR_IDN_CNTX_CONF = 0x10, + QUERY_ATTR_IDN_OBSOLETE = 0x11, + QUERY_ATTR_IDN_RESERVED2 = 0x12, + QUERY_ATTR_IDN_RESERVED3 = 0x13, + QUERY_ATTR_IDN_DEVICE_FFU_STATUS = 0x14, + QUERY_ATTR_IDN_DEVICE_PSA_STATE = 0x15, + QUERY_ATTR_IDN_DEVICE_PSA_DATA_SIZE = 0x16, + QUERY_ATTR_IDN_CASE_REF_CLK_GATING_WAIT_TIME = 0x17, + QUERY_ATTR_IDN_CASE_ROUGH_TEMPERAURE = 0x18, + QUERY_ATTR_IDN_TOO_HIGH_TEMP_BOUNDARY = 0x19, + QUERY_ATTR_IDN_TOO_LOW_TEMP_BOUNDARY = 0x1A, + QUERY_ATTR_IDN_THROTTLING_STAT = 0x1B, + QUERY_ATTR_IDN_WB_FLUSH_STAT = 0x1C, + QUERY_ATTR_IDN_WB_BUF_SIZE = 0x1D, + QUERY_ATTR_IDN_WB_LIFE_TIME_EST = 0x1E, + QUERY_ATTR_IDN_WB_CUR_BUF_SIZE = 0x1F, + QUERY_ATTR_IDN_REFRESH_STATUS = 0x2C, + QUERY_ATTR_IDN_REFRESH_FREQ = 0x2D, + QUERY_ATTR_IDN_REFRESH_UNIT = 0x2E, + QUERY_ATTR_IDN_REFRESH_METHOD = 0x2F, + QUERY_ATTR_IDN_MAX +}; + +/* Descriptor idn for Query requests */ +enum desc_idn { + QUERY_DESC_IDN_DEVICE = 0x0, + QUERY_DESC_IDN_CONFIGURAION = 0x1, + QUERY_DESC_IDN_UNIT = 0x2, + QUERY_DESC_IDN_RFU_0 = 0x3, + QUERY_DESC_IDN_INTERCONNECT = 0x4, + QUERY_DESC_IDN_STRING = 0x5, + QUERY_DESC_IDN_RFU_1 = 0x6, + QUERY_DESC_IDN_GEOMETRY = 0x7, + QUERY_DESC_IDN_POWER = 0x8, + QUERY_DESC_IDN_HEALTH = 0x9, + QUERY_DESC_IDN_RFU_3 = 0xA, + QUERY_DESC_IDN_MAX = 0xFF, +}; + +/* UTP QUERY Transaction Specific Fields OpCode */ +enum query_opcode { + UPIU_QUERY_OPCODE_NOP = 0x0, + UPIU_QUERY_OPCODE_READ_DESC = 0x1, + UPIU_QUERY_OPCODE_WRITE_DESC = 0x2, + UPIU_QUERY_OPCODE_READ_ATTR = 0x3, + UPIU_QUERY_OPCODE_WRITE_ATTR = 0x4, + UPIU_QUERY_OPCODE_READ_FLAG = 0x5, + UPIU_QUERY_OPCODE_SET_FLAG = 0x6, + UPIU_QUERY_OPCODE_CLEAR_FLAG = 0x7, + UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8, + UPIU_QUERY_OPCODE_MAX, +}; + +enum ufs_desc_max_size { + /* Max descriptors size from 2.1 to 3.0 UFS spec */ + QUERY_DESC_DEVICE_MAX_SIZE_3_0 = 0x40, + QUERY_DESC_CONFIGURAION_MAX_SIZE_3_0 = 0x90, + QUERY_DESC_UNIT_MAX_SIZE_3_0 = 0x23, + QUERY_DESC_GEOMETRY_MAX_SIZE_3_0 = 0x48, + QUERY_DESC_HEALTH_MAX_SIZE_2_1 = 0x25, + + /* Max descriptors size for 3.1 UFS spec */ + QUERY_DESC_DEVICE_MAX_SIZE = 0x59, + QUERY_DESC_CONFIGURAION_MAX_SIZE = 0xe6, + QUERY_DESC_GEOMETRY_MAX_SIZE = 0x57, + QUERY_DESC_UNIT_MAX_SIZE = 0x2d, + + /* + * Max. 126 UNICODE characters (2 bytes per character) plus 2 bytes + * of descriptor header. + */ + QUERY_DESC_STRING_MAX_SIZE = 0xFE, + QUERY_DESC_INTERCONNECT_MAX_SIZE = 0x06, + QUERY_DESC_POWER_MAX_SIZE = 0x62, + QUERY_DESC_HEALTH_MAX_SIZE = 0x2d +}; + +/* UPIU Read/Write flags */ +enum { + UPIU_CMD_FLAGS_NONE = 0x00, + UPIU_CMD_FLAGS_WRITE = 0x20, + UPIU_CMD_FLAGS_READ = 0x40, +}; + +/* UPIU Query request function */ +enum { + UPIU_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01, + UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81, +}; + +enum ufs_cong_type { + DESC_TYPE = 0, + ATTR_TYPE, + FLAG_TYPE, + ERR_HIST_TYPE, + UIC_TYPE, + FFU_TYPE, + VENDOR_BUFFER_TYPE, + RPMB_CMD_TYPE, + HMR_TYPE +}; + +/* UTP UPIU Transaction Codes Initiator to Target */ +enum { + UPIU_TRANSACTION_NOP_OUT = 0x00, + UPIU_TRANSACTION_COMMAND = 0x01, + UPIU_TRANSACTION_DATA_OUT = 0x02, + UPIU_TRANSACTION_TASK_REQ = 0x04, + UPIU_TRANSACTION_QUERY_REQ = 0x16, +}; + +int write_file(const char *name, const void *buffer, int length); +void print_error(const char *msg, ...); +void print_warn(const char *msg, ...); +long str_to_long(char *nptr, int base, long *result); +#ifdef DEBUG + #define WRITE_LOG(format, ...) fprintf(stderr, format"\n", __VA_ARGS__) + #define WRITE_LOG0(text) fprintf(stderr, "%s\n", text) +#else + #define WRITE_LOG(...) + #define WRITE_LOG0(...) +#endif + +#endif /* UFS_H_ */ diff --git a/libmtk_bsg/ufs_cmds.c b/libmtk_bsg/ufs_cmds.c new file mode 100644 index 0000000000000000000000000000000000000000..2da620fe1683b91483df81719a8cd40c44c57ef6 --- /dev/null +++ b/libmtk_bsg/ufs_cmds.c @@ -0,0 +1,1302 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#pragma GCC diagnostic ignored "-Wall" +#pragma GCC diagnostic ignored "-Wextra" +#pragma GCC diagnostic ignored "-Wsign-compare" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ufs.h" +#include "ufs_cmds.h" +#include "options.h" + +#define STR_BUF_LEN 33 +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#define ATTR_RSRV() "Reserved", BYTE, ACC_INVALID, MODE_INVALID, LEVEL_INVALID + +#define CONFIG_HEADER_OFFSET 0x16 +#define CONFIG_LUN_OFFSET 0x1A + +/* Config desc. offsets for UFS 2.0 - 3.0 spec */ +#define CONFIG_HEADER_OFFSET_3_0 0x10 +#define CONFIG_LUN_OFFSET_3_0 0x10 + +struct desc_field_offset device_desc_field_name[] = { + {"bLength", 0x00, BYTE}, + {"bDescriptorType", 0x01, BYTE}, + {"bDevice", 0x02, BYTE}, + {"bDeviceClass", 0x03, BYTE}, + {"bDeviceSubClass", 0x04, BYTE}, + {"bProtocol", 0x05, BYTE}, + {"bNumberLU", 0x06, BYTE}, + {"bNumberWLU", 0x07, BYTE}, + {"bBootEnable", 0x08, BYTE}, + {"bDescrAccessEn", 0x09, BYTE}, + {"bInitPowerMode", 0x0A, BYTE}, + {"bHighPriorityLUN", 0x0B, BYTE}, + {"bSecureRemovalType", 0x0C, BYTE}, + {"bSecurityLU", 0x0D, BYTE}, + {"bBackgroundOpsTermLat", 0x0E, BYTE}, + {"bInitActiveICCLevel", 0x0F, BYTE}, + {"wSpecVersion", 0x10, WORD}, + {"wManufactureDate", 0x12, WORD}, + {"iManufactureName", 0x14, BYTE}, + {"iProductName", 0x15, BYTE}, + {"iSerialNumber", 0x16, BYTE}, + {"iOemID", 0x17, BYTE}, + {"ManufacturerID", 0x18, WORD}, + {"bUD0BaseOffset", 0x1A, BYTE}, + {"bUDConfigPLength", 0x1B, BYTE}, + {"bDeviceRTTCap", 0x1C, BYTE}, + {"wPeriodicRTCUpdate", 0x1D, WORD}, + {"bUFSFeaturesSupport", 0x1F, BYTE}, + {"bFFUTimeout", 0x20, BYTE}, + {"bQueueDepth", 0x21, BYTE}, + {"wDeviceVersion", 0x22, WORD}, + {"bNumSecureWPArea", 0x24, BYTE}, + {"dPSAMaxDataSize", 0x25, DWORD}, + {"bPSAStateTimeout", 0x29, BYTE}, + {"iProductRevisionLevel", 0x2A, BYTE}, + {"Reserved1", 0x2B, BYTE}, + {"Reserved2", 0x2C, DWORD}, + {"Reserved3", 0x30, DWORD}, + {"Reserved4", 0x34, DWORD}, + {"Reserved5", 0x38, DWORD}, + {"Reserved6", 0x3c, DWORD}, + {"wHPBVersion", 0x40, WORD}, + {"bHPBControl", 0x42, BYTE}, + {"Reserved8", 0x43, DWORD}, + {"Reserved9", 0x47, DDWORD}, + {"dExtendedUFSFeaturesSupport", 0x4F, DWORD}, + {"bWriteBoosterBufferPreserveUserSpaceEn", 0x53, BYTE}, + {"bWriteBoosterBufferType", 0x54, BYTE}, + {"dNumSharedWriteBoosterBufferAllocUnits", 0x55, DWORD} +}; + +struct desc_field_offset device_config_desc_field_name[] = { + {"bLength", 0x00, BYTE}, + {"bDescriptorType", 0x01, BYTE}, + {"bConfDescContinue", 0x02, BYTE}, + {"bBootEnable", 0x03, BYTE}, + {"bDescrAccessEn", 0x04, BYTE}, + {"bInitPowerMode", 0x05, BYTE}, + {"bHighPriorityLUN", 0x06, BYTE}, + {"bSecureRemovalType", 0x07, BYTE}, + {"bInitActiveICCLevel", 0x08, BYTE}, + {"wPeriodicRTCUpdate", 0x09, WORD}, + {"bHPBControl", 0x0B, BYTE}, + {"bRPMBRegionEnable", 0x0C, BYTE}, + {"bRPMBRegion1Size", 0x0D, BYTE}, + {"bRPMBRegion2Size", 0x0E, BYTE}, + {"bRPMBRegion3Size", 0x0F, BYTE}, + {"bWriteBoosterBufferPreserveUserSpaceEn", 0x10, BYTE}, + {"bWriteBoosterBufferType", 0x11, BYTE}, + {"dNumSharedWriteBoosterBufferAllocUnits", 0x12, DWORD} +}; + +struct desc_field_offset device_config_unit_desc_field_name[] = { + {"bLUEnable", 0x00, BYTE}, + {"bBootLunID", 0x01, BYTE}, + {"bLUWriteProtect", 0x02, BYTE}, + {"bMemoryType", 0x03, BYTE}, + {"dNumAllocUnits", 0x04, DWORD}, + {"bDataReliability", 0x08, BYTE}, + {"bLogicalBlockSize", 0x09, BYTE}, + {"bProvisioningType", 0x0A, BYTE}, + {"wContextCapabilities", 0x0B, WORD}, + {"wLUMaxActiveHPBRegions", 0x10, WORD}, + {"wHPBPinnedRegionStartIdx", 0x12, WORD}, + {"wNumHPBPinnedRegions", 0x14, WORD}, + {"dLUNumWriteBoosterBufferAllocUnits", 0x16, DWORD} +}; + +struct desc_field_offset device_geo_desc_conf_field_name[] = { + {"bLength", 0x00, BYTE}, + {"bDescriptorType ", 0x01, BYTE}, + {"bMediaTechnology", 0x02, BYTE}, + {"qTotalRawDeviceCapacity", 0x04, DDWORD}, + {"bMaxNumberLU", 0x0C, BYTE}, + {"dSegmentSize", 0x0D, DWORD}, + {"bAllocationUnitSize", 0x11, BYTE}, + {"bMinAddrBlockSize", 0x12, BYTE}, + {"bOptimalReadBlockSize", 0x13, BYTE}, + {"bOptimalWriteBlockSize", 0x14, BYTE}, + {"bMaxInBufferSize", 0x15, BYTE}, + {"bMaxOutBufferSize", 0x16, BYTE}, + {"bRPMB_ReadWriteSize", 0x17, BYTE}, + {"bDynamicCapacityResourcePolicy", 0x18, BYTE}, + {"bDataOrdering", 0x19, BYTE}, + {"bMaxContexIDNumber", 0x1A, BYTE}, + {"bSysDataTagUnitSize", 0x1B, BYTE}, + {"bSysDataTagResSize", 0x1C, BYTE}, + {"bSupportedSecRTypes", 0x1D, BYTE}, + {"wSupportedMemoryTypes", 0x1E, WORD}, + {"dSystemCodeMaxNAllocU", 0x20, DWORD}, + {"wSystemCodeCapAdjFac", 0x24, DWORD}, + {"dNonPersistMaxNAllocU", 0x26, DWORD}, + {"wNonPersistCapAdjFac", 0x2A, WORD}, + {"dEnhanced1MaxNAllocU", 0x2C, DWORD}, + {"wEnhanced1CapAdjFac", 0x30, WORD}, + {"dEnhanced2MaxNAllocU", 0x32, DWORD}, + {"wEnhanced2CapAdjFac", 0x36, WORD}, + {"dEnhanced3MaxNAllocU", 0x38, DWORD}, + {"wEnhanced3CapAdjFac", 0x3C, WORD}, + {"dEnhanced4MaxNAllocU", 0x3E, DWORD}, + {"wEnhanced4CapAdjFac", 0X42, WORD}, + {"dOptimalLogicalBlockSize", 0X44, DWORD}, + {"bHPBRegionSize", 0X48, BYTE}, + {"bHPBNumberLU", 0X49, BYTE}, + {"bHPBSubRegionSize", 0X4a, BYTE}, + {"wDeviceMaxActiveHPBRegions", 0X4b, WORD}, + {"Reserved", 0X4d, WORD}, + {"dWriteBoosterBufferMaxNAllocUnits", 0X4f, DWORD}, + {"bDeviceMaxWriteBoosterLUs", 0X53, BYTE}, + {"bWriteBoosterBufferCapAdjFac", 0X54, BYTE}, + {"bSupportedWriteBoosterBufferUserSpaceReductionTypes", 0X55, BYTE}, + {"bSupportedWriteBoosterBufferTypes", 0X56, BYTE} +}; + +struct desc_field_offset device_interconnect_desc_conf_field_name[] = { + {"bLength", 0x00, BYTE}, + {"bDescriptorType", 0x01, BYTE}, + {"bcdUniproVersion", 0x02, WORD}, + {"bcdMphyVersion ", 0x04, WORD}, +}; + +struct desc_field_offset device_unit_desc_field_name[] = { + {"bLength", 0x00, BYTE}, + {"bDescriptorType", 0x01, BYTE}, + {"bUnitIndex", 0x02, BYTE}, + {"bLUEnable", 0x03, BYTE}, + {"bBootLunID", 0x04, BYTE}, + {"bLUWriteProtect", 0x05, BYTE}, + {"bLUQueueDepth", 0x06, BYTE}, + {"bPSASensitive", 0x07, BYTE}, + {"bMemoryType", 0x08, BYTE}, + {"bDataReliability", 0x09, BYTE}, + {"bLogicalBlockSize", 0x0A, BYTE}, + {"qLogicalBlockCount", 0x0B, DDWORD}, + {"dEraseBlockSize", 0x13, DWORD}, + {"bProvisioningType", 0x17, BYTE}, + {"qPhyMemResourceCount", 0x18, DDWORD}, + {"wContextCapabilities", 0x20, WORD}, + {"bLargeUnitGranularity_M1", 0x22, BYTE}, + {"wLUMaxActiveHPBRegions", 0x23, WORD}, + {"wHPBPinnedRegionStartIdx", 0x25, WORD}, + {"wNumHPBPinnedRegions", 0x27, WORD}, + {"dLUNumWriteBoosterBufferAllocUnits", 0x29, DWORD} +}; + +struct desc_field_offset device_unit_rpmb_desc_field_name[] = { + {"bLength", 0x00, BYTE}, + {"bDescriptorType", 0x01, BYTE}, + {"bUnitIndex", 0x02, BYTE}, + {"bLUEnable", 0x03, BYTE}, + {"bBootLunID", 0x04, BYTE}, + {"bLUWriteProtect", 0x05, BYTE}, + {"bLUQueueDepth", 0x06, BYTE}, + {"bPSASensitive", 0x07, BYTE}, + {"bMemoryType", 0x08, BYTE}, + {"bRPMBRegionEnable", 0x09, BYTE}, + {"bLogicalBlockSize", 0x0A, BYTE}, + {"qLogicalBlockCount", 0x0B, DDWORD}, + {"bRPMBRegion0Size", 0x13, BYTE}, + {"bRPMBRegion1Size", 0x14, BYTE}, + {"bRPMBRegion2Size", 0x15, BYTE}, + {"bRPMBRegion3Size", 0x16, BYTE}, + {"bProvisioningType", 0x17, BYTE}, + {"qPhyMemResourceCount", 0x18, DDWORD}, + {"wContextCapabilities", 0x20, WORD}, + {"wContextCapabilities", 0x22, BYTE}, +}; + +struct desc_field_offset device_power_desc_conf_field_name[] = { + {"bLength", 0x00, BYTE}, + {"bDescriptorType", 0x01, BYTE}, + {"wActiveICCLevelsVCC", 0x02, 32}, + {"wActiveICCLevelsVCCQ", 0x22, 32}, + {"wActiveICCLevelsVCCQ2", 0x42, 32} +}; + +struct desc_field_offset device_health_desc_conf_field_name[] = { + {"bLength", 0x00, BYTE}, + {"bDescriptorType", 0x01, BYTE}, + {"bPreEOLInfo", 0x02, BYTE}, + {"bDeviceLifeTimeEstA", 0x03, BYTE}, + {"bDeviceLifeTimeEstB", 0x04, BYTE}, + {"VendorPropInfo", 0x05, 32}, + {"dRefreshTotalCount", 0x25, DWORD}, + {"dRefreshProgress", 0x29, DWORD}, +}; + +struct query_err_res { + char *name; + __u8 opcode; +}; + +struct attr_fields ufs_attrs[] = { + {"bBootLunEn", BYTE, (URD|UWRT), (READ_ONLY|WRITE_PRSIST), DEV}, + {"bMAX_DATA_SIZE_FOR_HPB_SINGLE_CMD", BYTE, URD, READ_ONLY, DEV}, + {"bCurrentPowerMode", BYTE, URD, READ_ONLY, DEV}, + {"bActiveICCLevel", BYTE, (URD|UWRT), (READ_NRML|WRITE_PRSIST), DEV}, + {"bOutOfOrderDataEn", BYTE, (URD|UWRT), (READ_NRML|WRITE_ONCE), DEV}, + {"bBackgroundOpStatus", BYTE, URD, READ_ONLY, DEV}, + {"bPurgeStatus", BYTE, URD, READ_ONLY, DEV}, + {"bMaxDataInSize", BYTE, (URD|UWRT), (READ_NRML|WRITE_PRSIST), DEV}, + {"bMaxDataOutSize", BYTE, (URD|UWRT), (READ_NRML|WRITE_PRSIST), DEV}, + {"dDynCapNeeded", WORD, URD, READ_ONLY, ARRAY}, + {"bRefClkFreq", BYTE, (URD|UWRT), (READ_NRML|WRITE_PRSIST), DEV}, + {"bConfigDescrLock", BYTE, (URD|UWRT), (READ_NRML|WRITE_ONCE), DEV}, + {"bMaxNumOfRTT", BYTE, (URD|UWRT), (READ_NRML|WRITE_PRSIST), DEV}, + {"wExceptionEventControl", WORD, URD, READ_NRML, DEV}, + {"wExceptionEventStatus", WORD, URD, READ_ONLY, DEV}, + {"dSecondsPassed", DWORD, UWRT, WRITE_ONLY, DEV}, + {"wContextConf", WORD, (URD|UWRT), (READ_NRML|WRITE_VLT), ARRAY}, + {"Reserved", BYTE, ACC_INVALID, MODE_INVALID, LEVEL_INVALID}, + {"Reserved", BYTE, ACC_INVALID, MODE_INVALID, LEVEL_INVALID}, + {"Reserved", BYTE, ACC_INVALID, MODE_INVALID, LEVEL_INVALID}, + {"bDeviceFFUStatus", BYTE, URD, READ_ONLY, DEV}, + {"bPSAState", BYTE, (URD|UWRT), (READ_NRML|WRITE_PRSIST), DEV}, + {"dPSADataSize", DWORD, (URD|UWRT), (READ_NRML|WRITE_PRSIST), DEV}, + {"bRefClkGatingWaitTime", BYTE, URD, READ_ONLY, DEV}, + {"bDeviceCaseRoughTemperaure", BYTE, URD, READ_ONLY, DEV}, + {"bDeviceTooHighTempBoundary", BYTE, URD, READ_ONLY, DEV}, +/*1A*/ {"bDeviceTooLowTempBoundary", BYTE, URD, READ_ONLY, DEV}, +/*1B*/ {"bThrottlingStatus", BYTE, URD, READ_ONLY, DEV}, +/*1C*/ {"bWBBufFlushStatus", BYTE, URD, READ_ONLY, DEV | ARRAY}, +/*1D*/ {"bAvailableWBBufSize", BYTE, URD, READ_ONLY, DEV | ARRAY}, +/*1E*/ {"bWBBufLifeTimeEst", BYTE, URD, READ_ONLY, DEV | ARRAY}, +/*1F*/ {"bCurrentWBBufSize", DWORD, URD, READ_ONLY, DEV | ARRAY}, + {ATTR_RSRV()}, + {ATTR_RSRV()}, + {ATTR_RSRV()}, + {ATTR_RSRV()}, + {ATTR_RSRV()}, + {ATTR_RSRV()}, + {ATTR_RSRV()}, + {ATTR_RSRV()}, + {ATTR_RSRV()}, + {ATTR_RSRV()}, + {ATTR_RSRV()}, + {ATTR_RSRV()}, +/*2C*/ {"bRefreshStatus", BYTE, URD, READ_ONLY, DEV}, + {"bRefreshFreq", BYTE, (URD|UWRT), (READ_NRML|WRITE_PRSIST), DEV}, + {"bRefreshUnit", BYTE, (URD|UWRT), (READ_NRML|WRITE_PRSIST), DEV}, + {"bRefreshMethod", BYTE, (URD|UWRT), (READ_NRML|WRITE_PRSIST), DEV} +}; + +struct flag_fields ufs_flags[] = { + {"Reserved", ACC_INVALID, MODE_INVALID, LEVEL_INVALID}, + {"fDeviceInit", (URD|UWRT), (READ_NRML|SET_ONLY), DEV}, + {"fPermanentWPEn", (URD|UWRT), (READ_NRML|WRITE_ONCE), DEV}, + {"fPowerOnWPEn", (URD|UWRT), (READ_NRML|WRITE_PWR), DEV}, + {"fBackgroundOpsEn", (URD|UWRT), (READ_NRML|WRITE_VLT), DEV}, + {"fDeviceLifeSpanModeEn", (URD|UWRT), (READ_NRML|WRITE_VLT), DEV}, + {"fPurgeEnable", UWRT, (WRITE_ONLY|WRITE_VLT), DEV}, + {"fRefreshEnable", UWRT, (WRITE_ONLY|WRITE_VLT), DEV}, + {"fPhyResourceRemoval", (URD|UWRT), (READ_NRML|WRITE_PRSIST), DEV}, + {"fBusyRTC", URD, READ_ONLY, DEV}, + {"Reserved", ACC_INVALID, MODE_INVALID, LEVEL_INVALID}, + {"fPermanentlyDisableFw", (URD|UWRT), (READ_NRML|WRITE_ONCE), DEV}, + {"Reserved", ACC_INVALID, MODE_INVALID, LEVEL_INVALID}, +/*D*/ {"Reserved", ACC_INVALID, MODE_INVALID, LEVEL_INVALID}, +/*E*/ {"fWriteBoosterEn", (URD|UWRT), (READ_NRML|WRITE_VLT), DEV | ARRAY}, +/*F*/ {"fWBFlushEn", (URD|UWRT), (READ_NRML|WRITE_VLT), DEV | ARRAY}, +/*10h*/ {"fWBFlushDuringHibernate", (URD|UWRT), (READ_NRML|WRITE_VLT), + DEV | ARRAY}, +/*11h*/ {"fHPBReset", (URD|UWRT), (READ_NRML|SET_ONLY), DEV}, +/*12h*/ {"fHPBEn", (URD|UWRT), (READ_NRML|WRITE_PRSIST), DEV}, +}; + +static struct query_err_res query_err_status[] = { + {"Success", 0xF0}, + {"Reserved1", 0xF1}, + {"Reserved2", 0xF2}, + {"Reserved3", 0xF3}, + {"Reserved4", 0xF4}, + {"Reserved5", 0xF5}, + {"Parameter not readable", 0xF6}, + {"Parameter not written", 0xF7}, + {"Parameter already written", 0xF8}, + {"Invalid LENGTH", 0xF9}, + {"Invalid value", 0xFA}, + {"Invalid SELECTOR", 0xFB}, + {"Invalid INDEX", 0xFC}, + {"Invalid IDN", 0xFD}, + {"Invalid OPCODE", 0xFE}, + {"General failure", 0xFF} +}; + +static const char *const desc_text[] = { + "Device", + "Config", + "Unit", + "RFU0", + "Interconnect", + "String", + "RFU1", + "Geometry", + "Power", + "Health" +}; + +int do_read_desc(int fd, struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp, __u8 idn, __u8 index, + __u16 desc_buf_len, __u8 *data_buf); +static int do_unit_desc(int fd, __u8 lun); +static int do_power_desc(int fd); +static int do_conf_desc(int fd, __u8 opt, __u8 index, char *data_file); +static int do_string_desc(int fd, char *str_data, __u8 idn, __u8 opr, + __u8 index); +int do_query_rq(int fd, struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp, __u8 query_req_func, + __u8 opcode, __u8 idn, __u8 index, __u8 sel, + __u16 req_buf_len, __u16 res_buf_len, __u8 *data_buf); +static int do_write_desc(int fd, struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp, __u8 idn, __u8 index, + __u16 desc_buf_len, __u8 *data_buf); +static void query_response_error(__u8 opcode, __u8 idn); + +static void print_power_desc_icc(__u8 *desc_buf, int vccIndex) +{ + int i, offset = 0; + struct desc_field_offset *tmp; + + if (vccIndex < 2 || + vccIndex > ARRAY_SIZE(device_power_desc_conf_field_name) - 1) { + print_error("Illegal power desc index %d", vccIndex); + return; + } + + tmp = &device_power_desc_conf_field_name[vccIndex]; + offset = tmp->offset; + printf("\nPower Descriptor %s", tmp->name); + for (i = offset; i < offset + 32 ; i += 2) { + printf("\nLevel %2d value : 0x%x", (i - offset)/2, + be16toh((__u16)desc_buf[i])); + } + printf("\n"); +} + +static void print_vendor_info(__u8 *desc_buf, int len) +{ + int i; + + if (!desc_buf) + return; + + for (i = 0 ; i < len; i++) { + if (!(i%16)) + printf("\t\n"); + printf("0x%02x ", desc_buf[i]); + } + printf("\n"); +} + +void print_descriptors(char *desc_str, __u8 *desc_buf, + struct desc_field_offset *desc_array, int arr_size) +{ + int i; + struct desc_field_offset *tmp; + char str_buf[STR_BUF_LEN]; + int offset = 0; + + for (i = 0; offset < arr_size; ++i) { + tmp = &desc_array[i]; + offset = tmp->offset + tmp->width_in_bytes; + + if (tmp->width_in_bytes == BYTE) { + printf("%s [Byte offset 0x%x]: %s = 0x%x\n", desc_str, + tmp->offset, tmp->name, desc_buf[tmp->offset]); + } else if (tmp->width_in_bytes == WORD) { + printf("%s [Byte offset 0x%x]: %s = 0x%x\n", desc_str, + tmp->offset, tmp->name, + be16toh(*(__u16 *)&desc_buf[tmp->offset])); + } else if (tmp->width_in_bytes == DWORD) { + printf("%s [Byte offset 0x%x]: %s = 0x%x\n", desc_str, + tmp->offset, tmp->name, + be32toh(*(__u32 *)&desc_buf[tmp->offset])); + } else if (tmp->width_in_bytes == DDWORD) { + printf("%s [Byte offset 0x%x]: %s = 0x%lx\n", + desc_str, tmp->offset, tmp->name, + be64toh(*(__u64 *)&desc_buf[tmp->offset])); + } else if ((tmp->width_in_bytes > DDWORD) && + tmp->width_in_bytes < STR_BUF_LEN) { + if (!strcmp(tmp->name, "VendorPropInfo")) { + printf("%s [Byte offset 0x%x]: %s =\n", + desc_str, + tmp->offset, + tmp->name); + print_vendor_info(&desc_buf[tmp->offset], + tmp->width_in_bytes); + } else { + memset(str_buf, 0, STR_BUF_LEN); + memcpy(str_buf, &desc_buf[tmp->offset], + tmp->width_in_bytes); + printf("%s [Byte offset 0x%x]: %s = %s\n", + desc_str, + tmp->offset, tmp->name, str_buf); + } + } else { + printf("%s [Byte offset 0x%x]: %s Wrong Width = %d", + desc_str, tmp->offset, tmp->name, + tmp->width_in_bytes); + } + } +} + +static char *access_type_string(__u8 current_att, __u8 config_type, + char *access_string) +{ + enum acc_mode mode; + + switch (config_type) { + case ATTR_TYPE: + if (current_att >= QUERY_ATTR_IDN_MAX) + return NULL; + mode = ufs_attrs[current_att].acc_mode; + break; + case FLAG_TYPE: + if (current_att >= QUERY_FLAG_IDN_MAX) + return NULL; + mode = ufs_flags[current_att].acc_mode; + break; + default: + return NULL; + } + + if (mode & READ_NRML) + strcat(access_string, " | Read"); + if (mode & READ_ONLY) + strcat(access_string, " | ReadOnly"); + if (mode & WRITE_ONLY) + strcat(access_string, " | WriteOnly"); + if (mode & WRITE_ONCE) + strcat(access_string, " | WriteOnce"); + if (mode & WRITE_PRSIST) + strcat(access_string, " | Persistent"); + if (mode & WRITE_VLT) + strcat(access_string, " | Volatile"); + if (mode & SET_ONLY) + strcat(access_string, " | SetOnly"); + if (mode & WRITE_PWR) + strcat(access_string, " | ResetOnPower"); + + return access_string; +} + +static void query_response_error(__u8 opcode, __u8 idn) +{ + __u8 query_response_inx = opcode & 0x0F; + + printf("\n %s, for idn 0x%02x\n", + query_err_status[query_response_inx].name, idn); +} + +void desc_help(char *tool_name) +{ + printf("\n Descriptor command usage:\n"); + printf("\n\t%s desc [-t] [-a|-r|-w] [-p] " + " \n", tool_name); + printf("\n\t-t\t description type idn\n" + "\t\t Available description types based on UFS ver 3.1 :\n" + "\t\t\t0:\tDevice\n" + "\t\t\t1:\tConfiguration\n" + "\t\t\t2:\tUnit\n" + "\t\t\t3:\tRFU\n" + "\t\t\t4:\tInterconnect\n" + "\t\t\t5:\tString\n" + "\t\t\t6:\tRFU\n" + "\t\t\t7:\tGeometry\n" + "\t\t\t8:\tPower\n" + "\t\t\t9:\tDevice Health\n" + "\t\t\t10..255: RFU\n"); + printf("\n\t-r\t read operation (default) for readable descriptors\n"); + printf("\n\t-w\t write operation , for writable descriptors\n"); + printf("\t\t Set the input configuration file after -w opt\n"); + printf("\t\t for Configuration descriptor\n"); + printf("\t\t Set the input string after -w opt\n"); + printf("\t\t for String descriptor\n"); + printf("\n\t-i\t Set index parameter(default = 0)\n"); + printf("\n\t-s\t Set selector parameter(default = 0)\n"); + printf("\n\t-p\t path to ufs bsg device\n"); +} + +void attribute_help(char *tool_name) +{ + __u8 current_att = 0; + char access_string[100] = {0}; + + printf("\n Attributes command usage:\n"); + printf("\n\t%s attr [-t] [-a|-r|-w] [-p]" + "  \n", tool_name); + printf("\n\t-t\t Attributes type idn\n" + "\t\t Available attributes and its access based on" + " UFS ver 3.1 :\n"); + + while (current_att < ARRAY_SIZE(ufs_attrs)) { + printf("\t\t\t %-3d: %-25s %s\n", + current_att, + ufs_attrs[current_att].name, + access_type_string(current_att, ATTR_TYPE, + access_string)); + current_att++; + memset(access_string, 0, 100); + } + + printf("\n\t-a\tread and print all readable attributes" + " for the device\n"); + printf("\n\t-r\tread operation (default), for readable attribute(s)\n"); + printf("\n\t-w\twrite operation (with hex data)," + " for writable attribute\n"); + printf("\n\t-i\t Set index parameter(default = 0)\n"); + printf("\n\t-s\t Set selector parameter(default = 0)\n"); + printf("\n\t-p\tpath to ufs bsg device\n"); + printf("\n\tExample - Read bBootLunEn\n" + "\t\t%s attr -t 0 -p /dev/ufs-bsg\n", tool_name); +} + +void flag_help(char *tool_name) +{ + __u8 current_flag = 0; + char access_string[100] = {0}; + + printf("\n Flags command usage:\n"); + printf("\n\t%s fl [-t] [-a|-r|-o|-e] [-p]" + " \n", tool_name); + printf("\n\t-t\t Flags type idn\n" + "\t\t Available flags and its access, based on UFS ver 3.1 :\n"); + + while (current_flag < QUERY_FLAG_IDN_MAX) { + printf("\t\t\t %-3d: %-25s %s\n", current_flag, + ufs_flags[current_flag].name, + access_type_string(current_flag, FLAG_TYPE, + access_string)); + current_flag++; + memset(access_string, 0, 100); + } + printf("\n\t-a\t read and print all readable flags for the device\n"); + printf("\n\t-r\t read operation (default), for readable flag(s)\n"); + printf("\n\t-e\t set flag operation\n"); + printf("\n\t-c\t clear/reset flag operation\n"); + printf("\n\t-o\t toggle flag operation\n"); + printf("\n\t-i\t Set index parameter(default = 0)\n"); + printf("\n\t-s\t Set selector parameter(default = 0)\n"); + printf("\n\t-p\t path to ufs bsg device\n"); + printf("\n\tExample - Read the bkops operation flag\n" + "\t\t%s fl -t 4 -p /dev/ufs-bsg\n", tool_name); +} + +int do_device_desc(int fd, __u8 *desc_buff) +{ + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + __u8 data_buf[QUERY_DESC_DEVICE_MAX_SIZE] = {0}; + int rc = 0; + + rc = do_read_desc(fd, &bsg_req, &bsg_rsp, + QUERY_DESC_IDN_DEVICE, 0, + QUERY_DESC_DEVICE_MAX_SIZE, data_buf); + if (rc) { + print_error("Could not read device descriptor , error %d", rc); + goto out; + } + if (!desc_buff) + print_descriptors("Device Descriptor", data_buf, + device_desc_field_name, data_buf[0]); + else + memcpy(desc_buff, data_buf, data_buf[0]); + +out: + return rc; +} + +static int do_unit_desc(int fd, __u8 lun) +{ + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + __u8 data_buf[QUERY_DESC_UNIT_MAX_SIZE] = {0}; + int ret = 0; + + ret = do_read_desc(fd, &bsg_req, &bsg_rsp, QUERY_DESC_IDN_UNIT, lun, + QUERY_DESC_UNIT_MAX_SIZE, data_buf); + if (ret) { + print_error("Could not read unit descriptor error", ret); + goto out; + } + + if (lun == 0xc4) + print_descriptors("RPMB LUN Descriptor", data_buf, + device_unit_rpmb_desc_field_name, data_buf[0]); + else + print_descriptors("LUN Descriptor", data_buf, + device_unit_desc_field_name, data_buf[0]); + + +out: + return ret; +} + +static int do_interconnect_desc(int fd) +{ + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + __u8 data_buf[QUERY_DESC_INTERCONNECT_MAX_SIZE] = {0}; + int ret = 0; + + ret = do_read_desc(fd, &bsg_req, &bsg_rsp, QUERY_DESC_IDN_INTERCONNECT, + 0, QUERY_DESC_INTERCONNECT_MAX_SIZE, data_buf); + if (ret) { + print_error("Could not read interconnect descriptor error %d", + ret); + goto out; + } + + print_descriptors("Interconnect Descriptor", data_buf, + device_interconnect_desc_conf_field_name, data_buf[0]); + +out: + return ret; +} + +static int do_geo_desc(int fd) +{ + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + __u8 data_buf[QUERY_DESC_GEOMETRY_MAX_SIZE] = {0}; + int ret = 0; + + ret = do_read_desc(fd, &bsg_req, &bsg_rsp, QUERY_DESC_IDN_GEOMETRY, 0, + QUERY_DESC_GEOMETRY_MAX_SIZE, data_buf); + if (ret) { + print_error("Could not read geometry descriptor , error %d", + ret); + goto out; + } + + print_descriptors("Geometry Descriptor", data_buf, + device_geo_desc_conf_field_name, data_buf[0]); + +out: + return ret; +} + +static int do_power_desc(int fd) +{ + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + __u8 data_buf[QUERY_DESC_POWER_MAX_SIZE] = {0}; + int ret = 0; + + ret = do_read_desc(fd, &bsg_req, &bsg_rsp, + QUERY_DESC_IDN_POWER, 0, QUERY_DESC_POWER_MAX_SIZE, + data_buf); + if (ret) { + print_error("Could not read power descriptor , error %d", ret); + goto out; + } + + printf("Power Descriptor[Byte offset 0x%x]: %s = 0x%x\n", + device_power_desc_conf_field_name[0].offset, + device_power_desc_conf_field_name[0].name, data_buf[0]); + + printf("Power Descriptor[Byte offset 0x%x]: %s = 0x%x\n", + device_power_desc_conf_field_name[1].offset, + device_power_desc_conf_field_name[1].name, data_buf[1]); + + print_power_desc_icc(data_buf, 2); + print_power_desc_icc(data_buf, 3); + print_power_desc_icc(data_buf, 4); + +out: + return ret; +} + +static int do_health_desc(int fd) +{ + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + __u8 data_buf[QUERY_DESC_HEALTH_MAX_SIZE] = {0}; + int ret = 0; + + ret = do_read_desc(fd, &bsg_req, &bsg_rsp, QUERY_DESC_IDN_HEALTH, 0, + QUERY_DESC_HEALTH_MAX_SIZE, data_buf); + if (ret) { + print_error("Could not read device health descriptor error %d", + ret); + goto out; + } + + print_descriptors("Device Health Descriptor:", data_buf, + device_health_desc_conf_field_name, data_buf[0]); + +out: + return ret; +} + +static void create_str_desc_data(__u8 *dest_buf, const char *str, __u8 len) +{ + int j = 3; + int i; + + dest_buf[0] = len * 2 + 2; + dest_buf[1] = QUERY_DESC_IDN_STRING; + for (i = 0; i < len ; i++) { + dest_buf[j] = *(str++); + j = j + 2; + } +} + + + + + +static int do_string_desc(int fd, char *str_data, __u8 idn, __u8 opr, + __u8 index) +{ + int rc = 0; + __u8 data_buf[QUERY_DESC_STRING_MAX_SIZE] = {0}; + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + int len, i; + + if (opr == WRITE) { + len = strlen(str_data); + create_str_desc_data(data_buf, str_data, len); + rc = do_write_desc(fd, &bsg_req, &bsg_rsp, + QUERY_DESC_IDN_STRING, index, + len * 2 + 2, data_buf); + if (rc == OK) + printf("\nString Descriptor was written\n"); + } else { + rc = do_read_desc(fd, &bsg_req, &bsg_rsp, QUERY_DESC_IDN_STRING, + index, QUERY_DESC_STRING_MAX_SIZE, data_buf); + if (!rc) { + printf("\nString Desc(Row data):\n"); + for (i = 0; i < bsg_rsp.reply_payload_rcv_len; i++) + printf("0x%02x ", data_buf[i]); + printf("\n"); + } + } + return rc; +} + +static int do_conf_desc(int fd, __u8 opt, __u8 index, char *data_file) +{ + int rc = OK; + int file_size; + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + __u8 conf_desc_buf[QUERY_DESC_CONFIGURAION_MAX_SIZE] = {0}; + int offset, i; + int data_fd = INVALID; + char *filename_header = "config_desc_data_ind_%d"; + char output_file[30] = {0}; + + if (opt == WRITE) { + data_fd = open(data_file, O_RDONLY); + if (data_fd < 0) { + perror("can't open input file"); + return ERROR; + } + + file_size = lseek(data_fd, 0, SEEK_END); + if (file_size <= 0) { + print_error("Wrong config file"); + rc = ERROR; + goto out; + } + lseek(data_fd, 0, SEEK_SET); + + rc = read(data_fd, conf_desc_buf, file_size); + if (rc <= 0) { + print_error("Cannot config file"); + rc = ERROR; + goto out; + } + + rc = do_write_desc(fd, &bsg_req, &bsg_rsp, + QUERY_DESC_IDN_CONFIGURAION, index, + file_size, + conf_desc_buf); + if (!rc) + printf("Config Descriptor was written to device\n"); + } else { + __u8 head_off = CONFIG_HEADER_OFFSET; + __u8 lun_off = CONFIG_LUN_OFFSET; + + rc = do_read_desc(fd, &bsg_req, &bsg_rsp, + QUERY_DESC_IDN_CONFIGURAION, + index, QUERY_DESC_CONFIGURAION_MAX_SIZE, + conf_desc_buf); + if (rc) { + print_error("Coudn't read config descriptor error %d", + rc); + + goto out; + } + + if (conf_desc_buf[0] == QUERY_DESC_CONFIGURAION_MAX_SIZE_3_0) { + head_off = CONFIG_HEADER_OFFSET_3_0; + lun_off = CONFIG_LUN_OFFSET_3_0; + } + + print_descriptors("Config Device Descriptor:", + conf_desc_buf, + device_config_desc_field_name, + head_off); + + offset = head_off; + for (i = 0 ; i < 8; i++) { + printf("Config %d Unit Descriptor:\n", i); + print_descriptors("Config Descriptor:", + conf_desc_buf + offset, + device_config_unit_desc_field_name, + lun_off); + offset = offset + lun_off; + } + sprintf(output_file, filename_header, index); + data_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR); + if (data_fd < 0) { + perror("can't open output file"); + return ERROR; + } + + rc = write(data_fd, conf_desc_buf, conf_desc_buf[0]); + if (rc <= 0) { + print_error("Could not write config data into %s file", + output_file); + rc = ERROR; + goto out; + } + + printf("Config Descriptor was written into %s file\n", + output_file); + } +out: + if (data_fd != INVALID) + close(data_fd); + return rc; +} + +int do_desc(struct tool_options *opt) +{ + int fd; + int rc = OK; + int oflag = O_RDWR; + + if (opt->opr == READ_ALL || opt->opr == READ) + oflag = O_RDONLY; + + fd = open(opt->path, oflag); + if (fd < 0) { + print_error("open"); + return ERROR; + } + + if (opt->opr == READ_ALL) { + if (do_device_desc(fd, NULL) || do_unit_desc(fd, 0) || + do_interconnect_desc(fd) || do_geo_desc(fd) || + do_power_desc(fd) || + do_health_desc(fd) || + do_conf_desc(fd, READ, 0, NULL)) + rc = ERROR; + goto out; + } + + switch (opt->idn) { + case QUERY_DESC_IDN_DEVICE: + rc = do_device_desc(fd, NULL); + break; + case QUERY_DESC_IDN_CONFIGURAION: + if (opt->opr == READ) + rc = do_conf_desc(fd, opt->opr, opt->index, NULL); + else + rc = do_conf_desc(fd, opt->opr, opt->index, + (char *)opt->data); + break; + case QUERY_DESC_IDN_UNIT: + rc = do_unit_desc(fd, opt->index); + break; + case QUERY_DESC_IDN_GEOMETRY: + rc = do_geo_desc(fd); + break; + case QUERY_DESC_IDN_POWER: + rc = do_power_desc(fd); + break; + case QUERY_DESC_IDN_STRING: + rc = do_string_desc(fd, (char *)opt->data, opt->idn, opt->opr, + opt->index); + break; + case QUERY_DESC_IDN_HEALTH: + rc = do_health_desc(fd); + break; + case QUERY_DESC_IDN_INTERCONNECT: + rc = do_interconnect_desc(fd); + break; + default: + print_error("Unsupported Descriptor type %d", opt->idn); + rc = -EINVAL; + break; + } + +out: + close(fd); + return rc; +} + +void print_attribute(struct attr_fields *attr, __u8 *attr_buffer) +{ + if (attr->width_in_bytes == BYTE) + printf("%-26s := 0x%02x\n", attr->name, attr_buffer[0]); + else if (attr->width_in_bytes == WORD) + printf("%-26s := 0x%04x\n", attr->name, *(__u16 *)attr_buffer); + else if (attr->width_in_bytes == DWORD) + printf("%-26s := 0x%08x\n", attr->name, + be32toh(*(__u32 *)attr_buffer)); +} + +int do_query_rq(int fd, struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp, __u8 query_req_func, + __u8 opcode, __u8 idn, __u8 index, __u8 sel, + __u16 req_buf_len, __u16 res_buf_len, __u8 *data_buf) +{ + int rc = OK; + __u8 res_code; + __u16 len = res_buf_len; + + if (req_buf_len > 0) + len = req_buf_len; + + prepare_upiu(bsg_req, query_req_func, len, opcode, idn, + index, sel); + + rc = send_bsg_scsi_trs(fd, bsg_req, bsg_rsp, req_buf_len, res_buf_len, + data_buf); + + if (rc) { + print_error("%s: query failed, status %d idn: %d, i: %d, s: %d", + __func__, rc, idn, index, sel); + rc = ERROR; + goto out; + } + + res_code = (be32toh(bsg_rsp->upiu_rsp.header.dword_1) >> 8) & 0xff; + if (res_code) { + query_response_error(res_code, idn); + rc = ERROR; + } +out: + return rc; +} + +static int do_write_desc(int fd, struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp, __u8 idn, __u8 index, + __u16 desc_buf_len, __u8 *data_buf) +{ + return do_query_rq(fd, bsg_req, bsg_rsp, + UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + UPIU_QUERY_OPCODE_WRITE_DESC, idn, index, + 0, desc_buf_len, 0, data_buf); +} + +static int check_read_desc_size(__u8 idn, __u8 *data_buf) +{ + bool unoff = false; + int rc = OK; + + switch (idn) { + case QUERY_DESC_IDN_DEVICE: + if ((data_buf[0] != QUERY_DESC_DEVICE_MAX_SIZE) && + (data_buf[0] != QUERY_DESC_DEVICE_MAX_SIZE_3_0)) + unoff = true; + break; + case QUERY_DESC_IDN_CONFIGURAION: + if ((data_buf[0] != QUERY_DESC_CONFIGURAION_MAX_SIZE) && + (data_buf[0] != QUERY_DESC_CONFIGURAION_MAX_SIZE_3_0)) + unoff = true; + break; + case QUERY_DESC_IDN_UNIT: + if ((data_buf[0] != QUERY_DESC_UNIT_MAX_SIZE) && + (data_buf[0] != QUERY_DESC_UNIT_MAX_SIZE_3_0)) + unoff = true; + break; + case QUERY_DESC_IDN_INTERCONNECT: + if (data_buf[0] != QUERY_DESC_INTERCONNECT_MAX_SIZE) + unoff = true; + break; + case QUERY_DESC_IDN_GEOMETRY: + if ((data_buf[0] != QUERY_DESC_GEOMETRY_MAX_SIZE) && + (data_buf[0] != QUERY_DESC_GEOMETRY_MAX_SIZE_3_0)) + unoff = true; + break; + case QUERY_DESC_IDN_POWER: + if (data_buf[0] != QUERY_DESC_POWER_MAX_SIZE) + unoff = true; + break; + case QUERY_DESC_IDN_HEALTH: + if ((data_buf[0] != QUERY_DESC_HEALTH_MAX_SIZE) && + (data_buf[0] != QUERY_DESC_HEALTH_MAX_SIZE_2_1)) + unoff = true; + break; + } + + if (unoff) { + int file_status; + + rc = ERROR; + print_error("Unofficial %s desc size, len = 0x%x", + (char *)desc_text[idn], data_buf[0]); + file_status = write_file("unofficial.dat", data_buf, + data_buf[0]); + if (!file_status) + printf("\nunofficial.dat raw data file was created\n"); + } + + return rc; +} + +int do_read_desc(int fd, struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp, __u8 idn, __u8 index, + __u16 desc_buf_len, __u8 *data_buf) +{ + int rc; + + rc = do_query_rq(fd, bsg_req, bsg_rsp, + UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UPIU_QUERY_OPCODE_READ_DESC, idn, index, 0, + 0, desc_buf_len, data_buf); + if (!rc) + rc = check_read_desc_size(idn, data_buf); + + return rc; +} + +int do_attributes(struct tool_options *opt) +{ + int fd; + int rc = OK; + struct attr_fields *tmp = NULL; + int oflag = O_RDWR; + __u8 att_idn; + __u32 attr_value; + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + + if (opt->opr == READ_ALL || opt->opr == READ) + oflag = O_RDONLY; + + fd = open(opt->path, oflag); + if (fd < 0) { + print_error("open"); + return ERROR; + } + tmp = &ufs_attrs[opt->idn]; + + if (opt->opr == READ_ALL) { + att_idn = QUERY_ATTR_IDN_BOOT_LU_EN; + + while (att_idn < ARRAY_SIZE(ufs_attrs)) { + tmp = &ufs_attrs[att_idn]; + if (tmp->acc_type == ACC_INVALID || + tmp->acc_mode == WRITE_ONLY) { + att_idn++; + continue; + } + + rc = do_query_rq(fd, &bsg_req, &bsg_rsp, + UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UPIU_QUERY_OPCODE_READ_ATTR, att_idn, + opt->index, opt->selector, 0, 0, 0); + if (rc == OK) { + attr_value = be32toh(bsg_rsp.upiu_rsp.qr.value); + print_attribute(tmp, (__u8 *)&attr_value); + } + + memset(&bsg_rsp, 0, BSG_REPLY_SZ); + att_idn++; + } + } else if (opt->opr == WRITE) { + if (tmp->acc_type == ACC_INVALID || + tmp->acc_mode == READ_ONLY) { + print_error("%s Attribute is not writable", tmp->name); + rc = ERROR; + goto out; + } + + attr_value = *(__u32 *)opt->data; + switch (tmp->width_in_bytes) { + case BYTE: + if (attr_value > 0xFF) { + print_error("Wrong write data for %s attr\n", + tmp->name); + rc = ERROR; + goto out; + } + break; + case WORD: + if (attr_value > 0xFFFF) { + print_error("Wrong write data for %s attr\n", + tmp->name); + rc = ERROR; + goto out; + } + break; + case DWORD: + /* avoid -switch warning - no need to check value */ + break; + default: + print_error("Unsupported width %d", + tmp->width_in_bytes); + rc = ERROR; + goto out; + } + + bsg_req.upiu_req.qr.value = htobe32(attr_value); + rc = do_query_rq(fd, &bsg_req, &bsg_rsp, + UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + UPIU_QUERY_OPCODE_WRITE_ATTR, opt->idn, + opt->index, opt->selector, 0, 0, 0); + } else if (opt->opr == READ) { + if (tmp->acc_type == ACC_INVALID || + tmp->acc_mode == WRITE_ONLY) { + print_error("%s attribute is not readable", tmp->name); + rc = ERROR; + goto out; + } + + rc = do_query_rq(fd, &bsg_req, &bsg_rsp, + UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UPIU_QUERY_OPCODE_READ_ATTR, opt->idn, + opt->index, opt->selector, 0, 0, 0); + if (rc == OK) { + attr_value = be32toh(bsg_rsp.upiu_rsp.qr.value); + print_attribute(tmp, (__u8 *)&attr_value); + } + } +out: + close(fd); + return rc; +} + +int do_flags(struct tool_options *opt) +{ + int fd; + int rc = OK; + __u8 opcode, flag_idn; + struct flag_fields *tmp; + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + int oflag = O_RDWR; + + if (opt->opr == READ_ALL || opt->opr == READ) + oflag = O_RDONLY; + + fd = open(opt->path, oflag); + if (fd < 0) { + print_error("open"); + return ERROR; + } + + tmp = &ufs_flags[opt->idn]; + + switch (opt->opr) { + case READ_ALL: + flag_idn = QUERY_FLAG_IDN_FDEVICEINIT; + printf("UFS Device Flags:\n"); + while (flag_idn < QUERY_FLAG_IDN_MAX) { + tmp = &ufs_flags[flag_idn]; + if (tmp->acc_type == ACC_INVALID || + tmp->acc_type == UWRT) { + flag_idn++; + continue; + } + + rc = do_query_rq(fd, &bsg_req, &bsg_rsp, + UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UPIU_QUERY_OPCODE_READ_FLAG, flag_idn, + opt->index, opt->selector, 0, 0, 0); + if (rc == OK) { + printf("%-26s := 0x%01x\n", tmp->name, + be32toh(bsg_rsp.upiu_rsp.qr.value) & + 0xff); + } else { + /* on failuire make note and keep going */ + print_error("Read for flag %s failed", + tmp->name); + } + + memset(&bsg_rsp, 0, BSG_REPLY_SZ); + flag_idn++; + } + break; + case CLEAR_FLAG: + case TOGGLE_FLAG: + case SET_FLAG: + if (tmp->acc_type == ACC_INVALID || + tmp->acc_mode == READ_ONLY) { + print_error("%s flag is not writable", tmp->name); + rc = ERROR; + } else if ((tmp->acc_mode & SET_ONLY) && + opt->opr != SET_FLAG) { + print_error("Only set operation supported for %s flag", + tmp->name); + rc = ERROR; + } else { + if (opt->opr == CLEAR_FLAG) + opcode = UPIU_QUERY_OPCODE_CLEAR_FLAG; + else if (opt->opr == SET_FLAG) + opcode = UPIU_QUERY_OPCODE_SET_FLAG; + else if (opt->opr == TOGGLE_FLAG) + opcode = UPIU_QUERY_OPCODE_TOGGLE_FLAG; + rc = do_query_rq(fd, &bsg_req, &bsg_rsp, + UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + opcode, opt->idn, opt->index, + opt->selector, 0, 0, 0); + if (rc) + print_error("The operation for flag %s failed", + tmp->name); + } + break; + case READ:/*Read operation */ + if (tmp->acc_type == ACC_INVALID || tmp->acc_type == UWRT) { + print_error("%s flag is not readable", tmp->name); + rc = ERROR; + } else { + rc = do_query_rq(fd, &bsg_req, &bsg_rsp, + UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UPIU_QUERY_OPCODE_READ_FLAG, opt->idn, + opt->index, opt->selector, 0, 0, 0); + if (rc == OK) + printf("%-26s := 0x%01x\n", tmp->name, + be32toh(bsg_rsp.upiu_rsp.qr.value) & + 0xff); + else + print_error("Read for flag %s failed", tmp->name); + } + break; + default: + print_error("Unsupported operation for %s flag", tmp->name); + rc = ERROR; + break; + } + + close(fd); + return rc; +} diff --git a/libmtk_bsg/ufs_cmds.h b/libmtk_bsg/ufs_cmds.h new file mode 100644 index 0000000000000000000000000000000000000000..abd68fb12b4c78c2866f0c19275311acd476b48f --- /dev/null +++ b/libmtk_bsg/ufs_cmds.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef UFS_CMNDS_H_ +#define UFS_CMNDS_H_ + +#include "options.h" +#include + + +enum field_width { + BYTE = (1 << 0), + WORD = (1 << 1), + DWORD = (1 << 2), + DDWORD = (1 << 3) +}; + +struct desc_field_offset { + char *name; + int offset; + enum field_width width_in_bytes; +}; + +enum acc_mode { + READ_NRML = (1 << 0), + READ_ONLY = (1 << 1), + WRITE_ONLY = (1 << 2), + WRITE_ONCE = (1 << 3), + WRITE_PRSIST = (1 << 4), + WRITE_VLT = (1 << 5), + SET_ONLY = (1 << 6), + WRITE_PWR = (1 << 7), + MODE_INVALID = (1 << 8) +}; + +enum attr_level { + DEV = (1 << 0), + ARRAY = (1 << 1), + LEVEL_INVALID = (1 << 2) +}; + +enum access_type { + URD = (1 << 0), + UWRT = (1 << 1), + ACC_INVALID = (1 << 2) +}; + +struct attr_fields { + char *name; + enum field_width width_in_bytes; + enum access_type acc_type; + enum acc_mode acc_mode; + enum attr_level device_level; +}; + +struct flag_fields { + char *name; + enum access_type acc_type; + enum acc_mode acc_mode; + enum attr_level device_level; +}; + +int do_desc(struct tool_options *opt); +int do_attributes(struct tool_options *opt); +int do_flags(struct tool_options *opt); +void print_command_help (char *prgname, int config_type); +int do_device_desc(int fd, __u8 *desc_buff); +void desc_help(char *tool_name); +void attribute_help(char *tool_name); +void flag_help(char *tool_name); +#endif /* UFS_CMNDS_H_ */ diff --git a/libmtk_bsg/ufs_err_hist.c b/libmtk_bsg/ufs_err_hist.c new file mode 100644 index 0000000000000000000000000000000000000000..bf7e15d43fa822c689b607fe73ace08748ed65b6 --- /dev/null +++ b/libmtk_bsg/ufs_err_hist.c @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * UFS3.0(UFSv3.0 JESD220D spec.) allows to retrieve the error history by using + * the READ BUFFER command. + */ + +#include "ufs_err_hist.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ufs.h" +#include "ufs_cmds.h" +#include "options.h" +#include "ioctl.h" + +#define MIN(a, b) (((a) < (b))?(a):(b)) +#define MAX(a, b) (((a) > (b))?(a):(b)) + +/* + * The spec actualy says: "and ALLOCATION LENGTH set to at least 2088 + * (i.e., large enough to transfer the complete error history directory)." + * This is apparently an error because it doesn't adds up to the entries + * count and sizes: The error history header is 32bytes, and there can be + * up to (0xEF – 0x10 + 1) = 224 entries. Each entry is 8bytes, so the + * directory should weight 224*8 + 32 = 1824bytes, and not 2088. + */ +#define EHS_DIR_ALLOC_LEN 1824 +/* According to the spec, BUF ID can be between 0x10 0xEF range */ +#define EHS_MIN_BUF_ID 0x10 +#define EHS_MAX_BUF_ID 0xEF +#define EHS_MAX_ENTRIES (EHS_MAX_BUF_ID - EHS_MIN_BUF_ID + 1) +/* 3 bytes for Allocation Length field + 3 bytes for Buffer offset field*/ +#define READ_BUF_MAX_AVAIL_LEN (0xFFFFFF + 0xFFFFFF) +#define BLOCKS_IN_FAD_BLOCK (MAX_IOCTL_BUF_SIZE / BLOCK_SIZE) + +struct ehs_directory_entry { + u_int8_t buffer_id; + u_int8_t reserved[3]; + u_int32_t length; +}; + +struct ehs_directory_header { + u_int8_t vendor_id[8]; + u_int8_t version; + u_int8_t reserved1; + u_int8_t reserved2[20]; + u_int16_t length; +}; + +struct ehs_directory_buffer { + struct ehs_directory_header hdr; + struct ehs_directory_entry entries[EHS_MAX_ENTRIES]; +}; + +static inline int write_single_fad(const int file, const void *buffer, int sz) +{ + if (write(file, buffer, sz) != sz) + return -EIO; + else + return 0; +} + +static int log_ehs_buffer(int fd, int file, __u8 *buf, __u8 buf_id, + __u32 len, __u8 sg_type) +{ + int rc = -EINVAL; + __u32 sent = 0; + int i = 0; + + printf("\nPlease wait for error history extraction\n"); + while (sent < len) { + __u32 ofst = i * MAX_IOCTL_BUF_SIZE; + __u32 sz = + (len - sent >= MAX_IOCTL_BUF_SIZE) ? MAX_IOCTL_BUF_SIZE : + (len - sent); + + rc = read_buffer(fd, buf, BUFFER_EHS_MODE, buf_id, ofst, sz, + sg_type); + if (rc) { + print_error("read_buffer buff_id 0x%x fad %d", + buf_id, i); + goto out; + } + + rc = write_single_fad(file, buf, sz); + if (rc) { + print_error("write buf_id 0x%x fad %d", buf_id, i); + goto out; + } + + sent += sz; + i++; + memset(buf, 0x0, MAX_IOCTL_BUF_SIZE); + } + + rc = 0; +out: + return rc; +} + +static int log_error_history(int fd, struct ehs_directory_entry *entries, + __u8 buffers_cnt, __u8 sg_type) +{ + int file; + __u8 *buf = NULL; + int rc = -EINVAL; + int i; + + file = open("error_history.dat", O_RDWR | O_CREAT | O_TRUNC | O_SYNC, + S_IWUSR | S_IRUSR); + if (file == -1) { + perror("open"); + goto out; + } + + /* IO size is limited by max_sectors_kb which is usually 512k - set a + * slightly smaller chunk - 256k. + */ + buf = calloc(1, MAX_IOCTL_BUF_SIZE); + if (!buf) { + rc = -ENOMEM; + goto out; + } + + for (i = 0; i < buffers_cnt; i++) { + struct ehs_directory_entry *entry = entries + i; + u_int8_t buf_id = entry->buffer_id; + u_int32_t len = be32toh(entry->length); + + if (buf_id < EHS_MIN_BUF_ID || buf_id > EHS_MAX_BUF_ID) { + print_error("illegal buffer id 0x%x entry %d", + buf_id, i); + goto out; + } + + if (!len || len > READ_BUF_MAX_AVAIL_LEN) { + print_error("illegal len 0x%x entry %d", len, i); + goto out; + } + + rc = log_ehs_buffer(fd, file, buf, buf_id, len, sg_type); + if (rc) { + print_error("log_ehs_buffer buffer id 0x%x", buf_id); + goto out; + } + } + + rc = 0; +out: + if (buf) + free(buf); + + if (file != -1) + close(file); + return rc; +} + +static int decode_ehs_directory(struct ehs_directory_buffer *ehs_dir, + __u8 *buffers_cnt) +{ + int rc = -EINVAL; + u_int16_t length = 0; + + if (!ehs_dir) + goto out; + + length = be16toh(ehs_dir->hdr.length); + if (!length || length % sizeof(struct ehs_directory_entry)) { + print_error("Illegal directory length 0x%x", length); + goto out; + } + + *buffers_cnt = length / sizeof(struct ehs_directory_entry); + if (*buffers_cnt > EHS_MAX_ENTRIES) { + print_error("Illegal buffers count %d", *buffers_cnt); + goto out; + } + + rc = 0; +out: + return rc; +} + +int do_err_hist(struct tool_options *opt) +{ + int rc = INVALID; + int fd; + __u8 *ehs_buf = NULL; + struct ehs_directory_buffer *ehs_dir = NULL; + __u8 ehs_buffer_cnt = 0; + + fd = open(opt->path, O_RDWR | O_SYNC); + if (fd < 0) { + perror("open"); + return ERROR; + } + + WRITE_LOG("Start : %s cmd type %d", __func__, opt->idn); + ehs_buf = calloc(1, EHS_DIR_ALLOC_LEN); + if (!ehs_buf) { + rc = -ENOMEM; + goto out; + } + + rc = read_buffer(fd, ehs_buf, BUFFER_EHS_MODE, 0, 0, + EHS_DIR_ALLOC_LEN, opt->sg_type); + if (rc) + goto out; + + rc = write_file("error_history_directory.dat", ehs_buf, + EHS_DIR_ALLOC_LEN); + if (rc) + goto out; + + printf("error_history_directory.dat is created\n"); + + ehs_dir = (struct ehs_directory_buffer *)ehs_buf; + rc = decode_ehs_directory(ehs_dir, &ehs_buffer_cnt); + if (rc) + goto out; + + printf("retrieving error history, this may take a while\n\n"); + rc = log_error_history(fd, ehs_dir->entries, ehs_buffer_cnt, + opt->sg_type); + if (rc) + goto out; + + printf("\nerror_history.dat is created\n"); + +out: + if (ehs_buf) + free(ehs_buf); + close(fd); + + return rc; +} + +void err_hist_help(char *tool_name) +{ + printf("\n Error history command usage:\n"); + printf("\n\t%s err_hist [-p]  \n", tool_name); + printf("\n\t-g\tsg struct ver - 0: SG_IO_VER4 (default), 1: SG_IO_VER3\n"); + printf("\n\t-p\tPath to the bsg device\n"); +} diff --git a/libmtk_bsg/ufs_err_hist.h b/libmtk_bsg/ufs_err_hist.h new file mode 100644 index 0000000000000000000000000000000000000000..bb83fe96d28336b5460b770cbc737e444755262b --- /dev/null +++ b/libmtk_bsg/ufs_err_hist.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef UFS_ERR_HIST_H_ +#define UFS_ERR_HIST_H_ +#include "options.h" + +void err_hist_help(char *tool_name); +int do_err_hist(struct tool_options *opt); +#endif /*UFS_ERR_HIST_H_*/ diff --git a/libmtk_bsg/ufs_ffu.c b/libmtk_bsg/ufs_ffu.c new file mode 100644 index 0000000000000000000000000000000000000000..956d82be7e45cfbc411041d31d9320a9c0ea51b3 --- /dev/null +++ b/libmtk_bsg/ufs_ffu.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#pragma GCC diagnostic ignored "-Wall" +#pragma GCC diagnostic ignored "-Wextra" +#pragma GCC diagnostic ignored "-Wsign-compare" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ufs.h" +#include "ufs_cmds.h" +#include "options.h" +#include "ioctl.h" +#include "ufs_ffu.h" +#include "scsi_bsg_util.h" + +#define DEVICE_VERSION_OFFSET 0x1E +#define FFU_STATUS_ATTR 0x14 + +enum ffu_status_type { + NO_INFORMATION, + SUCCESSFUL_MICROCODE_UPDATE, + MICROCODE_CORRUPTION_ERROR, + INTERNAL_ERROR, + MICROCODE_VERSION_MISMATCH, + GENERAL_ERROR = 0xFF +}; + + +extern int do_query_rq(int fd, struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp, __u8 query_req_func, + __u8 opcode, __u8 idn, __u8 index, __u8 sel, + __u16 req_buf_len, __u16 res_buf_len, __u8 *data_buf); +extern struct desc_field_offset device_desc_field_name[]; + +/* Get sense key string or NULL if not available */ +static const char * +ffu_status_string(enum ffu_status_type status) +{ + switch (status) { + case NO_INFORMATION: + return "NO INFORMATION"; + break; + case SUCCESSFUL_MICROCODE_UPDATE: + return "SUCCESSFUL MICROCODE UPDATE"; + break; + case INTERNAL_ERROR: + return "INTERNAL ERROR"; + break; + case MICROCODE_CORRUPTION_ERROR: + return "MICROCODE CORRUPTION ERROR"; + break; + case GENERAL_ERROR: + return "GENERAL ERROR"; + break; + default: + return "UNSUPPORTED STATUS"; + break; + } + return 0; +} + +static int flash_ffu(int fd, struct tool_options *opt) +{ + int rc = INVALID; + int input_fd = INVALID; + off_t file_size; + __u8 *p_data = NULL; + uint32_t chunk_size = opt->size; + uint32_t buf_offset = 0; + uint32_t write_buf_count; + + input_fd = open(opt->data, O_RDONLY | O_SYNC); + if (input_fd < 0) { + perror("Input file open"); + goto out; + } + + file_size = lseek(input_fd, 0, SEEK_END); + /* The FFU file shall be aligned to 4k */ + if ((file_size <= 0) || (file_size % ALIGNMENT_CHUNK_SIZE)) { + print_error("Wrong FFU file"); + goto out; + } + lseek(input_fd, 0, SEEK_SET); + p_data = calloc(file_size, sizeof(__u8)); + if (!p_data) { + print_error("Cannot allocate FFU size %d", file_size); + goto out; + } + if (read(input_fd, (char *)p_data, file_size) != + file_size) { + print_error("Read FFU is failed"); + goto out; + } + + while (file_size > 0) { + if (file_size > chunk_size) + write_buf_count = chunk_size; + else + write_buf_count = file_size; + rc = write_buffer(fd, p_data + buf_offset, BUFFER_FFU_MODE, 0, + buf_offset, write_buf_count, opt->sg_type); + if (rc) { + print_error("Write error %d:", rc); + goto out; + } + buf_offset = buf_offset + write_buf_count; + file_size = file_size - write_buf_count; + } + + sync(); + printf("\nFFU was written to the device, reboot and check status\n"); + +out: + if (input_fd != INVALID) + close(input_fd); + if (p_data) + free(p_data); + return rc; + +} + +static int check_ffu_status(int fd, struct tool_options *opt) +{ + int rc = ERROR; + __u8 dev_desc[QUERY_DESC_DEVICE_MAX_SIZE] = {0}; + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + __u32 attr_value; + __u16 *ufs_feature_support; + struct desc_field_offset *tmp = &device_desc_field_name[DEVICE_VERSION_OFFSET]; + + rc = do_query_rq(fd, &bsg_req, &bsg_rsp, + UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UPIU_QUERY_OPCODE_READ_ATTR, FFU_STATUS_ATTR, + 0, 0, 0, 0, 0); + if (rc) { + print_warn("cannot read bDeviceFFUStatus attribute status"); + goto out; + } + + else { + attr_value = be32toh(bsg_rsp.upiu_rsp.qr.value); + printf("%-20s := 0x%02x (%s)\n", "bDeviceFFUStatus", + attr_value, + ffu_status_string((enum ffu_status_type)attr_value)); + } + + rc = do_device_desc(fd, (__u8 *)&dev_desc); + if (rc != OK) + print_error("Could not read device descriptor in order to " + "read device version\n"); + else { + ufs_feature_support = (__u16 *)&dev_desc[tmp->offset]; + printf("%s = 0x%x\n", tmp->name, *ufs_feature_support); + } +out: + return rc; +} + +int do_ffu(struct tool_options *opt) +{ + int rc = INVALID; + int fd = INVALID; + + fd = open(opt->path, O_RDWR | O_SYNC); + if (fd < 0) { + perror("open"); + exit(1); + } + + switch (opt->idn) { + case UFS_FFU: + rc = flash_ffu(fd, opt); + break; + case UFS_CHECK_FFU_STATUS: + rc = check_ffu_status(fd, opt); + break; + default: + print_error("Unsupported FFU type operation"); + break; + } + + close(fd); + return rc; +} + +void ffu_help(char *tool_name) +{ + printf("\n FFU command usage:\n"); + printf("\n\t%s ffu [-t] [-p]  \n", + tool_name); + printf("\n\t-t\t FFU cmd idn\n"); + printf("\t\t\t %-3d: %-25s\n", + UFS_FFU, + "FFU, flash FFU"); + printf("\t\t\t %-3d: %-25s\n", + UFS_CHECK_FFU_STATUS, + "Check FFU status (check FFU status attribute and display FW version)"); + printf("\n\t-s\t Max chunk size in KB alignment to 4KB, " + "which FFU file will be split (optional)\n"); + printf("\n\t-w\t path to FFU file\n"); + printf("\n\t-g\t sg struct ver - 0: SG_IO_VER4 (default), 1: SG_IO_VER3\n"); + printf("\n\t-p\t bsg device path for FFU, ufs-bsg for Check FFU status\n"); +} diff --git a/libmtk_bsg/ufs_ffu.h b/libmtk_bsg/ufs_ffu.h new file mode 100644 index 0000000000000000000000000000000000000000..beefd072bb697317ac5e9657eb970c1d4c6269f3 --- /dev/null +++ b/libmtk_bsg/ufs_ffu.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef UFS_FFU_H_ +#define UFS_FFU_H_ + + +enum ffu_type { + UFS_FFU = 0, + UFS_CHECK_FFU_STATUS, + UFS_FFU_MAX +}; + +void ffu_help(char *tool_name); +int do_ffu(struct tool_options *opt); +#endif /*UFS_FFU_H_*/ diff --git a/libmtk_bsg/ufs_hmr.c b/libmtk_bsg/ufs_hmr.c new file mode 100644 index 0000000000000000000000000000000000000000..92c3e0c8f5d44aa54caacdaaa5fd88384cdaa040 --- /dev/null +++ b/libmtk_bsg/ufs_hmr.c @@ -0,0 +1,1182 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#pragma GCC diagnostic ignored "-Wall" +#pragma GCC diagnostic ignored "-Wextra" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wpointer-bool-conversion" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ufs.h" +#include "ufs_hmr.h" +#include "ufs_cmds.h" + +/* + * HMR Quirks: 1 - enable, 0 - disable + */ + +/* + * Big-little-endian byte order: some params + * may occur in order other than expected. + * Change byte order for the following params. + */ +#define HMR_QUIRK_REFRESH_TOTCOUNT_BYTE_ORDER 1 +#define HMR_QUIRK_REFRESH_PROGRESS_BYTE_ORDER 1 + +/* + * There is the maximum number of HMR operations in the life + * of the device. Having reached this number, the device will + * return "General Failure" and set the bRefreshStatus attribute + * to 0x05. + */ +#define HMR_REFRESH_MAX_TOTCOUNT 200 + +/* + * Output progress every N iterations. + */ +#define HMR_PROGRESS_OUTPUT_ITER 1 +#if HMR_PROGRESS_OUTPUT_ITER <= 0 +# error keep HMR_PROGRESS_OUTPUT_ITER > 0 +#endif + +/* + * The HMR mode type description string size we + * support to output. Can be enlarged if required. + */ +#define HMR_MODE_TYPE_MAX_SIZE 40 + +enum hmr_err_codes { + EHMR_OK = 0, /* success */ + EHMR_REFRESH_PROGRESS = 100, /* wrong refresh progress */ + EHMR_REFRESH_STATUS, /* wrong refresh status */ + EHMR_REFRESH_TOTCOUNT, /* wrong refresh total count */ + EHMR_FREEMEM, /* memory wasn't freed */ + EHMR_NOMEM, /* not enough memory */ + EHMR_INVAL, /* invalid argument */ + EHMR_NORETRY, /* cannot be retried */ + EHMR_REFRESH_METHOD, /* wrong refrresh method */ + EHMR_REFRESH_UNIT, /* wrong refrresh unit */ +}; + +enum hmr_refresh_status { + HMR_ST_IDLE = 0, + HMR_ST_IN_PROGRESS, + HMR_ST_ABORTED, + HMR_ST_COMPLETED, + HMR_ST_BUSY, + HMR_ST_GENERAL, +}; + +enum hmr_stage_skip { + HMR_SKIP_STATUS_CHECK = 1 << 0, + HMR_SKIP_METHOD_SET = 1 << 1, + HMR_SKIP_UNIT_SET = 1 << 2, +}; + +#pragma pack(push, 1) +struct descriptor_health_layout { + __u8 length; + __u8 type; + __u8 pre_eol_info; + __u8 dev_life_time_est_a; + __u8 dev_life_time_est_b; + __u8 vendor_prop_info[0x20]; + __u32 refresh_total_count; + __u32 refresh_progress; +}; +#pragma pack(pop) + +struct descriptor { + enum desc_idn idn; + const char *name; + size_t size; + void *layout; +}; + +extern int do_query_rq(int fd, + struct ufs_bsg_request *bsg_req, /* request struct of the sg_io_v4 */ + struct ufs_bsg_reply *bsg_rsp, /* response struct of the sg_io_v4 */ + __u8 query_req_func, /* read / write */ + __u8 opcode, /* opcode r/w of desc/attr/fl etc.*/ + __u8 idn, /* (-t) util option */ + __u8 index, /* (-i) util option */ + __u8 sel, /* (-s) util option */ + __u16 req_buf_len, /* request buffer size */ + __u16 res_buf_len, /* response buffer size */ + __u8 *data_buf); /* buffer with/for data */ + +extern struct desc_field_offset device_health_desc_conf_field_name[]; +extern struct attr_fields ufs_attrs[]; +extern struct flag_fields ufs_flags[]; + +static struct descriptor_health_layout desc_health_layout; + +static struct descriptor desc_health = { + QUERY_DESC_IDN_HEALTH, + "Health", + sizeof desc_health_layout, + &desc_health_layout +}; + +static inline void hmr_delay_retry(int sec) +{ + if (sec > 0) + sleep(sec); +} + +static inline void hmr_output_message(const char *msg) +{ + /* + * |---------------------------------------------------------| + * | Message format template: | + * |---------------------------------------------------------| + * |<<-6->| |<<-29-> | + * |HMR: | |variable string | + * | | + * |---------------------------------------------------------| + * |HMR: | |waiting idle status | + * |---------------------------------------------------------| + */ + printf("%-6s %-29s\r", "HMR:", msg); + fflush(stdout); +} + +static inline void hmr_output_progress(__u32 progress, + __u64 iter, int sec, const char *msg) +{ + /* + * |---------------------------------------------------------| + * | Progress format template: | + * |---------------------------------------------------------| + * |<<-6->| | <-9->>| |<<-35-> | + * |HMR: | | hex dig| |variable string | + * | | + * |---------------------------------------------------------| + * | The case of up to 100% progress: | + * |---------------------------------------------------------| + * |<<-6->| | <-9->>| |<<-35-> | + * |HMR: | | f20a| | | + * | | | | | | + * |---------------------------------------------------------| + * | The case of 100% progress: | + * |---------------------------------------------------------| + * |<<-6->| | <-8->>| |<<-20-> | + * |HMR: | | 100|% | | + * |---------------------------------------------------------| + */ + + /* + * Completed - print 100%, + * otherwise print hex progress indicator every N iterations. + */ + if (!progress) + printf("%-6s %8d%% %-20s\r", "HMR:", 100, msg); + else if (0 == (iter % HMR_PROGRESS_OUTPUT_ITER)) + printf("%-6s %9x %-20s\r", "HMR:", progress, msg); + + fflush(stdout); + if (sec > 0) + sleep(sec); +} + +static inline void hmr_output_header(const char *unit_str, int method) +{ + int count; + const char *method_str; + char mode_str[HMR_MODE_TYPE_MAX_SIZE]; + + method_str = method == HMR_METHOD_FORCE ? "force" : "selective"; + + count = snprintf(mode_str, sizeof mode_str, "method:%s, unit:%s", + method_str, unit_str); + + if (count >= HMR_MODE_TYPE_MAX_SIZE) + ; /* the output was truncated, enlarge HMR_MODE_TYPE_MAX_SIZE */ + + /* + * |---------------------------------------------------------| + * | Header format template: | + * |---------------------------------------------------------| + * |<<-6->| | <-9->>| |<<-35-> | + * |HMR: | | status| |mode type | + * | | + * |---------------------------------------------------------| + * | Examples: | + * |---------------------------------------------------------| + * |HMR: | | started| |method:selective, unit:minimum | + * | | | | | | + * |---------------------------------------------------------| + * |HMR: | | started| |method:force, unit:full | + * | | | | | | + * |---------------------------------------------------------| + */ + printf("%-6s %9s %-30s\n", "HMR:", "started", mode_str); + fflush(stdout); +} + +static inline void hmr_output_footer(int rc) +{ + /* + * |---------------------------------------------------------| + * | Footer format template: | + * |---------------------------------------------------------| + * |<<-6->| | <-9->>| |<<-35-> | + * |HMR: | | status| |error msg / code | + * | | + * |---------------------------------------------------------| + * | Examples: | + * |---------------------------------------------------------| + * |HMR: | |completed| | OK | + * | | | | | | + * |---------------------------------------------------------| + * |HMR: | | stopped| |-115 | + * | | | | | | + * |---------------------------------------------------------| + */ + + /* + * Leading LF is due to CR-ending on progress print out. + * In case of error LF was already sent with the error msg. + */ + if (0 == rc) + printf("\n%-6s %9s %-30s\n", "HMR:", "completed", "OK"); + else + printf("%-6s %9s %-30d\n", "HMR:", "stopped", rc); + + fflush(stdout); +} + +static inline void hmr_query_error(int rc, + const char *job_type, /* write/read/set/clear/etc. */ + const char *subject, /* desc/attr/flag/etc. */ + int opcode, /* opcode r/w of desc/attr/fl etc. */ + const char *field_name, /* name of the operated field */ + int field_idn) /* index of the field */ +{ + print_error("hmr: query command: %s %s failed: " + "opcode 0x%x, field-name %s, field-idn 0x%x, rc %d.\n", + job_type, subject, opcode, field_name, field_idn); +} + +static inline int hmr_attr_sanity(enum attr_idn idn) +{ + if (idn < 0 || idn >= QUERY_ATTR_IDN_MAX) + return -EHMR_INVAL; + + return EHMR_OK; +} + +static inline int hmr_flag_sanity(enum flag_idn idn) +{ + if (idn < 0 || idn >= QUERY_FLAG_IDN_MAX) + return -EHMR_INVAL; + + return EHMR_OK; +} + +static inline int hmr_desc_sanity(enum desc_idn idn) +{ + if (idn < 0 || idn >= QUERY_DESC_IDN_MAX) + return -EHMR_INVAL; + + return EHMR_OK; +} + +static int hmr_dev_open(const char* path, int *fd) +{ + int rc = 0; + + errno = 0; + + *fd = open(path, O_RDWR); + if (*fd < 0) { + rc = errno; /* save errno: errno can be changed by the print */ + print_error("hmr: %s: '%s'", strerror(rc), path); + } + + return rc == 0 ? rc : -rc; +} + +static int hmr_dev_close(const char* path, int fd) +{ + int rc; + + errno = 0; + + rc = close(fd); + if (rc) { + rc = errno; + print_error("hmr: %s: '%s'", strerror(rc), path); + } + + return rc == 0 ? rc : -rc; +} + +static int hmr_attr_read(__u32 *result, + int fd, + struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp, + enum attr_idn idn) +{ + int rc; + struct attr_fields *field; + + if (hmr_attr_sanity(idn) != EHMR_OK || !result) + return -EHMR_INVAL; + + field = &ufs_attrs[idn]; + + /* Query to read attribute */ + rc = do_query_rq(fd, + bsg_req, + bsg_rsp, + UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UPIU_QUERY_OPCODE_READ_ATTR, + idn, + 0, + 0, + 0, + 0, + 0); + + if (rc) { + hmr_query_error(rc, "read", "attr", UPIU_QUERY_OPCODE_READ_ATTR, + field->name, idn); + goto out; + } + + *result = be32toh(bsg_rsp->upiu_rsp.qr.value); + +out: + return rc; +} + +static int hmr_attr_write(__u32 value, + int fd, + struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp, + enum attr_idn idn) +{ + int rc; + struct attr_fields *field; + + if (hmr_attr_sanity(idn) != EHMR_OK) + return -EHMR_INVAL; + + field = &ufs_attrs[idn]; + + bsg_req->upiu_req.qr.value = htobe32(value); + + /* Query to write attribute */ + rc = do_query_rq(fd, + bsg_req, + bsg_rsp, + UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + UPIU_QUERY_OPCODE_WRITE_ATTR, + idn, + 0, + 0, + 0, + 0, + 0); + + if (rc) + hmr_query_error(rc, "write", "attr", UPIU_QUERY_OPCODE_WRITE_ATTR, + field->name, idn); + + return rc; +} + +static int hmr_flag_modify(int fd, + struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp, + enum query_opcode opcode, + enum flag_idn idn) +{ + int rc; + struct flag_fields *field; + + if (opcode != UPIU_QUERY_OPCODE_SET_FLAG && + opcode != UPIU_QUERY_OPCODE_CLEAR_FLAG && + opcode != UPIU_QUERY_OPCODE_TOGGLE_FLAG) + return -EHMR_INVAL; + + if (hmr_flag_sanity(idn) != EHMR_OK) + return -EHMR_INVAL; + + field = &ufs_flags[idn]; + + /* Query to set/clear/toggle flag */ + rc = do_query_rq(fd, + bsg_req, + bsg_rsp, + UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST, + opcode, + idn, + 0, + 0, + 0, + 0, + 0); + + if (rc) + hmr_query_error(rc, "modify", "flag", opcode, field->name, idn); + + return rc; +} + +static int hmr_desc_read(struct descriptor *result, + int fd, + struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp, + enum desc_idn idn) +{ + int rc; + + if (hmr_desc_sanity(idn) != EHMR_OK || + !result || + !result->layout || + result->size <= 0) + return -EHMR_INVAL; + + /* Query to read descriptor */ + rc = do_query_rq(fd, + bsg_req, + bsg_rsp, + UPIU_QUERY_FUNC_STANDARD_READ_REQUEST, + UPIU_QUERY_OPCODE_READ_DESC, + idn, + 0, + 0, + 0, + result->size, + result->layout); + + if (rc) + hmr_query_error(rc, "read", "desc", UPIU_QUERY_OPCODE_READ_DESC, + result->name, idn); + + return rc; +} + +static int hmr_progress_read(__u32 *result, + int fd, + struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp) +{ + int rc; + struct descriptor *desc; + struct descriptor_health_layout *layout; + + desc = &desc_health; + + /* Read descriptor Health */ + rc = hmr_desc_read(desc, + fd, + bsg_req, + bsg_rsp, + desc->idn); + + if (rc) + goto out; + + layout = desc->layout; + + if (!HMR_QUIRK_REFRESH_PROGRESS_BYTE_ORDER) + *result = be32toh(layout->refresh_progress); + else + *result = layout->refresh_progress; + + return rc; + +out: + print_error("hmr: read progress: failed."); + return rc; +} + +static int inline hmr_method_set(int fd, int method) +{ + int rc; + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + + /* Set attribute bRefreshMethod - force or selective */ + rc = hmr_attr_write(method, + fd, &bsg_req, &bsg_rsp, QUERY_ATTR_IDN_REFRESH_METHOD); + + return rc; +} + +static inline int hmr_unit_set(int fd, int unit) +{ + int rc; + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + + /* Set attribute bRefreshUnit - minimum or full */ + rc = hmr_attr_write(unit, + fd, &bsg_req, &bsg_rsp, QUERY_ATTR_IDN_REFRESH_UNIT); + + return rc; +} + +static inline int hmr_precondition_verify_status(int fd, + struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp) +{ + int rc; + int cur = 0; + int count = 10; + __u32 result; + +retry: + /* Read refresh status */ + rc = hmr_attr_read(&result, + fd, + bsg_req, + bsg_rsp, + QUERY_ATTR_IDN_REFRESH_STATUS); + if (rc) + goto out; + + if (result != HMR_ST_IDLE) { + /* One time only */ + if (0 == cur) + hmr_output_message("waiting idle status"); + + /* Retry */ + if (++cur <= count) { + hmr_delay_retry(1); + goto retry; + } + + /* Error */ + print_error("hmr: precondition: " + "refresh status != 0x%x (0x%x)", HMR_ST_IDLE, result); + rc = -EHMR_REFRESH_STATUS; + } + +out: + return rc; +} + +static inline int hmr_precondition_validate_totcount(__u32 *result, + struct descriptor_health_layout *layout) +{ + int rc = EHMR_OK; + __u32 refresh_totcount; + + if (!result || !layout) + return -EHMR_INVAL; + + if (!HMR_QUIRK_REFRESH_TOTCOUNT_BYTE_ORDER) + refresh_totcount = be32toh(layout->refresh_total_count); + else + refresh_totcount = layout->refresh_total_count; + + if (refresh_totcount >= HMR_REFRESH_MAX_TOTCOUNT) { + print_error("hmr: precondition: " + "refresh total count >= max (0x%x >= 0x%x).", + refresh_totcount, HMR_REFRESH_MAX_TOTCOUNT); + rc = -EHMR_REFRESH_TOTCOUNT; + goto out; + } + + *result = refresh_totcount; + +out: + return rc; +} + +static inline void hmr_output_wrong_run(int method, int unit) +{ + print_error("hmr: precondition: device's hmr-progress is not empty. " + "Run is possible only with the method: %d, unit: %d", + method, unit); +} + +static int hmr_precondition_verify_run(int fd, + int req_method, int req_unit, enum hmr_stage_skip *stage_passer) +{ + int rc; + __u32 dev_method; + __u32 dev_unit; + __u32 dev_progress; + + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + + if (!stage_passer) + return -EHMR_INVAL; + + /* + * This code is intended to solve the case when the + * utility was run while HMR progress is not empty. + * It can happen, for example, when running the utility + * in one mode, then exit and run it again in some + * other mode, while the underline device's HMR status + * is still in progress. + * + * Let's make the policy simple: + * 1. Refresh progress is 0 -> OK. + * 2. Requested method equal device method + * and + * Requested unit equal device unit + * 1) Unit is minimum -> OK. + * 2) Unit is full -> OK, but have to skip the check for + * refresh status to be "idle", since + * in this mode it is "in-progress" + * until the HMR is completed. + * 3. Any other case is considered as violation. + */ + + /* Read progress */ + rc = hmr_progress_read(&dev_progress, fd, &bsg_req, &bsg_rsp); + if (rc) + goto out; + + /* Clean run, may proceed with HMR */ + if (0 == dev_progress) + goto out; + + /* Read method */ + rc = hmr_attr_read(&dev_method, + fd, + &bsg_req, + &bsg_rsp, + QUERY_ATTR_IDN_REFRESH_METHOD); + if (rc) + goto out; + + /* Read unit */ + rc = hmr_attr_read(&dev_unit, + fd, + &bsg_req, + &bsg_rsp, + QUERY_ATTR_IDN_REFRESH_UNIT); + if (rc) + goto out; + + /* Method is different, set error */ + if (req_method != dev_method) { + hmr_output_wrong_run(dev_method, dev_unit); + rc = -EHMR_REFRESH_UNIT; + goto out; + } + + /* Unit is different, set error */ + if (req_unit != dev_unit) { + hmr_output_wrong_run(dev_method, dev_unit); + rc = -EHMR_REFRESH_METHOD; + goto out; + } + + /* + * The progress is not empty, and method/unit are the same. + * + * 1. Unit type is full? - skip the refresh status check, + * since it will never be completed/idle in this mode until ends. + * 2. Skip set method and unit, no need - the values are already set. + */ + if (dev_unit == HMR_UNIT_FULL) + *stage_passer |= HMR_SKIP_STATUS_CHECK; + + *stage_passer |= (HMR_SKIP_METHOD_SET | HMR_SKIP_UNIT_SET); + +out: + return rc; +} + +static int hmr_precondition_verify(int fd, + struct tool_options *opt, __u32 *totcount, + enum hmr_stage_skip *stage_passer) +{ + int rc; + struct descriptor *desc; + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + + if (!opt || !totcount || !stage_passer) + return -EHMR_INVAL; + + /* + * 1. Verify the run perspective. + * + * In case of non-empty progress, make a decision + * if the run still can be proceeded. + */ + rc = hmr_precondition_verify_run(fd, + opt->hmr_method, opt->hmr_unit, stage_passer); + if (rc) + goto err; + + /* + * 2. Verify refresh total count. + * + * Note: the Health descriptor was already read in + * hmr_precondition_verify_run(), so updated + * refresh total count is already available. + */ + desc = &desc_health; + rc = hmr_precondition_validate_totcount(totcount, desc->layout); + if (rc) + goto err; + + /* Skip the refresh status check */ + if (*stage_passer & HMR_SKIP_STATUS_CHECK) + goto success; + + /* + * 3. Verify refresh status. + * + * Read refresh status. + * In case the status is not Idle - retry. + * + * We are expecting here to get the Idle status (0x00), + * but in some cases the status may be different: + * aborted (0x02), completed (0x03), etc. + * + * Usually, the statuses of this kind are saved until + * the first reading of the attribute is occured, then + * the value o the attribute should be change to Idle (0x00), + * but let's be generous and give it a sufficient number of + * retries. + */ + rc = hmr_precondition_verify_status(fd, &bsg_req, &bsg_rsp); + if (rc) + goto err; + +success: + return rc; + +err: + print_error("hmr: precondition failed."); + return rc; +} + +static inline int hmr_postcondition_verify_progress(int fd, + struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp) +{ + int rc; + __u32 result; + + /* Read Health descriptor, and get refresh progress field */ + rc = hmr_progress_read(&result, fd, bsg_req, bsg_rsp); + if (rc) + goto out; + + /* Progress should be 0 on HMR completion */ + if (result != 0) { + print_error("hmr: postcondition: " + "refresh progress != 0x0 (0x%x).", result); + rc = -EHMR_REFRESH_PROGRESS; + goto out; + } + +out: + return rc; +} + +static inline int hmr_postcondition_verify_status(int fd, + struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp) +{ + int rc; + __u32 result; + + /* Read refresh status */ + rc = hmr_attr_read(&result, + fd, + bsg_req, + bsg_rsp, + QUERY_ATTR_IDN_REFRESH_STATUS); + + if (rc) + goto out; + + /* The accepted statuses are Completed and Idle */ + if (result != HMR_ST_COMPLETED && result != HMR_ST_IDLE) { + print_error("hmr: postcondition: " + "refresh status != (0x%x or 0x%x) (0x%x)", + HMR_ST_COMPLETED, HMR_ST_IDLE, result); + rc = -EHMR_REFRESH_STATUS; + goto out; + } + +out: + return rc; +} + +static inline int hmr_postcondition_verify_totcount(__u32 prev_totcount, + struct descriptor_health_layout *layout) +{ + int rc = EHMR_OK; + __u32 result; + + if (!layout) + return -EHMR_INVAL; + + if (!HMR_QUIRK_REFRESH_TOTCOUNT_BYTE_ORDER) + result = be32toh(layout->refresh_total_count); + else + result = layout->refresh_total_count; + + if (result <= prev_totcount) { + print_error("hmr: postcondition: " + "refresh total count 0x%x <= 0x%x.", + prev_totcount, result); + rc = -EHMR_REFRESH_TOTCOUNT; + } + + return rc; +} + +static int hmr_postcondition_verify(int fd, __u32 totcount) +{ + int rc; + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + struct descriptor *desc; + + desc = &desc_health; + + /* + * 1. Verify refresh progress. + * + * Progress equal to 0 indicates refresh was completed. + */ + rc = hmr_postcondition_verify_progress(fd, &bsg_req, &bsg_rsp); + if (rc) + goto err; + + /* + * 2. Check refresh status. + * + * The expected value is Completed (0x03) in first read, + * and Idle (0x00) in any following read (assuming no new + * HMR process begins). + * Perhaps, depending on the type of test, the first reading + * has already taken place. Therefore, we may consider both + * values to be valid. + */ + rc = hmr_postcondition_verify_status(fd, &bsg_req, &bsg_rsp); + if (rc) + goto err; + + /* + * 3. Verify refresh total count. + * + * Refresh total count expected to be increased + * upon completion. + * + * The health descriptor was already read in step 1 + * doing hmr_progress_read(). Just use its layout. + */ + rc = hmr_postcondition_verify_totcount(totcount, desc->layout); + if (rc) + goto err; + + /* Success */ + return rc; + +err: + print_error("hmr: postcondition failed."); + return rc; +} + +static inline int hmr_refresh_initiate_retry(int fd, + struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp, + int cur, + int count) +{ + int rc; + __u32 result; + + if (cur > count) + return -EHMR_NORETRY; + + /* + * Read refresh status. + * Then retry only in case the status is Busy. + */ + rc = hmr_attr_read(&result, + fd, + bsg_req, + bsg_rsp, + QUERY_ATTR_IDN_REFRESH_STATUS); + + if (rc) + goto out; + + /* Other than Busy - canot be retried */ + if (result != HMR_ST_BUSY) { + rc = -EHMR_NORETRY; + goto out; + } + +out: + /* 0 - can be retried, otherwise cannot */ + return rc; +} + +static int hmr_refresh_initiate(int fd, + struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp) +{ + int rc; + int err; + int cur = 0; + int count = 10; + + /* + * Initiate refresh. + * For that, set flag fRefreshEnable to 1. + * In case device command queues are not empty, + * this query request may fail. In such a case + * the bRefreshStatus attribite shell be set to + * 0x04 - HMR_ST_BUSY. This case is handled by + * hmr_refresh_initiate_retry(). + */ +retry: + rc = hmr_flag_modify(fd, bsg_req, bsg_rsp, + UPIU_QUERY_OPCODE_SET_FLAG, + QUERY_FLAG_IDN_REFRESH_ENABLE); + + /* Success */ + if (!rc) + goto out; + + /* Check query can be retried */ + err = hmr_refresh_initiate_retry(fd, bsg_req, bsg_rsp, ++cur, count); + if (!err) { + hmr_delay_retry(1); + goto retry; + } + + print_error("hmr: initiate unit refresh: setting flag " + "fRefreshEnable failed after %d retries (%d).", count, rc); + +out: + return rc; +} + +static int hmr_unit_verify_completed(int fd, + struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp) +{ + __u32 result; + int rc; + int cur = 0; + int count = 10; + + /* + * Read refresh status. + * + * The expected status is Completed, which changes to Idle + * after it was read once. Thus, if a given attribute reads + * some other process, then we are in a race state and there + * is a possibility that the attribute value will be reset + * to Idle by another process. Thus, we will consider both + * statuses - Completed and Idle as valid at this stage. + */ +retry: + rc = hmr_attr_read(&result, + fd, + bsg_req, + bsg_rsp, + QUERY_ATTR_IDN_REFRESH_STATUS); + + /* Error or (Completed / Idle) */ + if (rc || + result == HMR_ST_COMPLETED || + result == HMR_ST_IDLE) + goto out; + + /* Retry */ + if (++cur <= count) { + hmr_delay_retry(1); + goto retry; + } + + /* + * Cannot be completed, result holds + * other than HMR_ST_COMPLETED or HMR_ST_IDLE status. + */ + rc = -EHMR_REFRESH_STATUS; + print_error("hmr: verify unit completed: getting status " + "completed failed after %d retries (%d).", count, result); + +out: + return rc; +} + +static int hmr_full_start(int fd, int method) +{ + int rc; + __u32 result; + __u64 iter = 0; + + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + + hmr_output_header("full", method); + + /* Start full refresh */ + rc = hmr_refresh_initiate(fd, &bsg_req, &bsg_rsp); + if (rc) + goto out; + + /* Start progress loop */ + while (1) { + /* Sample progress */ + rc = hmr_progress_read(&result, fd, &bsg_req, &bsg_rsp); + if (rc) + goto out; + + hmr_output_progress(result, iter++, 1, ""); + + /* Progress is 0 - completed */ + if (0 == result) + break; + } + +out: + hmr_output_footer(rc); + return rc; +} + +static int hmr_unit_start(int fd, int method) +{ + int rc; + __u32 result; + __u64 iter = 0; + + struct ufs_bsg_request bsg_req = {0}; + struct ufs_bsg_reply bsg_rsp = {0}; + + hmr_output_header("minimum", method); + + /* Start HMR loop */ + while (1) { + /* Start unit refresh */ + rc = hmr_refresh_initiate(fd, &bsg_req, &bsg_rsp); + if (rc) + goto out; + + /* Verify completed */ + rc = hmr_unit_verify_completed(fd, &bsg_req, &bsg_rsp); + if (rc) + goto out; + + /* Read progress */ + rc = hmr_progress_read(&result, fd, &bsg_req, &bsg_rsp); + if (rc) + goto out; + + hmr_output_progress(result, iter++, 0, ""); + + /* Progress is 0 - completed */ + if (0 == result) + break; + } + +out: + hmr_output_footer(rc); + return rc; +} + +int do_hmr(struct tool_options *opt) +{ + int rc; + int fd; + int (*hmr_job)(int, int); + __u32 refresh_totcount; + enum hmr_stage_skip stage_passer = 0; + + if (!opt || !opt->path) + return -EHMR_INVAL; + + /* Open dev in subject */ + rc = hmr_dev_open(opt->path, &fd); + if (rc) + goto out; + + /* Make verifications prior to HMR */ + rc = hmr_precondition_verify(fd, opt, &refresh_totcount, &stage_passer); + if (rc) + goto free; + + /* Set HMR method: force or selective */ + if (!(stage_passer & HMR_SKIP_METHOD_SET)) { + rc = hmr_method_set(fd, opt->hmr_method); + if (rc) + goto free; + } + + /* Set HMR unit: minimum or full */ + if (!(stage_passer & HMR_SKIP_UNIT_SET)) { + rc = hmr_unit_set(fd, opt->hmr_unit); + if (rc) + goto free; + } + + /* Do the HMR job */ + hmr_job = opt->hmr_unit == HMR_UNIT_MIN ? + &hmr_unit_start : &hmr_full_start; + + rc = (*hmr_job)(fd, opt->hmr_method); + if (rc) + goto free; + + /* Verify variables upon completion */ + rc = hmr_postcondition_verify(fd, refresh_totcount); + if (rc) + goto free; + +free: + rc = hmr_dev_close(opt->path, fd); + +out: + return rc; +} + +void hmr_help(char *tool_name) +{ + /* General use case description */ + printf("\n HMR command usage:\n"); + printf("\n\t%s hmr [-p]  ([-x] [-y] )\n", + tool_name); + + /* -p: mandatory, device path */ + printf("\n\t-p\t path - mandatory, ufs-bsg device path\n"); + + /* -x: optional, HMR method */ + printf("\n\t-x\t method - optional, the default is %d\n", + HMR_METHOD_SELECTIVE); + printf("\t\t\t %-3d: %-25s\n", + HMR_METHOD_FORCE, "force, refresh all blocks containing data"); + printf("\t\t\t %-3d: %-25s\n", + HMR_METHOD_SELECTIVE, "selective, refresh marked blocks only"); + + /* -y: optional, HMR unit */ + printf("\n\t-y\t unit - optional, the default is %d\n", HMR_UNIT_MIN); + printf("\t\t\t %-3d: %-25s\n", + HMR_UNIT_MIN, "minimum, perform HMR by minimum refresh units"); + printf("\t\t\t %-3d: %-25s\n", + HMR_UNIT_FULL, "full, perform a full HMR cycle in one command"); +} diff --git a/libmtk_bsg/ufs_hmr.h b/libmtk_bsg/ufs_hmr.h new file mode 100644 index 0000000000000000000000000000000000000000..27de01d4662291ff0e2a1fb3c68b19af8191ab21 --- /dev/null +++ b/libmtk_bsg/ufs_hmr.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef UFS_HMR_H_ +#define UFS_HMR_H_ + +#include "options.h" + +enum ufs_hmr_method { + HMR_METHOD_FORCE = 1, /* refresh all blocks containing data */ + HMR_METHOD_SELECTIVE, /* refresh marked blocks only */ + HMR_METHOD_MAX /* last member indicator */ +}; + +enum ufs_hmr_unit { + HMR_UNIT_MIN = 0, /* perform HMR in small steps (minimum refresh units) */ + HMR_UNIT_FULL, /* perform full HMR cycle in one command */ + HMR_UNIT_MAX /* last member indicator */ +}; + +void hmr_help(char *tool_name); +int do_hmr(struct tool_options *opt); +#endif /* UFS_HMR_H_ */ + diff --git a/libmtk_bsg/ufs_rpmb.c b/libmtk_bsg/ufs_rpmb.c new file mode 100644 index 0000000000000000000000000000000000000000..f3d25f82db525f07cea9651341157b80284881e4 --- /dev/null +++ b/libmtk_bsg/ufs_rpmb.c @@ -0,0 +1,740 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#pragma GCC diagnostic ignored "-Wall" +#pragma GCC diagnostic ignored "-Wextra" +#pragma GCC diagnostic ignored "-Wsign-compare" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ufs.h" +#include "ufs_cmds.h" +#include "options.h" +#include "ufs_rpmb.h" +#include "ioctl.h" +#include "hmac_sha2.h" +#include "scsi_bsg_util.h" + +enum rpmb_op_type { + RPMB_WRITE_KEY = 0x01, + RPMB_READ_CNT = 0x02, + RPMB_WRITE = 0x03, + RPMB_READ = 0x04, + RPMB_READ_RESP = 0x05, + RPMB_SEC_CONF_WRITE = 0x06, + RPMB_SEC_CONF_READ = 0x07, + +}; + +/* description of the sense key values */ +static const char *const rpmb_res_txt[] = { + "Success", + "General failure", + "Authentication failure", + "Counter failure", + "Address failure", + "Write failure", + "Read failure", + "Authentication Key not yet programmed", + "Secure Write Protect Configuration Block access failure", + "Invalid Secure Write Protect Block Configuration parameter", + "Secure Write Protection not applicable" +}; + +#define RESP_KEY_PROG 0x100 +#define RESP_COUNTER_READ 0x200 +#define RESP_DATA_WRITE 0x300 +#define RESP_DATA_READ 0x400 +#define RESP_CONF_BLOCK_WRITE 0x600 +#define RESP_CONF_BLOCK_READ 0x700 + +#define RPMB_KEY_SIZE 32 +#define RPMB_MAC_SIZE 32 +#define RPMB_NONCE_SIZE 16 +#define RPMB_DATA_SIZE 256 + +#define UFS_BSG_PATH "/dev/ufs-bsg" + +#define DEFAULT_RPMB_NUM_BLOCKS 64 + +#define MAX_ADDRESS 0xFFFF +#define SECOND_BYTE_MASK 0xFF00 + +#define MAX_RETRY 3 + +static unsigned char key[RPMB_KEY_SIZE]; + +#define CUC(x) ((const unsigned char *)(x)) + +extern int do_read_desc(int fd, struct ufs_bsg_request *bsg_req, + struct ufs_bsg_reply *bsg_rsp, __u8 idn, __u8 index, + __u16 desc_buf_len, __u8 *data_buf); + +static void hmac_update_frm(hmac_sha256_ctx *ctx, struct rpmb_frame *frm) +{ + hmac_sha256_update(ctx, CUC(frm->data), 256); + hmac_sha256_update(ctx, CUC(frm->nonce), 16); + hmac_sha256_update(ctx, CUC(&frm->write_counter), 4); + hmac_sha256_update(ctx, CUC(&frm->addr), 2); + hmac_sha256_update(ctx, CUC(&frm->block_count), 2); + hmac_sha256_update(ctx, CUC(&frm->result), 2); + hmac_sha256_update(ctx, CUC(&frm->req_resp), 2); +} + +static int rpmb_calc_hmac_sha256(struct rpmb_frame *frames, ssize_t blocks_cnt, + const unsigned char key[], __u32 key_size, + unsigned char mac[], __u32 mac_size) +{ + hmac_sha256_ctx ctx; + __u32 i; + + hmac_sha256_init(&ctx, key, key_size); + + for (i = 0; i < blocks_cnt; i++) + hmac_update_frm(&ctx, (frames + i)); + + hmac_sha256_final(&ctx, mac, mac_size); + + return 0; +} + +static void print_operation_error(__u16 result) +{ + if (result <= 0xA) + printf("\n %s\n", rpmb_res_txt[result]); + else + printf("\n Unsupported RPMB Operation Error %x\n", result); +} + +static int do_rpmb_op(int fd, struct rpmb_frame *frame_in, __u32 in_cnt, + struct rpmb_frame *frame_out, __u32 out_cnt, __u8 region, + __u8 sg_type) +{ + int ret = -EINVAL; + int try_again; + __u16 req_resp = 0; + + if (!frame_in || !frame_out || !in_cnt || !out_cnt) { + print_error("Wrong rpmb parameters"); + goto out; + } + for (try_again = 0; try_again < MAX_RETRY; try_again++) { + ret = scsi_security_out(fd, frame_in, in_cnt, region, sg_type); + if (!ret) + break; + if (try_again < MAX_RETRY - 1) + WRITE_LOG("SO failed: %d\n", try_again); + else + print_error("SO 1st RPMB cmd failed"); + } + + req_resp = be16toh(frame_in->req_resp & SECOND_BYTE_MASK); + if ((req_resp == RPMB_WRITE) || + (req_resp == RPMB_WRITE_KEY) || + (req_resp == RPMB_SEC_CONF_WRITE)) { + memset(&frame_in[0], 0, sizeof(frame_in[0])); + req_resp = (req_resp & SECOND_BYTE_MASK) | RPMB_READ_RESP; + frame_in[0].req_resp = htobe16(req_resp); + for (try_again = 0; try_again < MAX_RETRY; try_again++) { + ret = scsi_security_out(fd, &frame_in[0], 1, + region, sg_type); + if (!ret) + break; + if (try_again < MAX_RETRY - 1) + WRITE_LOG("SO 2 failed: %d\n", try_again); + else + print_error("SO 2nd RPMB cmd failed"); + } + } + for (try_again = 0; try_again < MAX_RETRY; try_again++) { + ret = scsi_security_in(fd, frame_out, out_cnt, region, sg_type); + if (!ret) { + WRITE_LOG("Result Response addr %d , write count %d\n", + be16toh(frame_out->addr), + be32toh(frame_out->write_counter)); + break; + } + if (try_again < MAX_RETRY - 1) + WRITE_LOG("SI failed: %d\n", try_again); + else + print_error("SI RPMB cmd failed"); + } +out: + return ret; +} + +static int do_key(int fd, const unsigned char *key, __u8 region, __u8 sg_type) +{ + int ret = INVALID; + struct rpmb_frame frame_in = { 0 }; + struct rpmb_frame frame_out = { 0 }; + + frame_in.req_resp = htobe16(RPMB_WRITE_KEY); + + if (key == NULL) { + WRITE_LOG0("key is NULL"); + goto out; + } + memcpy(frame_in.key_mac, key, sizeof(frame_in.key_mac)); + WRITE_LOG("Start : %s\n", __func__); + ret = do_rpmb_op(fd, &frame_in, 1, &frame_out, 1, region, sg_type); + + if (!ret) { + if (frame_out.result != 0) { + print_operation_error(be16toh(frame_out.result)); + goto out; + } else + printf("RPMB key is programmed\n"); + } +out: + return ret; +} + +static int do_read_counter(int fd, __u32 *cnt, __u8 region, __u8 sg_type, + bool prn_cnt) +{ + int ret; + struct rpmb_frame frame_in = { 0 }; + struct rpmb_frame frame_out = { 0 }; + + WRITE_LOG("Start : %s %d\n", __func__, region); + frame_in.req_resp = htobe16(RPMB_READ_CNT); + ret = do_rpmb_op(fd, &frame_in, 1, &frame_out, 1, region, sg_type); + + if (!ret) { + if (frame_out.result != 0) { + print_operation_error(be16toh(frame_out.result)); + } else { + if (prn_cnt) + printf("RPMB write counter = %u\n", + be32toh(frame_out.write_counter)); + *cnt = be32toh(frame_out.write_counter); + } + } + return ret; +} + +static int do_read_rpmb(int fd, int out_fd, unsigned char *key, + int start_addr, int num_blocks, __u8 region, __u8 sg_type) +{ + int ret = ERROR; + int i; + ssize_t write_size; + __u8 max_num_blocks; + __u8 num_read_blocks = 0; + struct rpmb_frame frame_in = { 0 }; + struct rpmb_frame *frames_out = NULL; + struct rpmb_frame *last_frame; + struct ufs_bsg_request bsg_req = { 0 }; + struct ufs_bsg_reply bsg_rsp = { 0 }; + int ufs_bsg_fd = INVALID; + __u8 data_buf[QUERY_DESC_GEOMETRY_MAX_SIZE] = { 0 }; + + WRITE_LOG("Start : %s , address %d , num_blocks %d\n", __func__, + start_addr, num_blocks); + + ufs_bsg_fd = open(UFS_BSG_PATH, O_RDWR); + if (ufs_bsg_fd != INVALID) { + ret = do_read_desc(ufs_bsg_fd, &bsg_req, &bsg_rsp, + QUERY_DESC_IDN_GEOMETRY, 0, + QUERY_DESC_GEOMETRY_MAX_SIZE, data_buf); + } + + if (ret) { + /* + * Could not read geometry descriptor, max block set + * DEFAULT_RPMB_NUM_BLOCKS); + */ + print_warn("Cannot get bRPMB_ReadWriteSize"); + max_num_blocks = DEFAULT_RPMB_NUM_BLOCKS; + } else { + max_num_blocks = data_buf[0x17]; + WRITE_LOG("max_num_blocks : %d\n", max_num_blocks); + } + + if (num_blocks > max_num_blocks) + num_read_blocks = max_num_blocks; + else + num_read_blocks = num_blocks; + while (num_blocks > 0) { + if (start_addr > MAX_ADDRESS) { + print_error("Max available address is reached"); + goto out; + } + + frames_out = (struct rpmb_frame *)calloc(num_read_blocks, + sizeof(struct rpmb_frame)); + if (!frames_out) { + print_error("Cannot allocate %d RPMB frames", + num_blocks); + goto out; + } + frame_in.req_resp = htobe16(RPMB_READ); + frame_in.addr = htobe16(start_addr); + frame_in.block_count = htobe16(num_read_blocks); + ret = do_rpmb_op(fd, &frame_in, 1, frames_out, + num_read_blocks, region, sg_type); + + if (ret != 0) { + print_error("RPMB operation is failed in addr %d ", + start_addr); + goto out; + } + if (frames_out[0].result != 0) { + print_operation_error(be16toh(frames_out[0].result)); + ret = -EINVAL; + goto out; + } + last_frame = &frames_out[num_read_blocks - 1]; + /* In case an user get the key ,verify the hash */ + if (key != NULL) { + __u8 mac[RPMB_MAC_SIZE]; + + rpmb_calc_hmac_sha256(frames_out, num_read_blocks, + key, RPMB_KEY_SIZE, + mac, RPMB_MAC_SIZE); + /* + * Compare calculated MAC and MAC from last frame + * Note the mac much only in case we read 1 block , + * otherwise the mac field is not much, in all frame , + * include the last one + */ + if (memcmp(mac, last_frame->key_mac, sizeof(mac))) + print_warn("RPMB MAC mismatch mac"); + } + for (i = 0; i < num_read_blocks; i++) { + write_size = write(out_fd, &(frames_out[i].data), + RPMB_DATA_SIZE); + if (write_size != RPMB_DATA_SIZE) { + WRITE_LOG("%s: failed in write sz=%d errno=%d", + __func__, (int)write_size, errno); + ret = INVALID; + goto out; + } + } + WRITE_LOG("num_blocks : %d start_addr %d num_read_blocks %d\n", + num_blocks, start_addr, num_read_blocks); + num_blocks = num_blocks - num_read_blocks; + start_addr = start_addr + num_read_blocks; + + if (num_blocks > max_num_blocks) + num_read_blocks = max_num_blocks; + else + num_read_blocks = num_blocks; + + if (frames_out) { + free(frames_out); + frames_out = NULL; + } + } +out: + if (frames_out) + free(frames_out); + if (ufs_bsg_fd != INVALID) + close(ufs_bsg_fd); + + return ret; +} + +static int do_write_rpmb(int fd, const unsigned char *key, int input_fd, + __u32 cnt, __u16 start_addr, __u16 num_blocks, + __u8 region, __u8 sg_type) +{ + int ret = ERROR; + unsigned char mac[RPMB_MAC_SIZE]; + struct rpmb_frame *frames_in = NULL; + struct rpmb_frame frame_out = { 0 }; + ssize_t read_size = 0; + __u8 max_num_blocks; + __u8 num_write_blocks = 0; + int i = 0; + int j = 0; + struct ufs_bsg_request bsg_req = { 0 }; + struct ufs_bsg_reply bsg_rsp = { 0 }; + int ufs_bsg_fd; + __u8 data_buf[QUERY_DESC_GEOMETRY_MAX_SIZE] = { 0 }; + + WRITE_LOG("Start : %s\n", __func__); + + ufs_bsg_fd = open(UFS_BSG_PATH, O_RDWR); + if (ufs_bsg_fd != INVALID) { + ret = do_read_desc(ufs_bsg_fd, &bsg_req, &bsg_rsp, + QUERY_DESC_IDN_GEOMETRY, 0, + QUERY_DESC_GEOMETRY_MAX_SIZE, data_buf); + } + + if (ret) { + print_warn("Cannot get bRPMB_ReadWriteSize"); + max_num_blocks = DEFAULT_RPMB_NUM_BLOCKS; + } else { + /*bRPMB_ReadWriteSize e.g 0x40 * 256 = 16K*/ + max_num_blocks = data_buf[0x17]; + if (max_num_blocks <= 0) + max_num_blocks = 1; + ret = OK; + } + + if (num_blocks > max_num_blocks) + num_write_blocks = max_num_blocks; + else + num_write_blocks = num_blocks; + WRITE_LOG("max_num_blocks : %d num_block %d, cnt %d start_addr %d\n", + max_num_blocks, num_write_blocks, cnt, start_addr); + while (num_blocks > 0) { + if (start_addr > MAX_ADDRESS) { + print_error("Max available address is reached"); + goto out; + } + frames_in = (struct rpmb_frame *)calloc(num_write_blocks, + sizeof(struct rpmb_frame)); + if (!frames_in) { + print_error("Cannot allocate %d RPMB frames", + num_write_blocks); + ret = -ENOMEM; + goto out; + } + for (i = 0; i < num_write_blocks; i++) { + frames_in[i].req_resp = htobe16(RPMB_WRITE); + frames_in[i].addr = htobe16(start_addr); + frames_in[i].block_count = htobe16(num_write_blocks); + frames_in[i].write_counter = htobe32(cnt); + read_size = read(input_fd, frames_in[i].data, + RPMB_DATA_SIZE); + if (read_size != RPMB_DATA_SIZE) { + WRITE_LOG("%s: failed in read size=%d errno=%d", + __func__, (int)read_size, errno); + ret = EINVAL; + goto out; + } + } + + rpmb_calc_hmac_sha256(frames_in, num_write_blocks, + key, RPMB_KEY_SIZE, mac, RPMB_MAC_SIZE); + memcpy(frames_in[num_write_blocks - 1].key_mac, + mac, RPMB_MAC_SIZE); + + ret = do_rpmb_op(fd, frames_in, num_write_blocks, + &frame_out, 1, region, sg_type); + if (ret != 0) + goto out; + + /* Check RPMB response */ + if (frame_out.result != 0) { + print_operation_error(be16toh(frame_out.result)); + ret = -EINVAL; + goto out; + } + + WRITE_LOG("num_blocks : %d start_addr %d num_write_blocks %d ," + "iter %d,cnt %d\n", + num_blocks, start_addr, num_write_blocks, j, cnt); + num_blocks = num_blocks - num_write_blocks; + start_addr = start_addr + num_write_blocks; + if (num_blocks > max_num_blocks) + num_write_blocks = max_num_blocks; + else + num_write_blocks = num_blocks; + j++; + cnt++; + if (frames_in) { + free(frames_in); + frames_in = NULL; + } + + } +out: + if (ufs_bsg_fd != INVALID) + close(ufs_bsg_fd); + if (frames_in) + free(frames_in); + return ret; +} + +static int do_read_conf_block(int fd, const unsigned char *key, __u8 lun, + int output_fd, __u8 sg_type) +{ + int ret = ERROR; + ssize_t write_size; + struct rpmb_frame frame_in = { 0 }; + struct rpmb_frame frame_out = { 0 }; + + WRITE_LOG("Start : %s\n", __func__); + + frame_in.req_resp = htobe16(RPMB_SEC_CONF_READ); + frame_in.data[0] = lun; + + ret = do_rpmb_op(fd, &frame_in, 1, &frame_out, 1, 0, sg_type); + if (ret != 0) { + print_error("Fail to read Secure Write Config Block"); + goto out; + } + if (frame_out.result != 0) { + print_operation_error(be16toh(frame_out.result)); + goto out; + } + + if (key != NULL) { + __u8 mac[RPMB_MAC_SIZE]; + + rpmb_calc_hmac_sha256(&frame_out, 1, key, + RPMB_KEY_SIZE, mac, RPMB_MAC_SIZE); + /* Compare calculated MAC and MAC from last frame + * Note the mac much only in case we read 1 block , otherwise the mac + * field is not much, in all frame ,include the last one */ + if (memcmp(mac, frame_out.key_mac, sizeof(mac))) + print_error("RPMB MAC mismatch mac"); + } + write_size = write(output_fd, frame_out.data, RPMB_DATA_SIZE); + if (write_size != RPMB_DATA_SIZE) { + WRITE_LOG("%s: failed in write size=%d errno=%d", + __func__, (int)write_size, errno); + ret = ERROR; + } else + printf("Secure Write Protect Config Block was read\n"); +out: + return ret; +} + +static int do_write_conf_block(int fd, const unsigned char *key, int input_fd, + __u32 cnt, __u8 sg_type) +{ + int ret = INVALID; + __u8 mac[RPMB_MAC_SIZE]; + struct rpmb_frame frame_in = { 0 }; + struct rpmb_frame frame_out = { 0 }; + ssize_t read_size = 0; + + WRITE_LOG("Start : %s\n", __func__); + + frame_in.req_resp = htobe16(RPMB_SEC_CONF_WRITE); + frame_in.block_count = htobe16(1); + frame_in.write_counter = htobe32(cnt); + read_size = read(input_fd, frame_in.data, RPMB_DATA_SIZE); + if (read_size != RPMB_DATA_SIZE) { + WRITE_LOG("%s: failed in read size=%d errno=%d", + __func__, (int)read_size, errno); + ret = INVALID; + goto out; + } + + rpmb_calc_hmac_sha256(&frame_in, 1, + key, RPMB_KEY_SIZE, mac, RPMB_MAC_SIZE); + memcpy(frame_in.key_mac, mac, RPMB_MAC_SIZE); + + ret = do_rpmb_op(fd, &frame_in, 1, &frame_out, 1, 0, sg_type); + if (ret != 0) { + print_error("Fail to write Secure Write Config Block"); + goto out; + } + + /* Check RPMB response */ + if (frame_out.result != 0) { + print_operation_error(be16toh(frame_out.result)); + ret = -EINVAL; + } else + printf("Secure Write Protect Config Block was written\n"); + +out: + return ret; +} + +static unsigned char *get_auth_key(char *key_path) +{ + unsigned char *pkey = NULL; + int key_fd = INVALID; + ssize_t read_size; + + if (key_path == NULL) + return NULL; + + key_fd = open(key_path, O_RDONLY); + if (key_fd < 0) { + perror("Key file open"); + } else { + read_size = read(key_fd, key, RPMB_KEY_SIZE); + if (read_size < RPMB_KEY_SIZE) { + print_error("Key must be %d bytes length,was read %d", + RPMB_KEY_SIZE, read_size); + } else + pkey = key; + } + + if (key_fd != INVALID) + close(key_fd); + return pkey; +} + +int do_rpmb(struct tool_options *opt) +{ + int rc = INVALID; + int fd; + int output_fd = INVALID; + unsigned char *key_ptr = NULL; + __u32 cnt = 0; + __u8 lun; + + fd = open(opt->path, O_RDWR | O_SYNC); + if (fd < 0) { + perror("open"); + return ERROR; + } + + switch (opt->idn) { + case AUTHENTICATION_KEY: + key_ptr = get_auth_key(opt->keypath); + if (key_ptr == NULL) + goto out; + rc = do_key(fd, key_ptr, opt->region, opt->sg_type); + break; + case READ_WRITE_COUNTER: + rc = do_read_counter(fd, &cnt, opt->region, opt->sg_type, true); + break; + case READ_RPMB: + output_fd = open(opt->data, O_WRONLY | O_CREAT | O_SYNC, + S_IRUSR | S_IWUSR); + if (output_fd < 0) { + perror("Output file open"); + goto out; + } + if (opt->keypath[0] != 0) { + key_ptr = get_auth_key(opt->keypath); + if (key_ptr == NULL) + goto out; + } + + rc = do_read_rpmb(fd, output_fd, key_ptr, opt->start_block, + opt->num_block, opt->region, opt->sg_type); + if (!rc) + printf("Finish to read RPMB data\n"); + break; + case WRITE_RPMB: + key_ptr = get_auth_key(opt->keypath); + if (key_ptr == NULL) + goto out; + + output_fd = open(opt->data, O_RDONLY | O_SYNC); + if (output_fd < 0) { + perror("Input file open"); + goto out; + } + rc = do_read_counter(fd, &cnt, opt->region, opt->sg_type, + false); + if (rc) + goto out; + rc = do_write_rpmb(fd, key_ptr, output_fd, cnt, + opt->start_block, opt->num_block, + opt->region, opt->sg_type); + if (!rc) + printf("Finish to write RPMB data\n"); + break; + case READ_SEC_RPMB_CONF_BLOCK: + lun = opt->lun; + if (opt->keypath[0] != 0) { + key_ptr = get_auth_key(opt->keypath); + if (key_ptr == NULL) + goto out; + } + + output_fd = open(opt->data, O_WRONLY | O_CREAT | O_SYNC, + S_IRUSR | S_IWUSR); + if (output_fd < 0) { + perror("Output file open"); + goto out; + } + + rc = do_read_conf_block(fd, key_ptr, lun, output_fd, + opt->sg_type); + break; + case WRITE_SEC_RPMB_CONF_BLOCK: + key_ptr = get_auth_key(opt->keypath); + if (key_ptr == NULL) + goto out; + + output_fd = open(opt->data, O_RDONLY | O_SYNC); + if (output_fd < 0) { + perror("Input file open"); + goto out; + } + rc = do_read_counter(fd, &cnt, 0, opt->sg_type, false); + if (rc) + goto out; + + rc = do_write_conf_block(fd, key_ptr, output_fd, cnt, + opt->sg_type); + break; + default: + print_error("Unsupported RPMB cmd %d", opt->idn); + break; + } +out: + if (output_fd != INVALID) + close(output_fd); + close(fd); + return rc; +} + +void rpmb_help(char *tool_name) +{ + printf("\n RPMB command usage:\n"); + printf("\n\t%s rpmb [-t] [-p] " + " -k -l -d +#include "options.h" + +#ifndef UFS_RPMB_H_ +#define UFS_RPMB_H_ + +enum rpmb_cmd_type { + AUTHENTICATION_KEY = 0, + READ_WRITE_COUNTER, + READ_RPMB, + WRITE_RPMB, + WRITE_SEC_RPMB_CONF_BLOCK, + READ_SEC_RPMB_CONF_BLOCK, + RPMB_CMD_MAX +}; + +void rpmb_help(char *tool_name); +int do_rpmb(struct tool_options *opt); + +#endif /* UFS_RPMB_H_ */ diff --git a/libmtk_bsg/ufs_vendor.c b/libmtk_bsg/ufs_vendor.c new file mode 100644 index 0000000000000000000000000000000000000000..0e58e34ce48396671e6109da1fbf129f83f3e597 --- /dev/null +++ b/libmtk_bsg/ufs_vendor.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ufs.h" +#include "ufs_cmds.h" +#include "options.h" +#include "options.h" +#include "scsi_bsg_util.h" +#include "ufs_vendor.h" + +static int write_data(struct tool_options *opt, int dev_fd, void *p_data); +static int read_data(struct tool_options *opt, int dev_fd, void *p_data); + +int do_vendor(struct tool_options *opt) +{ + int rc = INVALID; + int fd; + void *p_data; + + WRITE_LOG("Start : %s", __func__); + p_data = malloc(opt->len); + if (!p_data) { + print_error("Cannot allocate %d Bytes", opt->len); + return ERROR; + } + + fd = open(opt->path, O_RDWR | O_SYNC); + if (fd < 0) { + perror("Device open"); + goto out; + } + + if (opt->opr == WRITE) + rc = write_data(opt, fd, p_data); + else + rc = read_data(opt, fd, p_data); +out: + free(p_data); + + if (fd != INVALID) + close(fd); + + return rc; +} + +static int write_data(struct tool_options *opt, int dev_fd, void *p_data) +{ + int input_fd; + int rc = INVALID; + off_t file_size; + + input_fd = open(opt->data, O_RDONLY | O_SYNC); + if (input_fd < 0) { + perror("Input file open"); + return ERROR; + } + + file_size = lseek(input_fd, 0, SEEK_END); + if ((file_size <= 0) || (file_size < opt->len)) { + print_error("Wrong input data file length = %d", + file_size); + goto out; + } + lseek(input_fd, 0, SEEK_SET); + + if (read(input_fd, p_data, opt->len) != opt->len) { + print_error("Read %d data bytes from input file failed", + opt->len); + goto out; + } + rc = write_buffer(dev_fd, p_data, BUFFER_VENDOR_MODE, opt->index, + opt->offset, opt->len, opt->sg_type); + if (!rc) + printf("The vendor buffer was written\n"); +out: + close(input_fd); + return rc; +} + +static int read_data(struct tool_options *opt, int dev_fd, void *p_data) +{ + int rc = INVALID; + + rc = read_buffer(dev_fd, p_data, BUFFER_VENDOR_MODE, opt->index, + opt->offset, opt->len, opt->sg_type); + if (!rc) { + write_file("read_vendor_buffer.dat", p_data, opt->len); + printf("read_vendor_buffer.dat created\n"); + } + + return rc; +} + +void vendor_help(char *tool_name) +{ + printf("\n Vendor Write/Read Buffer command usage:\n"); + printf("\n\t%s vendor [-r ][-w] [-L] \n" + "\t\t[-O] [-p] \n", + tool_name); + printf("\n\t-r\tRead vendor buffer command[default operation]\n"); + printf("\n\t-w\tInput file path for write buffer vendor command\n"); + printf("\n\t-L\tData buffer length, up to 512 Bytes[default value 512B]\n"); + printf("\n\t-i\tBuffer ID\n"); + printf("\n\t-g\t sg struct ver - 0: SG_IO_VER4 (default), 1: SG_IO_VER3\n"); + printf("\n\t-O\tBuffer Offset\n"); + printf("\n\t-p\tDevice path\n"); +} diff --git a/libmtk_bsg/ufs_vendor.h b/libmtk_bsg/ufs_vendor.h new file mode 100644 index 0000000000000000000000000000000000000000..9f5cd3a5a835a7ad683e02617eeb86988f72e9f3 --- /dev/null +++ b/libmtk_bsg/ufs_vendor.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef UFS_VENDOR_H_ +#define UFS_VENDOR_H_ + +void vendor_help(char *tool_name); +int do_vendor(struct tool_options *opt); + +#endif /*UFS_VENDOR_H_*/ diff --git a/libmtk_bsg/unipro.c b/libmtk_bsg/unipro.c new file mode 100644 index 0000000000000000000000000000000000000000..071f911289773ff87a6f03f59b8af2c14865aea6 --- /dev/null +++ b/libmtk_bsg/unipro.c @@ -0,0 +1,573 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "options.h" +#include "ufs.h" +#include "unipro.h" + +/*PHY Adapter Layer(L1.5) */ +static struct ufs_uic_attr_fields phy_adapter_attrs[] = { + /* PHY Adapter (gettable, settable) Common Attributes */ + {"PA_ActiveTxDataLanes", 0x1560, (GETTABLE | SETTABLE)}, + {"PA_TxTrailingClocks", 0x1564, (GETTABLE | SETTABLE)}, + {"PA_ActiveRxDataLanes", 0x1580, (GETTABLE | SETTABLE)}, + + /* PHY Adapter (gettable, static) Common Attributes */ + {"PA_PHY_Type", 0x1500, (GETTABLE | STATIC)}, + {"PA_AvailTxDataLanes", 0x1520, (GETTABLE | STATIC)}, + {"PA_AvailRxDataLanes", 0x1540, (GETTABLE | STATIC)}, + {"PA_MinRxTrailingClocks", 0x1543, (GETTABLE | STATIC)}, + + /* PHY Adapter (gettable, dynamic) Common Attributes */ + {"PA_TxPWRStatus", 0x1567, (GETTABLE | DYNAMIC)}, + {"PA_RxPWRStatus", 0x1582, (GETTABLE | DYNAMIC)}, + {"PA_RemoteVerInfo", 0x15A0, (GETTABLE | DYNAMIC)}, + + /* PHY Adapter (gettable, settable) M-PHY-Specific Attributes */ + {"PA_TxHsG1SyncLength", 0x1552, (GETTABLE | SETTABLE)}, + {"PA_TxHsG1PrepareLength", 0x1553, (GETTABLE | SETTABLE)}, + {"PA_TxHsG2SyncLength", 0x1554, (GETTABLE | SETTABLE)}, + {"PA_TxHsG2PrepareLength", 0x1555, (GETTABLE | SETTABLE)}, + {"PA_TxHsG3SyncLength", 0x1556, (GETTABLE | SETTABLE)}, + {"PA_TxHsG3PrepareLength", 0x1557, (GETTABLE | SETTABLE)}, + {"PA_TxMk2Extension", 0x155A, (GETTABLE | SETTABLE)}, + {"PA_PeerScrambling", 0x155B, (GETTABLE | SETTABLE)}, + {"PA_TxSkip", 0x155C, (GETTABLE | SETTABLE)}, + {"PA_TxSkipPeriod", 0x155D, (GETTABLE | SETTABLE)}, + {"PA_Local_TX_LCC_Enable", 0x155E, (GETTABLE | SETTABLE)}, + {"PA_Peer_TX_LCC_Enable", 0x155F, (GETTABLE | SETTABLE)}, + {"PA_ConnectedTxDataLanes", 0x1561, (GETTABLE | SETTABLE)}, + {"PA_TxGear", 0x1568, (GETTABLE | SETTABLE)}, + {"PA_TxTermination", 0x1569, (GETTABLE | SETTABLE)}, + {"PA_HSSeries", 0x156A, (GETTABLE | SETTABLE)}, + {"PA_PWRMode", 0x1571, (GETTABLE | SETTABLE)}, + {"PA_ConnectedRxDataLanes", 0x1581, (GETTABLE | SETTABLE)}, + {"PA_RxGear", 0x1583, (GETTABLE | SETTABLE)}, + {"PA_RxTermination", 0x1584, (GETTABLE | SETTABLE)}, + {"PA_Scrambling", 0x1585, (GETTABLE | SETTABLE)}, + {"PA_MaxRxPWMGear", 0x1586, (GETTABLE | SETTABLE)}, + {"PA_MaxRxHSGear", 0x1587, (GETTABLE | SETTABLE)}, + {"PA_PACPReqTimeout", 0x1590, (GETTABLE | SETTABLE)}, + {"PA_PACPReqEoBTimeout", 0x1591, (GETTABLE | SETTABLE)}, + {"PA_LogicalLaneMap", 0x15A1, (GETTABLE | SETTABLE)}, + {"PA_SleepNoConfigTime", 0x15A2, (GETTABLE | SETTABLE)}, + {"PA_StallNoConfigTime", 0x15A3, (GETTABLE | SETTABLE)}, + {"PA_SaveConfigTime", 0x15A4, (GETTABLE | SETTABLE)}, + {"PA_RxHSUnterminationCapability", 0x15A5, (GETTABLE | SETTABLE)}, + {"PA_RxLSTerminationCapability", 0x15A6, (GETTABLE | SETTABLE)}, + {"PA_Hibern8Time", 0x15A7, (GETTABLE | SETTABLE)}, + {"PA_TActivate", 0x15A8, (GETTABLE | SETTABLE)}, + {"PA_LocalVerInfo", 0x15A9, (GETTABLE | SETTABLE)}, + {"PA_Granularity", 0x15AA, (GETTABLE | SETTABLE)}, + {"PA_MK2ExtensionGuardBand", 0x15AB, (GETTABLE | SETTABLE)}, + {"PA_PWRModeUserData", 0x15B0, (GETTABLE | SETTABLE)}, + {"PA_PACPFrameCount", 0x15C0, (GETTABLE | SETTABLE)}, + {"PA_PACPErrorCount", 0x15C1, (GETTABLE | SETTABLE)}, + {"PA_PHYTestControl", 0x15C2, (GETTABLE | SETTABLE)}, + {"PA_TxHsG4SyncLength", 0x15D0, (GETTABLE | SETTABLE)}, + {"PA_TxHsG4PrepareLength", 0x15D1, (GETTABLE | SETTABLE)}, + {"PA_PeerRxHsAdaptRefresh", 0x15D2, (GETTABLE | SETTABLE)}, + {"PA_PeerRxHsAdaptInitial", 0x15D3, (GETTABLE | SETTABLE)}, + {"PA_TxHsAdaptType", 0x15D4, (GETTABLE | SETTABLE)}, + {"PA_AdaptAfterLRSTInPA_INIT", 0x15D5, (GETTABLE | SETTABLE)}, +}; + +/* Unipro QoS Measurement DME Attributes */ +static struct ufs_uic_attr_fields dme_qos_attrs[] = { + /* Unipro QoS Measurement DME Attributes */ + {"DME_TX_DATA_OFL", 0x5100, (GETTABLE | SETTABLE)}, + {"DME_TX_NAC_RECEIVED", 0x5101, (GETTABLE | SETTABLE)}, + {"DME_TX_QoS_COUNT", 0x5102, (GETTABLE | SETTABLE)}, + {"DME_TX_DL_LM_ERROR", 0x5103, (GETTABLE | SETTABLE)}, + {"DME_RX_DATA_OFL", 0x5110, (GETTABLE | SETTABLE)}, + {"DME_RX_CRC_ERROR", 0x5111, (GETTABLE | SETTABLE)}, + {"DME_RX_QoS_COUNT", 0x5112, (GETTABLE | SETTABLE)}, + {"DME_RX_DL_LM_ERROR", 0x5113, (GETTABLE | SETTABLE)}, + {"DME_TXRX_DATA_OFL", 0x5120, (GETTABLE | SETTABLE)}, + {"DME_TXRX_PA_INIT_REQUEST", 0x5121, (GETTABLE | SETTABLE)}, + {"DME_TXRX_QoS_COUNT", 0x5122, (GETTABLE | SETTABLE)}, + {"DME_TXRX_DL_LM_ERROR", 0x5123, (GETTABLE | SETTABLE)}, + {"DME_QoS_ENABLE", 0x5130, (GETTABLE | SETTABLE)}, + {"DME_QoS_STATUS", 0x5131, (GETTABLE | SETTABLE)}, +}; + +/* M-TX/M-RX Capability Attributes */ +static struct ufs_uic_attr_fields mipi_mphy_attrs[] = { + /* M-PHY TX Capability Attributes */ + {"TX_HSMODE_Capability", 0x0001, (GETTABLE)}, + {"TX_HSGEAR_Capability", 0x0002, (GETTABLE)}, + {"TX_PWMG0_Capability", 0x0003, (GETTABLE)}, + {"TX_PWMGEAR_Capability", 0x0004, (GETTABLE)}, + {"TX_Amplitude_Capability", 0x0005, (GETTABLE)}, + {"TX_ExternalSYNC_Capability", 0x0006, (GETTABLE)}, + {"TX_HS_Unterminated_LINE_Drive_Capability", 0x0007, (GETTABLE)}, + {"TX_LS_Terminated_LINE_Drive_Capability", 0x0008, (GETTABLE)}, + {"TX_Min_SLEEP_NoConfig_Time_Capability", 0x0009, (GETTABLE)}, + {"TX_Min_STALL_NoConfig_Time_Capability", 0x000A, (GETTABLE)}, + {"TX_Min_SAVE_Config_Time_Capability", 0x000B, (GETTABLE)}, + {"TX_REF_CLOCK_SHARED_Capability", 0x000C, (GETTABLE)}, + {"TX_PHY_MajorMinor_Release_Capability", 0x000D, (GETTABLE)}, + {"TX_PHY_Editorial_Release_Capability", 0x000E, (GETTABLE)}, + {"TX_Hibern8Time_Capability", 0x000F, (GETTABLE)}, + {"TX_Advanced_Granularity_Capability", 0x0010, (GETTABLE)}, + {"TX_Advanced_Hibern8Time_Capability", 0x0011, (GETTABLE)}, + {"TX_HS_Equalizer_Setting_Capability", 0x0012, (GETTABLE)}, + + /* M-PHY TX Configuration Attributes */ + {"TX_MODE", 0x0021, (GETTABLE | SETTABLE)}, + {"TX_HSRATE_Series", 0x0022, (GETTABLE | SETTABLE)}, + {"TX_HSGEAR", 0x0023, (GETTABLE | SETTABLE)}, + {"TX_PWMGEAR", 0x0024, (GETTABLE | SETTABLE)}, + {"TX_Amplitude", 0x0025, (GETTABLE | SETTABLE)}, + {"TX_HS_SlewRate", 0x0026, (GETTABLE | SETTABLE)}, + {"TX_SYNC_Source", 0x0027, (GETTABLE | SETTABLE)}, + {"TX_HS_SYNC_LENGTH", 0x0028, (GETTABLE | SETTABLE)}, + {"TX_HS_PREPARE_LENGTH", 0x0029, (GETTABLE | SETTABLE)}, + {"TX_LS_PREPARE_LENGTH", 0x002A, (GETTABLE | SETTABLE)}, + {"TX_HIBERN8_Control", 0x002B, (GETTABLE | SETTABLE)}, + {"TX_LCC_Enable", 0x002C, (GETTABLE | SETTABLE)}, + {"TX_PWM_BURST_Closure_Extension", 0x002D, (GETTABLE | SETTABLE)}, + {"TX_BYPASS_8B10B_Enable", 0x002E, (GETTABLE | SETTABLE)}, + {"TX_DRIVER_POLARITY", 0x002F, (GETTABLE | SETTABLE)}, + {"TX_HS_Unterminated_LINE_Drive_Enable", 0x0030, (GETTABLE | SETTABLE)}, + {"TX_LS_Terminated_LINE_Drive_Enable", 0x0031, (GETTABLE | SETTABLE)}, + {"TX_LCC_Sequencer", 0x0032, (GETTABLE | SETTABLE)}, + {"TX_Min_ActivateTime", 0x0033, (GETTABLE | SETTABLE)}, + {"TX_PWM_G6_G7_SYNC_LENGTH", 0x0034, (GETTABLE | SETTABLE)}, + {"TX_Advanced_Granularity_Step", 0x0035, (GETTABLE | SETTABLE)}, + {"TX_Advanced_Granularity", 0x0036, (GETTABLE | SETTABLE)}, + {"TX_HS_Equalizer_Setting", 0x0037, (GETTABLE | SETTABLE)}, + {"TX_Min_SLEEP_NoConfig_Time", 0x0038, (GETTABLE | SETTABLE)}, + {"TX_Min_STALL_NoConfig_Time", 0x0039, (GETTABLE | SETTABLE)}, + {"TX_HS_ADAPT_LENGTH", 0x003A, (GETTABLE | SETTABLE)}, + + /* M-TX Status Attributes */ + {"TX_FSM_State", 0x0041, (GETTABLE)}, + + /* M-PHY OMC Write-only Attributes */ + {"MC_Output_Amplitude", 0x0061, (SETTABLE)}, + {"MC_HS_Unterminated_Enable", 0x0062, (SETTABLE)}, + {"MC_LS_Terminated_Enable", 0x0063, (SETTABLE)}, + {"MC_HS_Unterminated_LINE_Drive_Enable", 0x0064, (SETTABLE)}, + {"MC_LS_Terminated_LINE_Drive_Enable", 0x0065, (SETTABLE)}, + + /* M-PHY RX Capability Attributes */ + {"RX_HSMODE_Capability", 0x0081, (GETTABLE)}, + {"RX_HSGEAR_Capability", 0x0082, (GETTABLE)}, + {"RX_PWMG0_Capability", 0x0083, (GETTABLE)}, + {"RX_PWMGEAR_Capability", 0x0084, (GETTABLE)}, + {"RX_HS_Unterminated_Capability", 0x0085, (GETTABLE)}, + {"RX_LS_Terminated_Capability", 0x0086, (GETTABLE)}, + {"RX_Min_SLEEP_NoConfig_Time_Capability", 0x0087, (GETTABLE)}, + {"RX_Min_STALL_NoConfig_Time_Capability", 0x0088, (GETTABLE)}, + {"RX_Min_SAVE_Config_Time_Capability", 0x0089, (GETTABLE)}, + {"RX_REF_CLOCK_SHARED_Capability", 0x008A, (GETTABLE)}, + {"RX_HS_G1_SYNC_LENGTH_Capability", 0x008B, (GETTABLE)}, + {"RX_HS_G1_PREPARE_LENGTH_Capability", 0x008C, (GETTABLE)}, + {"RX_LS_PREPARE_LENGTH_Capability", 0x008D, (GETTABLE)}, + {"RX_PWM_Burst_Closure_Length_Capability", 0x008E, (GETTABLE)}, + {"RX_Min_ActivateTime_Capability", 0x008F, (GETTABLE)}, + {"RX_PHY_MajorMinor_Release_Capability", 0x0090, (GETTABLE)}, + {"RX_PHY_Editorial_Release_Capability", 0x0091, (GETTABLE)}, + {"RX_Hibern8Time_Capability", 0x0092, (GETTABLE)}, + {"RX_PWM_G6_G7_SYNC_LENGTH_Capability", 0x0093, (GETTABLE)}, + {"RX_HS_G2_SYNC_LENGTH_Capability", 0x0094, (GETTABLE)}, + {"RX_HS_G3_SYNC_LENGTH_Capability", 0x0095, (GETTABLE)}, + {"RX_HS_G2_PREPARE_LENGTH_Capability", 0x0096, (GETTABLE)}, + {"RX_HS_G3_PREPARE_LENGTH_Capability", 0x0097, (GETTABLE)}, + {"RX_Advanced_Granularity_Capability", 0x0098, (GETTABLE)}, + {"RX_Advanced_Hibern8Time_Capability", 0x0099, (GETTABLE)}, + {"RX_Advanced_Min_ActivateTime_Capability", 0x009A, (GETTABLE)}, + {"RX_HS_G4_SYNC_LENGTH_Capability", 0x009B, (GETTABLE)}, + {"RX_HS_G4_PREPARE_LENGTH_Capability", 0x009C, (GETTABLE)}, + {"RX_HS_Equalizer_Setting_Capability", 0x009D, (GETTABLE)}, + {"RX_HS_ADAPT_REFRESH_Capability", 0x009E, (GETTABLE)}, + {"RX_HS_ADAPT_INITIAL_Capability", 0x009F, (GETTABLE)}, + + /* M-RX Configuration Attributes */ + {"RX_MODE", 0x00A1, (GETTABLE | SETTABLE)}, + {"RX_HSRATE_Series", 0x00A2, (GETTABLE | SETTABLE)}, + {"RX_HSGEAR", 0x00A3, (GETTABLE | SETTABLE)}, + {"RX_PWMGEAR", 0x00A4, (GETTABLE | SETTABLE)}, + {"RX_LS_Terminated_Enable", 0x00A5, (GETTABLE | SETTABLE)}, + {"RX_HS_Unterminated_Enable", 0x00A6, (GETTABLE | SETTABLE)}, + {"RX_Enter_HIBERN8", 0x00A7, (GETTABLE | SETTABLE)}, + {"RX_BYPASS_8B10B_Enable", 0x00A8, (GETTABLE | SETTABLE)}, + {"RX_Termination_Force_Enable", 0x00A9, (GETTABLE | SETTABLE)}, + {"RX_ADAPT_Control", 0x00AA, (GETTABLE | SETTABLE)}, + {"RX_RECEIVER_POLARITY", 0x00AB, (GETTABLE | SETTABLE)}, + {"RX_HS_ADAPT_LENGTH", 0x00AC, (GETTABLE | SETTABLE)}, + + /* M-PHY RX Status Attributes */ + {"RX_FSM_State", 0x00C1, (GETTABLE)}, + + /* M-PHY OMC Status Attributes */ + {"OMC_TYPE_Capability", 0x00D1, (GETTABLE)}, + {"MC_HSMODE_Capability", 0x00D2, (GETTABLE)}, + {"MC_HSGEAR_Capability", 0x00D3, (GETTABLE)}, + {"MC_HS_START_TIME_Var_Capability", 0x00D4, (GETTABLE)}, + {"MC_HS_START_TIME_Range_Capability", 0x00D5, (GETTABLE)}, + {"MC_RX_SA_Capability", 0x00D6, (GETTABLE)}, + {"MC_HS_LA_Capability", 0x00D7, (GETTABLE)}, + {"MC_HS_LS_PREPARE_LENGTH", 0x00D8, (GETTABLE)}, + {"MC_PWMG0_Capability", 0x00D9, (GETTABLE)}, + {"MC_PWMGEAR_Capability", 0x00DA, (GETTABLE)}, + {"MC_LS_Terminated_Capability", 0x00DB, (GETTABLE)}, + {"MC_HS_Unterminated_Capability", 0x00DC, (GETTABLE)}, + {"MC_LS_Terminated_LINE_Drive_Capability", 0x00DD, (GETTABLE)}, + {"MC_HS_Unterminated_LINE_Drive_Capabilit", 0x00DE, (GETTABLE)}, + {"MC_MFG_ID_Part1", 0x00DF, (GETTABLE)}, + {"MC_MFG_ID_Part2", 0x00E0, (GETTABLE)}, + {"MC_PHY_MajorMinor_Release_Capability", 0x00E1, (GETTABLE)}, + {"MC_PHY_Editorial_Release_Capability", 0x00E2, (GETTABLE)}, + {"MC_Vendor_Info_Part1", 0x00E3, (GETTABLE)}, + {"MC_Vendor_Info_Part2", 0x00E4, (GETTABLE)}, + {"MC_Vendor_Info_Part3", 0x00E5, (GETTABLE)}, + {"MC_Vendor_Info_Part4", 0x00E6, (GETTABLE)}, +}; + +static struct ufs_unipro_attrs_info uic_attrs_group[MAX_UNIPRO_IDN] = { + { + "MIPI M-PHY", mipi_mphy_attrs, + sizeof(mipi_mphy_attrs) / sizeof(struct ufs_uic_attr_fields) + }, + { + "PHY-Adapter", phy_adapter_attrs, + sizeof(phy_adapter_attrs) / sizeof(struct ufs_uic_attr_fields) + }, + { + "DME Attributes for QoS", dme_qos_attrs, + sizeof(dme_qos_attrs) / sizeof(struct ufs_uic_attr_fields) + }, +}; + +static struct uic_cmd_result_code resultcode[] = { + {0, "SUCCESS"}, + {1, "INVALID_MIB_ATTRIBUTE"}, + {2, "INVALID_MIB_ATTRIBUTE_VALUE"}, + {3, "READ_ONLY_MIB_ATTRIBUTE"}, + {4, "WRITE_ONLY_MIB_ATTRIBUTE"}, + {5, "BAD_INDEX"}, + {6, "LOCKED_MIB_ATTRIBUTE"}, + {7, "BAD_TEST_FEATURE_INDEX"}, + {8, "PEER_COMMUNICATION_FAILURE"}, + {9, "BUSY"}, + {10, "DME_FAILURE"}, +}; + +static int ufshcd_dme_get_attr(int fd, __u32 attr_sel, __u8 peer) +{ + struct ufs_bsg_request bsg_req = { 0 }; + struct ufs_bsg_reply bsg_rsp = { 0 }; + struct uic_command *uic_cmd = + (struct uic_command *)&bsg_req.upiu_req.uc; + struct uic_command uic_rsq = { 0 }; + + int rt = OK; + __u8 res_code; + + uic_cmd->command = peer ? UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET; + uic_cmd->argument1 = attr_sel; + bsg_req.msgcode = UPIU_TRANSACTION_UIC_CMD; + + rt = send_bsg_scsi_trs(fd, &bsg_req, &bsg_rsp, 0, 0, 0); + if (rt) { + print_error("%s: bsg request failed", __func__); + rt = ERROR; + goto out; + } + + memcpy(&uic_rsq, &bsg_rsp.upiu_rsp.uc, UIC_CMD_SIZE); + res_code = uic_rsq.argument2 & MASK_UIC_COMMAND_RESULT; + + if (res_code) { + __u8 max_code = + sizeof(resultcode) / + sizeof(struct uic_cmd_result_code); + + if (res_code < (max_code - 1)) { + print_error("%s: attr-id 0x%x %s", + __func__, + UIC_GET_ATTR_ID(attr_sel), + resultcode[res_code].def); + } else { + print_error("%s: ID 0x%x, unknown error code %d", + __func__, UIC_GET_ATTR_ID(attr_sel), + res_code); + } + + rt = ERROR; + } else { + rt = uic_rsq.argument3; + } + +out: + return rt; +} + +static int ufshcd_dme_set_attr(int fd, __u32 attr_sel, __u8 attr_set, + __u32 mib_val, __u8 peer) +{ + struct ufs_bsg_request bsg_req = { 0 }; + struct ufs_bsg_reply bsg_rsp = { 0 }; + struct uic_command *uic_cmd = + (struct uic_command *)&bsg_req.upiu_req.uc; + struct uic_command uic_rsq = { 0 }; + + int rt = OK; + __u8 res_code; + + uic_cmd->command = peer ? UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET; + uic_cmd->argument1 = attr_sel; + uic_cmd->argument2 = UIC_ARG_ATTR_TYPE(attr_set); + uic_cmd->argument3 = mib_val; + + bsg_req.msgcode = UPIU_TRANSACTION_UIC_CMD; + + rt = send_bsg_scsi_trs(fd, &bsg_req, &bsg_rsp, 0, 0, 0); + if (rt) { + print_error("%s: bsg request failed", __func__); + rt = ERROR; + goto out; + } + + memcpy(&uic_rsq, &bsg_rsp.upiu_rsp.uc, UIC_CMD_SIZE); + res_code = uic_rsq.argument2 & MASK_UIC_COMMAND_RESULT; + + if (res_code) { + __u8 max_code = sizeof(resultcode) / + sizeof(struct uic_cmd_result_code); + + if (res_code < (max_code - 1)) { + print_error("%s: ID 0x%x %s", + __func__, + UIC_GET_ATTR_ID(attr_sel), + resultcode[res_code].def); + } else { + print_error("%s: ID 0x%x, unkonw error code %d", + __func__, + UIC_GET_ATTR_ID(attr_sel), + res_code); + } + rt = ERROR; + } + +out: + return rt; +} + +static int check_attr_id(__u32 idn, __u32 id) +{ + int index; + int qts = uic_attrs_group[idn].items; + struct ufs_uic_attr_fields *p = uic_attrs_group[idn].attrs; + + for (index = 0; index < qts; index++) { + if (p[index].id == id) + return index; + } + return INVALID; +} + +static void display(int id, const char *name, int local, int peer) +{ + printf("[0x%04x]%-45s : local = 0x%08x, peer = 0x%08x\n", + id, name, local, peer); +} + +static int unipro_read(int fd, int idn, int id, __u8 all) +{ + int index, qts; + int mib_val_local, mib_val_peer; + int ret = OK; + + qts = uic_attrs_group[idn].items; + struct ufs_uic_attr_fields *p = uic_attrs_group[idn].attrs; + + if (all) { + printf("\nUFS Unipro %s layer Attributes:\n", + uic_attrs_group[idn].name); + + for (index = 0; index < qts; index++) { + if (p[index].acc_mode & GETTABLE) { + mib_val_local = + ufshcd_dme_get_attr(fd, + UIC_ARG_MIB(p[index].id), + DME_LOCAL); + mib_val_peer = + ufshcd_dme_get_attr(fd, + UIC_ARG_MIB(p[index].id), + DME_PEER); + + if (mib_val_local != ERROR && + mib_val_peer != ERROR) { + display(p[index].id, p[index].name, + mib_val_local, mib_val_peer); + } else { + print_error("Read %s ID 0x%x Failed", + ((mib_val_local == ERROR) && + (mib_val_peer == ERROR)) ? + ("local&peer") : + ((mib_val_local == ERROR) ? + ("local") : ("peer")), + p[index].id); + + ret = ERROR; + } + } + } + } else { + /* read single item */ + index = check_attr_id(idn, id); + if (index >= 0) { + mib_val_local = + ufshcd_dme_get_attr(fd, + UIC_ARG_MIB(p[index].id), + DME_LOCAL); + mib_val_peer = + ufshcd_dme_get_attr(fd, + UIC_ARG_MIB(p[index].id), + DME_PEER); + + if (mib_val_local != ERROR && + mib_val_peer != ERROR) { + display(p[index].id, p[index].name, + mib_val_local, mib_val_peer); + } else { + print_error("Read %s ID 0x%x failed", + ((mib_val_local == ERROR) && + (mib_val_peer == ERROR)) ? + ("local&peer") : + ((mib_val_local == ERROR) ? + ("local") : ("peer")), + p[index].id); + ret = ERROR; + } + + } else { + print_error("Unsupport ID 0x%02x in %s", + id, uic_attrs_group[idn].name); + ret = ERROR; + } + } + + return ret; +} + +static int unipro_write(int fd, int idn, int id, int mib_val, + int attr_set, int target) +{ + int index; + int ret = OK; + struct ufs_uic_attr_fields *p = uic_attrs_group[idn].attrs; + + index = check_attr_id(idn, id); + + if (index >= 0) { + if (p[index].acc_mode & SETTABLE) { + ret = ufshcd_dme_set_attr(fd, + UIC_ARG_MIB(p[index].id), + attr_set, mib_val, target); + + printf("%s set %s 0x%04x:%s to 0x%08x\n", + (ret == OK ? "Successfully" : "Failed"), + (target == DME_PEER ? "PEER" : "LOCAL"), + p[index].id, p[index].name, mib_val); + } else { + print_error("un-settable id 0x%02x in %s", id, + uic_attrs_group[idn].name); + ret = ERROR; + } + } else { + print_error("unsupport id 0x%02x in %s", id, + uic_attrs_group[idn].name); + ret = ERROR; + } + + return ret; +} + +int do_uic(struct tool_options *opt) +{ + int fd; + int rt = OK; + int oflag = O_RDWR; + + if (opt->opr == READ_ALL || opt->opr == READ) + oflag = O_RDONLY; + + fd = open(opt->path, oflag); + if (fd < 0) { + print_error("open"); + return ERROR; + } + + switch (opt->opr) { + case READ_ALL: + rt = unipro_read(fd, opt->idn, 0, 1); + break; + case READ: + rt = unipro_read(fd, opt->idn, opt->index, 0); + break; + case WRITE: + rt = unipro_write(fd, + opt->idn, opt->index, + *(__u32 *)opt->data, + ATTR_SET_NOR, opt->target); + break; + default: + rt = INVALID; + break; + } + close(fd); + return rt; +} + +const char *help_str = + "\nUnipro command usage:\n" + " %s uic [-t idn] [-a|-r] [-i ID] [-w data ] [-p bsg]\n\n" + " -t idn\n" + " Supported Unipro layers attributes idn as below:\n" + " 0: MIPI M-PHY Attributes\n" + " 1: PHY-Adapter Attributes\n" + " 2: DME Attributes for QoS\n\n" + " -a Read all gettable attributes of peer & local, please\n" + " use -t to specify Unipro attributes idn\n\n" + " -r Read single attribute of peer & local, please use -i\n" + " to specify attribute ID, and -t for associated idn\n\n" + " -w data \n" + " Write settable attribute, followed by data writing,\n" + " Please use -i to specify which ID to write, --peer\n" + " and --local to specify accessed target\n\n" + " --peer : access to a peer device (UFS device)\n" + " --local : access to a local device (UFS host)\n\n" + " -i ID\n" + " Set attribute ID to read/write\n" + " -p bsg\n" + " Path to ufs-bsg device\n\n" + " Note :\n" + " As for the format of the data inputted, hex number should be\n" + " prefixed by 0x/0X\n" + " Eg :\n" + " 1. Set local PA_TxTrailingClocks:\n" + " %s uic -t 1 -w 0x44 -i 0x1564 --local -p /dev/ufs-bsg\n" + " 2. Read peer and local PA_TxTrailingClocks:\n" + " %s uic -t 1 -r -i 0x1564 -p /dev/ufs-bsg\n"; +void unipro_help(char *tool_name) +{ + printf(help_str, tool_name, tool_name, tool_name); +} diff --git a/libmtk_bsg/unipro.h b/libmtk_bsg/unipro.h new file mode 100644 index 0000000000000000000000000000000000000000..760a186d1fe396d5a7198c5c2c9aa5fdeae31e0e --- /dev/null +++ b/libmtk_bsg/unipro.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2020, Mediatek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef UNIPRO_H_ +#define UNIPRO_H_ + +#define UIC_ARG_MIB_SEL(attr, sel) ((((attr) & 0xFFFF) << 16) |\ + ((sel) & 0xFFFF)) +#define UIC_ARG_MIB(attr) UIC_ARG_MIB_SEL(attr, 0) +#define UIC_ARG_ATTR_TYPE(t) (((t) & 0xFF) << 16) +#define UIC_GET_ATTR_ID(v) (((v) >> 16) & 0xFFFF) + +/* UIC command interfaces for DME primitives */ +#define DME_LOCAL 0 +#define DME_PEER 1 +#define ATTR_SET_NOR 0 /* NORMAL */ +#define ATTR_SET_ST 1 /* STATIC */ +#define MASK_UIC_COMMAND_RESULT 0xFF + +#define UPIU_TRANSACTION_UIC_CMD 0x1F +/* uic commands are 4DW long, per UFSHCI V2.1 paragraph 5.6.1 */ +#define UIC_CMD_SIZE (sizeof(__u32) * 4) + +/** + * struct uic_command - UIC command structure + * @command: UIC command + * @argument1: UIC command argument 1 + * @argument2: UIC command argument 2 + * @argument3: UIC command argument 3 + */ +struct uic_command { + __u32 command; + __u32 argument1; + __u32 argument2; + __u32 argument3; +}; + +enum unipro_acc_mode { + GETTABLE = (1 << 0), + SETTABLE = (1 << 1), + STATIC = (1 << 2), + DYNAMIC = (1 << 3) +}; + +struct ufs_uic_attr_fields { + const char *name; + __u32 id; + enum unipro_acc_mode acc_mode; +}; + +struct ufs_unipro_attrs_info { + const char *name; + struct ufs_uic_attr_fields *attrs; + __u32 items; +}; + +struct uic_cmd_result_code { + __u8 value; + const char *def; +}; + +/* Unipro attribute idn */ +enum unipro_attr_idn { + MPHY = 0x00, + PHY_ADAPTER = 0x01, + DME_QOS = 0X02, + MAX_UNIPRO_IDN, +}; + +/* UIC Commands */ +enum uic_cmd_dme { + UIC_CMD_DME_GET = 0x01, + UIC_CMD_DME_SET = 0x02, + UIC_CMD_DME_PEER_GET = 0x03, + UIC_CMD_DME_PEER_SET = 0x04, + UIC_CMD_DME_POWERON = 0x10, + UIC_CMD_DME_POWEROFF = 0x11, + UIC_CMD_DME_ENABLE = 0x12, + UIC_CMD_DME_RESET = 0x14, + UIC_CMD_DME_END_PT_RST = 0x15, + UIC_CMD_DME_LINK_STARTUP = 0x16, + UIC_CMD_DME_HIBER_ENTER = 0x17, + UIC_CMD_DME_HIBER_EXIT = 0x18, + UIC_CMD_DME_TEST_MODE = 0x1A, +}; + +int do_uic(struct tool_options *opt); +void unipro_help(char *tool_name); + +#endif /* END UNIPRO_H_ */ diff --git a/proprietary-files.txt b/proprietary-files.txt index 773fd684af0db44e860cae55ca2bc338abac4ec7..2b740d0246b4f486a25c0147150c21637091b689 100644 --- a/proprietary-files.txt +++ b/proprietary-files.txt @@ -1,5 +1,5 @@ -# Teracube Build ID: 11.0.7+d5a7de0.emerald.user -# Unpinned blobs from full_yk673v6_lwg62_64-user 11 RP1A.200720.011 p1k61v164bspP13 release-keys +# Teracube Build ID: 12.0.0+021f22f.emerald.user +# Unpinned blobs from full_emernia-user 12 SP1A.210812.016 s0rc0emerniabsp release-keys # Camera vendor/lib/libimgsensorca.so @@ -12,7 +12,7 @@ vendor/lib64/libmtkcam_imgbuf.so # Fingerprint vendor/etc/init/init.fpsensor.rc -vendor/lib64/hw/fpsensor_fingerprint.default.so:vendor/lib64/hw/fingerprint.mt6765.so +vendor/lib64/hw/fingerprint.default.so:vendor/lib64/hw/fingerprint.mt6765.so vendor/lib64/libchiponeic_fingerprint_factory.so vendor/lib64/libfp_ext_svc2.so vendor/lib64/vendor.fpsensor.hardware.fpsensorhidlsvc@2.0.so @@ -52,12 +52,8 @@ vendor/lib64/libkeymaster_portable.so vendor/lib64/libkeystore-engine-wifi-hidl.so vendor/lib64/libkeystore-wifi-hidl.so vendor/lib64/libkmsetkey.so -vendor/lib64/libkphhelper.so -vendor/lib64/libkphproxy.so -vendor/lib64/libpl.so vendor/lib64/libpuresoftkeymasterdevice.so vendor/lib64/libsoft_attestation_cert.so -vendor/lib64/libteec.so vendor/lib64/vendor.mediatek.hardware.keymaster_attestation@1.0.so vendor/lib64/vendor.mediatek.hardware.keymaster_attestation@1.1.so diff --git a/sepolicy/vendor/file_contexts b/sepolicy/vendor/file_contexts deleted file mode 100644 index 922226aef01df73284197fba0e57aa7e12ba6333..0000000000000000000000000000000000000000 --- a/sepolicy/vendor/file_contexts +++ /dev/null @@ -1 +0,0 @@ -/vendor/bin/hw/logo_updater u:object_r:logo_updater_exec:s0 diff --git a/sepolicy/vendor/logo_updater.te b/sepolicy/vendor/logo_updater.te deleted file mode 100644 index a6ead89bf7eda77fb0b7af0526387654bedf064d..0000000000000000000000000000000000000000 --- a/sepolicy/vendor/logo_updater.te +++ /dev/null @@ -1,7 +0,0 @@ -type logo_updater, domain, mlstrustedsubject; -type logo_updater_exec, exec_type, file_type, vendor_file_type; -init_daemon_domain(logo_updater) - -allow logo_updater logo_block_device:blk_file rw_file_perms; -allow logo_updater vendor_file:file r_file_perms; -allow logo_updater block_device:dir search;