xref: /arm-trusted-firmware/lib/debugfs/debugfs_smc.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
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