| /** |
| * Copyright (c) 2011 Trusted Logic S.A. |
| * All Rights Reserved. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * version 2 as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| * MA 02111-1307 USA |
| */ |
| |
| #include <linux/mman.h> |
| #include "tf_util.h" |
| |
| /*---------------------------------------------------------------------------- |
| * Debug printing routines |
| *----------------------------------------------------------------------------*/ |
| #ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT |
| |
| void address_cache_property(unsigned long va) |
| { |
| unsigned long pa; |
| unsigned long inner; |
| unsigned long outer; |
| |
| asm volatile ("mcr p15, 0, %0, c7, c8, 0" : : "r" (va)); |
| asm volatile ("mrc p15, 0, %0, c7, c4, 0" : "=r" (pa)); |
| |
| dprintk(KERN_INFO "VA:%x, PA:%x\n", |
| (unsigned int) va, |
| (unsigned int) pa); |
| |
| if (pa & 1) { |
| dprintk(KERN_INFO "Prop Error\n"); |
| return; |
| } |
| |
| outer = (pa >> 2) & 3; |
| dprintk(KERN_INFO "\touter : %x", (unsigned int) outer); |
| |
| switch (outer) { |
| case 3: |
| dprintk(KERN_INFO "Write-Back, no Write-Allocate\n"); |
| break; |
| case 2: |
| dprintk(KERN_INFO "Write-Through, no Write-Allocate.\n"); |
| break; |
| case 1: |
| dprintk(KERN_INFO "Write-Back, Write-Allocate.\n"); |
| break; |
| case 0: |
| dprintk(KERN_INFO "Non-cacheable.\n"); |
| break; |
| } |
| |
| inner = (pa >> 4) & 7; |
| dprintk(KERN_INFO "\tinner : %x", (unsigned int)inner); |
| |
| switch (inner) { |
| case 7: |
| dprintk(KERN_INFO "Write-Back, no Write-Allocate\n"); |
| break; |
| case 6: |
| dprintk(KERN_INFO "Write-Through.\n"); |
| break; |
| case 5: |
| dprintk(KERN_INFO "Write-Back, Write-Allocate.\n"); |
| break; |
| case 3: |
| dprintk(KERN_INFO "Device.\n"); |
| break; |
| case 1: |
| dprintk(KERN_INFO "Strongly-ordered.\n"); |
| break; |
| case 0: |
| dprintk(KERN_INFO "Non-cacheable.\n"); |
| break; |
| } |
| |
| if (pa & 0x00000002) |
| dprintk(KERN_INFO "SuperSection.\n"); |
| if (pa & 0x00000080) |
| dprintk(KERN_INFO "Memory is shareable.\n"); |
| else |
| dprintk(KERN_INFO "Memory is non-shareable.\n"); |
| |
| if (pa & 0x00000200) |
| dprintk(KERN_INFO "Non-secure.\n"); |
| } |
| |
| #ifdef CONFIG_BENCH_SECURE_CYCLE |
| |
| #define LOOP_SIZE (100000) |
| |
| void run_bogo_mips(void) |
| { |
| uint32_t cycles; |
| void *address = &run_bogo_mips; |
| |
| dprintk(KERN_INFO "BogoMIPS:\n"); |
| |
| setup_counters(); |
| cycles = run_code_speed(LOOP_SIZE); |
| dprintk(KERN_INFO "%u cycles with code access\n", cycles); |
| cycles = run_data_speed(LOOP_SIZE, (unsigned long)address); |
| dprintk(KERN_INFO "%u cycles to access %x\n", cycles, |
| (unsigned int) address); |
| } |
| |
| #endif /* CONFIG_BENCH_SECURE_CYCLE */ |
| |
| /* |
| * Dump the L1 shared buffer. |
| */ |
| void tf_dump_l1_shared_buffer(struct tf_l1_shared_buffer *buffer) |
| { |
| dprintk(KERN_INFO |
| "buffer@%p:\n" |
| " config_flag_s=%08X\n" |
| " version_description=%64s\n" |
| " status_s=%08X\n" |
| " sync_serial_n=%08X\n" |
| " sync_serial_s=%08X\n" |
| " time_n[0]=%016llX\n" |
| " time_n[1]=%016llX\n" |
| " timeout_s[0]=%016llX\n" |
| " timeout_s[1]=%016llX\n" |
| " first_command=%08X\n" |
| " first_free_command=%08X\n" |
| " first_answer=%08X\n" |
| " first_free_answer=%08X\n\n", |
| buffer, |
| buffer->config_flag_s, |
| buffer->version_description, |
| buffer->status_s, |
| buffer->sync_serial_n, |
| buffer->sync_serial_s, |
| buffer->time_n[0], |
| buffer->time_n[1], |
| buffer->timeout_s[0], |
| buffer->timeout_s[1], |
| buffer->first_command, |
| buffer->first_free_command, |
| buffer->first_answer, |
| buffer->first_free_answer); |
| } |
| |
| |
| /* |
| * Dump the specified SChannel message using dprintk. |
| */ |
| void tf_dump_command(union tf_command *command) |
| { |
| u32 i; |
| |
| dprintk(KERN_INFO "message@%p:\n", command); |
| |
| switch (command->header.message_type) { |
| case TF_MESSAGE_TYPE_CREATE_DEVICE_CONTEXT: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "TF_MESSAGE_TYPE_CREATE_DEVICE_CONTEXT\n" |
| " operation_id = 0x%08X\n" |
| " device_context_id = 0x%08X\n", |
| command->header.message_size, |
| command->header.message_type, |
| command->header.operation_id, |
| command->create_device_context.device_context_id |
| ); |
| break; |
| |
| case TF_MESSAGE_TYPE_DESTROY_DEVICE_CONTEXT: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "TF_MESSAGE_TYPE_DESTROY_DEVICE_CONTEXT\n" |
| " operation_id = 0x%08X\n" |
| " device_context = 0x%08X\n", |
| command->header.message_size, |
| command->header.message_type, |
| command->header.operation_id, |
| command->destroy_device_context.device_context); |
| break; |
| |
| case TF_MESSAGE_TYPE_OPEN_CLIENT_SESSION: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "TF_MESSAGE_TYPE_OPEN_CLIENT_SESSION\n" |
| " param_types = 0x%04X\n" |
| " operation_id = 0x%08X\n" |
| " device_context = 0x%08X\n" |
| " cancellation_id = 0x%08X\n" |
| " timeout = 0x%016llX\n" |
| " destination_uuid = " |
| "%08X-%04X-%04X-%02X%02X-" |
| "%02X%02X%02X%02X%02X%02X\n", |
| command->header.message_size, |
| command->header.message_type, |
| command->open_client_session.param_types, |
| command->header.operation_id, |
| command->open_client_session.device_context, |
| command->open_client_session.cancellation_id, |
| command->open_client_session.timeout, |
| command->open_client_session.destination_uuid. |
| time_low, |
| command->open_client_session.destination_uuid. |
| time_mid, |
| command->open_client_session.destination_uuid. |
| time_hi_and_version, |
| command->open_client_session.destination_uuid. |
| clock_seq_and_node[0], |
| command->open_client_session.destination_uuid. |
| clock_seq_and_node[1], |
| command->open_client_session.destination_uuid. |
| clock_seq_and_node[2], |
| command->open_client_session.destination_uuid. |
| clock_seq_and_node[3], |
| command->open_client_session.destination_uuid. |
| clock_seq_and_node[4], |
| command->open_client_session.destination_uuid. |
| clock_seq_and_node[5], |
| command->open_client_session.destination_uuid. |
| clock_seq_and_node[6], |
| command->open_client_session.destination_uuid. |
| clock_seq_and_node[7] |
| ); |
| |
| for (i = 0; i < 4; i++) { |
| uint32_t *param = (uint32_t *) &command-> |
| open_client_session.params[i]; |
| dprintk(KERN_INFO " params[%d] = " |
| "0x%08X:0x%08X:0x%08X\n", |
| i, param[0], param[1], param[2]); |
| } |
| |
| switch (TF_LOGIN_GET_MAIN_TYPE( |
| command->open_client_session.login_type)) { |
| case TF_LOGIN_PUBLIC: |
| dprintk( |
| KERN_INFO " login_type = " |
| "TF_LOGIN_PUBLIC\n"); |
| break; |
| case TF_LOGIN_USER: |
| dprintk( |
| KERN_INFO " login_type = " |
| "TF_LOGIN_USER\n"); |
| break; |
| case TF_LOGIN_GROUP: |
| dprintk( |
| KERN_INFO " login_type = " |
| "TF_LOGIN_GROUP\n"); |
| break; |
| case TF_LOGIN_APPLICATION: |
| dprintk( |
| KERN_INFO " login_type = " |
| "TF_LOGIN_APPLICATION\n"); |
| break; |
| case TF_LOGIN_APPLICATION_USER: |
| dprintk( |
| KERN_INFO " login_type = " |
| "TF_LOGIN_APPLICATION_USER\n"); |
| break; |
| case TF_LOGIN_APPLICATION_GROUP: |
| dprintk( |
| KERN_INFO " login_type = " |
| "TF_LOGIN_APPLICATION_GROUP\n"); |
| break; |
| case TF_LOGIN_AUTHENTICATION: |
| dprintk( |
| KERN_INFO " login_type = " |
| "TF_LOGIN_AUTHENTICATION\n"); |
| break; |
| case TF_LOGIN_PRIVILEGED: |
| dprintk( |
| KERN_INFO " login_type = " |
| "TF_LOGIN_PRIVILEGED\n"); |
| break; |
| case TF_LOGIN_PRIVILEGED_KERNEL: |
| dprintk( |
| KERN_INFO " login_type = " |
| "TF_LOGIN_PRIVILEGED_KERNEL\n"); |
| break; |
| default: |
| dprintk( |
| KERN_ERR " login_type = " |
| "0x%08X (Unknown login type)\n", |
| command->open_client_session.login_type); |
| break; |
| } |
| |
| dprintk( |
| KERN_INFO " login_data = "); |
| for (i = 0; i < 20; i++) |
| dprintk( |
| KERN_INFO "%d", |
| command->open_client_session. |
| login_data[i]); |
| dprintk("\n"); |
| break; |
| |
| case TF_MESSAGE_TYPE_CLOSE_CLIENT_SESSION: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "TF_MESSAGE_TYPE_CLOSE_CLIENT_SESSION\n" |
| " operation_id = 0x%08X\n" |
| " device_context = 0x%08X\n" |
| " client_session = 0x%08X\n", |
| command->header.message_size, |
| command->header.message_type, |
| command->header.operation_id, |
| command->close_client_session.device_context, |
| command->close_client_session.client_session |
| ); |
| break; |
| |
| case TF_MESSAGE_TYPE_REGISTER_SHARED_MEMORY: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "TF_MESSAGE_TYPE_REGISTER_SHARED_MEMORY\n" |
| " memory_flags = 0x%04X\n" |
| " operation_id = 0x%08X\n" |
| " device_context = 0x%08X\n" |
| " block_id = 0x%08X\n" |
| " shared_mem_size = 0x%08X\n" |
| " shared_mem_start_offset = 0x%08X\n" |
| " shared_mem_descriptors[0] = 0x%08X\n" |
| " shared_mem_descriptors[1] = 0x%08X\n" |
| " shared_mem_descriptors[2] = 0x%08X\n" |
| " shared_mem_descriptors[3] = 0x%08X\n" |
| " shared_mem_descriptors[4] = 0x%08X\n" |
| " shared_mem_descriptors[5] = 0x%08X\n" |
| " shared_mem_descriptors[6] = 0x%08X\n" |
| " shared_mem_descriptors[7] = 0x%08X\n", |
| command->header.message_size, |
| command->header.message_type, |
| command->register_shared_memory.memory_flags, |
| command->header.operation_id, |
| command->register_shared_memory.device_context, |
| command->register_shared_memory.block_id, |
| command->register_shared_memory.shared_mem_size, |
| command->register_shared_memory. |
| shared_mem_start_offset, |
| command->register_shared_memory. |
| shared_mem_descriptors[0], |
| command->register_shared_memory. |
| shared_mem_descriptors[1], |
| command->register_shared_memory. |
| shared_mem_descriptors[2], |
| command->register_shared_memory. |
| shared_mem_descriptors[3], |
| command->register_shared_memory. |
| shared_mem_descriptors[4], |
| command->register_shared_memory. |
| shared_mem_descriptors[5], |
| command->register_shared_memory. |
| shared_mem_descriptors[6], |
| command->register_shared_memory. |
| shared_mem_descriptors[7]); |
| break; |
| |
| case TF_MESSAGE_TYPE_RELEASE_SHARED_MEMORY: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "TF_MESSAGE_TYPE_RELEASE_SHARED_MEMORY\n" |
| " operation_id = 0x%08X\n" |
| " device_context = 0x%08X\n" |
| " block = 0x%08X\n", |
| command->header.message_size, |
| command->header.message_type, |
| command->header.operation_id, |
| command->release_shared_memory.device_context, |
| command->release_shared_memory.block); |
| break; |
| |
| case TF_MESSAGE_TYPE_INVOKE_CLIENT_COMMAND: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "TF_MESSAGE_TYPE_INVOKE_CLIENT_COMMAND\n" |
| " param_types = 0x%04X\n" |
| " operation_id = 0x%08X\n" |
| " device_context = 0x%08X\n" |
| " client_session = 0x%08X\n" |
| " timeout = 0x%016llX\n" |
| " cancellation_id = 0x%08X\n" |
| " client_command_identifier = 0x%08X\n", |
| command->header.message_size, |
| command->header.message_type, |
| command->invoke_client_command.param_types, |
| command->header.operation_id, |
| command->invoke_client_command.device_context, |
| command->invoke_client_command.client_session, |
| command->invoke_client_command.timeout, |
| command->invoke_client_command.cancellation_id, |
| command->invoke_client_command. |
| client_command_identifier |
| ); |
| |
| for (i = 0; i < 4; i++) { |
| uint32_t *param = (uint32_t *) &command-> |
| open_client_session.params[i]; |
| dprintk(KERN_INFO " params[%d] = " |
| "0x%08X:0x%08X:0x%08X\n", i, |
| param[0], param[1], param[2]); |
| } |
| break; |
| |
| case TF_MESSAGE_TYPE_CANCEL_CLIENT_COMMAND: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "TF_MESSAGE_TYPE_CANCEL_CLIENT_COMMAND\n" |
| " operation_id = 0x%08X\n" |
| " device_context = 0x%08X\n" |
| " client_session = 0x%08X\n", |
| command->header.message_size, |
| command->header.message_type, |
| command->header.operation_id, |
| command->cancel_client_operation.device_context, |
| command->cancel_client_operation.client_session); |
| break; |
| |
| case TF_MESSAGE_TYPE_MANAGEMENT: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "TF_MESSAGE_TYPE_MANAGEMENT\n" |
| " operation_id = 0x%08X\n" |
| " command = 0x%08X\n" |
| " w3b_size = 0x%08X\n" |
| " w3b_start_offset = 0x%08X\n", |
| command->header.message_size, |
| command->header.message_type, |
| command->header.operation_id, |
| command->management.command, |
| command->management.w3b_size, |
| command->management.w3b_start_offset); |
| break; |
| |
| default: |
| dprintk( |
| KERN_ERR " message_type = 0x%08X " |
| "(Unknown message type)\n", |
| command->header.message_type); |
| break; |
| } |
| } |
| |
| |
| /* |
| * Dump the specified SChannel answer using dprintk. |
| */ |
| void tf_dump_answer(union tf_answer *answer) |
| { |
| u32 i; |
| dprintk( |
| KERN_INFO "answer@%p:\n", |
| answer); |
| |
| switch (answer->header.message_type) { |
| case TF_MESSAGE_TYPE_CREATE_DEVICE_CONTEXT: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "tf_answer_create_device_context\n" |
| " operation_id = 0x%08X\n" |
| " error_code = 0x%08X\n" |
| " device_context = 0x%08X\n", |
| answer->header.message_size, |
| answer->header.message_type, |
| answer->header.operation_id, |
| answer->create_device_context.error_code, |
| answer->create_device_context.device_context); |
| break; |
| |
| case TF_MESSAGE_TYPE_DESTROY_DEVICE_CONTEXT: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "ANSWER_DESTROY_DEVICE_CONTEXT\n" |
| " operation_id = 0x%08X\n" |
| " error_code = 0x%08X\n" |
| " device_context_id = 0x%08X\n", |
| answer->header.message_size, |
| answer->header.message_type, |
| answer->header.operation_id, |
| answer->destroy_device_context.error_code, |
| answer->destroy_device_context.device_context_id); |
| break; |
| |
| |
| case TF_MESSAGE_TYPE_OPEN_CLIENT_SESSION: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "tf_answer_open_client_session\n" |
| " error_origin = 0x%02X\n" |
| " operation_id = 0x%08X\n" |
| " error_code = 0x%08X\n" |
| " client_session = 0x%08X\n", |
| answer->header.message_size, |
| answer->header.message_type, |
| answer->open_client_session.error_origin, |
| answer->header.operation_id, |
| answer->open_client_session.error_code, |
| answer->open_client_session.client_session); |
| for (i = 0; i < 4; i++) { |
| dprintk(KERN_INFO " answers[%d]=0x%08X:0x%08X\n", |
| i, |
| answer->open_client_session.answers[i]. |
| value.a, |
| answer->open_client_session.answers[i]. |
| value.b); |
| } |
| break; |
| |
| case TF_MESSAGE_TYPE_CLOSE_CLIENT_SESSION: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "ANSWER_CLOSE_CLIENT_SESSION\n" |
| " operation_id = 0x%08X\n" |
| " error_code = 0x%08X\n", |
| answer->header.message_size, |
| answer->header.message_type, |
| answer->header.operation_id, |
| answer->close_client_session.error_code); |
| break; |
| |
| case TF_MESSAGE_TYPE_REGISTER_SHARED_MEMORY: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "tf_answer_register_shared_memory\n" |
| " operation_id = 0x%08X\n" |
| " error_code = 0x%08X\n" |
| " block = 0x%08X\n", |
| answer->header.message_size, |
| answer->header.message_type, |
| answer->header.operation_id, |
| answer->register_shared_memory.error_code, |
| answer->register_shared_memory.block); |
| break; |
| |
| case TF_MESSAGE_TYPE_RELEASE_SHARED_MEMORY: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "ANSWER_RELEASE_SHARED_MEMORY\n" |
| " operation_id = 0x%08X\n" |
| " error_code = 0x%08X\n" |
| " block_id = 0x%08X\n", |
| answer->header.message_size, |
| answer->header.message_type, |
| answer->header.operation_id, |
| answer->release_shared_memory.error_code, |
| answer->release_shared_memory.block_id); |
| break; |
| |
| case TF_MESSAGE_TYPE_INVOKE_CLIENT_COMMAND: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "tf_answer_invoke_client_command\n" |
| " error_origin = 0x%02X\n" |
| " operation_id = 0x%08X\n" |
| " error_code = 0x%08X\n", |
| answer->header.message_size, |
| answer->header.message_type, |
| answer->invoke_client_command.error_origin, |
| answer->header.operation_id, |
| answer->invoke_client_command.error_code |
| ); |
| for (i = 0; i < 4; i++) { |
| dprintk(KERN_INFO " answers[%d]=0x%08X:0x%08X\n", |
| i, |
| answer->invoke_client_command.answers[i]. |
| value.a, |
| answer->invoke_client_command.answers[i]. |
| value.b); |
| } |
| break; |
| |
| case TF_MESSAGE_TYPE_CANCEL_CLIENT_COMMAND: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "TF_ANSWER_CANCEL_CLIENT_COMMAND\n" |
| " operation_id = 0x%08X\n" |
| " error_code = 0x%08X\n", |
| answer->header.message_size, |
| answer->header.message_type, |
| answer->header.operation_id, |
| answer->cancel_client_operation.error_code); |
| break; |
| |
| case TF_MESSAGE_TYPE_MANAGEMENT: |
| dprintk(KERN_INFO |
| " message_size = 0x%02X\n" |
| " message_type = 0x%02X " |
| "TF_MESSAGE_TYPE_MANAGEMENT\n" |
| " operation_id = 0x%08X\n" |
| " error_code = 0x%08X\n", |
| answer->header.message_size, |
| answer->header.message_type, |
| answer->header.operation_id, |
| answer->header.error_code); |
| break; |
| |
| default: |
| dprintk( |
| KERN_ERR " message_type = 0x%02X " |
| "(Unknown message type)\n", |
| answer->header.message_type); |
| break; |
| |
| } |
| } |
| |
| #endif /* defined(TF_DRIVER_DEBUG_SUPPORT) */ |
| |
| /*---------------------------------------------------------------------------- |
| * SHA-1 implementation |
| * This is taken from the Linux kernel source crypto/sha1.c |
| *----------------------------------------------------------------------------*/ |
| |
| struct sha1_ctx { |
| u64 count; |
| u32 state[5]; |
| u8 buffer[64]; |
| }; |
| |
| static inline u32 rol(u32 value, u32 bits) |
| { |
| return ((value) << (bits)) | ((value) >> (32 - (bits))); |
| } |
| |
| /* blk0() and blk() perform the initial expand. */ |
| /* I got the idea of expanding during the round function from SSLeay */ |
| #define blk0(i) block32[i] |
| |
| #define blk(i) (block32[i & 15] = rol( \ |
| block32[(i + 13) & 15] ^ block32[(i + 8) & 15] ^ \ |
| block32[(i + 2) & 15] ^ block32[i & 15], 1)) |
| |
| /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ |
| #define R0(v, w, x, y, z, i) do { \ |
| z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ |
| w = rol(w, 30); } while (0) |
| |
| #define R1(v, w, x, y, z, i) do { \ |
| z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ |
| w = rol(w, 30); } while (0) |
| |
| #define R2(v, w, x, y, z, i) do { \ |
| z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \ |
| w = rol(w, 30); } while (0) |
| |
| #define R3(v, w, x, y, z, i) do { \ |
| z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ |
| w = rol(w, 30); } while (0) |
| |
| #define R4(v, w, x, y, z, i) do { \ |
| z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ |
| w = rol(w, 30); } while (0) |
| |
| |
| /* Hash a single 512-bit block. This is the core of the algorithm. */ |
| static void sha1_transform(u32 *state, const u8 *in) |
| { |
| u32 a, b, c, d, e; |
| u32 block32[16]; |
| |
| /* convert/copy data to workspace */ |
| for (a = 0; a < sizeof(block32)/sizeof(u32); a++) |
| block32[a] = ((u32) in[4 * a]) << 24 | |
| ((u32) in[4 * a + 1]) << 16 | |
| ((u32) in[4 * a + 2]) << 8 | |
| ((u32) in[4 * a + 3]); |
| |
| /* Copy context->state[] to working vars */ |
| a = state[0]; |
| b = state[1]; |
| c = state[2]; |
| d = state[3]; |
| e = state[4]; |
| |
| /* 4 rounds of 20 operations each. Loop unrolled. */ |
| R0(a, b, c, d, e, 0); R0(e, a, b, c, d, 1); |
| R0(d, e, a, b, c, 2); R0(c, d, e, a, b, 3); |
| R0(b, c, d, e, a, 4); R0(a, b, c, d, e, 5); |
| R0(e, a, b, c, d, 6); R0(d, e, a, b, c, 7); |
| R0(c, d, e, a, b, 8); R0(b, c, d, e, a, 9); |
| R0(a, b, c, d, e, 10); R0(e, a, b, c, d, 11); |
| R0(d, e, a, b, c, 12); R0(c, d, e, a, b, 13); |
| R0(b, c, d, e, a, 14); R0(a, b, c, d, e, 15); |
| |
| R1(e, a, b, c, d, 16); R1(d, e, a, b, c, 17); |
| R1(c, d, e, a, b, 18); R1(b, c, d, e, a, 19); |
| |
| R2(a, b, c, d, e, 20); R2(e, a, b, c, d, 21); |
| R2(d, e, a, b, c, 22); R2(c, d, e, a, b, 23); |
| R2(b, c, d, e, a, 24); R2(a, b, c, d, e, 25); |
| R2(e, a, b, c, d, 26); R2(d, e, a, b, c, 27); |
| R2(c, d, e, a, b, 28); R2(b, c, d, e, a, 29); |
| R2(a, b, c, d, e, 30); R2(e, a, b, c, d, 31); |
| R2(d, e, a, b, c, 32); R2(c, d, e, a, b, 33); |
| R2(b, c, d, e, a, 34); R2(a, b, c, d, e, 35); |
| R2(e, a, b, c, d, 36); R2(d, e, a, b, c, 37); |
| R2(c, d, e, a, b, 38); R2(b, c, d, e, a, 39); |
| |
| R3(a, b, c, d, e, 40); R3(e, a, b, c, d, 41); |
| R3(d, e, a, b, c, 42); R3(c, d, e, a, b, 43); |
| R3(b, c, d, e, a, 44); R3(a, b, c, d, e, 45); |
| R3(e, a, b, c, d, 46); R3(d, e, a, b, c, 47); |
| R3(c, d, e, a, b, 48); R3(b, c, d, e, a, 49); |
| R3(a, b, c, d, e, 50); R3(e, a, b, c, d, 51); |
| R3(d, e, a, b, c, 52); R3(c, d, e, a, b, 53); |
| R3(b, c, d, e, a, 54); R3(a, b, c, d, e, 55); |
| R3(e, a, b, c, d, 56); R3(d, e, a, b, c, 57); |
| R3(c, d, e, a, b, 58); R3(b, c, d, e, a, 59); |
| |
| R4(a, b, c, d, e, 60); R4(e, a, b, c, d, 61); |
| R4(d, e, a, b, c, 62); R4(c, d, e, a, b, 63); |
| R4(b, c, d, e, a, 64); R4(a, b, c, d, e, 65); |
| R4(e, a, b, c, d, 66); R4(d, e, a, b, c, 67); |
| R4(c, d, e, a, b, 68); R4(b, c, d, e, a, 69); |
| R4(a, b, c, d, e, 70); R4(e, a, b, c, d, 71); |
| R4(d, e, a, b, c, 72); R4(c, d, e, a, b, 73); |
| R4(b, c, d, e, a, 74); R4(a, b, c, d, e, 75); |
| R4(e, a, b, c, d, 76); R4(d, e, a, b, c, 77); |
| R4(c, d, e, a, b, 78); R4(b, c, d, e, a, 79); |
| |
| /* Add the working vars back into context.state[] */ |
| state[0] += a; |
| state[1] += b; |
| state[2] += c; |
| state[3] += d; |
| state[4] += e; |
| /* Wipe variables */ |
| a = b = c = d = e = 0; |
| memset(block32, 0x00, sizeof(block32)); |
| } |
| |
| |
| static void sha1_init(void *ctx) |
| { |
| struct sha1_ctx *sctx = ctx; |
| static const struct sha1_ctx initstate = { |
| 0, |
| { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }, |
| { 0, } |
| }; |
| |
| *sctx = initstate; |
| } |
| |
| |
| static void sha1_update(void *ctx, const u8 *data, unsigned int len) |
| { |
| struct sha1_ctx *sctx = ctx; |
| unsigned int i, j; |
| |
| j = (sctx->count >> 3) & 0x3f; |
| sctx->count += len << 3; |
| |
| if ((j + len) > 63) { |
| memcpy(&sctx->buffer[j], data, (i = 64 - j)); |
| sha1_transform(sctx->state, sctx->buffer); |
| for ( ; i + 63 < len; i += 64) |
| sha1_transform(sctx->state, &data[i]); |
| j = 0; |
| } else |
| i = 0; |
| memcpy(&sctx->buffer[j], &data[i], len - i); |
| } |
| |
| |
| /* Add padding and return the message digest. */ |
| static void sha1_final(void *ctx, u8 *out) |
| { |
| struct sha1_ctx *sctx = ctx; |
| u32 i, j, index, padlen; |
| u64 t; |
| u8 bits[8] = { 0, }; |
| static const u8 padding[64] = { 0x80, }; |
| |
| t = sctx->count; |
| bits[7] = 0xff & t; t >>= 8; |
| bits[6] = 0xff & t; t >>= 8; |
| bits[5] = 0xff & t; t >>= 8; |
| bits[4] = 0xff & t; t >>= 8; |
| bits[3] = 0xff & t; t >>= 8; |
| bits[2] = 0xff & t; t >>= 8; |
| bits[1] = 0xff & t; t >>= 8; |
| bits[0] = 0xff & t; |
| |
| /* Pad out to 56 mod 64 */ |
| index = (sctx->count >> 3) & 0x3f; |
| padlen = (index < 56) ? (56 - index) : ((64+56) - index); |
| sha1_update(sctx, padding, padlen); |
| |
| /* Append length */ |
| sha1_update(sctx, bits, sizeof(bits)); |
| |
| /* Store state in digest */ |
| for (i = j = 0; i < 5; i++, j += 4) { |
| u32 t2 = sctx->state[i]; |
| out[j+3] = t2 & 0xff; t2 >>= 8; |
| out[j+2] = t2 & 0xff; t2 >>= 8; |
| out[j+1] = t2 & 0xff; t2 >>= 8; |
| out[j] = t2 & 0xff; |
| } |
| |
| /* Wipe context */ |
| memset(sctx, 0, sizeof(*sctx)); |
| } |
| |
| |
| |
| |
| /*---------------------------------------------------------------------------- |
| * Process identification |
| *----------------------------------------------------------------------------*/ |
| |
| /* This function generates a processes hash table for authentication */ |
| int tf_get_current_process_hash(void *hash) |
| { |
| int result = 0; |
| void *buffer; |
| struct mm_struct *mm; |
| struct vm_area_struct *vma; |
| |
| buffer = internal_kmalloc(PAGE_SIZE, GFP_KERNEL); |
| if (buffer == NULL) { |
| dprintk( |
| KERN_ERR "tf_get_current_process_hash:" |
| " Out of memory for buffer!\n"); |
| return -ENOMEM; |
| } |
| |
| mm = current->mm; |
| |
| down_read(&(mm->mmap_sem)); |
| for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) { |
| if ((vma->vm_flags & VM_EXECUTABLE) != 0 && vma->vm_file |
| != NULL) { |
| struct dentry *dentry; |
| unsigned long start; |
| unsigned long cur; |
| unsigned long end; |
| struct sha1_ctx sha1; |
| |
| dentry = dget(vma->vm_file->f_dentry); |
| |
| dprintk( |
| KERN_DEBUG "tf_get_current_process_hash: " |
| "Found executable VMA for inode %lu " |
| "(%lu bytes).\n", |
| dentry->d_inode->i_ino, |
| (unsigned long) (dentry->d_inode-> |
| i_size)); |
| |
| start = do_mmap(vma->vm_file, 0, |
| dentry->d_inode->i_size, |
| PROT_READ | PROT_WRITE | PROT_EXEC, |
| MAP_PRIVATE, 0); |
| if (start < 0) { |
| dprintk( |
| KERN_ERR "tf_get_current_process_hash" |
| "Hash: do_mmap failed (error %d)!\n", |
| (int) start); |
| dput(dentry); |
| result = -EFAULT; |
| goto vma_out; |
| } |
| |
| end = start + dentry->d_inode->i_size; |
| |
| sha1_init(&sha1); |
| cur = start; |
| while (cur < end) { |
| unsigned long chunk; |
| |
| chunk = end - cur; |
| if (chunk > PAGE_SIZE) |
| chunk = PAGE_SIZE; |
| if (copy_from_user(buffer, (const void *) cur, |
| chunk) != 0) { |
| dprintk( |
| KERN_ERR "tf_get_current_" |
| "process_hash: copy_from_user " |
| "failed!\n"); |
| result = -EINVAL; |
| (void) do_munmap(mm, start, |
| dentry->d_inode->i_size); |
| dput(dentry); |
| goto vma_out; |
| } |
| sha1_update(&sha1, buffer, chunk); |
| cur += chunk; |
| } |
| sha1_final(&sha1, hash); |
| result = 0; |
| |
| (void) do_munmap(mm, start, dentry->d_inode->i_size); |
| dput(dentry); |
| break; |
| } |
| } |
| vma_out: |
| up_read(&(mm->mmap_sem)); |
| |
| internal_kfree(buffer); |
| |
| if (result == -ENOENT) |
| dprintk( |
| KERN_ERR "tf_get_current_process_hash: " |
| "No executable VMA found for process!\n"); |
| return result; |
| } |
| |
| #ifndef CONFIG_ANDROID |
| /* This function hashes the path of the current application. |
| * If data = NULL ,nothing else is added to the hash |
| else add data to the hash |
| */ |
| int tf_hash_application_path_and_data(char *buffer, void *data, |
| u32 data_len) |
| { |
| int result = -ENOENT; |
| char *buffer = NULL; |
| struct mm_struct *mm; |
| struct vm_area_struct *vma; |
| |
| buffer = internal_kmalloc(PAGE_SIZE, GFP_KERNEL); |
| if (buffer == NULL) { |
| result = -ENOMEM; |
| goto end; |
| } |
| |
| mm = current->mm; |
| |
| down_read(&(mm->mmap_sem)); |
| for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) { |
| if ((vma->vm_flags & VM_EXECUTABLE) != 0 |
| && vma->vm_file != NULL) { |
| struct path *path; |
| char *endpath; |
| size_t pathlen; |
| struct sha1_ctx sha1; |
| u8 hash[SHA1_DIGEST_SIZE]; |
| |
| path = &vma->vm_file->f_path; |
| |
| endpath = d_path(path, buffer, PAGE_SIZE); |
| if (IS_ERR(path)) { |
| result = PTR_ERR(endpath); |
| up_read(&(mm->mmap_sem)); |
| goto end; |
| } |
| pathlen = (buffer + PAGE_SIZE) - endpath; |
| |
| #ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT |
| { |
| char *c; |
| dprintk(KERN_DEBUG "current process path = "); |
| for (c = endpath; |
| c < buffer + PAGE_SIZE; |
| c++) |
| dprintk("%c", *c); |
| |
| dprintk(", uid=%d, euid=%d\n", current_uid(), |
| current_euid()); |
| } |
| #endif /* defined(CONFIG_TF_DRIVER_DEBUG_SUPPORT) */ |
| |
| sha1_init(&sha1); |
| sha1_update(&sha1, endpath, pathlen); |
| if (data != NULL) { |
| dprintk(KERN_INFO "current process path: " |
| "Hashing additional data\n"); |
| sha1_update(&sha1, data, data_len); |
| } |
| sha1_final(&sha1, hash); |
| memcpy(buffer, hash, sizeof(hash)); |
| |
| result = 0; |
| |
| break; |
| } |
| } |
| up_read(&(mm->mmap_sem)); |
| |
| end: |
| if (buffer != NULL) |
| internal_kfree(buffer); |
| |
| return result; |
| } |
| #endif /* !CONFIG_ANDROID */ |
| |
| void *internal_kmalloc(size_t size, int priority) |
| { |
| void *ptr; |
| struct tf_device *dev = tf_get_device(); |
| |
| ptr = kmalloc(size, priority); |
| |
| if (ptr != NULL) |
| atomic_inc( |
| &dev->stats.stat_memories_allocated); |
| |
| return ptr; |
| } |
| |
| void internal_kfree(void *ptr) |
| { |
| struct tf_device *dev = tf_get_device(); |
| |
| if (ptr != NULL) |
| atomic_dec( |
| &dev->stats.stat_memories_allocated); |
| return kfree(ptr); |
| } |
| |
| void internal_vunmap(void *ptr) |
| { |
| struct tf_device *dev = tf_get_device(); |
| |
| if (ptr != NULL) |
| atomic_dec( |
| &dev->stats.stat_memories_allocated); |
| |
| vunmap((void *) (((unsigned int)ptr) & 0xFFFFF000)); |
| } |
| |
| void *internal_vmalloc(size_t size) |
| { |
| void *ptr; |
| struct tf_device *dev = tf_get_device(); |
| |
| ptr = vmalloc(size); |
| |
| if (ptr != NULL) |
| atomic_inc( |
| &dev->stats.stat_memories_allocated); |
| |
| return ptr; |
| } |
| |
| void internal_vfree(void *ptr) |
| { |
| struct tf_device *dev = tf_get_device(); |
| |
| if (ptr != NULL) |
| atomic_dec( |
| &dev->stats.stat_memories_allocated); |
| return vfree(ptr); |
| } |
| |
| unsigned long internal_get_zeroed_page(int priority) |
| { |
| unsigned long result; |
| struct tf_device *dev = tf_get_device(); |
| |
| result = get_zeroed_page(priority); |
| |
| if (result != 0) |
| atomic_inc(&dev->stats. |
| stat_pages_allocated); |
| |
| return result; |
| } |
| |
| void internal_free_page(unsigned long addr) |
| { |
| struct tf_device *dev = tf_get_device(); |
| |
| if (addr != 0) |
| atomic_dec( |
| &dev->stats.stat_pages_allocated); |
| return free_page(addr); |
| } |
| |
| int internal_get_user_pages( |
| struct task_struct *tsk, |
| struct mm_struct *mm, |
| unsigned long start, |
| int len, |
| int write, |
| int force, |
| struct page **pages, |
| struct vm_area_struct **vmas) |
| { |
| int result; |
| struct tf_device *dev = tf_get_device(); |
| |
| result = get_user_pages( |
| tsk, |
| mm, |
| start, |
| len, |
| write, |
| force, |
| pages, |
| vmas); |
| |
| if (result > 0) |
| atomic_add(result, |
| &dev->stats.stat_pages_locked); |
| |
| return result; |
| } |
| |
| void internal_get_page(struct page *page) |
| { |
| struct tf_device *dev = tf_get_device(); |
| |
| atomic_inc(&dev->stats.stat_pages_locked); |
| |
| get_page(page); |
| } |
| |
| void internal_page_cache_release(struct page *page) |
| { |
| struct tf_device *dev = tf_get_device(); |
| |
| atomic_dec(&dev->stats.stat_pages_locked); |
| |
| page_cache_release(page); |
| } |