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