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