1992f091bSAmbroise Vincent /* 2992f091bSAmbroise Vincent * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. 3992f091bSAmbroise Vincent * 4992f091bSAmbroise Vincent * SPDX-License-Identifier: BSD-3-Clause 5992f091bSAmbroise Vincent */ 6992f091bSAmbroise Vincent 7992f091bSAmbroise Vincent #include <stdint.h> 8992f091bSAmbroise Vincent #include <stdbool.h> 9992f091bSAmbroise Vincent #include <string.h> 10992f091bSAmbroise Vincent 11992f091bSAmbroise Vincent #include <lib/debugfs.h> 12992f091bSAmbroise Vincent #include <lib/smccc.h> 13992f091bSAmbroise Vincent #include <lib/spinlock.h> 14992f091bSAmbroise Vincent #include <lib/xlat_tables/xlat_tables_v2.h> 15992f091bSAmbroise Vincent #include <smccc_helpers.h> 16992f091bSAmbroise Vincent 17992f091bSAmbroise Vincent #define MAX_PATH_LEN 256 18992f091bSAmbroise Vincent 19992f091bSAmbroise Vincent #define MOUNT 0 20992f091bSAmbroise Vincent #define CREATE 1 21992f091bSAmbroise Vincent #define OPEN 2 22992f091bSAmbroise Vincent #define CLOSE 3 23992f091bSAmbroise Vincent #define READ 4 24992f091bSAmbroise Vincent #define WRITE 5 25992f091bSAmbroise Vincent #define SEEK 6 26992f091bSAmbroise Vincent #define BIND 7 27992f091bSAmbroise Vincent #define STAT 8 28992f091bSAmbroise Vincent #define INIT 10 29992f091bSAmbroise Vincent #define VERSION 11 30992f091bSAmbroise Vincent 31992f091bSAmbroise Vincent /* This is the virtual address to which we map the NS shared buffer */ 32992f091bSAmbroise Vincent #define DEBUGFS_SHARED_BUF_VIRT ((void *)0x81000000U) 33992f091bSAmbroise Vincent 34992f091bSAmbroise Vincent static union debugfs_parms { 35992f091bSAmbroise Vincent struct { 36992f091bSAmbroise Vincent char fname[MAX_PATH_LEN]; 37992f091bSAmbroise Vincent } open; 38992f091bSAmbroise Vincent 39992f091bSAmbroise Vincent struct { 40992f091bSAmbroise Vincent char srv[MAX_PATH_LEN]; 41992f091bSAmbroise Vincent char where[MAX_PATH_LEN]; 42992f091bSAmbroise Vincent char spec[MAX_PATH_LEN]; 43992f091bSAmbroise Vincent } mount; 44992f091bSAmbroise Vincent 45992f091bSAmbroise Vincent struct { 46992f091bSAmbroise Vincent char path[MAX_PATH_LEN]; 47992f091bSAmbroise Vincent dir_t dir; 48992f091bSAmbroise Vincent } stat; 49992f091bSAmbroise Vincent 50992f091bSAmbroise Vincent struct { 51992f091bSAmbroise Vincent char oldpath[MAX_PATH_LEN]; 52992f091bSAmbroise Vincent char newpath[MAX_PATH_LEN]; 53992f091bSAmbroise Vincent } bind; 54992f091bSAmbroise Vincent } parms; 55992f091bSAmbroise Vincent 56992f091bSAmbroise Vincent /* debugfs_access_lock protects shared buffer and internal */ 57*1b491eeaSElyes Haouas /* FS functions from concurrent accesses. */ 58992f091bSAmbroise Vincent static spinlock_t debugfs_access_lock; 59992f091bSAmbroise Vincent 60992f091bSAmbroise Vincent static bool debugfs_initialized; 61992f091bSAmbroise Vincent 62992f091bSAmbroise Vincent uintptr_t debugfs_smc_handler(unsigned int smc_fid, 63992f091bSAmbroise Vincent u_register_t cmd, 64992f091bSAmbroise Vincent u_register_t arg2, 65992f091bSAmbroise Vincent u_register_t arg3, 66992f091bSAmbroise Vincent u_register_t arg4, 67992f091bSAmbroise Vincent void *cookie, 68992f091bSAmbroise Vincent void *handle, 69992f091bSAmbroise Vincent u_register_t flags) 70992f091bSAmbroise Vincent { 71992f091bSAmbroise Vincent int64_t smc_ret = DEBUGFS_E_INVALID_PARAMS, smc_resp = 0; 72992f091bSAmbroise Vincent int ret; 73992f091bSAmbroise Vincent 74992f091bSAmbroise Vincent /* Allow calls from non-secure only */ 75992f091bSAmbroise Vincent if (is_caller_secure(flags)) { 76992f091bSAmbroise Vincent SMC_RET1(handle, DEBUGFS_E_DENIED); 77992f091bSAmbroise Vincent } 78992f091bSAmbroise Vincent 79992f091bSAmbroise Vincent /* Expect a SiP service fast call */ 80992f091bSAmbroise Vincent if ((GET_SMC_TYPE(smc_fid) != SMC_TYPE_FAST) || 81992f091bSAmbroise Vincent (GET_SMC_OEN(smc_fid) != OEN_SIP_START)) { 82992f091bSAmbroise Vincent SMC_RET1(handle, SMC_UNK); 83992f091bSAmbroise Vincent } 84992f091bSAmbroise Vincent 85992f091bSAmbroise Vincent /* Truncate parameters if 32b SMC convention call */ 86992f091bSAmbroise Vincent if (GET_SMC_CC(smc_fid) == SMC_32) { 87992f091bSAmbroise Vincent arg2 &= 0xffffffff; 88992f091bSAmbroise Vincent arg3 &= 0xffffffff; 89992f091bSAmbroise Vincent arg4 &= 0xffffffff; 90992f091bSAmbroise Vincent } 91992f091bSAmbroise Vincent 92992f091bSAmbroise Vincent spin_lock(&debugfs_access_lock); 93992f091bSAmbroise Vincent 94992f091bSAmbroise Vincent if (debugfs_initialized == true) { 95992f091bSAmbroise Vincent /* Copy NS shared buffer to internal secure location */ 96992f091bSAmbroise Vincent memcpy(&parms, (void *)DEBUGFS_SHARED_BUF_VIRT, 97992f091bSAmbroise Vincent sizeof(union debugfs_parms)); 98992f091bSAmbroise Vincent } 99992f091bSAmbroise Vincent 100992f091bSAmbroise Vincent switch (cmd) { 101992f091bSAmbroise Vincent case INIT: 102992f091bSAmbroise Vincent if (debugfs_initialized == false) { 103992f091bSAmbroise Vincent /* TODO: check PA validity e.g. whether */ 104992f091bSAmbroise Vincent /* it is an NS region. */ 105992f091bSAmbroise Vincent ret = mmap_add_dynamic_region(arg2, 106992f091bSAmbroise Vincent (uintptr_t)DEBUGFS_SHARED_BUF_VIRT, 107992f091bSAmbroise Vincent PAGE_SIZE_4KB, 108992f091bSAmbroise Vincent MT_MEMORY | MT_RW | MT_NS); 109992f091bSAmbroise Vincent if (ret == 0) { 110992f091bSAmbroise Vincent debugfs_initialized = true; 111992f091bSAmbroise Vincent smc_ret = SMC_OK; 112992f091bSAmbroise Vincent smc_resp = 0; 113992f091bSAmbroise Vincent } 114992f091bSAmbroise Vincent } 115992f091bSAmbroise Vincent break; 116992f091bSAmbroise Vincent 117992f091bSAmbroise Vincent case VERSION: 118992f091bSAmbroise Vincent smc_ret = SMC_OK; 119992f091bSAmbroise Vincent smc_resp = DEBUGFS_VERSION; 120992f091bSAmbroise Vincent break; 121992f091bSAmbroise Vincent 122992f091bSAmbroise Vincent case MOUNT: 123992f091bSAmbroise Vincent ret = mount(parms.mount.srv, 124992f091bSAmbroise Vincent parms.mount.where, 125992f091bSAmbroise Vincent parms.mount.spec); 126992f091bSAmbroise Vincent if (ret == 0) { 127992f091bSAmbroise Vincent smc_ret = SMC_OK; 128992f091bSAmbroise Vincent smc_resp = 0; 129992f091bSAmbroise Vincent } 130992f091bSAmbroise Vincent break; 131992f091bSAmbroise Vincent 132992f091bSAmbroise Vincent case OPEN: 133992f091bSAmbroise Vincent ret = open(parms.open.fname, arg2); 134992f091bSAmbroise Vincent if (ret >= 0) { 135992f091bSAmbroise Vincent smc_ret = SMC_OK; 136992f091bSAmbroise Vincent smc_resp = ret; 137992f091bSAmbroise Vincent } 138992f091bSAmbroise Vincent break; 139992f091bSAmbroise Vincent 140992f091bSAmbroise Vincent case CLOSE: 141992f091bSAmbroise Vincent ret = close(arg2); 142992f091bSAmbroise Vincent if (ret == 0) { 143992f091bSAmbroise Vincent smc_ret = SMC_OK; 144992f091bSAmbroise Vincent smc_resp = 0; 145992f091bSAmbroise Vincent } 146992f091bSAmbroise Vincent break; 147992f091bSAmbroise Vincent 148992f091bSAmbroise Vincent case READ: 149992f091bSAmbroise Vincent ret = read(arg2, DEBUGFS_SHARED_BUF_VIRT, arg3); 150992f091bSAmbroise Vincent if (ret >= 0) { 151992f091bSAmbroise Vincent smc_ret = SMC_OK; 152992f091bSAmbroise Vincent smc_resp = ret; 153992f091bSAmbroise Vincent } 154992f091bSAmbroise Vincent break; 155992f091bSAmbroise Vincent 156992f091bSAmbroise Vincent case SEEK: 157992f091bSAmbroise Vincent ret = seek(arg2, arg3, arg4); 158992f091bSAmbroise Vincent if (ret == 0) { 159992f091bSAmbroise Vincent smc_ret = SMC_OK; 160992f091bSAmbroise Vincent smc_resp = 0; 161992f091bSAmbroise Vincent } 162992f091bSAmbroise Vincent break; 163992f091bSAmbroise Vincent 164992f091bSAmbroise Vincent case BIND: 165992f091bSAmbroise Vincent ret = bind(parms.bind.oldpath, parms.bind.newpath); 166992f091bSAmbroise Vincent if (ret == 0) { 167992f091bSAmbroise Vincent smc_ret = SMC_OK; 168992f091bSAmbroise Vincent smc_resp = 0; 169992f091bSAmbroise Vincent } 170992f091bSAmbroise Vincent break; 171992f091bSAmbroise Vincent 172992f091bSAmbroise Vincent case STAT: 173992f091bSAmbroise Vincent ret = stat(parms.stat.path, &parms.stat.dir); 174992f091bSAmbroise Vincent if (ret == 0) { 175992f091bSAmbroise Vincent memcpy((void *)DEBUGFS_SHARED_BUF_VIRT, &parms, 176992f091bSAmbroise Vincent sizeof(union debugfs_parms)); 177992f091bSAmbroise Vincent smc_ret = SMC_OK; 178992f091bSAmbroise Vincent smc_resp = 0; 179992f091bSAmbroise Vincent } 180992f091bSAmbroise Vincent break; 181992f091bSAmbroise Vincent 182992f091bSAmbroise Vincent /* Not implemented */ 183992f091bSAmbroise Vincent case CREATE: 184992f091bSAmbroise Vincent /* Intentional fall-through */ 185992f091bSAmbroise Vincent 186992f091bSAmbroise Vincent /* Not implemented */ 187992f091bSAmbroise Vincent case WRITE: 188992f091bSAmbroise Vincent /* Intentional fall-through */ 189992f091bSAmbroise Vincent 190992f091bSAmbroise Vincent default: 191992f091bSAmbroise Vincent smc_ret = SMC_UNK; 192992f091bSAmbroise Vincent smc_resp = 0; 193992f091bSAmbroise Vincent } 194992f091bSAmbroise Vincent 195992f091bSAmbroise Vincent spin_unlock(&debugfs_access_lock); 196992f091bSAmbroise Vincent 197992f091bSAmbroise Vincent SMC_RET2(handle, smc_ret, smc_resp); 198992f091bSAmbroise Vincent 199992f091bSAmbroise Vincent /* Not reached */ 200992f091bSAmbroise Vincent return smc_ret; 201992f091bSAmbroise Vincent } 202992f091bSAmbroise Vincent 203992f091bSAmbroise Vincent int debugfs_smc_setup(void) 204992f091bSAmbroise Vincent { 205992f091bSAmbroise Vincent debugfs_initialized = false; 206992f091bSAmbroise Vincent debugfs_access_lock.lock = 0; 207992f091bSAmbroise Vincent 208992f091bSAmbroise Vincent return 0; 209992f091bSAmbroise Vincent } 210