• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (c) 2019, 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  /* debugfs_access_lock protects shared buffer and internal */
57  /* FS functions from concurrent acccesses.                 */
58  static spinlock_t debugfs_access_lock;
59  
60  static bool debugfs_initialized;
61  
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)62  uintptr_t debugfs_smc_handler(unsigned int smc_fid,
63  			      u_register_t cmd,
64  			      u_register_t arg2,
65  			      u_register_t arg3,
66  			      u_register_t arg4,
67  			      void *cookie,
68  			      void *handle,
69  			      u_register_t flags)
70  {
71  	int64_t smc_ret = DEBUGFS_E_INVALID_PARAMS, smc_resp = 0;
72  	int ret;
73  
74  	/* Allow calls from non-secure only */
75  	if (is_caller_secure(flags)) {
76  		SMC_RET1(handle, DEBUGFS_E_DENIED);
77  	}
78  
79  	/* Expect a SiP service fast call */
80  	if ((GET_SMC_TYPE(smc_fid) != SMC_TYPE_FAST) ||
81  		(GET_SMC_OEN(smc_fid) != OEN_SIP_START)) {
82  		SMC_RET1(handle, SMC_UNK);
83  	}
84  
85  	/* Truncate parameters if 32b SMC convention call */
86  	if (GET_SMC_CC(smc_fid) == SMC_32) {
87  		arg2 &= 0xffffffff;
88  		arg3 &= 0xffffffff;
89  		arg4 &= 0xffffffff;
90  	}
91  
92  	spin_lock(&debugfs_access_lock);
93  
94  	if (debugfs_initialized == true) {
95  		/* Copy NS shared buffer to internal secure location */
96  		memcpy(&parms, (void *)DEBUGFS_SHARED_BUF_VIRT,
97  		       sizeof(union debugfs_parms));
98  	}
99  
100  	switch (cmd) {
101  	case INIT:
102  		if (debugfs_initialized == false) {
103  			/* TODO: check PA validity e.g. whether */
104  			/* it is an NS region.                  */
105  			ret = mmap_add_dynamic_region(arg2,
106  				(uintptr_t)DEBUGFS_SHARED_BUF_VIRT,
107  				PAGE_SIZE_4KB,
108  				MT_MEMORY | MT_RW | MT_NS);
109  			if (ret == 0) {
110  				debugfs_initialized = true;
111  				smc_ret = SMC_OK;
112  				smc_resp = 0;
113  			}
114  		}
115  		break;
116  
117  	case VERSION:
118  		smc_ret = SMC_OK;
119  		smc_resp = DEBUGFS_VERSION;
120  		break;
121  
122  	case MOUNT:
123  		ret = mount(parms.mount.srv,
124  			    parms.mount.where,
125  			    parms.mount.spec);
126  		if (ret == 0) {
127  			smc_ret = SMC_OK;
128  			smc_resp = 0;
129  		}
130  		break;
131  
132  	case OPEN:
133  		ret = open(parms.open.fname, arg2);
134  		if (ret >= 0) {
135  			smc_ret = SMC_OK;
136  			smc_resp = ret;
137  		}
138  		break;
139  
140  	case CLOSE:
141  		ret = close(arg2);
142  		if (ret == 0) {
143  			smc_ret = SMC_OK;
144  			smc_resp = 0;
145  		}
146  		break;
147  
148  	case READ:
149  		ret = read(arg2, DEBUGFS_SHARED_BUF_VIRT, arg3);
150  		if (ret >= 0) {
151  			smc_ret = SMC_OK;
152  			smc_resp = ret;
153  		}
154  		break;
155  
156  	case SEEK:
157  		ret = seek(arg2, arg3, arg4);
158  		if (ret == 0) {
159  			smc_ret = SMC_OK;
160  			smc_resp = 0;
161  		}
162  		break;
163  
164  	case BIND:
165  		ret = bind(parms.bind.oldpath, parms.bind.newpath);
166  		if (ret == 0) {
167  			smc_ret = SMC_OK;
168  			smc_resp = 0;
169  		}
170  		break;
171  
172  	case STAT:
173  		ret = stat(parms.stat.path, &parms.stat.dir);
174  		if (ret == 0) {
175  			memcpy((void *)DEBUGFS_SHARED_BUF_VIRT, &parms,
176  			       sizeof(union debugfs_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