xref: /rk3399_ARM-atf/lib/debugfs/debugfs_smc.c (revision 4287d22bdf8afcbad06f3d64efbb7bd0dbda2445)
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 
debugfs_smc_handler(unsigned int smc_fid,u_register_t cmd,u_register_t arg2,u_register_t arg3,u_register_t arg4,void * cookie,void * handle,u_register_t flags)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 
debugfs_smc_setup(void)203 int debugfs_smc_setup(void)
204 {
205 	debugfs_initialized = false;
206 	debugfs_access_lock.lock = 0;
207 
208 	return 0;
209 }
210