xref: /rk3399_ARM-atf/lib/debugfs/debugfs_smc.c (revision 4e4a8c585d880a11e66ad551da3d5203fff327d7)
1992f091bSAmbroise Vincent /*
24c700c15SGovindraj Raja  * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
3992f091bSAmbroise Vincent  *
4992f091bSAmbroise Vincent  * SPDX-License-Identifier: BSD-3-Clause
5992f091bSAmbroise Vincent  */
6992f091bSAmbroise Vincent 
7992f091bSAmbroise Vincent #include <stdint.h>
8992f091bSAmbroise Vincent #include <stdbool.h>
9992f091bSAmbroise Vincent #include <string.h>
10992f091bSAmbroise Vincent 
11992f091bSAmbroise Vincent #include <lib/debugfs.h>
12992f091bSAmbroise Vincent #include <lib/smccc.h>
13992f091bSAmbroise Vincent #include <lib/spinlock.h>
14992f091bSAmbroise Vincent #include <lib/xlat_tables/xlat_tables_v2.h>
15992f091bSAmbroise Vincent #include <smccc_helpers.h>
16992f091bSAmbroise Vincent 
17992f091bSAmbroise Vincent #define MAX_PATH_LEN	256
18992f091bSAmbroise Vincent 
19992f091bSAmbroise Vincent #define MOUNT		0
20992f091bSAmbroise Vincent #define CREATE		1
21992f091bSAmbroise Vincent #define OPEN		2
22992f091bSAmbroise Vincent #define CLOSE		3
23992f091bSAmbroise Vincent #define READ		4
24992f091bSAmbroise Vincent #define WRITE		5
25992f091bSAmbroise Vincent #define SEEK		6
26992f091bSAmbroise Vincent #define BIND		7
27992f091bSAmbroise Vincent #define STAT		8
28992f091bSAmbroise Vincent #define INIT		10
29992f091bSAmbroise Vincent #define VERSION		11
30992f091bSAmbroise Vincent 
31992f091bSAmbroise Vincent /* This is the virtual address to which we map the NS shared buffer */
32992f091bSAmbroise Vincent #define DEBUGFS_SHARED_BUF_VIRT		((void *)0x81000000U)
33992f091bSAmbroise Vincent 
34992f091bSAmbroise Vincent static union debugfs_parms {
35992f091bSAmbroise Vincent 	struct {
36992f091bSAmbroise Vincent 		char fname[MAX_PATH_LEN];
37992f091bSAmbroise Vincent 	} open;
38992f091bSAmbroise Vincent 
39992f091bSAmbroise Vincent 	struct {
40992f091bSAmbroise Vincent 		char srv[MAX_PATH_LEN];
41992f091bSAmbroise Vincent 		char where[MAX_PATH_LEN];
42992f091bSAmbroise Vincent 		char spec[MAX_PATH_LEN];
43992f091bSAmbroise Vincent 	} mount;
44992f091bSAmbroise Vincent 
45992f091bSAmbroise Vincent 	struct {
46992f091bSAmbroise Vincent 		char path[MAX_PATH_LEN];
47992f091bSAmbroise Vincent 		dir_t dir;
48992f091bSAmbroise Vincent 	} stat;
49992f091bSAmbroise Vincent 
50992f091bSAmbroise Vincent 	struct {
51992f091bSAmbroise Vincent 		char oldpath[MAX_PATH_LEN];
52992f091bSAmbroise Vincent 		char newpath[MAX_PATH_LEN];
53992f091bSAmbroise Vincent 	} bind;
54992f091bSAmbroise Vincent } parms;
55992f091bSAmbroise Vincent 
56992f091bSAmbroise Vincent /* debugfs_access_lock protects shared buffer and internal */
571b491eeaSElyes Haouas /* FS functions from concurrent accesses.                 */
58992f091bSAmbroise Vincent static spinlock_t debugfs_access_lock;
59992f091bSAmbroise Vincent 
60992f091bSAmbroise Vincent static bool debugfs_initialized;
61992f091bSAmbroise Vincent 
62992f091bSAmbroise Vincent uintptr_t debugfs_smc_handler(unsigned int smc_fid,
63992f091bSAmbroise Vincent 			      u_register_t cmd,
64992f091bSAmbroise Vincent 			      u_register_t arg2,
65992f091bSAmbroise Vincent 			      u_register_t arg3,
66992f091bSAmbroise Vincent 			      u_register_t arg4,
67992f091bSAmbroise Vincent 			      void *cookie,
68992f091bSAmbroise Vincent 			      void *handle,
69992f091bSAmbroise Vincent 			      u_register_t flags)
70992f091bSAmbroise Vincent {
71992f091bSAmbroise Vincent 	int64_t smc_ret = DEBUGFS_E_INVALID_PARAMS, smc_resp = 0;
72992f091bSAmbroise Vincent 	int ret;
73992f091bSAmbroise Vincent 
74992f091bSAmbroise Vincent 	/* Allow calls from non-secure only */
75*4e4a8c58SArvind Ram Prakash 	if (!is_caller_non_secure(flags)) {
76992f091bSAmbroise Vincent 		SMC_RET1(handle, DEBUGFS_E_DENIED);
77992f091bSAmbroise Vincent 	}
78992f091bSAmbroise Vincent 
79992f091bSAmbroise Vincent 	/* Expect a SiP service fast call */
80992f091bSAmbroise Vincent 	if ((GET_SMC_TYPE(smc_fid) != SMC_TYPE_FAST) ||
81992f091bSAmbroise Vincent 		(GET_SMC_OEN(smc_fid) != OEN_SIP_START)) {
82992f091bSAmbroise Vincent 		SMC_RET1(handle, SMC_UNK);
83992f091bSAmbroise Vincent 	}
84992f091bSAmbroise Vincent 
85992f091bSAmbroise Vincent 	/* Truncate parameters if 32b SMC convention call */
86992f091bSAmbroise Vincent 	if (GET_SMC_CC(smc_fid) == SMC_32) {
87992f091bSAmbroise Vincent 		arg2 &= 0xffffffff;
88992f091bSAmbroise Vincent 		arg3 &= 0xffffffff;
89992f091bSAmbroise Vincent 		arg4 &= 0xffffffff;
90992f091bSAmbroise Vincent 	}
91992f091bSAmbroise Vincent 
92992f091bSAmbroise Vincent 	spin_lock(&debugfs_access_lock);
93992f091bSAmbroise Vincent 
94992f091bSAmbroise Vincent 	if (debugfs_initialized == true) {
95992f091bSAmbroise Vincent 		/* Copy NS shared buffer to internal secure location */
96992f091bSAmbroise Vincent 		memcpy(&parms, (void *)DEBUGFS_SHARED_BUF_VIRT,
97992f091bSAmbroise Vincent 		       sizeof(union debugfs_parms));
98992f091bSAmbroise Vincent 	}
99992f091bSAmbroise Vincent 
100992f091bSAmbroise Vincent 	switch (cmd) {
101992f091bSAmbroise Vincent 	case INIT:
102992f091bSAmbroise Vincent 		if (debugfs_initialized == false) {
103992f091bSAmbroise Vincent 			/* TODO: check PA validity e.g. whether */
104992f091bSAmbroise Vincent 			/* it is an NS region.                  */
105992f091bSAmbroise Vincent 			ret = mmap_add_dynamic_region(arg2,
106992f091bSAmbroise Vincent 				(uintptr_t)DEBUGFS_SHARED_BUF_VIRT,
107992f091bSAmbroise Vincent 				PAGE_SIZE_4KB,
108992f091bSAmbroise Vincent 				MT_MEMORY | MT_RW | MT_NS);
109992f091bSAmbroise Vincent 			if (ret == 0) {
110992f091bSAmbroise Vincent 				debugfs_initialized = true;
111992f091bSAmbroise Vincent 				smc_ret = SMC_OK;
112992f091bSAmbroise Vincent 				smc_resp = 0;
113992f091bSAmbroise Vincent 			}
114992f091bSAmbroise Vincent 		}
115992f091bSAmbroise Vincent 		break;
116992f091bSAmbroise Vincent 
117992f091bSAmbroise Vincent 	case VERSION:
118992f091bSAmbroise Vincent 		smc_ret = SMC_OK;
119992f091bSAmbroise Vincent 		smc_resp = DEBUGFS_VERSION;
120992f091bSAmbroise Vincent 		break;
121992f091bSAmbroise Vincent 
122992f091bSAmbroise Vincent 	case MOUNT:
123992f091bSAmbroise Vincent 		ret = mount(parms.mount.srv,
124992f091bSAmbroise Vincent 			    parms.mount.where,
125992f091bSAmbroise Vincent 			    parms.mount.spec);
126992f091bSAmbroise Vincent 		if (ret == 0) {
127992f091bSAmbroise Vincent 			smc_ret = SMC_OK;
128992f091bSAmbroise Vincent 			smc_resp = 0;
129992f091bSAmbroise Vincent 		}
130992f091bSAmbroise Vincent 		break;
131992f091bSAmbroise Vincent 
132992f091bSAmbroise Vincent 	case OPEN:
133992f091bSAmbroise Vincent 		ret = open(parms.open.fname, arg2);
134992f091bSAmbroise Vincent 		if (ret >= 0) {
135992f091bSAmbroise Vincent 			smc_ret = SMC_OK;
136992f091bSAmbroise Vincent 			smc_resp = ret;
137992f091bSAmbroise Vincent 		}
138992f091bSAmbroise Vincent 		break;
139992f091bSAmbroise Vincent 
140992f091bSAmbroise Vincent 	case CLOSE:
141992f091bSAmbroise Vincent 		ret = close(arg2);
142992f091bSAmbroise Vincent 		if (ret == 0) {
143992f091bSAmbroise Vincent 			smc_ret = SMC_OK;
144992f091bSAmbroise Vincent 			smc_resp = 0;
145992f091bSAmbroise Vincent 		}
146992f091bSAmbroise Vincent 		break;
147992f091bSAmbroise Vincent 
148992f091bSAmbroise Vincent 	case READ:
149992f091bSAmbroise Vincent 		ret = read(arg2, DEBUGFS_SHARED_BUF_VIRT, arg3);
150992f091bSAmbroise Vincent 		if (ret >= 0) {
151992f091bSAmbroise Vincent 			smc_ret = SMC_OK;
152992f091bSAmbroise Vincent 			smc_resp = ret;
153992f091bSAmbroise Vincent 		}
154992f091bSAmbroise Vincent 		break;
155992f091bSAmbroise Vincent 
156992f091bSAmbroise Vincent 	case SEEK:
157992f091bSAmbroise Vincent 		ret = seek(arg2, arg3, arg4);
158992f091bSAmbroise Vincent 		if (ret == 0) {
159992f091bSAmbroise Vincent 			smc_ret = SMC_OK;
160992f091bSAmbroise Vincent 			smc_resp = 0;
161992f091bSAmbroise Vincent 		}
162992f091bSAmbroise Vincent 		break;
163992f091bSAmbroise Vincent 
164992f091bSAmbroise Vincent 	case BIND:
165992f091bSAmbroise Vincent 		ret = bind(parms.bind.oldpath, parms.bind.newpath);
166992f091bSAmbroise Vincent 		if (ret == 0) {
167992f091bSAmbroise Vincent 			smc_ret = SMC_OK;
168992f091bSAmbroise Vincent 			smc_resp = 0;
169992f091bSAmbroise Vincent 		}
170992f091bSAmbroise Vincent 		break;
171992f091bSAmbroise Vincent 
172992f091bSAmbroise Vincent 	case STAT:
173992f091bSAmbroise Vincent 		ret = stat(parms.stat.path, &parms.stat.dir);
174992f091bSAmbroise Vincent 		if (ret == 0) {
175992f091bSAmbroise Vincent 			memcpy((void *)DEBUGFS_SHARED_BUF_VIRT, &parms,
176992f091bSAmbroise Vincent 			       sizeof(union debugfs_parms));
177992f091bSAmbroise Vincent 			smc_ret = SMC_OK;
178992f091bSAmbroise Vincent 			smc_resp = 0;
179992f091bSAmbroise Vincent 		}
180992f091bSAmbroise Vincent 		break;
181992f091bSAmbroise Vincent 
182992f091bSAmbroise Vincent 	/* Not implemented */
183992f091bSAmbroise Vincent 	case CREATE:
184992f091bSAmbroise Vincent 		/* Intentional fall-through */
185992f091bSAmbroise Vincent 
186992f091bSAmbroise Vincent 	/* Not implemented */
187992f091bSAmbroise Vincent 	case WRITE:
188992f091bSAmbroise Vincent 		/* Intentional fall-through */
189992f091bSAmbroise Vincent 
190992f091bSAmbroise Vincent 	default:
191992f091bSAmbroise Vincent 		smc_ret = SMC_UNK;
192992f091bSAmbroise Vincent 		smc_resp = 0;
193992f091bSAmbroise Vincent 	}
194992f091bSAmbroise Vincent 
195992f091bSAmbroise Vincent 	spin_unlock(&debugfs_access_lock);
196992f091bSAmbroise Vincent 
197992f091bSAmbroise Vincent 	SMC_RET2(handle, smc_ret, smc_resp);
198992f091bSAmbroise Vincent 
199992f091bSAmbroise Vincent 	/* Not reached */
200992f091bSAmbroise Vincent 	return smc_ret;
201992f091bSAmbroise Vincent }
202992f091bSAmbroise Vincent 
203992f091bSAmbroise Vincent int debugfs_smc_setup(void)
204992f091bSAmbroise Vincent {
205992f091bSAmbroise Vincent 	debugfs_initialized = false;
206992f091bSAmbroise Vincent 	debugfs_access_lock.lock = 0;
207992f091bSAmbroise Vincent 
208992f091bSAmbroise Vincent 	return 0;
209992f091bSAmbroise Vincent }
210