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