From: Haoran.Wang Date: Mon, 28 Aug 2017 07:21:44 +0000 (+0800) Subject: MLK-18591-4 android: iot: Import ql-tipc lib for Trusty OS X-Git-Tag: rel_imx_4.19.35_1.1.0~366 X-Git-Url: https://git.somdevices.com/?a=commitdiff_plain;h=ffca28682c5a9375c29b3036a156aff190341960;p=u-boot.git MLK-18591-4 android: iot: Import ql-tipc lib for Trusty OS The lib provided ql-tipc communication channel with Trusty OS. Also the AVB, Keymaster, hwcrypto and SecureStorage service tipc client implement in this lib. Change-Id: I0ab1ec9ee1b6f272b960c2e944008283c2c9249a Signed-off-by: Haoran.Wang (cherry picked from commit 8fb370dd80fbb293b58115d2e7fc4970813773c7) (cherry picked from commit 0ccdd527a794c2b450658980361a7857ce7495c9) --- diff --git a/include/interface/avb/avb.h b/include/interface/avb/avb.h new file mode 100644 index 0000000000..608f6afc40 --- /dev/null +++ b/include/interface/avb/avb.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef TRUSTY_INTERFACE_AVB_H_ +#define TRUSTY_INTERFACE_AVB_H_ + +#include + +#define AVB_PORT "com.android.trusty.avb" +#define AVB_MAX_BUFFER_LENGTH 2048 + +enum avb_command { + AVB_REQ_SHIFT = 1, + AVB_RESP_BIT = 1, + + READ_ROLLBACK_INDEX = (0 << AVB_REQ_SHIFT), + WRITE_ROLLBACK_INDEX = (1 << AVB_REQ_SHIFT), + AVB_GET_VERSION = (2 << AVB_REQ_SHIFT), + READ_PERMANENT_ATTRIBUTES = (3 << AVB_REQ_SHIFT), + WRITE_PERMANENT_ATTRIBUTES = (4 << AVB_REQ_SHIFT), + READ_LOCK_STATE = (5 << AVB_REQ_SHIFT), + WRITE_LOCK_STATE = (6 << AVB_REQ_SHIFT), + LOCK_BOOT_STATE = (7 << AVB_REQ_SHIFT), + READ_VBMETA_PUBLIC_KEY = (8 << AVB_REQ_SHIFT), + WRITE_VBMETA_PUBLIC_KEY = (9 << AVB_REQ_SHIFT), +}; + +/** + * enum avb_error - error codes for AVB protocol + * @AVB_ERROR_NONE: All OK + * @AVB_ERROR_INVALID: Invalid input + * @AVB_ERROR_INTERNAL: Error occurred during an operation in Trusty + */ +enum avb_error { + AVB_ERROR_NONE = 0, + AVB_ERROR_INVALID = 1, + AVB_ERROR_INTERNAL = 2, +}; + +/** + * avb_message - Serial header for communicating with AVB server + * @cmd: the command. Payload must be a serialized buffer of the + * corresponding request object. + * @result: resulting error code for message, one of avb_error. + * @payload: start of the serialized command specific payload + */ +struct avb_message { + uint32_t cmd; + uint32_t result; + uint8_t payload[0]; +}; + +/** + * avb_rollback_req - request format for [READ|WRITE]_ROLLBACK_INDEX + * @value: value to write to rollback index. Ignored for read. + * @slot: slot number of rollback index to write + */ +struct avb_rollback_req { + uint64_t value; + uint32_t slot; +} TRUSTY_ATTR_PACKED; + +/** + * avb_rollback_resp - response format for [READ|WRITE]_ROLLBACK_INDEX. + * @value: value of the requested rollback index. + */ +struct avb_rollback_resp { + uint64_t value; +}; + +/** + * avb_get_version_resp - response format for AVB_GET_VERSION. + * @version: version of AVB message format + */ +struct avb_get_version_resp { + uint32_t version; +}; + +#endif /* TRUSTY_INTERFACE_AVB_H_ */ diff --git a/include/interface/hwcrypto/hwcrypto.h b/include/interface/hwcrypto/hwcrypto.h new file mode 100644 index 0000000000..270c57910a --- /dev/null +++ b/include/interface/hwcrypto/hwcrypto.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * Copyright NXP 2018 + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef TRUSTY_INTERFACE_HWCRYPTO_H_ +#define TRUSTY_INTERFACE_HWCRYPTO_H_ + +#include + +#define HWCRYPTO_PORT "com.android.trusty.hwcrypto" +#define HWCRYPTO_MAX_BUFFER_LENGTH 2048 + +enum hwcrypto_command { + HWCRYPTO_REQ_SHIFT = 1, + HWCRYPTO_RESP_BIT = 1, + + HWCRYPTO_HASH = (1 << HWCRYPTO_REQ_SHIFT), + HWCRYPTO_ENCAP_BLOB = (2 << HWCRYPTO_REQ_SHIFT), + HWCRYPTO_GEN_RNG = (3 << HWCRYPTO_REQ_SHIFT), +}; + +/** + * enum hwcrypto_error - error codes for HWCRYPTO protocol + * @HWCRYPTO_ERROR_NONE: All OK + * @HWCRYPTO_ERROR_INVALID: Invalid input + * @HWCRYPTO_ERROR_INTERNAL: Error occurred during an operation in Trusty + */ +enum hwcrypto_error { + HWCRYPTO_ERROR_NONE = 0, + HWCRYPTO_ERROR_INVALID = 1, + HWCRYPTO_ERROR_INTERNAL = 2, +}; + +enum hwcrypto_hash_algo { + SHA1 = 0, + SHA256 +}; +/** + * hwcrypto_message - Serial header for communicating with hwcrypto server + * @cmd: the command. Payload must be a serialized buffer of the + * corresponding request object. + * @result: resulting error code for message, one of hwcrypto_error. + * @payload: start of the serialized command specific payload + */ +struct hwcrypto_message { + uint32_t cmd; + uint32_t result; + uint8_t payload[0]; +}; + +/** + * hwcrypto_hash_msg - Serial header for communicating with hwcrypto server + * @in_addr: start address of the input buf. + * @in_len: size of the input buf. + * @out_addr: start addrss of the output buf. + * @out_len: size of the output buf. + * @algo: hash algorithm expect to use. + */ +typedef struct hwcrypto_hash_msg { + uint32_t in_addr; + uint32_t in_len; + uint32_t out_addr; + uint32_t out_len; + enum hwcrypto_hash_algo algo; +} hwcrypto_hash_msg; + +/** + * @plain_pa: physical start address of the plain blob buf. + * @plain_size: size of the plain blob. + * @blob: physical start addrss of the output buf. + */ +typedef struct hwcrypto_blob_msg { + uint32_t plain_pa; + uint32_t plain_size; + uint32_t blob_pa; +}hwcrypto_blob_msg; + +/** + * @buf: physical start address of the output rng buf. + * @len: size of required rng. + */ +typedef struct hwcrypto_rng_msg { + uint32_t buf; + uint32_t len; +}hwcrypto_rng_msg; +#endif /* TRUSTY_INTERFACE_HWCRYPTO_H_ */ diff --git a/include/interface/keymaster/keymaster.h b/include/interface/keymaster/keymaster.h new file mode 100644 index 0000000000..a5e3e8b4c7 --- /dev/null +++ b/include/interface/keymaster/keymaster.h @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef TRUSTY_INTERFACE_KEYMASTER_H_ +#define TRUSTY_INTERFACE_KEYMASTER_H_ + +#include + +#define KEYMASTER_PORT "com.android.trusty.keymaster" +#define KEYMASTER_MAX_BUFFER_LENGTH 4096 + +enum keymaster_command { + KEYMASTER_RESP_BIT = 1, + KEYMASTER_STOP_BIT = 2, + KEYMASTER_REQ_SHIFT = 2, + + KM_GENERATE_KEY = (0 << KEYMASTER_REQ_SHIFT), + KM_BEGIN_OPERATION = (1 << KEYMASTER_REQ_SHIFT), + KM_UPDATE_OPERATION = (2 << KEYMASTER_REQ_SHIFT), + KM_FINISH_OPERATION = (3 << KEYMASTER_REQ_SHIFT), + KM_ABORT_OPERATION = (4 << KEYMASTER_REQ_SHIFT), + KM_IMPORT_KEY = (5 << KEYMASTER_REQ_SHIFT), + + KM_EXPORT_KEY = (6 << KEYMASTER_REQ_SHIFT), + KM_GET_VERSION = (7 << KEYMASTER_REQ_SHIFT), + KM_ADD_RNG_ENTROPY = (8 << KEYMASTER_REQ_SHIFT), + KM_GET_SUPPORTED_ALGORITHMS = (9 << KEYMASTER_REQ_SHIFT), + KM_GET_SUPPORTED_BLOCK_MODES = (10 << KEYMASTER_REQ_SHIFT), + KM_GET_SUPPORTED_PADDING_MODES = (11 << KEYMASTER_REQ_SHIFT), + KM_GET_SUPPORTED_DIGESTS = (12 << KEYMASTER_REQ_SHIFT), + KM_GET_SUPPORTED_IMPORT_FORMATS = (13 << KEYMASTER_REQ_SHIFT), + KM_GET_SUPPORTED_EXPORT_FORMATS = (14 << KEYMASTER_REQ_SHIFT), + KM_GET_KEY_CHARACTERISTICS = (15 << KEYMASTER_REQ_SHIFT), + + // Bootloader calls. + KM_SET_BOOT_PARAMS = (0x1000 << KEYMASTER_REQ_SHIFT), + KM_SET_ATTESTATION_KEY = (0x2000 << KEYMASTER_REQ_SHIFT), + KM_APPEND_ATTESTATION_CERT_CHAIN = (0x3000 << KEYMASTER_REQ_SHIFT), + KM_ATAP_GET_CA_REQUEST = (0x4000 << KEYMASTER_REQ_SHIFT), + KM_ATAP_SET_CA_RESPONSE_BEGIN = (0x5000 << KEYMASTER_REQ_SHIFT), + KM_ATAP_SET_CA_RESPONSE_UPDATE = (0x6000 << KEYMASTER_REQ_SHIFT), + KM_ATAP_SET_CA_RESPONSE_FINISH = (0x7000 << KEYMASTER_REQ_SHIFT), + KM_ATAP_READ_UUID = (0x8000 << KEYMASTER_REQ_SHIFT), + KM_SET_PRODUCT_ID = (0x9000 << KEYMASTER_REQ_SHIFT) +}; + +typedef enum { + KM_VERIFIED_BOOT_VERIFIED = 0, /* Full chain of trust extending from the bootloader to + * verified partitions, including the bootloader, boot + * partition, and all verified partitions*/ + KM_VERIFIED_BOOT_SELF_SIGNED = 1, /* The boot partition has been verified using the embedded + * certificate, and the signature is valid. The bootloader + * displays a warning and the fingerprint of the public + * key before allowing the boot process to continue.*/ + KM_VERIFIED_BOOT_UNVERIFIED = 2, /* The device may be freely modified. Device integrity is left + * to the user to verify out-of-band. The bootloader + * displays a warning to the user before allowing the boot + * process to continue */ + KM_VERIFIED_BOOT_FAILED = 3, /* The device failed verification. The bootloader displays a + * warning and stops the boot process, so no keymaster + * implementation should ever actually return this value, + * since it should not run. Included here only for + * completeness. */ +} keymaster_verified_boot_t; + +/** + * Algorithms that may be provided by keymaster implementations. + */ +typedef enum { + /* Asymmetric algorithms. */ + KM_ALGORITHM_RSA = 1, + // KM_ALGORITHM_DSA = 2, -- Removed, do not re-use value 2. + KM_ALGORITHM_EC = 3, + + /* Block ciphers algorithms */ + KM_ALGORITHM_AES = 32, + + /* MAC algorithms */ + KM_ALGORITHM_HMAC = 128, +} keymaster_algorithm_t; + +typedef enum { + KM_ERROR_OK = 0, + KM_ERROR_ROOT_OF_TRUST_ALREADY_SET = -1, + KM_ERROR_UNSUPPORTED_PURPOSE = -2, + KM_ERROR_INCOMPATIBLE_PURPOSE = -3, + KM_ERROR_UNSUPPORTED_ALGORITHM = -4, + KM_ERROR_INCOMPATIBLE_ALGORITHM = -5, + KM_ERROR_UNSUPPORTED_KEY_SIZE = -6, + KM_ERROR_UNSUPPORTED_BLOCK_MODE = -7, + KM_ERROR_INCOMPATIBLE_BLOCK_MODE = -8, + KM_ERROR_UNSUPPORTED_MAC_LENGTH = -9, + KM_ERROR_UNSUPPORTED_PADDING_MODE = -10, + KM_ERROR_INCOMPATIBLE_PADDING_MODE = -11, + KM_ERROR_UNSUPPORTED_DIGEST = -12, + KM_ERROR_INCOMPATIBLE_DIGEST = -13, + KM_ERROR_INVALID_EXPIRATION_TIME = -14, + KM_ERROR_INVALID_USER_ID = -15, + KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT = -16, + KM_ERROR_UNSUPPORTED_KEY_FORMAT = -17, + KM_ERROR_INCOMPATIBLE_KEY_FORMAT = -18, + KM_ERROR_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = -19, /* For PKCS8 & PKCS12 */ + KM_ERROR_UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = -20, /* For PKCS8 & PKCS12 */ + KM_ERROR_INVALID_INPUT_LENGTH = -21, + KM_ERROR_KEY_EXPORT_OPTIONS_INVALID = -22, + KM_ERROR_DELEGATION_NOT_ALLOWED = -23, + KM_ERROR_KEY_NOT_YET_VALID = -24, + KM_ERROR_KEY_EXPIRED = -25, + KM_ERROR_KEY_USER_NOT_AUTHENTICATED = -26, + KM_ERROR_OUTPUT_PARAMETER_NULL = -27, + KM_ERROR_INVALID_OPERATION_HANDLE = -28, + KM_ERROR_INSUFFICIENT_BUFFER_SPACE = -29, + KM_ERROR_VERIFICATION_FAILED = -30, + KM_ERROR_TOO_MANY_OPERATIONS = -31, + KM_ERROR_UNEXPECTED_NULL_POINTER = -32, + KM_ERROR_INVALID_KEY_BLOB = -33, + KM_ERROR_IMPORTED_KEY_NOT_ENCRYPTED = -34, + KM_ERROR_IMPORTED_KEY_DECRYPTION_FAILED = -35, + KM_ERROR_IMPORTED_KEY_NOT_SIGNED = -36, + KM_ERROR_IMPORTED_KEY_VERIFICATION_FAILED = -37, + KM_ERROR_INVALID_ARGUMENT = -38, + KM_ERROR_UNSUPPORTED_TAG = -39, + KM_ERROR_INVALID_TAG = -40, + KM_ERROR_MEMORY_ALLOCATION_FAILED = -41, + KM_ERROR_IMPORT_PARAMETER_MISMATCH = -44, + KM_ERROR_SECURE_HW_ACCESS_DENIED = -45, + KM_ERROR_OPERATION_CANCELLED = -46, + KM_ERROR_CONCURRENT_ACCESS_CONFLICT = -47, + KM_ERROR_SECURE_HW_BUSY = -48, + KM_ERROR_SECURE_HW_COMMUNICATION_FAILED = -49, + KM_ERROR_UNSUPPORTED_EC_FIELD = -50, + KM_ERROR_MISSING_NONCE = -51, + KM_ERROR_INVALID_NONCE = -52, + KM_ERROR_MISSING_MAC_LENGTH = -53, + KM_ERROR_KEY_RATE_LIMIT_EXCEEDED = -54, + KM_ERROR_CALLER_NONCE_PROHIBITED = -55, + KM_ERROR_KEY_MAX_OPS_EXCEEDED = -56, + KM_ERROR_INVALID_MAC_LENGTH = -57, + KM_ERROR_MISSING_MIN_MAC_LENGTH = -58, + KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH = -59, + KM_ERROR_UNSUPPORTED_KDF = -60, + KM_ERROR_UNSUPPORTED_EC_CURVE = -61, + KM_ERROR_KEY_REQUIRES_UPGRADE = -62, + KM_ERROR_ATTESTATION_CHALLENGE_MISSING = -63, + KM_ERROR_KEYMASTER_NOT_CONFIGURED = -64, + + KM_ERROR_UNIMPLEMENTED = -100, + KM_ERROR_VERSION_MISMATCH = -101, + + KM_ERROR_UNKNOWN_ERROR = -1000, +} keymaster_error_t; + +/** + * keymaster_message - Serial header for communicating with KM server + * + * @cmd: the command, one of keymaster_command. + * @payload: start of the serialized command specific payload + */ +struct keymaster_message { + uint32_t cmd; + uint8_t payload[0]; +}; + +/** + * km_no_response - Generic keymaster response for commands with no special + * response data + * + * @error: error code from command + */ +struct km_no_response { + int32_t error; +}; + +/** + * km_get_version_resp - response format for KM_GET_VERSION. + */ +struct km_get_version_resp { + int32_t error; + uint8_t major_ver; + uint8_t minor_ver; + uint8_t subminor_ver; +} TRUSTY_ATTR_PACKED; + +/** + * km_raw_buffer_resp - response format for a raw buffer + */ +struct km_raw_buffer_resp { + int32_t error; + uint32_t data_size; + int8_t data[0]; +} TRUSTY_ATTR_PACKED; + +/** + * km_set_ca_response_begin_req - starts the process to set the ATAP CA Response + * + * @ca_response_size: total size of the CA Response message + */ +struct km_set_ca_response_begin_req { + uint32_t ca_response_size; +} TRUSTY_ATTR_PACKED; + +/** + * km_boot_params - Parameters sent from the bootloader to the Keymaster TA + * + * Since verified_boot_key_hash and verified_boot_hash have variable sizes, this + * structure must be serialized before sending to the secure side + * using km_boot_params_serialize(). + * + * @os_version: OS version from Android image header + * @os_patchlevel: OS patch level from Android image header + * @device_locked: nonzero if device is locked + * @verified_boot_state: one of keymaster_verified_boot_t + * @verified_boot_key_hash_size: size of verified_boot_key_hash + * @verified_boot_key_hash: hash of key used to verify Android image + * @verified_boot_hash_size: size of verified_boot_hash + * @verified_boot_hash: cumulative hash of all images verified thus far + */ +struct km_boot_params { + uint32_t os_version; + uint32_t os_patchlevel; + uint32_t device_locked; + uint32_t verified_boot_state; + uint32_t verified_boot_key_hash_size; + const uint8_t *verified_boot_key_hash; + uint32_t verified_boot_hash_size; + const uint8_t *verified_boot_hash; +} TRUSTY_ATTR_PACKED; + +/** + * km_attestation_data - represents a DER encoded key or certificate + * + * @algorithm: one of KM_ALGORITHM_RSA or KM_ALGORITHM_EC + * @data_size: size of |data| + * @data: DER encoded key or certificate (depending on operation) + */ +struct km_attestation_data { + uint32_t algorithm; + uint32_t data_size; + const uint8_t *data; +} TRUSTY_ATTR_PACKED; + +/** + * km_raw_buffer - represents a single raw buffer + * + * @data_size: size of |data| + * @data: pointer to the buffer + */ +struct km_raw_buffer { + uint32_t data_size; + const uint8_t *data; +} TRUSTY_ATTR_PACKED; + +#endif /* TRUSTY_INTERFACE_KEYMASTER_H_ */ diff --git a/include/interface/storage/storage.h b/include/interface/storage/storage.h new file mode 100644 index 0000000000..e4f7f83656 --- /dev/null +++ b/include/interface/storage/storage.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef TRUSTY_INTERFACE_STORAGE_H_ +#define TRUSTY_INTERFACE_STORAGE_H_ + +/* + * The contents of this file are copied from + * trusty/lib/interface/storage/include/interface/storage/storage.h. + * It is required to stay in sync for struct formats and enum values. + */ + +#include + +/* + * @STORAGE_DISK_PROXY_PORT: Port used by non-secure proxy server + */ +#define STORAGE_DISK_PROXY_PORT "com.android.trusty.storage.proxy" + +enum storage_cmd { + STORAGE_REQ_SHIFT = 1, + STORAGE_RESP_BIT = 1, + + STORAGE_RESP_MSG_ERR = STORAGE_RESP_BIT, + + STORAGE_FILE_DELETE = 1 << STORAGE_REQ_SHIFT, + STORAGE_FILE_OPEN = 2 << STORAGE_REQ_SHIFT, + STORAGE_FILE_CLOSE = 3 << STORAGE_REQ_SHIFT, + STORAGE_FILE_READ = 4 << STORAGE_REQ_SHIFT, + STORAGE_FILE_WRITE = 5 << STORAGE_REQ_SHIFT, + STORAGE_FILE_GET_SIZE = 6 << STORAGE_REQ_SHIFT, + STORAGE_FILE_SET_SIZE = 7 << STORAGE_REQ_SHIFT, + + STORAGE_RPMB_SEND = 8 << STORAGE_REQ_SHIFT, + + /* transaction support */ + STORAGE_END_TRANSACTION = 9 << STORAGE_REQ_SHIFT, +}; + +/** + * enum storage_err - error codes for storage protocol + * @STORAGE_NO_ERROR: all OK + * @STORAGE_ERR_GENERIC: unknown error. Can occur when there's an internal server + * error, e.g. the server runs out of memory or is in a bad state. + * @STORAGE_ERR_NOT_VALID: input not valid. May occur if the arguments passed + * into the command are not valid, for example if the file handle + * passed in is not a valid one. + * @STORAGE_ERR_UNIMPLEMENTED: the command passed in is not recognized + * @STORAGE_ERR_ACCESS: the file is not accessible in the requested mode + * @STORAGE_ERR_NOT_FOUND: the file was not found + * @STORAGE_ERR_EXIST the file exists when it shouldn't as in with OPEN_CREATE | OPEN_EXCLUSIVE. + * @STORAGE_ERR_TRANSACT returned by various operations to indicate that current transaction + * is in error state. Such state could be only cleared by sending + * STORAGE_END_TRANSACTION message. + */ +enum storage_err { + STORAGE_NO_ERROR = 0, + STORAGE_ERR_GENERIC = 1, + STORAGE_ERR_NOT_VALID = 2, + STORAGE_ERR_UNIMPLEMENTED = 3, + STORAGE_ERR_ACCESS = 4, + STORAGE_ERR_NOT_FOUND = 5, + STORAGE_ERR_EXIST = 6, + STORAGE_ERR_TRANSACT = 7, +}; + +/** + * enum storage_msg_flag - protocol-level flags in struct storage_msg + * @STORAGE_MSG_FLAG_BATCH: if set, command belongs to a batch transaction. + * No response will be sent by the server until + * it receives a command with this flag unset, at + * which point a cummulative result for all messages + * sent with STORAGE_MSG_FLAG_BATCH will be sent. + * This is only supported by the non-secure disk proxy + * server. + * @STORAGE_MSG_FLAG_PRE_COMMIT: if set, indicates that server need to commit + * pending changes before processing this message. + * @STORAGE_MSG_FLAG_POST_COMMIT: if set, indicates that server need to commit + * pending changes after processing this message. + * @STORAGE_MSG_FLAG_TRANSACT_COMPLETE: if set, indicates that server need to commit + * current transaction after processing this message. + * It is an alias for STORAGE_MSG_FLAG_POST_COMMIT. + */ +enum storage_msg_flag { + STORAGE_MSG_FLAG_BATCH = 0x1, + STORAGE_MSG_FLAG_PRE_COMMIT = 0x2, + STORAGE_MSG_FLAG_POST_COMMIT = 0x4, + STORAGE_MSG_FLAG_TRANSACT_COMPLETE = STORAGE_MSG_FLAG_POST_COMMIT, +}; + +/* + * The following declarations are the message-specific contents of + * the 'payload' element inside struct storage_msg. + */ + +/** + * struct storage_rpmb_send_req - request format for STORAGE_RPMB_SEND + * @reliable_write_size: size in bytes of reliable write region + * @write_size: size in bytes of write region + * @read_size: number of bytes to read for a read request + * @__reserved: unused, must be set to 0 + * @payload: start of reliable write region, followed by + * write region. + * + * Only used in proxy<->server interface. + */ +struct storage_rpmb_send_req { + uint32_t reliable_write_size; + uint32_t write_size; + uint32_t read_size; + uint32_t __reserved; + uint8_t payload[0]; +}; + +/** + * struct storage_rpmb_send_resp: response type for STORAGE_RPMB_SEND + * @data: the data frames frames retrieved from the MMC. + */ +struct storage_rpmb_send_resp { + uint8_t data[0]; +}; + +/** + * struct storage_msg - generic req/resp format for all storage commands + * @cmd: one of enum storage_cmd + * @op_id: client chosen operation identifier for an instance + * of a command or atomic grouping of commands (transaction). + * @flags: one or many of enum storage_msg_flag or'ed together. + * @size: total size of the message including this header + * @result: one of enum storage_err + * @__reserved: unused, must be set to 0. + * @payload: beginning of command specific message format + */ +struct storage_msg { + uint32_t cmd; + uint32_t op_id; + uint32_t flags; + uint32_t size; + int32_t result; + uint32_t __reserved; + uint8_t payload[0]; +}; + +#endif /* TRUSTY_INTERFACE_STORAGE_H_ */ diff --git a/include/trusty/avb.h b/include/trusty/avb.h new file mode 100644 index 0000000000..daaac2cae5 --- /dev/null +++ b/include/trusty/avb.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef TRUSTY_AVB_H_ +#define TRUSTY_AVB_H_ + +#include +#include +#include + +/* + * Initialize AVB TIPC client. Returns one of trusty_err. + * + * @dev: initialized with trusty_ipc_dev_create + */ +int avb_tipc_init(struct trusty_ipc_dev *dev); +/* + * Shutdown AVB TIPC client. + * + * @dev: initialized with trusty_ipc_dev_create + */ +void avb_tipc_shutdown(struct trusty_ipc_dev *dev); +/* + * Send request to secure side to read rollback index. + * Returns one of trusty_err. + * + * @slot: rollback index slot + * @value: rollback index value stored here + */ +int trusty_read_rollback_index(uint32_t slot, uint64_t *value); +/* + * Send request to secure side to write rollback index + * Returns one of trusty_err. + * + * @slot: rollback index slot + * @value: rollback index value to write + */ +int trusty_write_rollback_index(uint32_t slot, uint64_t value); +/* + * Send request to secure side to read permanent attributes. When permanent + * attributes are stored in RPMB, a hash of the permanent attributes which is + * given to AVB during verification MUST still be backed by write-once hardware. + * + * Copies attributes received by secure side to |attributes|. If |size| does not + * match the size returned by the secure side, an error is returned. Returns one + * of trusty_err. + * + * @attributes: caller allocated buffer + * @size: size of |attributes| + */ +int trusty_read_permanent_attributes(uint8_t *attributes, uint32_t size); +/* + * Send request to secure side to write permanent attributes. Permanent + * attributes can only be written to storage once. + * + * Returns one of trusty_err. + */ +int trusty_write_permanent_attributes(uint8_t *attributes, uint32_t size); +/* + * Send request to secure side to read vbmeta public key. + * + * Copies public key received by secure side to |publickey|. If |size| does not + * match the size returned by the secure side, an error is returned. Returns one + * of trusty_err. + * + * @publickey: caller allocated buffer + * @size: size of |publickey| + */ +int trusty_read_vbmeta_public_key(uint8_t *publickey, uint32_t size); +/* + * Send request to secure side to write vbmeta public key. Public key + * can only be written to storage once. + * + * Returns one of trusty_err. + */ +int trusty_write_vbmeta_public_key(uint8_t *publickey, uint32_t size); +/* + * Send request to secure side to read device lock state from RPMB. + * + * Returns one of trusty_err. + */ +int trusty_read_lock_state(uint8_t *lock_state); +/* + * Send request to secure side to write device lock state to RPMB. If the lock + * state is changed, all rollback index data will be cleared. + * + * Returns one of trusty_err. + */ +int trusty_write_lock_state(uint8_t lock_state); +/* + * Send request to secure side to lock the boot state. After this is invoked, + * the non-secure side will not be able to write to data managed by the AVB + * service until next boot. + * + * Returns one of trusty_err. + */ +int trusty_lock_boot_state(void); + +#endif /* TRUSTY_AVB_H_ */ diff --git a/include/trusty/hwcrypto.h b/include/trusty/hwcrypto.h new file mode 100644 index 0000000000..9a510a889d --- /dev/null +++ b/include/trusty/hwcrypto.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * Copyright NXP 2018 + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef TRUSTY_HWCRYPTO_H_ +#define TRUSTY_HWCRYPTO_H_ + +#include +#include +#include + +/* + * Initialize HWCRYPTO TIPC client. Returns one of trusty_err. + * + * @dev: initialized with trusty_ipc_dev_create + */ +int hwcrypto_tipc_init(struct trusty_ipc_dev *dev); +/* + * Shutdown HWCRYPTO TIPC client. + * + * @dev: initialized with trusty_ipc_dev_create + */ +void hwcrypto_tipc_shutdown(struct trusty_ipc_dev *dev); +/* + * Send request to secure side to calculate sha256 hash with caam. + * Returns one of trusty_err. + * + * @in_addr: start address of the input buf + * @in_len: size of the input buf + * @out_addr: start address of the output buf + * @out_len: size of the output buf + * @algo: hash algorithm type expect to use + */ +int hwcrypto_hash(uint32_t in_addr, uint32_t in_len, uint32_t out_addr, + uint32_t out_len, enum hwcrypto_hash_algo algo); + +/* + * Send request to secure side to generate blob with caam. + * Returns one of trusty_err. + * + * @plain_pa: physical start address of the plain blob buffer. + * @plain_size: size of the plain blob buffer. + * @blob_pa: physical start address of the generated blob buffer. + */ +int hwcrypto_gen_blob(uint32_t plain_pa, + uint32_t plain_size, uint32_t blob_pa); + +/* Send request to secure side to generate rng with caam. + * Returns one of trusty_err. + * + * @buf: physical start address of the output rng buf. + * @len: size of required rng. + * */ +int hwcrypto_gen_rng(uint32_t buf, uint32_t len); +#endif /* TRUSTY_HWCRYPTO_H_ */ diff --git a/include/trusty/keymaster.h b/include/trusty/keymaster.h new file mode 100644 index 0000000000..eadb0d1319 --- /dev/null +++ b/include/trusty/keymaster.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef TRUSTY_KEYMASTER_H_ +#define TRUSTY_KEYMASTER_H_ + +#include +#include +#include + +/* + * Initialize Keymaster TIPC client. Returns one of trusty_err. + * + * @dev: initialized with trusty_ipc_dev_create + */ +int km_tipc_init(struct trusty_ipc_dev *dev); + +/* + * Shutdown Keymaster TIPC client. + * + * @dev: initialized with trusty_ipc_dev_create + */ +void km_tipc_shutdown(struct trusty_ipc_dev *dev); + +/* + * Set Keymaster boot parameters. Returns one of trusty_err. + * + * @os_version: OS version from Android image header + * @os_patchlevel: OS patch level from Android image header + * @verified_boot_state: one of keymaster_verified_boot_t + * @device_locked: nonzero if device is locked + * @verified_boot_key_hash: hash of key used to verify Android image + * @verified_boot_key_hash_size: size of verified_boot_key_hash + * @verified_boot_hash: cumulative hash of all images verified thus far. + * May be NULL if not computed. + * @verified_boot_hash_size: size of verified_boot_hash + */ +int trusty_set_boot_params(uint32_t os_version, uint32_t os_patchlevel, + keymaster_verified_boot_t verified_boot_state, + bool device_locked, + const uint8_t *verified_boot_key_hash, + uint32_t verified_boot_key_hash_size, + const uint8_t *verified_boot_hash, + uint32_t verified_boot_hash_size); + +/* + * Set Keymaster attestation key. Returns one of trusty_err. + * + * @key: buffer containing key + * @key_size: size of key in bytes + * @algorithm: one of KM_ALGORITHM_RSA or KM_ALGORITHM_EC + */ +int trusty_set_attestation_key(const uint8_t *key, uint32_t key_size, + keymaster_algorithm_t algorithm); + +/* + * Append certificate to Keymaster attestation certificate chain. Returns + * one of trusty_err. + * + * @cert: buffer containing certificate + * @cert_size: size of certificate in bytes + * @algorithm: one of KM_ALGORITHM_RSA or KM_ALGORITHM_EC + */ +int trusty_append_attestation_cert_chain(const uint8_t *cert, + uint32_t cert_size, + keymaster_algorithm_t algorithm); +/* + * Reads a CA Request from Keymaster. On success allocates a new CA Request + * message at |*ca_request_p|, and the caller takes ownership. Returns one + * of trusty_err. + * + * @operation_start: Operation Start message + * @operation_start_size: size of operation_start + * @ca_request_p: location of newly allocated CA Request message + * @ca_request_size_p: location of size of the CA Request message + */ +int trusty_atap_get_ca_request(const uint8_t *operation_start, + uint32_t operation_start_size, + uint8_t** ca_request_p, + uint32_t* ca_request_size_p); +/* + * Sends the CA Response to Keymaster. Returns one of trusty_err. + * + * @ca_response: CA Response message + * @ca_response_size: size of ca_response + */ +int trusty_atap_set_ca_response(const uint8_t *ca_response, + uint32_t ca_response_size); + +/* +* Reads the UUID from the certificate of the last provisioned attestation +* credentials as a c-string into |*uuid_p|. Caller takes ownership of +* |*uuid_p|. Returns one of trusty_err. +* +* @uuid_p: location of newly allocated UUID c-string +*/ +int trusty_atap_read_uuid_str(char **uuid_p); + +/* + * SetProductId is only called once to set the secure product id. Caller should + * read the product id from permanent attributes structure and set the product + * id while fusing the permanent attributes. + * + * @product_id: The product id to be set. + * @size: The size of the product id. + */ +int trusty_set_product_id(const uint8_t *product_id, uint32_t size); + +#endif /* TRUSTY_KEYMASTER_H_ */ diff --git a/include/trusty/keymaster_serializable.h b/include/trusty/keymaster_serializable.h new file mode 100644 index 0000000000..196e606fe8 --- /dev/null +++ b/include/trusty/keymaster_serializable.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef TRUSTY_KEYMASTER_SERIALIZABLE_H_ +#define TRUSTY_KEYMASTER_SERIALIZABLE_H_ + +#include + +/** + * Simple serialization routines for dynamically sized keymaster messages. + */ + +/** + * Appends |data_len| bytes at |data| to |buf|. Performs no bounds checking, + * assumes sufficient memory allocated at |buf|. Returns |buf| + |data_len|. + */ +uint8_t *append_to_buf(uint8_t *buf, const void *data, size_t data_len); + +/** + * Appends |val| to |buf|. Performs no bounds checking. Returns |buf| + + * sizeof(uint32_t). + */ +uint8_t *append_uint32_to_buf(uint8_t *buf, uint32_t val); + +/** + * Appends a sized buffer to |buf|. First appends |data_len| to |buf|, then + * appends |data_len| bytes at |data| to |buf|. Performs no bounds checking. + * Returns |buf| + sizeof(uint32_t) + |data_len|. + */ +uint8_t *append_sized_buf_to_buf(uint8_t *buf, const uint8_t *data, + uint32_t data_len); + +/** + * Serializes a km_boot_params structure. On success, allocates |*out_size| + * bytes to |*out| and writes the serialized |params| to |*out|. Caller takes + * ownership of |*out|. Returns one of trusty_err. + */ +int km_boot_params_serialize(const struct km_boot_params *params, uint8_t **out, + uint32_t *out_size); + +/** + * Serializes a km_attestation_data structure. On success, allocates |*out_size| + * bytes to |*out| and writes the serialized |data| to |*out|. Caller takes + * ownership of |*out|. Returns one of trusty_err. + */ +int km_attestation_data_serialize(const struct km_attestation_data *data, + uint8_t **out, uint32_t *out_size); + +/** + * Serializes a km_raw_buffer structure. On success, allocates |*out_size| + * bytes to |*out| and writes the serialized |data| to |*out|. Caller takes + * ownership of |*out|. Returns one of trusty_err. + */ +int km_raw_buffer_serialize(const struct km_raw_buffer *buf, uint8_t** out, + uint32_t *out_size); + +#endif /* TRUSTY_KEYMASTER_SERIALIZABLE_H_ */ diff --git a/include/trusty/libtipc.h b/include/trusty/libtipc.h new file mode 100644 index 0000000000..69e480104c --- /dev/null +++ b/include/trusty/libtipc.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef TRUSTY_LIBTIPC_H_ +#define TRUSTY_LIBTIPC_H_ + +#include +#include +#include + +/* + * Initialize TIPC library + */ +int trusty_ipc_init(void); +/* + * Shutdown TIPC library + */ +void trusty_ipc_shutdown(void); + +#endif /* TRUSTY_LIBTIPC_H_ */ diff --git a/include/trusty/rpmb.h b/include/trusty/rpmb.h new file mode 100644 index 0000000000..e29a608a4b --- /dev/null +++ b/include/trusty/rpmb.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef TRUSTY_RPMB_H_ +#define TRUSTY_RPMB_H_ + +#include +#include + +#define MMC_BLOCK_SIZE 512 + +/* + * Initialize RPMB storage proxy. Returns one of trusty_err. + * + * @dev: initialized with trusty_ipc_dev_create + * @rpmb_dev: Context of RPMB device, initialized with rpmb_storage_get_ctx + */ +int rpmb_storage_proxy_init(struct trusty_ipc_dev *dev, void *rpmb_dev); +/* + * Shutdown RPMB storage proxy + * + * @dev: initialized with trusty_ipc_dev_create + */ +void rpmb_storage_proxy_shutdown(struct trusty_ipc_dev *dev); +/* + * Execute RPMB command. Implementation is platform specific. + * Returns one of trusty_err. + * + * @rpmb_dev: Context of RPMB device, initialized with + * rpmb_storage_get_ctx + * @reliable_write_data: Buffer containing RPMB structs for reliable write + * @reliable_write_size: Size of reliable_write_data + * @write_data: Buffer containing RPMB structs for write + * @write_size: Size of write_data + * @read_data: Buffer to be filled with RPMB structs read from RPMB + * partition + * @read_size: Size of read_data + */ +int rpmb_storage_send(void *rpmb_dev, + const void *reliable_write_data, + size_t reliable_write_size, + const void *write_data, size_t write_size, + void *read_buf, size_t read_size); +/* + * Return context for RPMB device. This is called when the RPMB storage proxy is + * initialized, and subsequently used when issuing RPMB storage requests. + * Implementation is platform specific. + */ +void *rpmb_storage_get_ctx(void); + +/* + * Put back RPMB device. This is called when the RPMB storage proxy is + * shutdown + */ +void rpmb_storage_put_ctx(void *dev); + +#endif /* TRUSTY_RPMB_H_ */ diff --git a/include/trusty/sysdeps.h b/include/trusty/sysdeps.h new file mode 100644 index 0000000000..1f26bbd4c3 --- /dev/null +++ b/include/trusty/sysdeps.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef TRUSTY_SYSDEPS_H_ +#define TRUSTY_SYSDEPS_H_ +/* + * Change these includes to match your platform to bring in the equivalent + * types available in a normal C runtime. At least things like uint64_t, + * uintptr_t, and bool (with |false|, |true| keywords) must be present. + */ +#include +#include + +/* + * These attribute macros may need to be adjusted if not using gcc or clang. + */ +#define TRUSTY_ATTR_PACKED __attribute__((packed)) +#define TRUSTY_ATTR_NO_RETURN __attribute__((noreturn)) +#define TRUSTY_ATTR_SENTINEL __attribute__((__sentinel__)) +#define TRUSTY_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) + +#define PAGE_SIZE 4096 +/* + * Struct containing attributes for memory to be shared with secure size. + */ +struct ns_mem_page_info { + uint64_t attr; +}; + +struct trusty_dev; + +/* + * Lock/unlock mutex associated with @dev. These can be safely empty in a single + * threaded environment. + * + * @dev: Trusty device initialized with trusty_dev_init + */ +void trusty_lock(struct trusty_dev *dev); +void trusty_unlock(struct trusty_dev *dev); +/* + * Disable/enable IRQ interrupts and save/restore @state + */ +void trusty_local_irq_disable(unsigned long *state); +void trusty_local_irq_restore(unsigned long *state); +/* + * Put in standby state waiting for interrupt. + * + * @dev: Trusty device initialized with trusty_dev_init + */ +void trusty_idle(struct trusty_dev *dev); +/* + * Aborts the program or reboots the device. + */ +void trusty_abort(void) TRUSTY_ATTR_NO_RETURN; +/* + * Print a formatted string. @format must point to a NULL-terminated string, and + * is followed by arguments to be printed. + */ +void trusty_printf(const char *format, ...); +/* + * Copy @n bytes from @src to @dest. + */ +void *trusty_memcpy(void *dest, const void *src, size_t n); +/* + * Set @n bytes starting at @dest to @c. Returns @dest. + */ +void *trusty_memset(void *dest, const int c, size_t n); +/* + * Copy string from @src to @dest, including the terminating NULL byte. + * + * The size of the array at @dest should be long enough to contain the string + * at @src, and should not overlap in memory with @src. + */ +char *trusty_strcpy(char *dest, const char *src); +/* + * Returns the length of @str, excluding the terminating NULL byte. + */ +size_t trusty_strlen(const char *str); +/* + * Allocate @n elements of size @size. Initializes memory to 0, returns pointer + * to it. + */ +void *trusty_calloc(size_t n, size_t size) TRUSTY_ATTR_WARN_UNUSED_RESULT; +/* + * Free memory at @addr allocated with trusty_calloc. + */ +void trusty_free(void *addr); +/* + * Allocate @count contiguous pages to be shared with secure side. + * + * Returns: vaddr of allocated memory + */ +void *trusty_alloc_pages(unsigned count) TRUSTY_ATTR_WARN_UNUSED_RESULT; +/* + * Free @count pages at @vaddr allocated by trusty_alloc_pages + */ +void trusty_free_pages(void *vaddr, unsigned count); + +#endif /* TRUSTY_SYSDEPS_H_ */ diff --git a/include/trusty/trusty_dev.h b/include/trusty/trusty_dev.h new file mode 100644 index 0000000000..27ae8cca83 --- /dev/null +++ b/include/trusty/trusty_dev.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef TRUSTY_TRUSTY_DEV_H_ +#define TRUSTY_TRUSTY_DEV_H_ + +#include + +/* + * Architecture specific Trusty device struct. + * + * @priv_data: system dependent data, may be unused + * @api_version: TIPC version + */ +struct trusty_dev { + void *priv_data; + uint32_t api_version; +}; + +/* + * Initializes @dev with @priv, and gets the API version by calling + * into Trusty. Returns negative on error. + */ +int trusty_dev_init(struct trusty_dev *dev, void *priv); + +/* + * Cleans up anything related to @dev. Returns negative on error. + */ +int trusty_dev_shutdown(struct trusty_dev *dev); + +/* + * Invokes creation of queueless Trusty IPC device on the secure side. + * @buf will be mapped into Trusty's address space. + * + * @dev: trusty device, initialized with trusty_dev_init + * @buf: physical address info of buffer to share with Trusty + * @buf_size: size of @buf + */ +int trusty_dev_init_ipc(struct trusty_dev *dev, struct ns_mem_page_info *buf, + uint32_t buf_size); +/* + * Invokes execution of command on the secure side. + * + * @dev: trusty device, initialized with trusty_dev_init + * @buf: physical address info of shared buffer containing command + * @buf_size: size of command data + */ +int trusty_dev_exec_ipc(struct trusty_dev *dev, struct ns_mem_page_info *buf, + uint32_t buf_size); +/* + * Invokes deletion of queueless Trusty IPC device on the secure side. + * @buf is unmapped, and all open channels are closed. + * + * @dev: trusty device, initialized with trusty_dev_init + * @buf: physical address info of shared buffer + * @buf_size: size of @buf + */ +int trusty_dev_shutdown_ipc(struct trusty_dev *dev, + struct ns_mem_page_info *buf, uint32_t buf_size); + +#endif /* TRUSTY_TRUSTY_DEV_H_ */ diff --git a/include/trusty/trusty_ipc.h b/include/trusty/trusty_ipc.h new file mode 100644 index 0000000000..ce7cbd126a --- /dev/null +++ b/include/trusty/trusty_ipc.h @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef TRUSTY_TRUSTY_IPC_H_ +#define TRUSTY_TRUSTY_IPC_H_ + +#include + +/* + * handle_t is an opaque 32 bit value that is used to reference an + * Trusty IPC channel + */ +typedef uint32_t handle_t; + +#define INVALID_IPC_HANDLE 0 + +/* + * Error codes returned by Trusty IPC device function calls + */ +enum trusty_err { + TRUSTY_ERR_NONE = 0, + TRUSTY_ERR_GENERIC = -1, + TRUSTY_ERR_NOT_SUPPORTED = -2, + TRUSTY_ERR_NO_MEMORY = -3, + TRUSTY_ERR_INVALID_ARGS = -4, + TRUSTY_ERR_SECOS_ERR = -5, + TRUSTY_ERR_MSG_TOO_BIG = -6, + TRUSTY_ERR_NO_MSG = -7, + TRUSTY_ERR_CHANNEL_CLOSED = -8, + TRUSTY_ERR_SEND_BLOCKED = -9, +}; +/* + * Return codes for successful Trusty IPC events (failures return trusty_err) + */ +enum trusty_event_result { + TRUSTY_EVENT_HANDLED = 1, + TRUSTY_EVENT_NONE = 2 +}; + +/* + * Combination of these values are used for the event field + * of trusty_ipc_event structure. + */ +enum trusty_ipc_event_type { + IPC_HANDLE_POLL_NONE = 0x0, + IPC_HANDLE_POLL_READY = 0x1, + IPC_HANDLE_POLL_ERROR = 0x2, + IPC_HANDLE_POLL_HUP = 0x4, + IPC_HANDLE_POLL_MSG = 0x8, + IPC_HANDLE_POLL_SEND_UNBLOCKED = 0x10, +}; + +struct trusty_dev; +struct trusty_ipc_chan; + +/* + * Trusty IPC event + * + * @event: event type + * @handle: handle this event is related to + * @cookie: cookie associated with handle + */ +struct trusty_ipc_event { + uint32_t event; + uint32_t handle; + uint64_t cookie; +}; + +struct trusty_ipc_iovec { + void *base; + size_t len; +}; + +/* + * Trusty IPC device + * + * @buf_vaddr: virtual address of shared buffer associated with device + * @buf_size: size of shared buffer + * @buf_ns: physical address info of shared buffer + * @tdev: trusty device + */ +struct trusty_ipc_dev { + void *buf_vaddr; + size_t buf_size; + struct ns_mem_page_info buf_ns; + struct trusty_dev *tdev; +}; + +/* + * Trusty IPC event handlers. + */ +struct trusty_ipc_ops { + int (*on_raw_event)(struct trusty_ipc_chan *chan, + struct trusty_ipc_event *evt); + int (*on_connect_complete)(struct trusty_ipc_chan *chan); + int (*on_send_unblocked)(struct trusty_ipc_chan *chan); + int (*on_message)(struct trusty_ipc_chan *chan); + int (*on_disconnect)(struct trusty_ipc_chan *chan); +}; + +/* + * Trusty IPC channel. + * + * @ops_ctx: refers to additional data that may be used by trusty_ipc_ops + * @handle: identifier for channel + * @complete: completion status of last event on channel + * @dev: Trusty IPC device used by channel, initialized with + trusty_ipc_dev_create + * @ops: callbacks for Trusty events + */ +struct trusty_ipc_chan { + void *ops_ctx; + handle_t handle; + volatile int complete; + struct trusty_ipc_dev *dev; + struct trusty_ipc_ops *ops; +}; + +/* + * Creates new Trusty IPC device on @tdev. Allocates shared buffer, and calls + * trusty_dev_init_ipc to register with secure side. Returns a trusty_err. + * + * @ipc_dev: new Trusty IPC device to be initialized + * @tdev: associated Trusty device + * @shared_buf_size: size of shared buffer to be allocated + */ +int trusty_ipc_dev_create(struct trusty_ipc_dev **ipc_dev, + struct trusty_dev *tdev, + size_t shared_buf_size); +/* + * Shutdown @dev. Frees shared buffer, and calls trusty_dev_shutdown_ipc + * to shutdown on the secure side. + */ +void trusty_ipc_dev_shutdown(struct trusty_ipc_dev *dev); + +/* + * Calls into secure OS to initiate a new connection to a Trusty IPC service. + * Returns handle for the new channel, a trusty_err on error. + * + * @dev: Trusty IPC device initialized with trusty_ipc_dev_create + * @port: name of port to connect to on secure side + * @cookie: cookie associated with new channel. + */ +int trusty_ipc_dev_connect(struct trusty_ipc_dev *dev, const char *port, + uint64_t cookie); +/* + * Calls into secure OS to close connection to Trusty IPC service. + * Returns a trusty_err. + * + * @dev: Trusty IPC device + * @chan: handle for connection, opened with trusty_ipc_dev_connect + */ +int trusty_ipc_dev_close(struct trusty_ipc_dev *dev, handle_t chan); + +/* + * Calls into secure OS to receive pending event. Returns a trusty_err. + * + * @dev: Trusty IPC device + * @chan: handle for connection + * @event: pointer to output event struct + */ +int trusty_ipc_dev_get_event(struct trusty_ipc_dev *dev, handle_t chan, + struct trusty_ipc_event *event); +/* + * Calls into secure OS to send message to channel. Returns a trusty_err. + * + * @dev: Trusty IPC device + * @chan: handle for connection + * @iovs: contains messages to be sent + * @iovs_cnt: number of iovecs to be sent + */ +int trusty_ipc_dev_send(struct trusty_ipc_dev *dev, handle_t chan, + const struct trusty_ipc_iovec *iovs, size_t iovs_cnt); +/* + * Calls into secure OS to receive message on channel. Returns number of bytes + * received on success, trusty_err on failure. + * + * @dev: Trusty IPC device + * @chan: handle for connection + * @iovs: contains received messages + * @iovs_cnt: number of iovecs received + */ +int trusty_ipc_dev_recv(struct trusty_ipc_dev *dev, handle_t chan, + const struct trusty_ipc_iovec *iovs, size_t iovs_cnt); + +void trusty_ipc_dev_idle(struct trusty_ipc_dev *dev); + +/* + * Initializes @chan with default values and @dev. + */ +void trusty_ipc_chan_init(struct trusty_ipc_chan *chan, + struct trusty_ipc_dev *dev); +/* + * Calls trusty_ipc_dev_connect to get a handle for channel. + * Returns a trusty_err. + * + * @chan: channel to initialize with new handle + * @port: name of port to connect to on secure side + * @wait: flag to wait for connect to complete by polling for + * IPC_HANDLE_POLL_READY event + */ +int trusty_ipc_connect(struct trusty_ipc_chan *chan, const char *port, + bool wait); +/* + * Calls trusty_ipc_dev_close and invalidates @chan. Returns a trusty_err. + */ +int trusty_ipc_close(struct trusty_ipc_chan *chan); +/* + * Calls trusty_ipc_dev_get_event to poll @dev for events. Handles + * events by calling appropriate callbacks. Returns nonnegative on success. + */ +int trusty_ipc_poll_for_event(struct trusty_ipc_dev *dev); +/* + * Calls trusty_ipc_dev_send to send a message. Returns a trusty_err. + * + * @chan: handle for connection + * @iovs: contains messages to be sent + * @iovs_cnt: number of iovecs to be sent + * @wait: flag to wait for send to complete + */ +int trusty_ipc_send(struct trusty_ipc_chan *chan, + const struct trusty_ipc_iovec *iovs, size_t iovs_cnt, + bool wait); +/* + * Calls trusty_ipc_dev_recv to receive a message. Return number of bytes + * received on success, trusty_err on failure. + * + * @chan: handle for connection + * @iovs: contains received messages + * @iovs_cnt: number of iovecs received + * @wait: flag to wait for a message to receive + */ +int trusty_ipc_recv(struct trusty_ipc_chan *chan, + const struct trusty_ipc_iovec *iovs, size_t iovs_cnt, + bool wait); + +#endif /* TRUSTY_TRUSTY_IPC_H_ */ diff --git a/include/trusty/trusty_mem.h b/include/trusty/trusty_mem.h new file mode 100644 index 0000000000..c796baa03f --- /dev/null +++ b/include/trusty/trusty_mem.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef TRUSTY_TRUSTY_MEM_H_ +#define TRUSTY_TRUSTY_MEM_H_ + +#include + +/* + * Encodes the memory attributes of @va into @inf + * + * @inf: ns_mem_page_info allocated by the caller + * @va: virtual addresses to retrieve attributes for + * + * Returns 0 on success and -1 on failure + */ + +int trusty_encode_page_info(struct ns_mem_page_info *inf, void *va); + +#endif /* TRUSTY_TRUSTY_MEM_H_ */ diff --git a/include/trusty/util.h b/include/trusty/util.h new file mode 100644 index 0000000000..72b960eacb --- /dev/null +++ b/include/trusty/util.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef TRUSTY_UTIL_H_ +#define TRUSTY_UTIL_H_ + +#include + +/* Returns the basename of |str|. This is defined as the last path + * component, assuming the normal POSIX separator '/'. If there are no + * separators, returns |str|. + */ +const char* trusty_basename(const char* str); + +#define TRUSTY_STRINGIFY(x) #x +#define TRUSTY_TO_STRING(x) TRUSTY_STRINGIFY(x) + +/* + * Aborts the program if @expr is false. + * + * This has no effect unless TIPC_ENABLE_DEBUG is defined. + */ +#ifdef TIPC_ENABLE_DEBUG +#define trusty_assert(expr) \ + do { \ + if (!(expr)) { \ + trusty_fatal("assert fail: " #expr "\n"); \ + } \ + } while(0) +#else +#define trusty_assert(expr) +#endif + +/* + * Prints debug message. + * + * This has no effect unless TIPC_ENABLE_DEBUG and LOCAL_LOG is defined. + */ +#ifdef TIPC_ENABLE_DEBUG +#define trusty_debug(message, ...) \ + do { \ + if (LOCAL_LOG) { \ + trusty_printf(trusty_basename(__FILE__)); \ + trusty_printf(":" TRUSTY_TO_STRING(__LINE__) ": DEBUG "); \ + trusty_printf(message, ##__VA_ARGS__); \ + } \ + } while(0) +#else +#define trusty_debug(message, ...) +#endif + +/* + * Prints info message. + */ +#define trusty_info(message, ...) \ + do { \ + trusty_printf(trusty_basename(__FILE__)); \ + trusty_printf(": INFO "); \ + trusty_printf(message, ##__VA_ARGS__); \ + } while(0) + +/* + * Prints error message. + */ +#define trusty_error(message, ...) \ + do { \ + trusty_printf(trusty_basename(__FILE__)); \ + trusty_printf(":" TRUSTY_TO_STRING(__LINE__) ": ERROR "); \ + trusty_printf(message, ##__VA_ARGS__); \ + } while(0) + +/* + * Prints message and calls trusty_abort. + */ +#define trusty_fatal(message, ...) \ + do { \ + trusty_printf(trusty_basename(__FILE__)); \ + trusty_printf(":" TRUSTY_TO_STRING(__LINE__) ": FATAL "); \ + trusty_printf(message, ##__VA_ARGS__); \ + trusty_abort(); \ + } while(0) + +#endif /* TRUSTY_UTIL_H_ */ diff --git a/lib/Makefile b/lib/Makefile index edf4b58e0c..4fd371c926 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_OF_LIVE) += of_live.o obj-$(CONFIG_CMD_DHRYSTONE) += dhry/ obj-$(CONFIG_ARCH_AT91) += at91/ obj-$(CONFIG_OPTEE) += optee/ +obj-$(CONFIG_IMX_TRUSTY_OS) += trusty/ql-tipc/ obj-$(CONFIG_AES) += aes.o diff --git a/lib/trusty/ql-tipc/LICENSE b/lib/trusty/ql-tipc/LICENSE new file mode 100644 index 0000000000..d21621abc4 --- /dev/null +++ b/lib/trusty/ql-tipc/LICENSE @@ -0,0 +1,20 @@ +Copyright 2016, The Android Open Source Project + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/trusty/ql-tipc/Makefile b/lib/trusty/ql-tipc/Makefile new file mode 100644 index 0000000000..5ee616ba93 --- /dev/null +++ b/lib/trusty/ql-tipc/Makefile @@ -0,0 +1,49 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +# Sample Makefile for U-boot + +#ccflags-y += -DTIPC_ENABLE_DEBUG + +TRUSTY_DIR = lib/trusty +#ccflags-y += -I$(TRUSTY_DIR)/ql-tipc/include +ccflags-y += -I$(TRUSTY_DIR)/interface/include + +QL_TIPC = . +obj-y += \ + $(QL_TIPC)/avb.o \ + $(QL_TIPC)/hwcrypto.o \ + $(QL_TIPC)/keymaster.o \ + $(QL_TIPC)/keymaster_serializable.o \ + $(QL_TIPC)/ipc.o \ + $(QL_TIPC)/ipc_dev.o \ + $(QL_TIPC)/libtipc.o \ + $(QL_TIPC)/rpmb_proxy.o \ + $(QL_TIPC)/util.o \ + sysdeps/sysdeps_uboot.o \ + sysdeps/storage_ops_uboot.o + +obj-$(CONFIG_ARM) += \ + $(QL_TIPC)/arch/arm/trusty_mem.o \ + $(QL_TIPC)/arch/arm/trusty_dev.o diff --git a/lib/trusty/ql-tipc/README.md b/lib/trusty/ql-tipc/README.md new file mode 100644 index 0000000000..76e3781756 --- /dev/null +++ b/lib/trusty/ql-tipc/README.md @@ -0,0 +1,30 @@ +# Queueless Trusty IPC + +ql-tipc is a portable client library that implements Trusty queueless IPC. +It is intended to enable Trusty IPC in bootloader environments. + +## Code organization + +### IPC components + +- libtipc - Functions to be called by library user +- ipc - IPC library +- ipc_dev - Helper functions for sending requests to the secure OS +- rpmb_proxy - Handles RPMB requests from secure storage service +- avb - Sends requests to the Android Verified Boot service + +### Misc + +- examples/ - Implementations of bootloader-specific code. +- arch/$ARCH/ - Architecture dependent implementation of Trusty device + (see trusty_dev.h). Implements SMCs on ARM for example. + +## Portability Notes + +The suggested approach to porting ql-tipc is to copy all header and C files +into the bootloader and integrate as needed. RPMB storage operations and +functions defined in trusty/sysdeps.h require system dependent implementations. + +If the TIPC_ENABLE_DEBUG preprocessor symbol is set, the code will include +debug information and run-time checks. Production builds should not use this. + diff --git a/lib/trusty/ql-tipc/arch/arm/sm_err.h b/lib/trusty/ql-tipc/arch/arm/sm_err.h new file mode 100644 index 0000000000..940125611c --- /dev/null +++ b/lib/trusty/ql-tipc/arch/arm/sm_err.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef QL_TIPC_SM_ERR_H_ +#define QL_TIPC_SM_ERR_H_ + +/* Errors from the secure monitor */ +#define SM_ERR_UNDEFINED_SMC 0xFFFFFFFF /* Unknown SMC (defined by ARM DEN 0028A(0.9.0) */ +#define SM_ERR_INVALID_PARAMETERS -2 +#define SM_ERR_INTERRUPTED -3 /* Got interrupted. Call back with restart SMC */ +#define SM_ERR_UNEXPECTED_RESTART -4 /* Got an restart SMC when we didn't expect it */ +#define SM_ERR_BUSY -5 /* Temporarily busy. Call back with original args */ +#define SM_ERR_INTERLEAVED_SMC -6 /* Got a trusted_service SMC when a restart SMC is required */ +#define SM_ERR_INTERNAL_FAILURE -7 /* Unknown error */ +#define SM_ERR_NOT_SUPPORTED -8 +#define SM_ERR_NOT_ALLOWED -9 /* SMC call not allowed */ +#define SM_ERR_END_OF_INPUT -10 +#define SM_ERR_PANIC -11 /* Secure OS crashed */ +#define SM_ERR_FIQ_INTERRUPTED -12 /* Got interrupted by FIQ. Call back with SMC_SC_RESTART_FIQ on same CPU */ +#define SM_ERR_CPU_IDLE -13 /* SMC call waiting for another CPU */ +#define SM_ERR_NOP_INTERRUPTED -14 /* Got interrupted. Call back with new SMC_SC_NOP */ +#define SM_ERR_NOP_DONE -15 /* Cpu idle after SMC_SC_NOP (not an error) */ + +#endif /* QL_TIPC_SM_ERR_H_ */ diff --git a/lib/trusty/ql-tipc/arch/arm/smcall.h b/lib/trusty/ql-tipc/arch/arm/smcall.h new file mode 100644 index 0000000000..695776c93e --- /dev/null +++ b/lib/trusty/ql-tipc/arch/arm/smcall.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef QL_TIPC_SMCALL_H_ +#define QL_TIPC_SMCALL_H_ + +#define SMC_NUM_ENTITIES 64 +#define SMC_NUM_ARGS 4 +#define SMC_NUM_PARAMS (SMC_NUM_ARGS - 1) + +#define SMC_IS_FASTCALL(smc_nr) ((smc_nr) & 0x80000000) +#define SMC_IS_SMC64(smc_nr) ((smc_nr) & 0x40000000) +#define SMC_ENTITY(smc_nr) (((smc_nr) & 0x3F000000) >> 24) +#define SMC_FUNCTION(smc_nr) ((smc_nr) & 0x0000FFFF) + +#define SMC_NR(entity, fn, fastcall, smc64) ((((fastcall) & 0x1) << 31) | \ + (((smc64) & 0x1) << 30) | \ + (((entity) & 0x3F) << 24) | \ + ((fn) & 0xFFFF) \ + ) + +#define SMC_FASTCALL_NR(entity, fn) SMC_NR((entity), (fn), 1, 0) +#define SMC_STDCALL_NR(entity, fn) SMC_NR((entity), (fn), 0, 0) +#define SMC_FASTCALL64_NR(entity, fn) SMC_NR((entity), (fn), 1, 1) +#define SMC_STDCALL64_NR(entity, fn) SMC_NR((entity), (fn), 0, 1) + +#define SMC_ENTITY_ARCH 0 /* ARM Architecture calls */ +#define SMC_ENTITY_CPU 1 /* CPU Service calls */ +#define SMC_ENTITY_SIP 2 /* SIP Service calls */ +#define SMC_ENTITY_OEM 3 /* OEM Service calls */ +#define SMC_ENTITY_STD 4 /* Standard Service calls */ +#define SMC_ENTITY_RESERVED 5 /* Reserved for future use */ +#define SMC_ENTITY_TRUSTED_APP 48 /* Trusted Application calls */ +#define SMC_ENTITY_TRUSTED_OS 50 /* Trusted OS calls */ +#define SMC_ENTITY_LOGGING 51 /* Used for secure -> nonsecure logging */ +#define SMC_ENTITY_SECURE_MONITOR 60 /* Trusted OS calls internal to secure monitor */ + +/* FC = Fast call, SC = Standard call */ +#define SMC_SC_RESTART_LAST SMC_STDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 0) +#define SMC_SC_LOCKED_NOP SMC_STDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 1) + +/** + * SMC_SC_RESTART_FIQ - Re-enter trusty after it was interrupted by an fiq + * + * No arguments, no return value. + * + * Re-enter trusty after returning to ns to process an fiq. Must be called iff + * trusty returns SM_ERR_FIQ_INTERRUPTED. + * + * Enable by selecting api version TRUSTY_API_VERSION_RESTART_FIQ (1) or later. + */ +#define SMC_SC_RESTART_FIQ SMC_STDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 2) + +/** + * SMC_SC_NOP - Enter trusty to run pending work. + * + * No arguments. + * + * Returns SM_ERR_NOP_INTERRUPTED or SM_ERR_NOP_DONE. + * If SM_ERR_NOP_INTERRUPTED is returned, the call must be repeated. + * + * Enable by selecting api version TRUSTY_API_VERSION_SMP (2) or later. + */ +#define SMC_SC_NOP SMC_STDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 3) + +/* + * Return from secure os to non-secure os with return value in r1 + */ +#define SMC_SC_NS_RETURN SMC_STDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 0) + +#define SMC_FC_RESERVED SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 0) +#define SMC_FC_FIQ_EXIT SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 1) +#define SMC_FC_REQUEST_FIQ SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 2) +#define SMC_FC_GET_NEXT_IRQ SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 3) +#define SMC_FC_FIQ_ENTER SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 4) + +#define SMC_FC64_SET_FIQ_HANDLER SMC_FASTCALL64_NR(SMC_ENTITY_SECURE_MONITOR, 5) +#define SMC_FC64_GET_FIQ_REGS SMC_FASTCALL64_NR (SMC_ENTITY_SECURE_MONITOR, 6) + +#define SMC_FC_CPU_SUSPEND SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 7) +#define SMC_FC_CPU_RESUME SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 8) + +#define SMC_FC_AARCH_SWITCH SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 9) +#define SMC_FC_GET_VERSION_STR SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 10) + +/** + * SMC_FC_API_VERSION - Find and select supported API version. + * + * @r1: Version supported by client. + * + * Returns version supported by trusty. + * + * If multiple versions are supported, the client should start by calling + * SMC_FC_API_VERSION with the largest version it supports. Trusty will then + * return a version it supports. If the client does not support the version + * returned by trusty and the version returned is less than the version + * requested, repeat the call with the largest supported version less than the + * last returned version. + * + * This call must be made before any calls that are affected by the api version. + */ +#define TRUSTY_API_VERSION_RESTART_FIQ (1) +#define TRUSTY_API_VERSION_SMP (2) +#define TRUSTY_API_VERSION_SMP_NOP (3) +#define TRUSTY_API_VERSION_CURRENT (3) +#define SMC_FC_API_VERSION SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 11) + +/* TRUSTED_OS entity calls */ +#define SMC_SC_VIRTIO_GET_DESCR SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 20) +#define SMC_SC_VIRTIO_START SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 21) +#define SMC_SC_VIRTIO_STOP SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 22) + +#define SMC_SC_VDEV_RESET SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 23) +#define SMC_SC_VDEV_KICK_VQ SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 24) +#define SMC_NC_VDEV_KICK_VQ SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 25) + +/* Queueless Trusty IPC Interface */ +#define SMC_SC_TRUSTY_IPC_CREATE_QL_DEV SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 30) +#define SMC_SC_TRUSTY_IPC_SHUTDOWN_QL_DEV SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 31) +#define SMC_SC_TRUSTY_IPC_HANDLE_QL_DEV_CMD SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 32) + +#endif /* QL_TIPC_SMCALL_H_ */ diff --git a/lib/trusty/ql-tipc/arch/arm/trusty_dev.c b/lib/trusty/ql-tipc/arch/arm/trusty_dev.c new file mode 100644 index 0000000000..bd9a5fbfb6 --- /dev/null +++ b/lib/trusty/ql-tipc/arch/arm/trusty_dev.c @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "sm_err.h" +#include "smcall.h" + +struct trusty_dev; + +#define LOCAL_LOG 0 + +#ifndef __asmeq +#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t" +#endif + +#ifdef NS_ARCH_ARM64 +#define SMC_ARG0 "x0" +#define SMC_ARG1 "x1" +#define SMC_ARG2 "x2" +#define SMC_ARG3 "x3" +#define SMC_ARCH_EXTENSION "" +#define SMC_REGISTERS_TRASHED "x4","x5","x6","x7","x8","x9","x10","x11", \ + "x12","x13","x14","x15","x16","x17" +#else +#define SMC_ARG0 "r0" +#define SMC_ARG1 "r1" +#define SMC_ARG2 "r2" +#define SMC_ARG3 "r3" +#define SMC_ARCH_EXTENSION ".arch_extension sec\n" +#define SMC_REGISTERS_TRASHED "ip" +#endif + +/* + * Execute SMC call into trusty + */ +static unsigned long smc(unsigned long r0, + unsigned long r1, + unsigned long r2, + unsigned long r3) +{ + register unsigned long _r0 __asm__(SMC_ARG0) = r0; + register unsigned long _r1 __asm__(SMC_ARG1) = r1; + register unsigned long _r2 __asm__(SMC_ARG2) = r2; + register unsigned long _r3 __asm__(SMC_ARG3) = r3; + + __asm__ volatile( + __asmeq("%0", SMC_ARG0) + __asmeq("%1", SMC_ARG1) + __asmeq("%2", SMC_ARG2) + __asmeq("%3", SMC_ARG3) + __asmeq("%4", SMC_ARG0) + __asmeq("%5", SMC_ARG1) + __asmeq("%6", SMC_ARG2) + __asmeq("%7", SMC_ARG3) + SMC_ARCH_EXTENSION + "smc #0" /* switch to secure world */ + : "=r" (_r0), "=r" (_r1), "=r" (_r2), "=r" (_r3) + : "r" (_r0), "r" (_r1), "r" (_r2), "r" (_r3) + : SMC_REGISTERS_TRASHED); + return _r0; +} + +static int32_t trusty_fast_call32(struct trusty_dev *dev, uint32_t smcnr, + uint32_t a0, uint32_t a1, uint32_t a2) +{ + trusty_assert(dev); + trusty_assert(SMC_IS_FASTCALL(smcnr)); + + return smc(smcnr, a0, a1, a2); +} + +static unsigned long trusty_std_call_inner(struct trusty_dev *dev, + unsigned long smcnr, + unsigned long a0, + unsigned long a1, + unsigned long a2) +{ + unsigned long ret; + int retry = 5; + + trusty_debug("%s(0x%lx 0x%lx 0x%lx 0x%lx)\n", __func__, smcnr, a0, a1, a2); + + while (true) { + ret = smc(smcnr, a0, a1, a2); + while ((int32_t)ret == SM_ERR_FIQ_INTERRUPTED) + ret = smc(SMC_SC_RESTART_FIQ, 0, 0, 0); + if ((int)ret != SM_ERR_BUSY || !retry) + break; + + trusty_debug("%s(0x%lx 0x%lx 0x%lx 0x%lx) returned busy, retry\n", + __func__, smcnr, a0, a1, a2); + + retry--; + } + + return ret; +} + +static unsigned long trusty_std_call_helper(struct trusty_dev *dev, + unsigned long smcnr, + unsigned long a0, + unsigned long a1, + unsigned long a2) +{ + unsigned long ret; + unsigned long irq_state; + + while (true) { + trusty_local_irq_disable(&irq_state); + ret = trusty_std_call_inner(dev, smcnr, a0, a1, a2); + trusty_local_irq_restore(&irq_state); + + if ((int)ret != SM_ERR_BUSY) + break; + + trusty_idle(dev); + } + + return ret; +} + +static int32_t trusty_std_call32(struct trusty_dev *dev, uint32_t smcnr, + uint32_t a0, uint32_t a1, uint32_t a2) +{ + int ret; + + trusty_assert(dev); + trusty_assert(!SMC_IS_FASTCALL(smcnr)); + + if (smcnr != SMC_SC_NOP) { + trusty_lock(dev); + } + + trusty_debug("%s(0x%x 0x%x 0x%x 0x%x) started\n", __func__, + smcnr, a0, a1, a2); + + ret = trusty_std_call_helper(dev, smcnr, a0, a1, a2); + while (ret == SM_ERR_INTERRUPTED || ret == SM_ERR_CPU_IDLE) { + trusty_debug("%s(0x%x 0x%x 0x%x 0x%x) interrupted\n", __func__, + smcnr, a0, a1, a2); + if (ret == SM_ERR_CPU_IDLE) { + trusty_idle(dev); + } + ret = trusty_std_call_helper(dev, SMC_SC_RESTART_LAST, 0, 0, 0); + } + + trusty_debug("%s(0x%x 0x%x 0x%x 0x%x) returned 0x%x\n", + __func__, smcnr, a0, a1, a2, ret); + + if (smcnr != SMC_SC_NOP) { + trusty_unlock(dev); + } + + return ret; +} + +static int trusty_call32_mem_buf(struct trusty_dev *dev, uint32_t smcnr, + struct ns_mem_page_info *page, uint32_t size) +{ + trusty_assert(dev); + trusty_assert(page); + + if (SMC_IS_FASTCALL(smcnr)) { + return trusty_fast_call32(dev, smcnr, + (uint32_t)page->attr, + (uint32_t)(page->attr >> 32), size); + } else { + return trusty_std_call32(dev, smcnr, + (uint32_t)page->attr, + (uint32_t)(page->attr >> 32), size); + } +} + +int trusty_dev_init_ipc(struct trusty_dev *dev, + struct ns_mem_page_info *buf, uint32_t buf_size) +{ + return trusty_call32_mem_buf(dev, SMC_SC_TRUSTY_IPC_CREATE_QL_DEV, + buf, buf_size); +} + +int trusty_dev_exec_ipc(struct trusty_dev *dev, + struct ns_mem_page_info *buf, uint32_t buf_size) +{ + return trusty_call32_mem_buf(dev, SMC_SC_TRUSTY_IPC_HANDLE_QL_DEV_CMD, + buf, buf_size); +} + +int trusty_dev_shutdown_ipc(struct trusty_dev *dev, + struct ns_mem_page_info *buf, uint32_t buf_size) +{ + return trusty_call32_mem_buf(dev, SMC_SC_TRUSTY_IPC_SHUTDOWN_QL_DEV, + buf, buf_size); +} + + +static int trusty_init_api_version(struct trusty_dev *dev) +{ + uint32_t api_version; + + api_version = trusty_fast_call32(dev, SMC_FC_API_VERSION, + TRUSTY_API_VERSION_CURRENT, 0, 0); + if (api_version == SM_ERR_UNDEFINED_SMC) + api_version = 0; + + if (api_version > TRUSTY_API_VERSION_CURRENT) { + trusty_error("unsupported trusty api version %u > %u\n", + api_version, TRUSTY_API_VERSION_CURRENT); + return -1; + } + + trusty_info("selected trusty api version: %u (requested %u)\n", + api_version, TRUSTY_API_VERSION_CURRENT); + + dev->api_version = api_version; + + return 0; +} + +int trusty_dev_init(struct trusty_dev *dev, void *priv_data) +{ + trusty_assert(dev); + + dev->priv_data = priv_data; + return trusty_init_api_version(dev); +} + +int trusty_dev_shutdown(struct trusty_dev *dev) +{ + trusty_assert(dev); + + dev->priv_data = NULL; + return 0; +} + diff --git a/lib/trusty/ql-tipc/arch/arm/trusty_mem.c b/lib/trusty/ql-tipc/arch/arm/trusty_mem.c new file mode 100644 index 0000000000..56d8348d3c --- /dev/null +++ b/lib/trusty/ql-tipc/arch/arm/trusty_mem.c @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +/* 48-bit physical address bits 47:12 */ + +#define NS_PTE_PHYSADDR_SHIFT 12 +#define NS_PTE_PHYSADDR(pte) ((pte) & 0xFFFFFFFFF000ULL) + +/* Access permissions bits 7:6 + * EL0 EL1 + * 00 None RW + * 01 RW RW + * 10 None RO + * 11 RO RO + */ +#define NS_PTE_AP_SHIFT 6 +#define NS_PTE_AP_MASK (0x3 << NS_PTE_AP_SHIFT) + +/* Memory type and cache attributes bits 55:48 */ +#define NS_PTE_MAIR_SHIFT 48 +#define NS_PTE_MAIR_MASK (0x00FFULL << NS_PTE_MAIR_SHIFT) + +#define NS_PTE_MAIR_INNER_SHIFT 48 +#define NS_PTE_MAIR_INNER_MASK (0x000FULL << NS_PTE_MAIR_INNER_SHIFT) + +#define NS_PTE_MAIR_OUTER_SHIFT 52 +#define NS_PTE_MAIR_OUTER_MASK (0x000FULL << NS_PTE_MAIR_OUTER_SHIFT) + +/* Normal memory */ +#define NS_MAIR_NORMAL_CACHED_WB_RWA 0xFF /* inner and outer write back read/write allocate */ +#define NS_MAIR_NORMAL_CACHED_WT_RA 0xAA /* inner and outer write through read allocate */ +#define NS_MAIR_NORMAL_CACHED_WB_RA 0xEE /* inner and outer write back, read allocate */ +#define NS_MAIR_NORMAL_UNCACHED 0x44 /* uncached */ + +/* Device memory */ +#define NS_MAIR_DEVICE_STRONGLY_ORDERED 0x00 /* nGnRnE (strongly ordered) */ +#define NS_MAIR_DEVICE 0x04 /* nGnRE (device) */ +#define NS_MAIR_DEVICE_GRE 0x0C /* GRE */ + +/* shareable attributes bits 9:8 */ +#define NS_PTE_SHAREABLE_SHIFT 8 + +#define NS_NON_SHAREABLE 0x0 +#define NS_OUTER_SHAREABLE 0x2 +#define NS_INNER_SHAREABLE 0x3 + +typedef uintptr_t addr_t; +typedef uintptr_t vaddr_t; +typedef uintptr_t paddr_t; + +#if NS_ARCH_ARM64 + +#define PAR_F (0x1 << 0) + +/* + * ARM64 + */ + +/* Note: this will crash if called from user space */ +static void arm64_write_ATS1ExW(uint64_t vaddr) +{ + uint64_t _current_el; + + __asm__ volatile("mrs %0, CurrentEL" : "=r" (_current_el)); + + _current_el = (_current_el >> 2) & 0x3; + switch (_current_el) { + case 0x1: + __asm__ volatile("at S1E1W, %0" :: "r" (vaddr)); + break; + case 0x2: + __asm__ volatile("at S1E2W, %0" :: "r" (vaddr)); + break; + case 0x3: + default: + trusty_fatal("Unsupported execution state: EL%u\n", _current_el ); + break; + } + + __asm__ volatile("isb" ::: "memory"); +} + +static uint64_t arm64_read_par64(void) +{ + uint64_t _val; + __asm__ volatile("mrs %0, par_el1" : "=r" (_val)); + return _val; +} + + +static uint64_t va2par(vaddr_t va) +{ + uint64_t par; + unsigned long irq_state; + + trusty_local_irq_disable(&irq_state); + arm64_write_ATS1ExW(va); + par = arm64_read_par64(); + trusty_local_irq_restore(&irq_state); + + return par; +} + +static uint64_t par2attr(uint64_t par) +{ + uint64_t attr; + + /* set phys address */ + attr = NS_PTE_PHYSADDR(par); + + /* cache attributes */ + attr |= ((par >> 56) & 0xFF) << NS_PTE_MAIR_SHIFT; + + /* shareable attributes */ + attr |= ((par >> 7) & 0x03) << NS_PTE_SHAREABLE_SHIFT; + + /* the memory is writable and accessible so leave AP field 0 */ + attr |= 0x0 << NS_PTE_AP_SHIFT; + + return attr; +} + +#else + +#define PAR_F (0x1 << 0) +#define PAR_SS (0x1 << 1) +#define PAR_SH (0x1 << 7) +#define PAR_NOS (0x1 << 10) +#define PAR_LPAE (0x1 << 11) + +/* + * ARM32 + */ + +/* Note: this will crash if called from user space */ +static void arm_write_ATS1xW(uint64_t vaddr) +{ + uint32_t _cpsr; + + __asm__ volatile("mrs %0, cpsr" : "=r"(_cpsr)); + + if ((_cpsr & 0xF) == 0xa) + __asm__ volatile("mcr p15, 4, %0, c7, c8, 1" : : "r"(vaddr)); + else + __asm__ volatile("mcr p15, 0, %0, c7, c8, 1" : : "r"(vaddr)); +} + +static uint64_t arm_read_par64(void) +{ + uint32_t lower, higher; + + __asm__ volatile( + "mrc p15, 0, %0, c7, c4, 0 \n" + "tst %0, #(1 << 11) @ LPAE / long desc format\n" + "moveq %1, #0 \n" + "mrrcne p15, 0, %0, %1, c7 \n" + :"=r"(lower), "=r"(higher) : : + ); + + return ((uint64_t)higher << 32) | lower; +} + + +static uint8_t ish_to_mair[8] = { + 0x04, /* 0b000 Non cacheble */ + 0x00, /* 0b001 Strongly ordered */ + 0xF0, /* 0b010 reserved */ + 0x04, /* 0b011 device */ + 0xF0, /* 0b100 reserved */ + 0x0F, /* 0b101 write back - write allocate */ + 0x0A, /* 0b110 write through */ + 0x0E, /* 0b111 write back - no write allocate */ +}; + +static uint8_t osh_to_mair[4] = { + 0x00, /* 0b00 Non-cacheable */ + 0x0F, /* 0b01 Write-back, Write-allocate */ + 0x0A, /* 0b10 Write-through, no Write-allocate */ + 0x0E, /* 0b11 Write-back, no Write-allocate */ +}; + +static uint64_t par2attr(uint64_t par) +{ + uint64_t attr; + + if (par & PAR_LPAE) { + /* set phys address */ + attr = NS_PTE_PHYSADDR(par); + + /* cache attributes */ + attr |= ((par >> 56) & 0xFF) << NS_PTE_MAIR_SHIFT; + + /* shareable attributes */ + attr |= ((par >> 7) & 0x03) << NS_PTE_SHAREABLE_SHIFT; + + } else { + + /* set phys address */ + trusty_assert((par & PAR_SS) == 0); /* super section not supported */ + attr = NS_PTE_PHYSADDR(par); + + /* cache attributes */ + uint64_t inner = ((uint64_t)ish_to_mair[(par >> 4) & 0x7]) << NS_PTE_MAIR_INNER_SHIFT; + uint64_t outer = ((uint64_t)osh_to_mair[(par >> 2) & 0x3]) << NS_PTE_MAIR_OUTER_SHIFT; + uint64_t cache_attributes = (outer << 4) | inner; + + /* Trusty does not support any kind of device memory, so we will force + * cache attributes to be NORMAL UNCACHED on the Trusty side. + */ + if (cache_attributes == NS_MAIR_DEVICE_STRONGLY_ORDERED) { + attr |= ((uint64_t)NS_MAIR_NORMAL_UNCACHED << NS_PTE_MAIR_SHIFT); + } else { + attr |= inner; + attr |= outer; + } + + /* shareable attributes */ + if (par & PAR_SH) { + /* how to handle NOS bit ? */ + attr |= ((uint64_t)NS_INNER_SHAREABLE) << NS_PTE_SHAREABLE_SHIFT; + } else { + attr |= ((uint64_t)NS_NON_SHAREABLE) << NS_PTE_SHAREABLE_SHIFT; + } + } + + /* the memory is writable and accessible so leave AP field 0 */ + attr |= 0x0 << NS_PTE_AP_SHIFT; + + return attr; +} + +static uint64_t va2par(vaddr_t va) +{ + uint64_t par; + unsigned long irq_state; + + trusty_local_irq_disable(&irq_state); + arm_write_ATS1xW(va); + par = arm_read_par64(); + trusty_local_irq_restore(&irq_state); + + return par; +} + +#endif /* ARM64 */ + + +int trusty_encode_page_info(struct ns_mem_page_info *inf, void *va) +{ + uint64_t par = va2par((vaddr_t)va); + + if (par & PAR_F) { + return -1; + } + + inf->attr = par2attr(par); + + return 0; +} + diff --git a/lib/trusty/ql-tipc/avb.c b/lib/trusty/ql-tipc/avb.c new file mode 100644 index 0000000000..95b26fd2f8 --- /dev/null +++ b/lib/trusty/ql-tipc/avb.c @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include + +#define LOCAL_LOG 0 + +static bool initialized; +static int avb_tipc_version = 1; +static struct trusty_ipc_chan avb_chan; + +static int avb_send_request(struct avb_message *msg, void *req, size_t req_len) +{ + struct trusty_ipc_iovec req_iovs[2] = { + { .base = msg, .len = sizeof(*msg) }, + { .base = req, .len = req_len }, + }; + + return trusty_ipc_send(&avb_chan, req_iovs, req ? 2 : 1, true); +} + +static int avb_read_response(struct avb_message *msg, uint32_t cmd, void *resp, + size_t resp_len) +{ + int rc; + struct trusty_ipc_iovec resp_iovs[2] = { + { .base = msg, .len = sizeof(*msg) }, + { .base = resp, .len = resp_len }, + }; + + rc = trusty_ipc_recv(&avb_chan, resp_iovs, resp ? 2 : 1, true); + if (rc < 0) { + trusty_error("failed (%d) to recv response\n", rc); + return rc; + } + if (msg->cmd != (cmd | AVB_RESP_BIT)) { + trusty_error("malformed response\n"); + return TRUSTY_ERR_GENERIC; + } + /* return payload size */ + return rc - sizeof(*msg); +} + +/* + * Convenience function to send a request to the AVB service and read the + * response. + * + * @cmd: the command + * @req: the request buffer + * @req_size: size of the request buffer + * @resp: the response buffer + * @resp_size_p: pointer to the size of the response buffer. changed to the + actual size of the response read from the secure side + */ +static int avb_do_tipc(uint32_t cmd, void *req, uint32_t req_size, void *resp, + uint32_t *resp_size_p) +{ + int rc; + struct avb_message msg = { .cmd = cmd }; + + if (!initialized && cmd != AVB_GET_VERSION) { + trusty_error("%s: AVB TIPC client not initialized\n", __func__); + return TRUSTY_ERR_GENERIC; + } + + rc = avb_send_request(&msg, req, req_size); + if (rc < 0) { + trusty_error("%s: failed (%d) to send AVB request\n", __func__, rc); + return rc; + } + + uint32_t resp_size = resp_size_p ? *resp_size_p : 0; + rc = avb_read_response(&msg, cmd, resp, resp_size); + if (rc < 0) { + trusty_error("%s: failed (%d) to read AVB response\n", __func__, rc); + return rc; + } + /* change response size to actual response size */ + if (resp_size_p && rc != *resp_size_p) { + *resp_size_p = rc; + } + if (msg.result != AVB_ERROR_NONE) { + trusty_error("%s: AVB service returned error (%d)\n", __func__, + msg.result); + return TRUSTY_ERR_GENERIC; + } + return TRUSTY_ERR_NONE; +} + +static int avb_get_version(uint32_t *version) +{ + int rc; + struct avb_get_version_resp resp; + uint32_t resp_size = sizeof(resp); + + rc = avb_do_tipc(AVB_GET_VERSION, NULL, 0, &resp, &resp_size); + + *version = resp.version; + return rc; +} + + +int avb_tipc_init(struct trusty_ipc_dev *dev) +{ + int rc; + uint32_t version = 0; + + trusty_assert(dev); + trusty_assert(!initialized); + + trusty_ipc_chan_init(&avb_chan, dev); + trusty_debug("Connecting to AVB service\n"); + + /* connect to AVB service and wait for connect to complete */ + rc = trusty_ipc_connect(&avb_chan, AVB_PORT, true); + if (rc < 0) { + trusty_error("failed (%d) to connect to '%s'\n", rc, AVB_PORT); + return rc; + } + + /* check for version mismatch */ + rc = avb_get_version(&version); + if (rc != 0) { + trusty_error("Error getting version"); + return TRUSTY_ERR_GENERIC; + } + if (version != avb_tipc_version) { + trusty_error("AVB TIPC version mismatch. Expected %u, received %u\n", + avb_tipc_version, version); + return TRUSTY_ERR_GENERIC; + } + + /* mark as initialized */ + initialized = true; + + return TRUSTY_ERR_NONE; +} + +void avb_tipc_shutdown(struct trusty_ipc_dev *dev) +{ + if (!initialized) + return; /* nothing to do */ + + /* close channel */ + trusty_ipc_close(&avb_chan); + + initialized = false; +} + +int trusty_read_rollback_index(uint32_t slot, uint64_t *value) +{ + int rc; + struct avb_rollback_req req = { .slot = slot, .value = 0 }; + struct avb_rollback_resp resp; + uint32_t resp_size = sizeof(resp); + + rc = avb_do_tipc(READ_ROLLBACK_INDEX, &req, sizeof(req), &resp, + &resp_size); + + *value = resp.value; + return rc; +} + +int trusty_write_rollback_index(uint32_t slot, uint64_t value) +{ + int rc; + struct avb_rollback_req req = { .slot = slot, .value = value }; + struct avb_rollback_resp resp; + uint32_t resp_size = sizeof(resp); + + rc = avb_do_tipc(WRITE_ROLLBACK_INDEX, &req, sizeof(req), &resp, + &resp_size); + return rc; +} + +int trusty_read_permanent_attributes(uint8_t *attributes, uint32_t size) +{ + uint8_t resp_buf[AVB_MAX_BUFFER_LENGTH]; + uint32_t resp_size = AVB_MAX_BUFFER_LENGTH; + int rc = avb_do_tipc(READ_PERMANENT_ATTRIBUTES, NULL, 0, resp_buf, + &resp_size); + if (rc != 0) { + return rc; + } + /* ensure caller passed size matches size returned by Trusty */ + if (size != resp_size) { + return TRUSTY_ERR_INVALID_ARGS; + } + trusty_memcpy(attributes, resp_buf, resp_size); + return rc; +} + +int trusty_write_permanent_attributes(uint8_t *attributes, uint32_t size) +{ + return avb_do_tipc(WRITE_PERMANENT_ATTRIBUTES, attributes, size, NULL, + NULL); +} + +int trusty_read_vbmeta_public_key(uint8_t *publickey, uint32_t size) +{ + uint8_t resp_buf[AVB_MAX_BUFFER_LENGTH]; + uint32_t resp_size = AVB_MAX_BUFFER_LENGTH; + int rc = avb_do_tipc(READ_VBMETA_PUBLIC_KEY, NULL, 0, resp_buf, + &resp_size); + if (rc != 0) { + return rc; + } + /* ensure caller passed size matches size returned by Trusty */ + if (size < resp_size) { + return TRUSTY_ERR_INVALID_ARGS; + } + trusty_memcpy(publickey, resp_buf, resp_size); + return rc; +} + +int trusty_write_vbmeta_public_key(uint8_t *publickey, uint32_t size) +{ + return avb_do_tipc(WRITE_VBMETA_PUBLIC_KEY, publickey, size, NULL, + NULL); +} + +int trusty_read_lock_state(uint8_t *lock_state) +{ + uint32_t resp_size = sizeof(*lock_state); + return avb_do_tipc(READ_LOCK_STATE, NULL, 0, lock_state, + &resp_size); +} + +int trusty_write_lock_state(uint8_t lock_state) +{ + return avb_do_tipc(WRITE_LOCK_STATE, &lock_state, sizeof(lock_state), NULL, + NULL); +} + +int trusty_lock_boot_state(void) +{ + return avb_do_tipc(LOCK_BOOT_STATE, NULL, 0, NULL, NULL); +} diff --git a/lib/trusty/ql-tipc/hwcrypto.c b/lib/trusty/ql-tipc/hwcrypto.c new file mode 100644 index 0000000000..ccaf18b427 --- /dev/null +++ b/lib/trusty/ql-tipc/hwcrypto.c @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * Copyright NXP 2018 + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include "common.h" + +#define LOCAL_LOG 0 +#define CAAM_KB_HEADER_LEN 48 + +static bool initialized; +static struct trusty_ipc_chan hwcrypto_chan; + +static int hwcrypto_send_request(struct hwcrypto_message *msg, void *req, size_t req_len) +{ + struct trusty_ipc_iovec req_iovs[2] = { + { .base = msg, .len = sizeof(*msg) }, + { .base = req, .len = req_len }, + }; + + return trusty_ipc_send(&hwcrypto_chan, req_iovs, req ? 2 : 1, true); +} + +static int hwcrypto_read_response(struct hwcrypto_message *msg, uint32_t cmd, void *resp, + size_t resp_len) +{ + int rc; + struct trusty_ipc_iovec resp_iovs[2] = { + { .base = msg, .len = sizeof(*msg) }, + { .base = resp, .len = resp_len }, + }; + + rc = trusty_ipc_recv(&hwcrypto_chan, resp_iovs, resp ? 2 : 1, true); + if (rc < 0) { + trusty_error("failed (%d) to recv response\n", rc); + return rc; + } + if (msg->cmd != (cmd | HWCRYPTO_RESP_BIT)) { + trusty_error("malformed response\n"); + return TRUSTY_ERR_GENERIC; + } + /* return payload size */ + return rc - sizeof(*msg); +} + +/* + * Convenience function to send a request to the hwcrypto service and read the + * response. + * + * @cmd: the command + * @req: the request buffer + * @req_size: size of the request buffer + * @resp: the response buffer + * @resp_size_p: pointer to the size of the response buffer. changed to the + actual size of the response read from the secure side + * @handle_rpmb: true if the request is expected to invoke RPMB callbacks + */ +static int hwcrypto_do_tipc(uint32_t cmd, void *req, uint32_t req_size, void *resp, + uint32_t *resp_size_p, bool handle_rpmb) +{ + int rc; + struct hwcrypto_message msg = { .cmd = cmd }; + + if (!initialized) { + trusty_error("%s: HWCRYPTO TIPC client not initialized\n", __func__); + return TRUSTY_ERR_GENERIC; + } + + rc = hwcrypto_send_request(&msg, req, req_size); + if (rc < 0) { + trusty_error("%s: failed (%d) to send hwcrypto request\n", __func__, rc); + return rc; + } + + if (handle_rpmb) { + /* handle any incoming RPMB requests */ + rc = rpmb_storage_proxy_poll(); + if (rc < 0) { + trusty_error("%s: failed (%d) to get RPMB requests\n", __func__, + rc); + return rc; + } + } + + uint32_t resp_size = resp_size_p ? *resp_size_p : 0; + rc = hwcrypto_read_response(&msg, cmd, resp, resp_size); + if (rc < 0) { + trusty_error("%s: failed (%d) to read HWCRYPTO response\n", __func__, rc); + return rc; + } + /* change response size to actual response size */ + if (resp_size_p && rc != *resp_size_p) { + *resp_size_p = rc; + } + if (msg.result != HWCRYPTO_ERROR_NONE) { + trusty_error("%s: HWCRYPTO service returned error (%d)\n", __func__, + msg.result); + return TRUSTY_ERR_GENERIC; + } + return TRUSTY_ERR_NONE; +} + +int hwcrypto_tipc_init(struct trusty_ipc_dev *dev) +{ + int rc; + + trusty_assert(dev); + trusty_assert(!initialized); + + trusty_ipc_chan_init(&hwcrypto_chan, dev); + trusty_debug("Connecting to hwcrypto service\n"); + + /* connect to hwcrypto service and wait for connect to complete */ + rc = trusty_ipc_connect(&hwcrypto_chan, HWCRYPTO_PORT, true); + if (rc < 0) { + trusty_error("failed (%d) to connect to '%s'\n", rc, HWCRYPTO_PORT); + return rc; + } + + /* mark as initialized */ + initialized = true; + + return TRUSTY_ERR_NONE; +} + +void hwcrypto_tipc_shutdown(struct trusty_ipc_dev *dev) +{ + if (!initialized) + return; /* nothing to do */ + + /* close channel */ + trusty_ipc_close(&hwcrypto_chan); + + initialized = false; +} + +int hwcrypto_hash(uint32_t in_addr, uint32_t in_len, uint32_t out_addr, + uint32_t out_len, enum hwcrypto_hash_algo algo) +{ + hwcrypto_hash_msg req; + unsigned long start, end; + + /* check the address */ + if (in_addr == 0 || out_addr == 0) + return TRUSTY_ERR_INVALID_ARGS; + /* fill the request buffer */ + req.in_addr = in_addr; + req.out_addr = out_addr; + req.in_len = in_len; + req.out_len = out_len; + req.algo = algo; + + /* flush dcache for input buffer */ + start = (unsigned long)in_addr & ~(ARCH_DMA_MINALIGN - 1); + end = ALIGN((unsigned long)in_addr + in_len, ARCH_DMA_MINALIGN); + flush_dcache_range(start, end); + + /* invalidate dcache for output buffer */ + start = (unsigned long)out_addr & ~(ARCH_DMA_MINALIGN - 1); + end = ALIGN((unsigned long)out_addr + out_len, ARCH_DMA_MINALIGN); + invalidate_dcache_range(start, end); + + int rc = hwcrypto_do_tipc(HWCRYPTO_HASH, (void*)&req, + sizeof(req), NULL, 0, false); + return rc; +} + +int hwcrypto_gen_blob(uint32_t plain_pa, + uint32_t plain_size, uint32_t blob_pa) +{ + hwcrypto_blob_msg req; + unsigned long start, end; + + /* check the address */ + if (plain_pa == 0 || blob_pa == 0) + return TRUSTY_ERR_INVALID_ARGS; + /* fill the request buffer */ + req.plain_pa = plain_pa; + req.plain_size = plain_size; + req.blob_pa = blob_pa; + + /* flush dcache for input buffer */ + start = (unsigned long)plain_pa & ~(ARCH_DMA_MINALIGN - 1); + end = ALIGN((unsigned long)plain_pa + plain_size, ARCH_DMA_MINALIGN); + flush_dcache_range(start, end); + + /* invalidate dcache for output buffer */ + start = (unsigned long)blob_pa & ~(ARCH_DMA_MINALIGN - 1); + end = ALIGN((unsigned long)blob_pa + plain_size + + CAAM_KB_HEADER_LEN, ARCH_DMA_MINALIGN); + invalidate_dcache_range(start, end); + + int rc = hwcrypto_do_tipc(HWCRYPTO_ENCAP_BLOB, (void*)&req, + sizeof(req), NULL, 0, false); + return rc; +} + +int hwcrypto_gen_rng(uint32_t buf, uint32_t len) +{ + hwcrypto_rng_msg req; + unsigned long start, end; + + /* check the address */ + if (buf == 0) + return TRUSTY_ERR_INVALID_ARGS; + /* fill the request buffer */ + req.buf = buf; + req.len = len; + + /* invalidate dcache for output buffer */ + start = (unsigned long)buf & ~(ARCH_DMA_MINALIGN - 1); + end = ALIGN((unsigned long)buf + len, ARCH_DMA_MINALIGN); + invalidate_dcache_range(start, end); + + int rc = hwcrypto_do_tipc(HWCRYPTO_GEN_RNG, (void*)&req, + sizeof(req), NULL, 0, false); + return rc; +} diff --git a/lib/trusty/ql-tipc/ipc.c b/lib/trusty/ql-tipc/ipc.c new file mode 100644 index 0000000000..f488984d76 --- /dev/null +++ b/lib/trusty/ql-tipc/ipc.c @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#define LOCAL_LOG 0 + +static int sync_ipc_on_connect_complete(struct trusty_ipc_chan *chan) +{ + trusty_assert(chan); + + chan->complete = 1; + return TRUSTY_EVENT_HANDLED; +} + +static int sync_ipc_on_message(struct trusty_ipc_chan *chan) +{ + trusty_assert(chan); + + chan->complete = 1; + return TRUSTY_EVENT_HANDLED; +} + +static int sync_ipc_on_disconnect(struct trusty_ipc_chan *chan) +{ + trusty_assert(chan); + + chan->complete = TRUSTY_ERR_CHANNEL_CLOSED; + return TRUSTY_EVENT_HANDLED; +} + +static int wait_for_complete(struct trusty_ipc_chan *chan) +{ + int rc; + + chan->complete = 0; + for (;;) { + rc = trusty_ipc_poll_for_event(chan->dev); + if (rc < 0) + return rc; + + if (chan->complete) + break; + + if (rc == TRUSTY_EVENT_NONE) + trusty_ipc_dev_idle(chan->dev); + } + + return chan->complete; +} + +static int wait_for_connect(struct trusty_ipc_chan *chan) +{ + trusty_debug("%s: chan %x: waiting for connect\n", __func__, + (int)chan->handle); + return wait_for_complete(chan); +} + +static int wait_for_send(struct trusty_ipc_chan *chan) +{ + trusty_debug("%s: chan %d: waiting for send\n", __func__, chan->handle); + return wait_for_complete(chan); +} + +static int wait_for_reply(struct trusty_ipc_chan *chan) +{ + trusty_debug("%s: chan %d: waiting for reply\n", __func__, chan->handle); + return wait_for_complete(chan); +} + +static struct trusty_ipc_ops sync_ipc_ops = { + .on_connect_complete = sync_ipc_on_connect_complete, + .on_message = sync_ipc_on_message, + .on_disconnect = sync_ipc_on_disconnect, +}; + +void trusty_ipc_chan_init(struct trusty_ipc_chan *chan, + struct trusty_ipc_dev *dev) +{ + trusty_assert(chan); + trusty_assert(dev); + + trusty_memset(chan, 0, sizeof(*chan)); + + chan->handle = INVALID_IPC_HANDLE; + chan->dev = dev; + chan->ops = &sync_ipc_ops; + chan->ops_ctx = chan; +} + +int trusty_ipc_connect(struct trusty_ipc_chan *chan, const char *port, + bool wait) +{ + int rc; + + trusty_assert(chan); + trusty_assert(chan->dev); + trusty_assert(chan->handle == INVALID_IPC_HANDLE); + trusty_assert(port); + + rc = trusty_ipc_dev_connect(chan->dev, port, (uint64_t)(uintptr_t)chan); + if (rc < 0) { + trusty_error("%s: init connection failed (%d)\n", __func__, rc); + return rc; + } + chan->handle = (handle_t)rc; + trusty_debug("chan->handle: %x\n", (int)chan->handle); + + /* got valid channel */ + if (wait) { + rc = wait_for_connect(chan); + if (rc < 0) { + trusty_error("%s: wait for connect failed (%d)\n", __func__, rc); + trusty_ipc_close(chan); + } + } + + return rc; +} + +int trusty_ipc_close(struct trusty_ipc_chan *chan) +{ + int rc; + + trusty_assert(chan); + + rc = trusty_ipc_dev_close(chan->dev, chan->handle); + chan->handle = INVALID_IPC_HANDLE; + + return rc; +} + +int trusty_ipc_send(struct trusty_ipc_chan *chan, + const struct trusty_ipc_iovec *iovs, size_t iovs_cnt, + bool wait) +{ + int rc; + + trusty_assert(chan); + trusty_assert(chan->dev); + trusty_assert(chan->handle); + +Again: + rc = trusty_ipc_dev_send(chan->dev, chan->handle, iovs, iovs_cnt); + if (rc == TRUSTY_ERR_SEND_BLOCKED) { + if (wait) { + rc = wait_for_send(chan); + if (rc < 0) { + trusty_error("%s: wait to send failed (%d)\n", __func__, rc); + return rc; + } + goto Again; + } + } + return rc; +} + +int trusty_ipc_recv(struct trusty_ipc_chan *chan, + const struct trusty_ipc_iovec *iovs, size_t iovs_cnt, + bool wait) +{ + int rc; + trusty_assert(chan); + trusty_assert(chan->dev); + trusty_assert(chan->handle); + + if (wait) { + rc = wait_for_reply(chan); + if (rc < 0) { + trusty_error("%s: wait to reply failed (%d)\n", __func__, rc); + return rc; + } + } + + rc = trusty_ipc_dev_recv(chan->dev, chan->handle, iovs, iovs_cnt); + if (rc < 0) + trusty_error("%s: ipc recv failed (%d)\n", __func__, rc); + + return rc; +} + +int trusty_ipc_poll_for_event(struct trusty_ipc_dev *ipc_dev) +{ + int rc; + struct trusty_ipc_event evt; + struct trusty_ipc_chan *chan; + + trusty_assert(dev); + + rc = trusty_ipc_dev_get_event(ipc_dev, 0, &evt); + if (rc) { + trusty_error("%s: get event failed (%d)\n", __func__, rc); + return rc; + } + + /* check if we have an event */ + if (!evt.event) { + trusty_debug("%s: no event\n", __func__); + return TRUSTY_EVENT_NONE; + } + + chan = (struct trusty_ipc_chan *)(uintptr_t)evt.cookie; + trusty_assert(chan && chan->ops); + + /* check if we have raw event handler */ + if (chan->ops->on_raw_event) { + /* invoke it first */ + rc = chan->ops->on_raw_event(chan, &evt); + if (rc < 0) { + trusty_error("%s: chan %d: raw event cb returned (%d)\n", __func__, + chan->handle, rc); + return rc; + } + if (rc > 0) + return rc; /* handled */ + } + + if (evt.event & IPC_HANDLE_POLL_ERROR) { + /* something is very wrong */ + trusty_error("%s: chan %d: chan in error state\n", __func__, + chan->handle); + return TRUSTY_ERR_GENERIC; + } + + /* send unblocked should be handled first as it is edge truggered event */ + if (evt.event & IPC_HANDLE_POLL_SEND_UNBLOCKED) { + if (chan->ops->on_send_unblocked) { + rc = chan->ops->on_send_unblocked(chan); + if (rc < 0) { + trusty_error("%s: chan %d: send unblocked cb returned (%d)\n", + __func__, chan->handle, rc); + return rc; + } + if (rc > 0) + return rc; /* handled */ + } + } + + /* check for connection complete */ + if (evt.event & IPC_HANDLE_POLL_READY) { + if (chan->ops->on_connect_complete) { + rc = chan->ops->on_connect_complete(chan); + if (rc < 0) { + trusty_error("%s: chan %d: ready cb returned (%d)\n", __func__, + chan->handle, rc); + return rc; + } + if (rc > 0) + return rc; /* handled */ + } + } + + /* check for incomming messages */ + if (evt.event & IPC_HANDLE_POLL_MSG) { + if (chan->ops->on_message) { + rc = chan->ops->on_message(chan); + if (rc < 0) { + trusty_error("%s: chan %d: msg cb returned (%d)\n", __func__, + chan->handle, rc); + return rc; + } + if (rc > 0) + return rc; + } + } + + /* check for hangups */ + if (evt.event & IPC_HANDLE_POLL_HUP) { + if (chan->ops->on_disconnect) { + rc = chan->ops->on_disconnect(chan); + if (rc < 0) { + trusty_error("%s: chan %d: hup cb returned (%d)\n", __func__, + chan->handle, rc); + return rc; + } + if (rc > 0) + return rc; + } + } + + return TRUSTY_ERR_NONE; +} diff --git a/lib/trusty/ql-tipc/ipc_dev.c b/lib/trusty/ql-tipc/ipc_dev.c new file mode 100644 index 0000000000..720acf22be --- /dev/null +++ b/lib/trusty/ql-tipc/ipc_dev.c @@ -0,0 +1,458 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include + +#define NS_PTE_PHYSADDR(pte) ((pte) & 0xFFFFFFFFF000ULL) + +#define QL_TIPC_DEV_RESP 0x8000 +#define QL_TIPC_DEV_CONNECT 0x1 +#define QL_TIPC_DEV_GET_EVENT 0x2 +#define QL_TIPC_DEV_SEND 0x3 +#define QL_TIPC_DEV_RECV 0x4 +#define QL_TIPC_DEV_DISCONNECT 0x5 + +#define LOCAL_LOG 0 + +struct trusty_ipc_cmd_hdr { + uint16_t opcode; + uint16_t flags; + uint32_t status; + uint32_t handle; + uint32_t payload_len; + uint8_t payload[0]; +}; + +struct trusty_ipc_wait_req { + uint64_t reserved; +}; + +struct trusty_ipc_connect_req { + uint64_t cookie; + uint64_t reserved; + uint8_t name[0]; +}; + +static size_t iovec_size(const struct trusty_ipc_iovec *iovs, size_t iovs_cnt) +{ + size_t i; + size_t cb = 0; + + trusty_assert(iovs); + + for (i = 0; i < iovs_cnt; i++) { + cb += iovs[i].len; + } + + return cb; +} + +static size_t iovec_to_buf(void *buf, size_t buf_len, + const struct trusty_ipc_iovec *iovs, size_t iovs_cnt) +{ + size_t i; + size_t buf_pos = 0; + + trusty_assert(iovs); + + for (i = 0; i < iovs_cnt; i++) { + size_t to_copy = (size_t)iovs[i].len; + + if (!to_copy) + continue; + + if (to_copy > buf_len) + to_copy = buf_len; + + trusty_memcpy((uint8_t *)buf + buf_pos, iovs[i].base, to_copy); + + buf_pos += to_copy; + buf_len -= to_copy; + + if (buf_len == 0) + break; + } + + return buf_pos; +} + +static size_t buf_to_iovec(const struct trusty_ipc_iovec *iovs, size_t iovs_cnt, + const void *buf, size_t buf_len) +{ + size_t i; + size_t copied = 0; + const uint8_t *buf_ptr = buf; + + trusty_assert(buf_ptr); + trusty_assert(iovs); + + if (iovs_cnt == 0 || buf_len == 0) + return 0; + + for (i = 0; i < iovs_cnt; i++) { + size_t to_copy = buf_len; + + if (to_copy > iovs[i].len) + to_copy = iovs[i].len; + + if (!to_copy) + continue; + + trusty_memcpy(iovs[i].base, buf_ptr, to_copy); + + copied += to_copy; + buf_ptr += to_copy; + buf_len -= to_copy; + + if (buf_len == 0) + break; + } + + return copied; +} + +static int check_response(struct trusty_ipc_dev *dev, + volatile struct trusty_ipc_cmd_hdr *hdr, uint16_t cmd) +{ + if (hdr->opcode != (cmd | QL_TIPC_DEV_RESP)) { + /* malformed response */ + trusty_error("%s: malformed response cmd: 0x%x\n", + __func__, hdr->opcode); + return TRUSTY_ERR_SECOS_ERR; + } + + if (hdr->status) { + /* secure OS responded with error: TODO need error code */ + trusty_error("%s: cmd 0x%x: status = %d\n", + __func__, hdr->opcode, hdr->status); + return TRUSTY_ERR_SECOS_ERR; + } + + return TRUSTY_ERR_NONE; +} + +int trusty_ipc_dev_create(struct trusty_ipc_dev **idev, + struct trusty_dev *tdev, + size_t shared_buf_size) +{ + int rc; + struct trusty_ipc_dev *dev; + + trusty_assert(idev); + trusty_assert(!(shared_buf_size % PAGE_SIZE)); + trusty_debug("%s: Create new Trusty IPC device (%zu)\n", __func__, + shared_buf_size); + + /* allocate device context */ + dev = trusty_calloc(1, sizeof(*dev)); + if (!dev) { + trusty_error("%s: failed to allocate Trusty IPC device\n", __func__); + return TRUSTY_ERR_NO_MEMORY; + } + dev->tdev = tdev; + + /* allocate shared buffer */ + dev->buf_size = shared_buf_size; + dev->buf_vaddr = trusty_alloc_pages(shared_buf_size / PAGE_SIZE); + if (!dev->buf_vaddr) { + trusty_error("%s: failed to allocate shared memory\n", __func__); + rc = TRUSTY_ERR_NO_MEMORY; + goto err_alloc_pages; + } + + /* Get memory attributes */ + rc = trusty_encode_page_info(&dev->buf_ns, dev->buf_vaddr); + if (rc != 0) { + trusty_error("%s: failed to get shared memory attributes\n", __func__); + rc = TRUSTY_ERR_GENERIC; + goto err_page_info; + } + /* call secure OS to register shared buffer */ + rc = trusty_dev_init_ipc(dev->tdev, &dev->buf_ns, dev->buf_size); + if (rc != 0) { + trusty_error("%s: failed (%d) to create Trusty IPC device\n", + __func__, rc); + rc = TRUSTY_ERR_SECOS_ERR; + goto err_create_sec_dev; + } + + trusty_debug("%s: new Trusty IPC device (%p)\n", __func__, dev); + + *idev = dev; + return TRUSTY_ERR_NONE; + +err_page_info: +err_create_sec_dev: + trusty_free_pages(dev->buf_vaddr, dev->buf_size / PAGE_SIZE); +err_alloc_pages: + trusty_free(dev); + return rc; +} + +void trusty_ipc_dev_shutdown(struct trusty_ipc_dev *dev) +{ + int rc; + trusty_assert(dev); + + trusty_debug("%s: shutting down Trusty IPC device (%p)\n", __func__, dev); + + /* shutdown Trusty IPC device */ + rc = trusty_dev_shutdown_ipc(dev->tdev, &dev->buf_ns, dev->buf_size); + trusty_assert(!rc); + if (rc != 0) { + trusty_error("%s: failed (%d) to shutdown Trusty IPC device\n", + __func__, rc); + } + trusty_free_pages(dev->buf_vaddr, dev->buf_size / PAGE_SIZE); + trusty_free(dev); +} + +int trusty_ipc_dev_connect(struct trusty_ipc_dev *dev, const char *port, + uint64_t cookie) +{ + int rc; + size_t port_len; + volatile struct trusty_ipc_cmd_hdr *cmd; + struct trusty_ipc_connect_req *req; + + trusty_assert(dev); + trusty_assert(port); + + trusty_debug("%s: connecting to '%s'\n", __func__, port); + + /* check port name length */ + port_len = trusty_strlen(port) + 1; + if (port_len > (dev->buf_size - sizeof(*cmd) + sizeof(*req))) { + /* it would not fit into buffer */ + trusty_error("%s: port name is too long (%zu)\n", __func__, port_len); + return TRUSTY_ERR_INVALID_ARGS; + } + + /* prepare command */ + cmd = dev->buf_vaddr; + trusty_memset((void *)cmd, 0, sizeof(*cmd)); + cmd->opcode = QL_TIPC_DEV_CONNECT; + + /* prepare payload */ + req = (struct trusty_ipc_connect_req *)cmd->payload; + trusty_memset((void *)req, 0, sizeof(*req)); + req->cookie = cookie; + trusty_strcpy((char *)req->name, port); + cmd->payload_len = sizeof(*req) + port_len; + + /* call secure os */ + rc = trusty_dev_exec_ipc(dev->tdev, + &dev->buf_ns, sizeof(*cmd) + cmd->payload_len); + if (rc) { + /* secure OS returned an error */ + trusty_error("%s: secure OS returned (%d)\n", __func__, rc); + return TRUSTY_ERR_SECOS_ERR; + } + + rc = check_response(dev, cmd, QL_TIPC_DEV_CONNECT); + if (rc) { + trusty_error("%s: connect cmd failed (%d)\n", __func__, rc); + return rc; + } + + /* success */ + return cmd->handle; +} + +int trusty_ipc_dev_close(struct trusty_ipc_dev *dev, handle_t handle) +{ + int rc; + volatile struct trusty_ipc_cmd_hdr *cmd; + + trusty_assert(dev); + + trusty_debug("%s: chan %d: closing\n", __func__, handle); + + /* prepare command */ + cmd = dev->buf_vaddr; + trusty_memset((void *)cmd, 0, sizeof(*cmd)); + cmd->opcode = QL_TIPC_DEV_DISCONNECT; + cmd->handle = handle; + /* no payload */ + + /* call into secure os */ + rc = trusty_dev_exec_ipc(dev->tdev, + &dev->buf_ns, sizeof(*cmd) + cmd->payload_len); + if (rc) { + trusty_error("%s: secure OS returned (%d)\n", __func__, rc); + return TRUSTY_ERR_SECOS_ERR; + } + + rc = check_response(dev, cmd, QL_TIPC_DEV_DISCONNECT); + if (rc) { + trusty_error("%s: disconnect cmd failed (%d)\n", __func__, rc); + return rc; + } + + trusty_debug("%s: chan %d: closed\n", __func__, handle); + + return TRUSTY_ERR_NONE; +} + +int trusty_ipc_dev_get_event(struct trusty_ipc_dev *dev, handle_t chan, + struct trusty_ipc_event *event) +{ + int rc; + volatile struct trusty_ipc_cmd_hdr *cmd; + + trusty_assert(dev); + trusty_assert(event); + + /* prepare command */ + cmd = dev->buf_vaddr; + trusty_memset((void *)cmd, 0, sizeof(*cmd)); + cmd->opcode = QL_TIPC_DEV_GET_EVENT; + cmd->handle = chan; + + /* prepare payload */ + trusty_memset((void *)cmd->payload, 0, sizeof(struct trusty_ipc_wait_req)); + cmd->payload_len = sizeof(struct trusty_ipc_wait_req); + + /* call into secure os */ + rc = trusty_dev_exec_ipc(dev->tdev, + &dev->buf_ns, sizeof(*cmd) + cmd->payload_len); + if (rc) { + trusty_error("%s: secure OS returned (%d)\n", __func__, rc); + return TRUSTY_ERR_SECOS_ERR; + } + + rc = check_response(dev, cmd, QL_TIPC_DEV_GET_EVENT); + if (rc) { + trusty_error("%s: get event cmd failed (%d)\n", __func__, rc); + return rc; + } + + if ((size_t)cmd->payload_len < sizeof(*event)) { + trusty_error("%s: invalid response length (%zd)\n", + __func__, (size_t)cmd->payload_len); + return TRUSTY_ERR_SECOS_ERR; + } + + /* copy out event */ + trusty_memcpy(event, (const void *)cmd->payload, sizeof(*event)); + return TRUSTY_ERR_NONE; +} + +int trusty_ipc_dev_send(struct trusty_ipc_dev *dev, handle_t chan, + const struct trusty_ipc_iovec *iovs, size_t iovs_cnt) +{ + int rc; + size_t msg_size; + volatile struct trusty_ipc_cmd_hdr *cmd; + + trusty_assert(dev); + /* calc message length */ + msg_size = iovec_size(iovs, iovs_cnt); + if (msg_size > dev->buf_size - sizeof(*cmd)) { + /* msg is too big to fit provided buffer */ + trusty_error("%s: chan %d: msg is too long (%zu)\n", __func__, + chan, msg_size); + return TRUSTY_ERR_MSG_TOO_BIG; + } + + /* prepare command */ + cmd = dev->buf_vaddr; + trusty_memset((void *)cmd, 0, sizeof(*cmd)); + cmd->opcode = QL_TIPC_DEV_SEND; + cmd->handle = chan; + + /* copy in message data */ + cmd->payload_len = (uint32_t)msg_size; + msg_size = iovec_to_buf(dev->buf_vaddr + sizeof(*cmd), dev->buf_size - sizeof(*cmd), + iovs, iovs_cnt); + trusty_assert(msg_size == (size_t)cmd->payload_len); + + /* call into secure os */ + rc = trusty_dev_exec_ipc(dev->tdev, + &dev->buf_ns, sizeof(*cmd) + cmd->payload_len); + if (rc < 0) { + trusty_error("%s: secure OS returned (%d)\n", __func__, rc); + return TRUSTY_ERR_SECOS_ERR; + } + + rc = check_response(dev, cmd, QL_TIPC_DEV_SEND); + if (rc) { + trusty_error("%s: send msg failed (%d)\n", __func__, rc); + } + + return rc; +} + + +int trusty_ipc_dev_recv(struct trusty_ipc_dev *dev, handle_t chan, + const struct trusty_ipc_iovec *iovs, size_t iovs_cnt) +{ + int rc; + size_t copied; + volatile struct trusty_ipc_cmd_hdr *cmd; + + trusty_assert(dev); + + /* prepare command */ + cmd = dev->buf_vaddr; + trusty_memset((void *)cmd, 0, sizeof(*cmd)); + cmd->opcode = QL_TIPC_DEV_RECV; + cmd->handle = chan; + /* no payload */ + + /* call into secure os */ + rc = trusty_dev_exec_ipc(dev->tdev, + &dev->buf_ns, sizeof(*cmd) + cmd->payload_len); + if (rc < 0) { + trusty_error("%s: secure OS returned (%d)\n", __func__, rc); + return TRUSTY_ERR_SECOS_ERR; + } + + rc = check_response(dev, cmd, QL_TIPC_DEV_RECV); + if (rc) { + trusty_error("%s: recv cmd failed (%d)\n", __func__, rc); + return rc; + } + + /* copy data out to proper destination */ + copied = buf_to_iovec(iovs, iovs_cnt, + (const void *)cmd->payload, cmd->payload_len); + if (copied != (size_t)cmd->payload_len) { + /* msg is too big to fit provided buffer */ + trusty_error("%s: chan %d: buffer too small (%zu vs. %zu)\n", + __func__, chan, copied, (size_t)cmd->payload_len); + return TRUSTY_ERR_MSG_TOO_BIG; + } + + return (int)copied; +} + +void trusty_ipc_dev_idle(struct trusty_ipc_dev *dev) +{ + trusty_idle(dev->tdev); +} + diff --git a/lib/trusty/ql-tipc/keymaster.c b/lib/trusty/ql-tipc/keymaster.c new file mode 100644 index 0000000000..eaa43e3874 --- /dev/null +++ b/lib/trusty/ql-tipc/keymaster.c @@ -0,0 +1,482 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#define LOCAL_LOG 0 + +static struct trusty_ipc_chan km_chan; +static bool initialized = false; +static int trusty_km_version = 2; +static const size_t kMaxCaRequestSize = 10000; +static const size_t kMaxSendSize = 4000; +static const size_t kUuidSize = 32; + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef NELEMS +#define NELEMS(x) (sizeof(x) / sizeof((x)[0])) +#endif + +static int km_send_request(uint32_t cmd, const void *req, size_t req_len) +{ + struct keymaster_message header = { .cmd = cmd }; + int num_iovecs = req ? 2 : 1; + + struct trusty_ipc_iovec req_iovs[2] = { + { .base = &header, .len = sizeof(header) }, + { .base = (void*)req, .len = req_len }, + }; + + return trusty_ipc_send(&km_chan, req_iovs, num_iovecs, true); +} + +/* Checks that the command opcode in |header| matches |ex-ected_cmd|. Checks + * that |tipc_result| is a valid response size. Returns negative on error. + */ +static int check_response_error(uint32_t expected_cmd, + struct keymaster_message header, + int32_t tipc_result) +{ + if (tipc_result < 0) { + trusty_error("failed (%d) to recv response\n", tipc_result); + return tipc_result; + } + if ((size_t) tipc_result < sizeof(struct keymaster_message)) { + trusty_error("invalid response size (%d)\n", tipc_result); + return TRUSTY_ERR_GENERIC; + } + if ((header.cmd & ~(KEYMASTER_STOP_BIT)) != + (expected_cmd | KEYMASTER_RESP_BIT)) { + trusty_error("malformed response\n"); + return TRUSTY_ERR_GENERIC; + } + return tipc_result; +} + +/* Reads the raw response to |resp| up to a maximum size of |resp_len|. Format + * of each message frame read from the secure side: + * + * command header : 4 bytes + * opaque bytes : MAX(KEYMASTER_MAX_BUFFER_LENGTH, x) bytes + * + * The individual message frames from the secure side are reassembled + * into |resp|, stripping each frame's command header. Returns the number + * of bytes written to |resp| on success, negative on error. + */ +static int km_read_raw_response(uint32_t cmd, void *resp, size_t resp_len) +{ + struct keymaster_message header = { .cmd = cmd }; + int rc = TRUSTY_ERR_GENERIC; + size_t max_resp_len = resp_len; + struct trusty_ipc_iovec resp_iovs[2] = { + { .base = &header, .len = sizeof(header) }, + { .base = resp, .len = MIN(KEYMASTER_MAX_BUFFER_LENGTH, max_resp_len) } + }; + + if (!resp) { + return TRUSTY_ERR_GENERIC; + } + resp_len = 0; + while (true) { + resp_iovs[1].base = (uint8_t*)resp + resp_len; + resp_iovs[1].len = MIN(KEYMASTER_MAX_BUFFER_LENGTH, + (int)max_resp_len - (int)resp_len); + + rc = trusty_ipc_recv(&km_chan, resp_iovs, NELEMS(resp_iovs), true); + rc = check_response_error(cmd, header, rc); + if (rc < 0) { + return rc; + } + resp_len += ((size_t)rc - sizeof(struct keymaster_message)); + if (header.cmd & KEYMASTER_STOP_BIT || resp_len >= max_resp_len) { + break; + } + } + + return resp_len; +} + +/* Reads a Keymaster Response message with a sized buffer. The format + * of the response is as follows: + * + * command header : 4 bytes + * error : 4 bytes + * data length : 4 bytes + * data : |data length| bytes + * + * On success, |error|, |resp_data|, and |resp_data_len| are filled + * successfully. Returns a trusty_err. + */ +static int km_read_data_response(uint32_t cmd, int32_t *error, + uint8_t* resp_data, uint32_t* resp_data_len) +{ + struct keymaster_message header = { .cmd = cmd }; + int rc = TRUSTY_ERR_GENERIC; + size_t max_resp_len = *resp_data_len; + uint32_t resp_data_bytes = 0; + /* On the first read, recv the keymaster_message header, error code, + * response data length, and response data. On subsequent iterations, + * only recv the keymaster_message header and response data. + */ + struct trusty_ipc_iovec resp_iovs[4] = { + { .base = &header, .len = sizeof(header) }, + { .base = error, .len = sizeof(int32_t) }, + { .base = resp_data_len, .len = sizeof(uint32_t) }, + { .base = resp_data, .len = MIN(KEYMASTER_MAX_BUFFER_LENGTH, max_resp_len) } + }; + + rc = trusty_ipc_recv(&km_chan, resp_iovs, NELEMS(resp_iovs), true); + rc = check_response_error(cmd, header, rc); + if (rc < 0) { + return rc; + } + /* resp_data_bytes does not include the error or response data length */ + resp_data_bytes += ((size_t)rc - sizeof(struct keymaster_message) - + 2 * sizeof(uint32_t)); + if (header.cmd & KEYMASTER_STOP_BIT) { + return TRUSTY_ERR_NONE; + } + + /* Read the remaining response data */ + uint8_t* resp_data_start = resp_data + resp_data_bytes; + size_t resp_data_remaining = *resp_data_len - resp_data_bytes; + rc = km_read_raw_response(cmd, resp_data_start, resp_data_remaining); + if (rc < 0) { + return rc; + } + resp_data_bytes += rc; + if (*resp_data_len != resp_data_bytes) { + return TRUSTY_ERR_GENERIC; + } + return TRUSTY_ERR_NONE; +} + +/** + * Convenience method to send a request to the secure side, handle rpmb + * operations, and receive the response. If |resp_data| is not NULL, the + * caller expects an additional data buffer to be returned from the secure + * side. + */ +static int km_do_tipc(uint32_t cmd, void* req, uint32_t req_len, + void* resp_data, uint32_t* resp_data_len) +{ + int rc = TRUSTY_ERR_GENERIC; + struct km_no_response resp_header; + + rc = km_send_request(cmd, req, req_len); + if (rc < 0) { + trusty_error("%s: failed (%d) to send km request\n", __func__, rc); + return rc; + } + + if (!resp_data) { + rc = km_read_raw_response(cmd, &resp_header, sizeof(resp_header)); + } else { + rc = km_read_data_response(cmd, &resp_header.error, resp_data, + resp_data_len); + } + + if (rc < 0) { + trusty_error("%s: failed (%d) to read km response\n", __func__, rc); + return rc; + } + if (resp_header.error != KM_ERROR_OK) { + trusty_error("%s: keymaster returned error (%d)\n", __func__, + resp_header.error); + return TRUSTY_ERR_GENERIC; + } + return TRUSTY_ERR_NONE; +} + +static int32_t MessageVersion(uint8_t major_ver, uint8_t minor_ver, + uint8_t subminor_ver) { + int32_t message_version = -1; + switch (major_ver) { + case 0: + message_version = 0; + break; + case 1: + switch (minor_ver) { + case 0: + message_version = 1; + break; + case 1: + message_version = 2; + break; + } + break; + case 2: + message_version = 3; + break; + } + return message_version; +} + +static int km_get_version(int32_t *version) +{ + int rc = TRUSTY_ERR_GENERIC; + struct km_get_version_resp resp; + + rc = km_send_request(KM_GET_VERSION, NULL, 0); + if (rc < 0) { + trusty_error("failed to send km version request", rc); + return rc; + } + + rc = km_read_raw_response(KM_GET_VERSION, &resp, sizeof(resp)); + if (rc < 0) { + trusty_error("%s: failed (%d) to read km response\n", __func__, rc); + return rc; + } + + *version = MessageVersion(resp.major_ver, resp.minor_ver, + resp.subminor_ver); + return TRUSTY_ERR_NONE; +} + +int km_tipc_init(struct trusty_ipc_dev *dev) +{ + int rc = TRUSTY_ERR_GENERIC; + + trusty_assert(dev); + + trusty_ipc_chan_init(&km_chan, dev); + trusty_debug("Connecting to Keymaster service\n"); + + /* connect to km service and wait for connect to complete */ + rc = trusty_ipc_connect(&km_chan, KEYMASTER_PORT, true); + if (rc < 0) { + trusty_error("failed (%d) to connect to '%s'\n", rc, KEYMASTER_PORT); + return rc; + } + + int32_t version = -1; + rc = km_get_version(&version); + if (rc < 0) { + trusty_error("failed (%d) to get keymaster version\n", rc); + return rc; + } + if (version < trusty_km_version) { + trusty_error("keymaster version mismatch. Expected %d, received %d\n", + trusty_km_version, version); + return TRUSTY_ERR_GENERIC; + } + + /* mark as initialized */ + initialized = true; + + return TRUSTY_ERR_NONE; +} + +void km_tipc_shutdown(struct trusty_ipc_dev *dev) +{ + if (!initialized) + return; + /* close channel */ + trusty_ipc_close(&km_chan); + + initialized = false; +} + +int trusty_set_boot_params(uint32_t os_version, uint32_t os_patchlevel, + keymaster_verified_boot_t verified_boot_state, + bool device_locked, + const uint8_t *verified_boot_key_hash, + uint32_t verified_boot_key_hash_size, + const uint8_t *verified_boot_hash, + uint32_t verified_boot_hash_size) +{ + if (!initialized) { + trusty_error("Keymaster TIPC client not initialized!\n"); + return -1; + } + struct km_boot_params params = { + .os_version = os_version, + .os_patchlevel = os_patchlevel, + .device_locked = (uint32_t)device_locked, + .verified_boot_state = (uint32_t)verified_boot_state, + .verified_boot_key_hash_size = verified_boot_key_hash_size, + .verified_boot_key_hash = verified_boot_key_hash, + .verified_boot_hash_size = verified_boot_hash_size, + .verified_boot_hash = verified_boot_hash + }; + uint8_t *req = NULL; + uint32_t req_size = 0; + int rc = km_boot_params_serialize(¶ms, &req, &req_size); + + if (rc < 0) { + trusty_error("failed (%d) to serialize request\n", rc); + goto end; + } + rc = km_do_tipc(KM_SET_BOOT_PARAMS, req, req_size, NULL, NULL); + +end: + if (req) { + trusty_free(req); + } + return rc; +} + +static int trusty_send_attestation_data(uint32_t cmd, const uint8_t *data, + uint32_t data_size, + keymaster_algorithm_t algorithm) +{ + struct km_attestation_data attestation_data = { + .algorithm = (uint32_t)algorithm, + .data_size = data_size, + .data = data, + }; + uint8_t *req = NULL; + uint32_t req_size = 0; + int rc = km_attestation_data_serialize(&attestation_data, &req, &req_size); + + if (rc < 0) { + trusty_error("failed (%d) to serialize request\n", rc); + goto end; + } + rc = km_do_tipc(cmd, req, req_size, NULL, NULL); + +end: + if (req) { + trusty_free(req); + } + return rc; +} + +static int trusty_send_raw_buffer(uint32_t cmd, const uint8_t *req_data, + uint32_t req_data_size, uint8_t *resp_data, + uint32_t *resp_data_size) +{ + struct km_raw_buffer buf = { + .data_size = req_data_size, + .data = req_data, + }; + uint8_t *req = NULL; + uint32_t req_size = 0; + int rc = km_raw_buffer_serialize(&buf, &req, &req_size); + if (rc < 0) { + trusty_error("failed (%d) to serialize request\n", rc); + goto end; + } + rc = km_do_tipc(cmd, req, req_size, resp_data, resp_data_size); + +end: + if (req) { + trusty_free(req); + } + return rc; +} + +int trusty_set_attestation_key(const uint8_t *key, uint32_t key_size, + keymaster_algorithm_t algorithm) +{ + return trusty_send_attestation_data(KM_SET_ATTESTATION_KEY, key, key_size, + algorithm); +} + +int trusty_append_attestation_cert_chain(const uint8_t *cert, + uint32_t cert_size, + keymaster_algorithm_t algorithm) +{ + return trusty_send_attestation_data(KM_APPEND_ATTESTATION_CERT_CHAIN, + cert, cert_size, algorithm); +} + +int trusty_atap_get_ca_request(const uint8_t *operation_start, + uint32_t operation_start_size, + uint8_t **ca_request_p, + uint32_t *ca_request_size_p) +{ + *ca_request_p = trusty_calloc(1, kMaxCaRequestSize); + if (!*ca_request_p) { + return TRUSTY_ERR_NO_MEMORY; + } + *ca_request_size_p = kMaxCaRequestSize; + int rc = trusty_send_raw_buffer(KM_ATAP_GET_CA_REQUEST, operation_start, + operation_start_size, *ca_request_p, + ca_request_size_p); + if (rc != TRUSTY_ERR_NONE) { + trusty_free(*ca_request_p); + } + return rc; +} + +int trusty_atap_set_ca_response(const uint8_t *ca_response, + uint32_t ca_response_size) +{ + struct km_set_ca_response_begin_req begin_req; + int rc = TRUSTY_ERR_GENERIC; + uint32_t bytes_sent = 0, send_size = 0; + + /* Tell the Trusty Keymaster TA the size of CA Response message */ + begin_req.ca_response_size = ca_response_size; + rc = km_do_tipc(KM_ATAP_SET_CA_RESPONSE_BEGIN, &begin_req, + sizeof(begin_req), NULL, NULL); + if (rc != TRUSTY_ERR_NONE) { + return rc; + } + + /* Send the CA Response message in chunks */ + while (bytes_sent < ca_response_size) { + send_size = MIN(kMaxSendSize, ca_response_size - bytes_sent); + rc = trusty_send_raw_buffer(KM_ATAP_SET_CA_RESPONSE_UPDATE, + ca_response + bytes_sent, send_size, + NULL, NULL); + if (rc != TRUSTY_ERR_NONE) { + return rc; + } + bytes_sent += send_size; + } + + /* Tell Trusty Keymaster to parse the CA Response message */ + return km_do_tipc(KM_ATAP_SET_CA_RESPONSE_FINISH, NULL, 0, NULL, NULL); +} + + +int trusty_atap_read_uuid_str(char **uuid_p) +{ + *uuid_p = (char*) trusty_calloc(1, kUuidSize); + + uint32_t response_size = kUuidSize; + int rc = km_do_tipc(KM_ATAP_READ_UUID, NULL, 0, *uuid_p, + &response_size); + if (rc < 0) { + trusty_error("failed to read uuid: %d\n", rc); + trusty_free(*uuid_p); + return rc; + } + if (response_size != kUuidSize) { + trusty_error("keymaster returned wrong uuid size: %d\n", response_size); + trusty_free(*uuid_p); + rc = TRUSTY_ERR_GENERIC; + } + return rc; +} diff --git a/lib/trusty/ql-tipc/keymaster_serializable.c b/lib/trusty/ql-tipc/keymaster_serializable.c new file mode 100644 index 0000000000..65bcca0545 --- /dev/null +++ b/lib/trusty/ql-tipc/keymaster_serializable.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +uint8_t *append_to_buf(uint8_t *buf, const void *data, size_t data_len) +{ + if (data && data_len) { + trusty_memcpy(buf, data, data_len); + } + return buf + data_len; +} + +uint8_t *append_uint32_to_buf(uint8_t *buf, uint32_t val) +{ + return append_to_buf(buf, &val, sizeof(val)); +} + +uint8_t *append_sized_buf_to_buf(uint8_t *buf, const uint8_t *data, + uint32_t data_len) +{ + buf = append_uint32_to_buf(buf, data_len); + return append_to_buf(buf, data, data_len); +} + +int km_boot_params_serialize(const struct km_boot_params *params, uint8_t** out, + uint32_t *out_size) +{ + uint8_t *tmp; + + if (!out || !params || !out_size) { + return TRUSTY_ERR_INVALID_ARGS; + } + *out_size = (sizeof(params->os_version) + sizeof(params->os_patchlevel) + + sizeof(params->device_locked) + + sizeof(params->verified_boot_state) + + sizeof(params->verified_boot_key_hash_size) + + sizeof(params->verified_boot_hash_size) + + params->verified_boot_key_hash_size + + params->verified_boot_hash_size); + *out = trusty_calloc(*out_size, 1); + if (!*out) { + return TRUSTY_ERR_NO_MEMORY; + } + + tmp = append_uint32_to_buf(*out, params->os_version); + tmp = append_uint32_to_buf(tmp, params->os_patchlevel); + tmp = append_uint32_to_buf(tmp, params->device_locked); + tmp = append_uint32_to_buf(tmp, params->verified_boot_state); + tmp = append_sized_buf_to_buf(tmp, params->verified_boot_key_hash, + params->verified_boot_key_hash_size); + tmp = append_sized_buf_to_buf(tmp, params->verified_boot_hash, + params->verified_boot_hash_size); + + return TRUSTY_ERR_NONE; +} + +int km_attestation_data_serialize(const struct km_attestation_data *data, + uint8_t** out, uint32_t *out_size) +{ + uint8_t *tmp; + + if (!out || !data || !out_size) { + return TRUSTY_ERR_INVALID_ARGS; + } + *out_size = (sizeof(data->algorithm) + sizeof(data->data_size) + + data->data_size); + *out = trusty_calloc(*out_size, 1); + if (!*out) { + return TRUSTY_ERR_NO_MEMORY; + } + + tmp = append_uint32_to_buf(*out, data->algorithm); + tmp = append_sized_buf_to_buf(tmp, data->data, data->data_size); + + return TRUSTY_ERR_NONE; +} + +int km_raw_buffer_serialize(const struct km_raw_buffer *buf, uint8_t** out, + uint32_t *out_size) +{ + if (!out || !buf || !out_size) { + return TRUSTY_ERR_INVALID_ARGS; + } + *out_size = sizeof(buf->data_size) + buf->data_size; + *out = trusty_calloc(*out_size, 1); + if (!*out) { + return TRUSTY_ERR_NO_MEMORY; + } + append_sized_buf_to_buf(*out, buf->data, buf->data_size); + + return TRUSTY_ERR_NONE; +} diff --git a/lib/trusty/ql-tipc/libtipc.c b/lib/trusty/ql-tipc/libtipc.c new file mode 100644 index 0000000000..30d4bbf854 --- /dev/null +++ b/lib/trusty/ql-tipc/libtipc.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * Copyright NXP 2018 + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_LOG 0 + +typedef uintptr_t vaddr_t; + +static struct trusty_ipc_dev *_ipc_dev; +static struct trusty_dev _tdev; /* There should only be one trusty device */ +static void *rpmb_ctx; +#ifndef CONFIG_AVB_ATX +bool rpmbkey_is_set(void); +#endif + +void rpmb_storage_put_ctx(void *dev); +void trusty_ipc_shutdown(void) +{ + (void)rpmb_storage_proxy_shutdown(_ipc_dev); + (void)rpmb_storage_put_ctx(rpmb_ctx); + + (void)avb_tipc_shutdown(_ipc_dev); + (void)km_tipc_shutdown(_ipc_dev); + +#ifndef CONFIG_AVB_ATX + (void)hwcrypto_tipc_shutdown(_ipc_dev); +#endif + + /* shutdown Trusty IPC device */ + (void)trusty_ipc_dev_shutdown(_ipc_dev); + + /* shutdown Trusty device */ + (void)trusty_dev_shutdown(&_tdev); +} + +int trusty_ipc_init(void) +{ + int rc; + /* init Trusty device */ + trusty_info("Initializing Trusty device\n"); + rc = trusty_dev_init(&_tdev, NULL); + if (rc != 0) { + trusty_error("Initializing Trusty device failed (%d)\n", rc); + return rc; + } + + /* create Trusty IPC device */ + trusty_info("Initializing Trusty IPC device\n"); + rc = trusty_ipc_dev_create(&_ipc_dev, &_tdev, PAGE_SIZE); + if (rc != 0) { + trusty_error("Initializing Trusty IPC device failed (%d)\n", rc); + return rc; + } + + /* get storage rpmb */ + rpmb_ctx = rpmb_storage_get_ctx(); + + /* start secure storage proxy service */ + trusty_info("Initializing RPMB storage proxy service\n"); + rc = rpmb_storage_proxy_init(_ipc_dev, rpmb_ctx); + if (rc != 0) { + trusty_error("Initlializing RPMB storage proxy service failed (%d)\n", + rc); +#ifndef CONFIG_AVB_ATX + /* check if rpmb key has been fused. */ + if(rpmbkey_is_set()) { + /* Go to hang if the key has been destroyed. */ + trusty_error("RPMB key was destroyed!\n"); + hang(); + } +#else + return rc; +#endif + } else { + /* secure storage service init ok, use trusty backed keystore */ + env_set("keystore", "trusty"); + + trusty_info("Initializing Trusty AVB client\n"); + rc = avb_tipc_init(_ipc_dev); + if (rc != 0) { + trusty_error("Initlializing Trusty AVB client failed (%d)\n", rc); + return rc; + } + + trusty_info("Initializing Trusty Keymaster client\n"); + rc = km_tipc_init(_ipc_dev); + if (rc != 0) { + trusty_error("Initlializing Trusty Keymaster client failed (%d)\n", rc); + return rc; + } + } + +#ifndef CONFIG_AVB_ATX + trusty_info("Initializing Trusty Hardware Crypto client\n"); + rc = hwcrypto_tipc_init(_ipc_dev); + if (rc != 0) { + trusty_error("Initlializing Trusty Keymaster client failed (%d)\n", rc); + return rc; + } +#endif + + return TRUSTY_ERR_NONE; +} diff --git a/lib/trusty/ql-tipc/rpmb_proxy.c b/lib/trusty/ql-tipc/rpmb_proxy.c new file mode 100644 index 0000000000..2d5ca94f49 --- /dev/null +++ b/lib/trusty/ql-tipc/rpmb_proxy.c @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include + +#define LOCAL_LOG 0 + +static bool initialized; +/* Address of rpmb device */ +static void *proxy_rpmb; +struct trusty_ipc_chan proxy_chan; + +struct storage_msg req_msg; +static uint8_t req_buf[4096]; +static uint8_t read_buf[4096]; + +/* + * Read RPMB request from storage service. Writes message to @msg + * and @req. + * + * @chan: proxy ipc channel + * @msg: address of storage message header + * @req: address of storage message request + * @req_len: length of req in bytes + */ +static int proxy_read_request(struct trusty_ipc_chan *chan, + struct storage_msg *msg, void *req, + size_t req_len) +{ + int rc; + + struct trusty_ipc_iovec req_iovs[2] = { + { .base = msg, .len = sizeof(*msg) }, + { .base = req, .len = req_len }, + }; + rc = trusty_ipc_recv(chan, req_iovs, 2, false); + if (rc < 0) { + /* recv message failed */ + trusty_error("%s: failed (%d) to recv request\n", __func__, rc); + return rc; + } + + if ((size_t)rc < sizeof(*msg)) { + /* malformed message */ + trusty_error("%s: malformed request (%zu)\n", __func__, (size_t)rc); + return TRUSTY_ERR_GENERIC; + } + + return rc - sizeof(*msg); /* return payload size */ +} + +/* + * Send RPMB response to storage service + * + * @chan: proxy ipc channel + * @msg: address of storage message header + * @resp: address of storage message response + * @resp_len: length of resp in bytes + */ +static int proxy_send_response(struct trusty_ipc_chan *chan, + struct storage_msg *msg, void *resp, + size_t resp_len) +{ + struct trusty_ipc_iovec resp_iovs[2] = { + { .base = msg, .len = sizeof(*msg) }, + { .base = resp, .len = resp_len } + }; + + msg->cmd |= STORAGE_RESP_BIT; + return trusty_ipc_send(chan, resp_iovs, resp ? 2 : 1, false); +} + +/* + * Executes the RPMB request at @r, sends response to storage service. + * + * @chan: proxy ipc channel + * @msg: address of storage message header + * @r: address of storage message request + * @req_len: length of resp in bytes + */ +static int proxy_handle_rpmb(struct trusty_ipc_chan *chan, + struct storage_msg *msg, const void *r, + size_t req_len) +{ + int rc; + size_t exp_len; + const void *write_data = NULL; + const void *rel_write_data = NULL; + const struct storage_rpmb_send_req *req = r; + + if (req_len < sizeof(req)) { + msg->result = STORAGE_ERR_NOT_VALID; + goto err_response; + } + + exp_len = sizeof(*req) + req->reliable_write_size + req->write_size; + if (req_len != exp_len) { + trusty_error( + "%s: malformed rpmb request: invalid length (%zu != %zu)\n", + __func__, req_len, exp_len); + msg->result = STORAGE_ERR_NOT_VALID; + goto err_response; + } + + if (req->reliable_write_size) { + if ((req->reliable_write_size % MMC_BLOCK_SIZE) != 0) { + trusty_error("%s: invalid reliable write size %u\n", __func__, + req->reliable_write_size); + msg->result = STORAGE_ERR_NOT_VALID; + goto err_response; + } + rel_write_data = req->payload; + } + + if (req->write_size) { + if ((req->write_size % MMC_BLOCK_SIZE) != 0) { + trusty_error("%: invalid write size %u\n", __func__, + req->write_size); + msg->result = STORAGE_ERR_NOT_VALID; + goto err_response; + } + write_data = req->payload + req->reliable_write_size; + } + + if (req->read_size) { + if (req->read_size % MMC_BLOCK_SIZE != 0 || + req->read_size > sizeof(read_buf)) { + trusty_error("%s: invalid read size %u\n", __func__, + req->read_size); + msg->result = STORAGE_ERR_NOT_VALID; + goto err_response; + } + } + + /* execute rpmb command */ + rc = rpmb_storage_send(proxy_rpmb, + rel_write_data, req->reliable_write_size, + write_data, req->write_size, + read_buf, req->read_size); + if (rc) { + trusty_error("%s: rpmb_storage_send failed: %d\n", __func__, rc); + msg->result = STORAGE_ERR_GENERIC; + goto err_response; + } + + if (msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) { + /* + * Nothing todo for post msg commit request as MMC_IOC_MULTI_CMD + * is fully synchronous in this implementation. + */ + } + + msg->result = STORAGE_NO_ERROR; + return proxy_send_response(chan, msg, read_buf, req->read_size); + +err_response: + return proxy_send_response(chan, msg, NULL, 0); +} + +/* + * Handles storage request. + * + * @chan: proxy ipc channel + * @msg: address of storage message header + * @req: address of storage message request + * @req_len: length of resp in bytes + */ +static int proxy_handle_req(struct trusty_ipc_chan *chan, + struct storage_msg *msg, const void *req, + size_t req_len) +{ + int rc; + + if (msg->flags & STORAGE_MSG_FLAG_PRE_COMMIT) { + /* nothing to do */ + } + + switch (msg->cmd) { + case STORAGE_RPMB_SEND: + rc = proxy_handle_rpmb(chan, msg, req, req_len); + break; + + case STORAGE_FILE_DELETE: + case STORAGE_FILE_OPEN: + case STORAGE_FILE_CLOSE: + case STORAGE_FILE_WRITE: + case STORAGE_FILE_READ: + case STORAGE_FILE_GET_SIZE: + case STORAGE_FILE_SET_SIZE: + /* Bulk filesystem is not supported */ + msg->result = STORAGE_ERR_UNIMPLEMENTED; + rc = proxy_send_response(chan, msg, NULL, 0); + break; + + default: + msg->result = STORAGE_ERR_UNIMPLEMENTED; + rc = proxy_send_response(chan, msg, NULL, 0); + } + + return rc; +} + +/* + * Invalidates @chan on hangup event + * + * @chan: proxy ipc channel + */ +static int proxy_on_disconnect(struct trusty_ipc_chan *chan) +{ + trusty_assert(chan); + + trusty_debug("%s: closed by peer\n", __func__); + chan->handle = INVALID_IPC_HANDLE; + return TRUSTY_EVENT_HANDLED; +} + +/* + * Handles received storage message on message event + * + * @chan: proxy ipc channel + */ +static int proxy_on_message(struct trusty_ipc_chan *chan) +{ + int rc; + + trusty_assert(chan); + + /* read request */ + rc = proxy_read_request(chan, &req_msg, req_buf, sizeof(req_buf)); + if (rc < 0) { + trusty_error("%s: failed (%d) to read request\n", __func__, rc); + trusty_ipc_close(chan); + return rc; + } + + /* handle it and send reply */ + rc = proxy_handle_req(chan, &req_msg, req_buf, rc); + if (rc < 0) { + trusty_error("%s: failed (%d) to handle request\n", __func__, rc); + trusty_ipc_close(chan); + return rc; + } + + return TRUSTY_EVENT_HANDLED; +} + +static struct trusty_ipc_ops proxy_ops = { + .on_message = proxy_on_message, + .on_disconnect = proxy_on_disconnect, +}; + +/* + * Initialize RPMB storage proxy + */ +int rpmb_storage_proxy_init(struct trusty_ipc_dev *dev, void *rpmb_dev) +{ + int rc; + + trusty_assert(dev); + trusty_assert(!initialized); + + /* attach rpmb device */ + proxy_rpmb = rpmb_dev; + + /* init ipc channel */ + trusty_ipc_chan_init(&proxy_chan, dev); + + /* connect to proxy service and wait for connect to complete */ + rc = trusty_ipc_connect(&proxy_chan, STORAGE_DISK_PROXY_PORT, true); + if (rc < 0) { + trusty_error("%s: failed (%d) to connect to '%s'\n", __func__, rc, + STORAGE_DISK_PROXY_PORT); + return rc; + } + + /* override default ops */ + proxy_chan.ops = &proxy_ops; + + do { + /* Check for RPMB events */ + rc = trusty_ipc_poll_for_event(proxy_chan.dev); + if (rc < 0) { + trusty_error("%s: failed (%d) to get rpmb event\n", __func__, rc); + return rc; + } + + if (proxy_chan.handle == INVALID_IPC_HANDLE) { + trusty_error("%s: unexpected proxy channel close\n", __func__); + return TRUSTY_ERR_CHANNEL_CLOSED; + } + } + while (rc != TRUSTY_EVENT_NONE); + + /* mark as initialized */ + initialized = true; + + return TRUSTY_ERR_NONE; +} + +void rpmb_storage_proxy_shutdown(struct trusty_ipc_dev *dev) +{ + trusty_assert(initialized); + + /* close channel */ + trusty_ipc_close(&proxy_chan); + + initialized = false; +} diff --git a/lib/trusty/ql-tipc/sysdeps/Makefile b/lib/trusty/ql-tipc/sysdeps/Makefile new file mode 100644 index 0000000000..f9b19d05cc --- /dev/null +++ b/lib/trusty/ql-tipc/sysdeps/Makefile @@ -0,0 +1,46 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +# Sample Makefile for U-boot + +#ccflags-y += -DTIPC_ENABLE_DEBUG + +TRUSTY_DIR = lib/trusty +#ccflags-y += -I$(TRUSTY_DIR)/ql-tipc/include +ccflags-y += -I$(TRUSTY_DIR)/interface/include + +QL_TIPC = ../ +obj-y += \ + $(QL_TIPC)/avb.o \ + $(QL_TIPC)/keymaster.o \ + $(QL_TIPC)/ipc.o \ + $(QL_TIPC)/ipc_dev.o \ + $(QL_TIPC)/libtipc.o \ + $(QL_TIPC)/rpmb_proxy.o \ + sysdeps_uboot.o \ + storage_ops_uboot.o + +obj-$(CONFIG_ARM) += \ + $(QL_TIPC)/arch/arm/trusty_mem.o \ + $(QL_TIPC)/arch/arm/trusty_dev.o diff --git a/lib/trusty/ql-tipc/sysdeps/storage_ops_uboot.c b/lib/trusty/ql-tipc/sysdeps/storage_ops_uboot.c new file mode 100644 index 0000000000..934286cb69 --- /dev/null +++ b/lib/trusty/ql-tipc/sysdeps/storage_ops_uboot.c @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include +#include +#include + +void *rpmb_storage_get_ctx(void) +{ + /* Unused for U-boot */ + return NULL; +} + +void rpmb_storage_put_ctx(void *dev) +{ +} + +int rpmb_storage_send(void *rpmb_dev, const void *rel_write_data, + size_t rel_write_size, const void *write_data, + size_t write_size, void *read_buf, size_t read_size) +{ + ALLOC_CACHE_ALIGN_BUFFER(uint8_t, rpmb_rel_write_data, rel_write_size); + ALLOC_CACHE_ALIGN_BUFFER(uint8_t, rpmb_write_data, write_size); + ALLOC_CACHE_ALIGN_BUFFER(uint8_t, rpmb_read_data, read_size); + int ret = TRUSTY_ERR_NONE; + struct mmc *mmc = find_mmc_device(mmc_get_env_dev()); + if (!mmc) { + trusty_error("failed to get mmc device.\n"); + return -1; + } + struct blk_desc *desc = mmc_get_blk_desc(mmc); + if (!desc) { + trusty_error("failed to get mmc desc.\n"); + return -1; + } + char original_part = desc->hwpart; + + /* Switch to RPMB partition */ + if (desc->hwpart != MMC_PART_RPMB) { + ret = mmc_switch_part(mmc, MMC_PART_RPMB); + if (ret) { + trusty_error("failed to switch to RPMB partition\n"); + ret = TRUSTY_ERR_GENERIC; + goto end; + } + desc->hwpart = MMC_PART_RPMB; + } + + if (rel_write_size) { + if (rel_write_size % MMC_BLOCK_SIZE) { + trusty_error( + "rel_write_size is not a multiple of MMC_BLOCK_SIZE: %d\n", + rel_write_size); + ret = TRUSTY_ERR_INVALID_ARGS; + goto end; + } + trusty_memcpy(rpmb_rel_write_data, rel_write_data, rel_write_size); + ret = mmc_rpmb_request(mmc, + (const struct s_rpmb *)rpmb_rel_write_data, + rel_write_size / MMC_BLOCK_SIZE, true); + if (ret) { + trusty_error("failed to execute rpmb reliable write\n"); + goto end; + } + } + if (write_size) { + if (write_size % MMC_BLOCK_SIZE) { + trusty_error("write_size is not a multiple of MMC_BLOCK_SIZE: %d\n", + write_size); + ret = TRUSTY_ERR_INVALID_ARGS; + goto end; + } + trusty_memcpy(rpmb_write_data, write_data, write_size); + ret = mmc_rpmb_request(mmc, (const struct s_rpmb *)rpmb_write_data, + write_size / MMC_BLOCK_SIZE, false); + if (ret) { + trusty_error("failed to execute rpmb write\n"); + goto end; + } + } + if (read_size) { + if (read_size % MMC_BLOCK_SIZE) { + trusty_error("read_size is not a multiple of MMC_BLOCK_SIZE: %d\n", + read_size); + ret = TRUSTY_ERR_INVALID_ARGS; + goto end; + } + ret = mmc_rpmb_response(mmc, (struct s_rpmb *)rpmb_read_data, + read_size / MMC_BLOCK_SIZE, 0); + trusty_memcpy((void *)read_buf, rpmb_read_data, read_size); + if (ret < 0) { + trusty_error("failed to execute rpmb read\n"); + } + } + +end: + /* Return to original partition */ + if (desc->hwpart != original_part) { + if (mmc_switch_part(mmc, original_part) != 0) { + trusty_error("failed to switch back to original partition\n"); + return TRUSTY_ERR_GENERIC; + } + desc->hwpart = original_part; + } + return ret; +} diff --git a/lib/trusty/ql-tipc/sysdeps/sysdeps_uboot.c b/lib/trusty/ql-tipc/sysdeps/sysdeps_uboot.c new file mode 100644 index 0000000000..b42cd20d4f --- /dev/null +++ b/lib/trusty/ql-tipc/sysdeps/sysdeps_uboot.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include +#include +#include + +extern int trusty_encode_page_info(struct ns_mem_page_info *page_info, + void *vaddr); + +void trusty_lock(struct trusty_dev *dev) +{ +} +void trusty_unlock(struct trusty_dev *dev) +{ +} + +void trusty_local_irq_disable(unsigned long *state) +{ + disable_interrupts(); +} + +void trusty_local_irq_restore(unsigned long *state) +{ + enable_interrupts(); +} + +void trusty_idle(struct trusty_dev *dev) +{ + wfi(); +} + +void trusty_abort(void) +{ + do_reset(NULL, 0, 0, NULL); + __builtin_unreachable(); +} + +void trusty_printf(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vprintf(format, ap); + va_end(ap); +} + +void *trusty_memcpy(void *dest, const void *src, size_t n) +{ + return memcpy(dest, src, n); +} + +void *trusty_memset(void *dest, const int c, size_t n) +{ + return memset(dest, c, n); +} + +char *trusty_strcpy(char *dest, const char *src) +{ + return strcpy(dest, src); +} + +size_t trusty_strlen(const char *str) +{ + return strlen(str); +} + +void *trusty_calloc(size_t n, size_t size) +{ + return calloc(n, size); +} + +void trusty_free(void *addr) +{ + if (addr) + free(addr); +} + +void *trusty_alloc_pages(unsigned count) +{ + return memalign(PAGE_SIZE, count * PAGE_SIZE); +} + +void trusty_free_pages(void *va, unsigned count) +{ + if (va) + free(va); +} diff --git a/lib/trusty/ql-tipc/util.c b/lib/trusty/ql-tipc/util.c new file mode 100644 index 0000000000..89ea855ba2 --- /dev/null +++ b/lib/trusty/ql-tipc/util.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +const char* trusty_basename(const char* str) { + int64_t n; + size_t len; + + len = trusty_strlen(str); + if (len >= 2) { + for (n = len - 2; n >= 0; n--) { + if (str[n] == '/') { + return str + n + 1; + } + } + } + return str; +}