xref: /arm-trusted-firmware/lib/debugfs/dev.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <cdefs.h>
8*91f16700Schasinglulu #include <common/debug.h>
9*91f16700Schasinglulu #include <lib/debugfs.h>
10*91f16700Schasinglulu #include <string.h>
11*91f16700Schasinglulu 
12*91f16700Schasinglulu #include "dev.h"
13*91f16700Schasinglulu 
14*91f16700Schasinglulu #define NR_MOUNT_POINTS		4
15*91f16700Schasinglulu 
16*91f16700Schasinglulu struct mount_point {
17*91f16700Schasinglulu 	chan_t	*new;
18*91f16700Schasinglulu 	chan_t	*old;
19*91f16700Schasinglulu };
20*91f16700Schasinglulu 
21*91f16700Schasinglulu /* This array contains all the available channels of the filesystem.
22*91f16700Schasinglulu  * A file descriptor is the index of a specific channel in this array.
23*91f16700Schasinglulu  */
24*91f16700Schasinglulu static chan_t fdset[NR_CHANS];
25*91f16700Schasinglulu 
26*91f16700Schasinglulu /* This array contains all the available mount points of the filesystem. */
27*91f16700Schasinglulu static struct mount_point mount_points[NR_MOUNT_POINTS];
28*91f16700Schasinglulu 
29*91f16700Schasinglulu /* This variable stores the channel associated to the root directory. */
30*91f16700Schasinglulu static chan_t slash_channel;
31*91f16700Schasinglulu 
32*91f16700Schasinglulu /* This function creates a channel from a device index and registers
33*91f16700Schasinglulu  * it to fdset.
34*91f16700Schasinglulu  */
35*91f16700Schasinglulu static chan_t *create_new_channel(unsigned char index)
36*91f16700Schasinglulu {
37*91f16700Schasinglulu 	chan_t *channel = NULL;
38*91f16700Schasinglulu 	int i;
39*91f16700Schasinglulu 
40*91f16700Schasinglulu 	for (i = 0; i < NR_CHANS; i++) {
41*91f16700Schasinglulu 		if (fdset[i].index == NODEV) {
42*91f16700Schasinglulu 			channel = &fdset[i];
43*91f16700Schasinglulu 			channel->index = index;
44*91f16700Schasinglulu 			break;
45*91f16700Schasinglulu 		}
46*91f16700Schasinglulu 	}
47*91f16700Schasinglulu 
48*91f16700Schasinglulu 	return channel;
49*91f16700Schasinglulu }
50*91f16700Schasinglulu 
51*91f16700Schasinglulu /*******************************************************************************
52*91f16700Schasinglulu  * This function returns a pointer to an existing channel in fdset from a file
53*91f16700Schasinglulu  * descriptor.
54*91f16700Schasinglulu  ******************************************************************************/
55*91f16700Schasinglulu static chan_t *fd_to_channel(int fd)
56*91f16700Schasinglulu {
57*91f16700Schasinglulu 	if ((fd < 0) || (fd >= NR_CHANS) || (fdset[fd].index == NODEV)) {
58*91f16700Schasinglulu 		return NULL;
59*91f16700Schasinglulu 	}
60*91f16700Schasinglulu 
61*91f16700Schasinglulu 	return &fdset[fd];
62*91f16700Schasinglulu }
63*91f16700Schasinglulu 
64*91f16700Schasinglulu /*******************************************************************************
65*91f16700Schasinglulu  * This function returns a file descriptor from a channel.
66*91f16700Schasinglulu  * The caller must be sure that the channel is registered in fdset.
67*91f16700Schasinglulu  ******************************************************************************/
68*91f16700Schasinglulu static int channel_to_fd(chan_t *channel)
69*91f16700Schasinglulu {
70*91f16700Schasinglulu 	return (channel == NULL) ? -1 : (channel - fdset);
71*91f16700Schasinglulu }
72*91f16700Schasinglulu 
73*91f16700Schasinglulu /*******************************************************************************
74*91f16700Schasinglulu  * This function checks the validity of a mode.
75*91f16700Schasinglulu  ******************************************************************************/
76*91f16700Schasinglulu static bool is_valid_mode(int mode)
77*91f16700Schasinglulu {
78*91f16700Schasinglulu 	if ((mode & O_READ) && (mode & (O_WRITE | O_RDWR))) {
79*91f16700Schasinglulu 		return false;
80*91f16700Schasinglulu 	}
81*91f16700Schasinglulu 	if ((mode & O_WRITE) && (mode & (O_READ | O_RDWR))) {
82*91f16700Schasinglulu 		return false;
83*91f16700Schasinglulu 	}
84*91f16700Schasinglulu 	if ((mode & O_RDWR) && (mode & (O_READ | O_WRITE))) {
85*91f16700Schasinglulu 		return false;
86*91f16700Schasinglulu 	}
87*91f16700Schasinglulu 
88*91f16700Schasinglulu 	return true;
89*91f16700Schasinglulu }
90*91f16700Schasinglulu 
91*91f16700Schasinglulu /*******************************************************************************
92*91f16700Schasinglulu  * This function extracts the next part of the given path contained and puts it
93*91f16700Schasinglulu  * in token. It returns a pointer to the remainder of the path.
94*91f16700Schasinglulu  ******************************************************************************/
95*91f16700Schasinglulu static const char *next(const char *path, char *token)
96*91f16700Schasinglulu {
97*91f16700Schasinglulu 	int index;
98*91f16700Schasinglulu 	const char *cursor;
99*91f16700Schasinglulu 
100*91f16700Schasinglulu 	while (*path == '/') {
101*91f16700Schasinglulu 		++path;
102*91f16700Schasinglulu 	}
103*91f16700Schasinglulu 
104*91f16700Schasinglulu 	index = 0;
105*91f16700Schasinglulu 	cursor = path;
106*91f16700Schasinglulu 	if (*path != '\0') {
107*91f16700Schasinglulu 		while (*cursor != '/' && *cursor != '\0') {
108*91f16700Schasinglulu 			if (index == NAMELEN) {
109*91f16700Schasinglulu 				return NULL;
110*91f16700Schasinglulu 			}
111*91f16700Schasinglulu 			token[index++] = *cursor++;
112*91f16700Schasinglulu 		}
113*91f16700Schasinglulu 	}
114*91f16700Schasinglulu 	token[index] = '\0';
115*91f16700Schasinglulu 
116*91f16700Schasinglulu 	return cursor;
117*91f16700Schasinglulu }
118*91f16700Schasinglulu 
119*91f16700Schasinglulu /*******************************************************************************
120*91f16700Schasinglulu  * This function returns the driver index in devtab of the driver
121*91f16700Schasinglulu  * identified by id.
122*91f16700Schasinglulu  ******************************************************************************/
123*91f16700Schasinglulu static int get_device_index(int id)
124*91f16700Schasinglulu {
125*91f16700Schasinglulu 	int index;
126*91f16700Schasinglulu 	dev_t * const *dp;
127*91f16700Schasinglulu 
128*91f16700Schasinglulu 	for (index = 0, dp = devtab; *dp && (*dp)->id != id; ++dp) {
129*91f16700Schasinglulu 		index++;
130*91f16700Schasinglulu 	}
131*91f16700Schasinglulu 
132*91f16700Schasinglulu 	if (*dp == NULL) {
133*91f16700Schasinglulu 		return -1;
134*91f16700Schasinglulu 	}
135*91f16700Schasinglulu 
136*91f16700Schasinglulu 	return index;
137*91f16700Schasinglulu }
138*91f16700Schasinglulu 
139*91f16700Schasinglulu /*******************************************************************************
140*91f16700Schasinglulu  * This function clears a given channel fields
141*91f16700Schasinglulu  ******************************************************************************/
142*91f16700Schasinglulu static void channel_clear(chan_t *channel)
143*91f16700Schasinglulu {
144*91f16700Schasinglulu 	channel->offset = 0;
145*91f16700Schasinglulu 	channel->qid    = 0;
146*91f16700Schasinglulu 	channel->index  = NODEV;
147*91f16700Schasinglulu 	channel->dev    = 0;
148*91f16700Schasinglulu 	channel->mode   = 0;
149*91f16700Schasinglulu }
150*91f16700Schasinglulu 
151*91f16700Schasinglulu /*******************************************************************************
152*91f16700Schasinglulu  * This function closes the channel pointed to by c.
153*91f16700Schasinglulu  ******************************************************************************/
154*91f16700Schasinglulu void channel_close(chan_t *channel)
155*91f16700Schasinglulu {
156*91f16700Schasinglulu 	if (channel != NULL) {
157*91f16700Schasinglulu 		channel_clear(channel);
158*91f16700Schasinglulu 	}
159*91f16700Schasinglulu }
160*91f16700Schasinglulu 
161*91f16700Schasinglulu /*******************************************************************************
162*91f16700Schasinglulu  * This function copies data from src to dst after applying the offset of the
163*91f16700Schasinglulu  * channel c. nbytes bytes are expected to be copied unless the data goes over
164*91f16700Schasinglulu  * dst + len.
165*91f16700Schasinglulu  * It returns the actual number of bytes that were copied.
166*91f16700Schasinglulu  ******************************************************************************/
167*91f16700Schasinglulu int buf_to_channel(chan_t *channel, void *dst, void *src, int nbytes, long len)
168*91f16700Schasinglulu {
169*91f16700Schasinglulu 	const char *addr = src;
170*91f16700Schasinglulu 
171*91f16700Schasinglulu 	if ((channel == NULL) || (dst == NULL) || (src == NULL)) {
172*91f16700Schasinglulu 		return 0;
173*91f16700Schasinglulu 	}
174*91f16700Schasinglulu 
175*91f16700Schasinglulu 	if (channel->offset >= len) {
176*91f16700Schasinglulu 		return 0;
177*91f16700Schasinglulu 	}
178*91f16700Schasinglulu 
179*91f16700Schasinglulu 	if ((channel->offset + nbytes) > len) {
180*91f16700Schasinglulu 		nbytes = len - channel->offset;
181*91f16700Schasinglulu 	}
182*91f16700Schasinglulu 
183*91f16700Schasinglulu 	memcpy(dst, addr + channel->offset, nbytes);
184*91f16700Schasinglulu 
185*91f16700Schasinglulu 	channel->offset += nbytes;
186*91f16700Schasinglulu 
187*91f16700Schasinglulu 	return nbytes;
188*91f16700Schasinglulu }
189*91f16700Schasinglulu 
190*91f16700Schasinglulu /*******************************************************************************
191*91f16700Schasinglulu  * This function checks whether a channel (identified by its device index and
192*91f16700Schasinglulu  * qid) is registered as a mount point.
193*91f16700Schasinglulu  * Returns a pointer to the channel it is mounted to when found, NULL otherwise.
194*91f16700Schasinglulu  ******************************************************************************/
195*91f16700Schasinglulu static chan_t *mount_point_to_channel(int index, qid_t qid)
196*91f16700Schasinglulu {
197*91f16700Schasinglulu 	chan_t *channel;
198*91f16700Schasinglulu 	struct mount_point *mp;
199*91f16700Schasinglulu 
200*91f16700Schasinglulu 	for (mp = mount_points; mp < &mount_points[NR_MOUNT_POINTS]; mp++) {
201*91f16700Schasinglulu 		channel = mp->new;
202*91f16700Schasinglulu 		if (channel == NULL) {
203*91f16700Schasinglulu 			continue;
204*91f16700Schasinglulu 		}
205*91f16700Schasinglulu 
206*91f16700Schasinglulu 		if ((channel->index == index) && (channel->qid == qid)) {
207*91f16700Schasinglulu 			return mp->old;
208*91f16700Schasinglulu 		}
209*91f16700Schasinglulu 	}
210*91f16700Schasinglulu 
211*91f16700Schasinglulu 	return NULL;
212*91f16700Schasinglulu }
213*91f16700Schasinglulu 
214*91f16700Schasinglulu /*******************************************************************************
215*91f16700Schasinglulu  * This function calls the attach function of the driver identified by id.
216*91f16700Schasinglulu  ******************************************************************************/
217*91f16700Schasinglulu chan_t *attach(int id, int dev)
218*91f16700Schasinglulu {
219*91f16700Schasinglulu 	/* Get the devtab index for the driver identified by id */
220*91f16700Schasinglulu 	int index = get_device_index(id);
221*91f16700Schasinglulu 
222*91f16700Schasinglulu 	if (index < 0) {
223*91f16700Schasinglulu 		return NULL;
224*91f16700Schasinglulu 	}
225*91f16700Schasinglulu 
226*91f16700Schasinglulu 	return devtab[index]->attach(id, dev);
227*91f16700Schasinglulu }
228*91f16700Schasinglulu 
229*91f16700Schasinglulu /*******************************************************************************
230*91f16700Schasinglulu  * This function is the default implementation of the driver attach function.
231*91f16700Schasinglulu  * It creates a new channel and returns a pointer to it.
232*91f16700Schasinglulu  ******************************************************************************/
233*91f16700Schasinglulu chan_t *devattach(int id, int dev)
234*91f16700Schasinglulu {
235*91f16700Schasinglulu 	chan_t *channel;
236*91f16700Schasinglulu 	int index;
237*91f16700Schasinglulu 
238*91f16700Schasinglulu 	index = get_device_index(id);
239*91f16700Schasinglulu 	if (index < 0) {
240*91f16700Schasinglulu 		return NULL;
241*91f16700Schasinglulu 	}
242*91f16700Schasinglulu 
243*91f16700Schasinglulu 	channel = create_new_channel(index);
244*91f16700Schasinglulu 	if (channel == NULL) {
245*91f16700Schasinglulu 		return NULL;
246*91f16700Schasinglulu 	}
247*91f16700Schasinglulu 
248*91f16700Schasinglulu 	channel->dev = dev;
249*91f16700Schasinglulu 	channel->qid = CHDIR;
250*91f16700Schasinglulu 
251*91f16700Schasinglulu 	return channel;
252*91f16700Schasinglulu }
253*91f16700Schasinglulu 
254*91f16700Schasinglulu /*******************************************************************************
255*91f16700Schasinglulu  * This function returns a channel given a path.
256*91f16700Schasinglulu  * It goes through the filesystem, from the root namespace ('/') or from a
257*91f16700Schasinglulu  * device namespace ('#'), switching channel on mount points.
258*91f16700Schasinglulu  ******************************************************************************/
259*91f16700Schasinglulu chan_t *path_to_channel(const char *path, int mode)
260*91f16700Schasinglulu {
261*91f16700Schasinglulu 	int i, n;
262*91f16700Schasinglulu 	const char *path_next;
263*91f16700Schasinglulu 	chan_t *mnt, *channel;
264*91f16700Schasinglulu 	char elem[NAMELEN];
265*91f16700Schasinglulu 
266*91f16700Schasinglulu 	if (path == NULL) {
267*91f16700Schasinglulu 		return NULL;
268*91f16700Schasinglulu 	}
269*91f16700Schasinglulu 
270*91f16700Schasinglulu 	switch (path[0]) {
271*91f16700Schasinglulu 	case '/':
272*91f16700Schasinglulu 		channel = clone(&slash_channel, NULL);
273*91f16700Schasinglulu 		path_next = path;
274*91f16700Schasinglulu 		break;
275*91f16700Schasinglulu 	case '#':
276*91f16700Schasinglulu 		path_next = next(path + 1, elem);
277*91f16700Schasinglulu 		if (path_next == NULL) {
278*91f16700Schasinglulu 			goto noent;
279*91f16700Schasinglulu 		}
280*91f16700Schasinglulu 
281*91f16700Schasinglulu 		n = 0;
282*91f16700Schasinglulu 		for (i = 1; (elem[i] >= '0') && (elem[i] <= '9'); i++) {
283*91f16700Schasinglulu 			n += elem[i] - '0';
284*91f16700Schasinglulu 		}
285*91f16700Schasinglulu 
286*91f16700Schasinglulu 		if (elem[i] != '\0') {
287*91f16700Schasinglulu 			goto noent;
288*91f16700Schasinglulu 		}
289*91f16700Schasinglulu 
290*91f16700Schasinglulu 		channel = attach(elem[0], n);
291*91f16700Schasinglulu 		break;
292*91f16700Schasinglulu 	default:
293*91f16700Schasinglulu 		return NULL;
294*91f16700Schasinglulu 	}
295*91f16700Schasinglulu 
296*91f16700Schasinglulu 	if (channel == NULL) {
297*91f16700Schasinglulu 		return NULL;
298*91f16700Schasinglulu 	}
299*91f16700Schasinglulu 
300*91f16700Schasinglulu 	for (path_next = next(path_next, elem); *elem;
301*91f16700Schasinglulu 			path_next = next(path_next, elem)) {
302*91f16700Schasinglulu 		if ((channel->qid & CHDIR) == 0) {
303*91f16700Schasinglulu 			goto notfound;
304*91f16700Schasinglulu 		}
305*91f16700Schasinglulu 
306*91f16700Schasinglulu 		if (devtab[channel->index]->walk(channel, elem) < 0) {
307*91f16700Schasinglulu 			channel_close(channel);
308*91f16700Schasinglulu 			goto notfound;
309*91f16700Schasinglulu 		}
310*91f16700Schasinglulu 
311*91f16700Schasinglulu 		mnt = mount_point_to_channel(channel->index, channel->qid);
312*91f16700Schasinglulu 		if (mnt != NULL) {
313*91f16700Schasinglulu 			clone(mnt, channel);
314*91f16700Schasinglulu 		}
315*91f16700Schasinglulu 	}
316*91f16700Schasinglulu 
317*91f16700Schasinglulu 	if (path_next == NULL) {
318*91f16700Schasinglulu 		goto notfound;
319*91f16700Schasinglulu 	}
320*91f16700Schasinglulu 
321*91f16700Schasinglulu 	/* TODO: check mode */
322*91f16700Schasinglulu 	return channel;
323*91f16700Schasinglulu 
324*91f16700Schasinglulu notfound:
325*91f16700Schasinglulu 	channel_close(channel);
326*91f16700Schasinglulu noent:
327*91f16700Schasinglulu 	return NULL;
328*91f16700Schasinglulu }
329*91f16700Schasinglulu 
330*91f16700Schasinglulu /*******************************************************************************
331*91f16700Schasinglulu  * This function calls the clone function of the driver associated to the
332*91f16700Schasinglulu  * channel c.
333*91f16700Schasinglulu  ******************************************************************************/
334*91f16700Schasinglulu chan_t *clone(chan_t *c, chan_t *nc)
335*91f16700Schasinglulu {
336*91f16700Schasinglulu 	if (c->index == NODEV) {
337*91f16700Schasinglulu 		return NULL;
338*91f16700Schasinglulu 	}
339*91f16700Schasinglulu 
340*91f16700Schasinglulu 	return devtab[c->index]->clone(c, nc);
341*91f16700Schasinglulu }
342*91f16700Schasinglulu 
343*91f16700Schasinglulu /*******************************************************************************
344*91f16700Schasinglulu  * This function is the default implementation of the driver clone function.
345*91f16700Schasinglulu  * It creates a new channel and returns a pointer to it.
346*91f16700Schasinglulu  * It clones channel into new_channel.
347*91f16700Schasinglulu  ******************************************************************************/
348*91f16700Schasinglulu chan_t *devclone(chan_t *channel, chan_t *new_channel)
349*91f16700Schasinglulu {
350*91f16700Schasinglulu 	if (channel == NULL) {
351*91f16700Schasinglulu 		return NULL;
352*91f16700Schasinglulu 	}
353*91f16700Schasinglulu 
354*91f16700Schasinglulu 	if (new_channel == NULL) {
355*91f16700Schasinglulu 		new_channel = create_new_channel(channel->index);
356*91f16700Schasinglulu 		if (new_channel == NULL) {
357*91f16700Schasinglulu 			return NULL;
358*91f16700Schasinglulu 		}
359*91f16700Schasinglulu 	}
360*91f16700Schasinglulu 
361*91f16700Schasinglulu 	new_channel->qid    = channel->qid;
362*91f16700Schasinglulu 	new_channel->dev    = channel->dev;
363*91f16700Schasinglulu 	new_channel->mode   = channel->mode;
364*91f16700Schasinglulu 	new_channel->offset = channel->offset;
365*91f16700Schasinglulu 	new_channel->index  = channel->index;
366*91f16700Schasinglulu 
367*91f16700Schasinglulu 	return new_channel;
368*91f16700Schasinglulu }
369*91f16700Schasinglulu 
370*91f16700Schasinglulu /*******************************************************************************
371*91f16700Schasinglulu  * This function is the default implementation of the driver walk function.
372*91f16700Schasinglulu  * It goes through all the elements of tab using the gen function until a match
373*91f16700Schasinglulu  * is found with name.
374*91f16700Schasinglulu  * If a match is found, it copies the qid of the new directory.
375*91f16700Schasinglulu  ******************************************************************************/
376*91f16700Schasinglulu int devwalk(chan_t *channel, const char *name, const dirtab_t *tab,
377*91f16700Schasinglulu 	    int ntab, devgen_t *gen)
378*91f16700Schasinglulu {
379*91f16700Schasinglulu 	int i;
380*91f16700Schasinglulu 	dir_t dir;
381*91f16700Schasinglulu 
382*91f16700Schasinglulu 	if ((channel == NULL) || (name == NULL) || (gen == NULL)) {
383*91f16700Schasinglulu 		return -1;
384*91f16700Schasinglulu 	}
385*91f16700Schasinglulu 
386*91f16700Schasinglulu 	if ((name[0] == '.') && (name[1] == '\0')) {
387*91f16700Schasinglulu 		return 1;
388*91f16700Schasinglulu 	}
389*91f16700Schasinglulu 
390*91f16700Schasinglulu 	for (i = 0; ; i++) {
391*91f16700Schasinglulu 		switch ((*gen)(channel, tab, ntab, i, &dir)) {
392*91f16700Schasinglulu 		case 0:
393*91f16700Schasinglulu 			/* Intentional fall-through */
394*91f16700Schasinglulu 		case -1:
395*91f16700Schasinglulu 			return -1;
396*91f16700Schasinglulu 		case 1:
397*91f16700Schasinglulu 			if (strncmp(name, dir.name, NAMELEN) != 0) {
398*91f16700Schasinglulu 				continue;
399*91f16700Schasinglulu 			}
400*91f16700Schasinglulu 			channel->qid = dir.qid;
401*91f16700Schasinglulu 			return 1;
402*91f16700Schasinglulu 		}
403*91f16700Schasinglulu 	}
404*91f16700Schasinglulu }
405*91f16700Schasinglulu 
406*91f16700Schasinglulu /*******************************************************************************
407*91f16700Schasinglulu  * This is a helper function which exposes the content of a directory, element
408*91f16700Schasinglulu  * by element. It is meant to be called until the end of the directory is
409*91f16700Schasinglulu  * reached or an error occurs.
410*91f16700Schasinglulu  * It returns -1 on error, 0 on end of directory and 1 when a new file is found.
411*91f16700Schasinglulu  ******************************************************************************/
412*91f16700Schasinglulu int dirread(chan_t *channel, dir_t *dir, const dirtab_t *tab,
413*91f16700Schasinglulu 	int ntab, devgen_t *gen)
414*91f16700Schasinglulu {
415*91f16700Schasinglulu 	int i, ret;
416*91f16700Schasinglulu 
417*91f16700Schasinglulu 	if ((channel == NULL) || (dir == NULL) || (gen == NULL)) {
418*91f16700Schasinglulu 		return -1;
419*91f16700Schasinglulu 	}
420*91f16700Schasinglulu 
421*91f16700Schasinglulu 	i = channel->offset/sizeof(dir_t);
422*91f16700Schasinglulu 	ret = (*gen)(channel, tab, ntab, i, dir);
423*91f16700Schasinglulu 	if (ret == 1) {
424*91f16700Schasinglulu 		channel->offset += sizeof(dir_t);
425*91f16700Schasinglulu 	}
426*91f16700Schasinglulu 
427*91f16700Schasinglulu 	return ret;
428*91f16700Schasinglulu }
429*91f16700Schasinglulu 
430*91f16700Schasinglulu /*******************************************************************************
431*91f16700Schasinglulu  * This function sets the elements of dir.
432*91f16700Schasinglulu  ******************************************************************************/
433*91f16700Schasinglulu void make_dir_entry(chan_t *channel, dir_t *dir,
434*91f16700Schasinglulu 	     const char *name, long length, qid_t qid, unsigned int mode)
435*91f16700Schasinglulu {
436*91f16700Schasinglulu 	if ((channel == NULL) || (dir == NULL) || (name == NULL)) {
437*91f16700Schasinglulu 		return;
438*91f16700Schasinglulu 	}
439*91f16700Schasinglulu 
440*91f16700Schasinglulu 	strlcpy(dir->name, name, sizeof(dir->name));
441*91f16700Schasinglulu 	dir->length = length;
442*91f16700Schasinglulu 	dir->qid = qid;
443*91f16700Schasinglulu 	dir->mode = mode;
444*91f16700Schasinglulu 
445*91f16700Schasinglulu 	if ((qid & CHDIR) != 0) {
446*91f16700Schasinglulu 		dir->mode |= O_DIR;
447*91f16700Schasinglulu 	}
448*91f16700Schasinglulu 
449*91f16700Schasinglulu 	dir->index = channel->index;
450*91f16700Schasinglulu 	dir->dev   = channel->dev;
451*91f16700Schasinglulu }
452*91f16700Schasinglulu 
453*91f16700Schasinglulu /*******************************************************************************
454*91f16700Schasinglulu  * This function is the default implementation of the internal driver gen
455*91f16700Schasinglulu  * function.
456*91f16700Schasinglulu  * It copies and formats the information of the nth element of tab into dir.
457*91f16700Schasinglulu  ******************************************************************************/
458*91f16700Schasinglulu int devgen(chan_t *channel, const dirtab_t *tab, int ntab, int n, dir_t *dir)
459*91f16700Schasinglulu {
460*91f16700Schasinglulu 	const dirtab_t *dp;
461*91f16700Schasinglulu 
462*91f16700Schasinglulu 	if ((channel == NULL) || (dir == NULL) || (tab == NULL) ||
463*91f16700Schasinglulu 			(n >= ntab)) {
464*91f16700Schasinglulu 		return 0;
465*91f16700Schasinglulu 	}
466*91f16700Schasinglulu 
467*91f16700Schasinglulu 	dp = &tab[n];
468*91f16700Schasinglulu 	make_dir_entry(channel, dir, dp->name, dp->length, dp->qid, dp->perm);
469*91f16700Schasinglulu 	return 1;
470*91f16700Schasinglulu }
471*91f16700Schasinglulu 
472*91f16700Schasinglulu /*******************************************************************************
473*91f16700Schasinglulu  * This function returns a file descriptor identifying the channel associated to
474*91f16700Schasinglulu  * the given path.
475*91f16700Schasinglulu  ******************************************************************************/
476*91f16700Schasinglulu int open(const char *path, int mode)
477*91f16700Schasinglulu {
478*91f16700Schasinglulu 	chan_t *channel;
479*91f16700Schasinglulu 
480*91f16700Schasinglulu 	if (path == NULL) {
481*91f16700Schasinglulu 		return -1;
482*91f16700Schasinglulu 	}
483*91f16700Schasinglulu 
484*91f16700Schasinglulu 	if (is_valid_mode(mode) == false) {
485*91f16700Schasinglulu 		return -1;
486*91f16700Schasinglulu 	}
487*91f16700Schasinglulu 
488*91f16700Schasinglulu 	channel = path_to_channel(path, mode);
489*91f16700Schasinglulu 
490*91f16700Schasinglulu 	return channel_to_fd(channel);
491*91f16700Schasinglulu }
492*91f16700Schasinglulu 
493*91f16700Schasinglulu /*******************************************************************************
494*91f16700Schasinglulu  * This function closes the channel identified by the file descriptor fd.
495*91f16700Schasinglulu  ******************************************************************************/
496*91f16700Schasinglulu int close(int fd)
497*91f16700Schasinglulu {
498*91f16700Schasinglulu 	chan_t *channel;
499*91f16700Schasinglulu 
500*91f16700Schasinglulu 	channel = fd_to_channel(fd);
501*91f16700Schasinglulu 	if (channel == NULL) {
502*91f16700Schasinglulu 		return -1;
503*91f16700Schasinglulu 	}
504*91f16700Schasinglulu 
505*91f16700Schasinglulu 	channel_close(channel);
506*91f16700Schasinglulu 	return 0;
507*91f16700Schasinglulu }
508*91f16700Schasinglulu 
509*91f16700Schasinglulu /*******************************************************************************
510*91f16700Schasinglulu  * This function is the default implementation of the driver stat function.
511*91f16700Schasinglulu  * It goes through all the elements of tab using the gen function until a match
512*91f16700Schasinglulu  * is found with file.
513*91f16700Schasinglulu  * If a match is found, dir contains the information file.
514*91f16700Schasinglulu  ******************************************************************************/
515*91f16700Schasinglulu int devstat(chan_t *dirc, const char *file, dir_t *dir,
516*91f16700Schasinglulu 	    const dirtab_t *tab, int ntab, devgen_t *gen)
517*91f16700Schasinglulu {
518*91f16700Schasinglulu 	int i, r = 0;
519*91f16700Schasinglulu 	chan_t *c, *mnt;
520*91f16700Schasinglulu 
521*91f16700Schasinglulu 	if ((dirc == NULL) || (dir == NULL) || (gen == NULL)) {
522*91f16700Schasinglulu 		return -1;
523*91f16700Schasinglulu 	}
524*91f16700Schasinglulu 
525*91f16700Schasinglulu 	c = path_to_channel(file, O_STAT);
526*91f16700Schasinglulu 	if (c == NULL) {
527*91f16700Schasinglulu 		return -1;
528*91f16700Schasinglulu 	}
529*91f16700Schasinglulu 
530*91f16700Schasinglulu 	for (i = 0; ; i++) {
531*91f16700Schasinglulu 		switch ((*gen)(dirc, tab, ntab, i, dir)) {
532*91f16700Schasinglulu 		case 0:
533*91f16700Schasinglulu 			/* Intentional fall-through */
534*91f16700Schasinglulu 		case -1:
535*91f16700Schasinglulu 			r = -1;
536*91f16700Schasinglulu 			goto leave;
537*91f16700Schasinglulu 		case 1:
538*91f16700Schasinglulu 			mnt = mount_point_to_channel(dir->index, dir->qid);
539*91f16700Schasinglulu 			if (mnt != NULL) {
540*91f16700Schasinglulu 				dir->qid = mnt->qid;
541*91f16700Schasinglulu 				dir->index = mnt->index;
542*91f16700Schasinglulu 			}
543*91f16700Schasinglulu 
544*91f16700Schasinglulu 			if ((dir->qid != c->qid) || (dir->index != c->index)) {
545*91f16700Schasinglulu 				continue;
546*91f16700Schasinglulu 			}
547*91f16700Schasinglulu 
548*91f16700Schasinglulu 			goto leave;
549*91f16700Schasinglulu 		}
550*91f16700Schasinglulu 	}
551*91f16700Schasinglulu 
552*91f16700Schasinglulu leave:
553*91f16700Schasinglulu 	channel_close(c);
554*91f16700Schasinglulu 	return r;
555*91f16700Schasinglulu }
556*91f16700Schasinglulu 
557*91f16700Schasinglulu /*******************************************************************************
558*91f16700Schasinglulu  * This function calls the stat function of the driver associated to the parent
559*91f16700Schasinglulu  * directory of the file in path.
560*91f16700Schasinglulu  * The result is stored in dir.
561*91f16700Schasinglulu  ******************************************************************************/
562*91f16700Schasinglulu int stat(const char *path, dir_t *dir)
563*91f16700Schasinglulu {
564*91f16700Schasinglulu 	int r;
565*91f16700Schasinglulu 	size_t len;
566*91f16700Schasinglulu 	chan_t *channel;
567*91f16700Schasinglulu 	char *p, dirname[PATHLEN];
568*91f16700Schasinglulu 
569*91f16700Schasinglulu 	if ((path == NULL) || (dir == NULL)) {
570*91f16700Schasinglulu 		return -1;
571*91f16700Schasinglulu 	}
572*91f16700Schasinglulu 
573*91f16700Schasinglulu 	len = strlen(path);
574*91f16700Schasinglulu 	if ((len + 1) > sizeof(dirname)) {
575*91f16700Schasinglulu 		return -1;
576*91f16700Schasinglulu 	}
577*91f16700Schasinglulu 
578*91f16700Schasinglulu 	memcpy(dirname, path, len);
579*91f16700Schasinglulu 	for (p = dirname + len; p > dirname; --p) {
580*91f16700Schasinglulu 		if (*p != '/') {
581*91f16700Schasinglulu 			break;
582*91f16700Schasinglulu 		}
583*91f16700Schasinglulu 	}
584*91f16700Schasinglulu 
585*91f16700Schasinglulu 	p = memrchr(dirname, '/', p - dirname);
586*91f16700Schasinglulu 	if (p == NULL) {
587*91f16700Schasinglulu 		return -1;
588*91f16700Schasinglulu 	}
589*91f16700Schasinglulu 
590*91f16700Schasinglulu 	dirname[p - dirname + 1] = '\0';
591*91f16700Schasinglulu 
592*91f16700Schasinglulu 	channel = path_to_channel(dirname, O_STAT);
593*91f16700Schasinglulu 	if (channel == NULL) {
594*91f16700Schasinglulu 		return -1;
595*91f16700Schasinglulu 	}
596*91f16700Schasinglulu 
597*91f16700Schasinglulu 	r = devtab[channel->index]->stat(channel, path, dir);
598*91f16700Schasinglulu 	channel_close(channel);
599*91f16700Schasinglulu 
600*91f16700Schasinglulu 	return r;
601*91f16700Schasinglulu }
602*91f16700Schasinglulu 
603*91f16700Schasinglulu /*******************************************************************************
604*91f16700Schasinglulu  * This function calls the read function of the driver associated to fd.
605*91f16700Schasinglulu  * It fills buf with at most n bytes.
606*91f16700Schasinglulu  * It returns the number of bytes that were actually read.
607*91f16700Schasinglulu  ******************************************************************************/
608*91f16700Schasinglulu int read(int fd, void *buf, int n)
609*91f16700Schasinglulu {
610*91f16700Schasinglulu 	chan_t *channel;
611*91f16700Schasinglulu 
612*91f16700Schasinglulu 	if (buf == NULL) {
613*91f16700Schasinglulu 		return -1;
614*91f16700Schasinglulu 	}
615*91f16700Schasinglulu 
616*91f16700Schasinglulu 	channel = fd_to_channel(fd);
617*91f16700Schasinglulu 	if (channel == NULL) {
618*91f16700Schasinglulu 		return -1;
619*91f16700Schasinglulu 	}
620*91f16700Schasinglulu 
621*91f16700Schasinglulu 	if (((channel->qid & CHDIR) != 0) && (n < sizeof(dir_t))) {
622*91f16700Schasinglulu 		return -1;
623*91f16700Schasinglulu 	}
624*91f16700Schasinglulu 
625*91f16700Schasinglulu 	return devtab[channel->index]->read(channel, buf, n);
626*91f16700Schasinglulu }
627*91f16700Schasinglulu 
628*91f16700Schasinglulu /*******************************************************************************
629*91f16700Schasinglulu  * This function calls the write function of the driver associated to fd.
630*91f16700Schasinglulu  * It writes at most n bytes of buf.
631*91f16700Schasinglulu  * It returns the number of bytes that were actually written.
632*91f16700Schasinglulu  ******************************************************************************/
633*91f16700Schasinglulu int write(int fd, void *buf, int n)
634*91f16700Schasinglulu {
635*91f16700Schasinglulu 	chan_t *channel;
636*91f16700Schasinglulu 
637*91f16700Schasinglulu 	if (buf == NULL) {
638*91f16700Schasinglulu 		return -1;
639*91f16700Schasinglulu 	}
640*91f16700Schasinglulu 
641*91f16700Schasinglulu 	channel = fd_to_channel(fd);
642*91f16700Schasinglulu 	if (channel == NULL) {
643*91f16700Schasinglulu 		return -1;
644*91f16700Schasinglulu 	}
645*91f16700Schasinglulu 
646*91f16700Schasinglulu 	if ((channel->qid & CHDIR) != 0) {
647*91f16700Schasinglulu 		return -1;
648*91f16700Schasinglulu 	}
649*91f16700Schasinglulu 
650*91f16700Schasinglulu 	return devtab[channel->index]->write(channel, buf, n);
651*91f16700Schasinglulu }
652*91f16700Schasinglulu 
653*91f16700Schasinglulu /*******************************************************************************
654*91f16700Schasinglulu  * This function calls the seek function of the driver associated to fd.
655*91f16700Schasinglulu  * It applies the offset off according to the strategy whence.
656*91f16700Schasinglulu  ******************************************************************************/
657*91f16700Schasinglulu int seek(int fd, long off, int whence)
658*91f16700Schasinglulu {
659*91f16700Schasinglulu 	chan_t *channel;
660*91f16700Schasinglulu 
661*91f16700Schasinglulu 	channel = fd_to_channel(fd);
662*91f16700Schasinglulu 	if (channel == NULL) {
663*91f16700Schasinglulu 		return -1;
664*91f16700Schasinglulu 	}
665*91f16700Schasinglulu 
666*91f16700Schasinglulu 	if ((channel->qid & CHDIR) != 0) {
667*91f16700Schasinglulu 		return -1;
668*91f16700Schasinglulu 	}
669*91f16700Schasinglulu 
670*91f16700Schasinglulu 	return devtab[channel->index]->seek(channel, off, whence);
671*91f16700Schasinglulu }
672*91f16700Schasinglulu 
673*91f16700Schasinglulu /*******************************************************************************
674*91f16700Schasinglulu  * This function is the default error implementation of the driver mount
675*91f16700Schasinglulu  * function.
676*91f16700Schasinglulu  ******************************************************************************/
677*91f16700Schasinglulu chan_t *deverrmount(chan_t *channel, const char *spec)
678*91f16700Schasinglulu {
679*91f16700Schasinglulu 	return NULL;
680*91f16700Schasinglulu }
681*91f16700Schasinglulu 
682*91f16700Schasinglulu /*******************************************************************************
683*91f16700Schasinglulu  * This function is the default error implementation of the driver write
684*91f16700Schasinglulu  * function.
685*91f16700Schasinglulu  ******************************************************************************/
686*91f16700Schasinglulu int deverrwrite(chan_t *channel, void *buf, int n)
687*91f16700Schasinglulu {
688*91f16700Schasinglulu 	return -1;
689*91f16700Schasinglulu }
690*91f16700Schasinglulu 
691*91f16700Schasinglulu /*******************************************************************************
692*91f16700Schasinglulu  * This function is the default error implementation of the driver seek
693*91f16700Schasinglulu  * function.
694*91f16700Schasinglulu  ******************************************************************************/
695*91f16700Schasinglulu int deverrseek(chan_t *channel, long off, int whence)
696*91f16700Schasinglulu {
697*91f16700Schasinglulu 	return -1;
698*91f16700Schasinglulu }
699*91f16700Schasinglulu 
700*91f16700Schasinglulu /*******************************************************************************
701*91f16700Schasinglulu  * This function is the default implementation of the driver seek function.
702*91f16700Schasinglulu  * It applies the offset off according to the strategy whence to the channel c.
703*91f16700Schasinglulu  ******************************************************************************/
704*91f16700Schasinglulu int devseek(chan_t *channel, long off, int whence)
705*91f16700Schasinglulu {
706*91f16700Schasinglulu 	switch (whence) {
707*91f16700Schasinglulu 	case KSEEK_SET:
708*91f16700Schasinglulu 		channel->offset = off;
709*91f16700Schasinglulu 		break;
710*91f16700Schasinglulu 	case KSEEK_CUR:
711*91f16700Schasinglulu 		channel->offset += off;
712*91f16700Schasinglulu 		break;
713*91f16700Schasinglulu 	case KSEEK_END:
714*91f16700Schasinglulu 		/* Not implemented */
715*91f16700Schasinglulu 		return -1;
716*91f16700Schasinglulu 	}
717*91f16700Schasinglulu 
718*91f16700Schasinglulu 	return 0;
719*91f16700Schasinglulu }
720*91f16700Schasinglulu 
721*91f16700Schasinglulu /*******************************************************************************
722*91f16700Schasinglulu  * This function registers the channel associated to the path new as a mount
723*91f16700Schasinglulu  * point for the channel c.
724*91f16700Schasinglulu  ******************************************************************************/
725*91f16700Schasinglulu static int add_mount_point(chan_t *channel, const char *new)
726*91f16700Schasinglulu {
727*91f16700Schasinglulu 	int i;
728*91f16700Schasinglulu 	chan_t *cn;
729*91f16700Schasinglulu 	struct mount_point *mp;
730*91f16700Schasinglulu 
731*91f16700Schasinglulu 	if (new == NULL) {
732*91f16700Schasinglulu 		goto err0;
733*91f16700Schasinglulu 	}
734*91f16700Schasinglulu 
735*91f16700Schasinglulu 	cn = path_to_channel(new, O_READ);
736*91f16700Schasinglulu 	if (cn == NULL) {
737*91f16700Schasinglulu 		goto err0;
738*91f16700Schasinglulu 	}
739*91f16700Schasinglulu 
740*91f16700Schasinglulu 	if ((cn->qid & CHDIR) == 0) {
741*91f16700Schasinglulu 		goto err1;
742*91f16700Schasinglulu 	}
743*91f16700Schasinglulu 
744*91f16700Schasinglulu 	for (i = NR_MOUNT_POINTS - 1; i >= 0; i--) {
745*91f16700Schasinglulu 		mp = &mount_points[i];
746*91f16700Schasinglulu 		if (mp->new == NULL) {
747*91f16700Schasinglulu 			break;
748*91f16700Schasinglulu 		}
749*91f16700Schasinglulu 	}
750*91f16700Schasinglulu 
751*91f16700Schasinglulu 	if (i < 0) {
752*91f16700Schasinglulu 		goto err1;
753*91f16700Schasinglulu 	}
754*91f16700Schasinglulu 
755*91f16700Schasinglulu 	mp->new = cn;
756*91f16700Schasinglulu 	mp->old = channel;
757*91f16700Schasinglulu 
758*91f16700Schasinglulu 	return 0;
759*91f16700Schasinglulu 
760*91f16700Schasinglulu err1:
761*91f16700Schasinglulu 	channel_close(cn);
762*91f16700Schasinglulu err0:
763*91f16700Schasinglulu 	return -1;
764*91f16700Schasinglulu }
765*91f16700Schasinglulu 
766*91f16700Schasinglulu /*******************************************************************************
767*91f16700Schasinglulu  * This function registers the path new as a mount point for the path old.
768*91f16700Schasinglulu  ******************************************************************************/
769*91f16700Schasinglulu int bind(const char *old, const char *new)
770*91f16700Schasinglulu {
771*91f16700Schasinglulu 	chan_t *channel;
772*91f16700Schasinglulu 
773*91f16700Schasinglulu 	channel = path_to_channel(old, O_BIND);
774*91f16700Schasinglulu 	if (channel == NULL) {
775*91f16700Schasinglulu 		return -1;
776*91f16700Schasinglulu 	}
777*91f16700Schasinglulu 
778*91f16700Schasinglulu 	if (add_mount_point(channel, new) < 0) {
779*91f16700Schasinglulu 		channel_close(channel);
780*91f16700Schasinglulu 		return -1;
781*91f16700Schasinglulu 	}
782*91f16700Schasinglulu 
783*91f16700Schasinglulu 	return 0;
784*91f16700Schasinglulu }
785*91f16700Schasinglulu 
786*91f16700Schasinglulu /*******************************************************************************
787*91f16700Schasinglulu  * This function calls the mount function of the driver associated to the path
788*91f16700Schasinglulu  * srv.
789*91f16700Schasinglulu  * It mounts the path srv on the path where.
790*91f16700Schasinglulu  ******************************************************************************/
791*91f16700Schasinglulu int mount(const char *srv, const char *where, const char *spec)
792*91f16700Schasinglulu {
793*91f16700Schasinglulu 	chan_t *channel, *mount_point_chan;
794*91f16700Schasinglulu 	int ret;
795*91f16700Schasinglulu 
796*91f16700Schasinglulu 	channel = path_to_channel(srv, O_RDWR);
797*91f16700Schasinglulu 	if (channel == NULL) {
798*91f16700Schasinglulu 		goto err0;
799*91f16700Schasinglulu 	}
800*91f16700Schasinglulu 
801*91f16700Schasinglulu 	mount_point_chan = devtab[channel->index]->mount(channel, spec);
802*91f16700Schasinglulu 	if (mount_point_chan == NULL) {
803*91f16700Schasinglulu 		goto err1;
804*91f16700Schasinglulu 	}
805*91f16700Schasinglulu 
806*91f16700Schasinglulu 	ret = add_mount_point(mount_point_chan, where);
807*91f16700Schasinglulu 	if (ret < 0) {
808*91f16700Schasinglulu 		goto err2;
809*91f16700Schasinglulu 	}
810*91f16700Schasinglulu 
811*91f16700Schasinglulu 	channel_close(channel);
812*91f16700Schasinglulu 
813*91f16700Schasinglulu 	return 0;
814*91f16700Schasinglulu 
815*91f16700Schasinglulu err2:
816*91f16700Schasinglulu 	channel_close(mount_point_chan);
817*91f16700Schasinglulu err1:
818*91f16700Schasinglulu 	channel_close(channel);
819*91f16700Schasinglulu err0:
820*91f16700Schasinglulu 	return -1;
821*91f16700Schasinglulu }
822*91f16700Schasinglulu 
823*91f16700Schasinglulu /*******************************************************************************
824*91f16700Schasinglulu  * This function initializes the device environment.
825*91f16700Schasinglulu  * It creates the '/' channel.
826*91f16700Schasinglulu  * It links the device drivers to the physical drivers.
827*91f16700Schasinglulu  ******************************************************************************/
828*91f16700Schasinglulu void debugfs_init(void)
829*91f16700Schasinglulu {
830*91f16700Schasinglulu 	chan_t *channel, *cloned_channel;
831*91f16700Schasinglulu 
832*91f16700Schasinglulu 	for (channel = fdset; channel < &fdset[NR_CHANS]; channel++) {
833*91f16700Schasinglulu 		channel_clear(channel);
834*91f16700Schasinglulu 	}
835*91f16700Schasinglulu 
836*91f16700Schasinglulu 	channel = devattach('/', 0);
837*91f16700Schasinglulu 	if (channel == NULL) {
838*91f16700Schasinglulu 		panic();
839*91f16700Schasinglulu 	}
840*91f16700Schasinglulu 
841*91f16700Schasinglulu 	cloned_channel = clone(channel, &slash_channel);
842*91f16700Schasinglulu 	if (cloned_channel == NULL) {
843*91f16700Schasinglulu 		panic();
844*91f16700Schasinglulu 	}
845*91f16700Schasinglulu 
846*91f16700Schasinglulu 	channel_close(channel);
847*91f16700Schasinglulu 	devlink();
848*91f16700Schasinglulu }
849*91f16700Schasinglulu 
850*91f16700Schasinglulu __dead2 void devpanic(const char *cause)
851*91f16700Schasinglulu {
852*91f16700Schasinglulu 	panic();
853*91f16700Schasinglulu }
854