1 /* 2 * Copyright (c) 2019-2025, Arm Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <stdint.h> 8 #include <stdbool.h> 9 #include <string.h> 10 11 #include <lib/debugfs.h> 12 #include <lib/smccc.h> 13 #include <lib/spinlock.h> 14 #include <lib/xlat_tables/xlat_tables_v2.h> 15 #include <smccc_helpers.h> 16 17 #define MAX_PATH_LEN 256 18 19 #define MOUNT 0 20 #define CREATE 1 21 #define OPEN 2 22 #define CLOSE 3 23 #define READ 4 24 #define WRITE 5 25 #define SEEK 6 26 #define BIND 7 27 #define STAT 8 28 #define INIT 10 29 #define VERSION 11 30 31 /* This is the virtual address to which we map the NS shared buffer */ 32 #define DEBUGFS_SHARED_BUF_VIRT ((void *)0x81000000U) 33 34 static union debugfs_parms { 35 struct { 36 char fname[MAX_PATH_LEN]; 37 } open; 38 39 struct { 40 char srv[MAX_PATH_LEN]; 41 char where[MAX_PATH_LEN]; 42 char spec[MAX_PATH_LEN]; 43 } mount; 44 45 struct { 46 char path[MAX_PATH_LEN]; 47 dir_t dir; 48 } stat; 49 50 struct { 51 char oldpath[MAX_PATH_LEN]; 52 char newpath[MAX_PATH_LEN]; 53 } bind; 54 } parms; 55 56 static volatile union debugfs_parms *shared_ns_buf = DEBUGFS_SHARED_BUF_VIRT; 57 58 /* debugfs_access_lock protects shared buffer and internal */ 59 /* FS functions from concurrent accesses. */ 60 static spinlock_t debugfs_access_lock; 61 62 static bool debugfs_initialized; 63 64 uintptr_t debugfs_smc_handler(unsigned int smc_fid, 65 u_register_t cmd, 66 u_register_t arg2, 67 u_register_t arg3, 68 u_register_t arg4, 69 void *cookie, 70 void *handle, 71 u_register_t flags) 72 { 73 int64_t smc_ret = DEBUGFS_E_INVALID_PARAMS, smc_resp = 0; 74 int ret; 75 76 /* Allow calls from non-secure only */ 77 if (!is_caller_non_secure(flags)) { 78 SMC_RET1(handle, DEBUGFS_E_DENIED); 79 } 80 81 /* Expect a vendor specific EL3 service fast call */ 82 if ((GET_SMC_TYPE(smc_fid) != SMC_TYPE_FAST) || 83 (GET_SMC_OEN(smc_fid) != OEN_VEN_EL3_START)) { 84 SMC_RET1(handle, SMC_UNK); 85 } 86 87 /* Truncate parameters if 32b SMC convention call */ 88 if (GET_SMC_CC(smc_fid) == SMC_32) { 89 arg2 &= 0xffffffff; 90 arg3 &= 0xffffffff; 91 arg4 &= 0xffffffff; 92 } 93 94 spin_lock(&debugfs_access_lock); 95 96 if (debugfs_initialized == true) { 97 /* Copy NS shared buffer to internal secure location */ 98 parms = *shared_ns_buf; 99 } 100 101 switch (cmd) { 102 case INIT: 103 if (debugfs_initialized == false) { 104 /* TODO: check PA validity e.g. whether */ 105 /* it is an NS region. */ 106 ret = mmap_add_dynamic_region(arg2, 107 (uintptr_t)DEBUGFS_SHARED_BUF_VIRT, 108 PAGE_SIZE_4KB, 109 MT_MEMORY | MT_RW | MT_NS); 110 if (ret == 0) { 111 debugfs_initialized = true; 112 smc_ret = SMC_OK; 113 smc_resp = 0; 114 } 115 } 116 break; 117 118 case VERSION: 119 smc_ret = SMC_OK; 120 smc_resp = DEBUGFS_VERSION; 121 break; 122 123 case MOUNT: 124 ret = mount(parms.mount.srv, 125 parms.mount.where, 126 parms.mount.spec); 127 if (ret == 0) { 128 smc_ret = SMC_OK; 129 smc_resp = 0; 130 } 131 break; 132 133 case OPEN: 134 ret = open(parms.open.fname, arg2); 135 if (ret >= 0) { 136 smc_ret = SMC_OK; 137 smc_resp = ret; 138 } 139 break; 140 141 case CLOSE: 142 ret = close(arg2); 143 if (ret == 0) { 144 smc_ret = SMC_OK; 145 smc_resp = 0; 146 } 147 break; 148 149 case READ: 150 ret = read(arg2, DEBUGFS_SHARED_BUF_VIRT, arg3); 151 if (ret >= 0) { 152 smc_ret = SMC_OK; 153 smc_resp = ret; 154 } 155 break; 156 157 case SEEK: 158 ret = seek(arg2, arg3, arg4); 159 if (ret == 0) { 160 smc_ret = SMC_OK; 161 smc_resp = 0; 162 } 163 break; 164 165 case BIND: 166 ret = bind(parms.bind.oldpath, parms.bind.newpath); 167 if (ret == 0) { 168 smc_ret = SMC_OK; 169 smc_resp = 0; 170 } 171 break; 172 173 case STAT: 174 ret = stat(parms.stat.path, &parms.stat.dir); 175 if (ret == 0) { 176 *shared_ns_buf = parms; 177 smc_ret = SMC_OK; 178 smc_resp = 0; 179 } 180 break; 181 182 /* Not implemented */ 183 case CREATE: 184 /* Intentional fall-through */ 185 186 /* Not implemented */ 187 case WRITE: 188 /* Intentional fall-through */ 189 190 default: 191 smc_ret = SMC_UNK; 192 smc_resp = 0; 193 } 194 195 spin_unlock(&debugfs_access_lock); 196 197 SMC_RET2(handle, smc_ret, smc_resp); 198 199 /* Not reached */ 200 return smc_ret; 201 } 202 203 int debugfs_smc_setup(void) 204 { 205 debugfs_initialized = false; 206 debugfs_access_lock.lock = 0; 207 208 return 0; 209 } 210